Home | History | Annotate | Download | only in favicon
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/favicon/favicon_util.h"
      6 
      7 #include "chrome/browser/history/select_favicon_frames.h"
      8 #include "chrome/common/favicon/favicon_types.h"
      9 #include "skia/ext/image_operations.h"
     10 #include "third_party/skia/include/core/SkBitmap.h"
     11 #include "ui/gfx/codec/png_codec.h"
     12 #include "ui/gfx/favicon_size.h"
     13 #include "ui/gfx/image/image_png_rep.h"
     14 #include "ui/gfx/image/image_skia.h"
     15 #include "ui/gfx/size.h"
     16 
     17 #if defined(OS_MACOSX) && !defined(OS_IOS)
     18 #include "base/mac/mac_util.h"
     19 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
     20 
     21 namespace {
     22 
     23 // Creates image reps of DIP size |favicon_size| for the subset of
     24 // |scale_factors| for which the image reps can be created without resizing
     25 // or decoding the bitmap data.
     26 std::vector<gfx::ImagePNGRep> SelectFaviconFramesFromPNGsWithoutResizing(
     27     const std::vector<chrome::FaviconBitmapResult>& png_data,
     28     const std::vector<ui::ScaleFactor>& scale_factors,
     29     int favicon_size) {
     30   std::vector<gfx::ImagePNGRep> png_reps;
     31   if (png_data.empty())
     32     return png_reps;
     33 
     34   // A |favicon_size| of 0 indicates that the largest frame is desired.
     35   if (favicon_size == 0 && scale_factors.size() == 1) {
     36     int maximum_area = 0;
     37     scoped_refptr<base::RefCountedMemory> best_candidate;
     38     for (size_t i = 0; i < png_data.size(); ++i) {
     39       int area = png_data[i].pixel_size.GetArea();
     40       if (area > maximum_area) {
     41         maximum_area = area;
     42         best_candidate = png_data[i].bitmap_data;
     43       }
     44     }
     45     png_reps.push_back(gfx::ImagePNGRep(best_candidate,
     46                                         scale_factors[0]));
     47     return png_reps;
     48   }
     49 
     50   // Cache the scale factor for each pixel size as |scale_factors| may contain
     51   // any of GetFaviconScaleFactors() which may include scale factors not
     52   // supported by the platform. (ui::GetScaleFactorFromScale() cannot be used.)
     53   std::map<int, ui::ScaleFactor> desired_pixel_sizes;
     54   for (size_t i = 0; i < scale_factors.size(); ++i) {
     55     int pixel_size = floor(favicon_size *
     56         ui::GetScaleFactorScale(scale_factors[i]));
     57     desired_pixel_sizes[pixel_size] = scale_factors[i];
     58   }
     59 
     60   for (size_t i = 0; i < png_data.size(); ++i) {
     61     if (!png_data[i].is_valid())
     62       continue;
     63 
     64     const gfx::Size& pixel_size = png_data[i].pixel_size;
     65     if (pixel_size.width() != pixel_size.height())
     66       continue;
     67 
     68     std::map<int, ui::ScaleFactor>::iterator it = desired_pixel_sizes.find(
     69         pixel_size.width());
     70     if (it == desired_pixel_sizes.end())
     71       continue;
     72 
     73     png_reps.push_back(gfx::ImagePNGRep(png_data[i].bitmap_data, it->second));
     74   }
     75 
     76   return png_reps;
     77 }
     78 
     79 }  // namespace
     80 
     81 // static
     82 std::vector<ui::ScaleFactor> FaviconUtil::GetFaviconScaleFactors() {
     83   const float kScale1x = ui::GetScaleFactorScale(ui::SCALE_FACTOR_100P);
     84   std::vector<ui::ScaleFactor> favicon_scale_factors =
     85       ui::GetSupportedScaleFactors();
     86 
     87   // The scale factors returned from ui::GetSupportedScaleFactors() are sorted.
     88   // Insert the 1x scale factor such that GetFaviconScaleFactors() is sorted as
     89   // well.
     90   size_t insert_index = favicon_scale_factors.size();
     91   for (size_t i = 0; i < favicon_scale_factors.size(); ++i) {
     92     float scale = ui::GetScaleFactorScale(favicon_scale_factors[i]);
     93     if (scale == kScale1x) {
     94       return favicon_scale_factors;
     95     } else if (scale > kScale1x) {
     96       insert_index = i;
     97       break;
     98     }
     99   }
    100   // TODO(ios): 100p should not be necessary on iOS retina devices. However
    101   // the sync service only supports syncing 100p favicons. Until sync supports
    102   // other scales 100p is needed in the list of scale factors to retrieve and
    103   // store the favicons in both 100p for sync and 200p for display. cr/160503.
    104   favicon_scale_factors.insert(favicon_scale_factors.begin() + insert_index,
    105                                ui::SCALE_FACTOR_100P);
    106   return favicon_scale_factors;
    107 }
    108 
    109 // static
    110 void FaviconUtil::SetFaviconColorSpace(gfx::Image* image) {
    111 #if defined(OS_MACOSX) && !defined(OS_IOS)
    112   image->SetSourceColorSpace(base::mac::GetSystemColorSpace());
    113 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    114 }
    115 
    116 // static
    117 gfx::Image FaviconUtil::SelectFaviconFramesFromPNGs(
    118       const std::vector<chrome::FaviconBitmapResult>& png_data,
    119       const std::vector<ui::ScaleFactor>& scale_factors,
    120       int favicon_size) {
    121   // Create image reps for as many scale factors as possible without resizing
    122   // the bitmap data or decoding it. FaviconHandler stores already resized
    123   // favicons into history so no additional resizing should be needed in the
    124   // common case.
    125   // Creating the gfx::Image from |png_data| without resizing or decoding if
    126   // possible is important because:
    127   // - Sync does a byte-to-byte comparison of gfx::Image::As1xPNGBytes() to
    128   //   the data it put into the database in order to determine whether any
    129   //   updates should be pushed to sync.
    130   // - The decoding occurs on the UI thread and the decoding can be a
    131   //   significant performance hit if a user has many bookmarks.
    132   // TODO(pkotwicz): Move the decoding off the UI thread.
    133   std::vector<gfx::ImagePNGRep> png_reps =
    134       SelectFaviconFramesFromPNGsWithoutResizing(png_data, scale_factors,
    135           favicon_size);
    136 
    137   std::vector<ui::ScaleFactor> scale_factors_to_generate = scale_factors;
    138   for (size_t i = 0; i < png_reps.size(); ++i) {
    139     std::vector<ui::ScaleFactor>::iterator it = std::find(
    140         scale_factors_to_generate.begin(),
    141         scale_factors_to_generate.end(),
    142         png_reps[i].scale_factor);
    143     CHECK(it != scale_factors_to_generate.end());
    144     scale_factors_to_generate.erase(it);
    145   }
    146 
    147   if (scale_factors_to_generate.empty())
    148     return gfx::Image(png_reps);
    149 
    150   std::vector<SkBitmap> bitmaps;
    151   for (size_t i = 0; i < png_data.size(); ++i) {
    152     if (!png_data[i].is_valid())
    153       continue;
    154 
    155     SkBitmap bitmap;
    156     if (gfx::PNGCodec::Decode(png_data[i].bitmap_data->front(),
    157                               png_data[i].bitmap_data->size(),
    158                               &bitmap)) {
    159       bitmaps.push_back(bitmap);
    160     }
    161   }
    162 
    163   if (bitmaps.empty())
    164     return gfx::Image();
    165 
    166   gfx::ImageSkia resized_image_skia = SelectFaviconFrames(bitmaps,
    167       scale_factors_to_generate, favicon_size, NULL);
    168 
    169   if (png_reps.empty())
    170     return gfx::Image(resized_image_skia);
    171 
    172   std::vector<gfx::ImageSkiaRep> resized_image_skia_reps =
    173       resized_image_skia.image_reps();
    174   for (size_t i = 0; i < resized_image_skia_reps.size(); ++i) {
    175     scoped_refptr<base::RefCountedBytes> png_bytes(new base::RefCountedBytes());
    176     if (gfx::PNGCodec::EncodeBGRASkBitmap(
    177         resized_image_skia_reps[i].sk_bitmap(), false, &png_bytes->data())) {
    178       png_reps.push_back(gfx::ImagePNGRep(png_bytes,
    179           resized_image_skia_reps[i].scale_factor()));
    180     }
    181   }
    182 
    183   return gfx::Image(png_reps);
    184 }
    185 
    186 // static
    187 size_t FaviconUtil::SelectBestFaviconFromBitmaps(
    188     const std::vector<SkBitmap>& bitmaps,
    189     const std::vector<ui::ScaleFactor>& scale_factors,
    190     int desired_size) {
    191   std::vector<gfx::Size> sizes;
    192   for (size_t i = 0; i < bitmaps.size(); ++i)
    193     sizes.push_back(gfx::Size(bitmaps[i].width(), bitmaps[i].height()));
    194   std::vector<size_t> selected_bitmap_indices;
    195   SelectFaviconFrameIndices(sizes, scale_factors, desired_size,
    196                             &selected_bitmap_indices, NULL);
    197   DCHECK_EQ(1u, selected_bitmap_indices.size());
    198   return selected_bitmap_indices[0];
    199 }
    200