PageRenderTime 269ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/external/skia/src/ports/SkFontHost_fontconfig.cpp

https://gitlab.com/brian0218/rk3188_r-box_android4.2.2_sdk
C++ | 354 lines | 214 code | 53 blank | 87 comment | 36 complexity | dd44996917787d7770eb158d7bbe6916 MD5 | raw file
  1. /*
  2. * Copyright 2008 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. // -----------------------------------------------------------------------------
  8. // This file provides implementations of the font resolution members of
  9. // SkFontHost by using the fontconfig[1] library. Fontconfig is usually found
  10. // on Linux systems and handles configuration, parsing and caching issues
  11. // involved with enumerating and matching fonts.
  12. //
  13. // [1] http://fontconfig.org
  14. // -----------------------------------------------------------------------------
  15. #include <map>
  16. #include <string>
  17. #include <fontconfig/fontconfig.h>
  18. #include "SkFontHost.h"
  19. #include "SkStream.h"
  20. // This is an extern from SkFontHost_FreeType
  21. SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name);
  22. // -----------------------------------------------------------------------------
  23. // The rest of Skia requires that fonts be identified by a unique unsigned id
  24. // and that we be able to load them given the id. What we actually get from
  25. // fontconfig is the filename of the font so we keep a locked map from
  26. // filenames to fileid numbers and back.
  27. //
  28. // Note that there's also a unique id in the SkTypeface. This is unique over
  29. // both filename and style. Thus we encode that id as (fileid << 8) | style.
  30. // Although truetype fonts can support multiple faces in a single file, at the
  31. // moment Skia doesn't.
  32. // -----------------------------------------------------------------------------
  33. SK_DECLARE_STATIC_MUTEX(global_fc_map_lock);
  34. static std::map<std::string, unsigned> global_fc_map;
  35. static std::map<unsigned, std::string> global_fc_map_inverted;
  36. static std::map<uint32_t, SkTypeface *> global_fc_typefaces;
  37. static unsigned global_fc_map_next_id = 0;
  38. static unsigned UniqueIdToFileId(unsigned uniqueid)
  39. {
  40. return uniqueid >> 8;
  41. }
  42. static SkTypeface::Style UniqueIdToStyle(unsigned uniqueid)
  43. {
  44. return static_cast<SkTypeface::Style>(uniqueid & 0xff);
  45. }
  46. static unsigned FileIdAndStyleToUniqueId(unsigned fileid,
  47. SkTypeface::Style style)
  48. {
  49. SkASSERT((style & 0xff) == style);
  50. return (fileid << 8) | static_cast<int>(style);
  51. }
  52. // -----------------------------------------------------------------------------
  53. // Normally we only return exactly the font asked for. In last-resort cases,
  54. // the request is for one of the basic font names "Sans", "Serif" or
  55. // "Monospace". This function tells you whether a given request is for such a
  56. // fallback.
  57. // -----------------------------------------------------------------------------
  58. static bool IsFallbackFontAllowed(const char* request)
  59. {
  60. return strcmp(request, "Sans") == 0 ||
  61. strcmp(request, "Serif") == 0 ||
  62. strcmp(request, "Monospace") == 0;
  63. }
  64. class FontConfigTypeface : public SkTypeface {
  65. public:
  66. FontConfigTypeface(Style style, uint32_t id)
  67. : SkTypeface(style, id)
  68. { }
  69. };
  70. // -----------------------------------------------------------------------------
  71. // Find a matching font where @type (one of FC_*) is equal to @value. For a
  72. // list of types, see http://fontconfig.org/fontconfig-devel/x19.html#AEN27.
  73. // The variable arguments are a list of triples, just like the first three
  74. // arguments, and must be NULL terminated.
  75. //
  76. // For example,
  77. // FontMatchString(FC_FILE, FcTypeString, "/usr/share/fonts/myfont.ttf",
  78. // NULL);
  79. // -----------------------------------------------------------------------------
  80. static FcPattern* FontMatch(const char* type, FcType vtype, const void* value,
  81. ...)
  82. {
  83. va_list ap;
  84. va_start(ap, value);
  85. FcPattern* pattern = FcPatternCreate();
  86. const char* family_requested = NULL;
  87. for (;;) {
  88. FcValue fcvalue;
  89. fcvalue.type = vtype;
  90. switch (vtype) {
  91. case FcTypeString:
  92. fcvalue.u.s = (FcChar8*) value;
  93. break;
  94. case FcTypeInteger:
  95. fcvalue.u.i = (int)(intptr_t)value;
  96. break;
  97. default:
  98. SkDEBUGFAIL("FontMatch unhandled type");
  99. }
  100. FcPatternAdd(pattern, type, fcvalue, 0);
  101. if (vtype == FcTypeString && strcmp(type, FC_FAMILY) == 0)
  102. family_requested = (const char*) value;
  103. type = va_arg(ap, const char *);
  104. if (!type)
  105. break;
  106. // FcType is promoted to int when passed through ...
  107. vtype = static_cast<FcType>(va_arg(ap, int));
  108. value = va_arg(ap, const void *);
  109. };
  110. va_end(ap);
  111. FcConfigSubstitute(0, pattern, FcMatchPattern);
  112. FcDefaultSubstitute(pattern);
  113. // Font matching:
  114. // CSS often specifies a fallback list of families:
  115. // font-family: a, b, c, serif;
  116. // However, fontconfig will always do its best to find *a* font when asked
  117. // for something so we need a way to tell if the match which it has found is
  118. // "good enough" for us. Otherwise, we can return NULL which gets piped up
  119. // and lets WebKit know to try the next CSS family name. However, fontconfig
  120. // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
  121. // wish to support that.
  122. //
  123. // Thus, if a specific family is requested we set @family_requested. Then we
  124. // record two strings: the family name after config processing and the
  125. // family name after resolving. If the two are equal, it's a good match.
  126. //
  127. // So consider the case where a user has mapped Arial to Helvetica in their
  128. // config.
  129. // requested family: "Arial"
  130. // post_config_family: "Helvetica"
  131. // post_match_family: "Helvetica"
  132. // -> good match
  133. //
  134. // and for a missing font:
  135. // requested family: "Monaco"
  136. // post_config_family: "Monaco"
  137. // post_match_family: "Times New Roman"
  138. // -> BAD match
  139. //
  140. // However, we special-case fallback fonts; see IsFallbackFontAllowed().
  141. FcChar8* post_config_family;
  142. FcPatternGetString(pattern, FC_FAMILY, 0, &post_config_family);
  143. FcResult result;
  144. FcPattern* match = FcFontMatch(0, pattern, &result);
  145. if (!match) {
  146. FcPatternDestroy(pattern);
  147. return NULL;
  148. }
  149. FcChar8* post_match_family;
  150. FcPatternGetString(match, FC_FAMILY, 0, &post_match_family);
  151. const bool family_names_match =
  152. !family_requested ?
  153. true :
  154. strcasecmp((char *)post_config_family, (char *)post_match_family) == 0;
  155. FcPatternDestroy(pattern);
  156. if (!family_names_match && !IsFallbackFontAllowed(family_requested)) {
  157. FcPatternDestroy(match);
  158. return NULL;
  159. }
  160. return match;
  161. }
  162. // -----------------------------------------------------------------------------
  163. // Check to see if the filename has already been assigned a fileid and, if so,
  164. // use it. Otherwise, assign one. Return the resulting fileid.
  165. // -----------------------------------------------------------------------------
  166. static unsigned FileIdFromFilename(const char* filename)
  167. {
  168. SkAutoMutexAcquire ac(global_fc_map_lock);
  169. std::map<std::string, unsigned>::const_iterator i =
  170. global_fc_map.find(filename);
  171. if (i == global_fc_map.end()) {
  172. const unsigned fileid = global_fc_map_next_id++;
  173. global_fc_map[filename] = fileid;
  174. global_fc_map_inverted[fileid] = filename;
  175. return fileid;
  176. } else {
  177. return i->second;
  178. }
  179. }
  180. // static
  181. SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
  182. const char familyName[],
  183. const void* data, size_t bytelength,
  184. SkTypeface::Style style)
  185. {
  186. const char* resolved_family_name = NULL;
  187. FcPattern* face_match = NULL;
  188. {
  189. SkAutoMutexAcquire ac(global_fc_map_lock);
  190. FcInit();
  191. }
  192. if (familyFace) {
  193. // Here we use the inverted global id map to find the filename from the
  194. // SkTypeface object. Given the filename we can ask fontconfig for the
  195. // familyname of the font.
  196. SkAutoMutexAcquire ac(global_fc_map_lock);
  197. const unsigned fileid = UniqueIdToFileId(familyFace->uniqueID());
  198. std::map<unsigned, std::string>::const_iterator i =
  199. global_fc_map_inverted.find(fileid);
  200. if (i == global_fc_map_inverted.end())
  201. return NULL;
  202. FcInit();
  203. face_match = FontMatch(FC_FILE, FcTypeString, i->second.c_str(),
  204. NULL);
  205. if (!face_match)
  206. return NULL;
  207. FcChar8* family;
  208. if (FcPatternGetString(face_match, FC_FAMILY, 0, &family)) {
  209. FcPatternDestroy(face_match);
  210. return NULL;
  211. }
  212. // At this point, @family is pointing into the @face_match object so we
  213. // cannot release it yet.
  214. resolved_family_name = reinterpret_cast<char*>(family);
  215. } else if (familyName) {
  216. resolved_family_name = familyName;
  217. } else {
  218. return NULL;
  219. }
  220. // At this point, we have a resolved_family_name from somewhere
  221. SkASSERT(resolved_family_name);
  222. const int bold = style & SkTypeface::kBold ?
  223. FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL;
  224. const int italic = style & SkTypeface::kItalic ?
  225. FC_SLANT_ITALIC : FC_SLANT_ROMAN;
  226. FcPattern* match = FontMatch(FC_FAMILY, FcTypeString, resolved_family_name,
  227. FC_WEIGHT, FcTypeInteger, bold,
  228. FC_SLANT, FcTypeInteger, italic,
  229. NULL);
  230. if (face_match)
  231. FcPatternDestroy(face_match);
  232. if (!match)
  233. return NULL;
  234. FcChar8* filename;
  235. if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) {
  236. FcPatternDestroy(match);
  237. return NULL;
  238. }
  239. // Now @filename is pointing into @match
  240. const unsigned fileid = FileIdFromFilename(reinterpret_cast<char*>(filename));
  241. const unsigned id = FileIdAndStyleToUniqueId(fileid, style);
  242. SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id));
  243. FcPatternDestroy(match);
  244. {
  245. SkAutoMutexAcquire ac(global_fc_map_lock);
  246. global_fc_typefaces[id] = typeface;
  247. }
  248. return typeface;
  249. }
  250. // static
  251. SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream)
  252. {
  253. SkDEBUGFAIL("SkFontHost::CreateTypefaceFromStream unimplemented");
  254. return NULL;
  255. }
  256. // static
  257. SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[])
  258. {
  259. SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented");
  260. return NULL;
  261. }
  262. // static
  263. SkStream* SkFontHost::OpenStream(uint32_t id)
  264. {
  265. SkAutoMutexAcquire ac(global_fc_map_lock);
  266. const unsigned fileid = UniqueIdToFileId(id);
  267. std::map<unsigned, std::string>::const_iterator i =
  268. global_fc_map_inverted.find(fileid);
  269. if (i == global_fc_map_inverted.end())
  270. return NULL;
  271. return SkNEW_ARGS(SkFILEStream, (i->second.c_str()));
  272. }
  273. size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
  274. int32_t* index) {
  275. SkAutoMutexAcquire ac(global_fc_map_lock);
  276. const unsigned fileid = UniqueIdToFileId(fontID);
  277. std::map<unsigned, std::string>::const_iterator i =
  278. global_fc_map_inverted.find(fileid);
  279. if (i == global_fc_map_inverted.end()) {
  280. return 0;
  281. }
  282. const std::string& str = i->second;
  283. if (path) {
  284. memcpy(path, str.c_str(), SkMin32(str.size(), length));
  285. }
  286. if (index) { // TODO: check if we're in a TTC
  287. *index = 0;
  288. }
  289. return str.size();
  290. }
  291. void SkFontHost::Serialize(const SkTypeface*, SkWStream*) {
  292. SkDEBUGFAIL("SkFontHost::Serialize unimplemented");
  293. }
  294. SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
  295. SkDEBUGFAIL("SkFontHost::Deserialize unimplemented");
  296. return NULL;
  297. }
  298. SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
  299. // We don't handle font fallback, WebKit does.
  300. return 0;
  301. }