// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/gfx/linux/fontconfig_util.h" #include #include "base/no_destructor.h" #include "ui/gfx/font_render_params.h" namespace gfx { namespace { // A singleton class to wrap a global font-config configuration. The // configuration reference counter is incremented to avoid the deletion of the // structure while being used. This class is single-threaded and should only be // used on the UI-Thread. class GFX_EXPORT GlobalFontConfig { public: GlobalFontConfig() { // Without this call, the FontConfig library gets implicitly initialized // on the first call to FontConfig. Since it's not safe to initialize it // concurrently from multiple threads, we explicitly initialize it here // to prevent races when there are multiple renderer's querying the library: // http://crbug.com/404311 // Note that future calls to FcInit() are safe no-ops per the FontConfig // interface. FcInit(); // Increment the reference counter to avoid the config to be deleted while // being used (see http://crbug.com/1004254). fc_config_ = FcConfigGetCurrent(); FcConfigReference(fc_config_); // Set rescan interval to 0 to disable re-scan. Re-scanning in the // background is a source of thread safety issues. // See in http://crbug.com/1004254. FcBool result = FcConfigSetRescanInterval(fc_config_, 0); DCHECK_EQ(result, FcTrue); } ~GlobalFontConfig() { FcConfigDestroy(fc_config_); } // Retrieve the native font-config FcConfig pointer. FcConfig* Get() const { DCHECK_EQ(fc_config_, FcConfigGetCurrent()); return fc_config_; } // Override the font-config configuration. void OverrideForTesting(FcConfig* config) { FcConfigSetCurrent(config); fc_config_ = config; } // Retrieve the global font-config configuration. static GlobalFontConfig* GetInstance() { static base::NoDestructor fontconfig; return fontconfig.get(); } private: FcConfig* fc_config_ = nullptr; DISALLOW_COPY_AND_ASSIGN(GlobalFontConfig); }; // Converts Fontconfig FC_HINT_STYLE to FontRenderParams::Hinting. FontRenderParams::Hinting ConvertFontconfigHintStyle(int hint_style) { switch (hint_style) { case FC_HINT_SLIGHT: return FontRenderParams::HINTING_SLIGHT; case FC_HINT_MEDIUM: return FontRenderParams::HINTING_MEDIUM; case FC_HINT_FULL: return FontRenderParams::HINTING_FULL; default: return FontRenderParams::HINTING_NONE; } } // Converts Fontconfig FC_RGBA to FontRenderParams::SubpixelRendering. FontRenderParams::SubpixelRendering ConvertFontconfigRgba(int rgba) { switch (rgba) { case FC_RGBA_RGB: return FontRenderParams::SUBPIXEL_RENDERING_RGB; case FC_RGBA_BGR: return FontRenderParams::SUBPIXEL_RENDERING_BGR; case FC_RGBA_VRGB: return FontRenderParams::SUBPIXEL_RENDERING_VRGB; case FC_RGBA_VBGR: return FontRenderParams::SUBPIXEL_RENDERING_VBGR; default: return FontRenderParams::SUBPIXEL_RENDERING_NONE; } } // Extracts a string property from a font-config pattern (e.g. FcPattern). std::string GetFontConfigPropertyAsString(FcPattern* pattern, const char* property) { FcChar8* text = nullptr; if (FcPatternGetString(pattern, property, 0, &text) != FcResultMatch || text == nullptr) { return std::string(); } return std::string(reinterpret_cast(text)); } // Extracts an integer property from a font-config pattern (e.g. FcPattern). int GetFontConfigPropertyAsInt(FcPattern* pattern, const char* property, int default_value) { int value = -1; if (FcPatternGetInteger(pattern, property, 0, &value) != FcResultMatch) return default_value; return value; } // Extracts an boolean property from a font-config pattern (e.g. FcPattern). bool GetFontConfigPropertyAsBool(FcPattern* pattern, const char* property) { FcBool value = FcFalse; if (FcPatternGetBool(pattern, property, 0, &value) != FcResultMatch) return false; return value != FcFalse; } } // namespace FcConfig* GetGlobalFontConfig() { return GlobalFontConfig::GetInstance()->Get(); } void OverrideGlobalFontConfigForTesting(FcConfig* config) { return GlobalFontConfig::GetInstance()->OverrideForTesting(config); } std::string GetFontName(FcPattern* pattern) { return GetFontConfigPropertyAsString(pattern, FC_FAMILY); } std::string GetFilename(FcPattern* pattern) { return GetFontConfigPropertyAsString(pattern, FC_FILE); } base::FilePath GetFontPath(FcPattern* pattern) { std::string filename = GetFilename(pattern); // Obtains the system root directory in 'config' if available. All files // (including file properties in patterns) obtained from this 'config' are // relative to this system root directory. const char* sysroot = reinterpret_cast(FcConfigGetSysRoot(nullptr)); if (!sysroot) return base::FilePath(filename); // Paths may be specified with a heading slash (e.g. // /test_fonts/DejaVuSans.ttf). if (!filename.empty() && base::FilePath::IsSeparator(filename[0])) filename = filename.substr(1); if (filename.empty()) return base::FilePath(); return base::FilePath(sysroot).Append(filename); } int GetFontTtcIndex(FcPattern* pattern) { return GetFontConfigPropertyAsInt(pattern, FC_INDEX, 0); } bool IsFontBold(FcPattern* pattern) { int weight = GetFontConfigPropertyAsInt(pattern, FC_WEIGHT, FC_WEIGHT_NORMAL); return weight >= FC_WEIGHT_BOLD; } bool IsFontItalic(FcPattern* pattern) { int slant = GetFontConfigPropertyAsInt(pattern, FC_SLANT, FC_SLANT_ROMAN); return slant != FC_SLANT_ROMAN; } bool IsFontScalable(FcPattern* pattern) { return GetFontConfigPropertyAsBool(pattern, FC_SCALABLE); } std::string GetFontFormat(FcPattern* pattern) { return GetFontConfigPropertyAsString(pattern, FC_FONTFORMAT); } void GetFontRenderParamsFromFcPattern(FcPattern* pattern, FontRenderParams* param_out) { FcBool fc_antialias = 0; if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &fc_antialias) == FcResultMatch) { param_out->antialiasing = fc_antialias; } FcBool fc_autohint = 0; if (FcPatternGetBool(pattern, FC_AUTOHINT, 0, &fc_autohint) == FcResultMatch) { param_out->autohinter = fc_autohint; } FcBool fc_bitmap = 0; if (FcPatternGetBool(pattern, FC_EMBEDDED_BITMAP, 0, &fc_bitmap) == FcResultMatch) { param_out->use_bitmaps = fc_bitmap; } FcBool fc_hinting = 0; if (FcPatternGetBool(pattern, FC_HINTING, 0, &fc_hinting) == FcResultMatch) { int fc_hint_style = FC_HINT_NONE; if (fc_hinting) { FcPatternGetInteger(pattern, FC_HINT_STYLE, 0, &fc_hint_style); } param_out->hinting = ConvertFontconfigHintStyle(fc_hint_style); } int fc_rgba = FC_RGBA_NONE; if (FcPatternGetInteger(pattern, FC_RGBA, 0, &fc_rgba) == FcResultMatch) param_out->subpixel_rendering = ConvertFontconfigRgba(fc_rgba); } } // namespace gfx