diff options
37 files changed, 1691 insertions, 2 deletions
diff --git a/android_webview/java_library_common.mk b/android_webview/java_library_common.mk index 56f36ac..15126cf 100644 --- a/android_webview/java_library_common.mk +++ b/android_webview/java_library_common.mk @@ -44,6 +44,7 @@ LOCAL_SRC_FILES += \ # Java files generated from .template rules. This list should match list of java dependencies in # android_webview/libwebviewchromium.gyp LOCAL_GENERATED_SOURCES := \ +$(call intermediates-dir-for,GYP,shared)/enums/android_resource_type_java/org/chromium/ui/resources/AndroidResourceType.java \ $(call intermediates-dir-for,GYP,shared)/enums/bitmap_format_java/org/chromium/ui/gfx/BitmapFormat.java \ $(call intermediates-dir-for,GYP,shared)/enums/cert_verify_status_android_java/org/chromium/net/CertVerifyStatusAndroid.java \ $(call intermediates-dir-for,GYP,shared)/enums/certificate_mime_types_java/org/chromium/net/CertificateMimeType.java \ diff --git a/android_webview/libwebviewchromium.gypi b/android_webview/libwebviewchromium.gypi index 099ca4b..8b2d40c 100644 --- a/android_webview/libwebviewchromium.gypi +++ b/android_webview/libwebviewchromium.gypi @@ -30,6 +30,7 @@ '../net/net.gyp:network_change_notifier_types_java', '../net/net.gyp:net_errors_java', '../net/net.gyp:private_key_types_java', + '../ui/android/ui_android.gyp:android_resource_type_java', '../ui/android/ui_android.gyp:bitmap_format_java', '../ui/android/ui_android.gyp:page_transition_types_java', '../ui/android/ui_android.gyp:system_ui_resource_type_java', diff --git a/content/app/BUILD.gn b/content/app/BUILD.gn index 82af6d7..d5a9371 100644 --- a/content/app/BUILD.gn +++ b/content/app/BUILD.gn @@ -44,6 +44,7 @@ if (is_win) { "//content/public/android:jni", "//skia", "//third_party/android_tools:cpu_features", + "//ui/android", ] } diff --git a/content/app/android/library_loader_hooks.cc b/content/app/android/library_loader_hooks.cc index d09e21e..d044e6b 100644 --- a/content/app/android/library_loader_hooks.cc +++ b/content/app/android/library_loader_hooks.cc @@ -25,6 +25,7 @@ #include "device/battery/android/battery_jni_registrar.h" #include "media/base/android/media_jni_registrar.h" #include "net/android/net_jni_registrar.h" +#include "ui/android/ui_android_jni_registrar.h" #include "ui/base/android/ui_base_jni_registrar.h" #include "ui/gfx/android/gfx_jni_registrar.h" #include "ui/gl/android/gl_jni_registrar.h" @@ -69,6 +70,9 @@ bool EnsureJniRegistered(JNIEnv* env) { if (!media::RegisterJni(env)) return false; + if (!ui::RegisterUIAndroidJni(env)) + return false; + g_jni_init_done = true; } diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 3a98908..930a3e2 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn @@ -329,6 +329,7 @@ source_set("browser") { "//content/public/android:jni", "//media", "//mojo/android:libsystem_java", + "//ui/android", ] libs += [ "jnigraphics" ] } diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index c070ac5..6da1273 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc @@ -165,8 +165,9 @@ bool CompositorImpl::IsInitialized() { CompositorImpl::CompositorImpl(CompositorClient* client, gfx::NativeWindow root_window) : root_layer_(cc::Layer::Create()), + resource_manager_(&ui_resource_provider_), surface_id_allocator_( - new cc::SurfaceIdAllocator(++g_surface_id_namespace)), + new cc::SurfaceIdAllocator(++g_surface_id_namespace)), has_transparent_background_(false), device_scale_factor_(1), window_(NULL), @@ -322,6 +323,10 @@ UIResourceProvider& CompositorImpl::GetUIResourceProvider() { return ui_resource_provider_; } +ui::ResourceManager& CompositorImpl::GetResourceManager() { + return resource_manager_; +} + ui::SystemUIResourceManager& CompositorImpl::GetSystemUIResourceManager() { return ui_resource_provider_.GetSystemUIResourceManager(); } diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index 0d83445..67f5d5d 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h @@ -18,6 +18,7 @@ #include "content/public/browser/android/compositor.h" #include "gpu/command_buffer/common/capabilities.h" #include "third_party/khronos/GLES2/gl2.h" +#include "ui/android/resources/resource_manager.h" #include "ui/base/android/system_ui_resource_manager.h" #include "ui/base/android/window_android_compositor.h" @@ -61,6 +62,7 @@ class CONTENT_EXPORT CompositorImpl virtual void SetHasTransparentBackground(bool flag) override; virtual void SetNeedsComposite() override; virtual UIResourceProvider& GetUIResourceProvider() override; + virtual ui::ResourceManager& GetResourceManager() override; // LayerTreeHostClient implementation. virtual void WillBeginMainFrame(int frame_id) override {} @@ -139,6 +141,7 @@ class CONTENT_EXPORT CompositorImpl scoped_ptr<cc::LayerTreeHost> host_; content::UIResourceProviderImpl ui_resource_provider_; + ui::ResourceManager resource_manager_; scoped_ptr<OnscreenDisplayClient> display_client_; scoped_ptr<cc::SurfaceIdAllocator> surface_id_allocator_; diff --git a/content/content_app.gypi b/content/content_app.gypi index c8ad3f0..d0a3296 100644 --- a/content/content_app.gypi +++ b/content/content_app.gypi @@ -46,6 +46,7 @@ 'dependencies': [ 'content.gyp:content_jni_headers', '../skia/skia.gyp:skia', + '../ui/android/ui_android.gyp:ui_android', ], 'includes': [ '../build/android/cpufeatures.gypi', diff --git a/content/content_browser.gypi b/content/content_browser.gypi index cf826c6..ea18825 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -1810,6 +1810,7 @@ 'dependencies': [ '../media/media.gyp:media', '../mojo/mojo_base.gyp:libmojo_system_java', + '../ui/android/ui_android.gyp:ui_android', 'content.gyp:content_jni_headers', ], 'defines': ['APPCACHE_USE_SIMPLE_CACHE'], diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 0224b40..7f28b16 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -355,6 +355,7 @@ }], ['OS=="android"', { 'dependencies': [ + '../ui/android/ui_android.gyp:ui_android', '../ui/shell_dialogs/shell_dialogs.gyp:shell_dialogs', 'content.gyp:content_v8_external_data', ], diff --git a/content/public/browser/android/compositor.h b/content/public/browser/android/compositor.h index 25a61c8..e7dd30e 100644 --- a/content/public/browser/android/compositor.h +++ b/content/public/browser/android/compositor.h @@ -23,6 +23,10 @@ namespace gfx { class JavaBitmap; } +namespace ui { +class ResourceManager; +} + namespace content { class CompositorClient; class UIResourceProvider; @@ -68,6 +72,9 @@ class CONTENT_EXPORT Compositor { // Returns the UI resource provider associated with the compositor. virtual UIResourceProvider& GetUIResourceProvider() = 0; + // Returns the resource manager associated with the compositor. + virtual ui::ResourceManager& GetResourceManager() = 0; + protected: Compositor() {} }; diff --git a/content/public/test/content_test_suite_base.cc b/content/public/test/content_test_suite_base.cc index afaeea7..81821b0 100644 --- a/content/public/test/content_test_suite_base.cc +++ b/content/public/test/content_test_suite_base.cc @@ -32,6 +32,7 @@ #include "content/public/browser/android/compositor.h" #include "media/base/android/media_jni_registrar.h" #include "net/android/net_jni_registrar.h" +#include "ui/android/ui_android_jni_registrar.h" #include "ui/base/android/ui_base_jni_registrar.h" #include "ui/gfx/android/gfx_jni_registrar.h" #include "ui/gl/android/gl_jni_registrar.h" @@ -84,6 +85,7 @@ void ContentTestSuiteBase::Initialize() { media::RegisterJni(env); net::android::RegisterJni(env); ui::android::RegisterJni(env); + ui::RegisterUIAndroidJni(env); ui::gl::android::RegisterJni(env); ui::shell_dialogs::RegisterJni(env); diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index eae2cd8..1aca2e2 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn @@ -127,7 +127,10 @@ static_library("test_support") { } if (is_android) { - deps += [ "//ui/shell_dialogs" ] + deps += [ + "//ui/android", + "//ui/shell_dialogs" + ] } if (is_win) { diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn index 1d4b2e1..8ee9722 100644 --- a/ui/android/BUILD.gn +++ b/ui/android/BUILD.gn @@ -2,6 +2,36 @@ import("//build/config/android/rules.gni") assert(is_android) +component("android") { + output_name = "ui_android" + sources = [ + "resources/resource_manager.cc", + "resources/resource_manager.h", + "resources/ui_resource_android.cc", + "resources/ui_resource_android.h", + "ui_android_export.h", + "ui_android_jni_registrar.cc", + "ui_android_jni_registrar.h", + ] + + defines = [ "UI_ANDROID_IMPLEMENTATION" ] + + deps = [ + "//cc", + "//skia", + "//ui/gfx", + "//ui/gfx/geometry", + ":ui_android_jni_headers", + ] +} + +generate_jni("ui_android_jni_headers") { + sources = [ + "java/src/org/chromium/ui/resources/ResourceManager.java", + ] + jni_package = "ui_android" +} + java_cpp_enum("java_enums_srcjar") { sources = [ "../base/page_transition_types.h", @@ -9,6 +39,7 @@ java_cpp_enum("java_enums_srcjar") { "../base/android/system_ui_resource_type.h", "../base/ime/text_input_type.h", "../gfx/android/java_bitmap.h", + "resources/resource_manager.h", ] outputs = [ "org/chromium/ui/WindowOpenDisposition.java", @@ -16,6 +47,7 @@ java_cpp_enum("java_enums_srcjar") { "org/chromium/ui/base/SystemUIResourceType.java", "org/chromium/ui/base/ime/TextInputType.java", "org/chromium/ui/gfx/BitmapFormat.java", + "org/chromium/ui/resources/AndroidResourceType.java", ] } diff --git a/ui/android/DEPS b/ui/android/DEPS new file mode 100644 index 0000000..c9ee84c --- /dev/null +++ b/ui/android/DEPS @@ -0,0 +1,10 @@ +include_rules = [ + "+cc/resources/ui_resource_client.h", + "+cc/resources/ui_resource_bitmap.h", + "+content/public/browser/android/ui_resource_client_android.h", + "+content/public/browser/android/ui_resource_provider.h", + "+jni", + "+skia/ext", + "+third_party/skia", + "+ui/gfx", +] diff --git a/ui/android/OWNERS b/ui/android/OWNERS index 85d8f5a..1fd40a0 100644 --- a/ui/android/OWNERS +++ b/ui/android/OWNERS @@ -2,3 +2,7 @@ jdduke@chromium.org miguelg@chromium.org newt@chromium.org tedchoc@chromium.org + +# for UI resources +dtrainor@chromium.org +jaekyun@chromium.org diff --git a/ui/android/java/src/org/chromium/ui/resources/LayoutResource.java b/ui/android/java/src/org/chromium/ui/resources/LayoutResource.java new file mode 100644 index 0000000..47e3f1f --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/resources/LayoutResource.java @@ -0,0 +1,57 @@ +// Copyright 2014 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.ui.resources; + +import android.graphics.Rect; +import android.graphics.RectF; + +/** + * A resource that provides sizing information for layouts. + */ +public class LayoutResource { + private final RectF mPadding; + private final RectF mBitmapSize; + private final RectF mAperture; + + public LayoutResource(float pxToDp, Resource resource) { + Rect padding = resource.getPadding(); + Rect bitmapSize = resource.getBitmapSize(); + Rect aperture = resource.getAperture(); + + mPadding = new RectF(padding.left * pxToDp, padding.top * pxToDp, padding.right * pxToDp, + padding.bottom * pxToDp); + + mBitmapSize = new RectF(bitmapSize.left * pxToDp, bitmapSize.top * pxToDp, + bitmapSize.right * pxToDp, bitmapSize.bottom * pxToDp); + + mAperture = new RectF(aperture.left * pxToDp, aperture.top * pxToDp, + aperture.right * pxToDp, aperture.bottom * pxToDp); + } + + /** + * @return The padded content area of this resource in dp. For 9-patches this will represent + * the valid content of the 9-patch. It can mean other things for other Resources + * though. + */ + public RectF getPadding() { + return mPadding; + } + + /** + * @return The size of the bitmap in dp; + */ + public RectF getBitmapSize() { + return mBitmapSize; + } + + /** + * @return The aperture of this resource in dp. For 9-patches this will represent the area of + * the {@link Bitmap} that should not be stretched. It can mean other things for other + * Resources though. + */ + public RectF getAperture() { + return mAperture; + } +}
\ No newline at end of file diff --git a/ui/android/java/src/org/chromium/ui/resources/Resource.java b/ui/android/java/src/org/chromium/ui/resources/Resource.java new file mode 100644 index 0000000..5884a88 --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/resources/Resource.java @@ -0,0 +1,38 @@ +// Copyright 2014 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.ui.resources; + +import android.graphics.Bitmap; +import android.graphics.Rect; + +/** + * A basic resource interface that all assets must use to be exposed to the CC layer as + * UIResourceIds. + */ +public interface Resource { + /** + * This may be called more than once so if possible avoid doing redundant work. + * @return A {@link Bitmap} representing the resource. + */ + Bitmap getBitmap(); + + /** + * @return The size of the bitmap. + */ + Rect getBitmapSize(); + + /** + * @return The padded content area of this resource. For 9-patches this will represent the + * valid content of the 9-patch. It can mean other things for other Resources though. + */ + Rect getPadding(); + + /** + * @return The aperture of this resource. For 9-patches this will represent the area of the + * {@link Bitmap} that should not be stretched. It can mean other things for other + * Resources though. + */ + Rect getAperture(); +}
\ No newline at end of file diff --git a/ui/android/java/src/org/chromium/ui/resources/ResourceLoader.java b/ui/android/java/src/org/chromium/ui/resources/ResourceLoader.java new file mode 100644 index 0000000..eef765e --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/resources/ResourceLoader.java @@ -0,0 +1,71 @@ +// Copyright 2014 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.ui.resources; + +/** + * A class responsible for loading {@link Resource}s for the {@link ResourceManager}. + */ +public abstract class ResourceLoader { + /** + * A callback that specifies when a {@link Resource} has been loaded and can be exposed to the + * CC layer. + */ + public interface ResourceLoaderCallback { + /** + * Called when a resource as finished loading. Note that it is up to the caller to recycle + * any {@link android.graphics.Bitmap}s or clean up any state after making this call. + * @param resType The {@link ResourceType} that loaded the resource. + * @param resId The Android id of the loaded resource. + * @param resource The {@link Resource} of the resource, or {@code null} if one could + * not be loaded. + */ + void onResourceLoaded(int resType, int resId, Resource resource); + } + + private final int mResourceType; + private final ResourceLoaderCallback mCallback; + + /** + * Creates an instance of a {@link ResourceLoader}. + * @param resourceType The resource type category this {@link ResourceLoader} is loading. + * @param callback The {@link ResourceLoaderCallback} to notify when a {@link Resource} is + * loaded. + */ + public ResourceLoader(int resourceType, ResourceLoaderCallback callback) { + mResourceType = resourceType; + mCallback = callback; + } + + /** + * @return What resource type this {@link ResourceLoader} is responsible for loading. + */ + public int getResourceType() { + return mResourceType; + } + + /** + * Requests that a resource specified by {@code resId} be loaded from this + * {@link ResourceLoader}. This may or may not actually load the resource and notify the + * {@link ResourceLoaderCallback} depending on the internal behavior of the particular loader. + * @param resId The id of the {@link Resource} to load. + */ + public abstract void loadResource(int resId); + + /** + * Requests that a resource be pre-loaded. This will typically happen asynchronously. + * @param resId The id of the {@link Resource} to load. + */ + public abstract void preloadResource(int resId); + + /** + * A helper method for subclasses to notify that the {@link Resource} specified by {@code resId} + * is done loading. + * @param resId The id of the {@link Resource} that loaded or failed. + * @param resource The {@link Resource}, or {@code null} if the load failed. + */ + protected void notifyLoadFinished(int resId, Resource resource) { + if (mCallback != null) mCallback.onResourceLoaded(getResourceType(), resId, resource); + } +} diff --git a/ui/android/java/src/org/chromium/ui/resources/ResourceManager.java b/ui/android/java/src/org/chromium/ui/resources/ResourceManager.java new file mode 100644 index 0000000..d6574fe --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/resources/ResourceManager.java @@ -0,0 +1,169 @@ +// Copyright 2014 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.ui.resources; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Rect; +import android.util.SparseArray; + +import org.chromium.base.CalledByNative; +import org.chromium.base.JNINamespace; +import org.chromium.ui.resources.ResourceLoader.ResourceLoaderCallback; +import org.chromium.ui.resources.dynamics.DynamicResource; +import org.chromium.ui.resources.dynamics.DynamicResourceLoader; +import org.chromium.ui.resources.statics.StaticResourceLoader; +import org.chromium.ui.resources.system.SystemResourceLoader; + +/** + * The Java component of a manager for all static resources to be loaded and used by CC layers. + * This class does not hold any resource state, but passes it directly to native as they are loaded. + */ +@JNINamespace("ui") +public class ResourceManager implements ResourceLoaderCallback { + private final SparseArray<ResourceLoader> mResourceLoaders = new SparseArray<ResourceLoader>(); + private final SparseArray<SparseArray<LayoutResource>> mLoadedResources = + new SparseArray<SparseArray<LayoutResource>>(); + + private final float mPxToDp; + + private long mNativeResourceManagerPtr; + + private ResourceManager(Context context, long staticResourceManagerPtr) { + Resources resources = context.getResources(); + mPxToDp = 1.f / resources.getDisplayMetrics().density; + + // Register ResourceLoaders + registerResourceLoader(new StaticResourceLoader( + AndroidResourceType.STATIC, this, resources)); + registerResourceLoader(new DynamicResourceLoader( + AndroidResourceType.DYNAMIC, this)); + registerResourceLoader(new DynamicResourceLoader( + AndroidResourceType.DYNAMIC_BITMAP, this)); + registerResourceLoader(new SystemResourceLoader( + AndroidResourceType.SYSTEM, this, context)); + + mNativeResourceManagerPtr = staticResourceManagerPtr; + } + + /** + * Creates an instance of a {@link ResourceManager}. This will + * @param context A {@link Context} instance to grab {@link Resources} from. + * @param staticResourceManagerPtr A pointer to the native component of this class. + * @return A new instance of a {@link ResourceManager}. + */ + @CalledByNative + private static ResourceManager create(Context context, long staticResourceManagerPtr) { + return new ResourceManager(context, staticResourceManagerPtr); + } + + /** + * @return A reference to the {@link DynamicResourceLoader} that provides + * {@link DynamicResource} objects to this class. + */ + public DynamicResourceLoader getDynamicResourceLoader() { + return (DynamicResourceLoader) mResourceLoaders.get( + AndroidResourceType.DYNAMIC); + } + + /** + * @return A reference to the {@link DynamicResourceLoader} for bitmaps that provides + * {@link BitmapDynamicResource} objects to this class. + */ + public DynamicResourceLoader getBitmapDynamicResourceLoader() { + return (DynamicResourceLoader) mResourceLoaders.get( + AndroidResourceType.DYNAMIC_BITMAP); + } + + /** + * Automatically loads any synchronous resources specified in |syncIds| and will start + * asynchronous reads for any asynchronous resources specified in |asyncIds|. + * @param type AndroidResourceType which will be loaded. + * @param syncIds Resource ids which will be loaded synchronously. + * @param asyncIds Resource ids which will be loaded asynchronously. + */ + public void preloadResources(int type, int[] syncIds, int[] asyncIds) { + ResourceLoader loader = mResourceLoaders.get(type); + if (asyncIds != null) { + for (Integer resId : asyncIds) { + loader.preloadResource(resId); + } + } + + if (syncIds != null) { + for (Integer resId : syncIds) { + loader.loadResource(resId); + } + } + } + + /** + * @param resType The type of the Android resource. + * @param resId The id of the Android resource. + * @return The corresponding {@link LayoutResource}. + */ + public LayoutResource getResource(int resType, int resId) { + SparseArray<LayoutResource> bucket = mLoadedResources.get(resType); + return bucket != null ? bucket.get(resId) : null; + } + + @Override + public void onResourceLoaded(int resType, int resId, Resource resource) { + if (resource == null) return; + + saveMetadataForLoadedResource(resType, resId, resource); + + if (mNativeResourceManagerPtr == 0) return; + Rect padding = resource.getPadding(); + Rect aperture = resource.getAperture(); + + nativeOnResourceReady(mNativeResourceManagerPtr, resType, resId, resource.getBitmap(), + padding.left, padding.top, padding.right, padding.bottom, + aperture.left, aperture.top, aperture.right, aperture.bottom); + } + + private void saveMetadataForLoadedResource(int resType, int resId, Resource resource) { + SparseArray<LayoutResource> bucket = mLoadedResources.get(resType); + if (bucket == null) { + bucket = new SparseArray<LayoutResource>(); + mLoadedResources.put(resType, bucket); + } + bucket.put(resId, new LayoutResource(mPxToDp, resource)); + } + + @CalledByNative + private void destroy() { + assert mNativeResourceManagerPtr != 0; + mNativeResourceManagerPtr = 0; + } + + @CalledByNative + private void resourceRequested(int resType, int resId) { + ResourceLoader loader = mResourceLoaders.get(resType); + if (loader != null) loader.loadResource(resId); + } + + @CalledByNative + private void preloadResource(int resType, int resId) { + ResourceLoader loader = mResourceLoaders.get(resType); + if (loader != null) loader.preloadResource(resId); + } + + @CalledByNative + private long getNativePtr() { + return mNativeResourceManagerPtr; + } + + private void registerResourceLoader(ResourceLoader loader) { + mResourceLoaders.put(loader.getResourceType(), loader); + } + + private native void nativeOnResourceReady(long nativeResourceManager, int resType, + int resId, Bitmap bitmap, int paddingLeft, int paddingTop, int paddingRight, + int paddingBottom, int apertureLeft, int apertureTop, int apertureRight, + int apertureBottom); + +}
\ No newline at end of file diff --git a/ui/android/java/src/org/chromium/ui/resources/async/AsyncPreloadResourceLoader.java b/ui/android/java/src/org/chromium/ui/resources/async/AsyncPreloadResourceLoader.java new file mode 100644 index 0000000..fb27244 --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/resources/async/AsyncPreloadResourceLoader.java @@ -0,0 +1,116 @@ +// Copyright 2014 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.ui.resources.async; + +import android.os.AsyncTask; +import android.util.SparseArray; + +import org.chromium.ui.resources.Resource; +import org.chromium.ui.resources.ResourceLoader; + +import java.util.concurrent.ExecutionException; + +/** + * Handles loading Android resources from disk asynchronously and synchronously. + */ +public class AsyncPreloadResourceLoader extends ResourceLoader { + /** + * Responsible for actually creating a {@link Resource} from a specific resource id. + */ + public interface ResourceCreator { + /** + * Creates a {@link Resource} from {@code resId}. Note that this method may be called from + * a background thread. No assumptions can be made on which thread this will be called + * from! + * @param resId The id of the resource to load. + * @return A {@link Resource} instance that represents {@code resId} or {@code null} if + * none can be loaded. + */ + Resource create(int resId); + } + + private final SparseArray<AsyncLoadTask> mOutstandingLoads = new SparseArray<AsyncLoadTask>(); + private final ResourceCreator mCreator; + + /** + * Creates a {@link AsyncPreloadResourceLoader}. + * @param resourceType The resource type this loader is responsible for loading. + * @param callback The {@link ResourceLoaderCallback} to notify when a {@link Resource} is + * done loading. + * @param creator A {@link ResourceCreator} instance that will be used to create the + * {@link Resource}s. + */ + public AsyncPreloadResourceLoader(int resourceType, ResourceLoaderCallback callback, + ResourceCreator creator) { + super(resourceType, callback); + mCreator = creator; + } + + /** + * Loads a resource synchronously. This will still call the {@link ResourceLoaderCallback} on + * completion. If the resource is currently being loaded asynchronously this will wait for that + * task to complete before returning. If the resource is queued to be read asynchronously later + * this will cancel that request. + * @param resId The Android resource id to load. + */ + @Override + public void loadResource(int resId) { + AsyncLoadTask task = mOutstandingLoads.get(resId); + + if (task != null) { + if (!task.cancel(false)) { + try { + registerResource(task.get(), resId); + } catch (InterruptedException e) { + notifyLoadFinished(resId, null); + } catch (ExecutionException e) { + notifyLoadFinished(resId, null); + } + return; + } + } + registerResource(mCreator.create(resId), resId); + } + + /** + * Loads a resource asynchronously. The load will be queued if other resources are currently + * being loaded. The {@link ResourceLoaderCallback} will be notified on completion. + * @param resId The Android resource id to load. + */ + @Override + public void preloadResource(int resId) { + if (mOutstandingLoads.get(resId) != null) return; + AsyncLoadTask task = new AsyncLoadTask(resId); + task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); + mOutstandingLoads.put(resId, task); + } + + private void registerResource(Resource resource, int resourceId) { + notifyLoadFinished(resourceId, resource); + if (resource != null) resource.getBitmap().recycle(); + mOutstandingLoads.remove(resourceId); + } + + private class AsyncLoadTask extends AsyncTask<Void, Void, Resource> { + private final int mResourceId; + + public AsyncLoadTask(int resourceId) { + mResourceId = resourceId; + } + + @Override + protected Resource doInBackground(Void... params) { + return mCreator.create(mResourceId); + } + + @Override + protected void onPostExecute(Resource resource) { + // If we've been removed from the list of outstanding load tasks, don't broadcast the + // callback. + if (mOutstandingLoads.get(mResourceId) == null) return; + registerResource(resource, mResourceId); + } + } +}
\ No newline at end of file diff --git a/ui/android/java/src/org/chromium/ui/resources/dynamics/BitmapDynamicResource.java b/ui/android/java/src/org/chromium/ui/resources/dynamics/BitmapDynamicResource.java new file mode 100644 index 0000000..4d5b501 --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/resources/dynamics/BitmapDynamicResource.java @@ -0,0 +1,66 @@ +// Copyright 2014 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.ui.resources.dynamics; + +import android.graphics.Bitmap; +import android.graphics.Rect; + +/** + * A basic implementation of {@link DynamicResource} to handle updatable bitmaps. + */ +public class BitmapDynamicResource implements DynamicResource { + private static final Rect EMPTY_RECT = new Rect(); + + private final int mResId; + private Bitmap mBitmap; + private final Rect mSize = new Rect(); + private boolean mIsDirty = true; + + public BitmapDynamicResource(int resourceId) { + mResId = resourceId; + } + + /** + * @return A unique id for this resource. + */ + public int getResId() { + return mResId; + } + + /** + * @param bitmap A bitmap to update this resource. + */ + public void setBitmap(Bitmap bitmap) { + mIsDirty = true; + mBitmap = bitmap; + mSize.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); + } + + @Override + public Bitmap getBitmap() { + mIsDirty = false; + return mBitmap; + } + + @Override + public Rect getBitmapSize() { + return mSize; + } + + @Override + public Rect getPadding() { + return EMPTY_RECT; + } + + @Override + public Rect getAperture() { + return EMPTY_RECT; + } + + @Override + public boolean isDirty() { + return mIsDirty; + } +} diff --git a/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResource.java b/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResource.java new file mode 100644 index 0000000..c31e25b --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResource.java @@ -0,0 +1,24 @@ +// Copyright 2014 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.ui.resources.dynamics; + +import org.chromium.ui.resources.Resource; + +/** + * A representation of a dynamic resource. The contents of the resource might change from frame to + * frame. + */ +public interface DynamicResource extends Resource { + /** + * Note that this is called for every access to the resource during a frame. If a resource is + * dirty, it should not be dirty again during the same looper call. + * + * TODO(dtrainor): Add checks so that a dynamic resource **can't** be built more than once each + * frame. + * + * @return Whether or not this resource is dirty and the CC component should be rebuilt. + */ + boolean isDirty(); +}
\ No newline at end of file diff --git a/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceLoader.java b/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceLoader.java new file mode 100644 index 0000000..6145cae --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceLoader.java @@ -0,0 +1,69 @@ +// Copyright 2014 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.ui.resources.dynamics; + +import android.util.SparseArray; + +import org.chromium.ui.resources.ResourceLoader; + +/** + * Handles managing dynamic resources. This is basically a list of dynamic resources that checks + * {@link DynamicResource#isDirty()} before notifying the {@link ResourceLoaderCallback}. + */ +public class DynamicResourceLoader extends ResourceLoader { + private final SparseArray<DynamicResource> mDynamicResources = + new SparseArray<DynamicResource>(); + + /** + * Builds a {@link DynamicResourceLoader} instance. + * @param resourceType The resource type this loader is responsible for loading. + * @param callback A {@link ResourceLoaderCallback} to be notified when the dynamic resource + * has changed. The callback will only be notified if + * {@link #loadResource(int)} is called. + */ + public DynamicResourceLoader(int resourceType, ResourceLoaderCallback callback) { + super(resourceType, callback); + } + + /** + * Registers a {@link DynamicResource} to be tracked and exposed by this class. + * @param resId The Android id to use. This should be an actual Android id (R.id.some_id). + * @param resource The {@link DynamicResource} to track and expose. + */ + public void registerResource(int resId, DynamicResource resource) { + assert mDynamicResources.get(resId) == null; + mDynamicResources.put(resId, resource); + } + + /** + * Unregisters a {@link DynamicResource} specified by {@code resId}. + * @param resId The Android id representing the {@link DynamicResource}. + */ + public void unregisterResource(int resId) { + mDynamicResources.remove(resId); + } + + /** + * Called when a {@link DynamicResource} was requested. This will notify the + * {@link ResourceLoaderCallback} if the resource has new contents. + * @param resId The Android id representing the {@link DynamicResource}. + */ + @Override + public void loadResource(int resId) { + DynamicResource resource = mDynamicResources.get(resId); + if (resource == null) return; + + if (resource.isDirty()) notifyLoadFinished(resId, resource); + } + + /** + * Since this class relies solely on registration it does not support preloading resources. + */ + @Override + public void preloadResource(int resId) { + // Not implemented. + assert false : "Preloading dynamic resources isn't supported."; + } +}
\ No newline at end of file diff --git a/ui/android/java/src/org/chromium/ui/resources/dynamics/ViewResourceAdapter.java b/ui/android/java/src/org/chromium/ui/resources/dynamics/ViewResourceAdapter.java new file mode 100644 index 0000000..13b8179 --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/resources/dynamics/ViewResourceAdapter.java @@ -0,0 +1,164 @@ +// Copyright 2014 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.ui.resources.dynamics; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.view.View; +import android.view.View.OnLayoutChangeListener; + +import org.chromium.base.TraceEvent; + +/** + * An adapter that exposes a {@link View} as a {@link DynamicResource}. In order to properly use + * this adapter {@link ViewResourceAdapter#invalidate(Rect)} must be called when parts of the + * {@link View} are invalidated. For {@link ViewGroup}s the easiest way to do this is to override + * {@link View#invalidateChildInParent(int[], Rect)}. + */ +public class ViewResourceAdapter implements DynamicResource, OnLayoutChangeListener { + private final View mView; + private final Rect mDirtyRect = new Rect(); + private final Rect mContentPadding = new Rect(); + private final Rect mContentAperture = new Rect(); + + private Bitmap mBitmap; + private Rect mBitmapSize = new Rect(); + + /** + * Builds a {@link ViewResourceAdapter} instance around {@code view}. + * @param view The {@link View} to expose as a {@link Resource}. + */ + public ViewResourceAdapter(View view) { + mView = view; + mView.addOnLayoutChangeListener(this); + } + + /** + * If this resource is not dirty ({@link #isDirty()} returned {@code false}), this will return + * the last {@link Bitmap} built from the {@link View}. Otherwise it will recapture a + * {@link Bitmap} of the {@link View}. + * @see {@link DynamicResource#getBitmap()}. + * @return A {@link Bitmap} representing the {@link View}. + */ + @Override + public Bitmap getBitmap() { + if (!isDirty()) return mBitmap; + TraceEvent.begin("ViewResourceAdapter:getBitmap"); + validateBitmap(); + + Canvas canvas = new Canvas(mBitmap); + + onCaptureStart(canvas, mDirtyRect.isEmpty() ? null : mDirtyRect); + + if (!mDirtyRect.isEmpty()) canvas.clipRect(mDirtyRect); + mView.draw(canvas); + + onCaptureEnd(); + + mDirtyRect.setEmpty(); + TraceEvent.end("ViewResourceAdapter:getBitmap"); + return mBitmap; + } + + @Override + public Rect getBitmapSize() { + return mBitmapSize; + } + + @Override + public Rect getPadding() { + computeContentPadding(mContentPadding); + + return mContentPadding; + } + + @Override + public Rect getAperture() { + computeContentAperture(mContentAperture); + + return mContentAperture; + } + + @Override + public boolean isDirty() { + if (mBitmap == null) mDirtyRect.set(0, 0, mView.getWidth(), mView.getHeight()); + + return !mDirtyRect.isEmpty(); + } + + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, + int oldTop, int oldRight, int oldBottom) { + final int width = right - left; + final int height = bottom - top; + final int oldWidth = oldRight - oldLeft; + final int oldHeight = oldBottom - oldTop; + + if (width != oldWidth || height != oldHeight) mDirtyRect.set(0, 0, width, height); + } + + /** + * Invalidates a particular region of the {@link View} that needs to be repainted. + * @param dirtyRect The region to invalidate, or {@code null} if the entire {@code Bitmap} + * should be redrawn. + */ + public void invalidate(Rect dirtyRect) { + if (dirtyRect == null) { + mDirtyRect.set(0, 0, mView.getWidth(), mView.getHeight()); + } else { + mDirtyRect.union(dirtyRect); + } + } + + /** + * Called before {@link View#draw(Canvas)} is called. + * @param canvas The {@link Canvas} that will be drawn to. + * @param dirtyRect The dirty {@link Rect} or {@code null} if the entire area is being redrawn. + */ + protected void onCaptureStart(Canvas canvas, Rect dirtyRect) { + } + + /** + * Called after {@link View#draw(Canvas)}. + */ + protected void onCaptureEnd() { + } + + /** + * Gives overriding classes the chance to specify a different content padding. + * @param outContentPadding The resulting content padding. + */ + protected void computeContentPadding(Rect outContentPadding) { + outContentPadding.set(0, 0, mView.getWidth(), mView.getHeight()); + } + + /** + * Gives overriding classes the chance to specify a different content aperture. + * @param outContentAperture The resulting content aperture. + */ + protected void computeContentAperture(Rect outContentAperture) { + outContentAperture.set(0, 0, mView.getWidth(), mView.getHeight()); + } + + private void validateBitmap() { + if (mBitmap != null + && (mBitmap.getWidth() != mView.getWidth() + || mBitmap.getHeight() != mView.getHeight())) { + mBitmap.recycle(); + mBitmap = null; + } + + if (mView.getWidth() == 0 || mView.getHeight() == 0) return; + + if (mBitmap == null) { + mBitmap = Bitmap.createBitmap( + mView.getWidth(), mView.getHeight(), Bitmap.Config.ARGB_8888); + mBitmap.setHasAlpha(true); + mDirtyRect.set(0, 0, mView.getWidth(), mView.getHeight()); + mBitmapSize.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); + } + } +}
\ No newline at end of file diff --git a/ui/android/java/src/org/chromium/ui/resources/statics/NinePatchData.java b/ui/android/java/src/org/chromium/ui/resources/statics/NinePatchData.java new file mode 100644 index 0000000..2c04bec --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/resources/statics/NinePatchData.java @@ -0,0 +1,136 @@ +// Copyright 2014 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.ui.resources.statics; + +import android.graphics.Bitmap; +import android.graphics.NinePatch; +import android.graphics.Rect; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * A helper class to decode and expose relevant 9-patch data from a Bitmap. + */ +class NinePatchData { + private final int mWidth; + private final int mHeight; + private final Rect mPadding; + private final int[] mDivX; + private final int[] mDivY; + + private Rect mAperture; + + /** + * Creates a {@link NinePatchData} that stores 9-patch metadata. + * @param width The width of the underlying bitmap. + * @param height The height of the underlying bitmap. + * @param padding The padding of the 9-patch for the content area. This padding is a set of + * insets (left = left padding, top = top padding, right = right padding, + * bottom = bottom padding). + * @param divX A run-length encoded list of stretch regions along the x dimension. The + * regions will go from 0 -> divX[0] - 1, divX[0] -> divX[1] - 1, etc.. + * @param divY A run-length encoded list of stretch regions along the y dimension. The + * regions will go from 0 -> divY[0] - 1, divY[0] -> divY[1] - 1, etc.. + */ + private NinePatchData(int width, int height, Rect padding, int[] divX, int[] divY) { + mWidth = width; + mHeight = height; + mPadding = new Rect( + padding.left, padding.top, mWidth - padding.right, mHeight - padding.bottom); + + mDivX = new int[divX.length]; + mDivY = new int[divY.length]; + + System.arraycopy(divX, 0, mDivX, 0, divX.length); + System.arraycopy(divY, 0, mDivY, 0, divY.length); + + mAperture = new Rect(mDivX[0], mDivY[0], mDivX[1], mDivY[1]); + } + + /** + * @return The padded content area of this 9-patch. + */ + public Rect getPadding() { + return mPadding; + } + + /** + * This class only exposes one 9-patch stretch region. + * @return The aperture of this 9-patch. This specifies the center of the 9-patch, with the + * surrounding areas being stretchable. + */ + public Rect getAperture() { + return mAperture; + } + + /** + * Attempts to decode 9-patch data from a {@link Bitmap}. + * @param bitmap The {@link Bitmap} to check. + * @return An instance of {@link NinePatchData} representing the 9-patch information + * encoded in {@code bitmap} or {@code null} if the {@link Bitmap} wasn't a + * 9-patch. + */ + public static NinePatchData create(Bitmap bitmap) { + if (bitmap == null) return null; + + try { + byte[] chunk = bitmap.getNinePatchChunk(); + if (chunk == null || !NinePatch.isNinePatchChunk(chunk)) return null; + + ByteBuffer buffer = ByteBuffer.wrap(chunk).order(ByteOrder.nativeOrder()); + + // int8_t wasDeserialized + if (buffer.get() == 0) return null; + + // int8_t numXDivs + int numDivX = buffer.get(); + if (numDivX == 0 || (numDivX & 0x01) != 0) return null; + + // int8_t numYDivs + int numDivY = buffer.get(); + if (numDivY == 0 || (numDivY & 0x01) != 0) return null; + + // int8_t numColors + buffer.get(); + + // uint32_t xDivsOffset + buffer.getInt(); + + // uint32_t yDivsOffset + buffer.getInt(); + + Rect padding = new Rect(); + + // uint32_t paddingLeft + padding.left = buffer.getInt(); + + // uint32_t paddingRight + padding.right = buffer.getInt(); + + // uint32_t paddingTop + padding.top = buffer.getInt(); + + // uint32_t paddingBottom + padding.bottom = buffer.getInt(); + + // uint32_t colorsOffset + buffer.getInt(); + + // uint32_t uint32_t uint32_t ... + int[] divX = new int[numDivX]; + for (int i = 0; i < numDivX; i++) divX[i] = buffer.getInt(); + + // uint32_t uint32_t uint32_t ... + int[] divY = new int[numDivY]; + for (int i = 0; i < numDivY; i++) divY[i] = buffer.getInt(); + + return new NinePatchData(bitmap.getWidth(), bitmap.getHeight(), padding, divX, divY); + } catch (BufferUnderflowException ex) { + return null; + } + } +}
\ No newline at end of file diff --git a/ui/android/java/src/org/chromium/ui/resources/statics/StaticResource.java b/ui/android/java/src/org/chromium/ui/resources/statics/StaticResource.java new file mode 100644 index 0000000..26a9155 --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/resources/statics/StaticResource.java @@ -0,0 +1,132 @@ +// Copyright 2014 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.ui.resources.statics; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import org.chromium.ui.resources.Resource; + +/** + * A representation of a static resource and all related information for drawing it. In general + * this means a {@link Bitmap} and a potential {@link NinePatchData}. + */ +public class StaticResource implements Resource { + private final Bitmap mBitmap; + private final NinePatchData mNinePatchData; + private final Rect mBitmapSize; + + /** + * Creates a {@link StaticResource} that represents {@code bitmap}. This will automatically + * pull out the {@link NinePatchData} from {@code bitmap} if it exists. + * @param bitmap The {@link Bitmap} to build a {@link StaticResource} of. + */ + public StaticResource(Bitmap bitmap) { + mBitmap = bitmap; + mNinePatchData = NinePatchData.create(mBitmap); + mBitmapSize = new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); + } + + @Override + public Bitmap getBitmap() { + return mBitmap; + } + + @Override + public Rect getBitmapSize() { + return mBitmapSize; + } + + @Override + public Rect getPadding() { + return mNinePatchData != null ? mNinePatchData.getPadding() : mBitmapSize; + } + + @Override + public Rect getAperture() { + return mNinePatchData != null ? mNinePatchData.getAperture() : mBitmapSize; + } + + /** + * Attempts to load the Android resource specified by {@code resId} from {@code resources}. + * This will attempt to first load the resource as a {@code Bitmap}. If that fails it will try + * to load the resource as a {@link Drawable}. + * @param resources The {@link Resources} instance to load from. + * @param resId The id of the Android resource to load. + * @param fitWidth The smallest width the image can be. The image will be shrunk to scale to + * try to get close to this value. Or use {@code 0} to use the intrinsic + * size. + * @param fitHeight The smallest height the image can be. The image will be shrunk to scale to + * try to get close to this value. Or use {@code 0} to use the intrinsic + * size. + * @return The loaded {@link StaticResource} or {@code null} if the resource could not + * be loaded. + */ + public static StaticResource create(Resources resources, int resId, int fitWidth, + int fitHeight) { + if (resId <= 0) return null; + Bitmap bitmap = decodeBitmap(resources, resId, fitWidth, fitHeight); + if (bitmap == null) bitmap = decodeDrawable(resources, resId, fitWidth, fitHeight); + if (bitmap == null) return null; + + return new StaticResource(bitmap); + } + + private static Bitmap decodeBitmap(Resources resources, int resId, int fitWidth, + int fitHeight) { + BitmapFactory.Options options = createOptions(resources, resId, fitWidth, fitHeight); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + Bitmap bitmap = BitmapFactory.decodeResource(resources, resId, options); + + if (bitmap == null) return null; + if (bitmap.getConfig() == options.inPreferredConfig) return bitmap; + + Bitmap convertedBitmap = Bitmap.createBitmap( + bitmap.getWidth(), bitmap.getHeight(), options.inPreferredConfig); + Canvas canvas = new Canvas(convertedBitmap); + canvas.drawBitmap(bitmap, 0, 0, null); + bitmap.recycle(); + return convertedBitmap; + } + + private static Bitmap decodeDrawable(Resources resources, int resId, int fitWidth, + int fitHeight) { + try { + Drawable drawable = resources.getDrawable(resId); + int width = Math.max(drawable.getMinimumWidth(), Math.max(fitWidth, 1)); + int height = Math.max(drawable.getMinimumHeight(), Math.max(fitHeight, 1)); + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, width, height); + drawable.draw(canvas); + return bitmap; + } catch (Resources.NotFoundException ex) { + return null; + } + } + + private static BitmapFactory.Options createOptions(Resources resources, int resId, + int fitWidth, int fitHeight) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + if (fitWidth == 0 || fitHeight == 0) return options; + + options.inJustDecodeBounds = true; + BitmapFactory.decodeResource(resources, resId, options); + options.inJustDecodeBounds = false; + + if (options.outHeight <= fitHeight && options.outWidth <= fitWidth) return options; + + int heightRatio = Math.round((float) options.outHeight / (float) fitHeight); + int widthRatio = Math.round((float) options.outWidth / (float) fitWidth); + options.inSampleSize = Math.min(heightRatio, widthRatio); + + return options; + } +}
\ No newline at end of file diff --git a/ui/android/java/src/org/chromium/ui/resources/statics/StaticResourceLoader.java b/ui/android/java/src/org/chromium/ui/resources/statics/StaticResourceLoader.java new file mode 100644 index 0000000..3444188 --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/resources/statics/StaticResourceLoader.java @@ -0,0 +1,32 @@ +// Copyright 2014 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.ui.resources.statics; + +import android.content.res.Resources; + +import org.chromium.ui.resources.Resource; +import org.chromium.ui.resources.async.AsyncPreloadResourceLoader; + +/** + * Handles loading Android resources from disk asynchronously and synchronously. + */ +public class StaticResourceLoader extends AsyncPreloadResourceLoader { + /** + * Creates a {@link StaticResourceLoader}. + * @param resourceType The resource type this loader is responsible for loading. + * @param callback The {@link ResourceLoaderCallback} to notify when a {@link Resource} is + * done loading. + * @param resources The {@link Resources} instance to load Android resources from. + */ + public StaticResourceLoader(int resourceType, ResourceLoaderCallback callback, + final Resources resources) { + super(resourceType, callback, new ResourceCreator() { + @Override + public Resource create(int resId) { + return StaticResource.create(resources, resId, 0, 0); + } + }); + } +}
\ No newline at end of file diff --git a/ui/android/java/src/org/chromium/ui/resources/system/SystemResourceLoader.java b/ui/android/java/src/org/chromium/ui/resources/system/SystemResourceLoader.java new file mode 100644 index 0000000..cae57f6 --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/resources/system/SystemResourceLoader.java @@ -0,0 +1,93 @@ +// Copyright 2014 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.ui.resources.system; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Paint.Style; +import android.graphics.RectF; + +import org.chromium.ui.base.SystemUIResourceType; +import org.chromium.ui.gfx.DeviceDisplayInfo; +import org.chromium.ui.resources.Resource; +import org.chromium.ui.resources.async.AsyncPreloadResourceLoader; +import org.chromium.ui.resources.statics.StaticResource; + +/** + * Handles loading system specific resources like overscroll and edge glows. + */ +public class SystemResourceLoader extends AsyncPreloadResourceLoader { + private static final float SIN_PI_OVER_6 = 0.5f; + private static final float COS_PI_OVER_6 = 0.866f; + + /** + * Creates an instance of a {@link SystemResourceLoader}. + * @param resourceType The resource type this loader is responsible for loading. + * @param callback The {@link ResourceLoaderCallback} to notify when a {@link Resource} is + * done loading. + * @param resources A {@link Resources} instance to load assets from. + */ + public SystemResourceLoader(int resourceType, ResourceLoaderCallback callback, + final Context context) { + super(resourceType, callback, new ResourceCreator() { + @Override + public Resource create(int resId) { + return createResource(context, resId); + } + }); + } + + private static Resource createResource(Context context, int resId) { + switch (resId) { + case SystemUIResourceType.OVERSCROLL_EDGE: + return StaticResource.create(Resources.getSystem(), + getResourceId("android:drawable/overscroll_edge"), 128, 12); + case SystemUIResourceType.OVERSCROLL_GLOW: + return StaticResource.create(Resources.getSystem(), + getResourceId("android:drawable/overscroll_glow"), 128, 64); + case SystemUIResourceType.OVERSCROLL_GLOW_L: + return createOverscrollGlowLBitmap(context); + } + return null; + } + + private static Resource createOverscrollGlowLBitmap(Context context) { + DeviceDisplayInfo displayInfo = DeviceDisplayInfo.create(context); + int screenWidth = displayInfo.getPhysicalDisplayWidth() != 0 + ? displayInfo.getPhysicalDisplayWidth() : displayInfo.getDisplayWidth(); + int screenHeight = displayInfo.getPhysicalDisplayHeight() != 0 + ? displayInfo.getPhysicalDisplayHeight() : displayInfo.getDisplayHeight(); + + float arcWidth = Math.min(screenWidth, screenHeight) * 0.5f / SIN_PI_OVER_6; + float y = COS_PI_OVER_6 * arcWidth; + float height = arcWidth - y; + + float arcRectX = -arcWidth / 2.f; + float arcRectY = -arcWidth - y; + float arcRectWidth = arcWidth * 2.f; + float arcRectHeight = arcWidth * 2.f; + RectF arcRect = new RectF( + arcRectX, arcRectY, arcRectX + arcRectWidth, arcRectY + arcRectHeight); + + Paint arcPaint = new Paint(); + arcPaint.setAntiAlias(true); + arcPaint.setAlpha(0xBB); + arcPaint.setStyle(Style.FILL); + + Bitmap bitmap = Bitmap.createBitmap((int) arcWidth, (int) height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + canvas.drawArc(arcRect, 45, 90, true, arcPaint); + + return new StaticResource(bitmap); + } + + private static int getResourceId(String name) { + Resources systemResources = Resources.getSystem(); + return systemResources.getIdentifier(name, null, null); + } +}
\ No newline at end of file diff --git a/ui/android/resources/resource_manager.cc b/ui/android/resources/resource_manager.cc new file mode 100644 index 0000000..557661f --- /dev/null +++ b/ui/android/resources/resource_manager.cc @@ -0,0 +1,138 @@ +// Copyright 2014 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 "ui/android/resources/resource_manager.h" + +#include "content/public/browser/android/ui_resource_provider.h" +#include "jni/ResourceManager_jni.h" +#include "ui/android/resources/ui_resource_android.h" +#include "ui/gfx/android/java_bitmap.h" +#include "ui/gfx/geometry/insets_f.h" + +namespace ui { + +ResourceManager::Resource::Resource() { +} + +ResourceManager::Resource::~Resource() { +} + +gfx::Rect ResourceManager::Resource::Border(const gfx::Size& bounds) { + return Border(bounds, gfx::InsetsF(1.f, 1.f, 1.f, 1.f)); +} + +gfx::Rect ResourceManager::Resource::Border(const gfx::Size& bounds, + const gfx::InsetsF& scale) { + // Calculate whether or not we need to scale down the border if the bounds of + // the layer are going to be smaller than the aperture padding. + float x_scale = std::min((float)bounds.width() / size.width(), 1.f); + float y_scale = std::min((float)bounds.height() / size.height(), 1.f); + + float left_scale = std::min(x_scale * scale.left(), 1.f); + float right_scale = std::min(x_scale * scale.right(), 1.f); + float top_scale = std::min(y_scale * scale.top(), 1.f); + float bottom_scale = std::min(y_scale * scale.bottom(), 1.f); + + return gfx::Rect(aperture.x() * left_scale, aperture.y() * top_scale, + (size.width() - aperture.width()) * right_scale, + (size.height() - aperture.height()) * bottom_scale); +} + +// static +ResourceManager* ResourceManager::FromJavaObject(jobject jobj) { + return reinterpret_cast<ResourceManager*>(Java_ResourceManager_getNativePtr( + base::android::AttachCurrentThread(), jobj)); +} + +ResourceManager::ResourceManager( + content::UIResourceProvider* ui_resource_provider) + : ui_resource_provider_(ui_resource_provider) { + JNIEnv* env = base::android::AttachCurrentThread(); + java_obj_.Reset(env, Java_ResourceManager_create( + env, base::android::GetApplicationContext(), + reinterpret_cast<intptr_t>(this)).obj()); + DCHECK(!java_obj_.is_null()); +} + +ResourceManager::~ResourceManager() { + Java_ResourceManager_destroy(base::android::AttachCurrentThread(), + java_obj_.obj()); +} + +base::android::ScopedJavaLocalRef<jobject> ResourceManager::GetJavaObject( + JNIEnv* env) { + return base::android::ScopedJavaLocalRef<jobject>(java_obj_); +} + +ResourceManager::Resource* ResourceManager::GetResource( + AndroidResourceType res_type, + int res_id) { + DCHECK_GE(res_type, ANDROID_RESOURCE_TYPE_FIRST); + DCHECK_LE(res_type, ANDROID_RESOURCE_TYPE_LAST); + + Resource* resource = resources_[res_type].Lookup(res_id); + + if (!resource || res_type == ANDROID_RESOURCE_TYPE_DYNAMIC || + res_type == ANDROID_RESOURCE_TYPE_DYNAMIC_BITMAP) { + Java_ResourceManager_resourceRequested(base::android::AttachCurrentThread(), + java_obj_.obj(), res_type, res_id); + resource = resources_[res_type].Lookup(res_id); + } + + return resource; +} + +void ResourceManager::PreloadResource(AndroidResourceType res_type, + int res_id) { + DCHECK_GE(res_type, ANDROID_RESOURCE_TYPE_FIRST); + DCHECK_LE(res_type, ANDROID_RESOURCE_TYPE_LAST); + + // Don't send out a query if the resource is already loaded. + if (resources_[res_type].Lookup(res_id)) + return; + + Java_ResourceManager_preloadResource(base::android::AttachCurrentThread(), + java_obj_.obj(), res_type, res_id); +} + +void ResourceManager::OnResourceReady(JNIEnv* env, + jobject jobj, + jint res_type, + jint res_id, + jobject bitmap, + jint padding_left, + jint padding_top, + jint padding_right, + jint padding_bottom, + jint aperture_left, + jint aperture_top, + jint aperture_right, + jint aperture_bottom) { + DCHECK_GE(res_type, ANDROID_RESOURCE_TYPE_FIRST); + DCHECK_LE(res_type, ANDROID_RESOURCE_TYPE_LAST); + + Resource* resource = resources_[res_type].Lookup(res_id); + if (!resource) { + resource = new Resource(); + resources_[res_type].AddWithID(resource, res_id); + } + + gfx::JavaBitmap jbitmap(bitmap); + resource->size = jbitmap.size(); + resource->padding.SetRect(padding_left, padding_top, + padding_right - padding_left, + padding_bottom - padding_top); + resource->aperture.SetRect(aperture_left, aperture_top, + aperture_right - aperture_left, + aperture_bottom - aperture_top); + resource->ui_resource = + UIResourceAndroid::CreateFromJavaBitmap(ui_resource_provider_, jbitmap); +} + +// static +bool ResourceManager::RegisterResourceManager(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace ui diff --git a/ui/android/resources/resource_manager.h b/ui/android/resources/resource_manager.h new file mode 100644 index 0000000..730d4dc --- /dev/null +++ b/ui/android/resources/resource_manager.h @@ -0,0 +1,91 @@ +// Copyright 2014 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 UI_ANDROID_RESOURCES_RESOURCE_MANAGER_H_ +#define UI_ANDROID_RESOURCES_RESOURCE_MANAGER_H_ + +#include "base/android/jni_android.h" +#include "base/id_map.h" +#include "cc/resources/ui_resource_client.h" +#include "ui/android/ui_android_export.h" +#include "ui/gfx/geometry/rect.h" + +namespace content { +class UIResourceProvider; +} + +namespace ui { + +class UIResourceAndroid; + +// A Java counterpart will be generated for this enum. +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.ui.resources +enum AndroidResourceType { + ANDROID_RESOURCE_TYPE_STATIC = 0, + ANDROID_RESOURCE_TYPE_DYNAMIC, + ANDROID_RESOURCE_TYPE_DYNAMIC_BITMAP, + ANDROID_RESOURCE_TYPE_SYSTEM, + + ANDROID_RESOURCE_TYPE_COUNT, + ANDROID_RESOURCE_TYPE_FIRST = ANDROID_RESOURCE_TYPE_STATIC, + ANDROID_RESOURCE_TYPE_LAST = ANDROID_RESOURCE_TYPE_SYSTEM, +}; + +class UI_ANDROID_EXPORT ResourceManager { + public: + struct Resource { + public: + Resource(); + ~Resource(); + gfx::Rect Border(const gfx::Size& bounds); + gfx::Rect Border(const gfx::Size& bounds, const gfx::InsetsF& scale); + + scoped_ptr<UIResourceAndroid> ui_resource; + gfx::Size size; + gfx::Rect padding; + gfx::Rect aperture; + }; + + static ResourceManager* FromJavaObject(jobject jobj); + + explicit ResourceManager(content::UIResourceProvider* ui_resource_provider); + virtual ~ResourceManager(); + + base::android::ScopedJavaLocalRef<jobject> GetJavaObject(JNIEnv* env); + + ResourceManager::Resource* GetResource(AndroidResourceType res_type, + int res_id); + void PreloadResource(AndroidResourceType res_type, int res_id); + + // Called from Java ---------------------------------------------------------- + void OnResourceReady(JNIEnv* env, + jobject jobj, + jint res_type, + jint res_id, + jobject bitmap, + jint padding_left, + jint padding_top, + jint padding_right, + jint padding_bottom, + jint aperture_left, + jint aperture_top, + jint aperture_right, + jint aperture_bottom); + + static bool RegisterResourceManager(JNIEnv* env); + + private: + typedef IDMap<Resource, IDMapOwnPointer> ResourceMap; + + content::UIResourceProvider* ui_resource_provider_; + ResourceMap resources_[ANDROID_RESOURCE_TYPE_COUNT]; + + base::android::ScopedJavaGlobalRef<jobject> java_obj_; + + DISALLOW_COPY_AND_ASSIGN(ResourceManager); +}; + +} // namespace ui + +#endif // UI_ANDROID_RESOURCES_RESOURCE_MANAGER_H_ diff --git a/ui/android/resources/ui_resource_android.cc b/ui/android/resources/ui_resource_android.cc new file mode 100644 index 0000000..c242630 --- /dev/null +++ b/ui/android/resources/ui_resource_android.cc @@ -0,0 +1,50 @@ +// Copyright 2014 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 "ui/android/resources/ui_resource_android.h" + +#include "base/logging.h" +#include "content/public/browser/android/ui_resource_provider.h" + +namespace ui { + +scoped_ptr<UIResourceAndroid> UIResourceAndroid::CreateFromJavaBitmap( + content::UIResourceProvider* provider, + const gfx::JavaBitmap& java_bitmap) { + SkBitmap skbitmap = gfx::CreateSkBitmapFromJavaBitmap(java_bitmap); + skbitmap.setImmutable(); + + return make_scoped_ptr(new UIResourceAndroid(provider, skbitmap)); +} + +UIResourceAndroid::~UIResourceAndroid() { + if (id_ && provider_) + provider_->DeleteUIResource(id_); +} + +cc::UIResourceBitmap UIResourceAndroid::GetBitmap(cc::UIResourceId uid, + bool resource_lost) { + DCHECK(!bitmap_.empty()); + return cc::UIResourceBitmap(bitmap_); +} + +cc::UIResourceId UIResourceAndroid::id() { + if (id_) + return id_; + if (!provider_ || bitmap_.empty()) + return 0; + id_ = provider_->CreateUIResource(this); + return id_; +} + +void UIResourceAndroid::UIResourceIsInvalid() { + id_ = 0; +} + +UIResourceAndroid::UIResourceAndroid(content::UIResourceProvider* provider, + const SkBitmap& skbitmap) + : provider_(provider), bitmap_(skbitmap), id_(0) { +} + +} // namespace ui diff --git a/ui/android/resources/ui_resource_android.h b/ui/android/resources/ui_resource_android.h new file mode 100644 index 0000000..c18c0d7 --- /dev/null +++ b/ui/android/resources/ui_resource_android.h @@ -0,0 +1,49 @@ +// Copyright 2014 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 UI_ANDROID_RESOURCES_UI_RESOURCE_ANDROID_H_ +#define UI_ANDROID_RESOURCES_UI_RESOURCE_ANDROID_H_ + +#include "base/basictypes.h" +#include "cc/resources/ui_resource_bitmap.h" +#include "content/public/browser/android/ui_resource_client_android.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/android/resources/ui_resource_android.h" +#include "ui/android/ui_android_export.h" +#include "ui/gfx/android/java_bitmap.h" + +namespace ui { + +class UI_ANDROID_EXPORT UIResourceAndroid + : public content::UIResourceClientAndroid { + public: + static scoped_ptr<UIResourceAndroid> CreateFromJavaBitmap( + content::UIResourceProvider* provider, + const gfx::JavaBitmap& java_bitmap); + + ~UIResourceAndroid() override; + + // cc::UIResourceClient implementation. + cc::UIResourceBitmap GetBitmap(cc::UIResourceId uid, + bool resource_lost) override; + + // UIResourceClientAndroid implementation. + void UIResourceIsInvalid() override; + + cc::UIResourceId id(); + + private: + UIResourceAndroid(content::UIResourceProvider* provider, + const SkBitmap& skbitmap); + + content::UIResourceProvider* provider_; + SkBitmap bitmap_; + cc::UIResourceId id_; + + DISALLOW_COPY_AND_ASSIGN(UIResourceAndroid); +}; + +} // namespace ui + +#endif // UI_ANDROID_RESOURCES_UI_RESOURCE_ANDROID_H_ diff --git a/ui/android/ui_android.gyp b/ui/android/ui_android.gyp index f4e6ce6..1acc7f4 100644 --- a/ui/android/ui_android.gyp +++ b/ui/android/ui_android.gyp @@ -8,6 +8,50 @@ }, 'targets': [ { + # GN version: //ui/android + 'target_name': 'ui_android', + 'type': '<(component)', + 'dependencies': [ + '../../cc/cc.gyp:cc', + '../../base/base.gyp:base', + '../../skia/skia.gyp:skia', + '../gfx/gfx.gyp:gfx', + '../gfx/gfx.gyp:gfx_geometry', + 'ui_android_jni_headers', + ], + 'defines': [ + 'UI_ANDROID_IMPLEMENTATION', + ], + 'sources' : [ + 'resources/resource_manager.cc', + 'resources/resource_manager.h', + 'resources/ui_resource_android.cc', + 'resources/ui_resource_android.h', + 'ui_android_export.h', + 'ui_android_jni_registrar.cc', + 'ui_android_jni_registrar.h', + ], + }, + { + 'target_name': 'ui_android_jni_headers', + 'type': 'none', + 'sources': [ + 'java/src/org/chromium/ui/resources/ResourceManager.java', + ], + 'variables': { + 'jni_gen_package': 'ui_android', + }, + 'includes': [ '../../build/jni_generator.gypi' ], + }, + { + 'target_name': 'android_resource_type_java', + 'type': 'none', + 'variables': { + 'source_file': 'resources/resource_manager.h', + }, + 'includes': [ '../../build/android/java_cpp_enum.gypi' ], + }, + { 'target_name': 'bitmap_format_java', 'type': 'none', 'variables': { @@ -58,6 +102,7 @@ }, 'dependencies': [ '../../base/base.gyp:base_java', + 'android_resource_type_java', 'bitmap_format_java', 'page_transition_types_java', 'system_ui_resource_type_java', diff --git a/ui/android/ui_android_export.h b/ui/android/ui_android_export.h new file mode 100644 index 0000000..1beb2ef --- /dev/null +++ b/ui/android/ui_android_export.h @@ -0,0 +1,31 @@ +// Copyright 2014 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 UI_ANDROID_UI_ANDROID_EXPORT_H_ +#define UI_ANDROID_UI_ANDROID_EXPORT_H_ + +// Defines UI_ANDROID_EXPORT so that functionality implemented by the UI module +// can be exported to consumers. + +#if defined(COMPONENT_BUILD) + +#if defined(WIN32) +#error Unsupported target architecture. +#else // !defined(WIN32) + +#if defined(UI_ANDROID_IMPLEMENTATION) +#define UI_ANDROID_EXPORT __attribute__((visibility("default"))) +#else +#define UI_ANDROID_EXPORT +#endif + +#endif + +#else // !defined(COMPONENT_BUILD) + +#define UI_ANDROID_EXPORT + +#endif + +#endif // UI_ANDROID_UI_ANDROID_EXPORT_H_ diff --git a/ui/android/ui_android_jni_registrar.cc b/ui/android/ui_android_jni_registrar.cc new file mode 100644 index 0000000..e0e1fd6 --- /dev/null +++ b/ui/android/ui_android_jni_registrar.cc @@ -0,0 +1,22 @@ +// Copyright 2014 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 "ui/android/ui_android_jni_registrar.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_registrar.h" +#include "ui/android/resources/resource_manager.h" + +namespace ui { + +static base::android::RegistrationMethod kAndroidRegisteredMethods[] = { + {"ResourceManager", ui::ResourceManager::RegisterResourceManager}, +}; + +bool RegisterUIAndroidJni(JNIEnv* env) { + return RegisterNativeMethods(env, kAndroidRegisteredMethods, + arraysize(kAndroidRegisteredMethods)); +} + +} // namespace ui diff --git a/ui/android/ui_android_jni_registrar.h b/ui/android/ui_android_jni_registrar.h new file mode 100644 index 0000000..b1a5fd6 --- /dev/null +++ b/ui/android/ui_android_jni_registrar.h @@ -0,0 +1,19 @@ +// Copyright 2014 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 UI_ANDROID_UI_ANDROID_JNI_REGISTRAR_H_ +#define UI_ANDROID_UI_ANDROID_JNI_REGISTRAR_H_ + +#include <jni.h> + +#include "ui/android/ui_android_export.h" + +namespace ui { + +// Register all JNI bindings necessary for chrome. +UI_ANDROID_EXPORT bool RegisterUIAndroidJni(JNIEnv* env); + +} // namespace ui + +#endif // UI_ANDROID_UI_ANDROID_JNI_REGISTRAR_H_ |