Reviewed by Darin

        Use the new CSS properties I added with my previous check-in. Also makes
        some changes to caret positioning and drawing to make the proper editing
        end-of-line behavior work correctly.

        * khtml/editing/selection.cpp:
        (khtml::Selection::layout): Caret drawing now takes affinity into account
        when deciding where to paint the caret (finally!).
        * khtml/editing/visible_position.cpp:
        (khtml::VisiblePosition::previousVisiblePosition): Move off Position::rendersInDifferentPosition
        to determine the result. Use a simpler test involving comparisons between
        downstream positions while iterating. This is cheaper to do and easier to understand.
        (khtml::VisiblePosition::nextVisiblePosition): Ditto.
        * khtml/rendering/bidi.cpp:
        (khtml::BidiIterator::current): Do not return non-breaking spaces for empty
        text renderers and for non-text renderers. Return a null Qchar instead. Returning
        non-breaking spaces was causing errors when the new -khtml-nbsp-mode was set to "space".
        (khtml::RenderBlock::computeHorizontalPositionsForLine): Shrink line boxes that
        contain with more spaces than can fit on the end of a line.
        (khtml::RenderBlock::skipWhitespace): Factor this out from findNextLineBreak.
        (khtml::RenderBlock::findNextLineBreak): Use new skipWhitespace function. Add
        in code to check and use new CSS properties.
        * khtml/rendering/break_lines.cpp:
        (khtml::isBreakable): Consider a non-breaking space a breakable character based
        on setting of new -khtml-nbsp-mode property.
        * khtml/rendering/break_lines.h: Ditto.
        * khtml/rendering/render_block.h: Declare skipWhitespace function.
        * khtml/rendering/render_text.cpp:
        (RenderText::caretRect): Do not draw the caret beyond the right edge of the
        window when in white-space normal mode.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@7764 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/khtml/rendering/bidi.cpp b/WebCore/khtml/rendering/bidi.cpp
index 3cdaa54..10e9893 100644
--- a/WebCore/khtml/rendering/bidi.cpp
+++ b/WebCore/khtml/rendering/bidi.cpp
@@ -340,14 +340,14 @@
 
 const QChar &BidiIterator::current() const
 {
-    static QChar nonBreakingSpace(0xA0);
+    static QChar nullCharacter;
     
     if (!obj || !obj->isText())
-      return nonBreakingSpace;
+      return nullCharacter;
     
     RenderText* text = static_cast<RenderText*>(obj);
     if (!text->text())
-        return nonBreakingSpace;
+        return nullCharacter;
     
     return text->text()[pos];
 }
