OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/base/resource/resource_bundle_android.h" | 5 #include "ui/base/resource/resource_bundle_android.h" |
6 | 6 |
7 #include "base/android/apk_assets.h" | 7 #include "base/android/apk_assets.h" |
8 #include "base/android/jni_android.h" | 8 #include "base/android/jni_android.h" |
9 #include "base/android/jni_string.h" | 9 #include "base/android/jni_string.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/memory/ptr_util.h" | |
12 #include "base/path_service.h" | 11 #include "base/path_service.h" |
13 #include "jni/ResourceBundle_jni.h" | 12 #include "jni/ResourceBundle_jni.h" |
14 #include "ui/base/l10n/l10n_util.h" | 13 #include "ui/base/l10n/l10n_util.h" |
15 #include "ui/base/resource/data_pack.h" | 14 #include "ui/base/resource/data_pack.h" |
16 #include "ui/base/resource/resource_bundle.h" | 15 #include "ui/base/resource/resource_bundle.h" |
17 #include "ui/base/ui_base_paths.h" | 16 #include "ui/base/ui_base_paths.h" |
18 | 17 |
19 namespace ui { | 18 namespace ui { |
20 | 19 |
21 namespace { | 20 namespace { |
22 | 21 |
23 bool g_locale_paks_in_apk = false; | 22 bool g_locale_paks_in_apk = false; |
24 bool g_load_secondary_locale_paks = false; | |
25 // It is okay to cache and share these file descriptors since the | 23 // It is okay to cache and share these file descriptors since the |
26 // ResourceBundle singleton never closes the handles. | 24 // ResourceBundle singleton never closes the handles. |
27 int g_chrome_100_percent_fd = -1; | 25 int g_chrome_100_percent_fd = -1; |
28 int g_resources_pack_fd = -1; | 26 int g_resources_pack_fd = -1; |
29 int g_locale_pack_fd = -1; | 27 int g_locale_pack_fd = -1; |
30 int g_secondary_locale_pack_fd = -1; | |
31 base::MemoryMappedFile::Region g_chrome_100_percent_region; | 28 base::MemoryMappedFile::Region g_chrome_100_percent_region; |
32 base::MemoryMappedFile::Region g_resources_pack_region; | 29 base::MemoryMappedFile::Region g_resources_pack_region; |
33 base::MemoryMappedFile::Region g_locale_pack_region; | 30 base::MemoryMappedFile::Region g_locale_pack_region; |
34 base::MemoryMappedFile::Region g_secondary_locale_pack_region; | |
35 | 31 |
36 bool LoadFromApkOrFile(const char* apk_path, | 32 bool LoadFromApkOrFile(const char* apk_path, |
37 const base::FilePath* disk_path, | 33 const base::FilePath* disk_path, |
38 int* out_fd, | 34 int* fd_out, |
39 base::MemoryMappedFile::Region* out_region) { | 35 base::MemoryMappedFile::Region* region_out) { |
40 DCHECK_EQ(*out_fd, -1) << "Attempt to load " << apk_path << " twice."; | 36 DCHECK_EQ(*fd_out, -1) << "Attempt to load " << apk_path << " twice."; |
41 if (apk_path != nullptr) { | 37 if (apk_path != nullptr) { |
42 *out_fd = base::android::OpenApkAsset(apk_path, out_region); | 38 *fd_out = base::android::OpenApkAsset(apk_path, region_out); |
43 } | 39 } |
44 // For unit tests, the file exists on disk. | 40 // For unit tests, the file exists on disk. |
45 if (*out_fd < 0 && disk_path != nullptr) { | 41 if (*fd_out < 0 && disk_path != nullptr) { |
46 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ; | 42 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ; |
47 *out_fd = base::File(*disk_path, flags).TakePlatformFile(); | 43 *fd_out = base::File(*disk_path, flags).TakePlatformFile(); |
48 *out_region = base::MemoryMappedFile::Region::kWholeFile; | 44 *region_out = base::MemoryMappedFile::Region::kWholeFile; |
49 } | 45 } |
50 bool success = *out_fd >= 0; | 46 bool success = *fd_out >= 0; |
51 if (!success) { | 47 if (!success) { |
52 LOG(ERROR) << "Failed to open pak file: " << apk_path; | 48 LOG(ERROR) << "Failed to open pak file: " << apk_path; |
53 } | 49 } |
54 return success; | 50 return success; |
55 } | 51 } |
56 | 52 |
57 int LoadLocalePakFromApk(const std::string& app_locale, | |
58 base::MemoryMappedFile::Region* out_region) { | |
59 std::string locale_path_within_apk = | |
60 GetPathForAndroidLocalePakWithinApk(app_locale); | |
61 if (locale_path_within_apk.empty()) { | |
62 LOG(ERROR) << "locale_path_within_apk.empty() for locale " | |
63 << app_locale; | |
64 return -1; | |
65 } | |
66 return base::android::OpenApkAsset(locale_path_within_apk, out_region); | |
67 } | |
68 | |
69 std::unique_ptr<DataPack> LoadDataPackFromLocalePak( | |
70 int locale_pack_fd, | |
71 const base::MemoryMappedFile::Region& region) { | |
72 auto data_pack = base::MakeUnique<DataPack>(SCALE_FACTOR_100P); | |
73 if (!data_pack->LoadFromFileRegion(base::File(locale_pack_fd), region)) { | |
74 LOG(ERROR) << "failed to load locale.pak"; | |
75 NOTREACHED(); | |
76 return nullptr; | |
77 } | |
78 return data_pack; | |
79 } | |
80 | |
81 } // namespace | 53 } // namespace |
82 | 54 |
83 void ResourceBundle::LoadCommonResources() { | 55 void ResourceBundle::LoadCommonResources() { |
84 base::FilePath disk_path; | 56 base::FilePath disk_path; |
85 PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &disk_path); | 57 PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &disk_path); |
86 disk_path = disk_path.AppendASCII("chrome_100_percent.pak"); | 58 disk_path = disk_path.AppendASCII("chrome_100_percent.pak"); |
87 if (LoadFromApkOrFile("assets/chrome_100_percent.pak", | 59 if (LoadFromApkOrFile("assets/chrome_100_percent.pak", |
88 &disk_path, | 60 &disk_path, |
89 &g_chrome_100_percent_fd, | 61 &g_chrome_100_percent_fd, |
90 &g_chrome_100_percent_region)) { | 62 &g_chrome_100_percent_region)) { |
91 AddDataPackFromFileRegion(base::File(g_chrome_100_percent_fd), | 63 AddDataPackFromFileRegion(base::File(g_chrome_100_percent_fd), |
92 g_chrome_100_percent_region, SCALE_FACTOR_100P); | 64 g_chrome_100_percent_region, SCALE_FACTOR_100P); |
93 } | 65 } |
94 } | 66 } |
95 | 67 |
96 bool ResourceBundle::LocaleDataPakExists(const std::string& locale) { | 68 bool ResourceBundle::LocaleDataPakExists(const std::string& locale) { |
97 if (g_locale_paks_in_apk) { | 69 if (g_locale_paks_in_apk) { |
98 return !GetPathForAndroidLocalePakWithinApk(locale).empty(); | 70 return !GetPathForAndroidLocalePakWithinApk(locale).empty(); |
99 } | 71 } |
100 return !GetLocaleFilePath(locale, true).empty(); | 72 return !GetLocaleFilePath(locale, true).empty(); |
101 } | 73 } |
102 | 74 |
103 std::string ResourceBundle::LoadLocaleResources( | 75 std::string ResourceBundle::LoadLocaleResources( |
104 const std::string& pref_locale) { | 76 const std::string& pref_locale) { |
105 DCHECK(!locale_resources_data_.get() && | 77 DCHECK(!locale_resources_data_.get()) << "locale.pak already loaded"; |
106 !secondary_locale_resources_data_.get()) | |
107 << "locale.pak already loaded"; | |
108 if (g_locale_pack_fd != -1) { | 78 if (g_locale_pack_fd != -1) { |
109 LOG(WARNING) | 79 LOG(WARNING) |
110 << "Unexpected (outside of tests): Loading a second locale pak file."; | 80 << "Unexpected (outside of tests): Loading a second locale pak file."; |
111 } | 81 } |
112 std::string app_locale = l10n_util::GetApplicationLocale(pref_locale); | 82 std::string app_locale = l10n_util::GetApplicationLocale(pref_locale); |
113 | |
114 // Load primary locale .pak file. | |
115 if (g_locale_paks_in_apk) { | 83 if (g_locale_paks_in_apk) { |
116 g_locale_pack_fd = LoadLocalePakFromApk(app_locale, &g_locale_pack_region); | 84 std::string locale_path_within_apk = |
| 85 GetPathForAndroidLocalePakWithinApk(app_locale); |
| 86 if (locale_path_within_apk.empty()) { |
| 87 LOG(WARNING) << "locale_path_within_apk.empty() for locale " |
| 88 << app_locale; |
| 89 return std::string(); |
| 90 } |
| 91 g_locale_pack_fd = base::android::OpenApkAsset(locale_path_within_apk, |
| 92 &g_locale_pack_region); |
117 } else { | 93 } else { |
118 base::FilePath locale_file_path = GetOverriddenPakPath(); | 94 base::FilePath locale_file_path = GetOverriddenPakPath(); |
119 if (locale_file_path.empty()) | 95 if (locale_file_path.empty()) |
120 locale_file_path = GetLocaleFilePath(app_locale, true); | 96 locale_file_path = GetLocaleFilePath(app_locale, true); |
121 | 97 |
122 if (locale_file_path.empty()) { | 98 if (locale_file_path.empty()) { |
123 // It's possible that there is no locale.pak. | 99 // It's possible that there is no locale.pak. |
124 LOG(WARNING) << "locale_file_path.empty() for locale " << app_locale; | 100 LOG(WARNING) << "locale_file_path.empty() for locale " << app_locale; |
125 return std::string(); | 101 return std::string(); |
126 } | 102 } |
127 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ; | 103 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ; |
128 g_locale_pack_fd = base::File(locale_file_path, flags).TakePlatformFile(); | 104 g_locale_pack_fd = base::File(locale_file_path, flags).TakePlatformFile(); |
129 g_locale_pack_region = base::MemoryMappedFile::Region::kWholeFile; | 105 g_locale_pack_region = base::MemoryMappedFile::Region::kWholeFile; |
130 } | 106 } |
131 | 107 |
132 locale_resources_data_ = LoadDataPackFromLocalePak( | 108 std::unique_ptr<DataPack> data_pack(new DataPack(SCALE_FACTOR_100P)); |
133 g_locale_pack_fd, g_locale_pack_region); | 109 if (!data_pack->LoadFromFileRegion(base::File(g_locale_pack_fd), |
134 | 110 g_locale_pack_region)) { |
135 if (!locale_resources_data_.get()) | 111 LOG(ERROR) << "failed to load locale.pak"; |
| 112 NOTREACHED(); |
136 return std::string(); | 113 return std::string(); |
137 | |
138 // Load secondary locale .pak file if it exists. For debug build monochrome, | |
139 // a secondary locale pak will always be loaded; however, it should be | |
140 // unnecessary for loading locale resources because the primary locale pak | |
141 // would have a copy of all the resources in the secondary locale pak. | |
142 if (g_load_secondary_locale_paks) { | |
143 g_secondary_locale_pack_fd = LoadLocalePakFromApk( | |
144 app_locale, &g_secondary_locale_pack_region); | |
145 | |
146 secondary_locale_resources_data_ = LoadDataPackFromLocalePak( | |
147 g_secondary_locale_pack_fd, g_secondary_locale_pack_region); | |
148 | |
149 if (!secondary_locale_resources_data_.get()) | |
150 return std::string(); | |
151 } | 114 } |
152 | 115 |
| 116 locale_resources_data_ = std::move(data_pack); |
153 return app_locale; | 117 return app_locale; |
154 } | 118 } |
155 | 119 |
156 gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id) { | 120 gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id) { |
157 return GetImageNamed(resource_id); | 121 return GetImageNamed(resource_id); |
158 } | 122 } |
159 | 123 |
160 void SetLocalePaksStoredInApk(bool value) { | 124 void SetLocalePaksStoredInApk(bool value) { |
161 g_locale_paks_in_apk = value; | 125 g_locale_paks_in_apk = value; |
162 } | 126 } |
163 | 127 |
164 void SetLoadSecondaryLocalePaks(bool value) { | |
165 g_load_secondary_locale_paks = value; | |
166 } | |
167 | |
168 void LoadMainAndroidPackFile(const char* path_within_apk, | 128 void LoadMainAndroidPackFile(const char* path_within_apk, |
169 const base::FilePath& disk_file_path) { | 129 const base::FilePath& disk_file_path) { |
170 if (LoadFromApkOrFile(path_within_apk, | 130 if (LoadFromApkOrFile(path_within_apk, |
171 &disk_file_path, | 131 &disk_file_path, |
172 &g_resources_pack_fd, | 132 &g_resources_pack_fd, |
173 &g_resources_pack_region)) { | 133 &g_resources_pack_region)) { |
174 ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion( | 134 ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion( |
175 base::File(g_resources_pack_fd), g_resources_pack_region, | 135 base::File(g_resources_pack_fd), g_resources_pack_region, |
176 SCALE_FACTOR_NONE); | 136 SCALE_FACTOR_NONE); |
177 } | 137 } |
(...skipping 10 matching lines...) Expand all Loading... |
188 *out_region = g_chrome_100_percent_region; | 148 *out_region = g_chrome_100_percent_region; |
189 return g_chrome_100_percent_fd; | 149 return g_chrome_100_percent_fd; |
190 } | 150 } |
191 | 151 |
192 int GetLocalePackFd(base::MemoryMappedFile::Region* out_region) { | 152 int GetLocalePackFd(base::MemoryMappedFile::Region* out_region) { |
193 DCHECK_GE(g_locale_pack_fd, 0); | 153 DCHECK_GE(g_locale_pack_fd, 0); |
194 *out_region = g_locale_pack_region; | 154 *out_region = g_locale_pack_region; |
195 return g_locale_pack_fd; | 155 return g_locale_pack_fd; |
196 } | 156 } |
197 | 157 |
198 int GetSecondaryLocalePackFd(base::MemoryMappedFile::Region* out_region) { | |
199 *out_region = g_secondary_locale_pack_region; | |
200 return g_secondary_locale_pack_fd; | |
201 } | |
202 | |
203 std::string GetPathForAndroidLocalePakWithinApk(const std::string& locale) { | 158 std::string GetPathForAndroidLocalePakWithinApk(const std::string& locale) { |
204 JNIEnv* env = base::android::AttachCurrentThread(); | 159 JNIEnv* env = base::android::AttachCurrentThread(); |
205 base::android::ScopedJavaLocalRef<jstring> ret = | 160 base::android::ScopedJavaLocalRef<jstring> ret = |
206 Java_ResourceBundle_getLocalePakResourcePath( | 161 Java_ResourceBundle_getLocalePakResourcePath( |
207 env, base::android::ConvertUTF8ToJavaString(env, locale)); | 162 env, base::android::ConvertUTF8ToJavaString(env, locale)); |
208 if (ret.obj() == nullptr) { | 163 if (ret.obj() == nullptr) { |
209 return std::string(); | 164 return std::string(); |
210 } | 165 } |
211 return base::android::ConvertJavaStringToUTF8(env, ret.obj()); | 166 return base::android::ConvertJavaStringToUTF8(env, ret.obj()); |
212 } | 167 } |
213 | 168 |
214 float GetPrimaryDisplayScale() { | 169 float GetPrimaryDisplayScale() { |
215 return Java_ResourceBundle_getPrimaryDisplayScale( | 170 return Java_ResourceBundle_getPrimaryDisplayScale( |
216 base::android::AttachCurrentThread()); | 171 base::android::AttachCurrentThread()); |
217 } | 172 } |
218 | 173 |
219 } // namespace ui | 174 } // namespace ui |
OLD | NEW |