Reviewed by Anders Carlsson.
authorap@apple.com <ap@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Apr 2011 20:48:10 +0000 (20:48 +0000)
committerap@apple.com <ap@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Apr 2011 20:48:10 +0000 (20:48 +0000)
        REGRESSION (WebKit2): Reverse conversion doesn't work in Kotoeri
        https://bugs.webkit.org/show_bug.cgi?id=58066
        <rdar://problem/8965302>

        * Scripts/webkit2/messages.py:
        * Shared/mac/AttributedString.h: Added.
        * Shared/mac/AttributedString.mm: Added.
        (WebKit::AttributedString::encode):
        (WebKit::AttributedString::decode):
        Added an class that wraps NSAttributedString. As far as I can tell, one can't pass a CF
        or NS object to another process without wrapping it in a C++ one.

        * Shared/mac/ArgumentCodersMac.h: Added.
        * Shared/mac/ArgumentCodersMac.mm: Added.
        Added coders for Foundation objects, similar to ArgumentCodersCF. There are two reasons why
        these are needed:
        1) Even though most Foundation objects are toll free bridged with CF, CFGetTypeID() doesn't
        work properly for them (I've been just getting 1).
        2) NSColor isn't toll free bridged to CF.
        This adds just the types necessary for editing NSAttributedString (and I don't yet know what
        happens with attachments).

        * UIProcess/API/mac/WKView.mm: (-[WKView attributedSubstringFromRange:]):
        * UIProcess/WebPageProxy.h:
        * UIProcess/mac/WebPageProxyMac.mm:
        (WebKit::WebPageProxy::getAttributedSubstringFromRange):
        * WebKit2.xcodeproj/project.pbxproj:
        * WebProcess/WebPage/WebPage.h:
        * WebProcess/WebPage/WebPage.messages.in:
        Boilerplate code for making a sync call to web process.

        * WebProcess/WebPage/mac/WebPageMac.mm: (WebKit::WebPage::getAttributedSubstringFromRange):
        Ported from WebHTMLView.

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

19 files changed:
Source/WebCore/ChangeLog
Source/WebCore/platform/mac/HTMLConverter.h
Source/WebCore/platform/mac/HTMLConverter.mm
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebView/WebHTMLRepresentation.mm
Source/WebKit/mac/WebView/WebHTMLView.mm
Source/WebKit2/ChangeLog
Source/WebKit2/Scripts/webkit2/messages.py
Source/WebKit2/Shared/mac/ArgumentCodersMac.h [new file with mode: 0644]
Source/WebKit2/Shared/mac/ArgumentCodersMac.mm [new file with mode: 0644]
Source/WebKit2/Shared/mac/AttributedString.h [new file with mode: 0644]
Source/WebKit2/Shared/mac/AttributedString.mm [new file with mode: 0644]
Source/WebKit2/UIProcess/API/mac/WKView.mm
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm
Source/WebKit2/WebKit2.xcodeproj/project.pbxproj
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/WebPage.messages.in
Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm

index adbe374..fad5a3c 100644 (file)
@@ -1,3 +1,16 @@
+2011-04-07  Alexey Proskuryakov  <ap@apple.com>
+
+        Reviewed by Anders Carlsson.
+
+        REGRESSION (WebKit2): Reverse conversion doesn't work in Kotoeri
+        https://bugs.webkit.org/show_bug.cgi?id=58066
+        <rdar://problem/8965302>
+
+        * platform/mac/HTMLConverter.h:
+        * platform/mac/HTMLConverter.mm: (+[WebHTMLConverter editingAttributedStringFromRange:]):
+        Changed editingAttributedStringFromRange: to use WebCore::Range instead of DOMRange, since
+        it's now used in WebKit2.
+
 2011-04-07  Andy Estes  <aestes@apple.com>
 
         Reviewed by Darin Adler.
