diff --git a/README.md b/README.md index 841dc1fc14850e68284e7d480c060a3c94b88d9a..a625b7d57a639d2b5996798e25ccfb932ed3e6f3 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,12 @@ 11. This project uses `/public` instead of `/www` for its DocumentRoot, you may have to go into your httpd.conf files and change this. Look in `/etc/httpd/conf.d/` for a number-prefixed conf file. 12. The server should now be running at `localhost:8009`. +** Testing ** +------------- +We are now striving for more unit testing. To run tests, please go to the +root folder and type +`phpunit --verbose --bootstrap config.inc.php tests` + ** Usage ** ----------- diff --git a/src/Controllers/LockupsController.php b/src/Controllers/LockupsController.php index a0b1a2379606db843e77d47de5ae2f6abb8f5f52..c76e92a4576f85bd5e7bc25ce7fffd1f0f3d74d2 100644 --- a/src/Controllers/LockupsController.php +++ b/src/Controllers/LockupsController.php @@ -8,10 +8,10 @@ use \SvgGenerator as SVG; class LockupsController extends Controller { - const LOCKUP_VERSION = '1.4'; + const LOCKUP_VERSION = '1.5'; private static function checkTextFieldLength($params, $field, $max_length) { - if (strlen($params[$field]) > $max_length) { + if (mb_strlen($params[$field]) > $max_length) { self::flashNotice(parent::NOTICE_LEVEL_ERROR, 'Invalid Text', ucwords(implode(' ',explode('_', $field))) . ' must be ' . $max_length . ' characters or fewer.'); return FALSE; } diff --git a/src/EasySVG.php b/src/EasySVG.php index a9a2c12acac8c638a0aa2be19eb73fd49302f492..0edd499b2a246df77cffb158661699a70bedcbc2 100644 --- a/src/EasySVG.php +++ b/src/EasySVG.php @@ -40,32 +40,81 @@ class EasySVG { * @param string $str * @return string */ - private function _utf8ToUnicode( $str ) { + private function _utf8ToUnicode($str) { $unicode = array(); $values = array(); $lookingFor = 1; - for ($i = 0; $i < strlen( $str ); $i++ ) { - $thisValue = ord( $str[ $i ] ); - if ( $thisValue < 128 ) $unicode[] = $thisValue; - else { - if ( count( $values ) == 0 ) $lookingFor = ( $thisValue < 224 ) ? 2 : 3; - $values[] = $thisValue; - if ( count( $values ) == $lookingFor ) { - $number = ( $lookingFor == 3 ) ? - ( ( $values[0] % 16 ) * 4096 ) + ( ( $values[1] % 64 ) * 64 ) + ( $values[2] % 64 ): - ( ( $values[0] % 32 ) * 64 ) + ( $values[1] % 64 ); - - $unicode[] = $number; - $values = array(); - $lookingFor = 1; + $ligature_table = array( + 'ff' => 64256, # = 0xFB00 + 'fi' => 64257, + 'fl' => 64258, + 'ffi' => 64259, + 'ffl' => 64260, + 'fb' => 64261, + 'fh' => 64262, + 'fj' => 64263, + 'fk' => 64264, + 'ffb' => 64265, + 'ffh' => 64266, + 'ffj' => 64267, + 'ffk' => 64268 + ); + + for ($i = 0; $i < mb_strlen($str); $i++ ) { + # check for ligatures here + # ------ THIS IS KIND OF A HACK ----- # + # see Unicode only supports ff, fi, fl, ffi, and ffl ligatures. However, certain unicode characters near these are unused. + # so I use these codes to correspond to other ligatures as given below. + # See https://en.wikipedia.org/wiki/Typographic_ligature#Ligatures_in_Unicode_.28Latin_alphabets.29 + # ---------------------------------------------------------------------------------------------------------------------- # + # | fb | ff | fh | fi | fj | fk | fl | ffb | ffh | ffi | ffj | ffk | ffl | # + # |--------------------------------------------------------------------------------------------------------------------| # + # | 0xFB05 | 0xFB00 | 0xFB06 | 0xFB01 | 0xFB07 | 0xFB08 | 0xFB02 | 0xFB09 | 0xFB0A | 0xFB03 | 0xFB0B | 0xFB0C | 0xFB04 | # + # |--------------------------------------------------------------------------------------------------------------------| # + + if (mb_substr($str, $i, 1) == 'f') { + if (mb_strlen($str) > $i+1 && in_array(mb_substr($str, $i+1, 1), array('b','h','i','j','k','l'))) { + $unicode[] = $ligature_table[mb_substr($str, $i, 2)]; + $i++; + continue; + } else if (mb_strlen($str) > $i+1 && mb_substr($str, $i+1, 1) == 'f') { + if (mb_strlen($str) > $i+2 && in_array(mb_substr($str, $i+2, 1), array('b','h','i','j','k','l'))) { + $unicode[] = $ligature_table[mb_substr($str, $i, 3)]; + $i += 2; + continue; + } else { + $unicode[] = $ligature_table['ff']; + $i++; + continue; + } } } + + $unicode[] = $this->_unicodeOrd(mb_substr($str, $i, 1)); } return $unicode; } + private function _unicodeOrd($c) { + if (ord($c[0]) >=0 && ord($c[0]) <= 127) + return ord($c[0]); + if (ord($c[0]) >= 192 && ord($c[0]) <= 223) + return (ord($c[0])-192)*64 + (ord($c[1])-128); + if (ord($c[0]) >= 224 && ord($c[0]) <= 239) + return (ord($c[0])-224)*4096 + (ord($c[1])-128)*64 + (ord($c[2])-128); + if (ord($c[0]) >= 240 && ord($c[0]) <= 247) + return (ord($c[0])-240)*262144 + (ord($c[1])-128)*4096 + (ord($c[2])-128)*64 + (ord($c[3])-128); + if (ord($c[0]) >= 248 && ord($c[0]) <= 251) + return (ord($c[0])-248)*16777216 + (ord($c[1])-128)*262144 + (ord($c[2])-128)*4096 + (ord($c[3])-128)*64 + (ord($c[4])-128); + if (ord($c[0]) >= 252 && ord($c[0]) <= 253) + return (ord($c[0])-252)*1073741824 + (ord($c[1])-128)*16777216 + (ord($c[2])-128)*262144 + (ord($c[3])-128)*4096 + (ord($c[4])-128)*64 + (ord($c[5])-128); + if (ord($c[0]) >= 254 && ord($c[0]) <= 255) // error + return FALSE; + return 0; + } + /** * Set font params (short-hand method) * @param string $filepath @@ -144,6 +193,7 @@ class EasySVG { if ($name == 'glyph') { $unicode = $z->getAttribute('unicode'); + $unicode = html_entity_decode($unicode); $unicode = $this->_utf8ToUnicode($unicode); if (count($unicode) > 0) { $unicode = $unicode[0]; @@ -212,8 +262,9 @@ class EasySVG { $horizAdvX = 0; $horizAdvY = $this->font->ascent + $this->font->descent; $fontSize = floatval($this->font->size) / $this->font->unitsPerEm; + $text = $this->_utf8ToUnicode($text); - error_log(print_r($text,1)); + error_log(print_r($text, 1)); for($i = 0; $i < count($text); $i++) { @@ -227,8 +278,13 @@ class EasySVG { } // extract character definition - $d = $this->font->glyphs[$letter]->d; + if (isset($this->font->glyphs[$letter])) { + $letter = $this->font->glyphs[$letter]; + } else { + $letter = $this->font->glyphs[32]; + } + $d = $letter->d; // transform typo from original SVG format to straight display $d = $this->defScale($d, $fontSize, -$fontSize); $d = $this->defTranslate($d, $horizAdvX, $horizAdvY*$fontSize*2); @@ -236,7 +292,7 @@ class EasySVG { $def[] = $d; // next letter's position - $horizAdvX += $this->font->glyphs[$letter]->horizAdvX * $fontSize + $this->font->em * $this->font->letterSpacing * $fontSize; + $horizAdvX += $letter->horizAdvX * $fontSize + $this->font->em * $this->font->letterSpacing * $fontSize; } return implode(' ', $def); } @@ -271,7 +327,14 @@ class EasySVG { continue; } - $lineWidth += $this->font->glyphs[$letter]->horizAdvX * $fontSize + $this->font->em * $this->font->letterSpacing * $fontSize; + // extract character definition + if (isset($this->font->glyphs[$letter])) { + $letter = $this->font->glyphs[$letter]; + } else { + $letter = $this->font->glyphs[32]; + } + + $lineWidth += $letter->horizAdvX * $fontSize + $this->font->em * $this->font->letterSpacing * $fontSize; } // only keep the widest line's width diff --git a/tests/EasySVGUTF8ToUnicodeTest.php b/tests/EasySVGUTF8ToUnicodeTest.php new file mode 100644 index 0000000000000000000000000000000000000000..362211c81a4d3c03f9f9ef14c4883364b6da5921 --- /dev/null +++ b/tests/EasySVGUTF8ToUnicodeTest.php @@ -0,0 +1,52 @@ +<?php + +class EasySVGUTF8ToUnicodeTest extends \PHPUnit_Framework_TestCase { + protected $svg; + protected $reflection; + + protected function setUp() { + $this->svg = new EasySVG; + $this->reflection = new \ReflectionClass(get_class($this->svg)); + } + + protected function runUTF8Method($string) { + $method = $this->reflection->getMethod('_utf8ToUnicode'); + $method->setAccessible(true); + return $method->invokeArgs($this->svg, array($string)); + } + + public function testStandardCharacters() { + $result = $this->runUTF8Method('omg lol'); + $this->assertEquals(array( + 111,109,103,32,108,111,108 + ), $result); + } + + public function testStrangeASCII() { + $result = $this->runUTF8Method('ümlaut eñye'); + $this->assertEquals(array( + 252,109,108,97,117,116,32,101,241,121,101 + ), $result); + } + + public function testLigatures() { + $result = $this->runUTF8Method('ff fb fj fi fj fk fl ffb ffj ffi ffj ffk ffl fff'); + $this->assertEquals(array( + 64256,32, + 64261,32, + 64263,32, + 64257,32, + 64263,32, + 64264,32, + 64258,32, + 64265,32, + 64267,32, + 64259,32, + 64267,32, + 64268,32, + 64260,32, + 64256,102 + ), $result); + } +} +