Skip to content

Commit a77d882

Browse files
committed
Add support for format 12 cmap. Issue dompdf#40
1 parent e7df150 commit a77d882

File tree

3 files changed

+107
-40
lines changed

3 files changed

+107
-40
lines changed
5.88 KB
Binary file not shown.

src/FontLib/Table/Type/cmap.php

+80-40
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ class cmap extends Table {
3535
"rangeShift" => self::uint16,
3636
);
3737

38+
private static $subtable_v12_format = array(
39+
"length" => self::uint32,
40+
"language" => self::uint32,
41+
"ngroups" => self::uint32
42+
);
43+
3844
protected function _parse() {
3945
$font = $this->getFont();
4046

@@ -46,74 +52,108 @@ protected function _parse() {
4652
for ($i = 0; $i < $data["numberSubtables"]; $i++) {
4753
$subtables[] = $font->unpack(self::$subtable_header_format);
4854
}
55+
4956
$data["subtables"] = $subtables;
5057

5158
foreach ($data["subtables"] as $i => &$subtable) {
5259
$font->seek($cmap_offset + $subtable["offset"]);
5360

5461
$subtable["format"] = $font->readUInt16();
5562

56-
// @todo Only CMAP version 4
57-
if ($subtable["format"] != 4) {
63+
// @todo Only CMAP version 4 and 12
64+
if (($subtable["format"] != 4) && ($subtable["format"] != 12)) {
5865
unset($data["subtables"][$i]);
5966
$data["numberSubtables"]--;
6067
continue;
6168
}
6269

63-
$subtable += $font->unpack(self::$subtable_v4_format);
64-
$segCount = $subtable["segCountX2"] / 2;
65-
$subtable["segCount"] = $segCount;
70+
if ($subtable["format"] == 12) {
6671

67-
$endCode = $font->readUInt16Many($segCount);
72+
$font->readUInt16();
6873

69-
$font->readUInt16(); // reservedPad
74+
$subtable += $font->unpack(self::$subtable_v12_format);
7075

71-
$startCode = $font->readUInt16Many($segCount);
72-
$idDelta = $font->readInt16Many($segCount);
76+
$glyphIndexArray = array();
77+
$endCodes = array();
78+
$startCodes = array();
7379

74-
$ro_start = $font->pos();
75-
$idRangeOffset = $font->readUInt16Many($segCount);
80+
for ($p = 0; $p < $subtable['ngroups']; $p++) {
7681

77-
$glyphIndexArray = array();
78-
for ($i = 0; $i < $segCount; $i++) {
79-
$c1 = $startCode[$i];
80-
$c2 = $endCode[$i];
81-
$d = $idDelta[$i];
82-
$ro = $idRangeOffset[$i];
82+
$startCode = $startCodes[] = $font->readUInt32();
83+
$endCode = $endCodes[] = $font->readUInt32();
84+
$startGlyphCode = $font->readUInt32();
8385

84-
if ($ro > 0) {
85-
$font->seek($subtable["offset"] + 2 * $i + $ro);
86+
for ($c = $startCode; $c <= $endCode; $c++) {
87+
$glyphIndexArray[$c] = $startGlyphCode;
88+
$startGlyphCode++;
89+
}
8690
}
8791

88-
for ($c = $c1; $c <= $c2; $c++) {
89-
if ($ro == 0) {
90-
$gid = ($c + $d) & 0xFFFF;
92+
$subtable += array(
93+
"startCode" => $startCodes,
94+
"endCode" => $endCodes,
95+
"glyphIndexArray" => $glyphIndexArray,
96+
);
97+
98+
}
99+
else if ($subtable["format"] == 4) {
100+
101+
$subtable += $font->unpack(self::$subtable_v4_format);
102+
103+
$segCount = $subtable["segCountX2"] / 2;
104+
$subtable["segCount"] = $segCount;
105+
106+
$endCode = $font->readUInt16Many($segCount);
107+
108+
$font->readUInt16(); // reservedPad
109+
110+
$startCode = $font->readUInt16Many($segCount);
111+
$idDelta = $font->readInt16Many($segCount);
112+
113+
$ro_start = $font->pos();
114+
$idRangeOffset = $font->readUInt16Many($segCount);
115+
116+
$glyphIndexArray = array();
117+
for ($i = 0; $i < $segCount; $i++) {
118+
$c1 = $startCode[$i];
119+
$c2 = $endCode[$i];
120+
$d = $idDelta[$i];
121+
$ro = $idRangeOffset[$i];
122+
123+
if ($ro > 0) {
124+
$font->seek($subtable["offset"] + 2 * $i + $ro);
91125
}
92-
else {
93-
$offset = ($c - $c1) * 2 + $ro;
94-
$offset = $ro_start + 2 * $i + $offset;
95126

96-
$font->seek($offset);
97-
$gid = $font->readUInt16();
127+
for ($c = $c1; $c <= $c2; $c++) {
128+
if ($ro == 0) {
129+
$gid = ($c + $d) & 0xFFFF;
130+
}
131+
else {
132+
$offset = ($c - $c1) * 2 + $ro;
133+
$offset = $ro_start + 2 * $i + $offset;
134+
135+
$font->seek($offset);
136+
$gid = $font->readUInt16();
98137

99-
if ($gid != 0) {
100-
$gid = ($gid + $d) & 0xFFFF;
138+
if ($gid != 0) {
139+
$gid = ($gid + $d) & 0xFFFF;
140+
}
101141
}
102-
}
103142

104-
if ($gid > 0) {
105-
$glyphIndexArray[$c] = $gid;
143+
if ($gid > 0) {
144+
$glyphIndexArray[$c] = $gid;
145+
}
106146
}
107147
}
108-
}
109148

110-
$subtable += array(
111-
"endCode" => $endCode,
112-
"startCode" => $startCode,
113-
"idDelta" => $idDelta,
114-
"idRangeOffset" => $idRangeOffset,
115-
"glyphIndexArray" => $glyphIndexArray,
116-
);
149+
$subtable += array(
150+
"endCode" => $endCode,
151+
"startCode" => $startCode,
152+
"idDelta" => $idDelta,
153+
"idRangeOffset" => $idRangeOffset,
154+
"glyphIndexArray" => $glyphIndexArray,
155+
);
156+
}
117157
}
118158

119159
$this->data = $data;

tests/FontLib/FontTest.php

+27
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,32 @@ public function testLoadTTFFontSuccessfully()
1919
$trueTypeFont = Font::load('sample-fonts/IntelClear-Light.ttf');
2020

2121
$this->assertInstanceOf('FontLib\TrueType\File', $trueTypeFont);
22+
23+
$trueTypeFont->saveAdobeFontMetrics("IntelClear-Light.font.data");
2224
}
25+
26+
public function test12CmapFormat()
27+
{
28+
$trueTypeFont = Font::load('sample-fonts/NotoSansShavian-Regular.ttf');
29+
30+
$trueTypeFont->parse();
31+
32+
$cmapTable = $trueTypeFont->getData("cmap", "subtables");
33+
34+
$cmapFormat4Table = $cmapTable[0];
35+
36+
$this->assertEquals(4, $cmapFormat4Table['format']);
37+
$this->assertEquals(6, $cmapFormat4Table['segCount']);
38+
$this->assertEquals($cmapFormat4Table['segCount'], count($cmapFormat4Table['startCode']));
39+
$this->assertEquals($cmapFormat4Table['segCount'], count($cmapFormat4Table['endCode']));
40+
41+
$cmapFormat12Table = $cmapTable[1];
42+
43+
$this->assertEquals(12, $cmapFormat12Table['format']);
44+
$this->assertEquals(6, $cmapFormat12Table['ngroups']);
45+
$this->assertEquals(6, count($cmapFormat12Table['startCode']));
46+
$this->assertEquals(6, count($cmapFormat12Table['endCode']));
47+
$this->assertEquals(53, count($cmapFormat12Table['glyphIndexArray']));
48+
}
49+
2350
}

0 commit comments

Comments
 (0)