| // Copyright 2014 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 "base/test/fontconfig_util_linux.h" | 
 |  | 
 | #include <fontconfig/fontconfig.h> | 
 |  | 
 | #include "base/base_paths.h" | 
 | #include "base/environment.h" | 
 | #include "base/files/file_path.h" | 
 | #include "base/files/file_util.h" | 
 | #include "base/logging.h" | 
 | #include "base/macros.h" | 
 | #include "base/path_service.h" | 
 | #include "base/strings/string_util.h" | 
 | #include "starboard/types.h" | 
 |  | 
 | namespace base { | 
 |  | 
 | namespace { | 
 |  | 
 | const char kFontsConfTemplate[] = R"(<?xml version="1.0"?> | 
 | <!DOCTYPE fontconfig SYSTEM "fonts.dtd"> | 
 | <fontconfig> | 
 |  | 
 |   <!-- Cache location. --> | 
 |   <cachedir>$1</cachedir> | 
 |  | 
 |   <!-- GCS-synced fonts. --> | 
 |   <dir>$2</dir> | 
 |  | 
 |   <!-- Default properties. --> | 
 |   <match target="font"> | 
 |     <edit name="embeddedbitmap" mode="append_last"> | 
 |       <bool>false</bool> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <!-- TODO(thomasanderson): Figure out why this is necessary. --> | 
 |   <match target="pattern"> | 
 |     <test name="family" compare="eq"> | 
 |       <string>Tinos</string> | 
 |     </test> | 
 |     <test name="prgname" compare="eq"> | 
 |       <string>chromevox_tests</string> | 
 |     </test> | 
 |     <edit name="hintstyle" mode="assign"> | 
 |       <const>hintslight</const> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>Times</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Tinos</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>sans</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>DejaVu Sans</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>sans serif</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Arimo</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <!-- Some layout tests specify Helvetica as a family and we need to make sure | 
 |        that we don't fallback to Tinos for them --> | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>Helvetica</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Arimo</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>sans-serif</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Arimo</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>serif</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Tinos</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>mono</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Cousine</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>monospace</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Cousine</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>Courier</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Cousine</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>cursive</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Comic Sans MS</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>fantasy</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Impact</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>Monaco</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Tinos</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>Arial</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Arimo</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>Courier New</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Cousine</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>Georgia</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Gelasio</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>Times New Roman</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Tinos</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test qual="any" name="family"> | 
 |       <string>Verdana</string> | 
 |     </test> | 
 |     <!-- NOT metrically compatible! --> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Arimo</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <!-- TODO(thomasanderson): Move these configs to be test-specific. --> | 
 |   <match target="pattern"> | 
 |     <test name="family" compare="eq"> | 
 |       <string>NonAntiAliasedSans</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Arimo</string> | 
 |     </edit> | 
 |     <edit name="antialias" mode="assign"> | 
 |       <bool>false</bool> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test name="family" compare="eq"> | 
 |       <string>SlightHintedGeorgia</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Gelasio</string> | 
 |     </edit> | 
 |     <edit name="hintstyle" mode="assign"> | 
 |       <const>hintslight</const> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test name="family" compare="eq"> | 
 |       <string>NonHintedSans</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Arimo</string> | 
 |     </edit> | 
 |     <!-- These deliberately contradict each other. The 'hinting' preference | 
 |          should take priority --> | 
 |     <edit name="hintstyle" mode="assign"> | 
 |       <const>hintfull</const> | 
 |     </edit> | 
 |    <edit name="hinting" mode="assign"> | 
 |       <bool>false</bool> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test name="family" compare="eq"> | 
 |       <string>AutohintedSerif</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Arimo</string> | 
 |     </edit> | 
 |     <edit name="autohint" mode="assign"> | 
 |       <bool>true</bool> | 
 |     </edit> | 
 |     <edit name="hintstyle" mode="assign"> | 
 |       <const>hintmedium</const> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test name="family" compare="eq"> | 
 |       <string>HintedSerif</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Arimo</string> | 
 |     </edit> | 
 |     <edit name="autohint" mode="assign"> | 
 |       <bool>false</bool> | 
 |     </edit> | 
 |     <edit name="hintstyle" mode="assign"> | 
 |       <const>hintmedium</const> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test name="family" compare="eq"> | 
 |       <string>FullAndAutoHintedSerif</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Arimo</string> | 
 |     </edit> | 
 |     <edit name="autohint" mode="assign"> | 
 |       <bool>true</bool> | 
 |     </edit> | 
 |     <edit name="hintstyle" mode="assign"> | 
 |       <const>hintfull</const> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test name="family" compare="eq"> | 
 |       <string>SubpixelEnabledArial</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Arimo</string> | 
 |     </edit> | 
 |     <edit name="rgba" mode="assign"> | 
 |       <const>rgb</const> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test name="family" compare="eq"> | 
 |       <string>SubpixelDisabledArial</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Arimo</string> | 
 |     </edit> | 
 |     <edit name="rgba" mode="assign"> | 
 |       <const>none</const> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <!-- FontConfig doesn't currently provide a well-defined way to turn on | 
 |          subpixel positioning.  This is just an arbitrary pattern to use after | 
 |          turning subpixel positioning on globally to ensure that we don't have | 
 |          issues with our style getting cached for other tests. --> | 
 |     <test name="family" compare="eq"> | 
 |       <string>SubpixelPositioning</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Tinos</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <!-- See comments above --> | 
 |     <test name="family" compare="eq"> | 
 |       <string>SubpixelPositioningAhem</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>ahem</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <match target="pattern"> | 
 |     <test name="family" compare="eq"> | 
 |       <string>SlightHintedTimesNewRoman</string> | 
 |     </test> | 
 |     <edit name="family" mode="assign"> | 
 |       <string>Tinos</string> | 
 |     </edit> | 
 |     <edit name="hintstyle" mode="assign"> | 
 |       <const>hintslight</const> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 |   <!-- When we encounter a character that the current font doesn't | 
 |        support, gfx::GetFallbackFontForChar() returns the first font | 
 |        that does have a glyph for the character. The list of fonts is | 
 |        sorted by a pattern that includes the current locale, but doesn't | 
 |        include a font family (which means that the fallback font depends | 
 |        on the locale but not on the current font). | 
 |  | 
 |        DejaVu Sans is commonly the only font that supports some | 
 |        characters, such as "⇧", and even when other candidates are | 
 |        available, DejaVu Sans is commonly first among them, because of | 
 |        the way Fontconfig is ordinarily configured. For example, the | 
 |        configuration in the Fonconfig source lists DejaVu Sans under the | 
 |        sans-serif generic family, and appends sans-serif to patterns | 
 |        that don't already include a generic family (such as the pattern | 
 |        in gfx::GetFallbackFontForChar()). | 
 |  | 
 |        To get the same fallback font in the layout tests, we could | 
 |        duplicate this configuration here, or more directly, simply | 
 |        append DejaVu Sans to all patterns. --> | 
 |   <match target="pattern"> | 
 |     <edit name="family" mode="append_last"> | 
 |       <string>DejaVu Sans</string> | 
 |     </edit> | 
 |   </match> | 
 |  | 
 | </fontconfig> | 
 | )"; | 
 |  | 
 | }  // namespace | 
 |  | 
 | void SetUpFontconfig() { | 
 |   // TODO(thomasanderson): Use FONTCONFIG_SYSROOT to avoid having to write | 
 |   // a new fonts.conf with updated paths. | 
 |   std::unique_ptr<Environment> env = Environment::Create(); | 
 |   if (!env->HasVar("FONTCONFIG_FILE")) { | 
 |     // fonts.conf must be generated on-the-fly since it contains absolute paths | 
 |     // which may be different if | 
 |     //   1. The user moves/renames their build directory (or any parent dirs). | 
 |     //   2. The build directory is mapped on a swarming bot at a location | 
 |     //      different from the one the buildbot used. | 
 |     FilePath dir_module; | 
 |     PathService::Get(DIR_MODULE, &dir_module); | 
 |     FilePath font_cache = dir_module.Append("fontconfig_caches"); | 
 |     FilePath test_fonts = dir_module.Append("test_fonts"); | 
 |     std::string fonts_conf = ReplaceStringPlaceholders( | 
 |         kFontsConfTemplate, {font_cache.value(), test_fonts.value()}, nullptr); | 
 |  | 
 |     // Write the data to a different file and then atomically rename it to | 
 |     // fonts.conf.  This avoids the file being in a bad state when different | 
 |     // parallel tests call this function at the same time. | 
 |     FilePath fonts_conf_file_temp; | 
 |     if(!CreateTemporaryFileInDir(dir_module, &fonts_conf_file_temp)) | 
 |       CHECK(CreateTemporaryFile(&fonts_conf_file_temp)); | 
 |     CHECK( | 
 |         WriteFile(fonts_conf_file_temp, fonts_conf.c_str(), fonts_conf.size())); | 
 |     FilePath fonts_conf_file = dir_module.Append("fonts.conf"); | 
 |     if (ReplaceFile(fonts_conf_file_temp, fonts_conf_file, nullptr)) | 
 |       env->SetVar("FONTCONFIG_FILE", fonts_conf_file.value()); | 
 |     else | 
 |       env->SetVar("FONTCONFIG_FILE", fonts_conf_file_temp.value()); | 
 |   } | 
 |  | 
 |   CHECK(FcInit()); | 
 | } | 
 |  | 
 | void TearDownFontconfig() { | 
 |   FcFini(); | 
 | } | 
 |  | 
 | }  // namespace base |