Home | History | Annotate | Download | only in resource
      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 "ui/base/resource/resource_bundle.h"
      6 
      7 #include "base/i18n/rtl.h"
      8 #include "base/logging.h"
      9 #include "base/memory/ref_counted_memory.h"
     10 #include "base/path_service.h"
     11 #include "base/synchronization/lock.h"
     12 #include "third_party/skia/include/core/SkBitmap.h"
     13 #include "ui/base/gtk/scoped_gobject.h"
     14 #include "ui/base/layout.h"
     15 #include "ui/base/resource/resource_handle.h"
     16 #include "ui/base/ui_base_paths.h"
     17 #include "ui/gfx/image/image.h"
     18 
     19 #include <gtk/gtk.h>
     20 
     21 namespace ui {
     22 
     23 namespace {
     24 
     25 // Convert the raw image data into a GdkPixbuf.  The GdkPixbuf that is returned
     26 // has a ref count of 1 so the caller must call g_object_unref to free the
     27 // memory.
     28 GdkPixbuf* LoadPixbuf(base::RefCountedStaticMemory* data, bool rtl_enabled) {
     29   ScopedGObject<GdkPixbufLoader>::Type loader(gdk_pixbuf_loader_new());
     30   bool ok = data && gdk_pixbuf_loader_write(loader.get(),
     31       reinterpret_cast<const guint8*>(data->front()), data->size(), NULL);
     32   if (!ok)
     33     return NULL;
     34   // Calling gdk_pixbuf_loader_close forces the data to be parsed by the
     35   // loader.  We must do this before calling gdk_pixbuf_loader_get_pixbuf.
     36   ok = gdk_pixbuf_loader_close(loader.get(), NULL);
     37   if (!ok)
     38     return NULL;
     39   GdkPixbuf* pixbuf = gdk_pixbuf_loader_get_pixbuf(loader.get());
     40   if (!pixbuf)
     41     return NULL;
     42 
     43   if (base::i18n::IsRTL() && rtl_enabled) {
     44     // |pixbuf| will get unreffed and destroyed (see below). The returned value
     45     // has ref count 1.
     46     return gdk_pixbuf_flip(pixbuf, TRUE);
     47   } else {
     48     // The pixbuf is owned by the loader, so add a ref so when we delete the
     49     // loader (when the ScopedGObject goes out of scope), the pixbuf still
     50     // exists.
     51     g_object_ref(pixbuf);
     52     return pixbuf;
     53   }
     54 }
     55 
     56 base::FilePath GetResourcesPakFilePath(const std::string& pak_name) {
     57   base::FilePath path;
     58   if (PathService::Get(base::DIR_MODULE, &path))
     59     return path.AppendASCII(pak_name.c_str());
     60 
     61   // Return just the name of the pack file.
     62   return base::FilePath(pak_name.c_str());
     63 }
     64 
     65 }  // namespace
     66 
     67 void ResourceBundle::LoadCommonResources() {
     68   AddDataPackFromPath(GetResourcesPakFilePath("chrome.pak"),
     69                       SCALE_FACTOR_NONE);
     70   AddDataPackFromPath(GetResourcesPakFilePath(
     71                       "chrome_100_percent.pak"),
     72                       SCALE_FACTOR_100P);
     73 }
     74 
     75 gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id, ImageRTL rtl) {
     76   // Use the negative |resource_id| for the key for BIDI-aware images.
     77   int key = rtl == RTL_ENABLED ? -resource_id : resource_id;
     78 
     79   // Check to see if the image is already in the cache.
     80   {
     81     base::AutoLock lock_scope(*images_and_fonts_lock_);
     82     if (images_.count(key))
     83       return images_[key];
     84   }
     85 
     86   gfx::Image image;
     87   if (delegate_)
     88     image = delegate_->GetNativeImageNamed(resource_id, rtl);
     89 
     90   if (image.IsEmpty()) {
     91     scoped_refptr<base::RefCountedStaticMemory> data(
     92         LoadDataResourceBytesForScale(resource_id, SCALE_FACTOR_100P));
     93     GdkPixbuf* pixbuf = LoadPixbuf(data.get(), rtl == RTL_ENABLED);
     94 
     95     if (!pixbuf) {
     96       LOG(WARNING) << "Unable to load pixbuf with id " << resource_id;
     97       NOTREACHED();  // Want to assert in debug mode.
     98       return GetEmptyImage();
     99     }
    100 
    101     image = gfx::Image(pixbuf);  // Takes ownership.
    102   }
    103 
    104   base::AutoLock lock_scope(*images_and_fonts_lock_);
    105 
    106   // Another thread raced the load and has already cached the image.
    107   if (images_.count(key))
    108     return images_[key];
    109 
    110   images_[key] = image;
    111   return images_[key];
    112 }
    113 
    114 }  // namespace ui
    115