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.
5 #include "ui/base/resource/resource_bundle.h"
9 #include "base/command_line.h"
10 #include "base/file_util.h"
11 #include "base/logging.h"
12 #include "base/memory/ref_counted_memory.h"
13 #include "base/metrics/histogram.h"
14 #include "base/path_service.h"
15 #include "base/stl_util.h"
16 #include "base/strings/string_piece.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/synchronization/lock.h"
19 #include "build/build_config.h"
20 #include "grit/app_locale_settings.h"
21 #include "net/base/big_endian.h"
22 #include "skia/ext/image_operations.h"
23 #include "third_party/skia/include/core/SkBitmap.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/base/layout.h"
26 #include "ui/base/resource/data_pack.h"
27 #include "ui/base/ui_base_paths.h"
28 #include "ui/base/ui_base_switches.h"
29 #include "ui/gfx/codec/jpeg_codec.h"
30 #include "ui/gfx/codec/png_codec.h"
31 #include "ui/gfx/image/image_skia.h"
32 #include "ui/gfx/image/image_skia_source.h"
33 #include "ui/gfx/safe_integer_conversions.h"
34 #include "ui/gfx/screen.h"
35 #include "ui/gfx/size_conversions.h"
36 #include "ui/gfx/skbitmap_operations.h"
38 #if defined(OS_CHROMEOS)
39 #include "ui/base/l10n/l10n_util.h"
40 #include "ui/gfx/platform_font_pango.h"
44 #include "ui/base/win/dpi_setup.h"
45 #include "ui/gfx/win/dpi.h"
48 #if defined(OS_MACOSX) && !defined(OS_IOS)
49 #include "base/mac/mac_util.h"
56 // Font sizes relative to base font.
57 const int kSmallFontSizeDelta
= -1;
58 const int kMediumFontSizeDelta
= 3;
59 const int kLargeFontSizeDelta
= 8;
61 // PNG-related constants.
62 const unsigned char kPngMagic
[8] = { 0x89, 'P', 'N', 'G', 13, 10, 26, 10 };
63 const size_t kPngChunkMetadataSize
= 12; // length, type, crc32
64 const unsigned char kPngScaleChunkType
[4] = { 'c', 's', 'C', 'l' };
65 const unsigned char kPngDataChunkType
[4] = { 'I', 'D', 'A', 'T' };
67 ResourceBundle
* g_shared_instance_
= NULL
;
69 void InitDefaultFontList() {
70 #if defined(OS_CHROMEOS)
71 gfx::FontList::SetDefaultFontDescription(
72 l10n_util::GetStringUTF8(IDS_UI_FONT_FAMILY_CROS
));
74 // TODO(yukishiino): Remove SetDefaultFontDescription() once the migration to
75 // the font list is done. We will no longer need SetDefaultFontDescription()
76 // after every client gets started using a FontList instead of a Font.
77 gfx::PlatformFontPango::SetDefaultFontDescription(
78 l10n_util::GetStringUTF8(IDS_UI_FONT_FAMILY_CROS
));
80 // Use a single default font as the default font list.
81 gfx::FontList::SetDefaultFontDescription(std::string());
87 // An ImageSkiaSource that loads bitmaps for the requested scale factor from
88 // ResourceBundle on demand for a given |resource_id|. If the bitmap for the
89 // requested scale factor does not exist, it will return the 1x bitmap scaled
90 // by the scale factor. This may lead to broken UI if the correct size of the
91 // scaled image is not exactly |scale_factor| * the size of the 1x resource.
92 // When --highlight-missing-scaled-resources flag is specified, scaled 1x images
93 // are higlighted by blending them with red.
94 class ResourceBundle::ResourceBundleImageSource
: public gfx::ImageSkiaSource
{
96 ResourceBundleImageSource(ResourceBundle
* rb
, int resource_id
)
97 : rb_(rb
), resource_id_(resource_id
) {}
98 virtual ~ResourceBundleImageSource() {}
100 // gfx::ImageSkiaSource overrides:
101 virtual gfx::ImageSkiaRep
GetImageForScale(float scale
) OVERRIDE
{
103 bool fell_back_to_1x
= false;
104 ScaleFactor scale_factor
= GetSupportedScaleFactor(scale
);
105 bool found
= rb_
->LoadBitmap(resource_id_
, &scale_factor
,
106 &image
, &fell_back_to_1x
);
107 // Force to a supported scale.
108 scale
= ui::GetImageScale(scale_factor
);
110 return gfx::ImageSkiaRep();
112 if (fell_back_to_1x
) {
113 // GRIT fell back to the 100% image, so rescale it to the correct size.
114 image
= skia::ImageOperations::Resize(
116 skia::ImageOperations::RESIZE_LANCZOS3
,
117 gfx::ToCeiledInt(image
.width() * scale
),
118 gfx::ToCeiledInt(image
.height() * scale
));
119 // If --highlight-missing-scaled-resources is specified, log the resource
120 // id and blend the created resource with red.
121 if (ShouldHighlightMissingScaledResources()) {
122 LOG(ERROR
) << "Missing " << scale
<< "x scaled resource. id="
126 mask
.setConfig(SkBitmap::kARGB_8888_Config
,
127 image
.width(), image
.height());
129 mask
.eraseColor(SK_ColorRED
);
130 image
= SkBitmapOperations::CreateBlendedBitmap(image
, mask
, 0.2);
134 return gfx::ImageSkiaRep(image
, scale
);
139 const int resource_id_
;
141 DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageSource
);
145 std::string
ResourceBundle::InitSharedInstanceWithLocale(
146 const std::string
& pref_locale
, Delegate
* delegate
) {
147 InitSharedInstance(delegate
);
148 g_shared_instance_
->LoadCommonResources();
149 std::string result
= g_shared_instance_
->LoadLocaleResources(pref_locale
);
150 InitDefaultFontList();
155 std::string
ResourceBundle::InitSharedInstanceLocaleOnly(
156 const std::string
& pref_locale
, Delegate
* delegate
) {
157 InitSharedInstance(delegate
);
158 std::string result
= g_shared_instance_
->LoadLocaleResources(pref_locale
);
159 InitDefaultFontList();
164 void ResourceBundle::InitSharedInstanceWithPakFile(
165 base::File pak_file
, bool should_load_common_resources
) {
166 InitSharedInstance(NULL
);
167 if (should_load_common_resources
)
168 g_shared_instance_
->LoadCommonResources();
170 scoped_ptr
<DataPack
> data_pack(
171 new DataPack(SCALE_FACTOR_100P
));
172 if (!data_pack
->LoadFromFile(pak_file
.Pass())) {
173 NOTREACHED() << "failed to load pak file";
176 g_shared_instance_
->locale_resources_data_
.reset(data_pack
.release());
177 InitDefaultFontList();
181 void ResourceBundle::InitSharedInstanceWithPakPath(const base::FilePath
& path
) {
182 InitSharedInstance(NULL
);
183 g_shared_instance_
->LoadTestResources(path
, path
);
185 InitDefaultFontList();
189 void ResourceBundle::CleanupSharedInstance() {
190 if (g_shared_instance_
) {
191 delete g_shared_instance_
;
192 g_shared_instance_
= NULL
;
197 bool ResourceBundle::HasSharedInstance() {
198 return g_shared_instance_
!= NULL
;
202 ResourceBundle
& ResourceBundle::GetSharedInstance() {
203 // Must call InitSharedInstance before this function.
204 CHECK(g_shared_instance_
!= NULL
);
205 return *g_shared_instance_
;
208 bool ResourceBundle::LocaleDataPakExists(const std::string
& locale
) {
209 return !GetLocaleFilePath(locale
, true).empty();
212 void ResourceBundle::AddDataPackFromPath(const base::FilePath
& path
,
213 ScaleFactor scale_factor
) {
214 AddDataPackFromPathInternal(path
, scale_factor
, false);
217 void ResourceBundle::AddOptionalDataPackFromPath(const base::FilePath
& path
,
218 ScaleFactor scale_factor
) {
219 AddDataPackFromPathInternal(path
, scale_factor
, true);
222 void ResourceBundle::AddDataPackFromFile(base::File file
,
223 ScaleFactor scale_factor
) {
224 scoped_ptr
<DataPack
> data_pack(
225 new DataPack(scale_factor
));
226 if (data_pack
->LoadFromFile(file
.Pass())) {
227 AddDataPack(data_pack
.release());
229 LOG(ERROR
) << "Failed to load data pack from file."
230 << "\nSome features may not be available.";
234 #if !defined(OS_MACOSX)
235 base::FilePath
ResourceBundle::GetLocaleFilePath(const std::string
& app_locale
,
236 bool test_file_exists
) {
237 if (app_locale
.empty())
238 return base::FilePath();
240 base::FilePath locale_file_path
;
242 PathService::Get(ui::DIR_LOCALES
, &locale_file_path
);
244 if (!locale_file_path
.empty())
245 locale_file_path
= locale_file_path
.AppendASCII(app_locale
+ ".pak");
249 delegate_
->GetPathForLocalePack(locale_file_path
, app_locale
);
252 // Don't try to load empty values or values that are not absolute paths.
253 if (locale_file_path
.empty() || !locale_file_path
.IsAbsolute())
254 return base::FilePath();
256 if (test_file_exists
&& !base::PathExists(locale_file_path
))
257 return base::FilePath();
259 return locale_file_path
;
263 std::string
ResourceBundle::LoadLocaleResources(
264 const std::string
& pref_locale
) {
265 DCHECK(!locale_resources_data_
.get()) << "locale.pak already loaded";
266 std::string app_locale
= l10n_util::GetApplicationLocale(pref_locale
);
267 base::FilePath locale_file_path
= GetOverriddenPakPath();
268 if (locale_file_path
.empty()) {
269 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
270 if (command_line
->HasSwitch(switches::kLocalePak
)) {
272 command_line
->GetSwitchValuePath(switches::kLocalePak
);
274 locale_file_path
= GetLocaleFilePath(app_locale
, true);
278 if (locale_file_path
.empty()) {
279 // It's possible that there is no locale.pak.
280 LOG(WARNING
) << "locale_file_path.empty()";
281 return std::string();
284 scoped_ptr
<DataPack
> data_pack(
285 new DataPack(SCALE_FACTOR_100P
));
286 if (!data_pack
->LoadFromPath(locale_file_path
)) {
287 UMA_HISTOGRAM_ENUMERATION("ResourceBundle.LoadLocaleResourcesError",
288 logging::GetLastSystemErrorCode(), 16000);
289 LOG(ERROR
) << "failed to load locale.pak";
291 return std::string();
294 locale_resources_data_
.reset(data_pack
.release());
298 void ResourceBundle::LoadTestResources(const base::FilePath
& path
,
299 const base::FilePath
& locale_path
) {
300 // Use the given resource pak for both common and localized resources.
301 scoped_ptr
<DataPack
> data_pack(new DataPack(SCALE_FACTOR_100P
));
302 if (!path
.empty() && data_pack
->LoadFromPath(path
))
303 AddDataPack(data_pack
.release());
305 data_pack
.reset(new DataPack(ui::SCALE_FACTOR_NONE
));
306 if (!locale_path
.empty() && data_pack
->LoadFromPath(locale_path
)) {
307 locale_resources_data_
.reset(data_pack
.release());
309 locale_resources_data_
.reset(new DataPack(ui::SCALE_FACTOR_NONE
));
313 void ResourceBundle::UnloadLocaleResources() {
314 locale_resources_data_
.reset();
317 void ResourceBundle::OverrideLocalePakForTest(const base::FilePath
& pak_path
) {
318 overridden_pak_path_
= pak_path
;
321 const base::FilePath
& ResourceBundle::GetOverriddenPakPath() {
322 return overridden_pak_path_
;
325 std::string
ResourceBundle::ReloadLocaleResources(
326 const std::string
& pref_locale
) {
327 base::AutoLock
lock_scope(*locale_resources_data_lock_
);
328 UnloadLocaleResources();
329 return LoadLocaleResources(pref_locale
);
332 gfx::ImageSkia
* ResourceBundle::GetImageSkiaNamed(int resource_id
) {
333 const gfx::ImageSkia
* image
= GetImageNamed(resource_id
).ToImageSkia();
334 return const_cast<gfx::ImageSkia
*>(image
);
337 gfx::Image
& ResourceBundle::GetImageNamed(int resource_id
) {
338 // Check to see if the image is already in the cache.
340 base::AutoLock
lock_scope(*images_and_fonts_lock_
);
341 if (images_
.count(resource_id
))
342 return images_
[resource_id
];
347 image
= delegate_
->GetImageNamed(resource_id
);
349 if (image
.IsEmpty()) {
350 DCHECK(!data_packs_
.empty()) <<
351 "Missing call to SetResourcesDataDLL?";
353 #if defined(OS_CHROMEOS)
354 ui::ScaleFactor scale_factor_to_load
= GetMaxScaleFactor();
356 ui::ScaleFactor scale_factor_to_load
= ui::SCALE_FACTOR_100P
;
359 float scale
= GetImageScale(scale_factor_to_load
);
360 // TODO(oshima): Consider reading the image size from png IHDR chunk and
361 // skip decoding here and remove #ifdef below.
362 // ResourceBundle::GetSharedInstance() is destroyed after the
363 // BrowserMainLoop has finished running. |image_skia| is guaranteed to be
364 // destroyed before the resource bundle is destroyed.
365 gfx::ImageSkia
image_skia(new ResourceBundleImageSource(this, resource_id
),
367 if (image_skia
.isNull()) {
368 LOG(WARNING
) << "Unable to load image with id " << resource_id
;
369 NOTREACHED(); // Want to assert in debug mode.
370 // The load failed to retrieve the image; show a debugging red square.
371 return GetEmptyImage();
373 image_skia
.SetReadOnly();
374 image
= gfx::Image(image_skia
);
377 // The load was successful, so cache the image.
378 base::AutoLock
lock_scope(*images_and_fonts_lock_
);
380 // Another thread raced the load and has already cached the image.
381 if (images_
.count(resource_id
))
382 return images_
[resource_id
];
384 images_
[resource_id
] = image
;
385 return images_
[resource_id
];
388 gfx::Image
& ResourceBundle::GetNativeImageNamed(int resource_id
) {
389 return GetNativeImageNamed(resource_id
, RTL_DISABLED
);
392 base::RefCountedStaticMemory
* ResourceBundle::LoadDataResourceBytes(
393 int resource_id
) const {
394 return LoadDataResourceBytesForScale(resource_id
, ui::SCALE_FACTOR_NONE
);
397 base::RefCountedStaticMemory
* ResourceBundle::LoadDataResourceBytesForScale(
399 ScaleFactor scale_factor
) const {
400 base::RefCountedStaticMemory
* bytes
= NULL
;
402 bytes
= delegate_
->LoadDataResourceBytes(resource_id
, scale_factor
);
405 base::StringPiece data
=
406 GetRawDataResourceForScale(resource_id
, scale_factor
);
408 bytes
= new base::RefCountedStaticMemory(
409 reinterpret_cast<const unsigned char*>(data
.data()), data
.length());
416 base::StringPiece
ResourceBundle::GetRawDataResource(int resource_id
) const {
417 return GetRawDataResourceForScale(resource_id
, ui::SCALE_FACTOR_NONE
);
420 base::StringPiece
ResourceBundle::GetRawDataResourceForScale(
422 ScaleFactor scale_factor
) const {
423 base::StringPiece data
;
425 delegate_
->GetRawDataResource(resource_id
, scale_factor
, &data
))
428 if (scale_factor
!= ui::SCALE_FACTOR_100P
) {
429 for (size_t i
= 0; i
< data_packs_
.size(); i
++) {
430 if (data_packs_
[i
]->GetScaleFactor() == scale_factor
&&
431 data_packs_
[i
]->GetStringPiece(resource_id
, &data
))
435 for (size_t i
= 0; i
< data_packs_
.size(); i
++) {
436 if ((data_packs_
[i
]->GetScaleFactor() == ui::SCALE_FACTOR_100P
||
437 data_packs_
[i
]->GetScaleFactor() == ui::SCALE_FACTOR_NONE
) &&
438 data_packs_
[i
]->GetStringPiece(resource_id
, &data
))
442 return base::StringPiece();
445 base::string16
ResourceBundle::GetLocalizedString(int message_id
) {
446 base::string16 string
;
447 if (delegate_
&& delegate_
->GetLocalizedString(message_id
, &string
))
450 // Ensure that ReloadLocaleResources() doesn't drop the resources while
452 base::AutoLock
lock_scope(*locale_resources_data_lock_
);
454 // If for some reason we were unable to load the resources , return an empty
455 // string (better than crashing).
456 if (!locale_resources_data_
.get()) {
457 LOG(WARNING
) << "locale resources are not loaded";
458 return base::string16();
461 base::StringPiece data
;
462 if (!locale_resources_data_
->GetStringPiece(message_id
, &data
)) {
463 // Fall back on the main data pack (shouldn't be any strings here except in
465 data
= GetRawDataResource(message_id
);
467 NOTREACHED() << "unable to find resource: " << message_id
;
468 return base::string16();
472 // Strings should not be loaded from a data pack that contains binary data.
473 ResourceHandle::TextEncodingType encoding
=
474 locale_resources_data_
->GetTextEncodingType();
475 DCHECK(encoding
== ResourceHandle::UTF16
|| encoding
== ResourceHandle::UTF8
)
476 << "requested localized string from binary pack file";
478 // Data pack encodes strings as either UTF8 or UTF16.
480 if (encoding
== ResourceHandle::UTF16
) {
481 msg
= base::string16(reinterpret_cast<const base::char16
*>(data
.data()),
483 } else if (encoding
== ResourceHandle::UTF8
) {
484 msg
= base::UTF8ToUTF16(data
);
489 const gfx::FontList
& ResourceBundle::GetFontList(FontStyle style
) {
491 base::AutoLock
lock_scope(*images_and_fonts_lock_
);
492 LoadFontsIfNecessary();
496 return *bold_font_list_
;
498 return *small_font_list_
;
500 return *medium_font_list_
;
502 return *small_bold_font_list_
;
504 return *medium_bold_font_list_
;
506 return *large_font_list_
;
508 return *large_bold_font_list_
;
510 return *base_font_list_
;
514 const gfx::Font
& ResourceBundle::GetFont(FontStyle style
) {
515 return GetFontList(style
).GetPrimaryFont();
518 void ResourceBundle::ReloadFonts() {
519 base::AutoLock
lock_scope(*images_and_fonts_lock_
);
520 base_font_list_
.reset();
521 LoadFontsIfNecessary();
524 ScaleFactor
ResourceBundle::GetMaxScaleFactor() const {
525 #if defined(OS_CHROMEOS)
526 return max_scale_factor_
;
528 return GetSupportedScaleFactors().back();
532 ResourceBundle::ResourceBundle(Delegate
* delegate
)
533 : delegate_(delegate
),
534 images_and_fonts_lock_(new base::Lock
),
535 locale_resources_data_lock_(new base::Lock
),
536 max_scale_factor_(SCALE_FACTOR_100P
) {
539 ResourceBundle::~ResourceBundle() {
541 UnloadLocaleResources();
545 void ResourceBundle::InitSharedInstance(Delegate
* delegate
) {
546 DCHECK(g_shared_instance_
== NULL
) << "ResourceBundle initialized twice";
547 g_shared_instance_
= new ResourceBundle(delegate
);
548 static std::vector
<ScaleFactor
> supported_scale_factors
;
550 // On platforms other than iOS, 100P is always a supported scale factor.
551 supported_scale_factors
.push_back(SCALE_FACTOR_100P
);
553 #if defined(OS_ANDROID)
554 const gfx::Display display
=
555 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
556 const float display_density
= display
.device_scale_factor();
557 const ScaleFactor closest
= FindClosestScaleFactorUnsafe(display_density
);
558 if (closest
!= SCALE_FACTOR_100P
)
559 supported_scale_factors
.push_back(closest
);
560 #elif defined(OS_IOS)
561 gfx::Display display
= gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
562 if (display
.device_scale_factor() > 1.0) {
563 DCHECK_EQ(2.0, display
.device_scale_factor());
564 supported_scale_factors
.push_back(SCALE_FACTOR_200P
);
566 supported_scale_factors
.push_back(SCALE_FACTOR_100P
);
568 #elif defined(OS_MACOSX)
569 if (base::mac::IsOSLionOrLater())
570 supported_scale_factors
.push_back(SCALE_FACTOR_200P
);
571 #elif defined(OS_CHROMEOS)
572 // TODO(oshima): Include 200P only if the device support 200P
573 supported_scale_factors
.push_back(SCALE_FACTOR_200P
);
575 ui::SetSupportedScaleFactors(supported_scale_factors
);
577 // Must be called _after_ supported scale factors are set since it
579 ui::win::InitDeviceScaleFactor();
583 void ResourceBundle::FreeImages() {
587 void ResourceBundle::AddDataPackFromPathInternal(const base::FilePath
& path
,
588 ScaleFactor scale_factor
,
590 // Do not pass an empty |path| value to this method. If the absolute path is
591 // unknown pass just the pack file name.
592 DCHECK(!path
.empty());
594 base::FilePath pack_path
= path
;
596 pack_path
= delegate_
->GetPathForResourcePack(pack_path
, scale_factor
);
598 // Don't try to load empty values or values that are not absolute paths.
599 if (pack_path
.empty() || !pack_path
.IsAbsolute())
602 scoped_ptr
<DataPack
> data_pack(
603 new DataPack(scale_factor
));
604 if (data_pack
->LoadFromPath(pack_path
)) {
605 AddDataPack(data_pack
.release());
606 } else if (!optional
) {
607 LOG(ERROR
) << "Failed to load " << pack_path
.value()
608 << "\nSome features may not be available.";
612 void ResourceBundle::AddDataPack(DataPack
* data_pack
) {
613 data_packs_
.push_back(data_pack
);
615 if (GetImageScale(data_pack
->GetScaleFactor()) >
616 GetImageScale(max_scale_factor_
))
617 max_scale_factor_
= data_pack
->GetScaleFactor();
620 void ResourceBundle::LoadFontsIfNecessary() {
621 images_and_fonts_lock_
->AssertAcquired();
622 if (!base_font_list_
.get()) {
624 base_font_list_
= GetFontListFromDelegate(BaseFont
);
625 bold_font_list_
= GetFontListFromDelegate(BoldFont
);
626 small_font_list_
= GetFontListFromDelegate(SmallFont
);
627 small_bold_font_list_
= GetFontListFromDelegate(SmallBoldFont
);
628 medium_font_list_
= GetFontListFromDelegate(MediumFont
);
629 medium_bold_font_list_
= GetFontListFromDelegate(MediumBoldFont
);
630 large_font_list_
= GetFontListFromDelegate(LargeFont
);
631 large_bold_font_list_
= GetFontListFromDelegate(LargeBoldFont
);
634 if (!base_font_list_
.get())
635 base_font_list_
.reset(new gfx::FontList());
637 if (!bold_font_list_
.get()) {
638 bold_font_list_
.reset(new gfx::FontList());
639 *bold_font_list_
= base_font_list_
->DeriveFontList(
640 base_font_list_
->GetFontStyle() | gfx::Font::BOLD
);
643 if (!small_font_list_
.get()) {
644 small_font_list_
.reset(new gfx::FontList());
645 *small_font_list_
= base_font_list_
->DeriveFontListWithSize(
646 base_font_list_
->GetFontSize() + kSmallFontSizeDelta
);
649 if (!small_bold_font_list_
.get()) {
650 small_bold_font_list_
.reset(new gfx::FontList());
651 *small_bold_font_list_
= small_font_list_
->DeriveFontList(
652 small_font_list_
->GetFontStyle() | gfx::Font::BOLD
);
655 if (!medium_font_list_
.get()) {
656 medium_font_list_
.reset(new gfx::FontList());
657 *medium_font_list_
= base_font_list_
->DeriveFontListWithSize(
658 base_font_list_
->GetFontSize() + kMediumFontSizeDelta
);
661 if (!medium_bold_font_list_
.get()) {
662 medium_bold_font_list_
.reset(new gfx::FontList());
663 *medium_bold_font_list_
= medium_font_list_
->DeriveFontList(
664 medium_font_list_
->GetFontStyle() | gfx::Font::BOLD
);
667 if (!large_font_list_
.get()) {
668 large_font_list_
.reset(new gfx::FontList());
669 *large_font_list_
= base_font_list_
->DeriveFontListWithSize(
670 base_font_list_
->GetFontSize() + kLargeFontSizeDelta
);
673 if (!large_bold_font_list_
.get()) {
674 large_bold_font_list_
.reset(new gfx::FontList());
675 *large_bold_font_list_
= large_font_list_
->DeriveFontList(
676 large_font_list_
->GetFontStyle() | gfx::Font::BOLD
);
681 scoped_ptr
<gfx::FontList
> ResourceBundle::GetFontListFromDelegate(
684 scoped_ptr
<gfx::Font
> font
= delegate_
->GetFont(style
);
686 return scoped_ptr
<gfx::FontList
>(new gfx::FontList(*font
));
687 return scoped_ptr
<gfx::FontList
>();
690 bool ResourceBundle::LoadBitmap(const ResourceHandle
& data_handle
,
693 bool* fell_back_to_1x
) const {
694 DCHECK(fell_back_to_1x
);
695 scoped_refptr
<base::RefCountedMemory
> memory(
696 data_handle
.GetStaticMemory(resource_id
));
700 if (DecodePNG(memory
->front(), memory
->size(), bitmap
, fell_back_to_1x
))
704 // iOS does not compile or use the JPEG codec. On other platforms,
705 // 99% of our assets are PNGs, however fallback to JPEG.
706 scoped_ptr
<SkBitmap
> jpeg_bitmap(
707 gfx::JPEGCodec::Decode(memory
->front(), memory
->size()));
708 if (jpeg_bitmap
.get()) {
709 bitmap
->swap(*jpeg_bitmap
.get());
710 *fell_back_to_1x
= false;
715 NOTREACHED() << "Unable to decode theme image resource " << resource_id
;
719 bool ResourceBundle::LoadBitmap(int resource_id
,
720 ScaleFactor
* scale_factor
,
722 bool* fell_back_to_1x
) const {
723 DCHECK(fell_back_to_1x
);
724 for (size_t i
= 0; i
< data_packs_
.size(); ++i
) {
725 // If the resource is in the package with SCALE_FACTOR_NONE, it
726 // can be used in any scale factor, but set 100P in ImageSkia so
727 // that it will be scaled property.
728 if (data_packs_
[i
]->GetScaleFactor() == ui::SCALE_FACTOR_NONE
&&
729 LoadBitmap(*data_packs_
[i
], resource_id
, bitmap
, fell_back_to_1x
)) {
730 *scale_factor
= ui::SCALE_FACTOR_100P
;
731 DCHECK(!*fell_back_to_1x
);
734 if (data_packs_
[i
]->GetScaleFactor() == *scale_factor
&&
735 LoadBitmap(*data_packs_
[i
], resource_id
, bitmap
, fell_back_to_1x
)) {
742 gfx::Image
& ResourceBundle::GetEmptyImage() {
743 base::AutoLock
lock(*images_and_fonts_lock_
);
745 if (empty_image_
.IsEmpty()) {
746 // The placeholder bitmap is bright red so people notice the problem.
748 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, 32, 32);
749 bitmap
.allocPixels();
750 bitmap
.eraseARGB(255, 255, 0, 0);
751 empty_image_
= gfx::Image::CreateFrom1xBitmap(bitmap
);
757 bool ResourceBundle::ShouldHighlightMissingScaledResources() {
758 return CommandLine::ForCurrentProcess()->HasSwitch(
759 switches::kHighlightMissingScaledResources
);
763 bool ResourceBundle::PNGContainsFallbackMarker(const unsigned char* buf
,
765 if (size
< arraysize(kPngMagic
) ||
766 memcmp(buf
, kPngMagic
, arraysize(kPngMagic
)) != 0) {
767 // Data invalid or a JPEG.
770 size_t pos
= arraysize(kPngMagic
);
772 // Scan for custom chunks until we find one, find the IDAT chunk, or run out
775 if (size
- pos
< kPngChunkMetadataSize
)
778 net::ReadBigEndian(reinterpret_cast<const char*>(buf
+ pos
), &length
);
779 if (size
- pos
- kPngChunkMetadataSize
< length
)
781 if (length
== 0 && memcmp(buf
+ pos
+ sizeof(uint32
), kPngScaleChunkType
,
782 arraysize(kPngScaleChunkType
)) == 0) {
785 if (memcmp(buf
+ pos
+ sizeof(uint32
), kPngDataChunkType
,
786 arraysize(kPngDataChunkType
)) == 0) {
787 // Stop looking for custom chunks, any custom chunks should be before an
791 pos
+= length
+ kPngChunkMetadataSize
;
797 bool ResourceBundle::DecodePNG(const unsigned char* buf
,
800 bool* fell_back_to_1x
) {
801 *fell_back_to_1x
= PNGContainsFallbackMarker(buf
, size
);
802 return gfx::PNGCodec::Decode(buf
, size
, bitmap
);