Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(409)

Side by Side Diff: ui/base/resource/resource_bundle.cc

Issue 854713003: More old files deletion. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Fix tryjobs? Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/base/resource/resource_bundle.h ('k') | ui/base/resource/resource_bundle_android.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 <limits>
8 #include <vector>
9
10 #include "base/big_endian.h"
11 #include "base/command_line.h"
12 #include "base/files/file.h"
13 #include "base/files/file_util.h"
14 #include "base/logging.h"
15 #include "base/memory/ref_counted_memory.h"
16 #include "base/metrics/histogram.h"
17 #include "base/path_service.h"
18 #include "base/stl_util.h"
19 #include "base/strings/string_piece.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/synchronization/lock.h"
22 #include "build/build_config.h"
23 #include "skia/ext/image_operations.h"
24 #include "third_party/skia/include/core/SkBitmap.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/base/layout.h"
27 #include "ui/base/resource/data_pack.h"
28 #include "ui/base/ui_base_paths.h"
29 #include "ui/base/ui_base_switches.h"
30 #include "ui/gfx/codec/jpeg_codec.h"
31 #include "ui/gfx/codec/png_codec.h"
32 #include "ui/gfx/image/image_skia.h"
33 #include "ui/gfx/image/image_skia_source.h"
34 #include "ui/gfx/safe_integer_conversions.h"
35 #include "ui/gfx/screen.h"
36 #include "ui/gfx/size_conversions.h"
37 #include "ui/strings/grit/app_locale_settings.h"
38
39 #if defined(OS_ANDROID)
40 #include "ui/base/resource/resource_bundle_android.h"
41 #endif
42
43 #if defined(OS_CHROMEOS)
44 #include "ui/base/l10n/l10n_util.h"
45 #include "ui/gfx/platform_font_pango.h"
46 #endif
47
48 #if defined(OS_WIN)
49 #include "ui/base/win/dpi_setup.h"
50 #include "ui/gfx/win/dpi.h"
51 #endif
52
53 #if defined(OS_MACOSX) && !defined(OS_IOS)
54 #include "base/mac/mac_util.h"
55 #endif
56
57 namespace ui {
58
59 namespace {
60
61 // Font sizes relative to base font.
62 const int kSmallFontSizeDelta = -1;
63 const int kMediumFontSizeDelta = 3;
64 const int kLargeFontSizeDelta = 8;
65
66 // PNG-related constants.
67 const unsigned char kPngMagic[8] = { 0x89, 'P', 'N', 'G', 13, 10, 26, 10 };
68 const size_t kPngChunkMetadataSize = 12; // length, type, crc32
69 const unsigned char kPngScaleChunkType[4] = { 'c', 's', 'C', 'l' };
70 const unsigned char kPngDataChunkType[4] = { 'I', 'D', 'A', 'T' };
71
72 #if !defined(OS_MACOSX)
73 const char kPakFileSuffix[] = ".pak";
74 #endif
75
76 ResourceBundle* g_shared_instance_ = NULL;
77
78 void InitDefaultFontList() {
79 #if defined(OS_CHROMEOS) && defined(USE_PANGO)
80 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
81 std::string font_family = base::UTF16ToUTF8(
82 rb.GetLocalizedString(IDS_UI_FONT_FAMILY_CROS));
83 gfx::FontList::SetDefaultFontDescription(font_family);
84
85 // TODO(yukishiino): Remove SetDefaultFontDescription() once the migration to
86 // the font list is done. We will no longer need SetDefaultFontDescription()
87 // after every client gets started using a FontList instead of a Font.
88 gfx::PlatformFontPango::SetDefaultFontDescription(font_family);
89 #else
90 // Use a single default font as the default font list.
91 gfx::FontList::SetDefaultFontDescription(std::string());
92 #endif
93 }
94
95 #if defined(OS_ANDROID)
96 // Returns the scale factor closest to |scale| from the full list of factors.
97 // Note that it does NOT rely on the list of supported scale factors.
98 // Finding the closest match is inefficient and shouldn't be done frequently.
99 ScaleFactor FindClosestScaleFactorUnsafe(float scale) {
100 float smallest_diff = std::numeric_limits<float>::max();
101 ScaleFactor closest_match = SCALE_FACTOR_100P;
102 for (int i = SCALE_FACTOR_100P; i < NUM_SCALE_FACTORS; ++i) {
103 const ScaleFactor scale_factor = static_cast<ScaleFactor>(i);
104 float diff = std::abs(GetScaleForScaleFactor(scale_factor) - scale);
105 if (diff < smallest_diff) {
106 closest_match = scale_factor;
107 smallest_diff = diff;
108 }
109 }
110 return closest_match;
111 }
112 #endif // OS_ANDROID
113
114 } // namespace
115
116 // An ImageSkiaSource that loads bitmaps for the requested scale factor from
117 // ResourceBundle on demand for a given |resource_id|. If the bitmap for the
118 // requested scale factor does not exist, it will return the 1x bitmap scaled
119 // by the scale factor. This may lead to broken UI if the correct size of the
120 // scaled image is not exactly |scale_factor| * the size of the 1x resource.
121 // When --highlight-missing-scaled-resources flag is specified, scaled 1x images
122 // are higlighted by blending them with red.
123 class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource {
124 public:
125 ResourceBundleImageSource(ResourceBundle* rb, int resource_id)
126 : rb_(rb), resource_id_(resource_id) {}
127 ~ResourceBundleImageSource() override {}
128
129 // gfx::ImageSkiaSource overrides:
130 gfx::ImageSkiaRep GetImageForScale(float scale) override {
131 SkBitmap image;
132 bool fell_back_to_1x = false;
133 ScaleFactor scale_factor = GetSupportedScaleFactor(scale);
134 bool found = rb_->LoadBitmap(resource_id_, &scale_factor,
135 &image, &fell_back_to_1x);
136 if (!found)
137 return gfx::ImageSkiaRep();
138
139 // If the resource is in the package with SCALE_FACTOR_NONE, it
140 // can be used in any scale factor. The image is maked as "unscaled"
141 // so that the ImageSkia do not automatically scale.
142 if (scale_factor == ui::SCALE_FACTOR_NONE)
143 return gfx::ImageSkiaRep(image, 0.0f);
144
145 if (fell_back_to_1x) {
146 // GRIT fell back to the 100% image, so rescale it to the correct size.
147 image = skia::ImageOperations::Resize(
148 image,
149 skia::ImageOperations::RESIZE_LANCZOS3,
150 gfx::ToCeiledInt(image.width() * scale),
151 gfx::ToCeiledInt(image.height() * scale));
152 } else {
153 scale = GetScaleForScaleFactor(scale_factor);
154 }
155 return gfx::ImageSkiaRep(image, scale);
156 }
157
158 private:
159 ResourceBundle* rb_;
160 const int resource_id_;
161
162 DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageSource);
163 };
164
165 // static
166 std::string ResourceBundle::InitSharedInstanceWithLocale(
167 const std::string& pref_locale,
168 Delegate* delegate,
169 LoadResources load_resources) {
170 InitSharedInstance(delegate);
171 if (load_resources == LOAD_COMMON_RESOURCES)
172 g_shared_instance_->LoadCommonResources();
173 std::string result = g_shared_instance_->LoadLocaleResources(pref_locale);
174 InitDefaultFontList();
175 return result;
176 }
177
178 // static
179 void ResourceBundle::InitSharedInstanceWithPakFileRegion(
180 base::File pak_file,
181 const base::MemoryMappedFile::Region& region) {
182 InitSharedInstance(NULL);
183 scoped_ptr<DataPack> data_pack(new DataPack(SCALE_FACTOR_100P));
184 if (!data_pack->LoadFromFileRegion(pak_file.Pass(), region)) {
185 NOTREACHED() << "failed to load pak file";
186 return;
187 }
188 g_shared_instance_->locale_resources_data_.reset(data_pack.release());
189 InitDefaultFontList();
190 }
191
192 // static
193 void ResourceBundle::InitSharedInstanceWithPakPath(const base::FilePath& path) {
194 InitSharedInstance(NULL);
195 g_shared_instance_->LoadTestResources(path, path);
196
197 InitDefaultFontList();
198 }
199
200 // static
201 void ResourceBundle::CleanupSharedInstance() {
202 if (g_shared_instance_) {
203 delete g_shared_instance_;
204 g_shared_instance_ = NULL;
205 }
206 }
207
208 // static
209 bool ResourceBundle::HasSharedInstance() {
210 return g_shared_instance_ != NULL;
211 }
212
213 // static
214 ResourceBundle& ResourceBundle::GetSharedInstance() {
215 // Must call InitSharedInstance before this function.
216 CHECK(g_shared_instance_ != NULL);
217 return *g_shared_instance_;
218 }
219
220 bool ResourceBundle::LocaleDataPakExists(const std::string& locale) {
221 bool locale_file_path_exists = !GetLocaleFilePath(locale, true).empty();
222 #if defined(OS_ANDROID)
223 // TODO(mkosiba,primiano): Chrome should mmap the .pak files too, in which
224 // case we'd not need to check if locale_file_path_exists here.
225 // http://crbug.com/394502.
226 return locale_file_path_exists ||
227 AssetContainedInApk(locale + kPakFileSuffix);
228 #else
229 return locale_file_path_exists;
230 #endif
231 }
232
233 void ResourceBundle::AddDataPackFromPath(const base::FilePath& path,
234 ScaleFactor scale_factor) {
235 AddDataPackFromPathInternal(path, scale_factor, false);
236 }
237
238 void ResourceBundle::AddOptionalDataPackFromPath(const base::FilePath& path,
239 ScaleFactor scale_factor) {
240 AddDataPackFromPathInternal(path, scale_factor, true);
241 }
242
243 void ResourceBundle::AddDataPackFromFile(base::File file,
244 ScaleFactor scale_factor) {
245 AddDataPackFromFileRegion(
246 file.Pass(), base::MemoryMappedFile::Region::kWholeFile, scale_factor);
247 }
248
249 void ResourceBundle::AddDataPackFromFileRegion(
250 base::File file,
251 const base::MemoryMappedFile::Region& region,
252 ScaleFactor scale_factor) {
253 scoped_ptr<DataPack> data_pack(
254 new DataPack(scale_factor));
255 if (data_pack->LoadFromFileRegion(file.Pass(), region)) {
256 AddDataPack(data_pack.release());
257 } else {
258 LOG(ERROR) << "Failed to load data pack from file."
259 << "\nSome features may not be available.";
260 }
261 }
262
263 #if !defined(OS_MACOSX)
264 base::FilePath ResourceBundle::GetLocaleFilePath(const std::string& app_locale,
265 bool test_file_exists) {
266 if (app_locale.empty())
267 return base::FilePath();
268
269 base::FilePath locale_file_path;
270
271 PathService::Get(ui::DIR_LOCALES, &locale_file_path);
272
273 if (!locale_file_path.empty()) {
274 locale_file_path =
275 locale_file_path.AppendASCII(app_locale + kPakFileSuffix);
276 }
277
278 if (delegate_) {
279 locale_file_path =
280 delegate_->GetPathForLocalePack(locale_file_path, app_locale);
281 }
282
283 // Don't try to load empty values or values that are not absolute paths.
284 if (locale_file_path.empty() || !locale_file_path.IsAbsolute())
285 return base::FilePath();
286
287 if (test_file_exists && !base::PathExists(locale_file_path))
288 return base::FilePath();
289
290 return locale_file_path;
291 }
292 #endif
293
294 std::string ResourceBundle::LoadLocaleResources(
295 const std::string& pref_locale) {
296 DCHECK(!locale_resources_data_.get()) << "locale.pak already loaded";
297 std::string app_locale = l10n_util::GetApplicationLocale(pref_locale);
298 base::FilePath locale_file_path = GetOverriddenPakPath();
299 if (locale_file_path.empty())
300 locale_file_path = GetLocaleFilePath(app_locale, true);
301
302 if (locale_file_path.empty()) {
303 // It's possible that there is no locale.pak.
304 LOG(WARNING) << "locale_file_path.empty()";
305 return std::string();
306 }
307
308 scoped_ptr<DataPack> data_pack(
309 new DataPack(SCALE_FACTOR_100P));
310 if (!data_pack->LoadFromPath(locale_file_path)) {
311 UMA_HISTOGRAM_ENUMERATION("ResourceBundle.LoadLocaleResourcesError",
312 logging::GetLastSystemErrorCode(), 16000);
313 LOG(ERROR) << "failed to load locale.pak";
314 NOTREACHED();
315 return std::string();
316 }
317
318 locale_resources_data_.reset(data_pack.release());
319 return app_locale;
320 }
321
322 void ResourceBundle::LoadTestResources(const base::FilePath& path,
323 const base::FilePath& locale_path) {
324 DCHECK(!ui::GetSupportedScaleFactors().empty());
325 const ScaleFactor scale_factor(ui::GetSupportedScaleFactors()[0]);
326 // Use the given resource pak for both common and localized resources.
327 scoped_ptr<DataPack> data_pack(new DataPack(scale_factor));
328 if (!path.empty() && data_pack->LoadFromPath(path))
329 AddDataPack(data_pack.release());
330
331 data_pack.reset(new DataPack(ui::SCALE_FACTOR_NONE));
332 if (!locale_path.empty() && data_pack->LoadFromPath(locale_path)) {
333 locale_resources_data_.reset(data_pack.release());
334 } else {
335 locale_resources_data_.reset(new DataPack(ui::SCALE_FACTOR_NONE));
336 }
337 }
338
339 void ResourceBundle::UnloadLocaleResources() {
340 locale_resources_data_.reset();
341 }
342
343 void ResourceBundle::OverrideLocalePakForTest(const base::FilePath& pak_path) {
344 overridden_pak_path_ = pak_path;
345 }
346
347 void ResourceBundle::OverrideLocaleStringResource(
348 int message_id,
349 const base::string16& string) {
350 overridden_locale_strings_[message_id] = string;
351 }
352
353 const base::FilePath& ResourceBundle::GetOverriddenPakPath() {
354 return overridden_pak_path_;
355 }
356
357 std::string ResourceBundle::ReloadLocaleResources(
358 const std::string& pref_locale) {
359 base::AutoLock lock_scope(*locale_resources_data_lock_);
360
361 // Remove all overriden strings, as they will not be valid for the new locale.
362 overridden_locale_strings_.clear();
363
364 UnloadLocaleResources();
365 return LoadLocaleResources(pref_locale);
366 }
367
368 gfx::ImageSkia* ResourceBundle::GetImageSkiaNamed(int resource_id) {
369 const gfx::ImageSkia* image = GetImageNamed(resource_id).ToImageSkia();
370 return const_cast<gfx::ImageSkia*>(image);
371 }
372
373 gfx::Image& ResourceBundle::GetImageNamed(int resource_id) {
374 // Check to see if the image is already in the cache.
375 {
376 base::AutoLock lock_scope(*images_and_fonts_lock_);
377 if (images_.count(resource_id))
378 return images_[resource_id];
379 }
380
381 gfx::Image image;
382 if (delegate_)
383 image = delegate_->GetImageNamed(resource_id);
384
385 if (image.IsEmpty()) {
386 DCHECK(!data_packs_.empty()) <<
387 "Missing call to SetResourcesDataDLL?";
388
389 #if defined(OS_CHROMEOS) || defined(OS_WIN)
390 ui::ScaleFactor scale_factor_to_load = GetMaxScaleFactor();
391 #else
392 ui::ScaleFactor scale_factor_to_load = ui::SCALE_FACTOR_100P;
393 #endif
394
395 // TODO(oshima): Consider reading the image size from png IHDR chunk and
396 // skip decoding here and remove #ifdef below.
397 // ResourceBundle::GetSharedInstance() is destroyed after the
398 // BrowserMainLoop has finished running. |image_skia| is guaranteed to be
399 // destroyed before the resource bundle is destroyed.
400 gfx::ImageSkia image_skia(new ResourceBundleImageSource(this, resource_id),
401 GetScaleForScaleFactor(scale_factor_to_load));
402 if (image_skia.isNull()) {
403 LOG(WARNING) << "Unable to load image with id " << resource_id;
404 NOTREACHED(); // Want to assert in debug mode.
405 // The load failed to retrieve the image; show a debugging red square.
406 return GetEmptyImage();
407 }
408 image_skia.SetReadOnly();
409 image = gfx::Image(image_skia);
410 }
411
412 // The load was successful, so cache the image.
413 base::AutoLock lock_scope(*images_and_fonts_lock_);
414
415 // Another thread raced the load and has already cached the image.
416 if (images_.count(resource_id))
417 return images_[resource_id];
418
419 images_[resource_id] = image;
420 return images_[resource_id];
421 }
422
423 gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id) {
424 return GetNativeImageNamed(resource_id, RTL_DISABLED);
425 }
426
427 base::RefCountedStaticMemory* ResourceBundle::LoadDataResourceBytes(
428 int resource_id) const {
429 return LoadDataResourceBytesForScale(resource_id, ui::SCALE_FACTOR_NONE);
430 }
431
432 base::RefCountedStaticMemory* ResourceBundle::LoadDataResourceBytesForScale(
433 int resource_id,
434 ScaleFactor scale_factor) const {
435 base::RefCountedStaticMemory* bytes = NULL;
436 if (delegate_)
437 bytes = delegate_->LoadDataResourceBytes(resource_id, scale_factor);
438
439 if (!bytes) {
440 base::StringPiece data =
441 GetRawDataResourceForScale(resource_id, scale_factor);
442 if (!data.empty()) {
443 bytes = new base::RefCountedStaticMemory(data.data(), data.length());
444 }
445 }
446
447 return bytes;
448 }
449
450 base::StringPiece ResourceBundle::GetRawDataResource(int resource_id) const {
451 return GetRawDataResourceForScale(resource_id, ui::SCALE_FACTOR_NONE);
452 }
453
454 base::StringPiece ResourceBundle::GetRawDataResourceForScale(
455 int resource_id,
456 ScaleFactor scale_factor) const {
457 base::StringPiece data;
458 if (delegate_ &&
459 delegate_->GetRawDataResource(resource_id, scale_factor, &data))
460 return data;
461
462 if (scale_factor != ui::SCALE_FACTOR_100P) {
463 for (size_t i = 0; i < data_packs_.size(); i++) {
464 if (data_packs_[i]->GetScaleFactor() == scale_factor &&
465 data_packs_[i]->GetStringPiece(static_cast<uint16>(resource_id),
466 &data))
467 return data;
468 }
469 }
470 for (size_t i = 0; i < data_packs_.size(); i++) {
471 if ((data_packs_[i]->GetScaleFactor() == ui::SCALE_FACTOR_100P ||
472 data_packs_[i]->GetScaleFactor() == ui::SCALE_FACTOR_200P ||
473 data_packs_[i]->GetScaleFactor() == ui::SCALE_FACTOR_NONE) &&
474 data_packs_[i]->GetStringPiece(static_cast<uint16>(resource_id),
475 &data))
476 return data;
477 }
478
479 return base::StringPiece();
480 }
481
482 base::string16 ResourceBundle::GetLocalizedString(int message_id) {
483 base::string16 string;
484 if (delegate_ && delegate_->GetLocalizedString(message_id, &string))
485 return string;
486
487 // Ensure that ReloadLocaleResources() doesn't drop the resources while
488 // we're using them.
489 base::AutoLock lock_scope(*locale_resources_data_lock_);
490
491 IdToStringMap::const_iterator it =
492 overridden_locale_strings_.find(message_id);
493 if (it != overridden_locale_strings_.end())
494 return it->second;
495
496 // If for some reason we were unable to load the resources , return an empty
497 // string (better than crashing).
498 if (!locale_resources_data_.get()) {
499 LOG(WARNING) << "locale resources are not loaded";
500 return base::string16();
501 }
502
503 base::StringPiece data;
504 if (!locale_resources_data_->GetStringPiece(static_cast<uint16>(message_id),
505 &data)) {
506 // Fall back on the main data pack (shouldn't be any strings here except in
507 // unittests).
508 data = GetRawDataResource(message_id);
509 if (data.empty()) {
510 NOTREACHED() << "unable to find resource: " << message_id;
511 return base::string16();
512 }
513 }
514
515 // Strings should not be loaded from a data pack that contains binary data.
516 ResourceHandle::TextEncodingType encoding =
517 locale_resources_data_->GetTextEncodingType();
518 DCHECK(encoding == ResourceHandle::UTF16 || encoding == ResourceHandle::UTF8)
519 << "requested localized string from binary pack file";
520
521 // Data pack encodes strings as either UTF8 or UTF16.
522 base::string16 msg;
523 if (encoding == ResourceHandle::UTF16) {
524 msg = base::string16(reinterpret_cast<const base::char16*>(data.data()),
525 data.length() / 2);
526 } else if (encoding == ResourceHandle::UTF8) {
527 msg = base::UTF8ToUTF16(data);
528 }
529 return msg;
530 }
531
532 const gfx::FontList& ResourceBundle::GetFontList(FontStyle style) {
533 {
534 base::AutoLock lock_scope(*images_and_fonts_lock_);
535 LoadFontsIfNecessary();
536 }
537 switch (style) {
538 case BoldFont:
539 return *bold_font_list_;
540 case SmallFont:
541 return *small_font_list_;
542 case MediumFont:
543 return *medium_font_list_;
544 case SmallBoldFont:
545 return *small_bold_font_list_;
546 case MediumBoldFont:
547 return *medium_bold_font_list_;
548 case LargeFont:
549 return *large_font_list_;
550 case LargeBoldFont:
551 return *large_bold_font_list_;
552 default:
553 return *base_font_list_;
554 }
555 }
556
557 const gfx::Font& ResourceBundle::GetFont(FontStyle style) {
558 return GetFontList(style).GetPrimaryFont();
559 }
560
561 void ResourceBundle::ReloadFonts() {
562 base::AutoLock lock_scope(*images_and_fonts_lock_);
563 base_font_list_.reset();
564 LoadFontsIfNecessary();
565 }
566
567 ScaleFactor ResourceBundle::GetMaxScaleFactor() const {
568 #if defined(OS_CHROMEOS) || defined(OS_WIN)
569 return max_scale_factor_;
570 #else
571 return GetSupportedScaleFactors().back();
572 #endif
573 }
574
575 bool ResourceBundle::IsScaleFactorSupported(ScaleFactor scale_factor) {
576 const std::vector<ScaleFactor>& supported_scale_factors =
577 ui::GetSupportedScaleFactors();
578 return std::find(supported_scale_factors.begin(),
579 supported_scale_factors.end(),
580 scale_factor) != supported_scale_factors.end();
581 }
582
583 ResourceBundle::ResourceBundle(Delegate* delegate)
584 : delegate_(delegate),
585 images_and_fonts_lock_(new base::Lock),
586 locale_resources_data_lock_(new base::Lock),
587 max_scale_factor_(SCALE_FACTOR_100P) {
588 }
589
590 ResourceBundle::~ResourceBundle() {
591 FreeImages();
592 UnloadLocaleResources();
593 }
594
595 // static
596 void ResourceBundle::InitSharedInstance(Delegate* delegate) {
597 DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice";
598 g_shared_instance_ = new ResourceBundle(delegate);
599 static std::vector<ScaleFactor> supported_scale_factors;
600 #if !defined(OS_IOS) && !defined(OS_WIN)
601 // On platforms other than iOS, 100P is always a supported scale factor.
602 // For Windows we have a separate case in this function.
603 supported_scale_factors.push_back(SCALE_FACTOR_100P);
604 #endif
605 #if defined(OS_ANDROID)
606 const gfx::Display display =
607 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
608 const float display_density = display.device_scale_factor();
609 const ScaleFactor closest = FindClosestScaleFactorUnsafe(display_density);
610 if (closest != SCALE_FACTOR_100P)
611 supported_scale_factors.push_back(closest);
612 #elif defined(OS_IOS)
613 gfx::Display display = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
614 if (display.device_scale_factor() > 2.0) {
615 DCHECK_EQ(3.0, display.device_scale_factor());
616 supported_scale_factors.push_back(SCALE_FACTOR_300P);
617 } else if (display.device_scale_factor() > 1.0) {
618 DCHECK_EQ(2.0, display.device_scale_factor());
619 supported_scale_factors.push_back(SCALE_FACTOR_200P);
620 } else {
621 supported_scale_factors.push_back(SCALE_FACTOR_100P);
622 }
623 #elif defined(OS_MACOSX)
624 if (base::mac::IsOSLionOrLater())
625 supported_scale_factors.push_back(SCALE_FACTOR_200P);
626 #elif defined(OS_CHROMEOS)
627 // TODO(oshima): Include 200P only if the device support 200P
628 supported_scale_factors.push_back(SCALE_FACTOR_200P);
629 #elif defined(OS_LINUX) && defined(ENABLE_HIDPI)
630 supported_scale_factors.push_back(SCALE_FACTOR_200P);
631 #elif defined(OS_WIN)
632 bool default_to_100P = true;
633 if (gfx::IsHighDPIEnabled()) {
634 // On Windows if the dpi scale is greater than 1.25 on high dpi machines
635 // downscaling from 200 percent looks better than scaling up from 100
636 // percent.
637 if (gfx::GetDPIScale() > 1.25) {
638 supported_scale_factors.push_back(SCALE_FACTOR_200P);
639 default_to_100P = false;
640 }
641 }
642 if (default_to_100P)
643 supported_scale_factors.push_back(SCALE_FACTOR_100P);
644 #endif
645 ui::SetSupportedScaleFactors(supported_scale_factors);
646 #if defined(OS_WIN)
647 // Must be called _after_ supported scale factors are set since it
648 // uses them.
649 // Don't initialize the device scale factor if it has already been
650 // initialized.
651 if (!gfx::win::IsDeviceScaleFactorSet())
652 ui::win::InitDeviceScaleFactor();
653 #endif
654 }
655
656 void ResourceBundle::FreeImages() {
657 images_.clear();
658 }
659
660 void ResourceBundle::AddDataPackFromPathInternal(const base::FilePath& path,
661 ScaleFactor scale_factor,
662 bool optional) {
663 // Do not pass an empty |path| value to this method. If the absolute path is
664 // unknown pass just the pack file name.
665 DCHECK(!path.empty());
666
667 base::FilePath pack_path = path;
668 if (delegate_)
669 pack_path = delegate_->GetPathForResourcePack(pack_path, scale_factor);
670
671 // Don't try to load empty values or values that are not absolute paths.
672 if (pack_path.empty() || !pack_path.IsAbsolute())
673 return;
674
675 scoped_ptr<DataPack> data_pack(
676 new DataPack(scale_factor));
677 if (data_pack->LoadFromPath(pack_path)) {
678 AddDataPack(data_pack.release());
679 } else if (!optional) {
680 LOG(ERROR) << "Failed to load " << pack_path.value()
681 << "\nSome features may not be available.";
682 }
683 }
684
685 void ResourceBundle::AddDataPack(DataPack* data_pack) {
686 data_packs_.push_back(data_pack);
687
688 if (GetScaleForScaleFactor(data_pack->GetScaleFactor()) >
689 GetScaleForScaleFactor(max_scale_factor_))
690 max_scale_factor_ = data_pack->GetScaleFactor();
691 }
692
693 void ResourceBundle::LoadFontsIfNecessary() {
694 images_and_fonts_lock_->AssertAcquired();
695 if (!base_font_list_.get()) {
696 if (delegate_) {
697 base_font_list_ = GetFontListFromDelegate(BaseFont);
698 bold_font_list_ = GetFontListFromDelegate(BoldFont);
699 small_font_list_ = GetFontListFromDelegate(SmallFont);
700 small_bold_font_list_ = GetFontListFromDelegate(SmallBoldFont);
701 medium_font_list_ = GetFontListFromDelegate(MediumFont);
702 medium_bold_font_list_ = GetFontListFromDelegate(MediumBoldFont);
703 large_font_list_ = GetFontListFromDelegate(LargeFont);
704 large_bold_font_list_ = GetFontListFromDelegate(LargeBoldFont);
705 }
706
707 if (!base_font_list_.get())
708 base_font_list_.reset(new gfx::FontList());
709
710 if (!bold_font_list_.get()) {
711 bold_font_list_.reset(new gfx::FontList());
712 *bold_font_list_ = base_font_list_->DeriveWithStyle(
713 base_font_list_->GetFontStyle() | gfx::Font::BOLD);
714 }
715
716 if (!small_font_list_.get()) {
717 small_font_list_.reset(new gfx::FontList());
718 *small_font_list_ =
719 base_font_list_->DeriveWithSizeDelta(kSmallFontSizeDelta);
720 }
721
722 if (!small_bold_font_list_.get()) {
723 small_bold_font_list_.reset(new gfx::FontList());
724 *small_bold_font_list_ = small_font_list_->DeriveWithStyle(
725 small_font_list_->GetFontStyle() | gfx::Font::BOLD);
726 }
727
728 if (!medium_font_list_.get()) {
729 medium_font_list_.reset(new gfx::FontList());
730 *medium_font_list_ =
731 base_font_list_->DeriveWithSizeDelta(kMediumFontSizeDelta);
732 }
733
734 if (!medium_bold_font_list_.get()) {
735 medium_bold_font_list_.reset(new gfx::FontList());
736 *medium_bold_font_list_ = medium_font_list_->DeriveWithStyle(
737 medium_font_list_->GetFontStyle() | gfx::Font::BOLD);
738 }
739
740 if (!large_font_list_.get()) {
741 large_font_list_.reset(new gfx::FontList());
742 *large_font_list_ =
743 base_font_list_->DeriveWithSizeDelta(kLargeFontSizeDelta);
744 }
745
746 if (!large_bold_font_list_.get()) {
747 large_bold_font_list_.reset(new gfx::FontList());
748 *large_bold_font_list_ = large_font_list_->DeriveWithStyle(
749 large_font_list_->GetFontStyle() | gfx::Font::BOLD);
750 }
751 }
752 }
753
754 scoped_ptr<gfx::FontList> ResourceBundle::GetFontListFromDelegate(
755 FontStyle style) {
756 DCHECK(delegate_);
757 scoped_ptr<gfx::Font> font = delegate_->GetFont(style);
758 if (font.get())
759 return scoped_ptr<gfx::FontList>(new gfx::FontList(*font));
760 return scoped_ptr<gfx::FontList>();
761 }
762
763 bool ResourceBundle::LoadBitmap(const ResourceHandle& data_handle,
764 int resource_id,
765 SkBitmap* bitmap,
766 bool* fell_back_to_1x) const {
767 DCHECK(fell_back_to_1x);
768 scoped_refptr<base::RefCountedMemory> memory(
769 data_handle.GetStaticMemory(static_cast<uint16>(resource_id)));
770 if (!memory.get())
771 return false;
772
773 if (DecodePNG(memory->front(), memory->size(), bitmap, fell_back_to_1x))
774 return true;
775
776 #if !defined(OS_IOS)
777 // iOS does not compile or use the JPEG codec. On other platforms,
778 // 99% of our assets are PNGs, however fallback to JPEG.
779 scoped_ptr<SkBitmap> jpeg_bitmap(
780 gfx::JPEGCodec::Decode(memory->front(), memory->size()));
781 if (jpeg_bitmap.get()) {
782 bitmap->swap(*jpeg_bitmap.get());
783 *fell_back_to_1x = false;
784 return true;
785 }
786 #endif
787
788 NOTREACHED() << "Unable to decode theme image resource " << resource_id;
789 return false;
790 }
791
792 bool ResourceBundle::LoadBitmap(int resource_id,
793 ScaleFactor* scale_factor,
794 SkBitmap* bitmap,
795 bool* fell_back_to_1x) const {
796 DCHECK(fell_back_to_1x);
797 for (size_t i = 0; i < data_packs_.size(); ++i) {
798 if (data_packs_[i]->GetScaleFactor() == ui::SCALE_FACTOR_NONE &&
799 LoadBitmap(*data_packs_[i], resource_id, bitmap, fell_back_to_1x)) {
800 DCHECK(!*fell_back_to_1x);
801 *scale_factor = ui::SCALE_FACTOR_NONE;
802 return true;
803 }
804 if (data_packs_[i]->GetScaleFactor() == *scale_factor &&
805 LoadBitmap(*data_packs_[i], resource_id, bitmap, fell_back_to_1x)) {
806 return true;
807 }
808 }
809 return false;
810 }
811
812 gfx::Image& ResourceBundle::GetEmptyImage() {
813 base::AutoLock lock(*images_and_fonts_lock_);
814
815 if (empty_image_.IsEmpty()) {
816 // The placeholder bitmap is bright red so people notice the problem.
817 SkBitmap bitmap;
818 bitmap.allocN32Pixels(32, 32);
819 bitmap.eraseARGB(255, 255, 0, 0);
820 empty_image_ = gfx::Image::CreateFrom1xBitmap(bitmap);
821 }
822 return empty_image_;
823 }
824
825 // static
826 bool ResourceBundle::PNGContainsFallbackMarker(const unsigned char* buf,
827 size_t size) {
828 if (size < arraysize(kPngMagic) ||
829 memcmp(buf, kPngMagic, arraysize(kPngMagic)) != 0) {
830 // Data invalid or a JPEG.
831 return false;
832 }
833 size_t pos = arraysize(kPngMagic);
834
835 // Scan for custom chunks until we find one, find the IDAT chunk, or run out
836 // of chunks.
837 for (;;) {
838 if (size - pos < kPngChunkMetadataSize)
839 break;
840 uint32 length = 0;
841 base::ReadBigEndian(reinterpret_cast<const char*>(buf + pos), &length);
842 if (size - pos - kPngChunkMetadataSize < length)
843 break;
844 if (length == 0 && memcmp(buf + pos + sizeof(uint32), kPngScaleChunkType,
845 arraysize(kPngScaleChunkType)) == 0) {
846 return true;
847 }
848 if (memcmp(buf + pos + sizeof(uint32), kPngDataChunkType,
849 arraysize(kPngDataChunkType)) == 0) {
850 // Stop looking for custom chunks, any custom chunks should be before an
851 // IDAT chunk.
852 break;
853 }
854 pos += length + kPngChunkMetadataSize;
855 }
856 return false;
857 }
858
859 // static
860 bool ResourceBundle::DecodePNG(const unsigned char* buf,
861 size_t size,
862 SkBitmap* bitmap,
863 bool* fell_back_to_1x) {
864 *fell_back_to_1x = PNGContainsFallbackMarker(buf, size);
865 return gfx::PNGCodec::Decode(buf, size, bitmap);
866 }
867
868 } // namespace ui
OLDNEW
« no previous file with comments | « ui/base/resource/resource_bundle.h ('k') | ui/base/resource/resource_bundle_android.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698