diff --git a/lib/line_wrapper.coffee b/lib/line_wrapper.coffee index 25db6581a..8b64fe350 100644 --- a/lib/line_wrapper.coffee +++ b/lib/line_wrapper.coffee @@ -63,19 +63,34 @@ class LineWrapper extends EventEmitter while bk = breaker.nextBreak() word = text.slice(last?.position or 0, bk.position) w = wordWidths[word] ?= @wordWidth word - + # if the word is longer than the whole line, chop it up # TODO: break by grapheme clusters, not JS string characters if w > @lineWidth + @continuedX # make some fake break objects lbk = last fbk = {} - + while word.length # fit as much of the word as possible into the space we have - l = word.length - while w > @spaceLeft and l > 0 - w = @wordWidth word.slice(0, --l) + if w > @spaceLeft + # start our check at the end of our available space - this method is faster than a loop of each character and it resolves + # an issue with long loops when processing massive words, such as a huge number of spaces + l = Math.ceil(@spaceLeft / (w / word.length)) + w = @wordWidth word.slice(0, l) + mightGrow = w <= @spaceLeft and l < word.length + else + l = word.length + mustShrink = w > @spaceLeft and l > 0 + # shrink or grow word as necessary after our near-guess above + while mustShrink or mightGrow + if mustShrink + w = @wordWidth word.slice(0, --l) + mustShrink = w > @spaceLeft and l > 0 + else + w = @wordWidth word.slice(0, ++l) + mustShrink = w > @spaceLeft and l > 0 + mightGrow = w <= @spaceLeft and l < word.length # send a required break unless this is the last piece fbk.required = l < word.length