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
+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.
&& 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.
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();
- (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;
#import "render_style.h"
#import "selection.h"
#import "visible_position.h"
+#import "visible_text.h"
#import "visible_units.h"
#import "xml_tokenizer.h"
using khtml::Selection;
using khtml::setAffinityUsingLinePosition;
using khtml::Tokenizer;
+using khtml::TextIterator;
using khtml::TypingCommand;
using khtml::UPSTREAM;
using khtml::VisiblePosition;
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());
return [DOMRange _rangeWithImpl:_part->markedTextRange().handle()];
}
+- (NSRange)markedTextNSRange
+{
+ return [self convertToNSRange:_part->markedTextRange().handle()];
+}
+
- (void)replaceMarkedTextWithText:(NSString *)text
{
if (!partHasSelection(self))
+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>
// 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);
- (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.
- (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
- (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];
}
}
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;
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];