diff options
Diffstat (limited to 'app/Functions/FunctionsRtl.php')
| -rw-r--r-- | app/Functions/FunctionsRtl.php | 2152 |
1 files changed, 1108 insertions, 1044 deletions
diff --git a/app/Functions/FunctionsRtl.php b/app/Functions/FunctionsRtl.php index 65c91b7085..bee0e3ffbe 100644 --- a/app/Functions/FunctionsRtl.php +++ b/app/Functions/FunctionsRtl.php @@ -20,1144 +20,1208 @@ use Fisharebest\Webtrees\I18N; /** * RTL Functions for use in the PDF/HTML reports */ -class FunctionsRtl { - const UTF8_LRM = "\xE2\x80\x8E"; // U+200E (Left to Right mark: zero-width character with LTR directionality) - const UTF8_RLM = "\xE2\x80\x8F"; // U+200F (Right to Left mark: zero-width character with RTL directionality) - const UTF8_LRO = "\xE2\x80\xAD"; // U+202D (Left to Right override: force everything following to LTR mode) - const UTF8_RLO = "\xE2\x80\xAE"; // U+202E (Right to Left override: force everything following to RTL mode) - const UTF8_LRE = "\xE2\x80\xAA"; // U+202A (Left to Right embedding: treat everything following as LTR text) - const UTF8_RLE = "\xE2\x80\xAB"; // U+202B (Right to Left embedding: treat everything following as RTL text) - const UTF8_PDF = "\xE2\x80\xAC"; // U+202C (Pop directional formatting: restore state prior to last LRO, RLO, LRE, RLE) +class FunctionsRtl +{ + const UTF8_LRM = "\xE2\x80\x8E"; // U+200E (Left to Right mark: zero-width character with LTR directionality) + const UTF8_RLM = "\xE2\x80\x8F"; // U+200F (Right to Left mark: zero-width character with RTL directionality) + const UTF8_LRO = "\xE2\x80\xAD"; // U+202D (Left to Right override: force everything following to LTR mode) + const UTF8_RLO = "\xE2\x80\xAE"; // U+202E (Right to Left override: force everything following to RTL mode) + const UTF8_LRE = "\xE2\x80\xAA"; // U+202A (Left to Right embedding: treat everything following as LTR text) + const UTF8_RLE = "\xE2\x80\xAB"; // U+202B (Right to Left embedding: treat everything following as RTL text) + const UTF8_PDF = "\xE2\x80\xAC"; // U+202C (Pop directional formatting: restore state prior to last LRO, RLO, LRE, RLE) - const OPEN_PARENTHESES = '([{'; + const OPEN_PARENTHESES = '([{'; - const CLOSE_PARENTHESES = ')]}'; + const CLOSE_PARENTHESES = ')]}'; - const NUMBERS = '0123456789'; + const NUMBERS = '0123456789'; - const NUMBER_PREFIX = '+-'; // Treat these like numbers when at beginning or end of numeric strings + const NUMBER_PREFIX = '+-'; // Treat these like numbers when at beginning or end of numeric strings - const NUMBER_PUNCTUATION = '- ,.:/'; // Treat these like numbers when inside numeric strings + const NUMBER_PUNCTUATION = '- ,.:/'; // Treat these like numbers when inside numeric strings - const PUNCTUATION = ',.:;?!'; + const PUNCTUATION = ',.:;?!'; - /** @var string Were we previously processing LTR or RTL. */ - private static $previousState; + /** @var string Were we previously processing LTR or RTL. */ + private static $previousState; - /** @var string Are we currently processing LTR or RTL. */ - private static $currentState; + /** @var string Are we currently processing LTR or RTL. */ + private static $currentState; - /** @var string Text waiting to be processed. */ - private static $waitingText; + /** @var string Text waiting to be processed. */ + private static $waitingText; - /** @var string LTR text. */ - private static $startLTR; + /** @var string LTR text. */ + private static $startLTR; - /** @var string LTR text. */ - private static $endLTR; + /** @var string LTR text. */ + private static $endLTR; - /** @var string RTL text. */ - private static $startRTL; + /** @var string RTL text. */ + private static $startRTL; - /** @var string RTL text. */ - private static $endRTL; + /** @var string RTL text. */ + private static $endRTL; - /** @var int Offset into the text. */ - private static $lenStart; + /** @var int Offset into the text. */ + private static $lenStart; - /** @var int Offset into the text. */ - private static $lenEnd; + /** @var int Offset into the text. */ + private static $lenEnd; - /** @var int Offset into the text. */ - private static $posSpanStart; + /** @var int Offset into the text. */ + private static $posSpanStart; - /** - * This function strips ‎ and ‏ from the input string. It should be used for all - * text that has been passed through the PrintReady() function before that text is stored - * in the database. The database should NEVER contain these characters. - * - * @param string $inputText The string from which the ‎ and ‏ characters should be stripped - * - * @return string The input string, with ‎ and ‏ stripped - */ - public static function stripLrmRlm($inputText) { - return str_replace([self::UTF8_LRM, self::UTF8_RLM, self::UTF8_LRO, self::UTF8_RLO, self::UTF8_LRE, self::UTF8_RLE, self::UTF8_PDF, '‎', '‏', '&LRM;', '&RLM;'], '', $inputText); - } + /** + * This function strips ‎ and ‏ from the input string. It should be used for all + * text that has been passed through the PrintReady() function before that text is stored + * in the database. The database should NEVER contain these characters. + * + * @param string $inputText The string from which the ‎ and ‏ characters should be stripped + * + * @return string The input string, with ‎ and ‏ stripped + */ + public static function stripLrmRlm($inputText) + { + return str_replace([ + self::UTF8_LRM, + self::UTF8_RLM, + self::UTF8_LRO, + self::UTF8_RLO, + self::UTF8_LRE, + self::UTF8_RLE, + self::UTF8_PDF, + '‎', + '‏', + '&LRM;', + '&RLM;', + ], '', $inputText); + } - /** - * This function encapsulates all texts in the input with <span dir='xxx'> and </span> - * according to the directionality specified. - * - * @param string $inputText Raw input - * @param string $direction Directionality (LTR, BOTH, RTL) default BOTH - * @param string $class Additional text to insert into output <span dir="xxx"> (such as 'class="yyy"') - * - * @return string The string with all texts encapsulated as required - */ - public static function spanLtrRtl($inputText, $direction = 'BOTH', $class = '') { - if ($inputText == '') { - // Nothing to do - return ''; - } + /** + * This function encapsulates all texts in the input with <span dir='xxx'> and </span> + * according to the directionality specified. + * + * @param string $inputText Raw input + * @param string $direction Directionality (LTR, BOTH, RTL) default BOTH + * @param string $class Additional text to insert into output <span dir="xxx"> (such as 'class="yyy"') + * + * @return string The string with all texts encapsulated as required + */ + public static function spanLtrRtl($inputText, $direction = 'BOTH', $class = '') + { + if ($inputText == '') { + // Nothing to do + return ''; + } - $workingText = str_replace("\n", '<br>', $inputText); - $workingText = str_replace(['<span class="starredname"><br>', '<span<br>class="starredname">'], '<br><span class="starredname">', $workingText); // Reposition some incorrectly placed line breaks - $workingText = self::stripLrmRlm($workingText); // Get rid of any existing UTF8 control codes + $workingText = str_replace("\n", '<br>', $inputText); + $workingText = str_replace([ + '<span class="starredname"><br>', + '<span<br>class="starredname">', + ], '<br><span class="starredname">', $workingText); // Reposition some incorrectly placed line breaks + $workingText = self::stripLrmRlm($workingText); // Get rid of any existing UTF8 control codes - // $nothing = '‌'; // Zero Width Non-Joiner (not sure whether this is still needed to work around a TCPDF bug) - $nothing = ''; + // $nothing = '‌'; // Zero Width Non-Joiner (not sure whether this is still needed to work around a TCPDF bug) + $nothing = ''; - self::$startLTR = '<LTR>'; // This will become '<span dir="ltr">' at the end - self::$endLTR = '</LTR>'; // This will become '</span>' at the end - self::$startRTL = '<RTL>'; // This will become '<span dir="rtl">' at the end - self::$endRTL = '</RTL>'; // This will become '</span>' at the end - self::$lenStart = strlen(self::$startLTR); // RTL version MUST have same length - self::$lenEnd = strlen(self::$endLTR); // RTL version MUST have same length + self::$startLTR = '<LTR>'; // This will become '<span dir="ltr">' at the end + self::$endLTR = '</LTR>'; // This will become '</span>' at the end + self::$startRTL = '<RTL>'; // This will become '<span dir="rtl">' at the end + self::$endRTL = '</RTL>'; // This will become '</span>' at the end + self::$lenStart = strlen(self::$startLTR); // RTL version MUST have same length + self::$lenEnd = strlen(self::$endLTR); // RTL version MUST have same length - self::$previousState = ''; - self::$currentState = strtoupper(I18N::direction()); - $numberState = false; // Set when we're inside a numeric string - $result = ''; - self::$waitingText = ''; - $openParDirection = []; + self::$previousState = ''; + self::$currentState = strtoupper(I18N::direction()); + $numberState = false; // Set when we're inside a numeric string + $result = ''; + self::$waitingText = ''; + $openParDirection = []; - self::beginCurrentSpan($result); + self::beginCurrentSpan($result); - while ($workingText != '') { - $charArray = self::getChar($workingText, 0); // Get the next ASCII or UTF-8 character - $currentLetter = $charArray['letter']; - $currentLen = $charArray['length']; + while ($workingText != '') { + $charArray = self::getChar($workingText, 0); // Get the next ASCII or UTF-8 character + $currentLetter = $charArray['letter']; + $currentLen = $charArray['length']; - $openParIndex = strpos(self::OPEN_PARENTHESES, $currentLetter); // Which opening parenthesis is this? - $closeParIndex = strpos(self::CLOSE_PARENTHESES, $currentLetter); // Which closing parenthesis is this? + $openParIndex = strpos(self::OPEN_PARENTHESES, $currentLetter); // Which opening parenthesis is this? + $closeParIndex = strpos(self::CLOSE_PARENTHESES, $currentLetter); // Which closing parenthesis is this? - switch ($currentLetter) { - case '<': - // Assume this '<' starts an HTML element - $endPos = strpos($workingText, '>'); // look for the terminating '>' - if ($endPos === false) { - $endPos = 0; - } - $currentLen += $endPos; - $element = substr($workingText, 0, $currentLen); - $temp = strtolower(substr($element, 0, 3)); - if (strlen($element) < 7 && $temp == '<br') { - if ($numberState) { - $numberState = false; - if (self::$currentState == 'RTL') { - self::$waitingText .= self::UTF8_PDF; - } - } - self::breakCurrentSpan($result); - } elseif (self::$waitingText == '') { - $result .= $element; - } else { - self::$waitingText .= $element; - } - $workingText = substr($workingText, $currentLen); - break; - case '&': - // Assume this '&' starts an HTML entity - $endPos = strpos($workingText, ';'); // look for the terminating ';' - if ($endPos === false) { - $endPos = 0; - } - $currentLen += $endPos; - $entity = substr($workingText, 0, $currentLen); - if (strtolower($entity) == ' ') { - $entity .= ' '; // Ensure consistent case for this entity - } - if (self::$waitingText == '') { - $result .= $entity; - } else { - self::$waitingText .= $entity; - } - $workingText = substr($workingText, $currentLen); - break; - case '{': - if (substr($workingText, 1, 1) == '{') { - // Assume this '{{' starts a TCPDF directive - $endPos = strpos($workingText, '}}'); // look for the terminating '}}' - if ($endPos === false) { - $endPos = 0; - } - $currentLen = $endPos + 2; - $directive = substr($workingText, 0, $currentLen); - $workingText = substr($workingText, $currentLen); - $result = $result . self::$waitingText . $directive; - self::$waitingText = ''; - break; - } - default: - // Look for strings of numbers with optional leading or trailing + or - - // and with optional embedded numeric punctuation - if ($numberState) { - // If we're inside a numeric string, look for reasons to end it - $offset = 0; // Be sure to look at the current character first - $charArray = self::getChar($workingText . "\n", $offset); - if (strpos(self::NUMBERS, $charArray['letter']) === false) { - // This is not a digit. Is it numeric punctuation? - if (substr($workingText . "\n", $offset, 6) == ' ') { - $offset += 6; // This could be numeric punctuation - } elseif (strpos(self::NUMBER_PUNCTUATION, $charArray['letter']) !== false) { - $offset += $charArray['length']; // This could be numeric punctuation - } - // If the next character is a digit, the current character is numeric punctuation - $charArray = self::getChar($workingText . "\n", $offset); - if (strpos(self::NUMBERS, $charArray['letter']) === false) { - // This is not a digit. End the run of digits and punctuation. - $numberState = false; - if (self::$currentState == 'RTL') { - if (strpos(self::NUMBER_PREFIX, $currentLetter) === false) { - $currentLetter = self::UTF8_PDF . $currentLetter; - } else { - $currentLetter = $currentLetter . self::UTF8_PDF; // Include a trailing + or - in the run - } - } - } - } - } else { - // If we're outside a numeric string, look for reasons to start it - if (strpos(self::NUMBER_PREFIX, $currentLetter) !== false) { - // This might be a number lead-in - $offset = $currentLen; - $nextChar = substr($workingText . "\n", $offset, 1); - if (strpos(self::NUMBERS, $nextChar) !== false) { - $numberState = true; // We found a digit: the lead-in is therefore numeric - if (self::$currentState == 'RTL') { - $currentLetter = self::UTF8_LRE . $currentLetter; - } - } - } elseif (strpos(self::NUMBERS, $currentLetter) !== false) { - $numberState = true; // The current letter is a digit - if (self::$currentState == 'RTL') { - $currentLetter = self::UTF8_LRE . $currentLetter; - } - } - } + switch ($currentLetter) { + case '<': + // Assume this '<' starts an HTML element + $endPos = strpos($workingText, '>'); // look for the terminating '>' + if ($endPos === false) { + $endPos = 0; + } + $currentLen += $endPos; + $element = substr($workingText, 0, $currentLen); + $temp = strtolower(substr($element, 0, 3)); + if (strlen($element) < 7 && $temp == '<br') { + if ($numberState) { + $numberState = false; + if (self::$currentState == 'RTL') { + self::$waitingText .= self::UTF8_PDF; + } + } + self::breakCurrentSpan($result); + } elseif (self::$waitingText == '') { + $result .= $element; + } else { + self::$waitingText .= $element; + } + $workingText = substr($workingText, $currentLen); + break; + case '&': + // Assume this '&' starts an HTML entity + $endPos = strpos($workingText, ';'); // look for the terminating ';' + if ($endPos === false) { + $endPos = 0; + } + $currentLen += $endPos; + $entity = substr($workingText, 0, $currentLen); + if (strtolower($entity) == ' ') { + $entity .= ' '; // Ensure consistent case for this entity + } + if (self::$waitingText == '') { + $result .= $entity; + } else { + self::$waitingText .= $entity; + } + $workingText = substr($workingText, $currentLen); + break; + case '{': + if (substr($workingText, 1, 1) == '{') { + // Assume this '{{' starts a TCPDF directive + $endPos = strpos($workingText, '}}'); // look for the terminating '}}' + if ($endPos === false) { + $endPos = 0; + } + $currentLen = $endPos + 2; + $directive = substr($workingText, 0, $currentLen); + $workingText = substr($workingText, $currentLen); + $result = $result . self::$waitingText . $directive; + self::$waitingText = ''; + break; + } + default: + // Look for strings of numbers with optional leading or trailing + or - + // and with optional embedded numeric punctuation + if ($numberState) { + // If we're inside a numeric string, look for reasons to end it + $offset = 0; // Be sure to look at the current character first + $charArray = self::getChar($workingText . "\n", $offset); + if (strpos(self::NUMBERS, $charArray['letter']) === false) { + // This is not a digit. Is it numeric punctuation? + if (substr($workingText . "\n", $offset, 6) == ' ') { + $offset += 6; // This could be numeric punctuation + } elseif (strpos(self::NUMBER_PUNCTUATION, $charArray['letter']) !== false) { + $offset += $charArray['length']; // This could be numeric punctuation + } + // If the next character is a digit, the current character is numeric punctuation + $charArray = self::getChar($workingText . "\n", $offset); + if (strpos(self::NUMBERS, $charArray['letter']) === false) { + // This is not a digit. End the run of digits and punctuation. + $numberState = false; + if (self::$currentState == 'RTL') { + if (strpos(self::NUMBER_PREFIX, $currentLetter) === false) { + $currentLetter = self::UTF8_PDF . $currentLetter; + } else { + $currentLetter = $currentLetter . self::UTF8_PDF; // Include a trailing + or - in the run + } + } + } + } + } else { + // If we're outside a numeric string, look for reasons to start it + if (strpos(self::NUMBER_PREFIX, $currentLetter) !== false) { + // This might be a number lead-in + $offset = $currentLen; + $nextChar = substr($workingText . "\n", $offset, 1); + if (strpos(self::NUMBERS, $nextChar) !== false) { + $numberState = true; // We found a digit: the lead-in is therefore numeric + if (self::$currentState == 'RTL') { + $currentLetter = self::UTF8_LRE . $currentLetter; + } + } + } elseif (strpos(self::NUMBERS, $currentLetter) !== false) { + $numberState = true; // The current letter is a digit + if (self::$currentState == 'RTL') { + $currentLetter = self::UTF8_LRE . $currentLetter; + } + } + } - // Determine the directionality of the current UTF-8 character - $newState = self::$currentState; - while (true) { - if (I18N::scriptDirection(I18N::textScript($currentLetter)) === 'rtl') { - if (self::$currentState == '') { - $newState = 'RTL'; - break; - } + // Determine the directionality of the current UTF-8 character + $newState = self::$currentState; + while (true) { + if (I18N::scriptDirection(I18N::textScript($currentLetter)) === 'rtl') { + if (self::$currentState == '') { + $newState = 'RTL'; + break; + } - if (self::$currentState == 'RTL') { - break; - } - // Switch to RTL only if this isn't a solitary RTL letter - $tempText = substr($workingText, $currentLen); - while ($tempText != '') { - $nextCharArray = self::getChar($tempText, 0); - $nextLetter = $nextCharArray['letter']; - $nextLen = $nextCharArray['length']; - $tempText = substr($tempText, $nextLen); + if (self::$currentState == 'RTL') { + break; + } + // Switch to RTL only if this isn't a solitary RTL letter + $tempText = substr($workingText, $currentLen); + while ($tempText != '') { + $nextCharArray = self::getChar($tempText, 0); + $nextLetter = $nextCharArray['letter']; + $nextLen = $nextCharArray['length']; + $tempText = substr($tempText, $nextLen); - if (I18N::scriptDirection(I18N::textScript($nextLetter)) === 'rtl') { - $newState = 'RTL'; - break 2; - } + if (I18N::scriptDirection(I18N::textScript($nextLetter)) === 'rtl') { + $newState = 'RTL'; + break 2; + } - if (strpos(self::PUNCTUATION, $nextLetter) !== false || strpos(self::OPEN_PARENTHESES, $nextLetter) !== false) { - $newState = 'RTL'; - break 2; - } + if (strpos(self::PUNCTUATION, $nextLetter) !== false || strpos(self::OPEN_PARENTHESES, $nextLetter) !== false) { + $newState = 'RTL'; + break 2; + } - if ($nextLetter === ' ') { - break; - } - $nextLetter .= substr($tempText . "\n", 0, 5); - if ($nextLetter === ' ') { - break; - } - } - // This is a solitary RTL letter : wrap it in UTF8 control codes to force LTR directionality - $currentLetter = self::UTF8_LRO . $currentLetter . self::UTF8_PDF; - $newState = 'LTR'; - break; - } - if (($currentLen != 1) || ($currentLetter >= 'A' && $currentLetter <= 'Z') || ($currentLetter >= 'a' && $currentLetter <= 'z')) { - // Since it’s neither Hebrew nor Arabic, this UTF-8 character or ASCII letter must be LTR - $newState = 'LTR'; - break; - } - if ($closeParIndex !== false) { - // This closing parenthesis has to inherit the matching opening parenthesis' directionality - if (!empty($openParDirection[$closeParIndex]) && $openParDirection[$closeParIndex] != '?') { - $newState = $openParDirection[$closeParIndex]; - } - $openParDirection[$closeParIndex] = ''; - break; - } - if ($openParIndex !== false) { - // Opening parentheses always inherit the following directionality - self::$waitingText .= $currentLetter; - $workingText = substr($workingText, $currentLen); - while (true) { - if ($workingText === '') { - break; - } - if (substr($workingText, 0, 1) === ' ') { - // Spaces following this left parenthesis inherit the following directionality too - self::$waitingText .= ' '; - $workingText = substr($workingText, 1); - continue; - } - if (substr($workingText, 0, 6) === ' ') { - // Spaces following this left parenthesis inherit the following directionality too - self::$waitingText .= ' '; - $workingText = substr($workingText, 6); - continue; - } - break; - } - $openParDirection[$openParIndex] = '?'; - break 2; // double break because we're waiting for more information - } + if ($nextLetter === ' ') { + break; + } + $nextLetter .= substr($tempText . "\n", 0, 5); + if ($nextLetter === ' ') { + break; + } + } + // This is a solitary RTL letter : wrap it in UTF8 control codes to force LTR directionality + $currentLetter = self::UTF8_LRO . $currentLetter . self::UTF8_PDF; + $newState = 'LTR'; + break; + } + if (($currentLen != 1) || ($currentLetter >= 'A' && $currentLetter <= 'Z') || ($currentLetter >= 'a' && $currentLetter <= 'z')) { + // Since it’s neither Hebrew nor Arabic, this UTF-8 character or ASCII letter must be LTR + $newState = 'LTR'; + break; + } + if ($closeParIndex !== false) { + // This closing parenthesis has to inherit the matching opening parenthesis' directionality + if (!empty($openParDirection[$closeParIndex]) && $openParDirection[$closeParIndex] != '?') { + $newState = $openParDirection[$closeParIndex]; + } + $openParDirection[$closeParIndex] = ''; + break; + } + if ($openParIndex !== false) { + // Opening parentheses always inherit the following directionality + self::$waitingText .= $currentLetter; + $workingText = substr($workingText, $currentLen); + while (true) { + if ($workingText === '') { + break; + } + if (substr($workingText, 0, 1) === ' ') { + // Spaces following this left parenthesis inherit the following directionality too + self::$waitingText .= ' '; + $workingText = substr($workingText, 1); + continue; + } + if (substr($workingText, 0, 6) === ' ') { + // Spaces following this left parenthesis inherit the following directionality too + self::$waitingText .= ' '; + $workingText = substr($workingText, 6); + continue; + } + break; + } + $openParDirection[$openParIndex] = '?'; + break 2; // double break because we're waiting for more information + } - // We have a digit or a "normal" special character. - // - // When this character is not at the start of the input string, it inherits the preceding directionality; - // at the start of the input string, it assumes the following directionality. - // - // Exceptions to this rule will be handled later during final clean-up. - // - self::$waitingText .= $currentLetter; - $workingText = substr($workingText, $currentLen); - if (self::$currentState != '') { - $result .= self::$waitingText; - self::$waitingText = ''; - } - break 2; // double break because we're waiting for more information - } - if ($newState != self::$currentState) { - // A direction change has occurred - self::finishCurrentSpan($result, false); - self::$previousState = self::$currentState; - self::$currentState = $newState; - self::beginCurrentSpan($result); - } - self::$waitingText .= $currentLetter; - $workingText = substr($workingText, $currentLen); - $result .= self::$waitingText; - self::$waitingText = ''; + // We have a digit or a "normal" special character. + // + // When this character is not at the start of the input string, it inherits the preceding directionality; + // at the start of the input string, it assumes the following directionality. + // + // Exceptions to this rule will be handled later during final clean-up. + // + self::$waitingText .= $currentLetter; + $workingText = substr($workingText, $currentLen); + if (self::$currentState != '') { + $result .= self::$waitingText; + self::$waitingText = ''; + } + break 2; // double break because we're waiting for more information + } + if ($newState != self::$currentState) { + // A direction change has occurred + self::finishCurrentSpan($result, false); + self::$previousState = self::$currentState; + self::$currentState = $newState; + self::beginCurrentSpan($result); + } + self::$waitingText .= $currentLetter; + $workingText = substr($workingText, $currentLen); + $result .= self::$waitingText; + self::$waitingText = ''; - foreach ($openParDirection as $index => $value) { - // Since we now know the proper direction, remember it for all waiting opening parentheses - if ($value === '?') { - $openParDirection[$index] = self::$currentState; - } - } + foreach ($openParDirection as $index => $value) { + // Since we now know the proper direction, remember it for all waiting opening parentheses + if ($value === '?') { + $openParDirection[$index] = self::$currentState; + } + } - break; - } - } + break; + } + } - // We're done. Finish last <span> if necessary - if ($numberState) { - if (self::$waitingText === '') { - if (self::$currentState === 'RTL') { - $result .= self::UTF8_PDF; - } - } else { - if (self::$currentState === 'RTL') { - self::$waitingText .= self::UTF8_PDF; - } - } - } - self::finishCurrentSpan($result, true); + // We're done. Finish last <span> if necessary + if ($numberState) { + if (self::$waitingText === '') { + if (self::$currentState === 'RTL') { + $result .= self::UTF8_PDF; + } + } else { + if (self::$currentState === 'RTL') { + self::$waitingText .= self::UTF8_PDF; + } + } + } + self::finishCurrentSpan($result, true); - // Get rid of any waiting text - if (self::$waitingText != '') { - if (I18N::direction() === 'rtl' && self::$currentState === 'LTR') { - $result .= self::$startRTL; - $result .= self::$waitingText; - $result .= self::$endRTL; - } else { - $result .= self::$startLTR; - $result .= self::$waitingText; - $result .= self::$endLTR; - } - self::$waitingText = ''; - } + // Get rid of any waiting text + if (self::$waitingText != '') { + if (I18N::direction() === 'rtl' && self::$currentState === 'LTR') { + $result .= self::$startRTL; + $result .= self::$waitingText; + $result .= self::$endRTL; + } else { + $result .= self::$startLTR; + $result .= self::$waitingText; + $result .= self::$endLTR; + } + self::$waitingText = ''; + } - // Lastly, do some more cleanups + // Lastly, do some more cleanups - // Move leading RTL numeric strings to following LTR text - // (this happens when the page direction is RTL and the original text begins with a number and is followed by LTR text) - while (substr($result, 0, self::$lenStart + 3) === self::$startRTL . self::UTF8_LRE) { - $spanEnd = strpos($result, self::$endRTL . self::$startLTR); - if ($spanEnd === false) { - break; - } - $textSpan = self::stripLrmRlm(substr($result, self::$lenStart + 3, $spanEnd - self::$lenStart - 3)); - if (I18N::scriptDirection(I18N::textScript($textSpan)) === 'rtl') { - break; - } - $result = self::$startLTR . substr($result, self::$lenStart, $spanEnd - self::$lenStart) . substr($result, $spanEnd + self::$lenStart + self::$lenEnd); - break; - } + // Move leading RTL numeric strings to following LTR text + // (this happens when the page direction is RTL and the original text begins with a number and is followed by LTR text) + while (substr($result, 0, self::$lenStart + 3) === self::$startRTL . self::UTF8_LRE) { + $spanEnd = strpos($result, self::$endRTL . self::$startLTR); + if ($spanEnd === false) { + break; + } + $textSpan = self::stripLrmRlm(substr($result, self::$lenStart + 3, $spanEnd - self::$lenStart - 3)); + if (I18N::scriptDirection(I18N::textScript($textSpan)) === 'rtl') { + break; + } + $result = self::$startLTR . substr($result, self::$lenStart, $spanEnd - self::$lenStart) . substr($result, $spanEnd + self::$lenStart + self::$lenEnd); + break; + } - // On RTL pages, put trailing "." in RTL numeric strings into its own RTL span - if (I18N::direction() === 'rtl') { - $result = str_replace(self::UTF8_PDF . '.' . self::$endRTL, self::UTF8_PDF . self::$endRTL . self::$startRTL . '.' . self::$endRTL, $result); - } + // On RTL pages, put trailing "." in RTL numeric strings into its own RTL span + if (I18N::direction() === 'rtl') { + $result = str_replace(self::UTF8_PDF . '.' . self::$endRTL, self::UTF8_PDF . self::$endRTL . self::$startRTL . '.' . self::$endRTL, $result); + } - // Trim trailing blanks preceding <br> in LTR text - while (self::$previousState != 'RTL') { - if (strpos($result, ' <LTRbr>') !== false) { - $result = str_replace(' <LTRbr>', '<LTRbr>', $result); - continue; - } - if (strpos($result, ' <LTRbr>') !== false) { - $result = str_replace(' <LTRbr>', '<LTRbr>', $result); - continue; - } - if (strpos($result, ' <br>') !== false) { - $result = str_replace(' <br>', '<br>', $result); - continue; - } - if (strpos($result, ' <br>') !== false) { - $result = str_replace(' <br>', '<br>', $result); - continue; - } - break; // Neither space nor : we're done - } + // Trim trailing blanks preceding <br> in LTR text + while (self::$previousState != 'RTL') { + if (strpos($result, ' <LTRbr>') !== false) { + $result = str_replace(' <LTRbr>', '<LTRbr>', $result); + continue; + } + if (strpos($result, ' <LTRbr>') !== false) { + $result = str_replace(' <LTRbr>', '<LTRbr>', $result); + continue; + } + if (strpos($result, ' <br>') !== false) { + $result = str_replace(' <br>', '<br>', $result); + continue; + } + if (strpos($result, ' <br>') !== false) { + $result = str_replace(' <br>', '<br>', $result); + continue; + } + break; // Neither space nor : we're done + } - // Trim trailing blanks preceding <br> in RTL text - while (true) { - if (strpos($result, ' <RTLbr>') !== false) { - $result = str_replace(' <RTLbr>', '<RTLbr>', $result); - continue; - } - if (strpos($result, ' <RTLbr>') !== false) { - $result = str_replace(' <RTLbr>', '<RTLbr>', $result); - continue; - } - break; // Neither space nor : we're done - } + // Trim trailing blanks preceding <br> in RTL text + while (true) { + if (strpos($result, ' <RTLbr>') !== false) { + $result = str_replace(' <RTLbr>', '<RTLbr>', $result); + continue; + } + if (strpos($result, ' <RTLbr>') !== false) { + $result = str_replace(' <RTLbr>', '<RTLbr>', $result); + continue; + } + break; // Neither space nor : we're done + } - // Convert '<LTRbr>' and '<RTLbr /' - $result = str_replace(['<LTRbr>', '<RTLbr>'], [self::$endLTR . '<br>' . self::$startLTR, self::$endRTL . '<br>' . self::$startRTL], $result); + // Convert '<LTRbr>' and '<RTLbr /' + $result = str_replace([ + '<LTRbr>', + '<RTLbr>', + ], [ + self::$endLTR . '<br>' . self::$startLTR, + self::$endRTL . '<br>' . self::$startRTL, + ], $result); - // Include leading indeterminate directional text in whatever follows - if (substr($result . "\n", 0, self::$lenStart) != self::$startLTR && substr($result . "\n", 0, self::$lenStart) != self::$startRTL && substr($result . "\n", 0, 6) != '<br>') { - $leadingText = ''; - while (true) { - if ($result == '') { - $result = $leadingText; - break; - } - if (substr($result . "\n", 0, self::$lenStart) != self::$startLTR && substr($result . "\n", 0, self::$lenStart) != self::$startRTL) { - $leadingText .= substr($result, 0, 1); - $result = substr($result, 1); - continue; - } - $result = substr($result, 0, self::$lenStart) . $leadingText . substr($result, self::$lenStart); - break; - } - } + // Include leading indeterminate directional text in whatever follows + if (substr($result . "\n", 0, self::$lenStart) != self::$startLTR && substr($result . "\n", 0, self::$lenStart) != self::$startRTL && substr($result . "\n", 0, 6) != '<br>') { + $leadingText = ''; + while (true) { + if ($result == '') { + $result = $leadingText; + break; + } + if (substr($result . "\n", 0, self::$lenStart) != self::$startLTR && substr($result . "\n", 0, self::$lenStart) != self::$startRTL) { + $leadingText .= substr($result, 0, 1); + $result = substr($result, 1); + continue; + } + $result = substr($result, 0, self::$lenStart) . $leadingText . substr($result, self::$lenStart); + break; + } + } - // Include solitary "-" and "+" in surrounding RTL text - $result = str_replace([self::$endRTL . self::$startLTR . '-' . self::$endLTR . self::$startRTL, self::$endRTL . self::$startLTR . '-' . self::$endLTR . self::$startRTL], ['-', '+'], $result); + // Include solitary "-" and "+" in surrounding RTL text + $result = str_replace([ + self::$endRTL . self::$startLTR . '-' . self::$endLTR . self::$startRTL, + self::$endRTL . self::$startLTR . '-' . self::$endLTR . self::$startRTL, + ], [ + '-', + '+', + ], $result); - // Remove empty spans - $result = str_replace([self::$startLTR . self::$endLTR, self::$startRTL . self::$endRTL], '', $result); + // Remove empty spans + $result = str_replace([ + self::$startLTR . self::$endLTR, + self::$startRTL . self::$endRTL, + ], '', $result); - // Finally, correct '<LTR>', '</LTR>', '<RTL>', and '</RTL>' - switch ($direction) { - case 'BOTH': - case 'both': - // LTR text: <span dir="ltr"> text </span> - // RTL text: <span dir="rtl"> text </span> - $sLTR = '<span dir="ltr" ' . $class . '>' . $nothing; - $eLTR = $nothing . '</span>'; - $sRTL = '<span dir="rtl" ' . $class . '>' . $nothing; - $eRTL = $nothing . '</span>'; - break; - case 'LTR': - case 'ltr': - // LTR text: <span dir="ltr"> text </span> - // RTL text: text - $sLTR = '<span dir="ltr" ' . $class . '>' . $nothing; - $eLTR = $nothing . '</span>'; - $sRTL = ''; - $eRTL = ''; - break; - case 'RTL': - case 'rtl': - default: - // LTR text: text - // RTL text: <span dir="rtl"> text </span> - $sLTR = ''; - $eLTR = ''; - $sRTL = '<span dir="rtl" ' . $class . '>' . $nothing; - $eRTL = $nothing . '</span>'; - break; - } - $result = str_replace([self::$startLTR, self::$endLTR, self::$startRTL, self::$endRTL], [$sLTR, $eLTR, $sRTL, $eRTL], $result); + // Finally, correct '<LTR>', '</LTR>', '<RTL>', and '</RTL>' + switch ($direction) { + case 'BOTH': + case 'both': + // LTR text: <span dir="ltr"> text </span> + // RTL text: <span dir="rtl"> text </span> + $sLTR = '<span dir="ltr" ' . $class . '>' . $nothing; + $eLTR = $nothing . '</span>'; + $sRTL = '<span dir="rtl" ' . $class . '>' . $nothing; + $eRTL = $nothing . '</span>'; + break; + case 'LTR': + case 'ltr': + // LTR text: <span dir="ltr"> text </span> + // RTL text: text + $sLTR = '<span dir="ltr" ' . $class . '>' . $nothing; + $eLTR = $nothing . '</span>'; + $sRTL = ''; + $eRTL = ''; + break; + case 'RTL': + case 'rtl': + default: + // LTR text: text + // RTL text: <span dir="rtl"> text </span> + $sLTR = ''; + $eLTR = ''; + $sRTL = '<span dir="rtl" ' . $class . '>' . $nothing; + $eRTL = $nothing . '</span>'; + break; + } + $result = str_replace([ + self::$startLTR, + self::$endLTR, + self::$startRTL, + self::$endRTL, + ], [ + $sLTR, + $eLTR, + $sRTL, + $eRTL, + ], $result); - return $result; - } + return $result; + } - /** - * Wrap words that have an asterisk suffix in <u> and </u> tags. - * This should underline starred names to show the preferred name. - * - * @param string $textSpan - * @param string $direction - * - * @return string - */ - public static function starredName($textSpan, $direction) { - // To avoid a TCPDF bug that mixes up the word order, insert those <u> and </u> tags - // only when page and span directions are identical. - if ($direction === strtoupper(I18N::direction())) { - while (true) { - $starPos = strpos($textSpan, '*'); - if ($starPos === false) { - break; - } - $trailingText = substr($textSpan, $starPos + 1); - $textSpan = substr($textSpan, 0, $starPos); - $wordStart = strrpos($textSpan, ' '); // Find the start of the word - if ($wordStart !== false) { - $leadingText = substr($textSpan, 0, $wordStart + 1); - $wordText = substr($textSpan, $wordStart + 1); - } else { - $leadingText = ''; - $wordText = $textSpan; - } - $textSpan = $leadingText . '<u>' . $wordText . '</u>' . $trailingText; - } - $textSpan = preg_replace('~<span class="starredname">(.*)</span>~', '<u>\1</u>', $textSpan); - // The is a work-around for a TCPDF bug eating blanks. - $textSpan = str_replace([' <u>', '</u> '], [' <u>', '</u> '], $textSpan); - } else { - // Text and page directions differ: remove the <span> and </span> - $textSpan = preg_replace('~(.*)\*~', '\1', $textSpan); - $textSpan = preg_replace('~<span class="starredname">(.*)</span>~', '\1', $textSpan); - } + /** + * Wrap words that have an asterisk suffix in <u> and </u> tags. + * This should underline starred names to show the preferred name. + * + * @param string $textSpan + * @param string $direction + * + * @return string + */ + public static function starredName($textSpan, $direction) + { + // To avoid a TCPDF bug that mixes up the word order, insert those <u> and </u> tags + // only when page and span directions are identical. + if ($direction === strtoupper(I18N::direction())) { + while (true) { + $starPos = strpos($textSpan, '*'); + if ($starPos === false) { + break; + } + $trailingText = substr($textSpan, $starPos + 1); + $textSpan = substr($textSpan, 0, $starPos); + $wordStart = strrpos($textSpan, ' '); // Find the start of the word + if ($wordStart !== false) { + $leadingText = substr($textSpan, 0, $wordStart + 1); + $wordText = substr($textSpan, $wordStart + 1); + } else { + $leadingText = ''; + $wordText = $textSpan; + } + $textSpan = $leadingText . '<u>' . $wordText . '</u>' . $trailingText; + } + $textSpan = preg_replace('~<span class="starredname">(.*)</span>~', '<u>\1</u>', $textSpan); + // The is a work-around for a TCPDF bug eating blanks. + $textSpan = str_replace([ + ' <u>', + '</u> ', + ], [ + ' <u>', + '</u> ', + ], $textSpan); + } else { + // Text and page directions differ: remove the <span> and </span> + $textSpan = preg_replace('~(.*)\*~', '\1', $textSpan); + $textSpan = preg_replace('~<span class="starredname">(.*)</span>~', '\1', $textSpan); + } - return $textSpan; - } + return $textSpan; + } - /** - * Get the next character from an input string - * - * @param string $text - * @param string $offset - * - * @return array - */ - public static function getChar($text, $offset) { - if ($text == '') { - return ['letter' => '', 'length' => 0]; - } + /** + * Get the next character from an input string + * + * @param string $text + * @param string $offset + * + * @return array + */ + public static function getChar($text, $offset) + { + if ($text == '') { + return [ + 'letter' => '', + 'length' => 0, + ]; + } - $char = substr($text, $offset, 1); - $length = 1; - if ((ord($char) & 0xE0) == 0xC0) { - $length = 2; - } - if ((ord($char) & 0xF0) == 0xE0) { - $length = 3; - } - if ((ord($char) & 0xF8) == 0xF0) { - $length = 4; - } - $letter = substr($text, $offset, $length); + $char = substr($text, $offset, 1); + $length = 1; + if ((ord($char) & 0xE0) == 0xC0) { + $length = 2; + } + if ((ord($char) & 0xF0) == 0xE0) { + $length = 3; + } + if ((ord($char) & 0xF8) == 0xF0) { + $length = 4; + } + $letter = substr($text, $offset, $length); - return ['letter' => $letter, 'length' => $length]; - } + return [ + 'letter' => $letter, + 'length' => $length, + ]; + } - /** - * Insert <br> into current span - * - * @param string $result - */ - public static function breakCurrentSpan(&$result) { - // Interrupt the current span, insert that <br>, and then continue the current span - $result .= self::$waitingText; - self::$waitingText = ''; + /** + * Insert <br> into current span + * + * @param string $result + */ + public static function breakCurrentSpan(&$result) + { + // Interrupt the current span, insert that <br>, and then continue the current span + $result .= self::$waitingText; + self::$waitingText = ''; - $breakString = '<' . self::$currentState . 'br>'; - $result .= $breakString; - } + $breakString = '<' . self::$currentState . 'br>'; + $result .= $breakString; + } - /** - * Begin current span - * - * @param string $result - */ - public static function beginCurrentSpan(&$result) { - if (self::$currentState == 'LTR') { - $result .= self::$startLTR; - } - if (self::$currentState == 'RTL') { - $result .= self::$startRTL; - } + /** + * Begin current span + * + * @param string $result + */ + public static function beginCurrentSpan(&$result) + { + if (self::$currentState == 'LTR') { + $result .= self::$startLTR; + } + if (self::$currentState == 'RTL') { + $result .= self::$startRTL; + } - self::$posSpanStart = strlen($result); - } + self::$posSpanStart = strlen($result); + } - /** - * Finish current span - * - * @param string $result - * @param bool $theEnd - */ - public static function finishCurrentSpan(&$result, $theEnd = false) { - $textSpan = substr($result, self::$posSpanStart); - $result = substr($result, 0, self::$posSpanStart); + /** + * Finish current span + * + * @param string $result + * @param bool $theEnd + */ + public static function finishCurrentSpan(&$result, $theEnd = false) + { + $textSpan = substr($result, self::$posSpanStart); + $result = substr($result, 0, self::$posSpanStart); - // Get rid of empty spans, so that our check for presence of RTL will work - $result = str_replace([self::$startLTR . self::$endLTR, self::$startRTL . self::$endRTL], '', $result); + // Get rid of empty spans, so that our check for presence of RTL will work + $result = str_replace([ + self::$startLTR . self::$endLTR, + self::$startRTL . self::$endRTL, + ], '', $result); - // Look for numeric strings that are times (hh:mm:ss). These have to be separated from surrounding numbers. - $tempResult = ''; - while ($textSpan != '') { - $posColon = strpos($textSpan, ':'); - if ($posColon === false) { - break; - } // No more possible time strings - $posLRE = strpos($textSpan, self::UTF8_LRE); - if ($posLRE === false) { - break; - } // No more numeric strings - $posPDF = strpos($textSpan, self::UTF8_PDF, $posLRE); - if ($posPDF === false) { - break; - } // No more numeric strings + // Look for numeric strings that are times (hh:mm:ss). These have to be separated from surrounding numbers. + $tempResult = ''; + while ($textSpan != '') { + $posColon = strpos($textSpan, ':'); + if ($posColon === false) { + break; + } // No more possible time strings + $posLRE = strpos($textSpan, self::UTF8_LRE); + if ($posLRE === false) { + break; + } // No more numeric strings + $posPDF = strpos($textSpan, self::UTF8_PDF, $posLRE); + if ($posPDF === false) { + break; + } // No more numeric strings - $tempResult .= substr($textSpan, 0, $posLRE + 3); // Copy everything preceding the numeric string - $numericString = substr($textSpan, $posLRE + 3, $posPDF - $posLRE); // Separate the entire numeric string - $textSpan = substr($textSpan, $posPDF + 3); - $posColon = strpos($numericString, ':'); - if ($posColon === false) { - // Nothing that looks like a time here - $tempResult .= $numericString; - continue; - } - $posBlank = strpos($numericString . ' ', ' '); - $posNbsp = strpos($numericString . ' ', ' '); - if ($posBlank < $posNbsp) { - $posSeparator = $posBlank; - $lengthSeparator = 1; - } else { - $posSeparator = $posNbsp; - $lengthSeparator = 6; - } - if ($posColon > $posSeparator) { - // We have a time string preceded by a blank: Exclude that blank from the numeric string - $tempResult .= substr($numericString, 0, $posSeparator); - $tempResult .= self::UTF8_PDF; - $tempResult .= substr($numericString, $posSeparator, $lengthSeparator); - $tempResult .= self::UTF8_LRE; - $numericString = substr($numericString, $posSeparator + $lengthSeparator); - } + $tempResult .= substr($textSpan, 0, $posLRE + 3); // Copy everything preceding the numeric string + $numericString = substr($textSpan, $posLRE + 3, $posPDF - $posLRE); // Separate the entire numeric string + $textSpan = substr($textSpan, $posPDF + 3); + $posColon = strpos($numericString, ':'); + if ($posColon === false) { + // Nothing that looks like a time here + $tempResult .= $numericString; + continue; + } + $posBlank = strpos($numericString . ' ', ' '); + $posNbsp = strpos($numericString . ' ', ' '); + if ($posBlank < $posNbsp) { + $posSeparator = $posBlank; + $lengthSeparator = 1; + } else { + $posSeparator = $posNbsp; + $lengthSeparator = 6; + } + if ($posColon > $posSeparator) { + // We have a time string preceded by a blank: Exclude that blank from the numeric string + $tempResult .= substr($numericString, 0, $posSeparator); + $tempResult .= self::UTF8_PDF; + $tempResult .= substr($numericString, $posSeparator, $lengthSeparator); + $tempResult .= self::UTF8_LRE; + $numericString = substr($numericString, $posSeparator + $lengthSeparator); + } - $posBlank = strpos($numericString, ' '); - $posNbsp = strpos($numericString, ' '); - if ($posBlank === false && $posNbsp === false) { - // The time string isn't followed by a blank - $textSpan = $numericString . $textSpan; - continue; - } + $posBlank = strpos($numericString, ' '); + $posNbsp = strpos($numericString, ' '); + if ($posBlank === false && $posNbsp === false) { + // The time string isn't followed by a blank + $textSpan = $numericString . $textSpan; + continue; + } - // We have a time string followed by a blank: Exclude that blank from the numeric string - if ($posBlank === false) { - $posSeparator = $posNbsp; - $lengthSeparator = 6; - } elseif ($posNbsp === false) { - $posSeparator = $posBlank; - $lengthSeparator = 1; - } elseif ($posBlank < $posNbsp) { - $posSeparator = $posBlank; - $lengthSeparator = 1; - } else { - $posSeparator = $posNbsp; - $lengthSeparator = 6; - } - $tempResult .= substr($numericString, 0, $posSeparator); - $tempResult .= self::UTF8_PDF; - $tempResult .= substr($numericString, $posSeparator, $lengthSeparator); - $posSeparator += $lengthSeparator; - $numericString = substr($numericString, $posSeparator); - $textSpan = self::UTF8_LRE . $numericString . $textSpan; - } - $textSpan = $tempResult . $textSpan; - $trailingBlanks = ''; - $trailingBreaks = ''; + // We have a time string followed by a blank: Exclude that blank from the numeric string + if ($posBlank === false) { + $posSeparator = $posNbsp; + $lengthSeparator = 6; + } elseif ($posNbsp === false) { + $posSeparator = $posBlank; + $lengthSeparator = 1; + } elseif ($posBlank < $posNbsp) { + $posSeparator = $posBlank; + $lengthSeparator = 1; + } else { + $posSeparator = $posNbsp; + $lengthSeparator = 6; + } + $tempResult .= substr($numericString, 0, $posSeparator); + $tempResult .= self::UTF8_PDF; + $tempResult .= substr($numericString, $posSeparator, $lengthSeparator); + $posSeparator += $lengthSeparator; + $numericString = substr($numericString, $posSeparator); + $textSpan = self::UTF8_LRE . $numericString . $textSpan; + } + $textSpan = $tempResult . $textSpan; + $trailingBlanks = ''; + $trailingBreaks = ''; - /* ****************************** LTR text handling ******************************** */ + /* ****************************** LTR text handling ******************************** */ - if (self::$currentState === 'LTR') { - // Move trailing numeric strings to the following RTL text. Include any blanks preceding or following the numeric text too. - if (I18N::direction() === 'rtl' && self::$previousState === 'RTL' && !$theEnd) { - $trailingString = ''; - $savedSpan = $textSpan; - while ($textSpan !== '') { - // Look for trailing spaces and tentatively move them - if (substr($textSpan, -1) === ' ') { - $trailingString = ' ' . $trailingString; - $textSpan = substr($textSpan, 0, -1); - continue; - } - if (substr($textSpan, -6) === ' ') { - $trailingString = ' ' . $trailingString; - $textSpan = substr($textSpan, 0, -1); - continue; - } - if (substr($textSpan, -3) !== self::UTF8_PDF) { - // There is no trailing numeric string - $textSpan = $savedSpan; - break; - } + if (self::$currentState === 'LTR') { + // Move trailing numeric strings to the following RTL text. Include any blanks preceding or following the numeric text too. + if (I18N::direction() === 'rtl' && self::$previousState === 'RTL' && !$theEnd) { + $trailingString = ''; + $savedSpan = $textSpan; + while ($textSpan !== '') { + // Look for trailing spaces and tentatively move them + if (substr($textSpan, -1) === ' ') { + $trailingString = ' ' . $trailingString; + $textSpan = substr($textSpan, 0, -1); + continue; + } + if (substr($textSpan, -6) === ' ') { + $trailingString = ' ' . $trailingString; + $textSpan = substr($textSpan, 0, -1); + continue; + } + if (substr($textSpan, -3) !== self::UTF8_PDF) { + // There is no trailing numeric string + $textSpan = $savedSpan; + break; + } - // We have a numeric string - $posStartNumber = strrpos($textSpan, self::UTF8_LRE); - if ($posStartNumber === false) { - $posStartNumber = 0; - } - $trailingString = substr($textSpan, $posStartNumber, strlen($textSpan) - $posStartNumber) . $trailingString; - $textSpan = substr($textSpan, 0, $posStartNumber); + // We have a numeric string + $posStartNumber = strrpos($textSpan, self::UTF8_LRE); + if ($posStartNumber === false) { + $posStartNumber = 0; + } + $trailingString = substr($textSpan, $posStartNumber, strlen($textSpan) - $posStartNumber) . $trailingString; + $textSpan = substr($textSpan, 0, $posStartNumber); - // Look for more spaces and move them too - while ($textSpan != '') { - if (substr($textSpan, -1) == ' ') { - $trailingString = ' ' . $trailingString; - $textSpan = substr($textSpan, 0, -1); - continue; - } - if (substr($textSpan, -6) == ' ') { - $trailingString = ' ' . $trailingString; - $textSpan = substr($textSpan, 0, -1); - continue; - } - break; - } + // Look for more spaces and move them too + while ($textSpan != '') { + if (substr($textSpan, -1) == ' ') { + $trailingString = ' ' . $trailingString; + $textSpan = substr($textSpan, 0, -1); + continue; + } + if (substr($textSpan, -6) == ' ') { + $trailingString = ' ' . $trailingString; + $textSpan = substr($textSpan, 0, -1); + continue; + } + break; + } - self::$waitingText = $trailingString . self::$waitingText; - break; - } - } + self::$waitingText = $trailingString . self::$waitingText; + break; + } + } - $savedSpan = $textSpan; - // Move any trailing <br>, optionally preceded or followed by blanks, outside this LTR span - while ($textSpan != '') { - if (substr($textSpan, -1) == ' ') { - $trailingBlanks = ' ' . $trailingBlanks; - $textSpan = substr($textSpan, 0, -1); - continue; - } - if (substr('......' . $textSpan, -6) == ' ') { - $trailingBlanks = ' ' . $trailingBlanks; - $textSpan = substr($textSpan, 0, -6); - continue; - } - break; - } - while (substr($textSpan, -9) == '<LTRbr>') { - $trailingBreaks = '<br>' . $trailingBreaks; // Plain <br> because it’s outside a span - $textSpan = substr($textSpan, 0, -9); - } - if ($trailingBreaks != '') { - while ($textSpan != '') { - if (substr($textSpan, -1) == ' ') { - $trailingBreaks = ' ' . $trailingBreaks; - $textSpan = substr($textSpan, 0, -1); - continue; - } - if (substr('......' . $textSpan, -6) == ' ') { - $trailingBreaks = ' ' . $trailingBreaks; - $textSpan = substr($textSpan, 0, -6); - continue; - } - break; - } - self::$waitingText = $trailingBlanks . self::$waitingText; // Put those trailing blanks inside the following span - } else { - $textSpan = $savedSpan; - } + $savedSpan = $textSpan; + // Move any trailing <br>, optionally preceded or followed by blanks, outside this LTR span + while ($textSpan != '') { + if (substr($textSpan, -1) == ' ') { + $trailingBlanks = ' ' . $trailingBlanks; + $textSpan = substr($textSpan, 0, -1); + continue; + } + if (substr('......' . $textSpan, -6) == ' ') { + $trailingBlanks = ' ' . $trailingBlanks; + $textSpan = substr($textSpan, 0, -6); + continue; + } + break; + } + while (substr($textSpan, -9) == '<LTRbr>') { + $trailingBreaks = '<br>' . $trailingBreaks; // Plain <br> because it’s outside a span + $textSpan = substr($textSpan, 0, -9); + } + if ($trailingBreaks != '') { + while ($textSpan != '') { + if (substr($textSpan, -1) == ' ') { + $trailingBreaks = ' ' . $trailingBreaks; + $textSpan = substr($textSpan, 0, -1); + continue; + } + if (substr('......' . $textSpan, -6) == ' ') { + $trailingBreaks = ' ' . $trailingBreaks; + $textSpan = substr($textSpan, 0, -6); + continue; + } + break; + } + self::$waitingText = $trailingBlanks . self::$waitingText; // Put those trailing blanks inside the following span + } else { + $textSpan = $savedSpan; + } - $trailingBlanks = ''; - $trailingPunctuation = ''; - $trailingID = ''; - $trailingSeparator = ''; - $leadingSeparator = ''; - while (I18N::direction() === 'rtl') { - if (strpos($result, self::$startRTL) !== false) { - // Remove trailing blanks for inclusion in a separate LTR span - while ($textSpan != '') { - if (substr($textSpan, -1) === ' ') { - $trailingBlanks = ' ' . $trailingBlanks; - $textSpan = substr($textSpan, 0, -1); - continue; - } - if (substr($textSpan, -6) === ' ') { - $trailingBlanks = ' ' . $trailingBlanks; - $textSpan = substr($textSpan, 0, -1); - continue; - } - break; - } + $trailingBlanks = ''; + $trailingPunctuation = ''; + $trailingID = ''; + $trailingSeparator = ''; + $leadingSeparator = ''; + while (I18N::direction() === 'rtl') { + if (strpos($result, self::$startRTL) !== false) { + // Remove trailing blanks for inclusion in a separate LTR span + while ($textSpan != '') { + if (substr($textSpan, -1) === ' ') { + $trailingBlanks = ' ' . $trailingBlanks; + $textSpan = substr($textSpan, 0, -1); + continue; + } + if (substr($textSpan, -6) === ' ') { + $trailingBlanks = ' ' . $trailingBlanks; + $textSpan = substr($textSpan, 0, -1); + continue; + } + break; + } - // Remove trailing punctuation for inclusion in a separate LTR span - if ($textSpan == '') { - $trailingChar = "\n"; - } else { - $trailingChar = substr($textSpan, -1); - } - if (strpos(self::PUNCTUATION, $trailingChar) !== false) { - $trailingPunctuation = $trailingChar; - $textSpan = substr($textSpan, 0, -1); - } - } + // Remove trailing punctuation for inclusion in a separate LTR span + if ($textSpan == '') { + $trailingChar = "\n"; + } else { + $trailingChar = substr($textSpan, -1); + } + if (strpos(self::PUNCTUATION, $trailingChar) !== false) { + $trailingPunctuation = $trailingChar; + $textSpan = substr($textSpan, 0, -1); + } + } - // Remove trailing ID numbers that look like "(xnnn)" for inclusion in a separate LTR span - while (true) { - if (substr($textSpan, -1) != ')') { - break; - } // There is no trailing ')' - $posLeftParen = strrpos($textSpan, '('); - if ($posLeftParen === false) { - break; - } // There is no leading '(' - $temp = self::stripLrmRlm(substr($textSpan, $posLeftParen)); // Get rid of UTF8 control codes + // Remove trailing ID numbers that look like "(xnnn)" for inclusion in a separate LTR span + while (true) { + if (substr($textSpan, -1) != ')') { + break; + } // There is no trailing ')' + $posLeftParen = strrpos($textSpan, '('); + if ($posLeftParen === false) { + break; + } // There is no leading '(' + $temp = self::stripLrmRlm(substr($textSpan, $posLeftParen)); // Get rid of UTF8 control codes - // If the parenthesized text doesn't look like an ID number, - // we don't want to touch it. - // This check won’t work if somebody uses ID numbers with an unusual format. - $offset = 1; - $charArray = self::getChar($temp, $offset); // Get 1st character of parenthesized text - if (strpos(self::NUMBERS, $charArray['letter']) !== false) { - break; - } - $offset += $charArray['length']; // Point at 2nd character of parenthesized text - if (strpos(self::NUMBERS, substr($temp, $offset, 1)) === false) { - break; - } - // 1st character of parenthesized text is alpha, 2nd character is a digit; last has to be a digit too - if (strpos(self::NUMBERS, substr($temp, -2, 1)) === false) { - break; - } + // If the parenthesized text doesn't look like an ID number, + // we don't want to touch it. + // This check won’t work if somebody uses ID numbers with an unusual format. + $offset = 1; + $charArray = self::getChar($temp, $offset); // Get 1st character of parenthesized text + if (strpos(self::NUMBERS, $charArray['letter']) !== false) { + break; + } + $offset += $charArray['length']; // Point at 2nd character of parenthesized text + if (strpos(self::NUMBERS, substr($temp, $offset, 1)) === false) { + break; + } + // 1st character of parenthesized text is alpha, 2nd character is a digit; last has to be a digit too + if (strpos(self::NUMBERS, substr($temp, -2, 1)) === false) { + break; + } - $trailingID = substr($textSpan, $posLeftParen); - $textSpan = substr($textSpan, 0, $posLeftParen); - break; - } + $trailingID = substr($textSpan, $posLeftParen); + $textSpan = substr($textSpan, 0, $posLeftParen); + break; + } - // Look for " - " or blank preceding the ID number and remove it for inclusion in a separate LTR span - if ($trailingID != '') { - while ($textSpan != '') { - if (substr($textSpan, -1) == ' ') { - $trailingSeparator = ' ' . $trailingSeparator; - $textSpan = substr($textSpan, 0, -1); - continue; - } - if (substr($textSpan, -6) == ' ') { - $trailingSeparator = ' ' . $trailingSeparator; - $textSpan = substr($textSpan, 0, -6); - continue; - } - if (substr($textSpan, -1) == '-') { - $trailingSeparator = '-' . $trailingSeparator; - $textSpan = substr($textSpan, 0, -1); - continue; - } - break; - } - } + // Look for " - " or blank preceding the ID number and remove it for inclusion in a separate LTR span + if ($trailingID != '') { + while ($textSpan != '') { + if (substr($textSpan, -1) == ' ') { + $trailingSeparator = ' ' . $trailingSeparator; + $textSpan = substr($textSpan, 0, -1); + continue; + } + if (substr($textSpan, -6) == ' ') { + $trailingSeparator = ' ' . $trailingSeparator; + $textSpan = substr($textSpan, 0, -6); + continue; + } + if (substr($textSpan, -1) == '-') { + $trailingSeparator = '-' . $trailingSeparator; + $textSpan = substr($textSpan, 0, -1); + continue; + } + break; + } + } - // Look for " - " preceding the text and remove it for inclusion in a separate LTR span - $foundSeparator = false; - $savedSpan = $textSpan; - while ($textSpan != '') { - if (substr($textSpan, 0, 1) == ' ') { - $leadingSeparator = ' ' . $leadingSeparator; - $textSpan = substr($textSpan, 1); - continue; - } - if (substr($textSpan, 0, 6) == ' ') { - $leadingSeparator = ' ' . $leadingSeparator; - $textSpan = substr($textSpan, 6); - continue; - } - if (substr($textSpan, 0, 1) == '-') { - $leadingSeparator = '-' . $leadingSeparator; - $textSpan = substr($textSpan, 1); - $foundSeparator = true; - continue; - } - break; - } - if (!$foundSeparator) { - $textSpan = $savedSpan; - $leadingSeparator = ''; - } - break; - } + // Look for " - " preceding the text and remove it for inclusion in a separate LTR span + $foundSeparator = false; + $savedSpan = $textSpan; + while ($textSpan != '') { + if (substr($textSpan, 0, 1) == ' ') { + $leadingSeparator = ' ' . $leadingSeparator; + $textSpan = substr($textSpan, 1); + continue; + } + if (substr($textSpan, 0, 6) == ' ') { + $leadingSeparator = ' ' . $leadingSeparator; + $textSpan = substr($textSpan, 6); + continue; + } + if (substr($textSpan, 0, 1) == '-') { + $leadingSeparator = '-' . $leadingSeparator; + $textSpan = substr($textSpan, 1); + $foundSeparator = true; + continue; + } + break; + } + if (!$foundSeparator) { + $textSpan = $savedSpan; + $leadingSeparator = ''; + } + break; + } - // We're done: finish the span - $textSpan = self::starredName($textSpan, 'LTR'); // Wrap starred name in <u> and </u> tags - while (true) { - // Remove blanks that precede <LTRbr> - if (strpos($textSpan, ' <LTRbr>') !== false) { - $textSpan = str_replace(' <LTRbr>', '<LTRbr>', $textSpan); - continue; - } - if (strpos($textSpan, ' <LTRbr>') !== false) { - $textSpan = str_replace(' <LTRbr>', '<LTRbr>', $textSpan); - continue; - } - break; - } - if ($leadingSeparator != '') { - $result = $result . self::$startLTR . $leadingSeparator . self::$endLTR; - } - $result = $result . $textSpan . self::$endLTR; - if ($trailingSeparator != '') { - $result = $result . self::$startLTR . $trailingSeparator . self::$endLTR; - } - if ($trailingID != '') { - $result = $result . self::$startLTR . $trailingID . self::$endLTR; - } - if ($trailingPunctuation != '') { - $result = $result . self::$startLTR . $trailingPunctuation . self::$endLTR; - } - if ($trailingBlanks != '') { - $result = $result . self::$startLTR . $trailingBlanks . self::$endLTR; - } - } + // We're done: finish the span + $textSpan = self::starredName($textSpan, 'LTR'); // Wrap starred name in <u> and </u> tags + while (true) { + // Remove blanks that precede <LTRbr> + if (strpos($textSpan, ' <LTRbr>') !== false) { + $textSpan = str_replace(' <LTRbr>', '<LTRbr>', $textSpan); + continue; + } + if (strpos($textSpan, ' <LTRbr>') !== false) { + $textSpan = str_replace(' <LTRbr>', '<LTRbr>', $textSpan); + continue; + } + break; + } + if ($leadingSeparator != '') { + $result = $result . self::$startLTR . $leadingSeparator . self::$endLTR; + } + $result = $result . $textSpan . self::$endLTR; + if ($trailingSeparator != '') { + $result = $result . self::$startLTR . $trailingSeparator . self::$endLTR; + } + if ($trailingID != '') { + $result = $result . self::$startLTR . $trailingID . self::$endLTR; + } + if ($trailingPunctuation != '') { + $result = $result . self::$startLTR . $trailingPunctuation . self::$endLTR; + } + if ($trailingBlanks != '') { + $result = $result . self::$startLTR . $trailingBlanks . self::$endLTR; + } + } - /* ****************************** RTL text handling ******************************** */ + /* ****************************** RTL text handling ******************************** */ - if (self::$currentState == 'RTL') { - $savedSpan = $textSpan; + if (self::$currentState == 'RTL') { + $savedSpan = $textSpan; - // Move any trailing <br>, optionally followed by blanks, outside this RTL span - while ($textSpan != '') { - if (substr($textSpan, -1) == ' ') { - $trailingBlanks = ' ' . $trailingBlanks; - $textSpan = substr($textSpan, 0, -1); - continue; - } - if (substr('......' . $textSpan, -6) == ' ') { - $trailingBlanks = ' ' . $trailingBlanks; - $textSpan = substr($textSpan, 0, -6); - continue; - } - break; - } - while (substr($textSpan, -9) == '<RTLbr>') { - $trailingBreaks = '<br>' . $trailingBreaks; // Plain <br> because it’s outside a span - $textSpan = substr($textSpan, 0, -9); - } - if ($trailingBreaks != '') { - self::$waitingText = $trailingBlanks . self::$waitingText; // Put those trailing blanks inside the following span - } else { - $textSpan = $savedSpan; - } + // Move any trailing <br>, optionally followed by blanks, outside this RTL span + while ($textSpan != '') { + if (substr($textSpan, -1) == ' ') { + $trailingBlanks = ' ' . $trailingBlanks; + $textSpan = substr($textSpan, 0, -1); + continue; + } + if (substr('......' . $textSpan, -6) == ' ') { + $trailingBlanks = ' ' . $trailingBlanks; + $textSpan = substr($textSpan, 0, -6); + continue; + } + break; + } + while (substr($textSpan, -9) == '<RTLbr>') { + $trailingBreaks = '<br>' . $trailingBreaks; // Plain <br> because it’s outside a span + $textSpan = substr($textSpan, 0, -9); + } + if ($trailingBreaks != '') { + self::$waitingText = $trailingBlanks . self::$waitingText; // Put those trailing blanks inside the following span + } else { + $textSpan = $savedSpan; + } - // Move trailing numeric strings to the following LTR text. Include any blanks preceding or following the numeric text too. - if (!$theEnd && I18N::direction() !== 'rtl') { - $trailingString = ''; - $savedSpan = $textSpan; - while ($textSpan != '') { - // Look for trailing spaces and tentatively move them - if (substr($textSpan, -1) === ' ') { - $trailingString = ' ' . $trailingString; - $textSpan = substr($textSpan, 0, -1); - continue; - } - if (substr($textSpan, -6) === ' ') { - $trailingString = ' ' . $trailingString; - $textSpan = substr($textSpan, 0, -1); - continue; - } - if (substr($textSpan, -3) !== self::UTF8_PDF) { - // There is no trailing numeric string - $textSpan = $savedSpan; - break; - } + // Move trailing numeric strings to the following LTR text. Include any blanks preceding or following the numeric text too. + if (!$theEnd && I18N::direction() !== 'rtl') { + $trailingString = ''; + $savedSpan = $textSpan; + while ($textSpan != '') { + // Look for trailing spaces and tentatively move them + if (substr($textSpan, -1) === ' ') { + $trailingString = ' ' . $trailingString; + $textSpan = substr($textSpan, 0, -1); + continue; + } + if (substr($textSpan, -6) === ' ') { + $trailingString = ' ' . $trailingString; + $textSpan = substr($textSpan, 0, -1); + continue; + } + if (substr($textSpan, -3) !== self::UTF8_PDF) { + // There is no trailing numeric string + $textSpan = $savedSpan; + break; + } - // We have a numeric string - $posStartNumber = strrpos($textSpan, self::UTF8_LRE); - if ($posStartNumber === false) { - $posStartNumber = 0; - } - $trailingString = substr($textSpan, $posStartNumber, strlen($textSpan) - $posStartNumber) . $trailingString; - $textSpan = substr($textSpan, 0, $posStartNumber); + // We have a numeric string + $posStartNumber = strrpos($textSpan, self::UTF8_LRE); + if ($posStartNumber === false) { + $posStartNumber = 0; + } + $trailingString = substr($textSpan, $posStartNumber, strlen($textSpan) - $posStartNumber) . $trailingString; + $textSpan = substr($textSpan, 0, $posStartNumber); - // Look for more spaces and move them too - while ($textSpan != '') { - if (substr($textSpan, -1) == ' ') { - $trailingString = ' ' . $trailingString; - $textSpan = substr($textSpan, 0, -1); - continue; - } - if (substr($textSpan, -6) == ' ') { - $trailingString = ' ' . $trailingString; - $textSpan = substr($textSpan, 0, -1); - continue; - } - break; - } + // Look for more spaces and move them too + while ($textSpan != '') { + if (substr($textSpan, -1) == ' ') { + $trailingString = ' ' . $trailingString; + $textSpan = substr($textSpan, 0, -1); + continue; + } + if (substr($textSpan, -6) == ' ') { + $trailingString = ' ' . $trailingString; + $textSpan = substr($textSpan, 0, -1); + continue; + } + break; + } - self::$waitingText = $trailingString . self::$waitingText; - break; - } - } + self::$waitingText = $trailingString . self::$waitingText; + break; + } + } - // Trailing " - " needs to be prefixed to the following span - if (!$theEnd && substr('...' . $textSpan, -3) == ' - ') { - $textSpan = substr($textSpan, 0, -3); - self::$waitingText = ' - ' . self::$waitingText; - } + // Trailing " - " needs to be prefixed to the following span + if (!$theEnd && substr('...' . $textSpan, -3) == ' - ') { + $textSpan = substr($textSpan, 0, -3); + self::$waitingText = ' - ' . self::$waitingText; + } - while (I18N::direction() === 'rtl') { - // Look for " - " preceding <RTLbr> and relocate it to the front of the string - $posDashString = strpos($textSpan, ' - <RTLbr>'); - if ($posDashString === false) { - break; - } - $posStringStart = strrpos(substr($textSpan, 0, $posDashString), '<RTLbr>'); - if ($posStringStart === false) { - $posStringStart = 0; - } else { - $posStringStart += 9; - } // Point to the first char following the last <RTLbr> + while (I18N::direction() === 'rtl') { + // Look for " - " preceding <RTLbr> and relocate it to the front of the string + $posDashString = strpos($textSpan, ' - <RTLbr>'); + if ($posDashString === false) { + break; + } + $posStringStart = strrpos(substr($textSpan, 0, $posDashString), '<RTLbr>'); + if ($posStringStart === false) { + $posStringStart = 0; + } else { + $posStringStart += 9; + } // Point to the first char following the last <RTLbr> - $textSpan = substr($textSpan, 0, $posStringStart) . ' - ' . substr($textSpan, $posStringStart, $posDashString - $posStringStart) . substr($textSpan, $posDashString + 3); - } + $textSpan = substr($textSpan, 0, $posStringStart) . ' - ' . substr($textSpan, $posStringStart, $posDashString - $posStringStart) . substr($textSpan, $posDashString + 3); + } - // Strip leading spaces from the RTL text - $countLeadingSpaces = 0; - while ($textSpan != '') { - if (substr($textSpan, 0, 1) == ' ') { - $countLeadingSpaces++; - $textSpan = substr($textSpan, 1); - continue; - } - if (substr($textSpan, 0, 6) == ' ') { - $countLeadingSpaces++; - $textSpan = substr($textSpan, 6); - continue; - } - break; - } + // Strip leading spaces from the RTL text + $countLeadingSpaces = 0; + while ($textSpan != '') { + if (substr($textSpan, 0, 1) == ' ') { + $countLeadingSpaces++; + $textSpan = substr($textSpan, 1); + continue; + } + if (substr($textSpan, 0, 6) == ' ') { + $countLeadingSpaces++; + $textSpan = substr($textSpan, 6); + continue; + } + break; + } - // Strip trailing spaces from the RTL text - $countTrailingSpaces = 0; - while ($textSpan != '') { - if (substr($textSpan, -1) == ' ') { - $countTrailingSpaces++; - $textSpan = substr($textSpan, 0, -1); - continue; - } - if (substr($textSpan, -6) == ' ') { - $countTrailingSpaces++; - $textSpan = substr($textSpan, 0, -6); - continue; - } - break; - } + // Strip trailing spaces from the RTL text + $countTrailingSpaces = 0; + while ($textSpan != '') { + if (substr($textSpan, -1) == ' ') { + $countTrailingSpaces++; + $textSpan = substr($textSpan, 0, -1); + continue; + } + if (substr($textSpan, -6) == ' ') { + $countTrailingSpaces++; + $textSpan = substr($textSpan, 0, -6); + continue; + } + break; + } - // Look for trailing " -", reverse it, and relocate it to the front of the string - if (substr($textSpan, -2) === ' -') { - $posDashString = strlen($textSpan) - 2; - $posStringStart = strrpos(substr($textSpan, 0, $posDashString), '<RTLbr>'); - if ($posStringStart === false) { - $posStringStart = 0; - } else { - $posStringStart += 9; - } // Point to the first char following the last <RTLbr> + // Look for trailing " -", reverse it, and relocate it to the front of the string + if (substr($textSpan, -2) === ' -') { + $posDashString = strlen($textSpan) - 2; + $posStringStart = strrpos(substr($textSpan, 0, $posDashString), '<RTLbr>'); + if ($posStringStart === false) { + $posStringStart = 0; + } else { + $posStringStart += 9; + } // Point to the first char following the last <RTLbr> - $textSpan = substr($textSpan, 0, $posStringStart) . '- ' . substr($textSpan, $posStringStart, $posDashString - $posStringStart) . substr($textSpan, $posDashString + 2); - } + $textSpan = substr($textSpan, 0, $posStringStart) . '- ' . substr($textSpan, $posStringStart, $posDashString - $posStringStart) . substr($textSpan, $posDashString + 2); + } - if ($countLeadingSpaces != 0) { - $newLength = strlen($textSpan) + $countLeadingSpaces; - $textSpan = str_pad($textSpan, $newLength, ' ', (I18N::direction() === 'rtl' ? STR_PAD_LEFT : STR_PAD_RIGHT)); - } - if ($countTrailingSpaces != 0) { - if (I18N::direction() === 'ltr') { - if ($trailingBreaks === '') { - // Move trailing RTL spaces to front of following LTR span - $newLength = strlen(self::$waitingText) + $countTrailingSpaces; - self::$waitingText = str_pad(self::$waitingText, $newLength, ' ', STR_PAD_LEFT); - } - } else { - $newLength = strlen($textSpan) + $countTrailingSpaces; - $textSpan = str_pad($textSpan, $newLength, ' ', STR_PAD_RIGHT); - } - } + if ($countLeadingSpaces != 0) { + $newLength = strlen($textSpan) + $countLeadingSpaces; + $textSpan = str_pad($textSpan, $newLength, ' ', (I18N::direction() === 'rtl' ? STR_PAD_LEFT : STR_PAD_RIGHT)); + } + if ($countTrailingSpaces != 0) { + if (I18N::direction() === 'ltr') { + if ($trailingBreaks === '') { + // Move trailing RTL spaces to front of following LTR span + $newLength = strlen(self::$waitingText) + $countTrailingSpaces; + self::$waitingText = str_pad(self::$waitingText, $newLength, ' ', STR_PAD_LEFT); + } + } else { + $newLength = strlen($textSpan) + $countTrailingSpaces; + $textSpan = str_pad($textSpan, $newLength, ' ', STR_PAD_RIGHT); + } + } - // We're done: finish the span - $textSpan = self::starredName($textSpan, 'RTL'); // Wrap starred name in <u> and </u> tags - $result = $result . $textSpan . self::$endRTL; - } + // We're done: finish the span + $textSpan = self::starredName($textSpan, 'RTL'); // Wrap starred name in <u> and </u> tags + $result = $result . $textSpan . self::$endRTL; + } - if (self::$currentState != 'LTR' && self::$currentState != 'RTL') { - $result = $result . $textSpan; - } + if (self::$currentState != 'LTR' && self::$currentState != 'RTL') { + $result = $result . $textSpan; + } - $result .= $trailingBreaks; // Get rid of any waiting <br> - } + $result .= $trailingBreaks; // Get rid of any waiting <br> + } - /** - * Wrap text, similar to the PHP wordwrap() function. - * - * @param string $string - * @param int $width - * @param string $sep - * @param bool $cut - * - * @return string - */ - public static function utf8WordWrap($string, $width = 75, $sep = "\n", $cut = false) { - $out = ''; - while ($string) { - if (mb_strlen($string) <= $width) { - // Do not wrap any text that is less than the output area. - $out .= $string; - $string = ''; - } else { - $sub1 = mb_substr($string, 0, $width + 1); - if (mb_substr($string, mb_strlen($sub1) - 1, 1) == ' ') { - // include words that end by a space immediately after the area. - $sub = $sub1; - } else { - $sub = mb_substr($string, 0, $width); - } - $spacepos = strrpos($sub, ' '); - if ($spacepos === false) { - // No space on line? - if ($cut) { - $out .= $sub . $sep; - $string = mb_substr($string, mb_strlen($sub)); - } else { - $spacepos = strpos($string, ' '); - if ($spacepos === false) { - $out .= $string; - $string = ''; - } else { - $out .= substr($string, 0, $spacepos) . $sep; - $string = substr($string, $spacepos + 1); - } - } - } else { - // Split at space; - $out .= substr($string, 0, $spacepos) . $sep; - $string = substr($string, $spacepos + 1); - } - } - } + /** + * Wrap text, similar to the PHP wordwrap() function. + * + * @param string $string + * @param int $width + * @param string $sep + * @param bool $cut + * + * @return string + */ + public static function utf8WordWrap($string, $width = 75, $sep = "\n", $cut = false) + { + $out = ''; + while ($string) { + if (mb_strlen($string) <= $width) { + // Do not wrap any text that is less than the output area. + $out .= $string; + $string = ''; + } else { + $sub1 = mb_substr($string, 0, $width + 1); + if (mb_substr($string, mb_strlen($sub1) - 1, 1) == ' ') { + // include words that end by a space immediately after the area. + $sub = $sub1; + } else { + $sub = mb_substr($string, 0, $width); + } + $spacepos = strrpos($sub, ' '); + if ($spacepos === false) { + // No space on line? + if ($cut) { + $out .= $sub . $sep; + $string = mb_substr($string, mb_strlen($sub)); + } else { + $spacepos = strpos($string, ' '); + if ($spacepos === false) { + $out .= $string; + $string = ''; + } else { + $out .= substr($string, 0, $spacepos) . $sep; + $string = substr($string, $spacepos + 1); + } + } + } else { + // Split at space; + $out .= substr($string, 0, $spacepos) . $sep; + $string = substr($string, $spacepos + 1); + } + } + } - return $out; - } + return $out; + } } |
