Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / base / resource / resource_bundle.cc
index 42367f7..b19133a 100644 (file)
@@ -4,10 +4,13 @@
 
 #include "ui/base/resource/resource_bundle.h"
 
+#include <limits>
 #include <vector>
 
+#include "base/big_endian.h"
 #include "base/command_line.h"
-#include "base/file_util.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/metrics/histogram.h"
@@ -17,8 +20,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock.h"
 #include "build/build_config.h"
-#include "grit/app_locale_settings.h"
-#include "net/base/big_endian.h"
 #include "skia/ext/image_operations.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/safe_integer_conversions.h"
 #include "ui/gfx/screen.h"
 #include "ui/gfx/size_conversions.h"
-#include "ui/gfx/skbitmap_operations.h"
+#include "ui/strings/grit/app_locale_settings.h"
+
+#if defined(OS_ANDROID)
+#include "ui/base/resource/resource_bundle_android.h"
+#endif
 
 #if defined(OS_CHROMEOS)
 #include "ui/base/l10n/l10n_util.h"
@@ -64,10 +69,14 @@ const size_t kPngChunkMetadataSize = 12;  // length, type, crc32
 const unsigned char kPngScaleChunkType[4] = { 'c', 's', 'C', 'l' };
 const unsigned char kPngDataChunkType[4] = { 'I', 'D', 'A', 'T' };
 
+#if !defined(OS_MACOSX)
+const char kPakFileSuffix[] = ".pak";
+#endif
+
 ResourceBundle* g_shared_instance_ = NULL;
 
 void InitDefaultFontList() {
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) && defined(USE_PANGO)
   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
   std::string font_family = base::UTF16ToUTF8(
       rb.GetLocalizedString(IDS_UI_FONT_FAMILY_CROS));
@@ -83,6 +92,25 @@ void InitDefaultFontList() {
 #endif
 }
 
+#if defined(OS_ANDROID)
+// Returns the scale factor closest to |scale| from the full list of factors.
+// Note that it does NOT rely on the list of supported scale factors.
+// Finding the closest match is inefficient and shouldn't be done frequently.
+ScaleFactor FindClosestScaleFactorUnsafe(float scale) {
+  float smallest_diff =  std::numeric_limits<float>::max();
+  ScaleFactor closest_match = SCALE_FACTOR_100P;
+  for (int i = SCALE_FACTOR_100P; i < NUM_SCALE_FACTORS; ++i) {
+    const ScaleFactor scale_factor = static_cast<ScaleFactor>(i);
+    float diff = std::abs(GetScaleForScaleFactor(scale_factor) - scale);
+    if (diff < smallest_diff) {
+      closest_match = scale_factor;
+      smallest_diff = diff;
+    }
+  }
+  return closest_match;
+}
+#endif  // OS_ANDROID
+
 }  // namespace
 
 // An ImageSkiaSource that loads bitmaps for the requested scale factor from
