SkFontConfigInterface_direct.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. /*
  2. * Copyright 2009-2015 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. /* migrated from chrome/src/skia/ext/SkFontHost_fontconfig_direct.cpp */
  8. #include "include/core/SkFontStyle.h"
  9. #include "include/core/SkStream.h"
  10. #include "include/core/SkString.h"
  11. #include "include/core/SkTypeface.h"
  12. #include "include/private/SkFixed.h"
  13. #include "include/private/SkMutex.h"
  14. #include "include/private/SkTArray.h"
  15. #include "include/private/SkTDArray.h"
  16. #include "include/private/SkTemplates.h"
  17. #include "src/core/SkAutoMalloc.h"
  18. #include "src/core/SkBuffer.h"
  19. #include "src/ports/SkFontConfigInterface_direct.h"
  20. #include <fontconfig/fontconfig.h>
  21. #include <unistd.h>
  22. #ifdef SK_DEBUG
  23. # include "src/core/SkTLS.h"
  24. #endif
  25. namespace {
  26. // Fontconfig is not threadsafe before 2.10.91. Before that, we lock with a global mutex.
  27. // See https://bug.skia.org/1497 for background.
  28. static SkMutex& f_c_mutex() {
  29. static SkMutex& mutex = *(new SkMutex);
  30. return mutex;
  31. }
  32. #ifdef SK_DEBUG
  33. void* CreateThreadFcLocked() { return new bool(false); }
  34. void DeleteThreadFcLocked(void* v) { delete static_cast<bool*>(v); }
  35. # define THREAD_FC_LOCKED \
  36. static_cast<bool*>(SkTLS::Get(CreateThreadFcLocked, DeleteThreadFcLocked))
  37. #endif
  38. struct FCLocker {
  39. // Assume FcGetVersion() has always been thread safe.
  40. FCLocker() {
  41. if (FcGetVersion() < 21091) {
  42. f_c_mutex().acquire();
  43. } else {
  44. SkDEBUGCODE(bool* threadLocked = THREAD_FC_LOCKED);
  45. SkASSERT(false == *threadLocked);
  46. SkDEBUGCODE(*threadLocked = true);
  47. }
  48. }
  49. ~FCLocker() {
  50. AssertHeld();
  51. if (FcGetVersion() < 21091) {
  52. f_c_mutex().release();
  53. } else {
  54. SkDEBUGCODE(*THREAD_FC_LOCKED = false);
  55. }
  56. }
  57. static void AssertHeld() { SkDEBUGCODE(
  58. if (FcGetVersion() < 21091) {
  59. f_c_mutex().assertHeld();
  60. } else {
  61. SkASSERT(true == *THREAD_FC_LOCKED);
  62. }
  63. ) }
  64. };
  65. } // namespace
  66. size_t SkFontConfigInterface::FontIdentity::writeToMemory(void* addr) const {
  67. size_t size = sizeof(fID) + sizeof(fTTCIndex);
  68. size += sizeof(int32_t) + sizeof(int32_t) + sizeof(uint8_t); // weight, width, italic
  69. size += sizeof(int32_t) + fString.size(); // store length+data
  70. if (addr) {
  71. SkWBuffer buffer(addr, size);
  72. buffer.write32(fID);
  73. buffer.write32(fTTCIndex);
  74. buffer.write32(fString.size());
  75. buffer.write32(fStyle.weight());
  76. buffer.write32(fStyle.width());
  77. buffer.write8(fStyle.slant());
  78. buffer.write(fString.c_str(), fString.size());
  79. buffer.padToAlign4();
  80. SkASSERT(buffer.pos() == size);
  81. }
  82. return size;
  83. }
  84. size_t SkFontConfigInterface::FontIdentity::readFromMemory(const void* addr,
  85. size_t size) {
  86. SkRBuffer buffer(addr, size);
  87. (void)buffer.readU32(&fID);
  88. (void)buffer.readS32(&fTTCIndex);
  89. uint32_t strLen, weight, width;
  90. (void)buffer.readU32(&strLen);
  91. (void)buffer.readU32(&weight);
  92. (void)buffer.readU32(&width);
  93. uint8_t u8;
  94. (void)buffer.readU8(&u8);
  95. SkFontStyle::Slant slant = (SkFontStyle::Slant)u8;
  96. fStyle = SkFontStyle(weight, width, slant);
  97. fString.resize(strLen);
  98. (void)buffer.read(fString.writable_str(), strLen);
  99. buffer.skipToAlign4();
  100. return buffer.pos(); // the actual number of bytes read
  101. }
  102. #ifdef SK_DEBUG
  103. static void make_iden(SkFontConfigInterface::FontIdentity* iden) {
  104. iden->fID = 10;
  105. iden->fTTCIndex = 2;
  106. iden->fString.set("Hello world");
  107. iden->fStyle = SkFontStyle(300, 6, SkFontStyle::kItalic_Slant);
  108. }
  109. static void test_writeToMemory(const SkFontConfigInterface::FontIdentity& iden0,
  110. int initValue) {
  111. SkFontConfigInterface::FontIdentity iden1;
  112. size_t size0 = iden0.writeToMemory(nullptr);
  113. SkAutoMalloc storage(size0);
  114. memset(storage.get(), initValue, size0);
  115. size_t size1 = iden0.writeToMemory(storage.get());
  116. SkASSERT(size0 == size1);
  117. SkASSERT(iden0 != iden1);
  118. size_t size2 = iden1.readFromMemory(storage.get(), size1);
  119. SkASSERT(size2 == size1);
  120. SkASSERT(iden0 == iden1);
  121. }
  122. static void fontconfiginterface_unittest() {
  123. SkFontConfigInterface::FontIdentity iden0, iden1;
  124. SkASSERT(iden0 == iden1);
  125. make_iden(&iden0);
  126. SkASSERT(iden0 != iden1);
  127. make_iden(&iden1);
  128. SkASSERT(iden0 == iden1);
  129. test_writeToMemory(iden0, 0);
  130. test_writeToMemory(iden0, 0);
  131. }
  132. #endif
  133. ///////////////////////////////////////////////////////////////////////////////
  134. // Returns the string from the pattern, or nullptr
  135. static const char* get_string(FcPattern* pattern, const char field[], int index = 0) {
  136. const char* name;
  137. if (FcPatternGetString(pattern, field, index, (FcChar8**)&name) != FcResultMatch) {
  138. name = nullptr;
  139. }
  140. return name;
  141. }
  142. ///////////////////////////////////////////////////////////////////////////////
  143. namespace {
  144. // Equivalence classes, used to match the Liberation and other fonts
  145. // with their metric-compatible replacements. See the discussion in
  146. // GetFontEquivClass().
  147. enum FontEquivClass
  148. {
  149. OTHER,
  150. SANS,
  151. SERIF,
  152. MONO,
  153. SYMBOL,
  154. PGOTHIC,
  155. GOTHIC,
  156. PMINCHO,
  157. MINCHO,
  158. SIMSUN,
  159. NSIMSUN,
  160. SIMHEI,
  161. PMINGLIU,
  162. MINGLIU,
  163. PMINGLIUHK,
  164. MINGLIUHK,
  165. CAMBRIA,
  166. CALIBRI,
  167. };
  168. // Match the font name against a whilelist of fonts, returning the equivalence
  169. // class.
  170. FontEquivClass GetFontEquivClass(const char* fontname)
  171. {
  172. // It would be nice for fontconfig to tell us whether a given suggested
  173. // replacement is a "strong" match (that is, an equivalent font) or
  174. // a "weak" match (that is, fontconfig's next-best attempt at finding a
  175. // substitute). However, I played around with the fontconfig API for
  176. // a good few hours and could not make it reveal this information.
  177. //
  178. // So instead, we hardcode. Initially this function emulated
  179. // /etc/fonts/conf.d/30-metric-aliases.conf
  180. // from my Ubuntu system, but we're better off being very conservative.
  181. // Arimo, Tinos and Cousine are a set of fonts metric-compatible with
  182. // Arial, Times New Roman and Courier New with a character repertoire
  183. // much larger than Liberation. Note that Cousine is metrically
  184. // compatible with Courier New, but the former is sans-serif while
  185. // the latter is serif.
  186. struct FontEquivMap {
  187. FontEquivClass clazz;
  188. const char name[40];
  189. };
  190. static const FontEquivMap kFontEquivMap[] = {
  191. { SANS, "Arial" },
  192. { SANS, "Arimo" },
  193. { SANS, "Liberation Sans" },
  194. { SERIF, "Times New Roman" },
  195. { SERIF, "Tinos" },
  196. { SERIF, "Liberation Serif" },
  197. { MONO, "Courier New" },
  198. { MONO, "Cousine" },
  199. { MONO, "Liberation Mono" },
  200. { SYMBOL, "Symbol" },
  201. { SYMBOL, "Symbol Neu" },
  202. // MS Pゴシック
  203. { PGOTHIC, "MS PGothic" },
  204. { PGOTHIC, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0"
  205. "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" },
  206. { PGOTHIC, "Noto Sans CJK JP" },
  207. { PGOTHIC, "IPAPGothic" },
  208. { PGOTHIC, "MotoyaG04Gothic" },
  209. // MS ゴシック
  210. { GOTHIC, "MS Gothic" },
  211. { GOTHIC, "\xef\xbc\xad\xef\xbc\xb3 "
  212. "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" },
  213. { GOTHIC, "Noto Sans Mono CJK JP" },
  214. { GOTHIC, "IPAGothic" },
  215. { GOTHIC, "MotoyaG04GothicMono" },
  216. // MS P明朝
  217. { PMINCHO, "MS PMincho" },
  218. { PMINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0"
  219. "\xe6\x98\x8e\xe6\x9c\x9d"},
  220. { PMINCHO, "Noto Serif CJK JP" },
  221. { PMINCHO, "IPAPMincho" },
  222. { PMINCHO, "MotoyaG04Mincho" },
  223. // MS 明朝
  224. { MINCHO, "MS Mincho" },
  225. { MINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xe6\x98\x8e\xe6\x9c\x9d" },
  226. { MINCHO, "Noto Serif CJK JP" },
  227. { MINCHO, "IPAMincho" },
  228. { MINCHO, "MotoyaG04MinchoMono" },
  229. // 宋体
  230. { SIMSUN, "Simsun" },
  231. { SIMSUN, "\xe5\xae\x8b\xe4\xbd\x93" },
  232. { SIMSUN, "Noto Serif CJK SC" },
  233. { SIMSUN, "MSung GB18030" },
  234. { SIMSUN, "Song ASC" },
  235. // 新宋体
  236. { NSIMSUN, "NSimsun" },
  237. { NSIMSUN, "\xe6\x96\xb0\xe5\xae\x8b\xe4\xbd\x93" },
  238. { NSIMSUN, "Noto Serif CJK SC" },
  239. { NSIMSUN, "MSung GB18030" },
  240. { NSIMSUN, "N Song ASC" },
  241. // 黑体
  242. { SIMHEI, "Simhei" },
  243. { SIMHEI, "\xe9\xbb\x91\xe4\xbd\x93" },
  244. { SIMHEI, "Noto Sans CJK SC" },
  245. { SIMHEI, "MYingHeiGB18030" },
  246. { SIMHEI, "MYingHeiB5HK" },
  247. // 新細明體
  248. { PMINGLIU, "PMingLiU"},
  249. { PMINGLIU, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" },
  250. { PMINGLIU, "Noto Serif CJK TC"},
  251. { PMINGLIU, "MSung B5HK"},
  252. // 細明體
  253. { MINGLIU, "MingLiU"},
  254. { MINGLIU, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" },
  255. { MINGLIU, "Noto Serif CJK TC"},
  256. { MINGLIU, "MSung B5HK"},
  257. // 新細明體
  258. { PMINGLIUHK, "PMingLiU_HKSCS"},
  259. { PMINGLIUHK, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" },
  260. { PMINGLIUHK, "Noto Serif CJK TC"},
  261. { PMINGLIUHK, "MSung B5HK"},
  262. // 細明體
  263. { MINGLIUHK, "MingLiU_HKSCS"},
  264. { MINGLIUHK, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" },
  265. { MINGLIUHK, "Noto Serif CJK TC"},
  266. { MINGLIUHK, "MSung B5HK"},
  267. // Cambria
  268. { CAMBRIA, "Cambria" },
  269. { CAMBRIA, "Caladea" },
  270. // Calibri
  271. { CALIBRI, "Calibri" },
  272. { CALIBRI, "Carlito" },
  273. };
  274. static const size_t kFontCount =
  275. sizeof(kFontEquivMap)/sizeof(kFontEquivMap[0]);
  276. // TODO(jungshik): If this loop turns out to be hot, turn
  277. // the array to a static (hash)map to speed it up.
  278. for (size_t i = 0; i < kFontCount; ++i) {
  279. if (strcasecmp(kFontEquivMap[i].name, fontname) == 0)
  280. return kFontEquivMap[i].clazz;
  281. }
  282. return OTHER;
  283. }
  284. // Return true if |font_a| and |font_b| are visually and at the metrics
  285. // level interchangeable.
  286. bool IsMetricCompatibleReplacement(const char* font_a, const char* font_b)
  287. {
  288. FontEquivClass class_a = GetFontEquivClass(font_a);
  289. FontEquivClass class_b = GetFontEquivClass(font_b);
  290. return class_a != OTHER && class_a == class_b;
  291. }
  292. // Normally we only return exactly the font asked for. In last-resort
  293. // cases, the request either doesn't specify a font or is one of the
  294. // basic font names like "Sans", "Serif" or "Monospace". This function
  295. // tells you whether a given request is for such a fallback.
  296. bool IsFallbackFontAllowed(const SkString& family) {
  297. const char* family_cstr = family.c_str();
  298. return family.isEmpty() ||
  299. strcasecmp(family_cstr, "sans") == 0 ||
  300. strcasecmp(family_cstr, "serif") == 0 ||
  301. strcasecmp(family_cstr, "monospace") == 0;
  302. }
  303. // Retrieves |is_bold|, |is_italic| and |font_family| properties from |font|.
  304. static int get_int(FcPattern* pattern, const char object[], int missing) {
  305. int value;
  306. if (FcPatternGetInteger(pattern, object, 0, &value) != FcResultMatch) {
  307. return missing;
  308. }
  309. return value;
  310. }
  311. static int map_range(SkScalar value,
  312. SkScalar old_min, SkScalar old_max,
  313. SkScalar new_min, SkScalar new_max)
  314. {
  315. SkASSERT(old_min < old_max);
  316. SkASSERT(new_min <= new_max);
  317. return new_min + ((value - old_min) * (new_max - new_min) / (old_max - old_min));
  318. }
  319. struct MapRanges {
  320. SkScalar old_val;
  321. SkScalar new_val;
  322. };
  323. static SkScalar map_ranges(SkScalar val, MapRanges const ranges[], int rangesCount) {
  324. // -Inf to [0]
  325. if (val < ranges[0].old_val) {
  326. return ranges[0].new_val;
  327. }
  328. // Linear from [i] to [i+1]
  329. for (int i = 0; i < rangesCount - 1; ++i) {
  330. if (val < ranges[i+1].old_val) {
  331. return map_range(val, ranges[i].old_val, ranges[i+1].old_val,
  332. ranges[i].new_val, ranges[i+1].new_val);
  333. }
  334. }
  335. // From [n] to +Inf
  336. // if (fcweight < Inf)
  337. return ranges[rangesCount-1].new_val;
  338. }
  339. #ifndef FC_WEIGHT_DEMILIGHT
  340. #define FC_WEIGHT_DEMILIGHT 65
  341. #endif
  342. static SkFontStyle skfontstyle_from_fcpattern(FcPattern* pattern) {
  343. typedef SkFontStyle SkFS;
  344. static constexpr MapRanges weightRanges[] = {
  345. { FC_WEIGHT_THIN, SkFS::kThin_Weight },
  346. { FC_WEIGHT_EXTRALIGHT, SkFS::kExtraLight_Weight },
  347. { FC_WEIGHT_LIGHT, SkFS::kLight_Weight },
  348. { FC_WEIGHT_DEMILIGHT, 350 },
  349. { FC_WEIGHT_BOOK, 380 },
  350. { FC_WEIGHT_REGULAR, SkFS::kNormal_Weight },
  351. { FC_WEIGHT_MEDIUM, SkFS::kMedium_Weight },
  352. { FC_WEIGHT_DEMIBOLD, SkFS::kSemiBold_Weight },
  353. { FC_WEIGHT_BOLD, SkFS::kBold_Weight },
  354. { FC_WEIGHT_EXTRABOLD, SkFS::kExtraBold_Weight },
  355. { FC_WEIGHT_BLACK, SkFS::kBlack_Weight },
  356. { FC_WEIGHT_EXTRABLACK, SkFS::kExtraBlack_Weight },
  357. };
  358. SkScalar weight = map_ranges(get_int(pattern, FC_WEIGHT, FC_WEIGHT_REGULAR),
  359. weightRanges, SK_ARRAY_COUNT(weightRanges));
  360. static constexpr MapRanges widthRanges[] = {
  361. { FC_WIDTH_ULTRACONDENSED, SkFS::kUltraCondensed_Width },
  362. { FC_WIDTH_EXTRACONDENSED, SkFS::kExtraCondensed_Width },
  363. { FC_WIDTH_CONDENSED, SkFS::kCondensed_Width },
  364. { FC_WIDTH_SEMICONDENSED, SkFS::kSemiCondensed_Width },
  365. { FC_WIDTH_NORMAL, SkFS::kNormal_Width },
  366. { FC_WIDTH_SEMIEXPANDED, SkFS::kSemiExpanded_Width },
  367. { FC_WIDTH_EXPANDED, SkFS::kExpanded_Width },
  368. { FC_WIDTH_EXTRAEXPANDED, SkFS::kExtraExpanded_Width },
  369. { FC_WIDTH_ULTRAEXPANDED, SkFS::kUltraExpanded_Width },
  370. };
  371. SkScalar width = map_ranges(get_int(pattern, FC_WIDTH, FC_WIDTH_NORMAL),
  372. widthRanges, SK_ARRAY_COUNT(widthRanges));
  373. SkFS::Slant slant = SkFS::kUpright_Slant;
  374. switch (get_int(pattern, FC_SLANT, FC_SLANT_ROMAN)) {
  375. case FC_SLANT_ROMAN: slant = SkFS::kUpright_Slant; break;
  376. case FC_SLANT_ITALIC : slant = SkFS::kItalic_Slant ; break;
  377. case FC_SLANT_OBLIQUE: slant = SkFS::kOblique_Slant; break;
  378. default: SkASSERT(false); break;
  379. }
  380. return SkFontStyle(SkScalarRoundToInt(weight), SkScalarRoundToInt(width), slant);
  381. }
  382. static void fcpattern_from_skfontstyle(SkFontStyle style, FcPattern* pattern) {
  383. typedef SkFontStyle SkFS;
  384. static constexpr MapRanges weightRanges[] = {
  385. { SkFS::kThin_Weight, FC_WEIGHT_THIN },
  386. { SkFS::kExtraLight_Weight, FC_WEIGHT_EXTRALIGHT },
  387. { SkFS::kLight_Weight, FC_WEIGHT_LIGHT },
  388. { 350, FC_WEIGHT_DEMILIGHT },
  389. { 380, FC_WEIGHT_BOOK },
  390. { SkFS::kNormal_Weight, FC_WEIGHT_REGULAR },
  391. { SkFS::kMedium_Weight, FC_WEIGHT_MEDIUM },
  392. { SkFS::kSemiBold_Weight, FC_WEIGHT_DEMIBOLD },
  393. { SkFS::kBold_Weight, FC_WEIGHT_BOLD },
  394. { SkFS::kExtraBold_Weight, FC_WEIGHT_EXTRABOLD },
  395. { SkFS::kBlack_Weight, FC_WEIGHT_BLACK },
  396. { SkFS::kExtraBlack_Weight, FC_WEIGHT_EXTRABLACK },
  397. };
  398. int weight = map_ranges(style.weight(), weightRanges, SK_ARRAY_COUNT(weightRanges));
  399. static constexpr MapRanges widthRanges[] = {
  400. { SkFS::kUltraCondensed_Width, FC_WIDTH_ULTRACONDENSED },
  401. { SkFS::kExtraCondensed_Width, FC_WIDTH_EXTRACONDENSED },
  402. { SkFS::kCondensed_Width, FC_WIDTH_CONDENSED },
  403. { SkFS::kSemiCondensed_Width, FC_WIDTH_SEMICONDENSED },
  404. { SkFS::kNormal_Width, FC_WIDTH_NORMAL },
  405. { SkFS::kSemiExpanded_Width, FC_WIDTH_SEMIEXPANDED },
  406. { SkFS::kExpanded_Width, FC_WIDTH_EXPANDED },
  407. { SkFS::kExtraExpanded_Width, FC_WIDTH_EXTRAEXPANDED },
  408. { SkFS::kUltraExpanded_Width, FC_WIDTH_ULTRAEXPANDED },
  409. };
  410. int width = map_ranges(style.width(), widthRanges, SK_ARRAY_COUNT(widthRanges));
  411. int slant = FC_SLANT_ROMAN;
  412. switch (style.slant()) {
  413. case SkFS::kUpright_Slant: slant = FC_SLANT_ROMAN ; break;
  414. case SkFS::kItalic_Slant : slant = FC_SLANT_ITALIC ; break;
  415. case SkFS::kOblique_Slant: slant = FC_SLANT_OBLIQUE; break;
  416. default: SkASSERT(false); break;
  417. }
  418. FcPatternAddInteger(pattern, FC_WEIGHT, weight);
  419. FcPatternAddInteger(pattern, FC_WIDTH , width);
  420. FcPatternAddInteger(pattern, FC_SLANT , slant);
  421. }
  422. } // anonymous namespace
  423. ///////////////////////////////////////////////////////////////////////////////
  424. #define kMaxFontFamilyLength 2048
  425. #ifdef SK_FONT_CONFIG_INTERFACE_ONLY_ALLOW_SFNT_FONTS
  426. const char* kFontFormatTrueType = "TrueType";
  427. const char* kFontFormatCFF = "CFF";
  428. #endif
  429. SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() {
  430. FCLocker lock;
  431. FcInit();
  432. SkDEBUGCODE(fontconfiginterface_unittest();)
  433. }
  434. SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() {
  435. }
  436. bool SkFontConfigInterfaceDirect::isAccessible(const char* filename) {
  437. if (access(filename, R_OK) != 0) {
  438. return false;
  439. }
  440. return true;
  441. }
  442. bool SkFontConfigInterfaceDirect::isValidPattern(FcPattern* pattern) {
  443. #ifdef SK_FONT_CONFIG_INTERFACE_ONLY_ALLOW_SFNT_FONTS
  444. const char* font_format = get_string(pattern, FC_FONTFORMAT);
  445. if (font_format
  446. && strcmp(font_format, kFontFormatTrueType) != 0
  447. && strcmp(font_format, kFontFormatCFF) != 0)
  448. {
  449. return false;
  450. }
  451. #endif
  452. // fontconfig can also return fonts which are unreadable
  453. const char* c_filename = get_string(pattern, FC_FILE);
  454. if (!c_filename) {
  455. return false;
  456. }
  457. const char* sysroot = (const char*)FcConfigGetSysRoot(nullptr);
  458. SkString resolvedFilename;
  459. if (sysroot) {
  460. resolvedFilename = sysroot;
  461. resolvedFilename += c_filename;
  462. c_filename = resolvedFilename.c_str();
  463. }
  464. return this->isAccessible(c_filename);
  465. }
  466. // Find matching font from |font_set| for the given font family.
  467. FcPattern* SkFontConfigInterfaceDirect::MatchFont(FcFontSet* font_set,
  468. const char* post_config_family,
  469. const SkString& family) {
  470. // Older versions of fontconfig have a bug where they cannot select
  471. // only scalable fonts so we have to manually filter the results.
  472. FcPattern* match = nullptr;
  473. for (int i = 0; i < font_set->nfont; ++i) {
  474. FcPattern* current = font_set->fonts[i];
  475. if (this->isValidPattern(current)) {
  476. match = current;
  477. break;
  478. }
  479. }
  480. if (match && !IsFallbackFontAllowed(family)) {
  481. bool acceptable_substitute = false;
  482. for (int id = 0; id < 255; ++id) {
  483. const char* post_match_family = get_string(match, FC_FAMILY, id);
  484. if (!post_match_family)
  485. break;
  486. acceptable_substitute =
  487. (strcasecmp(post_config_family, post_match_family) == 0 ||
  488. // Workaround for Issue 12530:
  489. // requested family: "Bitstream Vera Sans"
  490. // post_config_family: "Arial"
  491. // post_match_family: "Bitstream Vera Sans"
  492. // -> We should treat this case as a good match.
  493. strcasecmp(family.c_str(), post_match_family) == 0) ||
  494. IsMetricCompatibleReplacement(family.c_str(), post_match_family);
  495. if (acceptable_substitute)
  496. break;
  497. }
  498. if (!acceptable_substitute)
  499. return nullptr;
  500. }
  501. return match;
  502. }
  503. bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[],
  504. SkFontStyle style,
  505. FontIdentity* outIdentity,
  506. SkString* outFamilyName,
  507. SkFontStyle* outStyle) {
  508. SkString familyStr(familyName ? familyName : "");
  509. if (familyStr.size() > kMaxFontFamilyLength) {
  510. return false;
  511. }
  512. FCLocker lock;
  513. FcPattern* pattern = FcPatternCreate();
  514. if (familyName) {
  515. FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
  516. }
  517. fcpattern_from_skfontstyle(style, pattern);
  518. FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
  519. FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
  520. FcDefaultSubstitute(pattern);
  521. // Font matching:
  522. // CSS often specifies a fallback list of families:
  523. // font-family: a, b, c, serif;
  524. // However, fontconfig will always do its best to find *a* font when asked
  525. // for something so we need a way to tell if the match which it has found is
  526. // "good enough" for us. Otherwise, we can return nullptr which gets piped up
  527. // and lets WebKit know to try the next CSS family name. However, fontconfig
  528. // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
  529. // wish to support that.
  530. //
  531. // Thus, if a specific family is requested we set @family_requested. Then we
  532. // record two strings: the family name after config processing and the
  533. // family name after resolving. If the two are equal, it's a good match.
  534. //
  535. // So consider the case where a user has mapped Arial to Helvetica in their
  536. // config.
  537. // requested family: "Arial"
  538. // post_config_family: "Helvetica"
  539. // post_match_family: "Helvetica"
  540. // -> good match
  541. //
  542. // and for a missing font:
  543. // requested family: "Monaco"
  544. // post_config_family: "Monaco"
  545. // post_match_family: "Times New Roman"
  546. // -> BAD match
  547. //
  548. // However, we special-case fallback fonts; see IsFallbackFontAllowed().
  549. const char* post_config_family = get_string(pattern, FC_FAMILY);
  550. if (!post_config_family) {
  551. // we can just continue with an empty name, e.g. default font
  552. post_config_family = "";
  553. }
  554. FcResult result;
  555. FcFontSet* font_set = FcFontSort(nullptr, pattern, 0, nullptr, &result);
  556. if (!font_set) {
  557. FcPatternDestroy(pattern);
  558. return false;
  559. }
  560. FcPattern* match = this->MatchFont(font_set, post_config_family, familyStr);
  561. if (!match) {
  562. FcPatternDestroy(pattern);
  563. FcFontSetDestroy(font_set);
  564. return false;
  565. }
  566. FcPatternDestroy(pattern);
  567. // From here out we just extract our results from 'match'
  568. post_config_family = get_string(match, FC_FAMILY);
  569. if (!post_config_family) {
  570. FcFontSetDestroy(font_set);
  571. return false;
  572. }
  573. const char* c_filename = get_string(match, FC_FILE);
  574. if (!c_filename) {
  575. FcFontSetDestroy(font_set);
  576. return false;
  577. }
  578. const char* sysroot = (const char*)FcConfigGetSysRoot(nullptr);
  579. SkString resolvedFilename;
  580. if (sysroot) {
  581. resolvedFilename = sysroot;
  582. resolvedFilename += c_filename;
  583. c_filename = resolvedFilename.c_str();
  584. }
  585. int face_index = get_int(match, FC_INDEX, 0);
  586. FcFontSetDestroy(font_set);
  587. if (outIdentity) {
  588. outIdentity->fTTCIndex = face_index;
  589. outIdentity->fString.set(c_filename);
  590. }
  591. if (outFamilyName) {
  592. outFamilyName->set(post_config_family);
  593. }
  594. if (outStyle) {
  595. *outStyle = skfontstyle_from_fcpattern(match);
  596. }
  597. return true;
  598. }
  599. SkStreamAsset* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) {
  600. return SkStream::MakeFromFile(identity.fString.c_str()).release();
  601. }