Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
SegmentToDelta.php
Go to the documentation of this file.
1 <?php
24 #require_once 'Zend/Pdf/Cmap.php';
25 
26 
40 {
41  /**** Instance Variables ****/
42 
43 
48  protected $_segmentCount = 0;
49 
54  protected $_searchRange = 0;
55 
61  protected $_searchIterations = 0;
62 
67  protected $_segmentTableEndCodes = array();
68 
74  protected $_searchRangeEndCode = 0;
75 
80  protected $_segmentTableStartCodes = array();
81 
86  protected $_segmentTableIdDeltas = array();
87 
92  protected $_segmentTableIdRangeOffsets = array();
93 
98  protected $_glyphIndexArray = array();
99 
100 
101 
102  /**** Public Interface ****/
103 
104 
105  /* Concrete Class Implementation */
106 
118  public function glyphNumbersForCharacters($characterCodes)
119  {
120  $glyphNumbers = array();
121  foreach ($characterCodes as $key => $characterCode) {
122 
123  /* These tables only cover the 16-bit character range.
124  */
125  if ($characterCode > 0xffff) {
126  $glyphNumbers[$key] = Zend_Pdf_Cmap::MISSING_CHARACTER_GLYPH;
127  continue;
128  }
129 
130  /* Determine where to start the binary search. The segments are
131  * ordered from lowest-to-highest. We are looking for the first
132  * segment whose end code is greater than or equal to our character
133  * code.
134  *
135  * If the end code at the top of the search range is larger, then
136  * our target is probably below it.
137  *
138  * If it is smaller, our target is probably above it, so move the
139  * search range to the end of the segment list.
140  */
141  if ($this->_searchRangeEndCode >= $characterCode) {
142  $searchIndex = $this->_searchRange;
143  } else {
144  $searchIndex = $this->_segmentCount;
145  }
146 
147  /* Now do a binary search to find the first segment whose end code
148  * is greater or equal to our character code. No matter the number
149  * of segments (there may be hundreds in a large font), we will only
150  * need to perform $this->_searchIterations.
151  */
152  for ($i = 1; $i <= $this->_searchIterations; $i++) {
153  if ($this->_segmentTableEndCodes[$searchIndex] >= $characterCode) {
154  $subtableIndex = $searchIndex;
155  $searchIndex -= $this->_searchRange >> $i;
156  } else {
157  $searchIndex += $this->_searchRange >> $i;
158  }
159  }
160 
161  /* If the segment's start code is greater than our character code,
162  * that character is not represented in this font. Move on.
163  */
164  if ($this->_segmentTableStartCodes[$subtableIndex] > $characterCode) {
165  $glyphNumbers[$key] = Zend_Pdf_Cmap::MISSING_CHARACTER_GLYPH;
166  continue;
167  }
168 
169  if ($this->_segmentTableIdRangeOffsets[$subtableIndex] == 0) {
170  /* This segment uses a simple mapping from character code to
171  * glyph number.
172  */
173  $glyphNumbers[$key] = ($characterCode + $this->_segmentTableIdDeltas[$subtableIndex]) % 65536;
174 
175  } else {
176  /* This segment relies on the glyph index array to determine the
177  * glyph number. The calculation below determines the correct
178  * index into that array. It's a little odd because the range
179  * offset in the font file is designed to quickly provide an
180  * address of the index in the raw binary data instead of the
181  * index itself. Since we've parsed the data into arrays, we
182  * must process it a bit differently.
183  */
184  $glyphIndex = ($characterCode - $this->_segmentTableStartCodes[$subtableIndex] +
185  $this->_segmentTableIdRangeOffsets[$subtableIndex] - $this->_segmentCount +
186  $subtableIndex - 1);
187  $glyphNumbers[$key] = $this->_glyphIndexArray[$glyphIndex];
188 
189  }
190 
191  }
192  return $glyphNumbers;
193  }
194 
207  public function glyphNumberForCharacter($characterCode)
208  {
209  /* This code is pretty much a copy of glyphNumbersForCharacters().
210  * See that method for inline documentation.
211  */
212 
213  if ($characterCode > 0xffff) {
215  }
216 
217  if ($this->_searchRangeEndCode >= $characterCode) {
218  $searchIndex = $this->_searchRange;
219  } else {
220  $searchIndex = $this->_segmentCount;
221  }
222 
223  for ($i = 1; $i <= $this->_searchIterations; $i++) {
224  if ($this->_segmentTableEndCodes[$searchIndex] >= $characterCode) {
225  $subtableIndex = $searchIndex;
226  $searchIndex -= $this->_searchRange >> $i;
227  } else {
228  $searchIndex += $this->_searchRange >> $i;
229  }
230  }
231 
232  if ($this->_segmentTableStartCodes[$subtableIndex] > $characterCode) {
234  }
235 
236  if ($this->_segmentTableIdRangeOffsets[$subtableIndex] == 0) {
237  $glyphNumber = ($characterCode + $this->_segmentTableIdDeltas[$subtableIndex]) % 65536;
238  } else {
239  $glyphIndex = ($characterCode - $this->_segmentTableStartCodes[$subtableIndex] +
240  $this->_segmentTableIdRangeOffsets[$subtableIndex] - $this->_segmentCount +
241  $subtableIndex - 1);
242  $glyphNumber = $this->_glyphIndexArray[$glyphIndex];
243  }
244  return $glyphNumber;
245  }
246 
253  public function getCoveredCharacters()
254  {
255  $characterCodes = array();
256  for ($i = 1; $i <= $this->_segmentCount; $i++) {
257  for ($code = $this->_segmentTableStartCodes[$i]; $code <= $this->_segmentTableEndCodes[$i]; $code++) {
258  $characterCodes[] = $code;
259  }
260  }
261  return $characterCodes;
262  }
263 
264 
276  public function getCoveredCharactersGlyphs()
277  {
278  $glyphNumbers = array();
279 
280  for ($segmentNum = 1; $segmentNum <= $this->_segmentCount; $segmentNum++) {
281  if ($this->_segmentTableIdRangeOffsets[$segmentNum] == 0) {
282  $delta = $this->_segmentTableIdDeltas[$segmentNum];
283 
284  for ($code = $this->_segmentTableStartCodes[$segmentNum];
285  $code <= $this->_segmentTableEndCodes[$segmentNum];
286  $code++) {
287  $glyphNumbers[$code] = ($code + $delta) % 65536;
288  }
289  } else {
290  $code = $this->_segmentTableStartCodes[$segmentNum];
291  $glyphIndex = $this->_segmentTableIdRangeOffsets[$segmentNum] - ($this->_segmentCount - $segmentNum) - 1;
292 
293  while ($code <= $this->_segmentTableEndCodes[$segmentNum]) {
294  $glyphNumbers[$code] = $this->_glyphIndexArray[$glyphIndex];
295 
296  $code++;
297  $glyphIndex++;
298  }
299  }
300  }
301 
302  return $glyphNumbers;
303  }
304 
305 
306 
307  /* Object Lifecycle */
308 
318  public function __construct($cmapData)
319  {
320  /* Sanity check: The table should be at least 23 bytes in size.
321  */
322  $actualLength = strlen($cmapData);
323  if ($actualLength < 23) {
324  #require_once 'Zend/Pdf/Exception.php';
325  throw new Zend_Pdf_Exception('Insufficient table data',
327  }
328 
329  /* Sanity check: Make sure this is right data for this table type.
330  */
331  $type = $this->_extractUInt2($cmapData, 0);
333  #require_once 'Zend/Pdf/Exception.php';
334  throw new Zend_Pdf_Exception('Wrong cmap table type',
336  }
337 
338  $length = $this->_extractUInt2($cmapData, 2);
339  if ($length != $actualLength) {
340  #require_once 'Zend/Pdf/Exception.php';
341  throw new Zend_Pdf_Exception("Table length ($length) does not match actual length ($actualLength)",
343  }
344 
345  /* Mapping tables should be language-independent. The font may not work
346  * as expected if they are not. Unfortunately, many font files in the
347  * wild incorrectly record a language ID in this field, so we can't
348  * call this a failure.
349  */
350  $language = $this->_extractUInt2($cmapData, 4);
351  if ($language != 0) {
352  // Record a warning here somehow?
353  }
354 
355  /* These two values are stored premultiplied by two which is convienent
356  * when using the binary data directly, but we're parsing it out to
357  * native PHP data types, so divide by two.
358  */
359  $this->_segmentCount = $this->_extractUInt2($cmapData, 6) >> 1;
360  $this->_searchRange = $this->_extractUInt2($cmapData, 8) >> 1;
361 
362  $this->_searchIterations = $this->_extractUInt2($cmapData, 10) + 1;
363 
364  $offset = 14;
365  for ($i = 1; $i <= $this->_segmentCount; $i++, $offset += 2) {
366  $this->_segmentTableEndCodes[$i] = $this->_extractUInt2($cmapData, $offset);
367  }
368 
369  $this->_searchRangeEndCode = $this->_segmentTableEndCodes[$this->_searchRange];
370 
371  $offset += 2; // reserved bytes
372 
373  for ($i = 1; $i <= $this->_segmentCount; $i++, $offset += 2) {
374  $this->_segmentTableStartCodes[$i] = $this->_extractUInt2($cmapData, $offset);
375  }
376 
377  for ($i = 1; $i <= $this->_segmentCount; $i++, $offset += 2) {
378  $this->_segmentTableIdDeltas[$i] = $this->_extractInt2($cmapData, $offset); // signed
379  }
380 
381  /* The range offset helps determine the index into the glyph index array.
382  * Like the segment count and search range above, it's stored as a byte
383  * multiple in the font, so divide by two as we extract the values.
384  */
385  for ($i = 1; $i <= $this->_segmentCount; $i++, $offset += 2) {
386  $this->_segmentTableIdRangeOffsets[$i] = $this->_extractUInt2($cmapData, $offset) >> 1;
387  }
388 
389  /* The size of the glyph index array varies by font and depends on the
390  * extent of the usage of range offsets versus deltas. Some fonts may
391  * not have any entries in this array.
392  */
393  for (; $offset < $length; $offset += 2) {
394  $this->_glyphIndexArray[] = $this->_extractUInt2($cmapData, $offset);
395  }
396 
397  /* Sanity check: After reading all of the data, we should be at the end
398  * of the table.
399  */
400  if ($offset != $length) {
401  #require_once 'Zend/Pdf/Exception.php';
402  throw new Zend_Pdf_Exception("Ending offset ($offset) does not match length ($length)",
404  }
405  }
406 
407 }
glyphNumberForCharacter($characterCode)
const CMAP_WRONG_TABLE_LENGTH
Definition: Exception.php:275
const CMAP_FINAL_OFFSET_NOT_LENGTH
Definition: Exception.php:287
const CMAP_TABLE_DATA_TOO_SMALL
Definition: Exception.php:265
glyphNumbersForCharacters($characterCodes)
$type
Definition: item.phtml:13
_extractInt2(&$data, $index)
Definition: Cmap.php:270
const TYPE_SEGMENT_TO_DELTA
Definition: Cmap.php:73
const CMAP_WRONG_TABLE_TYPE
Definition: Exception.php:270
const MISSING_CHARACTER_GLYPH
Definition: Cmap.php:112
_extractUInt2(&$data, $index)
Definition: Cmap.php:297
$i
Definition: gallery.phtml:31
$code
Definition: info.phtml:12