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/ChangeLog-2005-08-23 b/WebCore/ChangeLog-2005-08-23
index a6777ab..49f407b 100644
--- a/WebCore/ChangeLog-2005-08-23
+++ b/WebCore/ChangeLog-2005-08-23
@@ -1,6 +1,40 @@
2004-10-05 Ken Kocienda <kocienda@apple.com>
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.
+
+2004-10-05 Ken Kocienda <kocienda@apple.com>
+
+ Reviewed by Darin
Fix for these bugs:
diff --git a/WebCore/khtml/editing/SelectionController.cpp b/WebCore/khtml/editing/SelectionController.cpp
index b53bc03..55a9e26 100644
--- a/WebCore/khtml/editing/SelectionController.cpp
+++ b/WebCore/khtml/editing/SelectionController.cpp
@@ -618,9 +618,17 @@
}
if (isCaret()) {
- // EDIT FIXME: Enhance call to pass along selection
- // upstream/downstream affinity to get the right position.
- m_caretRect = m_start.node()->renderer()->caretRect(m_start.offset(), false);
+ Position pos = m_start;
+ pos.node()->getDocument()->updateRendering();
+ switch (m_affinity) {
+ case DOWNSTREAM:
+ pos = VisiblePosition(m_start).deepEquivalent();
+ break;
+ case UPSTREAM:
+ pos = VisiblePosition(m_start).upstreamDeepEquivalent();
+ break;
+ }
+ m_caretRect = pos.node()->renderer()->caretRect(pos.offset(), false);
m_expectedVisibleRect = m_caretRect;
}
else {
diff --git a/WebCore/khtml/editing/selection.cpp b/WebCore/khtml/editing/selection.cpp
index b53bc03..55a9e26 100644
--- a/WebCore/khtml/editing/selection.cpp
+++ b/WebCore/khtml/editing/selection.cpp
@@ -618,9 +618,17 @@
}
if (isCaret()) {
- // EDIT FIXME: Enhance call to pass along selection
- // upstream/downstream affinity to get the right position.
- m_caretRect = m_start.node()->renderer()->caretRect(m_start.offset(), false);
+ Position pos = m_start;
+ pos.node()->getDocument()->updateRendering();
+ switch (m_affinity) {
+ case DOWNSTREAM:
+ pos = VisiblePosition(m_start).deepEquivalent();
+ break;
+ case UPSTREAM:
+ pos = VisiblePosition(m_start).upstreamDeepEquivalent();
+ break;
+ }
+ m_caretRect = pos.node()->renderer()->caretRect(pos.offset(), false);
m_expectedVisibleRect = m_caretRect;
}
else {
diff --git a/WebCore/khtml/editing/visible_position.cpp b/WebCore/khtml/editing/visible_position.cpp
index d5c8b92..ff634fc 100644
--- a/WebCore/khtml/editing/visible_position.cpp
+++ b/WebCore/khtml/editing/visible_position.cpp
@@ -169,12 +169,13 @@
return Position();
Position test = deepEquivalent(pos);
- bool acceptAnyVisiblePosition = !isCandidate(test) || pos.isFirstRenderedPositionOnLine();
+ Position downstreamTest = test.downstream(StayInBlock);
+ bool acceptAnyVisiblePosition = !isCandidate(test);
Position current = test;
while (!atStart(current)) {
current = previousPosition(current);
- if (isCandidate(current) && (acceptAnyVisiblePosition || current.rendersInDifferentPosition(test))) {
+ if (isCandidate(current) && (acceptAnyVisiblePosition || (downstreamTest != current.downstream(StayInBlock)))) {
return current;
}
}
@@ -188,12 +189,13 @@
return Position();
Position test = deepEquivalent(pos);
- bool acceptAnyVisiblePosition = !isCandidate(test) || pos.isLastRenderedPositionOnLine();
+ bool acceptAnyVisiblePosition = !isCandidate(test);
Position current = test;
+ Position downstreamTest = test.downstream(StayInBlock);
while (!atEnd(current)) {
current = nextPosition(current);
- if (isCandidate(current) && (acceptAnyVisiblePosition || current.rendersInDifferentPosition(test))) {
+ if (isCandidate(current) && (acceptAnyVisiblePosition || (downstreamTest != current.downstream(StayInBlock)))) {
return current;
}
}
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);
diff --git a/WebCore/khtml/rendering/break_lines.cpp b/WebCore/khtml/rendering/break_lines.cpp
index 1a2a49a..a1f0686 100644
--- a/WebCore/khtml/rendering/break_lines.cpp
+++ b/WebCore/khtml/rendering/break_lines.cpp
@@ -28,7 +28,7 @@
This function returns true, if the string can bre broken before the
character at position pos in the string s with length len
*/
-bool isBreakable( const QChar *s, int pos, int len)
+bool isBreakable(const QChar *s, int pos, int len, bool breakNBSP)
{
#if !APPLE_CHANGES
const QChar *c = s+pos;
@@ -84,8 +84,8 @@
const QChar *c = s+pos;
unsigned short ch = c->unicode();
- // Newlines are always breakable.
- if (ch == '\n')
+ // Newlines are always breakable, as are non-breaking spaces when breakNBSP is true.
+ if (ch == '\n' || (breakNBSP && ch == 0xa0))
return true;
// If current character, or the previous character aren't simple latin1 then
diff --git a/WebCore/khtml/rendering/break_lines.h b/WebCore/khtml/rendering/break_lines.h
index 312e583..0810f71 100644
--- a/WebCore/khtml/rendering/break_lines.h
+++ b/WebCore/khtml/rendering/break_lines.h
@@ -1,5 +1,5 @@
#include <qstring.h>
namespace khtml {
- bool isBreakable( const QChar *str, int pos, int len );
+ bool isBreakable(const QChar *str, int pos, int len, bool breakNBSP = false);
};
diff --git a/WebCore/khtml/rendering/render_block.h b/WebCore/khtml/rendering/render_block.h
index 271d83d..3bb0274 100644
--- a/WebCore/khtml/rendering/render_block.h
+++ b/WebCore/khtml/rendering/render_block.h
@@ -121,6 +121,7 @@
RootInlineBox* determineEndPosition(RootInlineBox* startBox, BidiIterator& cleanLineStart, int& yPos);
bool matchedEndLine(const BidiIterator& start, const BidiIterator& endLineStart,
RootInlineBox*& endLine, int& endYPos);
+ int skipWhitespace(BidiIterator &, BidiState &);
BidiIterator findNextLineBreak(BidiIterator &start, BidiState &info );
RootInlineBox* constructLine(const BidiIterator& start, const BidiIterator& end);
InlineFlowBox* createLineBoxes(RenderObject* obj);
diff --git a/WebCore/khtml/rendering/render_text.cpp b/WebCore/khtml/rendering/render_text.cpp
index 5dcbee1..0f76007 100644
--- a/WebCore/khtml/rendering/render_text.cpp
+++ b/WebCore/khtml/rendering/render_text.cpp
@@ -720,6 +720,11 @@
// Would be better to somehow derive it once we understand exactly why it's needed.
left += 1;
+ RenderBlock *cb = containingBlock();
+ int availableWidth = cb->lineWidth(height);
+ if (style()->whiteSpace() == NORMAL)
+ left = kMin(left, absx + availableWidth - 1);
+
return QRect(left, top, 1, height);
}