WebCore:
authorrjw <rjw@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 23 Mar 2005 19:49:41 +0000 (19:49 +0000)
committerrjw <rjw@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 23 Mar 2005 19:49:41 +0000 (19:49 +0000)
Fixed <rdar://problem/4053515> REGRESSION (Mail): Kotoeri input method reconversion does not work in WebViews

We now use actual document NSRanges to represent both marked text
ranges and selection ranges.

        Reviewed by Ken.

        * khtml/editing/visible_text.cpp:
        (khtml::TextIterator::rangeLength):
        (khtml::TextIterator::setRangeFromLocationAndLength):
        * khtml/editing/visible_text.h:
        * kwq/WebCoreBridge.h:
        * kwq/WebCoreBridge.mm:
        (-[WebCoreBridge convertToNSRange:DOM::]):
        (-[WebCoreBridge DOM::convertToDOMRange:]):
        (-[WebCoreBridge selectNSRange:]):
        (-[WebCoreBridge markedTextDOMRange]):
        (-[WebCoreBridge markedTextNSRange]):

WebKit:
Fixed <rdar://problem/4053515> REGRESSION (Mail): Kotoeri input method reconversion does not work in WebViews

We now use actual document NSRanges to represent both marked text
ranges and selection ranges.

        Reviewed by Ken Kocienda.

        * WebView.subproj/WebHTMLView.m:
        (-[WebHTMLView validAttributesForMarkedText]):
        (-[WebHTMLView firstRectForCharacterRange:]):
        (-[WebHTMLView selectedRange]):
        (-[WebHTMLView markedRange]):
        (-[WebHTMLView _selectMarkedText]):
        (-[WebHTMLView setMarkedText:selectedRange:]):

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

WebCore/ChangeLog-2005-08-23
WebCore/khtml/editing/visible_text.cpp
WebCore/khtml/editing/visible_text.h
WebCore/kwq/WebCoreBridge.h
WebCore/kwq/WebCoreBridge.mm
WebKit/ChangeLog
WebKit/WebView.subproj/WebHTMLView.m

index d52453918fab0de6841dba59231d2ff0014cc5ba..5081ec34fd6f90e5ee2b8cf91e488ef610481598 100644 (file)
@@ -1,3 +1,24 @@
+2005-03-23  Richard Williamson   <rjw@apple.com>
+
+       Fixed <rdar://problem/4053515> REGRESSION (Mail): Kotoeri input method reconversion does not work in WebViews
+
+       We now use actual document NSRanges to represent both marked text
+       ranges and selection ranges.
+
+        Reviewed by Ken.
+
+        * khtml/editing/visible_text.cpp:
+        (khtml::TextIterator::rangeLength):
+        (khtml::TextIterator::setRangeFromLocationAndLength):
+        * khtml/editing/visible_text.h:
+        * kwq/WebCoreBridge.h:
+        * kwq/WebCoreBridge.mm:
+        (-[WebCoreBridge convertToNSRange:DOM::]):
+        (-[WebCoreBridge DOM::convertToDOMRange:]):
+        (-[WebCoreBridge selectNSRange:]):
+        (-[WebCoreBridge markedTextDOMRange]):
+        (-[WebCoreBridge markedTextNSRange]):
+
 2005-03-22  Kevin Decker  <kdecker@apple.com>
 
         Reviewed by Vicki.
index a2e66f628a989d62fecde50ba961d2d50c1c6386..4817e526f2622ef8ada43a849b6bf8fa99dbd3da 100644 (file)
@@ -978,6 +978,36 @@ bool CircularSearchBuffer::isMatch() const
         && memcmp(m_buffer, m_target.unicode() + tailSpace, headSpace * sizeof(QChar)) == 0;
 }
 