index 86ffd87..3250769 100644 (file)
@@ -27,7 +27,8 @@
 @class DOMRange;
 
 namespace WebCore {
-class DocumentLoader;
+    class DocumentLoader;
+    class Range;
 }
 
 @interface WebHTMLConverter : NSObject {
@@ -85,6 +86,6 @@ class DocumentLoader;
 - (NSAttributedString *)attributedString;
 #endif
 
-+ (NSAttributedString *)editingAttributedStringFromRange:(DOMRange *)range;
++ (NSAttributedString *)editingAttributedStringFromRange:(WebCore::Range*)range;
 @end
 
index e8b7b6e..c0b0ba2 100644 (file)
@@ -55,7 +55,7 @@ static NSFileWrapper *fileWrapperForElement(Element*);
 // Additional control Unicode characters
 const unichar WebNextLineCharacter = 0x0085;
 
-@interface NSTextList (TextListPrivate)
+@interface NSTextList (WebCoreNSTextListDetails)
 + (NSDictionary *)_standardMarkerAttributesForAttributes:(NSDictionary *)attrs;
 @end
 
@@ -64,12 +64,12 @@ const unichar WebNextLineCharacter = 0x0085;
 - (BOOL)ignoresOrientation;
 @end
 
-@interface NSURL (WebDataURL)
+@interface NSURL (WebCoreNSURLDetails)
 // FIXME: What is the reason to use this Foundation method, and not +[NSURL URLWithString:relativeToURL:]?
 + (NSURL *)_web_URLWithString:(NSString *)string relativeToURL:(NSURL *)baseURL;
 @end
 
-@interface WebHTMLConverter(WebHTMLConverterPrivate)
+@interface WebHTMLConverter(WebHTMLConverterInternal)
 
 - (NSString *)_stringForNode:(DOMNode *)node property:(NSString *)key;
 - (NSColor *)_colorForNode:(DOMNode *)node property:(NSString *)key;
@@ -1660,9 +1660,8 @@ static NSInteger _colCompare(id block1, id block2, void *)
 #endif // !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
 
 // This function uses TextIterator, which makes offsets in its result compatible with HTML editing.
-+ (NSAttributedString *)editingAttributedStringFromRange:(DOMRange *)domRange
++ (NSAttributedString *)editingAttributedStringFromRange:(Range*)range
 {
-    Range *range = core(domRange);
     NSMutableAttributedString *string = [[NSMutableAttributedString alloc] init];
     NSUInteger stringLength = 0;
     RetainPtr<NSMutableDictionary> attrs(AdoptNS, [[NSMutableDictionary alloc] init]);
index ac6e73b..24bc135 100644 (file)
@@ -1,3 +1,19 @@
+2011-04-07  Alexey Proskuryakov  <ap@apple.com>
+
+        Reviewed by Anders Carlsson.
+
+        REGRESSION (WebKit2): Reverse conversion doesn't work in Kotoeri
+        https://bugs.webkit.org/show_bug.cgi?id=58066
+        <rdar://problem/8965302>
+
+        * WebView/WebHTMLRepresentation.mm:
+        (-[WebHTMLRepresentation attributedStringFrom:startOffset:to:endOffset:]):
+        * WebView/WebHTMLView.mm:
+        (-[WebHTMLView attributedSubstringFromRange:]):
+        (-[WebHTMLView attributedString]):
+        (-[WebHTMLView selectedAttributedString]):
+        Updated for editingAttributedStringFromRange: now taking a WebCore::Range instead of DOMRange.
+
 2011-04-07  Andy Estes  <aestes@apple.com>
 
         Reviewed by Darin Adler.
index aac6f3d..1802ca8 100644 (file)
@@ -277,7 +277,7 @@ static NSArray *concatenateArrays(NSArray *first, NSArray *second)
 
 - (NSAttributedString *)attributedStringFrom:(DOMNode *)startNode startOffset:(int)startOffset to:(DOMNode *)endNode endOffset:(int)endOffset
 {
-    return [WebHTMLConverter editingAttributedStringFromRange:kit(Range::create(core(startNode)->document(), core(startNode), startOffset, core(endNode), endOffset).get())];
+    return [WebHTMLConverter editingAttributedStringFromRange:Range::create(core(startNode)->document(), core(startNode), startOffset, core(endNode), endOffset).get()];
 }
 
 static HTMLFormElement* formElementFromDOMElement(DOMElement *element)
index c64068e..2520061 100644 (file)
@@ -5837,13 +5837,13 @@ static CGPoint coreGraphicsScreenPointForAppKitScreenPoint(NSPoint point)
         LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> nil", nsRange.location, nsRange.length);
         return nil;
     }
-    DOMRange *domRange = [frame _convertNSRangeToDOMRange:nsRange];
-    if (!domRange) {
+    RefPtr<Range> range = [frame _convertToDOMRange:nsRange];
+    if (!range) {
         LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> nil", nsRange.location, nsRange.length);
         return nil;
     }
 
-    NSAttributedString *result = [WebHTMLConverter editingAttributedStringFromRange:domRange];
+    NSAttributedString *result = [WebHTMLConverter editingAttributedStringFromRange:range.get()];
     
     // [WebHTMLConverter editingAttributedStringFromRange:]  insists on inserting a trailing 
     // whitespace at the end of the string which breaks the ATOK input method.  <rdar://problem/5400551>
@@ -6227,7 +6227,7 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
     NSAttributedString *attributedString = [self _attributeStringFromDOMRange:[document _documentRange]];
     if (!attributedString) {
         Document* coreDocument = core(document);
-        attributedString = [WebHTMLConverter editingAttributedStringFromRange:kit(Range::create(coreDocument, coreDocument, 0, coreDocument, coreDocument->childNodeCount()).get())];
+        attributedString = [WebHTMLConverter editingAttributedStringFromRange:Range::create(coreDocument, coreDocument, 0, coreDocument, coreDocument->childNodeCount()).get()];
     }
     return attributedString;
 }
@@ -6244,7 +6244,7 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
         Frame* coreFrame = core([self _frame]);
         if (coreFrame) {
             RefPtr<Range> range = coreFrame->selection()->selection().toNormalizedRange();
-            attributedString = [WebHTMLConverter editingAttributedStringFromRange:kit(range.get())];
+            attributedString = [WebHTMLConverter editingAttributedStringFromRange:range.get()];
         }
     }
     return attributedString;
