getPartsIterator(); $lines = array(); $line_length = 0; $was_at = 0; // Determine non-wrappable regions. $at = 0; $end = \strlen( $text ); $nobrs = array(); $delta = 0; while ( $at < $end ) { $nobr_at = \strpos( $text, "\u{E0001}", $at ); if ( false === $nobr_at ) { break; } $at = \strpos( $text, "\u{E007F}", $nobr_at ); // Given the bug with formats closing unexpectedly, there may be no closer. // assert( false !== $at ); if ( false === $at ) { $next_br_at = strpos( $text, "\u{E0001}", $nobr_at + 1 ); // This length value is arbitrarily chosen. This is already a degenerate case. $at = false === $next_br_at ? ( $nobr_at + 20 ) : min( $nobr_at + 20, $next_br_at ); } $nobrs[] = array( $nobr_at - $delta, $at - $delta - 4 ); $delta += 8; } $nobr = \array_shift( $nobrs ); $text = str_replace( array( "\u{E0001}", "\u{E007F}" ), '', $text ); $bi->setText( $text ); foreach ( $pi as $part ) { $offset = $bi->current(); $chunk_width = \mb_strwidth( $part ); $width_remaining = $soft_limit - $line_length; if ( $nobr && $offset >= $nobr[1] ) { $nobr = \array_shift( $nobrs ); } $is_unbreakable = $nobr && $offset > $nobr[0] && $offset <= $nobr[1]; if ( $is_unbreakable ) { $line_length += $chunk_width; continue; } // Add trailing non-word content to the previous line. if ( 0 === $line_length && \IntlBreakIterator::WORD_NONE === $bi->getRuleStatus() && \count( $lines ) > 0 && 1 === \preg_match( '~\A[`*_\p{C}\p{P}\p{Z}]*\Z~u', $part ) ) { $lines[ count( $lines ) - 1 ] .= \preg_replace( '~\p{Z}+\Z~u', '', $part ); $was_at = $offset; continue; } if ( $chunk_width < $width_remaining ) { // Is this faster from OOP/speculation than `= $next_width`? $line_length += $chunk_width; continue; } // If it sticks out a little, append it, otherwise start a new line. if ( ( $chunk_width / max( 1, $width_remaining ) ) < $fractional_soft_limit_ratio ) { $line_length += $chunk_width; continue; } // It’s too long, but for now just append it and move on. $lines[] = \substr( $text, $was_at, $offset - $was_at ); $line_length = 0; $was_at = $offset; } if ( $was_at < \strlen( $text ) ) { $lines[] = \substr( $text, $was_at ); } return $lines; }