Part one of fix for <rdar://problem/3757712> REGRESSION (Mail): WebCore does not...
authorrjw <rjw@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Jan 2005 22:51:19 +0000 (22:51 +0000)
committerrjw <rjw@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Jan 2005 22:51:19 +0000 (22:51 +0000)
This patch changes the semantics of next() and previous() on
VisiblePosition to move a grapheme (character cluster) at a
time.  This means that cursor navigation with correctly move
over an entire cluster.

However, the expected behavior for deleting a grapheme is to
delete individual code points, thus decomposing the grapheme
into it constituent parts.  That will be addressed in the next
part of the fix.

        Reviewed by Ken.

        * khtml/editing/visible_position.cpp:
        (khtml::VisiblePosition::previousPosition):
        (khtml::VisiblePosition::nextPosition):
        * khtml/editing/visible_position.h:
        * khtml/rendering/render_object.cpp:
        (RenderObject::previousOffset):
        (RenderObject::nextOffset):
        * khtml/rendering/render_object.h:
        * khtml/rendering/render_text.cpp:
        (RenderText::previousOffset):
        (RenderText::nextOffset):
        (RenderText::findNextInlineTextBox):
        * khtml/rendering/render_text.h:
        * khtml/xml/dom_nodeimpl.cpp:
        (NodeImpl::previousOffset):
        (NodeImpl::nextOffset):
        * khtml/xml/dom_nodeimpl.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@8450 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog-2005-08-23
WebCore/khtml/editing/visible_position.cpp
WebCore/khtml/editing/visible_position.h
WebCore/khtml/rendering/render_object.cpp
WebCore/khtml/rendering/render_object.h
WebCore/khtml/rendering/render_text.cpp
WebCore/khtml/rendering/render_text.h
WebCore/khtml/xml/dom_nodeimpl.cpp
WebCore/khtml/xml/dom_nodeimpl.h

index d49943216a48bab9e88adf231c07c180e7e0d086..902487f1a74c6f2913220e66077f332c458d10f3 100644 (file)
@@ -1,3 +1,37 @@
+2005-01-25  Richard Williamson   <rjw@apple.com>
+
+       Part one of fix for <rdar://problem/3757712> REGRESSION (Mail): WebCore does not allow Devanagari ligature input
+
+       This patch changes the semantics of next() and previous() on
+       VisiblePosition to move a grapheme (character cluster) at a
+       time.  This means that cursor navigation with correctly move
+       over an entire cluster.
+
+       However, the expected behavior for deleting a grapheme is to
+       delete individual code points, thus decomposing the grapheme
+       into it constituent parts.  That will be addressed in the next
+       part of the fix.
+
+        Reviewed by Ken.
+
+        * khtml/editing/visible_position.cpp:
+        (khtml::VisiblePosition::previousPosition):
+        (khtml::VisiblePosition::nextPosition):
+        * khtml/editing/visible_position.h:
+        * khtml/rendering/render_object.cpp:
+        (RenderObject::previousOffset):
+        (RenderObject::nextOffset):
+        * khtml/rendering/render_object.h:
+        * khtml/rendering/render_text.cpp:
+        (RenderText::previousOffset):
+        (RenderText::nextOffset):
+        (RenderText::findNextInlineTextBox):
+        * khtml/rendering/render_text.h:
+        * khtml/xml/dom_nodeimpl.cpp:
+        (NodeImpl::previousOffset):
+        (NodeImpl::nextOffset):
+        * khtml/xml/dom_nodeimpl.h:
+
 2005-01-25  David Harrison  <harrison@apple.com>
 
         Reviewed by Maciej.
index d98871cde02c0482688ef34a97a3688eddb3cdea..375dbd2e86b4dade2f38a0a03ac92fd3a25052f8 100644 (file)
@@ -213,7 +213,8 @@ Position VisiblePosition::previousPosition(const Position &pos)
             result = Position(prevNode, prevNode->maxOffset());
     }
     else {
-        result = Position(pos.node(), pos.offset() - 1);
+        NodeImpl *node = pos.node();
+        result = Position(node, node->previousOffset(pos.offset()));
     }
     
     return result;
@@ -232,7 +233,8 @@ Position VisiblePosition::nextPosition(const Position &pos)
             result = Position(nextNode, 0);
     }
     else {
-        result = Position(pos.node(), pos.offset() + 1);
+        NodeImpl *node = pos.node();
+        result = Position(node, node->nextOffset(pos.offset()));
     }
     
     return result;
index 79571fc3bd9fc5559ea57bb1a6b42292a4863b30..54cb85289032a421c7d80d8af8e5739a511d4260 100644 (file)
@@ -61,6 +61,7 @@ public:
 
     friend bool operator==(const VisiblePosition &a, const VisiblePosition &b);
 
+    // next() and previous() will increment/decrement by a character cluster.
     VisiblePosition next() const;
     VisiblePosition previous() const;
 
index 7dd249240a4e7c089cb8a5f348041ed53dd2630f..272b4c3fcf8b47c884142a8e35769e378ad21148 100644 (file)
@@ -2334,6 +2334,18 @@ unsigned long RenderObject::caretMaxRenderedOffset() const
     return 0;
 }
 