index c55cdb3..f99f329 100644 (file)
@@ -1,3 +1,41 @@
+2011-04-07  Alexey Proskuryakov  <ap@apple.com>
+
+        Reviewed by Anders Carlsson.
+
+        REGRESSION (WebKit2): Reverse conversion doesn't work in Kotoeri
+        https://bugs.webkit.org/show_bug.cgi?id=58066
+        <rdar://problem/8965302>
+
+        * Scripts/webkit2/messages.py:
+        * Shared/mac/AttributedString.h: Added.
+        * Shared/mac/AttributedString.mm: Added.
+        (WebKit::AttributedString::encode):
+        (WebKit::AttributedString::decode):
+        Added an class that wraps NSAttributedString. As far as I can tell, one can't pass a CF
+        or NS object to another process without wrapping it in a C++ one.
+        
+        * Shared/mac/ArgumentCodersMac.h: Added.
+        * Shared/mac/ArgumentCodersMac.mm: Added.
+        Added coders for Foundation objects, similar to ArgumentCodersCF. There are two reasons why
+        these are needed:
+        1) Even though most Foundation objects are toll free bridged with CF, CFGetTypeID() doesn't
+        work properly for them (I've been just getting 1).
+        2) NSColor isn't toll free bridged to CF.
+        This adds just the types necessary for editing NSAttributedString (and I don't yet know what
+        happens with attachments).
+
+        * UIProcess/API/mac/WKView.mm: (-[WKView attributedSubstringFromRange:]):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/mac/WebPageProxyMac.mm:
+        (WebKit::WebPageProxy::getAttributedSubstringFromRange):
+        * WebKit2.xcodeproj/project.pbxproj:
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+        Boilerplate code for making a sync call to web process.
+
+        * WebProcess/WebPage/mac/WebPageMac.mm: (WebKit::WebPage::getAttributedSubstringFromRange):
+        Ported from WebHTMLView.
+
 2011-04-07  Jeff Miller  <jeffm@apple.com>
 
         Mac build fix.
index 0daffb8..6f6c464 100644 (file)
@@ -262,6 +262,7 @@ def struct_or_class(namespace, type):
         'WebCore::PrintInfo',
         'WebCore::ViewportArguments',
         'WebCore::WindowFeatures',
+        'WebKit::AttributedString',
         'WebKit::ContextMenuState',
         'WebKit::DictionaryPopupInfo',
         'WebKit::DrawingAreaInfo',
