Font_Metrics

The font metrics class.

Defined (1)

The class is defined in the following location(s).

/lib/dompdf/include/font_metrics.cls.php  
  1. class Font_Metrics { 
  2.  
  3. /** 
  4. * @see __DOMPDF_FONT_CACHE_FILE 
  5. */ 
  6. const CACHE_FILE = __DOMPDF_FONT_CACHE_FILE; 
  7.  
  8. /** 
  9. * Underlying {@link Canvas} object to perform text size calculations 
  10. * @var Canvas 
  11. */ 
  12. static protected $_pdf = null; 
  13.  
  14. /** 
  15. * Array of font family names to font files 
  16. * Usually cached by the {@link load_font.php} script 
  17. * @var array 
  18. */ 
  19. static protected $_font_lookup = array(); 
  20.  
  21.  
  22. /** 
  23. * Class initialization 
  24. */ 
  25. static function init(Canvas $canvas = null) { 
  26. if (!self::$_pdf) { 
  27. if (!$canvas) { 
  28. $canvas = Canvas_Factory::get_instance(new DOMPDF()); 
  29.  
  30. self::$_pdf = $canvas; 
  31.  
  32. /** 
  33. * Calculates text size, in points 
  34. * @param string $text the text to be sized 
  35. * @param string $font the desired font 
  36. * @param float $size the desired font size 
  37. * @param float $word_spacing 
  38. * @param float $char_spacing 
  39. * @internal param float $spacing word spacing, if any 
  40. * @return float 
  41. */ 
  42. static function get_text_width($text, $font, $size, $word_spacing = 0.0, $char_spacing = 0.0) { 
  43. //return self::$_pdf->get_text_width($text, $font, $size, $word_spacing, $char_spacing); 
  44.  
  45. // @todo Make sure this cache is efficient before enabling it 
  46. static $cache = array(); 
  47.  
  48. if ( $text === "" ) { 
  49. return 0; 
  50.  
  51. // Don't cache long strings 
  52. $use_cache = !isset($text[50]); // Faster than strlen 
  53.  
  54. $key = "$font/$size/$word_spacing/$char_spacing"; 
  55.  
  56. if ( $use_cache && isset($cache[$key][$text]) ) { 
  57. return $cache[$key]["$text"]; 
  58.  
  59. $width = self::$_pdf->get_text_width($text, $font, $size, $word_spacing, $char_spacing); 
  60.  
  61. if ( $use_cache ) { 
  62. $cache[$key][$text] = $width; 
  63.  
  64. return $width; 
  65.  
  66. /** 
  67. * Calculates font height 
  68. * @param string $font 
  69. * @param float $size 
  70. * @return float 
  71. */ 
  72. static function get_font_height($font, $size) { 
  73. return self::$_pdf->get_font_height($font, $size); 
  74.  
  75. /** 
  76. * Resolves a font family & subtype into an actual font file 
  77. * Subtype can be one of 'normal', 'bold', 'italic' or 'bold_italic'. If 
  78. * the particular font family has no suitable font file, the default font 
  79. * ({@link DOMPDF_DEFAULT_FONT}) is used. The font file returned 
  80. * is the absolute pathname to the font file on the system. 
  81. * @param string $family_raw 
  82. * @param string $subtype_raw 
  83. * @return string 
  84. */ 
  85. static function get_font($family_raw, $subtype_raw = "normal") { 
  86. static $cache = array(); 
  87.  
  88. if ( isset($cache[$family_raw][$subtype_raw]) ) { 
  89. return $cache[$family_raw][$subtype_raw]; 
  90.  
  91. /** Allow calling for various fonts in search path. Therefore not immediately 
  92. * return replacement on non match. 
  93. * Only when called with NULL try replacement. 
  94. * When this is also missing there is really trouble. 
  95. * If only the subtype fails, nevertheless return failure. 
  96. * Only on checking the fallback font, check various subtypes on same font. 
  97. */ 
  98.  
  99. $subtype = strtolower($subtype_raw); 
  100.  
  101. if ( $family_raw ) { 
  102. $family = str_replace( array("'", '"'), "", strtolower($family_raw)); 
  103.  
  104. if ( isset(self::$_font_lookup[$family][$subtype]) ) { 
  105. return $cache[$family_raw][$subtype_raw] = self::$_font_lookup[$family][$subtype]; 
  106.  
  107. return null; 
  108.  
  109. $family = "serif"; 
  110.  
  111. if ( isset(self::$_font_lookup[$family][$subtype]) ) { 
  112. return $cache[$family_raw][$subtype_raw] = self::$_font_lookup[$family][$subtype]; 
  113.  
  114. if ( !isset(self::$_font_lookup[$family]) ) { 
  115. return null; 
  116.  
  117. $family = self::$_font_lookup[$family]; 
  118.  
  119. foreach ( $family as $sub => $font ) { 
  120. if (strpos($subtype, $sub) !== false) { 
  121. return $cache[$family_raw][$subtype_raw] = $font; 
  122.  
  123. if ($subtype !== "normal") { 
  124. foreach ( $family as $sub => $font ) { 
  125. if ($sub !== "normal") { 
  126. return $cache[$family_raw][$subtype_raw] = $font; 
  127.  
  128. $subtype = "normal"; 
  129.  
  130. if ( isset($family[$subtype]) ) { 
  131. return $cache[$family_raw][$subtype_raw] = $family[$subtype]; 
  132.  
  133. return null; 
  134.  
  135. static function get_family($family) { 
  136. $family = str_replace( array("'", '"'), "", mb_strtolower($family)); 
  137.  
  138. if ( isset(self::$_font_lookup[$family]) ) { 
  139. return self::$_font_lookup[$family]; 
  140.  
  141. return null; 
  142.  
  143. /** 
  144. * Saves the stored font family cache 
  145. * The name and location of the cache file are determined by {@link 
  146. * Font_Metrics::CACHE_FILE}. This file should be writable by the 
  147. * webserver process. 
  148. * @see Font_Metrics::load_font_families() 
  149. */ 
  150. static function save_font_families() { 
  151. // replace the path to the DOMPDF font directories with the corresponding constants (allows for more portability) 
  152. $cache_data = var_export(self::$_font_lookup, true); 
  153. $cache_data = str_replace('\''.DOMPDF_FONT_DIR , 'DOMPDF_FONT_DIR . \'' , $cache_data); 
  154. $cache_data = str_replace('\''.DOMPDF_DIR , 'DOMPDF_DIR . \'' , $cache_data); 
  155. $cache_data = "<"."?php return $cache_data ?".">"; 
  156. file_put_contents(self::CACHE_FILE, $cache_data); 
  157.  
  158. /** 
  159. * Loads the stored font family cache 
  160. * @see save_font_families() 
  161. */ 
  162. static function load_font_families() { 
  163. $dist_fonts = require_once DOMPDF_DIR . "/lib/fonts/dompdf_font_family_cache.dist.php"; 
  164.  
  165. // FIXME: temporary step for font cache created before the font cache fix 
  166. if ( is_readable( DOMPDF_FONT_DIR . "dompdf_font_family_cache" ) ) { 
  167. $old_fonts = require_once DOMPDF_FONT_DIR . "dompdf_font_family_cache"; 
  168. // If the font family cache is still in the old format 
  169. if ( $old_fonts === 1 ) { 
  170. $cache_data = file_get_contents(DOMPDF_FONT_DIR . "dompdf_font_family_cache"); 
  171. file_put_contents(DOMPDF_FONT_DIR . "dompdf_font_family_cache", "<"."?php return $cache_data ?".">"); 
  172. $old_fonts = require_once DOMPDF_FONT_DIR . "dompdf_font_family_cache"; 
  173. $dist_fonts += $old_fonts; 
  174.  
  175. if ( !is_readable(self::CACHE_FILE) ) { 
  176. self::$_font_lookup = $dist_fonts; 
  177. return; 
  178.  
  179. self::$_font_lookup = require_once self::CACHE_FILE; 
  180.  
  181. // If the font family cache is still in the old format 
  182. if ( self::$_font_lookup === 1 ) { 
  183. $cache_data = file_get_contents(self::CACHE_FILE); 
  184. file_put_contents(self::CACHE_FILE, "<"."?php return $cache_data ?".">"); 
  185. self::$_font_lookup = require_once self::CACHE_FILE; 
  186.  
  187. // Merge provided fonts 
  188. self::$_font_lookup += $dist_fonts; 
  189.  
  190. static function get_type($type) { 
  191. if (preg_match("/bold/i", $type)) { 
  192. if (preg_match("/italic|oblique/i", $type)) { 
  193. $type = "bold_italic"; 
  194. else { 
  195. $type = "bold"; 
  196. elseif (preg_match("/italic|oblique/i", $type)) { 
  197. $type = "italic"; 
  198. else { 
  199. $type = "normal"; 
  200.  
  201. return $type; 
  202.  
  203. static function install_fonts($files) { 
  204. $names = array(); 
  205.  
  206. foreach($files as $file) { 
  207. $font = Font::load($file); 
  208. $records = $font->getData("name", "records"); 
  209. $type = self::get_type($records[2]); 
  210. $names[mb_strtolower($records[1])][$type] = $file; 
  211.  
  212. return $names; 
  213.  
  214. static function get_system_fonts() { 
  215. $files = glob("/usr/share/fonts/truetype/*.ttf") + 
  216. glob("/usr/share/fonts/truetype/*/*.ttf") + 
  217. glob("/usr/share/fonts/truetype/*/*/*.ttf") + 
  218. glob("C:\\Windows\\fonts\\*.ttf") +  
  219. glob("C:\\WinNT\\fonts\\*.ttf") +  
  220. glob("/mnt/c_drive/WINDOWS/Fonts/"); 
  221.  
  222. return self::install_fonts($files); 
  223.  
  224. /** 
  225. * Returns the current font lookup table 
  226. * @return array 
  227. */ 
  228. static function get_font_families() { 
  229. return self::$_font_lookup; 
  230.  
  231. static function set_font_family($fontname, $entry) { 
  232. self::$_font_lookup[mb_strtolower($fontname)] = $entry; 
  233.  
  234. static function register_font($style, $remote_file) { 
  235. $fontname = mb_strtolower($style["family"]); 
  236. $families = Font_Metrics::get_font_families(); 
  237.  
  238. $entry = array(); 
  239. if ( isset($families[$fontname]) ) { 
  240. $entry = $families[$fontname]; 
  241.  
  242. $local_file = DOMPDF_FONT_DIR . md5($remote_file); 
  243. $cache_entry = $local_file; 
  244. $local_file .= ".ttf"; 
  245.  
  246. $style_string = Font_Metrics::get_type("{$style['weight']} {$style['style']}"); 
  247.  
  248. if ( !isset($entry[$style_string]) ) { 
  249. $entry[$style_string] = $cache_entry; 
  250.  
  251. Font_Metrics::set_font_family($fontname, $entry); 
  252.  
  253. // Download the remote file 
  254. if ( !is_file($local_file) ) { 
  255. file_put_contents($local_file, file_get_contents($remote_file)); 
  256.  
  257. $font = Font::load($local_file); 
  258.  
  259. if (!$font) { 
  260. return false; 
  261.  
  262. $font->parse(); 
  263. $font->saveAdobeFontMetrics("$cache_entry.ufm"); 
  264.  
  265. // Save the changes 
  266. Font_Metrics::save_font_families(); 
  267.  
  268. return true;