I needed a simple line wrapping algorithm, so I turned to Wikipedia:
http://en.wikipedia.org/wiki/Line_wrap_and_word_wrap#Minimum_number_of_lines
The greedy algorithm:
1. | SpaceLeft := LineWidth 2. | for each Word in Text 3. | if (Width(Word) + SpaceWidth) > SpaceLeft 4. | insert line break before Word in Text 5. | SpaceLeft := LineWidth - Width(Word) 6. | else 7. | SpaceLeft := SpaceLeft - (Width(Word) + SpaceWidth)
On line #5, when we start a new line and subtract the word width from the available width, shouldn't we also subtract the space width?
5. | SpaceLeft := LineWidth - (Width(Word) + SpaceWidth)
Why is the space width not accounted for on line #5?
-- UPDATE --
Some simple testing.
In each of the images, the first paragraph is created by JavaScript using the above wrapping algorithm (orange outline), and the second paragraph is native-rendered by the browser (blue outline).
Interestingly, this extremely bare-bones algorithm, indeed produces the exact same results as the browser rendering, for text with NO edge cases.
This first image shows that when we use
SpaceLeft := LineWidth - Width(Word)
JS rendering and browser rendering are exactly same.

But the following images (different line widths) show the subtle differences between JS and browser renderings when we use:
SpaceLeft := LineWidth - (Width(Word) + SpaceWidth)

The Code
// function getWidth() uses canvas to calculate the widths
// http://stackoverflow.com/questions/118241/calculate-text-width-with-javascript
var wrap = function(container, text, lineWidth) {
var words = text.split(' ');
var w, x, i, l;
var spaceWidth = getWidth(' ');
var spaceLeft = lineWidth;
var arr = [], line = [];
arr.push(line);
for ( i = 0, l = words.length; i < l; i++ ) {
w = words[i];
x = getWidth(w) + spaceWidth;
if ( x > spaceLeft ) {
line = [];
arr.push(line);
line.push(w);
// this is the case for Wikipedia algorithm
// spaceLeft = lineWidth - getWidth(w);
spaceLeft = lineWidth - x;
}
else {
spaceLeft = spaceLeft - x;
line.push(w);
}
}
for ( i = 0, l = arr.length; i < l; i++ ) {
container.append(
$('<span>').text(arr[i].join(' '))
);
}
};