diff --git a/Source/WebKit2/Shared/mac/ArgumentCodersMac.h b/Source/WebKit2/Shared/mac/ArgumentCodersMac.h
new file mode 100644 (file)
index 0000000..e83a50f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ArgumentCodersMac_h
+#define ArgumentCodersMac_h
+
+#include <wtf/RetainPtr.h>
+
+namespace CoreIPC {
+
+class ArgumentEncoder;
+class ArgumentDecoder;
+
+// NSAttributedString
+void encode(ArgumentEncoder*, NSAttributedString *);
+bool decode(ArgumentDecoder*, RetainPtr<NSAttributedString>&);
+
+// NSColor
+void encode(ArgumentEncoder*, NSColor *);
+bool decode(ArgumentDecoder*, RetainPtr<NSColor>&);
+
+// NSDictionary
+void encode(ArgumentEncoder*, NSDictionary *);
+bool decode(ArgumentDecoder*, RetainPtr<NSDictionary>&);
+
+// NSFont
+void encode(ArgumentEncoder*, NSFont *);
+bool decode(ArgumentDecoder*, RetainPtr<NSFont>&);
+
+// NSNumber
+void encode(ArgumentEncoder*, NSNumber *);
+bool decode(ArgumentDecoder*, RetainPtr<NSNumber>&);
+
+// NSString
+void encode(ArgumentEncoder*, NSString *);
+bool decode(ArgumentDecoder*, RetainPtr<NSString>&);
+
+}
+
+#endif // ArgumentCodersMac_h
diff --git a/Source/WebKit2/Shared/mac/ArgumentCodersMac.mm b/Source/WebKit2/Shared/mac/ArgumentCodersMac.mm
new file mode 100644 (file)
index 0000000..394f56c
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "ArgumentCodersMac.h"
+
+#import "ArgumentCodersCF.h"
+#import "ArgumentDecoder.h"
+#import "ArgumentEncoder.h"
+#import "WebCoreArgumentCoders.h"
+#import <WebCore/ColorMac.h>
+
+using namespace WebCore;
+using namespace std;
+
+namespace CoreIPC {
+
+enum NSType {
+    NSAttributedStringType,
+    NSColorType,
+    NSDictionaryType,
+    NSFontType,
+    NSNumberType,
+    NSStringType,
+    Unknown,
+};
+
+static NSType typeFromObject(id object)
+{
+    ASSERT(object);
+
+    if ([object isKindOfClass:[NSAttributedString class]])
+        return NSAttributedStringType;
+    if ([object isKindOfClass:[NSColor class]])
+        return NSColorType;
+    if ([object isKindOfClass:[NSDictionary class]])
+        return NSDictionaryType;
+    if ([object isKindOfClass:[NSFont class]])
+        return NSFontType;
+    if ([object isKindOfClass:[NSNumber class]])
+        return NSNumberType;
+    if ([object isKindOfClass:[NSString class]])
+        return NSStringType;
+
+    ASSERT_NOT_REACHED();
+    return Unknown;
+}
+
+static void encode(ArgumentEncoder* encoder, id object)
+{
+    NSType type = typeFromObject(object);
+    encoder->encodeEnum(type);
+
+    switch (type) {
+    case NSAttributedStringType:
+        encode(encoder, static_cast<NSAttributedString *>(object));
+        return;
+    case NSColorType:
+        encode(encoder, static_cast<NSColor *>(object));
+        return;
+    case NSDictionaryType:
+        encode(encoder, static_cast<NSDictionary *>(object));
+        return;
+    case NSFontType:
+        encode(encoder, static_cast<NSFont *>(object));
+        return;
+    case NSNumberType:
+        encode(encoder, static_cast<NSNumber *>(object));
+        return;
+    case NSStringType:
+        encode(encoder, static_cast<NSString *>(object));
+        return;
+    case Unknown:
+        break;
+    }
+
+    ASSERT_NOT_REACHED();
+}
+
+static bool decode(ArgumentDecoder* decoder, RetainPtr<id>& result)
+{
+    NSType type;
+    if (!decoder->decodeEnum(type))
+        return false;
+
+    switch (type) {
+    case NSAttributedStringType: {
+        RetainPtr<NSAttributedString> string;
+        if (!decode(decoder, string))
+            return false;
+        result = string;
+        return true;
+    }
+    case NSColorType: {
+        RetainPtr<NSColor> color;
+        if (!decode(decoder, color))
+            return false;
+        result = color;
+        return true;
+    }
+    case NSDictionaryType: {
+        RetainPtr<NSDictionary> dictionary;
+        if (!decode(decoder, dictionary))
+            return false;
+        result = dictionary;
+        return true;
+    }
+    case NSFontType: {
+        RetainPtr<NSFont> font;
+        if (!decode(decoder, font))
+            return false;
+        result = font;
+        return true;
+    }
+    case NSNumberType: {
+        RetainPtr<NSNumber> number;
+        if (!decode(decoder, number))
+            return false;
+        result = number;
+        return true;
+    }
+    case NSStringType: {
+        RetainPtr<NSString> string;
+        if (!decode(decoder, string))
+            return false;
+        result = string;
+        return true;
+    }
+    case Unknown:
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+
+    return false;
+}
+
+void encode(ArgumentEncoder* encoder, NSAttributedString *string)
+{
+    // Even though NSAttributedString is toll free bridged with CFAttributedStringRef, attributes' values may be not, so we should stay within this file's code.
+
+    NSString *plainString = [string string];
+    NSUInteger length = [plainString length];
+    CoreIPC::encode(encoder, plainString);
+
+    Vector<pair<NSRange, RetainPtr<NSDictionary> > > ranges;
+
+    NSUInteger position = 0;
+    while (position < length) {
+        // Collect ranges in a vector, becasue the total count should be encoded first.
+        NSRange effectiveRange;
+        RetainPtr<NSDictionary> attributesAtIndex = [string attributesAtIndex:position effectiveRange:&effectiveRange];
+        ASSERT(effectiveRange.location == position);
+        ASSERT(effectiveRange.length);
+        ASSERT(NSMaxRange(effectiveRange) <= length);
+
+        ranges.append(make_pair(effectiveRange, attributesAtIndex));
+
+        position = NSMaxRange(effectiveRange);
+    }
+
+    encoder->encodeUInt64(ranges.size());
+
+    for (size_t i = 0; i < ranges.size(); ++i) {
+        encoder->encodeUInt64(ranges[i].first.location);
+        encoder->encodeUInt64(ranges[i].first.length);
+        CoreIPC::encode(encoder, ranges[i].second.get());
+    }
+}
+
+bool decode(ArgumentDecoder* decoder, RetainPtr<NSAttributedString>& result)
+{
+    RetainPtr<NSString> plainString;
+    if (!CoreIPC::decode(decoder, plainString))
+        return false;
+
+    NSUInteger stringLength = [plainString.get() length];
+
+    RetainPtr<NSMutableAttributedString> resultString(AdoptNS, [[NSMutableAttributedString alloc] initWithString:plainString.get()]);
+
+    uint64_t rangeCount;
+    if (!decoder->decode(rangeCount))
+        return false;
+
+    while (rangeCount--) {
+        uint64_t rangeLocation;
+        uint64_t rangeLength;
+        RetainPtr<NSDictionary> attributes;
+        if (!decoder->decode(rangeLocation))
+            return false;
+        if (!decoder->decode(rangeLength))
+            return false;
+
+        ASSERT(rangeLocation + rangeLength > rangeLocation);
+        ASSERT(rangeLocation + rangeLength <= stringLength);
+        if (rangeLocation + rangeLength <= rangeLocation || rangeLocation + rangeLength > stringLength)
+            return false;
+
+        if (!CoreIPC::decode(decoder, attributes))
+            return false;
+        [resultString.get() addAttributes:attributes.get() range:NSMakeRange(rangeLocation, rangeLength)];
+    }
+
+    result.adoptCF(resultString.leakRef());
+    return true;
+}
+
+void encode(ArgumentEncoder* encoder, NSColor *color)
+{
+    encoder->encode(colorFromNSColor(color));
+}
+
+bool decode(ArgumentDecoder* decoder, RetainPtr<NSColor>& result)
+{
+    Color color;
+    if (!decoder->decode(color))
+        return false;
+
+    result = nsColor(color);
+    return true;
+}
+
+void encode(ArgumentEncoder* encoder, NSDictionary *dictionary)
+{
+    // Even though NSDictionary is toll free bridged with CFDictionaryRef, values may be not, so we should stay within this file's code.
+
+    NSUInteger size = [dictionary count];
+    NSArray *keys = [dictionary allKeys];
+    NSArray *values = [dictionary allValues];
+
+    encoder->encodeUInt64(size);
+
+    for (NSUInteger i = 0; i < size; ++i) {
+        id key = [keys objectAtIndex:i];
+        id value = [values objectAtIndex:i];
+        ASSERT(key);
+        ASSERT([key isKindOfClass:[NSString class]]);
+        ASSERT(value);
+
+        // Ignore values we don't recognize.
+        if (typeFromObject(value) == Unknown)
+            continue;
+
+        encode(encoder, (NSString *)key);
+        encode(encoder, value);
+    }
+}
+
+bool decode(ArgumentDecoder* decoder, RetainPtr<NSDictionary>& result)
+{
+    uint64_t size;
+    if (!decoder->decodeUInt64(size))
+        return false;
+
+    RetainPtr<NSMutableDictionary> dictionary(AdoptNS, [[NSMutableDictionary alloc] initWithCapacity:size]);
+    for (uint64_t i = 0; i < size; ++i) {
+        // Try to decode the key name.
+        RetainPtr<NSString> key;
+        if (!decode(decoder, key))
+            return false;
+
+        RetainPtr<id> value;
+        if (!decode(decoder, value))
+            return false;
+
+        [dictionary.get() setObject:value.get() forKey:key.get()];
+    }
+
+    result.adoptCF(dictionary.leakRef());
+    return true;
+}
+
+
+void encode(ArgumentEncoder* encoder, NSFont *font)
+{
+    // NSFont could use CTFontRef code if we had it in ArgumentCodersCF.
+    encode(encoder, [[font fontDescriptor] fontAttributes]);
+}
+
+bool decode(ArgumentDecoder* decoder, RetainPtr<NSFont>& result)
+{
+    RetainPtr<NSDictionary> fontAttributes;
+    if (!decode(decoder, fontAttributes))
+        return false;
+
+    NSFontDescriptor *fontDescriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:fontAttributes.get()];
+    result = [NSFont fontWithDescriptor:fontDescriptor size:0];
+
+    return true;
+}
+
+void encode(ArgumentEncoder* encoder, NSNumber *number)
+{
+    encode(encoder, (CFNumberRef)number);
+}
+
+bool decode(ArgumentDecoder* decoder, RetainPtr<NSNumber>& result)
+{
+    RetainPtr<CFNumberRef> number;
+    if (!decode(decoder, number))
+        return false;
+
+    result.adoptCF((NSNumber *)number.leakRef());
+    return true;
+}
+
+void encode(ArgumentEncoder* encoder, NSString *string)
+{
+    encode(encoder, (CFStringRef)string);
+}
+
+bool decode(ArgumentDecoder* decoder, RetainPtr<NSString>& result)
+{
+    RetainPtr<CFStringRef> string;
+    if (!decode(decoder, string))
+        return false;
+
+    result.adoptCF((NSString *)string.leakRef());
+    return true;
+}
+
+}
diff --git a/Source/WebKit2/Shared/mac/AttributedString.h b/Source/WebKit2/Shared/mac/AttributedString.h
new file mode 100644 (file)
index 0000000..6c8a8ae
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AttributedString_h
+#define AttributedString_h
+
+#include <wtf/RetainPtr.h>
+
+OBJC_CLASS NSAttributedString;
+
+namespace CoreIPC {
+    class ArgumentDecoder;
+    class ArgumentEncoder;
+}
+
+namespace WebKit {
+
+struct AttributedString {
+    void encode(CoreIPC::ArgumentEncoder*) const;
+    static bool decode(CoreIPC::ArgumentDecoder*, AttributedString&);
+    
+    RetainPtr<NSAttributedString> string;
+};
+
+}
+
+#endif // AttributedString_h
diff --git a/Source/WebKit2/Shared/mac/AttributedString.mm b/Source/WebKit2/Shared/mac/AttributedString.mm
new file mode 100644 (file)
index 0000000..5ecc302
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "AttributedString.h"
+
+#import "ArgumentCodersMac.h"
+
+namespace WebKit {
+
+void AttributedString::encode(CoreIPC::ArgumentEncoder* encoder) const
+{
+    CoreIPC::encode(encoder, string.get());
+}
+
+bool AttributedString::decode(CoreIPC::ArgumentDecoder* decoder, AttributedString& attributedString)
+{
+    return CoreIPC::decode(decoder, attributedString.string);
+}
+
+} // namespace WebKit
index 73aa535..7c15449 100644 (file)
@@ -26,6 +26,7 @@
 #import "config.h"
 #import "WKView.h"
 