@@ -717,14 +717,24 @@
 void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, BidiState &bidi)
 {
     // First determine our total width.
+    int availableWidth = lineWidth(m_height);
     int totWidth = lineBox->getFlowSpacingWidth();
     BidiRun* r = 0;
     for (r = sFirstBidiRun; r; r = r->nextRun) {
         if (!r->box || r->obj->isPositioned())
             continue; // Positioned objects are only participating to figure out their
                       // correct static x position.  They have no effect on the width.
-        if (r->obj->isText())
-            r->box->setWidth(static_cast<RenderText *>(r->obj)->width(r->start, r->stop-r->start, m_firstLine));
+        if (r->obj->isText()) {
+            int textWidth = static_cast<RenderText *>(r->obj)->width(r->start, r->stop-r->start, m_firstLine);
+            if (!r->compact) {
+                RenderStyle *style = r->obj->style();
+                if (style->whiteSpace() == NORMAL && style->khtmlLineBreak() == AFTER_WHITE_SPACE) {
+                    // shrink the box as needed to keep the line from overflowing the available width
+                    textWidth = kMin(textWidth, availableWidth - totWidth + style->borderLeftWidth());
+                }
+                r->box->setWidth(textWidth);
+            }
+        }
         else if (!r->obj->isInlineFlow()) {
             r->obj->calcWidth();
             r->box->setWidth(r->obj->width());
@@ -742,7 +752,6 @@
     // objects horizontally.  The total width of the line can be increased if we end up
     // justifying text.
     int x = leftOffset(m_height);
-    int availableWidth = lineWidth(m_height);
     switch(style()->textAlign()) {
         case LEFT:
         case KHTML_LEFT:
@@ -1723,23 +1732,16 @@
     return false;
 }
 
-BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi)
+static const ushort nonBreakingSpace = 0xa0;
+
+int RenderBlock::skipWhitespace(BidiIterator &it, BidiState &bidi)
 {
     int width = lineWidth(m_height);
-    int w = 0;
-    int tmpW = 0;
-#ifdef DEBUG_LINEBREAKS
-    kdDebug(6041) << "findNextLineBreak: line at " << m_height << " line width " << width << endl;
-    kdDebug(6041) << "sol: " << start.obj << " " << start.pos << endl;
-#endif
-
-    // eliminate spaces at beginning of line
-    // remove leading spaces.  Any inline flows we encounter will be empty and should also
-    // be skipped.
-    while (!start.atEnd() && (start.obj->isInlineFlow() || (start.obj->style()->whiteSpace() != PRE && !start.obj->isBR() &&
-          (start.current() == ' ' || start.current() == '\n' || start.obj->isFloatingOrPositioned())))) {
-        if( start.obj->isFloatingOrPositioned() ) {
-            RenderObject *o = start.obj;
+    while (!it.atEnd() && (it.obj->isInlineFlow() || (it.obj->style()->whiteSpace() != PRE && !it.obj->isBR() &&
+          (it.current() == ' ' || it.current() == '\n' || 
+          (it.obj->style()->nbspMode() == SPACE && it.current().unicode() == nonBreakingSpace) || it.obj->isFloatingOrPositioned())))) {
+        if (it.obj->isFloatingOrPositioned()) {
+            RenderObject *o = it.obj;
             // add to special objects...
             if (o->isFloating()) {
                 insertFloatingObject(o);
@@ -1757,9 +1759,24 @@
         }
         
         adjustEmbedding = true;
-        start.increment(bidi);
+        it.increment(bidi);
         adjustEmbedding = false;
     }
+    return width;
+}
+
+BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi)
+{
+    int width = lineWidth(m_height);
+    int w = 0;
+    int tmpW = 0;
+#ifdef DEBUG_LINEBREAKS
+    kdDebug(6041) << "findNextLineBreak: line at " << m_height << " line width " << width << endl;
+    kdDebug(6041) << "sol: " << start.obj << " " << start.pos << endl;
+#endif
+
+    // eliminate spaces at beginning of line
+    width = skipWhitespace(start, bidi);
     
     if ( start.atEnd() ){
         return start;
@@ -1967,11 +1984,12 @@
                 }
                 
                 bool applyWordSpacing = false;
-
-                bool breakWords = w == 0 && o->style()->whiteSpace() == NORMAL && o->style()->wordWrap() == BREAK_WORD;
+                bool isNormal = o->style()->whiteSpace() == NORMAL;
+                bool breakNBSP = isNormal && o->style()->nbspMode() == SPACE;
+                bool breakWords = w == 0 && isNormal && o->style()->wordWrap() == BREAK_WORD;
                 if (breakWords)
                     wrapW += t->width(pos, 1, f);
-                if ((isPre && c == '\n') || (!isPre && isBreakable(str, pos, strlen)) || (breakWords && wrapW > width)) {
+                if ((isPre && c == '\n') || (!isPre && isBreakable(str, pos, strlen, breakNBSP)) || (breakWords && wrapW > width)) {
                     if (ignoringSpaces) {
                         if (!currentCharacterIsSpace) {
                             // Stop ignoring spaces and begin at this
@@ -2023,8 +2041,11 @@
                     }
         
                     if (o->style()->whiteSpace() == NORMAL) {
-                        if (w + tmpW > width)
+                        if (w + tmpW > width) {
+                            if (o->style()->khtmlLineBreak() == AFTER_WHITE_SPACE)
+                                skipWhitespace(lBreak, bidi);
                             goto end; // Didn't fit. Jump to the end.
+                        }
                         else if (pos > 1 && str[pos-1].unicode() == SOFT_HYPHEN)
                             // Subtract the width of the soft hyphen out since we fit on a line.
                             tmpW -= t->width(pos-1, 1, f);