#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "ui/base/resource/resource_bundle.h"
#include <stdint.h>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/debug/alias.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted_memory.h"
#include "base/notreached.h"
#include "base/numerics/byte_conversions.h"
#include "base/numerics/safe_conversions.h"
#include "base/path_service.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock.h"
#include "base/trace_event/base_tracing.h"
#include "build/build_config.h"
#include "net/filter/gzip_header.h"
#include "skia/ext/image_operations.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
#include "third_party/brotli/include/brotli/decode.h"
#include "third_party/skia/include/codec/SkPngDecoder.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/zlib/google/compression_utils.h"
#include "ui/base/buildflags.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/data_pack.h"
#include "ui/base/resource/resource_scale_factor.h"
#include "ui/base/ui_base_paths.h"
#include "ui/base/ui_base_switches.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/codec/jpeg_codec.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/image/image_skia_source.h"
#include "ui/strings/grit/app_locale_settings.h"
#include "url/gurl.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#include "ui/base/resource/resource_bundle_android.h"
#endif
#if BUILDFLAG(IS_CHROMEOS)
#include "ui/gfx/platform_font_skia.h"
#endif
#if BUILDFLAG(IS_WIN)
#include "ui/display/win/dpi.h"
#undef LoadBitmap
#endif
namespace ui {
namespace {
const uint8_t kPngMagic[8] = …;
const size_t kPngChunkMetadataSize = …;
const unsigned char kPngScaleChunkType[4] = …;
const unsigned char kPngDataChunkType[4] = …;
#if !BUILDFLAG(IS_APPLE)
const char kPakFileExtension[] = …;
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
ResourceBundle::LottieImageParseFunction g_parse_lottie_as_still_image_ =
nullptr;
ResourceBundle::LottieThemedImageParseFunction
g_parse_lottie_as_themed_still_image_ = nullptr;
#endif
ResourceBundle* g_shared_instance_ = …;
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
base::FilePath GetResourcesPakFilePath(const std::string& pak_name) { … }
#endif
SkBitmap CreateEmptyBitmap() { … }
bool HasGzipHeader(std::string_view data) { … }
bool HasBrotliHeader(std::string_view data) { … }
size_t GetBrotliDecompressSize(std::string_view input) { … }
OutputBufferType;
base::span<uint8_t> GetBufferForWriting(OutputBufferType out_buf, size_t len) { … }
bool BrotliDecompress(std::string_view input, OutputBufferType output) { … }
void DecompressIfNeeded(std::string_view data, OutputBufferType output) { … }
}
class ResourceBundle::BitmapImageSource : public gfx::ImageSkiaSource { … };
ResourceBundle::FontDetails::FontDetails(std::string typeface,
int size_delta,
gfx::Font::Weight weight)
: … { … }
bool ResourceBundle::FontDetails::operator==(const FontDetails& rhs) const { … }
bool ResourceBundle::FontDetails::operator<(const FontDetails& rhs) const { … }
std::string ResourceBundle::InitSharedInstanceWithLocale(
const std::string& pref_locale,
Delegate* delegate,
LoadResources load_resources) { … }
void ResourceBundle::InitSharedInstanceWithBuffer(
base::span<const uint8_t> buffer,
ResourceScaleFactor scale_factor) { … }
void ResourceBundle::InitSharedInstanceWithPakFileRegion(
base::File pak_file,
const base::MemoryMappedFile::Region& region) { … }
void ResourceBundle::InitSharedInstanceWithPakPath(const base::FilePath& path) { … }
void ResourceBundle::CleanupSharedInstance() { … }
ResourceBundle* ResourceBundle::SwapSharedInstanceForTesting(
ResourceBundle* instance) { … }
bool ResourceBundle::HasSharedInstance() { … }
ResourceBundle& ResourceBundle::GetSharedInstance() { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
void ResourceBundle::SetLottieParsingFunctions(
LottieImageParseFunction parse_lottie_as_still_image,
LottieThemedImageParseFunction parse_lottie_as_themed_still_image) {
g_parse_lottie_as_still_image_ = parse_lottie_as_still_image;
g_parse_lottie_as_themed_still_image_ = parse_lottie_as_themed_still_image;
}
#endif
void ResourceBundle::LoadSecondaryLocaleDataWithPakFileRegion(
base::File pak_file,
const base::MemoryMappedFile::Region& region) { … }
#if !BUILDFLAG(IS_ANDROID)
bool ResourceBundle::LocaleDataPakExists(const std::string& locale) { … }
#endif
void ResourceBundle::AddDataPackFromPath(const base::FilePath& path,
ResourceScaleFactor scale_factor) { … }
void ResourceBundle::AddOptionalDataPackFromPath(
const base::FilePath& path,
ResourceScaleFactor scale_factor) { … }
void ResourceBundle::AddDataPackFromBuffer(base::span<const uint8_t> buffer,
ResourceScaleFactor scale_factor) { … }
void ResourceBundle::AddDataPackFromFileRegion(
base::File file,
const base::MemoryMappedFile::Region& region,
ResourceScaleFactor scale_factor) { … }
#if !BUILDFLAG(IS_APPLE)
base::FilePath ResourceBundle::GetLocaleFilePath(
const std::string& app_locale) { … }
#endif
#if !BUILDFLAG(IS_ANDROID)
std::string ResourceBundle::LoadLocaleResources(const std::string& pref_locale,
bool crash_on_failure) { … }
#endif
void ResourceBundle::LoadTestResources(const base::FilePath& path,
const base::FilePath& locale_path) { … }
void ResourceBundle::UnloadLocaleResources() { … }
void ResourceBundle::OverrideLocalePakForTest(const base::FilePath& pak_path) { … }
void ResourceBundle::OverrideLocaleStringResource(
int resource_id,
const std::u16string& string) { … }
const base::FilePath& ResourceBundle::GetOverriddenPakPath() const { … }
std::u16string ResourceBundle::MaybeMangleLocalizedString(
const std::u16string& str) const { … }
std::string ResourceBundle::ReloadLocaleResources(
const std::string& pref_locale) { … }
gfx::ImageSkia* ResourceBundle::GetImageSkiaNamed(int resource_id) { … }
gfx::Image& ResourceBundle::GetImageNamed(int resource_id) { … }
std::optional<ResourceBundle::LottieData> ResourceBundle::GetLottieData(
int resource_id) const { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
const ui::ImageModel& ResourceBundle::GetThemedLottieImageNamed(
int resource_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto found = image_models_.find(resource_id);
if (found != image_models_.end())
return found->second;
std::optional<LottieData> data = GetLottieData(resource_id);
CHECK(data) << "Unable to load themed Lottie image with id " << resource_id;
auto inserted = image_models_.emplace(
resource_id, (*g_parse_lottie_as_themed_still_image_)(std::move(*data)));
DCHECK(inserted.second);
return inserted.first->second;
}
#endif
constexpr uint8_t ResourceBundle::kBrotliConst[];
base::RefCountedMemory* ResourceBundle::LoadDataResourceBytes(
int resource_id) const { … }
base::RefCountedMemory* ResourceBundle::LoadDataResourceBytesForScale(
int resource_id,
ResourceScaleFactor scale_factor) const { … }
std::string_view ResourceBundle::GetRawDataResource(int resource_id) const { … }
std::string_view ResourceBundle::GetRawDataResourceForScale(
int resource_id,
ResourceScaleFactor scale_factor,
ResourceScaleFactor* loaded_scale_factor) const { … }
std::string ResourceBundle::LoadDataResourceString(int resource_id) const { … }
std::string ResourceBundle::LoadDataResourceStringForScale(
int resource_id,
ResourceScaleFactor scaling_factor) const { … }
std::string ResourceBundle::LoadLocalizedResourceString(int resource_id) const { … }
bool ResourceBundle::IsGzipped(int resource_id) const { … }
bool ResourceBundle::IsBrotli(int resource_id) const { … }
std::u16string ResourceBundle::GetLocalizedString(int resource_id) { … }
base::RefCountedMemory* ResourceBundle::LoadLocalizedResourceBytes(
int resource_id) const { … }
const gfx::FontList& ResourceBundle::GetFontListWithDelta(int size_delta) { … }
const gfx::FontList& ResourceBundle::GetFontListForDetails(
const FontDetails& details) { … }
const gfx::FontList& ResourceBundle::GetFontList(FontStyle legacy_style) { … }
const gfx::Font& ResourceBundle::GetFont(FontStyle style) { … }
void ResourceBundle::ReloadFonts() { … }
ResourceScaleFactor ResourceBundle::GetMaxResourceScaleFactor() const { … }
void ResourceBundle::CheckCanOverrideStringResources() { … }
ResourceBundle::ResourceBundle(Delegate* delegate)
: … { … }
ResourceBundle::~ResourceBundle() { … }
void ResourceBundle::InitSharedInstance(Delegate* delegate) { … }
void ResourceBundle::FreeImages() { … }
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
void ResourceBundle::LoadChromeResources() { … }
#endif
void ResourceBundle::AddDataPackFromPathInternal(
const base::FilePath& path,
ResourceScaleFactor scale_factor,
bool optional) { … }
void ResourceBundle::AddResourceHandle(
std::unique_ptr<ResourceHandle> resource_handle) { … }
void ResourceBundle::InitDefaultFontList() { … }
gfx::ImageSkia ResourceBundle::CreateImageSkia(int resource_id) { … }
bool ResourceBundle::LoadBitmap(const ResourceHandle& data_handle,
int resource_id,
SkBitmap* bitmap,
bool* fell_back_to_1x) const { … }
bool ResourceBundle::LoadBitmap(int resource_id,
ResourceScaleFactor* scale_factor,
SkBitmap* bitmap,
bool* fell_back_to_1x) const { … }
gfx::Image& ResourceBundle::GetEmptyImage() { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
const ui::ImageModel& ResourceBundle::GetEmptyImageModel() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (empty_image_model_.IsEmpty())
empty_image_model_ = ui::ImageModel::FromImage(GetEmptyImage());
return empty_image_model_;
}
#endif
std::u16string ResourceBundle::GetLocalizedStringImpl(int resource_id) const { … }
bool ResourceBundle::PNGContainsFallbackMarker(base::span<const uint8_t> buf) { … }
bool ResourceBundle::DecodePNG(const unsigned char* buf,
size_t size,
SkBitmap* bitmap,
bool* fell_back_to_1x) { … }
}