+long RenderObject::previousOffset (long current) const
+{
+    long previousOffset = current - 1;
+    return previousOffset;
+}
+
+long RenderObject::nextOffset (long current) const
+{
+    long nextOffset = current + 1;
+    return nextOffset;
+}
+
 InlineBox *RenderObject::inlineBox(long offset, EAffinity affinity)
 {
     return inlineBoxWrapper();
index b24c1c467061c8404cb4fc5880e1edea02609908..0e0a2e98156954b50b4657a28abb6844d54fda7f 100644 (file)
@@ -833,6 +833,9 @@ public:
     virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
 
+    virtual long previousOffset (long current) const;
+    virtual long nextOffset (long current) const;
+
     virtual void setPixmap(const QPixmap&, const QRect&, CachedImage *);
 
     virtual void selectionStartEnd(int& spos, int& epos);
index e3a9b5607212ea6ea3217f0d9814e8786265cea6..82eeb0ee7ed933d46c210eaec9e87aabc064489e 100644 (file)
 #include <kdebug.h>
 #include <assert.h>
 
+// You may have to turn this to 0 to compile without the headers for ICU installed.
+#define HAVE_ICU_LIBRARY 1
+
+#if HAVE_ICU_LIBRARY
+#include <unicode/ubrk.h>
+#include <unicode/uloc.h>
+#include <unicode/utypes.h>
+#include <unicode/parseerr.h>
+#endif
+
 using namespace khtml;
 using namespace DOM;
 
@@ -666,6 +676,67 @@ unsigned long InlineTextBox::caretMaxRenderedOffset() const
     return m_start + m_len;
 }
 
+long RenderText::previousOffset (long current) const
+{
+#if !HAVE_ICU_LIBRARY
+    long previousOffset = current - 1;
+    return previousOffset;
+#else
+    UErrorCode status = U_ZERO_ERROR;
+    
+    // The locale is currently ignored when determining character cluster breaks.  This may change
+    // in the future (according to Deborah Goldsmith).
+    UBreakIterator* iterator = ubrk_open (UBRK_CHARACTER, "en_us", (const UChar*)str->s, str->l, &status);
+    if (iterator) {
+        // ICU gives us the leading and trailing edges of ligature graphemes, so we determine if
+        // the size of the previous grapheme is larger than 1 (i.e. we have a ligature or some sort),
+        // and if so, move back to the leading edge of the the grapheme, which is the same
+        // as the start of the previous character.
+        long off1 = ubrk_preceding (iterator, current);
+        long off2 = ubrk_preceding (iterator, off1);
+        ubrk_close (iterator);
+        
+        if (off2 >= 0 && off1 - off2 > 1)
+            return off2;
+            
+        return off1;
+    }
+    
+    return current - 1;
+#endif
+}
+
+long RenderText::nextOffset (long current) const
+{
+#if !HAVE_ICU_LIBRARY
+    long nextOffset = current + 1;
+    return nextOffset;
+#else
+    UErrorCode status = U_ZERO_ERROR;
+
+    // The locale is currently ignored when determining character cluster breaks.  This may change
+    // in the future (according to Deborah Goldsmith).
+    UBreakIterator* iterator = ubrk_open (UBRK_CHARACTER, "en_us", (const UChar*)str->s, str->l, &status);
+    if (iterator) {
+        // ICU gives us the leading and trailing edges of ligature graphemes, so we determine if
+        // the size of the next grapheme is larger than 1 (i.e. we have a ligature or some sort),
+        // and if so, move forward to the trailing edge of the the grapheme, which is the same
+        // as the start of the next character.
+        long off1 = ubrk_following (iterator, current);
+        long off2 = ubrk_following (iterator, off1);
+        ubrk_close (iterator);
+        
+        if (off2 >= 0 && off1 - current > 1)
+            return off2;
+
+        return off1;
+    }
+    
+    return current + 1;
+#endif
+}
+
+
 #define LOCAL_WIDTH_BUF_SIZE   1024
 
 int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs)
@@ -827,7 +898,7 @@ void RenderText::absoluteRects(QValueList<QRect>& rects, int _tx, int _ty)
                            box->height()));
 }
 
-InlineTextBox* RenderText::findNextInlineTextBox(int offset, int &pos)
+InlineTextBox* RenderText::findNextInlineTextBox(int offset, int &pos) const
 {
     // The text runs point to parts of the rendertext's str string
     // (they don't include '\n')
index e0696f00eeb0ebca481a3a69a79cf80f2530941c..d9c4190964953bacf9ebbb588f7845dac4fedba2 100644 (file)
@@ -256,11 +256,14 @@ public:
     virtual long caretMinOffset() const;
     virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
+
+    virtual long previousOffset (long current) const;
+    virtual long nextOffset (long current) const;
     
 #if APPLE_CHANGES
 public:
 #endif
-    InlineTextBox * findNextInlineTextBox( int offset, int &pos );
+    InlineTextBox * findNextInlineTextBox( int offset, int &pos ) const;
 
 protected: // members
     DOM::DOMStringImpl *str;
index 583320a9e2105d7a012c5af5fe715cf956e696c0..89122e8ac03a11e87cccd4d4de74eb6569480a11 100644 (file)
@@ -1288,6 +1288,16 @@ unsigned long NodeImpl::caretMaxRenderedOffset() const
     return renderer() ? renderer()->caretMaxRenderedOffset() : 1;
 }
 
+long NodeImpl::previousOffset (long current) const
+{
+    return renderer() ? renderer()->previousOffset(current) : current - 1;
+}
+
+long NodeImpl::nextOffset (long current) const
+{
+    return renderer() ? renderer()->nextOffset(current) : current + 1;
+}
+
 bool NodeImpl::isBlockFlow() const
 {
     return renderer() && renderer()->isBlockFlow();
index 39d932b5abeb41f5d33d5b38d706d7843e382a52..616b200a38b5ede9de5bee791e75b2da88437400 100644 (file)
@@ -350,6 +350,9 @@ public:
     virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
 
+    virtual long previousOffset (long current) const;
+    virtual long nextOffset (long current) const;
+    
 #ifndef NDEBUG
     virtual void dump(QTextStream *stream, QString ind = "") const;
 #endif