+#import "AttributedString.h"
 #import "ChunkedUpdateDrawingAreaProxy.h"
 #import "DataReference.h"
 #import "DrawingAreaProxyImpl.h"
@@ -1364,9 +1365,17 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
 {
     [self _executeSavedKeypressCommands];
 
-    // This is not implemented for now. Need to figure out how to serialize the attributed string across processes.
-    LOG(TextInput, "attributedSubstringFromRange");
-    return nil;
+    WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
+    if (parameters && !parameters->cachedTextInputState.selectionIsEditable) {
+        LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> nil", nsRange.location, nsRange.length);
+        return nil;
+    }
+
+    AttributedString result;
+    _data->_page->getAttributedSubstringFromRange(nsRange.location, NSMaxRange(nsRange), result);
+
+    LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> \"%@\"", nsRange.location, nsRange.length, [result.string.get() string]);
+    return [[result.string.get() retain] autorelease];
 }
 
 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
index 6868822..cbb1573 100644 (file)
@@ -94,6 +94,7 @@ class WebPageGroup;
 class WebProcessProxy;
 class WebURLRequest;
 class WebWheelEvent;
+struct AttributedString;
 struct DictionaryPopupInfo;
 struct PlatformPopupMenuData;
 struct PrintInfo;
@@ -259,6 +260,7 @@ public:
     bool insertText(const String& text, uint64_t replacementRangeStart, uint64_t replacementRangeEnd, TextInputState& newState);
     void getMarkedRange(uint64_t& location, uint64_t& length);
     void getSelectedRange(uint64_t& location, uint64_t& length);
