@@ -65,7 +65,7 @@ public function wrap(
6565 $ lines [] = $ currentLine ;
6666 }
6767
68- return $ lines === [] ? [ $ text ] : $ lines ;
68+ return $ lines ;
6969 }
7070
7171 private function fitsOnCurrentLine (
@@ -98,14 +98,9 @@ private function appendBrokenWord(
9898 string &$ currentLine ,
9999 ): void {
100100 $ segments = $ this ->breakWord ($ word , $ maxWidth , $ fontAlias , $ fontSize , $ hyphens );
101- $ lastIndex = count ($ segments ) - 1 ;
102-
103- foreach ($ segments as $ index => $ segment ) {
104- if ($ index === $ lastIndex ) {
105- $ currentLine = $ segment ;
106- continue ;
107- }
101+ $ currentLine = array_pop ($ segments ) ?? '' ;
108102
103+ foreach ($ segments as $ segment ) {
109104 $ lines [] = $ segment ;
110105 }
111106 }
@@ -120,7 +115,7 @@ private function breakWord(
120115 float $ fontSize ,
121116 string $ hyphens ,
122117 ): array {
123- if ($ hyphens === 'none ' ) {
118+ if ($ hyphens === 'none ' || ( $ hyphens !== ' manual ' && $ hyphens !== ' auto ' ) ) {
124119 return [$ word ];
125120 }
126121
@@ -129,10 +124,6 @@ private function breakWord(
129124 return $ manualSegments ;
130125 }
131126
132- if ($ hyphens !== 'auto ' ) {
133- return [$ word ];
134- }
135-
136127 return $ this ->breakWordAutomatically ($ word , $ maxWidth , $ fontAlias , $ fontSize );
137128 }
138129
@@ -146,15 +137,17 @@ private function resolveManualBreaks(
146137 float $ fontSize ,
147138 string $ hyphens ,
148139 ): ?array {
149- if ($ hyphens !== 'manual ' || !str_contains ($ word , "\u{00AD}" )) {
140+ if ($ hyphens !== 'manual ' ) {
141+ return null ;
142+ }
143+
144+ if (!str_contains ($ word , "\u{00AD}" )) {
150145 return null ;
151146 }
152147
153148 $ manualBreaks = explode ("\u{00AD}" , $ word );
154149
155- return count ($ manualBreaks ) > 1
156- ? $ this ->packManualSegments ($ manualBreaks , $ maxWidth , $ fontAlias , $ fontSize )
157- : null ;
150+ return $ this ->packManualSegments ($ manualBreaks , $ maxWidth , $ fontAlias , $ fontSize );
158151 }
159152
160153 /**
@@ -166,64 +159,67 @@ private function breakWordAutomatically(
166159 string $ fontAlias ,
167160 float $ fontSize ,
168161 ): array {
162+ $ characters = $ this ->splitCharacters ($ word );
163+ if ($ characters === []) {
164+ return [$ word ];
165+ }
166+
169167 $ segments = [];
170- $ remaining = $ this ->splitCharacters ($ word );
168+ $ hyphenWidth = $ this ->fontMetrics ->measureString ($ fontAlias , $ fontSize , '- ' );
169+ $ offset = 0 ;
170+ $ characterCount = count ($ characters );
171171
172- while ($ remaining !== [] ) {
173- [ ' segment ' => $ segment, ' consumed ' => $ consumed ] = $ this ->resolveAutoSegment (
174- $ remaining ,
172+ while (isset ( $ characters [ $ offset ]) ) {
173+ $ segment = $ this ->resolveAutoSegment (
174+ array_slice ( $ characters , $ offset ) ,
175175 $ maxWidth ,
176176 $ fontAlias ,
177177 $ fontSize ,
178+ $ hyphenWidth ,
178179 );
179180
180- if ($ consumed <= 0 ) {
181- break ;
182- }
183-
184- $ remaining = array_slice ($ remaining , $ consumed );
185- $ segments [] = $ remaining === [] ? $ segment : ($ segment . '- ' );
181+ $ segmentCharacters = $ this ->splitCharacters ($ segment );
182+ $ fallbackCount = count ($ this ->splitCharacters ($ characters [$ offset ]));
183+ $ consumedCount = max (count ($ segmentCharacters ) + $ fallbackCount - 1 , $ fallbackCount );
184+ $ offset = min ($ offset + $ consumedCount , $ characterCount );
185+ $ segments [] = !isset ($ characters [$ offset ]) ? $ segment : ($ segment . '- ' );
186186 }
187187
188- return $ segments === [] ? [ $ word ] : $ segments ;
188+ return $ segments ;
189189 }
190190
191191 /**
192192 * @param list<string> $remaining
193- * @return array{segment: string, consumed: int}
193+ * @return string
194194 */
195195 private function resolveAutoSegment (
196196 array $ remaining ,
197197 float $ maxWidth ,
198198 string $ fontAlias ,
199199 float $ fontSize ,
200- ): array {
200+ float $ hyphenWidth ,
201+ ): string {
201202 $ segment = '' ;
202- $ consumed = 0 ;
203203 $ remainingCount = count ($ remaining );
204204
205205 foreach ($ remaining as $ index => $ character ) {
206206 $ candidate = $ segment . $ character ;
207- $ isLastCharacter = $ index === ($ remainingCount - 1 );
208- $ candidateWidth = $ this ->fontMetrics ->measureString (
209- $ fontAlias ,
210- $ fontSize ,
211- $ candidate . ($ isLastCharacter ? '' : '- ' ),
212- );
207+ $ hasMoreCharacters = ($ index + 1 ) < $ remainingCount ;
208+ $ candidateWidth = $ this ->fontMetrics ->measureString ($ fontAlias , $ fontSize , $ candidate )
209+ + ($ hasMoreCharacters ? $ hyphenWidth : 0.0 );
213210
214211 if ($ candidateWidth > $ maxWidth && $ segment !== '' ) {
215212 break ;
216213 }
217214
218215 if ($ candidateWidth > $ maxWidth ) {
219- return [ ' segment ' => $ character, ' consumed ' => 1 ] ;
216+ return $ character ;
220217 }
221218
222219 $ segment = $ candidate ;
223- $ consumed = $ index + 1 ;
224220 }
225221
226- return [ ' segment ' => $ segment, ' consumed ' => $ consumed ] ;
222+ return $ segment ;
227223 }
228224
229225 /**
@@ -239,13 +235,15 @@ private function packManualSegments(
239235 $ packed = [];
240236 $ current = '' ;
241237 $ lastIndex = count ($ segments ) - 1 ;
238+ $ hyphenWidth = $ this ->fontMetrics ->measureString ($ fontAlias , $ fontSize , '- ' );
242239
243240 foreach ($ segments as $ index => $ segment ) {
244241 $ candidate = $ current . $ segment ;
245- $ candidateWithHyphen = $ candidate . ($ index === $ lastIndex ? '' : '- ' );
242+ $ candidateWidth = $ this ->fontMetrics ->measureString ($ fontAlias , $ fontSize , $ candidate )
243+ + ($ index === $ lastIndex ? 0.0 : $ hyphenWidth );
246244 if (
247245 $ current !== ''
248- && $ this -> fontMetrics -> measureString ( $ fontAlias , $ fontSize , $ candidateWithHyphen ) > $ maxWidth
246+ && $ candidateWidth > $ maxWidth
249247 ) {
250248 $ packed [] = $ current . '- ' ;
251249 $ current = $ segment ;
0 commit comments