favicon_helper.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file.
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/android/favicon_helper.h"
6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <jni.h>
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/android/jni_android.h"
10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/android/jni_string.h"
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/android/scoped_java_ref.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/bind.h"
1368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/strings/string_util.h"
1468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/favicon/favicon_service.h"
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/favicon/favicon_service_factory.h"
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/profiles/profile.h"
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/profiles/profile_android.h"
1968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "chrome/browser/sync/glue/session_model_associator.h"
2068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "chrome/browser/sync/glue/session_model_associator.h"
2168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "chrome/browser/sync/profile_sync_service.h"
2268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "chrome/browser/sync/profile_sync_service_factory.h"
2368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "chrome/browser/sync/profile_sync_service_factory.h"
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "jni/FaviconHelper_jni.h"
25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "third_party/skia/include/core/SkBitmap.h"
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/gfx/android/java_bitmap.h"
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/gfx/color_analysis.h"
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/gfx/color_utils.h"
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing base::android::ScopedJavaGlobalRef;
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing base::android::ScopedJavaLocalRef;
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing base::android::AttachCurrentThread;
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing base::android::ConvertJavaStringToUTF16;
3468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)using base::android::ConvertJavaStringToUTF8;
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing base::android::ConvertUTF8ToJavaString;
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace {
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void OnLocalFaviconAvailable(
4068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    ScopedJavaGlobalRef<jobject>* j_favicon_image_callback,
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const chrome::FaviconImageResult& favicon_image_result) {
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  JNIEnv* env = AttachCurrentThread();
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Convert favicon_image_result to java objects.
4568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ScopedJavaLocalRef<jstring> j_icon_url =
4668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ConvertUTF8ToJavaString(env, favicon_image_result.icon_url.spec());
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SkBitmap favicon_bitmap = favicon_image_result.image.AsBitmap();
4868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ScopedJavaLocalRef<jobject> j_favicon_bitmap;
4968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!favicon_bitmap.isNull())
5068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    j_favicon_bitmap = gfx::ConvertToJavaBitmap(&favicon_bitmap);
5168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
5268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Call java side OnLocalFaviconAvailable method.
5368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  Java_FaviconImageCallback_onFaviconAvailable(env,
5468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                               j_favicon_image_callback->obj(),
5568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                               j_favicon_bitmap.obj(),
5668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                               j_icon_url.obj());
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic jint Init(JNIEnv* env, jclass clazz) {
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return reinterpret_cast<jint>(new FaviconHelper());
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochFaviconHelper::FaviconHelper() {
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  cancelable_task_tracker_.reset(new CancelableTaskTracker());
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid FaviconHelper::Destroy(JNIEnv* env, jobject obj) {
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  delete this;
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)jboolean FaviconHelper::GetLocalFaviconImageForURL(
7468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    JNIEnv* env,
7568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    jobject obj,
7668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    jobject j_profile,
7768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    jstring j_page_url,
7868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    jint j_icon_types,
7968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    jint j_desired_size_in_dip,
8068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    jobject j_favicon_image_callback) {
8168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(profile);
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!profile)
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  FaviconService* favicon_service = FaviconServiceFactory::GetForProfile(
87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      profile, Profile::EXPLICIT_ACCESS);
88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(favicon_service);
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!favicon_service)
90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  FaviconService::FaviconForURLParams params(
9368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      profile,
9468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      GURL(ConvertJavaStringToUTF16(env, j_page_url)),
9568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      static_cast<int>(j_icon_types),
9668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      static_cast<int>(j_desired_size_in_dip));
97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ScopedJavaGlobalRef<jobject>* j_scoped_favicon_callback =
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      new ScopedJavaGlobalRef<jobject>();
10068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  j_scoped_favicon_callback->Reset(env, j_favicon_image_callback);
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  FaviconService::FaviconImageCallback callback_runner = base::Bind(
10368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      &OnLocalFaviconAvailable, base::Owned(j_scoped_favicon_callback));
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  favicon_service->GetFaviconImageForURL(
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      params, callback_runner,
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      cancelable_task_tracker_.get());
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
11268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)ScopedJavaLocalRef<jobject> FaviconHelper::GetSyncedFaviconImageForURL(
11368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    JNIEnv* env,
11468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    jobject obj,
11568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    jobject jprofile,
11668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    jstring j_page_url) {
11768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
11868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(profile);
11968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
12068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::string page_url = ConvertJavaStringToUTF8(env, j_page_url);
12168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
12268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ProfileSyncService* sync_service =
12368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile);
12468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(sync_service);
12568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
12668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  scoped_refptr<base::RefCountedMemory> favicon_png;
12768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  browser_sync::SessionModelAssociator* associator =
12868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      sync_service->GetSessionModelAssociator();
12968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(associator);
13068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
13168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!associator->GetSyncedFaviconForPageURL(page_url, &favicon_png))
13268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return ScopedJavaLocalRef<jobject>();
13368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
13468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // Convert favicon_image_result to java objects.
13568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  gfx::Image favicon_image = gfx::Image::CreateFrom1xPNGBytes(
13668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      favicon_png->front(), favicon_png->size());
13768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  SkBitmap favicon_bitmap = favicon_image.AsBitmap();
13868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
13968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ScopedJavaLocalRef<jobject> j_favicon_bitmap;
14068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (favicon_bitmap.isNull())
14168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return ScopedJavaLocalRef<jobject>();
14268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
14368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return gfx::ConvertToJavaBitmap(&favicon_bitmap);
144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)jint FaviconHelper::GetDominantColorForBitmap(JNIEnv* env,
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                              jobject obj,
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                              jobject bitmap) {
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!bitmap)
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return 0;
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  gfx::JavaBitmap bitmap_lock(bitmap);
1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SkBitmap skbitmap = gfx::CreateSkBitmapFromJavaBitmap(bitmap_lock);
1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  skbitmap.setImmutable();
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_refptr<base::RefCountedMemory> png_data =
1564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      gfx::Image::CreateFrom1xBitmap(skbitmap).As1xPNGBytes();
1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  uint32_t max_brightness = 665;
1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  uint32_t min_darkness = 100;
1594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  color_utils::GridSampler sampler;
1604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return color_utils::CalculateKMeanColorOfPNG(
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      png_data, min_darkness, max_brightness, &sampler);
1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
16468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)FaviconHelper::~FaviconHelper() {}
16568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// static
167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool FaviconHelper::RegisterFaviconHelper(JNIEnv* env) {
168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return RegisterNativesImpl(env);
169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
170