+    void getAttributedSubstringFromRange(uint64_t location, uint64_t length, AttributedString&);
     uint64_t characterIndexForPoint(const WebCore::IntPoint);
     WebCore::IntRect firstRectForCharacterRange(uint64_t, uint64_t);
     bool executeKeypressCommands(const Vector<WebCore::KeypressCommand>&, TextInputState& newState);
index 900b1b5..0517bab 100644 (file)
@@ -26,6 +26,7 @@
 #import "config.h"
 #import "WebPageProxy.h"
 
+#import "AttributedString.h"
 #import "DataReference.h"
 #import "DictionaryPopupInfo.h"
 #import "NativeWebKeyboardEvent.h"
@@ -167,6 +168,11 @@ void WebPageProxy::getSelectedRange(uint64_t& location, uint64_t& length)
     process()->sendSync(Messages::WebPage::GetSelectedRange(), Messages::WebPage::GetSelectedRange::Reply(location, length), m_pageID);
 }
 
+void WebPageProxy::getAttributedSubstringFromRange(uint64_t location, uint64_t length, AttributedString& result)
+{
+    process()->sendSync(Messages::WebPage::GetAttributedSubstringFromRange(location, length), Messages::WebPage::GetAttributedSubstringFromRange::Reply(result), m_pageID);
+}
+
 uint64_t WebPageProxy::characterIndexForPoint(const IntPoint point)
 {
     uint64_t result;
index a953347..e34ed6b 100644 (file)
                D3B9484911FF4B6500032B39 /* WebSearchPopupMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = D3B9484511FF4B6500032B39 /* WebSearchPopupMenu.h */; };
                E134F01712EA5D33004EC58D /* WKPrintingView.h in Headers */ = {isa = PBXBuildFile; fileRef = E134F01512EA5D11004EC58D /* WKPrintingView.h */; };
                E134F01A12EA5D99004EC58D /* WKPrintingView.mm in Sources */ = {isa = PBXBuildFile; fileRef = E134F01912EA5D99004EC58D /* WKPrintingView.mm */; };
