/application/third_party/dompdf/lib/php-font-lib/src/FontLib/Table/Type/cmap.php

https://gitlab.com/Japang-Jawara/jawara-penilaian · PHP · 298 lines · 216 code · 66 blank · 16 comment · 26 complexity · cf5dc3c5f13d81e7dab01e0accd87c3c MD5 · raw file

  1. <?php
  2. /**
  3. * @package php-font-lib
  4. * @link https://github.com/PhenX/php-font-lib
  5. * @author Fabien Ménager <fabien.menager@gmail.com>
  6. * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  7. */
  8. namespace FontLib\Table\Type;
  9. use FontLib\Table\Table;
  10. /**
  11. * `cmap` font table.
  12. *
  13. * @package php-font-lib
  14. */
  15. class cmap extends Table {
  16. private static $header_format = array(
  17. "version" => self::uint16,
  18. "numberSubtables" => self::uint16,
  19. );
  20. private static $subtable_header_format = array(
  21. "platformID" => self::uint16,
  22. "platformSpecificID" => self::uint16,
  23. "offset" => self::uint32,
  24. );
  25. private static $subtable_v4_format = array(
  26. "length" => self::uint16,
  27. "language" => self::uint16,
  28. "segCountX2" => self::uint16,
  29. "searchRange" => self::uint16,
  30. "entrySelector" => self::uint16,
  31. "rangeShift" => self::uint16,
  32. );
  33. private static $subtable_v12_format = array(
  34. "length" => self::uint32,
  35. "language" => self::uint32,
  36. "ngroups" => self::uint32
  37. );
  38. protected function _parse() {
  39. $font = $this->getFont();
  40. $cmap_offset = $font->pos();
  41. $data = $font->unpack(self::$header_format);
  42. $subtables = array();
  43. for ($i = 0; $i < $data["numberSubtables"]; $i++) {
  44. $subtables[] = $font->unpack(self::$subtable_header_format);
  45. }
  46. $data["subtables"] = $subtables;
  47. foreach ($data["subtables"] as $i => &$subtable) {
  48. $font->seek($cmap_offset + $subtable["offset"]);
  49. $subtable["format"] = $font->readUInt16();
  50. // @todo Only CMAP version 4 and 12
  51. if (($subtable["format"] != 4) && ($subtable["format"] != 12)) {
  52. unset($data["subtables"][$i]);
  53. $data["numberSubtables"]--;
  54. continue;
  55. }
  56. if ($subtable["format"] == 12) {
  57. $font->readUInt16();
  58. $subtable += $font->unpack(self::$subtable_v12_format);
  59. $glyphIndexArray = array();
  60. $endCodes = array();
  61. $startCodes = array();
  62. for ($p = 0; $p < $subtable['ngroups']; $p++) {
  63. $startCode = $startCodes[] = $font->readUInt32();
  64. $endCode = $endCodes[] = $font->readUInt32();
  65. $startGlyphCode = $font->readUInt32();
  66. for ($c = $startCode; $c <= $endCode; $c++) {
  67. $glyphIndexArray[$c] = $startGlyphCode;
  68. $startGlyphCode++;
  69. }
  70. }
  71. $subtable += array(
  72. "startCode" => $startCodes,
  73. "endCode" => $endCodes,
  74. "glyphIndexArray" => $glyphIndexArray,
  75. );
  76. }
  77. else if ($subtable["format"] == 4) {
  78. $subtable += $font->unpack(self::$subtable_v4_format);
  79. $segCount = $subtable["segCountX2"] / 2;
  80. $subtable["segCount"] = $segCount;
  81. $endCode = $font->readUInt16Many($segCount);
  82. $font->readUInt16(); // reservedPad
  83. $startCode = $font->readUInt16Many($segCount);
  84. $idDelta = $font->readInt16Many($segCount);
  85. $ro_start = $font->pos();
  86. $idRangeOffset = $font->readUInt16Many($segCount);
  87. $glyphIndexArray = array();
  88. for ($i = 0; $i < $segCount; $i++) {
  89. $c1 = $startCode[$i];
  90. $c2 = $endCode[$i];
  91. $d = $idDelta[$i];
  92. $ro = $idRangeOffset[$i];
  93. if ($ro > 0) {
  94. $font->seek($subtable["offset"] + 2 * $i + $ro);
  95. }
  96. for ($c = $c1; $c <= $c2; $c++) {
  97. if ($ro == 0) {
  98. $gid = ($c + $d) & 0xFFFF;
  99. }
  100. else {
  101. $offset = ($c - $c1) * 2 + $ro;
  102. $offset = $ro_start + 2 * $i + $offset;
  103. $font->seek($offset);
  104. $gid = $font->readUInt16();
  105. if ($gid != 0) {
  106. $gid = ($gid + $d) & 0xFFFF;
  107. }
  108. }
  109. if ($gid > 0) {
  110. $glyphIndexArray[$c] = $gid;
  111. }
  112. }
  113. }
  114. $subtable += array(
  115. "endCode" => $endCode,
  116. "startCode" => $startCode,
  117. "idDelta" => $idDelta,
  118. "idRangeOffset" => $idRangeOffset,
  119. "glyphIndexArray" => $glyphIndexArray,
  120. );
  121. }
  122. }
  123. $this->data = $data;
  124. }
  125. function _encode() {
  126. $font = $this->getFont();
  127. $subset = $font->getSubset();
  128. $glyphIndexArray = $font->getUnicodeCharMap();
  129. $newGlyphIndexArray = array();
  130. foreach ($glyphIndexArray as $code => $gid) {
  131. $new_gid = array_search($gid, $subset);
  132. if ($new_gid !== false) {
  133. $newGlyphIndexArray[$code] = $new_gid;
  134. }
  135. }
  136. ksort($newGlyphIndexArray); // Sort by char code
  137. $segments = array();
  138. $i = -1;
  139. $prevCode = 0xFFFF;
  140. $prevGid = 0xFFFF;
  141. foreach ($newGlyphIndexArray as $code => $gid) {
  142. if (
  143. $prevCode + 1 != $code ||
  144. $prevGid + 1 != $gid
  145. ) {
  146. $i++;
  147. $segments[$i] = array();
  148. }
  149. $segments[$i][] = array($code, $gid);
  150. $prevCode = $code;
  151. $prevGid = $gid;
  152. }
  153. $segments[][] = array(0xFFFF, 0xFFFF);
  154. $startCode = array();
  155. $endCode = array();
  156. $idDelta = array();
  157. foreach ($segments as $codes) {
  158. $start = reset($codes);
  159. $end = end($codes);
  160. $startCode[] = $start[0];
  161. $endCode[] = $end[0];
  162. $idDelta[] = $start[1] - $start[0];
  163. }
  164. $segCount = count($startCode);
  165. $idRangeOffset = array_fill(0, $segCount, 0);
  166. $searchRange = 1;
  167. $entrySelector = 0;
  168. while ($searchRange * 2 <= $segCount) {
  169. $searchRange *= 2;
  170. $entrySelector++;
  171. }
  172. $searchRange *= 2;
  173. $rangeShift = $segCount * 2 - $searchRange;
  174. $subtables = array(
  175. array(
  176. // header
  177. "platformID" => 3, // Unicode
  178. "platformSpecificID" => 1,
  179. "offset" => null,
  180. // subtable
  181. "format" => 4,
  182. "length" => null,
  183. "language" => 0,
  184. "segCount" => $segCount,
  185. "segCountX2" => $segCount * 2,
  186. "searchRange" => $searchRange,
  187. "entrySelector" => $entrySelector,
  188. "rangeShift" => $rangeShift,
  189. "startCode" => $startCode,
  190. "endCode" => $endCode,
  191. "idDelta" => $idDelta,
  192. "idRangeOffset" => $idRangeOffset,
  193. "glyphIndexArray" => $newGlyphIndexArray,
  194. )
  195. );
  196. $data = array(
  197. "version" => 0,
  198. "numberSubtables" => count($subtables),
  199. "subtables" => $subtables,
  200. );
  201. $length = $font->pack(self::$header_format, $data);
  202. $subtable_headers_size = $data["numberSubtables"] * 8; // size of self::$subtable_header_format
  203. $subtable_headers_offset = $font->pos();
  204. $length += $font->write(str_repeat("\0", $subtable_headers_size), $subtable_headers_size);
  205. // write subtables data
  206. foreach ($data["subtables"] as $i => $subtable) {
  207. $length_before = $length;
  208. $data["subtables"][$i]["offset"] = $length;
  209. $length += $font->writeUInt16($subtable["format"]);
  210. $before_subheader = $font->pos();
  211. $length += $font->pack(self::$subtable_v4_format, $subtable);
  212. $segCount = $subtable["segCount"];
  213. $length += $font->w(array(self::uint16, $segCount), $subtable["endCode"]);
  214. $length += $font->writeUInt16(0); // reservedPad
  215. $length += $font->w(array(self::uint16, $segCount), $subtable["startCode"]);
  216. $length += $font->w(array(self::int16, $segCount), $subtable["idDelta"]);
  217. $length += $font->w(array(self::uint16, $segCount), $subtable["idRangeOffset"]);
  218. $length += $font->w(array(self::uint16, $segCount), array_values($subtable["glyphIndexArray"]));
  219. $after_subtable = $font->pos();
  220. $subtable["length"] = $length - $length_before;
  221. $font->seek($before_subheader);
  222. $length += $font->pack(self::$subtable_v4_format, $subtable);
  223. $font->seek($after_subtable);
  224. }
  225. // write subtables headers
  226. $font->seek($subtable_headers_offset);
  227. foreach ($data["subtables"] as $subtable) {
  228. $font->pack(self::$subtable_header_format, $subtable);
  229. }
  230. return $length;
  231. }
  232. }