+long TextIterator::rangeLength(const Range &r)
+{
+    // Allocate string at the right size, rather than building it up by successive append calls.
+    long length = 0;
+    for (TextIterator it(r); !it.atEnd(); it.advance()) {
+        length += it.length();
+    }
+    return length;
+}
+
+void TextIterator::setRangeFromLocationAndLength (const Range &range, Range &resultRange, long rangeLocation, long rangeLength)
+{
+    long docTextPosition = 0;
+    long rangeEnd = rangeLocation + rangeLength;
+
+    for (TextIterator it(range); !it.atEnd(); it.advance()) {
+        long len = it.length();
+        if (rangeLocation >= docTextPosition && rangeLocation < docTextPosition + len) {
+            resultRange.setStart(it.m_node, rangeLocation - docTextPosition);
+        }
+        if (rangeEnd >= docTextPosition && rangeEnd <= docTextPosition + len) {
+            if ( !(rangeLength == 0 && rangeEnd == docTextPosition + len) ) {
+                resultRange.setEnd(it.m_node, rangeEnd - docTextPosition);
+                break;
+            }
+        }
+        docTextPosition += it.length();
+    }
+}
+
 QString plainText(const Range &r)
 {
     // Allocate string at the right size, rather than building it up by successive append calls.
index b652a2929bde2d6def13c34c5ed05cd3e9d36bbc..28d3fb6479cc909be731e48b1e14f0f748c89c2e 100644 (file)
@@ -68,7 +68,10 @@ public:
     const QChar *characters() const { return m_textCharacters; }
     
     DOM::Range range() const;
-        
+     
+    static long TextIterator::rangeLength(const DOM::Range &r);
+    static void TextIterator::setRangeFromLocationAndLength (const DOM::Range &range, DOM::Range &resultRange, long rangeLocation, long rangeLength);
+    
 private:
     void exitNode();
     bool handleTextNode();
index 473ee4d4063f44015a9ddb3d061145dde8ff6cd5..f6cfd06b44e6ccd8fd3b3903ad1f801fdf1887e8 100644 (file)
@@ -374,6 +374,10 @@ typedef enum {
 - (DOMRange *)smartDeleteRangeForProposedRange:(DOMRange *)proposedCharRange;
 - (void)smartInsertForString:(NSString *)pasteString replacingRange:(DOMRange *)charRangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString;
 - (BOOL)canDeleteRange:(DOMRange *)range;
+- (void)selectNSRange:(NSRange)range;
+- (NSRange)selectedNSRange;
+- (NSRange)markedTextNSRange;
+- (DOMRange *)convertToObjCDOMRange:(NSRange)range;
 
 - (DOMDocumentFragment *)documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString;
 - (DOMDocumentFragment *)documentFragmentWithText:(NSString *)text;
index 1070969c489fd2f5f8c9a3eb1ba43c0371f24a81..e3660865c78ab1fc950b86e793d93de692d3b935 100644 (file)
@@ -56,6 +56,7 @@
 #import "render_style.h"
 #import "selection.h"
 #import "visible_position.h"
+#import "visible_text.h"
 #import "visible_units.h"
 #import "xml_tokenizer.h"
 
@@ -129,6 +130,7 @@ using khtml::ReplaceSelectionCommand;
 using khtml::Selection;
 using khtml::setAffinityUsingLinePosition;
 using khtml::Tokenizer;
+using khtml::TextIterator;
 using khtml::TypingCommand;
 using khtml::UPSTREAM;
 using khtml::VisiblePosition;
@@ -1624,6 +1626,52 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     return [DOMRange _rangeWithImpl:_part->selection().toRange().handle()];
 }
 
+- (NSRange)convertToNSRange:(DOM::RangeImpl *)drange
+{
+    Range toStartRange, toEndRange;
+    Range actualRange = Range(drange);
+    long startPosition, endPosition;
+
+    toStartRange = Range (_part->xmlDocImpl()->createRange());
+    toStartRange.setEnd (actualRange.startContainer(), actualRange.startOffset());
+    toEndRange = Range (_part->xmlDocImpl()->createRange());
+    toEndRange.setEnd (actualRange.endContainer(), actualRange.endOffset());
+    
+    startPosition = TextIterator::rangeLength (toStartRange);
+    endPosition = TextIterator::rangeLength (toEndRange);
+    
+    return NSMakeRange(startPosition, endPosition - startPosition);
+}
+
+- (DOM::Range)convertToDOMRange:(NSRange)nsrange
+{
+    // Set the range to cover the entire document.  This assumes that the start
+    // and end node of the range are the document node.
+    DOM::Range docRange = Range (_part->xmlDocImpl()->createRange());
+    docRange.setEnd (docRange.endContainer(), docRange.endContainer().handle()->childNodeCount());
+
+    DOM::Range resultRange = Range (_part->xmlDocImpl()->createRange());
+    TextIterator::setRangeFromLocationAndLength (docRange, resultRange, nsrange.location, nsrange.length);
+    
+    return resultRange;
+}
+
+- (DOMRange *)convertToObjCDOMRange:(NSRange)nsrange
+{
+    return [DOMRange _rangeWithImpl:[self convertToDOMRange:nsrange].handle()];
+}
+
+- (void)selectNSRange:(NSRange)range
+{
+    DOM::Range replaceRange = [self convertToDOMRange:range];
+    _part->setSelection(Selection(replaceRange.handle(), khtml::SEL_DEFAULT_AFFINITY, khtml::SEL_DEFAULT_AFFINITY));
+}
+
+- (NSRange)selectedNSRange
+{
+    return [self convertToNSRange:_part->selection().toRange().handle()];
+}
+
 - (NSSelectionAffinity)selectionAffinity
 {
     return static_cast<NSSelectionAffinity>(_part->selection().startAffinity());
@@ -1649,6 +1697,11 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     return [DOMRange _rangeWithImpl:_part->markedTextRange().handle()];
 }
 
+- (NSRange)markedTextNSRange
+{
+    return [self convertToNSRange:_part->markedTextRange().handle()];
+}
+
 - (void)replaceMarkedTextWithText:(NSString *)text
 {
     if (!partHasSelection(self))
index dfaccabfda590b719641051a702fd52924e3ac34..5b77ef681255f8886f9d8781a689e6e26674bb67 100644 (file)
@@ -1,3 +1,20 @@
+2005-03-23  Richard Williamson   <rjw@apple.com>
+
+       Fixed <rdar://problem/4053515> REGRESSION (Mail): Kotoeri input method reconversion does not work in WebViews
+
+       We now use actual document NSRanges to represent both marked text
+       ranges and selection ranges.
+
+        Reviewed by Ken Kocienda.
+
+        * WebView.subproj/WebHTMLView.m:
+        (-[WebHTMLView validAttributesForMarkedText]):
+        (-[WebHTMLView firstRectForCharacterRange:]):
+        (-[WebHTMLView selectedRange]):
+        (-[WebHTMLView markedRange]):
+        (-[WebHTMLView _selectMarkedText]):
+        (-[WebHTMLView setMarkedText:selectedRange:]):
+
 === Safari-410 ===
 
 2005-03-22  Darin Adler  <darin@apple.com>
index 8bf88a72355545cc0d77fe314ebf5dc4a2b4d451..805a3263f5206029944fd661bce309654460f687 100644 (file)
@@ -65,6 +65,7 @@
 
 // need to declare this because AppKit does not make it available as API or SPI
 extern NSString *NSMarkedClauseSegmentAttributeName; 
+extern NSString *NSTextInputReplacementRangeAttributeName; 
 
 // Kill ring calls. Would be better to use NSKillRing.h, but that's not available in SPI.
 void _NSInitializeKillRing(void);
@@ -4880,7 +4881,7 @@ static NSArray *validAttributes = nil;
 - (NSArray *)validAttributesForMarkedText
 {
     if (!validAttributes) {
-        validAttributes = [[NSArray allocWithZone:[self zone]] initWithObjects:NSUnderlineStyleAttributeName, NSUnderlineColorAttributeName, NSMarkedClauseSegmentAttributeName, nil];
+        validAttributes = [[NSArray allocWithZone:[self zone]] initWithObjects:NSUnderlineStyleAttributeName, NSUnderlineColorAttributeName, NSMarkedClauseSegmentAttributeName, NSTextInputReplacementRangeAttributeName, nil];
         // NSText also supports the following attributes, but it's
         // hard to tell which are really required for text input to
         // work well; I have not seen any input method make use of them yet.
@@ -4901,48 +4902,34 @@ static NSArray *validAttributes = nil;
 
 - (NSRect)firstRectForCharacterRange:(NSRange)theRange
 {
-    NSRect resultRect = NSMakeRect(0,0,0,0);
     WebBridge *bridge = [self _bridge];
-    DOMRange *rectRange = nil;
     
-    if ([self hasMarkedText]) {
-        rectRange = [[bridge DOMDocument] createRange];
-        DOMRange *markedRange = [bridge markedTextDOMRange];
-        [rectRange setStart:[markedRange startContainer] :theRange.location];
-        [rectRange setEnd:[markedRange startContainer] :(theRange.location + theRange.length)];
-    } else {
-        // no marked text, so use current selection instead
-        // this helps for text input methods that unmark and delete the typed characters,
-        // then put up a word selector at the current insertion point
-        rectRange = [self _selectedRange];
-    }
-
-    if ([rectRange startContainer]) {
-        resultRect = [self convertRect:[bridge firstRectForDOMRange:rectRange] toView:nil];
-        resultRect.origin = [[self window] convertBaseToScreen:resultRect.origin];
-    }
+    DOMRange *range = [bridge convertToObjCDOMRange:theRange];
+    
+    NSRect resultRect = [self convertRect:[bridge firstRectForDOMRange:range] toView:nil];
+    resultRect.origin = [[self window] convertBaseToScreen:resultRect.origin];
     
     return resultRect;
 }
 
 - (NSRange)selectedRange
 {
-    ERROR("TEXTINPUT: selectedRange not yet implemented");
-    return NSMakeRange(0,0);
+    WebBridge *bridge = [self _bridge];
+    
+    NSRange range = [bridge selectedNSRange];
+
+    return range;
 }
 
 - (NSRange)markedRange
 {
     if (![self hasMarkedText]) {
-       return NSMakeRange(NSNotFound,0);
+        return NSMakeRange(NSNotFound,0);
     }
 
-    DOMRange *markedTextDOMRange = [[self _bridge] markedTextDOMRange];
-
-    unsigned rangeLocation = [markedTextDOMRange startOffset];
-    unsigned rangeLength = [markedTextDOMRange endOffset] - rangeLocation;
+    NSRange range = [[self _bridge] markedTextNSRange];
 
-    return NSMakeRange(rangeLocation, rangeLength);
+    return range;
 }
 
 - (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange
@@ -4969,9 +4956,9 @@ static NSArray *validAttributes = nil;
 - (void)_selectMarkedText
 {
     if ([self hasMarkedText]) {
-       WebBridge *bridge = [self _bridge];
-       DOMRange *markedTextRange = [bridge markedTextDOMRange];
-       [bridge setSelectedDOMRange:markedTextRange affinity:NSSelectionAffinityDownstream closeTyping:NO];
+        WebBridge *bridge = [self _bridge];
+        DOMRange *markedTextRange = [bridge markedTextDOMRange];
+        [bridge setSelectedDOMRange:markedTextRange affinity:NSSelectionAffinityDownstream closeTyping:NO];
     }
 }
 
@@ -5016,7 +5003,20 @@ static NSArray *validAttributes = nil;
     WebBridge *bridge = [self _bridge];
 
     if (![self _isEditable])
-       return;
+        return;
+
+    BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; // Otherwise, NSString
+
+    if (isAttributedString) {
+        unsigned markedTextLength = [(NSString *)string length];
+        NSString *rangeString = [string attribute:NSTextInputReplacementRangeAttributeName atIndex:0 longestEffectiveRange:NULL inRange:NSMakeRange(0, markedTextLength)];
+        // The AppKit adds a 'secret' property to the string that contains the replacement
+        // range.  The replacement range is the range of the the text that should be replaced
+        // with the new string.
+        if (rangeString) {
+            [[self _bridge] selectNSRange:NSRangeFromString(rangeString)];
+        }
+    }
 
     _private->ignoreMarkedTextSelectionChange = YES;
 
@@ -5027,11 +5027,11 @@ static NSArray *validAttributes = nil;
     NSString *text;
     NSArray *attributes = nil;
     NSArray *ranges = nil;
-    if ([string isKindOfClass:[NSAttributedString class]]) {
-       text = [string string];
+    if (isAttributedString) {
+        text = [string string];
         [self _extractAttributes:&attributes ranges:&ranges fromAttributedString:string];
     } else {
-       text = string;
+        text = string;
     }
 
     [bridge replaceMarkedTextWithText:text];