+               E179FD9C134D38060015B883 /* ArgumentCodersMac.h in Headers */ = {isa = PBXBuildFile; fileRef = E179FD9B134D38060015B883 /* ArgumentCodersMac.h */; };
+               E179FD9F134D38250015B883 /* ArgumentCodersMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = E179FD9E134D38250015B883 /* ArgumentCodersMac.mm */; };
                E1839349134297A5001842EC /* TextInputState.h in Headers */ = {isa = PBXBuildFile; fileRef = E1839348134297A5001842EC /* TextInputState.h */; };
                E18C92F412DB9E7100CF2AEB /* PrintInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E18C92F312DB9E7100CF2AEB /* PrintInfo.cpp */; };
+               E1A31732134CEA6C007C9A4F /* AttributedString.h in Headers */ = {isa = PBXBuildFile; fileRef = E1A31731134CEA6C007C9A4F /* AttributedString.h */; };
+               E1A31735134CEA80007C9A4F /* AttributedString.mm in Sources */ = {isa = PBXBuildFile; fileRef = E1A31734134CEA80007C9A4F /* AttributedString.mm */; };
                E1BB16A413201B9B00F49431 /* FullKeyboardAccessWatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = E1BB1688132018BA00F49431 /* FullKeyboardAccessWatcher.h */; };
                E1BB16A513201B9B00F49431 /* FullKeyboardAccessWatcher.mm in Sources */ = {isa = PBXBuildFile; fileRef = E1BB1689132018BA00F49431 /* FullKeyboardAccessWatcher.mm */; };
                E1CC1B9012D7EADF00625838 /* PrintInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = E1CC1B8E12D7EADF00625838 /* PrintInfo.h */; };
                D3B9484511FF4B6500032B39 /* WebSearchPopupMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSearchPopupMenu.h; sourceTree = "<group>"; };
                E134F01512EA5D11004EC58D /* WKPrintingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKPrintingView.h; sourceTree = "<group>"; };
                E134F01912EA5D99004EC58D /* WKPrintingView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKPrintingView.mm; sourceTree = "<group>"; };
+               E179FD9B134D38060015B883 /* ArgumentCodersMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArgumentCodersMac.h; sourceTree = "<group>"; };
+               E179FD9E134D38250015B883 /* ArgumentCodersMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ArgumentCodersMac.mm; sourceTree = "<group>"; };
                E1839348134297A5001842EC /* TextInputState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextInputState.h; sourceTree = "<group>"; };
                E18C92F312DB9E7100CF2AEB /* PrintInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PrintInfo.cpp; sourceTree = "<group>"; };
+               E1A31731134CEA6C007C9A4F /* AttributedString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AttributedString.h; sourceTree = "<group>"; };
+               E1A31734134CEA80007C9A4F /* AttributedString.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AttributedString.mm; sourceTree = "<group>"; };
                E1BB1688132018BA00F49431 /* FullKeyboardAccessWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FullKeyboardAccessWatcher.h; sourceTree = "<group>"; };
                E1BB1689132018BA00F49431 /* FullKeyboardAccessWatcher.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = FullKeyboardAccessWatcher.mm; sourceTree = "<group>"; };
                E1CC1B8E12D7EADF00625838 /* PrintInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrintInfo.h; sourceTree = "<group>"; };
                BC111B5A112F628200337BAB /* mac */ = {
                        isa = PBXGroup;
                        children = (
+                               E179FD9B134D38060015B883 /* ArgumentCodersMac.h */,
+                               E179FD9E134D38250015B883 /* ArgumentCodersMac.mm */,
+                               E1A31731134CEA6C007C9A4F /* AttributedString.h */,
+                               E1A31734134CEA80007C9A4F /* AttributedString.mm */,
                                1A6F9FB611E1408500DB1371 /* CommandLineMac.cpp */,
                                1A9639F512F38ECD0078A062 /* CoreAnimationRenderer.h */,
                                1A9639F612F38ECD0078A062 /* CoreAnimationRenderer.mm */,
                                51834593134532E90092B696 /* WebIconDatabaseClient.h in Headers */,
                                E1839349134297A5001842EC /* TextInputState.h in Headers */,
                                C0FA52431345694A0028E8C2 /* LayerTreeHostCAMac.h in Headers */,
+                               E1A31732134CEA6C007C9A4F /* AttributedString.h in Headers */,
+                               E179FD9C134D38060015B883 /* ArgumentCodersMac.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                F6A90813133C20510082C3F4 /* WebCookieManagerMac.mm in Sources */,
                                F6D632BC133D198200743D77 /* WebCookieManagerProxyMac.mm in Sources */,
                                51834592134532E90092B696 /* WebIconDatabaseClient.cpp in Sources */,
+                               E1A31735134CEA80007C9A4F /* AttributedString.mm in Sources */,
+                               E179FD9F134D38250015B883 /* ArgumentCodersMac.mm in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index e02ba9c..ee9ec83 100644 (file)
@@ -104,6 +104,7 @@ class WebOpenPanelResultListener;
 class WebPageGroupProxy;
 class WebPopupMenu;
 class WebWheelEvent;
+struct AttributedString;
 struct PrintInfo;
 struct TextInputState;
 struct WebPageCreationParameters;
@@ -312,6 +313,7 @@ public:
     void insertText(const String& text, uint64_t replacementRangeStart, uint64_t replacementRangeEnd, bool& handled, TextInputState& newState);
     void getMarkedRange(uint64_t& location, uint64_t& length);
     void getSelectedRange(uint64_t& location, uint64_t& length);
+    void getAttributedSubstringFromRange(uint64_t location, uint64_t length, AttributedString&);
     void characterIndexForPoint(const WebCore::IntPoint point, uint64_t& result);
     void firstRectForCharacterRange(uint64_t location, uint64_t length, WebCore::IntRect& resultRect);
     void executeKeypressCommands(const Vector<WebCore::KeypressCommand>&, bool& handled, TextInputState& newState);
index 1297477..b291317 100644 (file)
@@ -190,6 +190,7 @@ messages -> WebPage {
     InsertText(WTF::String text, uint64_t replacementRangeStart, uint64_t replacementRangeEnd) -> (bool handled, WebKit::TextInputState newState)
     GetMarkedRange() -> (uint64_t location, uint64_t length)
     GetSelectedRange() -> (uint64_t location, uint64_t length)
+    GetAttributedSubstringFromRange(uint64_t location, uint64_t length) -> (WebKit::AttributedString result)
     CharacterIndexForPoint(WebCore::IntPoint point) -> (uint64_t result)
     FirstRectForCharacterRange(uint64_t location, uint64_t length) -> (WebCore::IntRect resultRect)
     ExecuteKeypressCommands(Vector<WebCore::KeypressCommand> savedCommands) -> (bool handled, WebKit::TextInputState newState)
index 32f41a2..9f3c547 100644 (file)
@@ -27,6 +27,7 @@
 #import "WebPage.h"
 
 #import "AccessibilityWebPageObject.h"
+#import "AttributedString.h"
 #import "DataReference.h"
 #import "PluginView.h"
 #import "TextInputState.h"
@@ -40,6 +41,7 @@
 #import <WebCore/Frame.h>
 #import <WebCore/FrameView.h>
 #import <WebCore/HitTestResult.h>
+#import <WebCore/HTMLConverter.h>
 #import <WebCore/KeyboardEvent.h>
 #import <WebCore/Page.h>
 #import <WebCore/PlatformKeyboardEvent.h>
@@ -302,6 +304,34 @@ void WebPage::getSelectedRange(uint64_t& location, uint64_t& length)
     }
 }
 
+void WebPage::getAttributedSubstringFromRange(uint64_t location, uint64_t length, AttributedString& result)
+{
+    NSRange nsRange = NSMakeRange(location, length - location);
+
+    Frame* frame = m_page->focusController()->focusedOrMainFrame();
+    if (!frame)
+        return;
+
+    if (frame->selection()->isNone() || !frame->selection()->isContentEditable() || frame->selection()->isInPasswordField())
+        return;
+
+    RefPtr<Range> range = convertToRange(frame, nsRange);
+    if (!range)
+        return;
+
+    result.string = [WebHTMLConverter editingAttributedStringFromRange:range.get()];
+    NSAttributedString* attributedString = result.string.get();
+    
+    // [WebHTMLConverter editingAttributedStringFromRange:] insists on inserting a trailing 
+    // whitespace at the end of the string which breaks the ATOK input method.  <rdar://problem/5400551>
+    // To work around this we truncate the resultant string to the correct length.
+    if ([attributedString length] > nsRange.length) {
+        ASSERT([attributedString length] == nsRange.length + 1);
+        ASSERT([[attributedString string] characterAtIndex:nsRange.length] == '\n' || [[attributedString string] characterAtIndex:nsRange.length] == ' ');
+        result.string = [attributedString attributedSubstringFromRange:NSMakeRange(0, nsRange.length)];
+    }
+}
+
 void WebPage::characterIndexForPoint(IntPoint point, uint64_t& index)
 {
     index = NSNotFound;