@@ -105,11 +133,15 @@ class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource {
     ScaleFactor scale_factor = GetSupportedScaleFactor(scale);
     bool found = rb_->LoadBitmap(resource_id_, &scale_factor,
                                  &image, &fell_back_to_1x);
-    // Force to a supported scale.
-    scale = ui::GetImageScale(scale_factor);
     if (!found)
       return gfx::ImageSkiaRep();
 
+    // If the resource is in the package with SCALE_FACTOR_NONE, it
+    // can be used in any scale factor. The image is maked as "unscaled"
+    // so that the ImageSkia do not automatically scale.
+    if (scale_factor == ui::SCALE_FACTOR_NONE)
+      return gfx::ImageSkiaRep(image, 0.0f);
+
     if (fell_back_to_1x) {
       // GRIT fell back to the 100% image, so rescale it to the correct size.
       image = skia::ImageOperations::Resize(
@@ -117,21 +149,9 @@ class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource {
           skia::ImageOperations::RESIZE_LANCZOS3,
           gfx::ToCeiledInt(image.width() * scale),
           gfx::ToCeiledInt(image.height() * scale));
-      // If --highlight-missing-scaled-resources is specified, log the resource
-      // id and blend the created resource with red.
-      if (ShouldHighlightMissingScaledResources()) {
-        LOG(ERROR) << "Missing " << scale << "x scaled resource. id="
-                   << resource_id_;
-
-        SkBitmap mask;
-        mask.setConfig(SkBitmap::kARGB_8888_Config,
-                       image.width(), image.height());
-        mask.allocPixels();
-        mask.eraseColor(SK_ColorRED);
-        image = SkBitmapOperations::CreateBlendedBitmap(image, mask, 0.2);
-      }
+    } else {
+      scale = GetScaleForScaleFactor(scale_factor);
     }
-
     return gfx::ImageSkiaRep(image, scale);
   }
 
@@ -144,33 +164,24 @@ class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource {
 
 // static
 std::string ResourceBundle::InitSharedInstanceWithLocale(
-    const std::string& pref_locale, Delegate* delegate) {
-  InitSharedInstance(delegate);
-  g_shared_instance_->LoadCommonResources();
-  std::string result = g_shared_instance_->LoadLocaleResources(pref_locale);
-  InitDefaultFontList();
-  return result;
-}
-
-// static
-std::string ResourceBundle::InitSharedInstanceLocaleOnly(
-    const std::string& pref_locale, Delegate* delegate) {
+    const std::string& pref_locale,
+    Delegate* delegate,
+    LoadResources load_resources) {
   InitSharedInstance(delegate);
+  if (load_resources == LOAD_COMMON_RESOURCES)
+    g_shared_instance_->LoadCommonResources();
   std::string result = g_shared_instance_->LoadLocaleResources(pref_locale);
   InitDefaultFontList();
   return result;
 }
 
 // static
-void ResourceBundle::InitSharedInstanceWithPakFile(
-    base::File pak_file, bool should_load_common_resources) {
+void ResourceBundle::InitSharedInstanceWithPakFileRegion(
+    base::File pak_file,
+    const base::MemoryMappedFile::Region& region) {
   InitSharedInstance(NULL);
-  if (should_load_common_resources)
-    g_shared_instance_->LoadCommonResources();
-
-  scoped_ptr<DataPack> data_pack(
-      new DataPack(SCALE_FACTOR_100P));
-  if (!data_pack->LoadFromFile(pak_file.Pass())) {
+  scoped_ptr<DataPack> data_pack(new DataPack(SCALE_FACTOR_100P));
+  if (!data_pack->LoadFromFileRegion(pak_file.Pass(), region)) {
     NOTREACHED() << "failed to load pak file";
     return;
   }
@@ -207,7 +218,16 @@ ResourceBundle& ResourceBundle::GetSharedInstance() {
 }
 
 bool ResourceBundle::LocaleDataPakExists(const std::string& locale) {
-  return !GetLocaleFilePath(locale, true).empty();
+  bool locale_file_path_exists = !GetLocaleFilePath(locale, true).empty();
+#if defined(OS_ANDROID)
+  // TODO(mkosiba,primiano): Chrome should mmap the .pak files too, in which
+  // case we'd not need to check if locale_file_path_exists here.
+  // http://crbug.com/394502.
+  return locale_file_path_exists ||
+      AssetContainedInApk(locale + kPakFileSuffix);
+#else
+  return locale_file_path_exists;
+#endif
 }
 
 void ResourceBundle::AddDataPackFromPath(const base::FilePath& path,
@@ -222,9 +242,17 @@ void ResourceBundle::AddOptionalDataPackFromPath(const base::FilePath& path,
 
 void ResourceBundle::AddDataPackFromFile(base::File file,
                                          ScaleFactor scale_factor) {
+  AddDataPackFromFileRegion(
+      file.Pass(), base::MemoryMappedFile::Region::kWholeFile, scale_factor);
+}
+
+void ResourceBundle::AddDataPackFromFileRegion(
+    base::File file,
+    const base::MemoryMappedFile::Region& region,
+    ScaleFactor scale_factor) {
   scoped_ptr<DataPack> data_pack(
       new DataPack(scale_factor));
-  if (data_pack->LoadFromFile(file.Pass())) {
+  if (data_pack->LoadFromFileRegion(file.Pass(), region)) {
     AddDataPack(data_pack.release());
   } else {
     LOG(ERROR) << "Failed to load data pack from file."
@@ -242,8 +270,10 @@ base::FilePath ResourceBundle::GetLocaleFilePath(const std::string& app_locale,
 
   PathService::Get(ui::DIR_LOCALES, &locale_file_path);
 
-  if (!locale_file_path.empty())
-    locale_file_path = locale_file_path.AppendASCII(app_locale + ".pak");
+  if (!locale_file_path.empty()) {
+    locale_file_path =
+        locale_file_path.AppendASCII(app_locale + kPakFileSuffix);
+  }
 
   if (delegate_) {
     locale_file_path =
@@ -266,15 +296,8 @@ std::string ResourceBundle::LoadLocaleResources(
   DCHECK(!locale_resources_data_.get()) << "locale.pak already loaded";
   std::string app_locale = l10n_util::GetApplicationLocale(pref_locale);
   base::FilePath locale_file_path = GetOverriddenPakPath();
-  if (locale_file_path.empty()) {
-    CommandLine* command_line = CommandLine::ForCurrentProcess();
-    if (command_line->HasSwitch(switches::kLocalePak)) {
-      locale_file_path =
-          command_line->GetSwitchValuePath(switches::kLocalePak);
-    } else {
-      locale_file_path = GetLocaleFilePath(app_locale, true);
-    }
-  }
+  if (locale_file_path.empty())
+    locale_file_path = GetLocaleFilePath(app_locale, true);
 
   if (locale_file_path.empty()) {
     // It's possible that there is no locale.pak.
@@ -298,8 +321,10 @@ std::string ResourceBundle::LoadLocaleResources(
 
 void ResourceBundle::LoadTestResources(const base::FilePath& path,
                                        const base::FilePath& locale_path) {
+  DCHECK(!ui::GetSupportedScaleFactors().empty());
+  const ScaleFactor scale_factor(ui::GetSupportedScaleFactors()[0]);
   // Use the given resource pak for both common and localized resources.
-  scoped_ptr<DataPack> data_pack(new DataPack(SCALE_FACTOR_100P));
+  scoped_ptr<DataPack> data_pack(new DataPack(scale_factor));
   if (!path.empty() && data_pack->LoadFromPath(path))
     AddDataPack(data_pack.release());
 
@@ -319,6 +344,12 @@ void ResourceBundle::OverrideLocalePakForTest(const base::FilePath& pak_path) {
   overridden_pak_path_ = pak_path;
 }
 
+void ResourceBundle::OverrideLocaleStringResource(
+    int message_id,
+    const base::string16& string) {
+  overridden_locale_strings_[message_id] = string;
+}
+
 const base::FilePath& ResourceBundle::GetOverriddenPakPath() {
   return overridden_pak_path_;
 }
@@ -326,6 +357,10 @@ const base::FilePath& ResourceBundle::GetOverriddenPakPath() {
 std::string ResourceBundle::ReloadLocaleResources(
     const std::string& pref_locale) {
   base::AutoLock lock_scope(*locale_resources_data_lock_);
+
+  // Remove all overriden strings, as they will not be valid for the new locale.
+  overridden_locale_strings_.clear();
+
   UnloadLocaleResources();
   return LoadLocaleResources(pref_locale);
 }
@@ -351,20 +386,19 @@ gfx::Image& ResourceBundle::GetImageNamed(int resource_id) {
     DCHECK(!data_packs_.empty()) <<
         "Missing call to SetResourcesDataDLL?";
 
-#if defined(OS_CHROMEOS)
-    ui::ScaleFactor scale_factor_to_load = GetMaxScaleFactor();
+#if defined(OS_CHROMEOS) || defined(OS_WIN)
+  ui::ScaleFactor scale_factor_to_load = GetMaxScaleFactor();
 #else
-    ui::ScaleFactor scale_factor_to_load = ui::SCALE_FACTOR_100P;
+  ui::ScaleFactor scale_factor_to_load = ui::SCALE_FACTOR_100P;
 #endif
 
-    float scale = GetImageScale(scale_factor_to_load);
     // TODO(oshima): Consider reading the image size from png IHDR chunk and
     // skip decoding here and remove #ifdef below.
     // ResourceBundle::GetSharedInstance() is destroyed after the
     // BrowserMainLoop has finished running. |image_skia| is guaranteed to be
     // destroyed before the resource bundle is destroyed.
     gfx::ImageSkia image_skia(new ResourceBundleImageSource(this, resource_id),
-                              scale);
+                              GetScaleForScaleFactor(scale_factor_to_load));
     if (image_skia.isNull()) {
       LOG(WARNING) << "Unable to load image with id " << resource_id;
       NOTREACHED();  // Want to assert in debug mode.
@@ -434,6 +468,7 @@ base::StringPiece ResourceBundle::GetRawDataResourceForScale(
   }
   for (size_t i = 0; i < data_packs_.size(); i++) {
     if ((data_packs_[i]->GetScaleFactor() == ui::SCALE_FACTOR_100P ||
+         data_packs_[i]->GetScaleFactor() == ui::SCALE_FACTOR_200P ||
          data_packs_[i]->GetScaleFactor() == ui::SCALE_FACTOR_NONE) &&
         data_packs_[i]->GetStringPiece(resource_id, &data))
       return data;
@@ -451,6 +486,11 @@ base::string16 ResourceBundle::GetLocalizedString(int message_id) {
   // we're using them.
   base::AutoLock lock_scope(*locale_resources_data_lock_);
 
+  IdToStringMap::const_iterator it =
+      overridden_locale_strings_.find(message_id);
+  if (it != overridden_locale_strings_.end())
+    return it->second;
+
   // If for some reason we were unable to load the resources , return an empty
   // string (better than crashing).
   if (!locale_resources_data_.get()) {
@@ -522,13 +562,21 @@ void ResourceBundle::ReloadFonts() {
 }
 
 ScaleFactor ResourceBundle::GetMaxScaleFactor() const {
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) || defined(OS_WIN)
   return max_scale_factor_;
 #else
   return GetSupportedScaleFactors().back();
 #endif
 }
 
+bool ResourceBundle::IsScaleFactorSupported(ScaleFactor scale_factor) {
+  const std::vector<ScaleFactor>& supported_scale_factors =
+      ui::GetSupportedScaleFactors();
+  return std::find(supported_scale_factors.begin(),
+                   supported_scale_factors.end(),
+                   scale_factor) != supported_scale_factors.end();
+}
+
 ResourceBundle::ResourceBundle(Delegate* delegate)
     : delegate_(delegate),
       images_and_fonts_lock_(new base::Lock),
@@ -546,8 +594,9 @@ void ResourceBundle::InitSharedInstance(Delegate* delegate) {
   DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice";
   g_shared_instance_ = new ResourceBundle(delegate);
   static std::vector<ScaleFactor> supported_scale_factors;
-#if !defined(OS_IOS)
+#if !defined(OS_IOS) && !defined(OS_WIN)
   // On platforms other than iOS, 100P is always a supported scale factor.
+  // For Windows we have a separate case in this function.
   supported_scale_factors.push_back(SCALE_FACTOR_100P);
 #endif
 #if defined(OS_ANDROID)
@@ -559,7 +608,10 @@ void ResourceBundle::InitSharedInstance(Delegate* delegate) {
     supported_scale_factors.push_back(closest);
 #elif defined(OS_IOS)
     gfx::Display display = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
-  if (display.device_scale_factor() > 1.0) {
+  if (display.device_scale_factor() > 2.0) {
+    DCHECK_EQ(3.0, display.device_scale_factor());
+    supported_scale_factors.push_back(SCALE_FACTOR_300P);
+  } else if (display.device_scale_factor() > 1.0) {
     DCHECK_EQ(2.0, display.device_scale_factor());
     supported_scale_factors.push_back(SCALE_FACTOR_200P);
   } else {
@@ -573,12 +625,28 @@ void ResourceBundle::InitSharedInstance(Delegate* delegate) {
   supported_scale_factors.push_back(SCALE_FACTOR_200P);
 #elif defined(OS_LINUX) && defined(ENABLE_HIDPI)
   supported_scale_factors.push_back(SCALE_FACTOR_200P);
+#elif defined(OS_WIN)
+  bool default_to_100P = true;
+  if (gfx::IsHighDPIEnabled()) {
+    // On Windows if the dpi scale is greater than 1.25 on high dpi machines
+    // downscaling from 200 percent looks better than scaling up from 100
+    // percent.
+    if (gfx::GetDPIScale() > 1.25) {
+      supported_scale_factors.push_back(SCALE_FACTOR_200P);
+      default_to_100P = false;
+    }
+  }
+  if (default_to_100P)
+    supported_scale_factors.push_back(SCALE_FACTOR_100P);
 #endif
   ui::SetSupportedScaleFactors(supported_scale_factors);
 #if defined(OS_WIN)
   // Must be called _after_ supported scale factors are set since it
   // uses them.
-  ui::win::InitDeviceScaleFactor();
+  // Don't initialize the device scale factor if it has already been
+  // initialized.
+  if (!gfx::win::IsDeviceScaleFactorSet())
+    ui::win::InitDeviceScaleFactor();
 #endif
 }
 
@@ -614,8 +682,8 @@ void ResourceBundle::AddDataPackFromPathInternal(const base::FilePath& path,
 void ResourceBundle::AddDataPack(DataPack* data_pack) {
   data_packs_.push_back(data_pack);
 
-  if (GetImageScale(data_pack->GetScaleFactor()) >
-      GetImageScale(max_scale_factor_))
+  if (GetScaleForScaleFactor(data_pack->GetScaleFactor()) >
+      GetScaleForScaleFactor(max_scale_factor_))
     max_scale_factor_ = data_pack->GetScaleFactor();
 }
 
@@ -724,13 +792,10 @@ bool ResourceBundle::LoadBitmap(int resource_id,
                                 bool* fell_back_to_1x) const {
   DCHECK(fell_back_to_1x);
   for (size_t i = 0; i < data_packs_.size(); ++i) {
-    // If the resource is in the package with SCALE_FACTOR_NONE, it
-    // can be used in any scale factor, but set 100P in ImageSkia so
-    // that it will be scaled property.
     if (data_packs_[i]->GetScaleFactor() == ui::SCALE_FACTOR_NONE &&
         LoadBitmap(*data_packs_[i], resource_id, bitmap, fell_back_to_1x)) {
-      *scale_factor = ui::SCALE_FACTOR_100P;
       DCHECK(!*fell_back_to_1x);
+      *scale_factor = ui::SCALE_FACTOR_NONE;
       return true;
     }
     if (data_packs_[i]->GetScaleFactor() == *scale_factor &&
@@ -747,8 +812,7 @@ gfx::Image& ResourceBundle::GetEmptyImage() {
   if (empty_image_.IsEmpty()) {
     // The placeholder bitmap is bright red so people notice the problem.
     SkBitmap bitmap;
-    bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32, 32);
-    bitmap.allocPixels();
+    bitmap.allocN32Pixels(32, 32);
     bitmap.eraseARGB(255, 255, 0, 0);
     empty_image_ = gfx::Image::CreateFrom1xBitmap(bitmap);
   }
@@ -756,14 +820,8 @@ gfx::Image& ResourceBundle::GetEmptyImage() {
 }
 
 // static
-bool ResourceBundle::ShouldHighlightMissingScaledResources() {
-  return CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kHighlightMissingScaledResources);
-}
-
-// static
 bool ResourceBundle::PNGContainsFallbackMarker(const unsigned char* buf,
-                               size_t size) {
+                                               size_t size) {
   if (size < arraysize(kPngMagic) ||
       memcmp(buf, kPngMagic, arraysize(kPngMagic)) != 0) {
     // Data invalid or a JPEG.
@@ -777,7 +835,7 @@ bool ResourceBundle::PNGContainsFallbackMarker(const unsigned char* buf,
     if (size - pos < kPngChunkMetadataSize)
       break;
     uint32 length = 0;
-    net::ReadBigEndian(reinterpret_cast<const char*>(buf + pos), &length);
+    base::ReadBigEndian(reinterpret_cast<const char*>(buf + pos), &length);
     if (size - pos - kPngChunkMetadataSize < length)
       break;
     if (length == 0 && memcmp(buf + pos + sizeof(uint32), kPngScaleChunkType,