Reviewed by Darin.
authorap@webkit.org <ap@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 6 Mar 2008 17:50:08 +0000 (17:50 +0000)
committerap@webkit.org <ap@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 6 Mar 2008 17:50:08 +0000 (17:50 +0000)
        <rdar://problem/5687269> Need to create a Collator abstraction for WebCore and JavaScriptCore

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

24 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/GNUmakefile.am
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/JavaScriptCore.pri
JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj
JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
JavaScriptCore/JavaScriptCoreSources.bkl
JavaScriptCore/kjs/string_object.cpp
JavaScriptCore/wtf/Threading.h
JavaScriptCore/wtf/ThreadingGtk.cpp
JavaScriptCore/wtf/ThreadingNone.cpp
JavaScriptCore/wtf/ThreadingPthreads.cpp
JavaScriptCore/wtf/ThreadingWin.cpp
JavaScriptCore/wtf/unicode/Collator.h [new file with mode: 0644]
JavaScriptCore/wtf/unicode/CollatorDefault.cpp [new file with mode: 0644]
JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp [new file with mode: 0644]
LayoutTests/ChangeLog
LayoutTests/fast/xsl/sort-locale-expected.txt [new file with mode: 0644]
LayoutTests/fast/xsl/sort-locale.xml [new file with mode: 0644]
LayoutTests/fast/xsl/sort-locale.xsl [new file with mode: 0644]
WebCore/ChangeLog
WebCore/ForwardingHeaders/wtf/unicode/Collator.h [new file with mode: 0644]
WebCore/xml/XSLTUnicodeSort.cpp
WebCore/xml/XSLTUnicodeSort.h

index e9bbd743f88af3b61bfbb765aa18cb62a2f50f14..f73070d9ff56cdf2926319ad97fed3fef792ca11 100644 (file)
@@ -1,3 +1,44 @@
+2008-03-06  Alexey Proskuryakov  <ap@webkit.org>
+
+        Reviewed by Darin.
+
+        <rdar://problem/5687269> Need to create a Collator abstraction for WebCore and JavaScriptCore
+
+        * wtf/Threading.h:
+        (WTF::initializeThreading):
+        * wtf/ThreadingGtk.cpp:
+        (WTF::initializeThreading):
+        * wtf/ThreadingNone.cpp:
+        * wtf/ThreadingPthreads.cpp:
+        * wtf/ThreadingWin.cpp:
+        Added AtomicallyInitializedStatic.
+
+        * kjs/string_object.cpp: (KJS::localeCompare): Changed to use Collator.
+
+        * GNUmakefile.am:
+        * JavaScriptCore.exp:
+        * JavaScriptCore.pri:
+        * JavaScriptCore.vcproj/WTF/WTF.vcproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * JavaScriptCoreSources.bkl:
+        Added new fiiles to projects.
+
+        * wtf/unicode/Collator.h: Added.
+        (WTF::Collator::):
+        * wtf/unicode/CollatorDefault.cpp: Added.
+        (WTF::Collator::Collator):
+        (WTF::Collator::~Collator):
+        (WTF::Collator::setOrderLowerFirst):
+        (WTF::Collator::collate):
+        * wtf/unicode/icu/CollatorICU.cpp: Added.
+        (WTF::cachedCollatorMutex):
+        (WTF::Collator::Collator):
+        (WTF::Collator::~Collator):
+        (WTF::Collator::setOrderLowerFirst):
+        (WTF::Collator::collate):
+        (WTF::Collator::createCollator):
+        (WTF::Collator::releaseCollator):
+
 2008-03-05  Kevin Ollivier  <kevino@theolliviers.com>
 
         Fix the wx build after the bindings move.
index 73afe623fc5f5e7bf9694f8dea081c19120f0237..f76c85bc7e49c409bf202f6bdb5ce2d451bc1235 100644 (file)
@@ -48,6 +48,8 @@ javascriptcore_sources += \
        JavaScriptCore/wtf/Assertions.cpp \
        JavaScriptCore/wtf/HashTable.cpp \
        JavaScriptCore/wtf/ThreadingGtk.cpp \
+       JavaScriptCore/wtf/unicode/CollatorDefault.cpp \
+       JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp \
        JavaScriptCore/wtf/unicode/UTF8.cpp
 
 # Debug build
index 5c951720c998cbda87c10e1d9351886be3ff095c..4a4c68a21436776527d8598cc098a5794c4647ba 100644 (file)
@@ -209,6 +209,7 @@ __ZN3WTF15ThreadConditionC1Ev
 __ZN3WTF15ThreadConditionD1Ev
 __ZN3WTF16fastZeroedMallocEm
 __ZN3WTF23waitForThreadCompletionEjPPv
+__ZN3WTF32atomicallyInitializedStaticMutexE
 __ZN3WTF5Mutex4lockEv
 __ZN3WTF5Mutex6unlockEv
 __ZN3WTF5Mutex7tryLockEv
@@ -267,8 +268,11 @@ _jscore_collector_introspection
 _jscore_fastmalloc_introspection
 _kJSClassDefinitionEmpty
 _kjs_strtod
+__ZN3WTF8Collator18setOrderLowerFirstEb
+__ZN3WTF8CollatorC1EPKc
+__ZN3WTF8CollatorD1Ev
+__ZNK3WTF8Collator7collateEPKtmS2_m
 __ZN3KJS10throwErrorEPNS_9ExecStateENS_9ErrorTypeERKNS_7UStringE
 __ZNK3KJS8JSObject11hasPropertyEPNS_9ExecStateEj
 __ZN3KJS7UString6appendEPKc
 __ZN3KJS7CStringaSERKS0_
-
index 5a4f38561c08fa760843ed535865f323c0c6057e..f6f59d05a56e7601178f1164541c78a76e8b0d23 100644 (file)
@@ -36,6 +36,8 @@ KJSBISON += \
 SOURCES += \
     wtf/Assertions.cpp \
     wtf/HashTable.cpp \
+    wtf/unicode/CollatorDefault.cpp \
+    wtf/unicode/icu/CollatorICU.cpp \
     wtf/unicode/UTF8.cpp \
     bindings/NP_jsobject.cpp \
     bindings/npruntime.cpp \
index 19609751448455e922a34beeaf3153594bfc5da3..bdbe691d61b8135383522fed65f6dc219062d0ec 100644 (file)
                        RelativePath="..\..\wtf\unicode\Unicode.h"\r
                        >\r
                </File>\r
+               <File\r
+                       RelativePath="..\..\wtf\unicode\Collator.h"\r
+                       >\r
+               </File>\r
+               <File\r
+                       RelativePath="..\..\wtf\unicode\CollatorDefault.cpp"\r
+                       >\r
+               </File>\r
+               <File\r
+                       RelativePath="..\..\wtf\unicode\icu\CollatorICU.cpp"\r
+                       >\r
+               </File>\r
                <File\r
                        RelativePath="..\..\wtf\unicode\icu\UnicodeIcu.h"\r
                        >\r
index c1269300c3290fef8e0ad886d8b7f6dee93c3fad..27c8b0862754855f557271789824a9e9fc55abca 100644 (file)
                E11D51760B2E798D0056C188 /* StringExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = E11D51750B2E798D0056C188 /* StringExtras.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E195679609E7CF1200B89D13 /* UnicodeIcu.h in Headers */ = {isa = PBXBuildFile; fileRef = E195678F09E7CF1200B89D13 /* UnicodeIcu.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E195679809E7CF1200B89D13 /* Unicode.h in Headers */ = {isa = PBXBuildFile; fileRef = E195679409E7CF1200B89D13 /* Unicode.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               E1A862A90D7EBB76001EC6AA /* CollatorICU.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1A862A80D7EBB76001EC6AA /* CollatorICU.cpp */; };
+               E1A862AB0D7EBB7D001EC6AA /* Collator.h in Headers */ = {isa = PBXBuildFile; fileRef = E1A862AA0D7EBB7D001EC6AA /* Collator.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               E1A862D60D7F2B5C001EC6AA /* CollatorDefault.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1A862D50D7F2B5C001EC6AA /* CollatorDefault.cpp */; };
                E1EE79230D6C95CD00FEA3BA /* Threading.h in Headers */ = {isa = PBXBuildFile; fileRef = E1EE79220D6C95CD00FEA3BA /* Threading.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E1EE79280D6C964500FEA3BA /* Locker.h in Headers */ = {isa = PBXBuildFile; fileRef = E1EE79270D6C964500FEA3BA /* Locker.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E1EE793D0D6C9B9200FEA3BA /* ThreadingPthreads.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1EE793C0D6C9B9200FEA3BA /* ThreadingPthreads.cpp */; };
                E11D51750B2E798D0056C188 /* StringExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringExtras.h; sourceTree = "<group>"; };
                E195678F09E7CF1200B89D13 /* UnicodeIcu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnicodeIcu.h; sourceTree = "<group>"; };
                E195679409E7CF1200B89D13 /* Unicode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Unicode.h; sourceTree = "<group>"; };
+               E1A862A80D7EBB76001EC6AA /* CollatorICU.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CollatorICU.cpp; sourceTree = "<group>"; };
+               E1A862AA0D7EBB7D001EC6AA /* Collator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Collator.h; sourceTree = "<group>"; };
+               E1A862D50D7F2B5C001EC6AA /* CollatorDefault.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CollatorDefault.cpp; sourceTree = "<group>"; };
                E1EE79220D6C95CD00FEA3BA /* Threading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Threading.h; sourceTree = "<group>"; };
                E1EE79270D6C964500FEA3BA /* Locker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Locker.h; sourceTree = "<group>"; };
                E1EE793C0D6C9B9200FEA3BA /* ThreadingPthreads.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadingPthreads.cpp; sourceTree = "<group>"; };
                        isa = PBXGroup;
                        children = (
                                E195678E09E7CF1200B89D13 /* icu */,
+                               E1A862AA0D7EBB7D001EC6AA /* Collator.h */,
+                               E1A862D50D7F2B5C001EC6AA /* CollatorDefault.cpp */,
                                E195679409E7CF1200B89D13 /* Unicode.h */,
                                E1EF79A80CE97BA60088D500 /* UTF8.cpp */,
                                E1EF79A90CE97BA60088D500 /* UTF8.h */,
                E195678E09E7CF1200B89D13 /* icu */ = {
                        isa = PBXGroup;
                        children = (
+                               E1A862A80D7EBB76001EC6AA /* CollatorICU.cpp */,
                                E195678F09E7CF1200B89D13 /* UnicodeIcu.h */,
                        );
                        path = icu;
                                932F5B5C0822A1C700736975 /* ustring.h in Headers */,
                                14ABB36F099C076400E2A24F /* value.h in Headers */,
                                E1EE79280D6C964500FEA3BA /* Locker.h in Headers */,
+                               E1A862AB0D7EBB7D001EC6AA /* Collator.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                937013480CA97E0E00FA14D3 /* pcre_ucp_searchfuncs.cpp in Sources */,
                                93E26BD408B1514100F85226 /* pcre_xclass.cpp in Sources */,
                                E1EE793D0D6C9B9200FEA3BA /* ThreadingPthreads.cpp in Sources */,
+                               E1A862A90D7EBB76001EC6AA /* CollatorICU.cpp in Sources */,
+                               E1A862D60D7F2B5C001EC6AA /* CollatorDefault.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index adcb1da27bb477edc3a5830e082dfaf1099724a2..f7b09d15f50fef8145193777784baf26e7a7c3e5 100644 (file)
@@ -100,6 +100,8 @@ Source files for JSCore.
         wtf/HashTable.cpp
         wtf/TCSystemAlloc.cpp
         wtf/ThreadingNone.cpp
+        wtf/unicode/CollatorDefault.cpp
+        wtf/unicode/icu/CollatorICU.cpp
         wtf/unicode/UTF8.cpp
     </set>
 
index 04d8ebb7e2e1e145c6d12d7d61f05ee542acf868..0032c5ccea194df0991761bca18cd7f11d27ea79 100644 (file)
 #include "operations.h"
 #include "regexp_object.h"
 #include <wtf/MathExtras.h>
-#include <wtf/unicode/Unicode.h>
-
-#if PLATFORM(CF)
-#include <CoreFoundation/CoreFoundation.h>
-#elif PLATFORM(WIN_OS)
-#include <windows.h>
-#endif
+#include <wtf/unicode/Collator.h>
 
 using namespace WTF;
 
@@ -294,26 +288,10 @@ static inline UString substituteBackreferences(const UString &replacement, const
 
   return substitutedReplacement;
 }
+
 static inline int localeCompare(const UString& a, const UString& b)
 {
-#if PLATFORM(WIN_OS)
-    int retval = CompareStringW(LOCALE_USER_DEFAULT, 0,
-                                reinterpret_cast<LPCWSTR>(a.data()), a.size(),
-                                reinterpret_cast<LPCWSTR>(b.data()), b.size());
-    return !retval ? retval : retval - 2;
-#elif PLATFORM(CF)
-    CFStringRef sa = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(a.data()), a.size(), kCFAllocatorNull);
-    CFStringRef sb = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(b.data()), b.size(), kCFAllocatorNull);
-
-    int retval = CFStringCompare(sa, sb, kCFCompareLocalized);
-
-    CFRelease(sa);
-    CFRelease(sb);
-
-    return retval;
-#else
-    return compare(a, b);
-#endif
+    return Collator::userDefault()->collate(reinterpret_cast<const ::UChar*>(a.data()), a.size(), reinterpret_cast<const ::UChar*>(b.data()), b.size());
 }
 
 static JSValue *replace(ExecState *exec, StringImp* sourceVal, JSValue *pattern, JSValue *replacement)
index 1cb52729a408bb8432dcdb2590ce4ec6d628ac14..63d828668755afec0c1a775c781adf0c74d522c6 100644 (file)
@@ -91,6 +91,12 @@ class QWaitCondition;
 
 #include <stdint.h>
 
+// For portability, we do not use thread-safe statics natively supported by some compilers (e.g. gcc).
+#define AtomicallyInitializedStatic(T, name) \
+    WTF::atomicallyInitializedStaticMutex->lock(); \
+    static T name; \
+    WTF::atomicallyInitializedStaticMutex->unlock();
+
 namespace WTF {
 
 typedef uint32_t ThreadIdentifier;
@@ -232,9 +238,13 @@ private:
 
 void initializeThreading();
 
+extern Mutex* atomicallyInitializedStaticMutex;
+
 #if !PLATFORM(GTK)
 inline void initializeThreading()
 {
+    if (!atomicallyInitializedStaticMutex)
+        atomicallyInitializedStaticMutex = new Mutex;
 }
 #endif
 
index a5de7a2c546c6743eb87099e0df264765e1bc8f0..fd87fce333d8115ef8c9858d69b78116a3489ba4 100644 (file)
 
 namespace WTF {
 
+Mutex* atomicallyInitializedStaticMutex;
+
 void initializeThreading()
 {
-    if (!g_thread_supported())
+    if (!g_thread_supported()) {
         g_thread_init(NULL);
+        ASSERT(!atomicallyInitializedStaticMutex);
+        atomicallyInitializedStaticMutex = new Mutex;
+    }
     ASSERT(g_thread_supported());
 }
 
index 2c208649a54f2b8dac662fbb427a27a672fc02b7..a06b5ba3322aac7473cd89460046e2499f89c9e4 100644 (file)
@@ -31,6 +31,8 @@
 
 namespace WTF {
 
+Mutex* atomicallyInitializedStaticMutex;
+
 ThreadIdentifier createThread(ThreadFunction, void*) { return 0; }
 int waitForThreadCompletion(ThreadIdentifier, void**) { return 0; }
 void detachThread(ThreadIdentifier) { }
index 2fea5ba7df3074c032283236f446ccf6b76111ea..edd311959c9e673fbe98d427df94a2aab86314f5 100644 (file)
@@ -35,6 +35,8 @@
 
 namespace WTF {
 
+Mutex* atomicallyInitializedStaticMutex;
+
 static Mutex& threadMapMutex()
 {
     static Mutex mutex;
index c946313869110169b04a65776608a21d4a69b2be..7bff7bdca3a4c3831cbfd4160282b0a857ff8976 100644 (file)
@@ -68,6 +68,8 @@
 
 namespace WTF {
 
+Mutex* atomicallyInitializedStaticMutex;
+
 static Mutex& threadMapMutex()
 {
     static Mutex mutex;
diff --git a/JavaScriptCore/wtf/unicode/Collator.h b/JavaScriptCore/wtf/unicode/Collator.h
new file mode 100644 (file)
index 0000000..f04779d
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 WTF_Collator_h
+#define WTF_Collator_h
+
+#include <memory>
+#include <wtf/Noncopyable.h>
+#include <wtf/unicode/Unicode.h>
+
+#if USE(ICU_UNICODE) && !UCONFIG_NO_COLLATION
+struct UCollator;
+#endif
+
+namespace WTF {
+
+    class Collator : Noncopyable {
+    public:
+        enum Result { Equal = 0, Greater = 1, Less = -1 };
+
+        Collator(const char* locale); // Parsing is lenient; e.g. language identifiers (such as "en-US") are accepted, too.
+        ~Collator();
+        void setOrderLowerFirst(bool);
+
+        static std::auto_ptr<Collator> userDefault();
+
+        Result collate(const ::UChar*, size_t, const ::UChar*, size_t) const;
+
+    private:
+#if USE(ICU_UNICODE) && !UCONFIG_NO_COLLATION
+        void createCollator() const;
+        void releaseCollator();
+        mutable UCollator* m_collator;
+#endif
+        char* m_locale;
+        bool m_lowerFirst;
+    };
+}
+
+using WTF::Collator;
+
+#endif
diff --git a/JavaScriptCore/wtf/unicode/CollatorDefault.cpp b/JavaScriptCore/wtf/unicode/CollatorDefault.cpp
new file mode 100644 (file)
index 0000000..e72ff2a
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ */
+
+#include "config.h"
+#include "Collator.h"
+
+#if !USE(ICU_UNICODE) || UCONFIG_NO_COLLATION
+
+namespace WTF {
+
+Collator::Collator(const char*)
+{
+}
+
+Collator::~Collator()
+{
+}
+
+void Collator::setOrderLowerFirst(bool)
+{
+}
+
+std::auto_ptr<Collator> Collator::userDefault()
+{
+    return std::auto_ptr<Collator>(new Collator);
+}
+
+// A default implementation for platforms that lack Unicode-aware collation.
+Collator::Result Collator::collate(const UChar* lhs, size_t lhsLength, const UChar* rhs, size_t rhsLength) const
+{
+    int lmin = lhsLength < rhsLength ? lhsLength : rhsLength;
+    int l = 0;
+    while (l < lmin && *lhs == *rhs) {
+        lhs++;
+        rhs++;
+        l++;
+    }
+
+    if (l < lmin)
+        return (*lhs > *rhs) ? Greater : Less;
+
+    if (lhsLength == rhsLength)
+        return Equal;
+
+    return (lhsLength > rhsLength) ? Greater : Less;
+}
+
+}
+
+#endif
diff --git a/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp b/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp
new file mode 100644 (file)
index 0000000..b7f0570
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2008 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ */
+
+#include "config.h"
+#include "Collator.h"
+
+#if USE(ICU_UNICODE) && !UCONFIG_NO_COLLATION
+
+#include "Assertions.h"
+#include "Threading.h"
+#include <unicode/ucol.h>
+
+#if PLATFORM(DARWIN)
+#include <Corefoundation/CoreFoundation.h>
+#endif
+
+namespace WTF {
+
+static UCollator* cachedCollator;
+static Mutex& cachedCollatorMutex()
+{
+    AtomicallyInitializedStatic(Mutex, mutex);
+    return mutex;
+}
+
+Collator::Collator(const char* locale)
+    : m_collator(0)
+    , m_locale(locale ? strdup(locale) : 0)
+    , m_lowerFirst(false)
+{
+}
+
+std::auto_ptr<Collator> Collator::userDefault()
+{
+#if PLATFORM(DARWIN)
+    // Mac OS X doesn't set UNIX locale to match user-selected one, so ICU default doesn't work.
+    CFStringRef collationOrder = (CFStringRef)CFPreferencesCopyValue(CFSTR("AppleCollationOrder"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
+    char buf[256];
+    if (collationOrder) {
+        CFStringGetCString(collationOrder, buf, sizeof(buf), kCFStringEncodingASCII);
+        CFRelease(collationOrder);
+        return std::auto_ptr<Collator>(new Collator(buf));
+    } else
+        return std::auto_ptr<Collator>(new Collator(""));
+#else
+    return std::auto_ptr<Collator>(new Collator(0));
+#endif
+}
+
+Collator::~Collator()
+{
+    releaseCollator();
+    free(m_locale);
+}
+
+void Collator::setOrderLowerFirst(bool lowerFirst)
+{
+    m_lowerFirst = lowerFirst;
+}
+
+Collator::Result Collator::collate(const UChar* lhs, size_t lhsLength, const UChar* rhs, size_t rhsLength) const
+{
+    if (!m_collator)
+        createCollator();
+
+    return static_cast<Result>(ucol_strcoll(m_collator, lhs, lhsLength, rhs, rhsLength));
+}
+
+void Collator::createCollator() const
+{
+    ASSERT(!m_collator);
+    UErrorCode status = U_ZERO_ERROR;
+
+    {
+        Locker<Mutex> lock(cachedCollatorMutex());
+        if (cachedCollator) {
+            const char* cachedCollatorLocale = ucol_getLocaleByType(cachedCollator, ULOC_REQUESTED_LOCALE, &status);
+            ASSERT(U_SUCCESS(status));
+            
+            UColAttributeValue cachedCollatorLowerFirst = ucol_getAttribute(cachedCollator, UCOL_CASE_FIRST, &status);
+            ASSERT(U_SUCCESS(status));
+
+            if (0 == strcmp(cachedCollatorLocale, m_locale) && ((UCOL_LOWER_FIRST == cachedCollatorLowerFirst && m_lowerFirst) || (UCOL_UPPER_FIRST == cachedCollatorLowerFirst && !m_lowerFirst))) {
+                m_collator = cachedCollator;
+                cachedCollator = 0;
+                return;
+            }
+        }
+    }
+        
+    m_collator = ucol_open(m_locale, &status);
+    if (U_FAILURE(status)) {
+        status = U_ZERO_ERROR;
+        m_collator = ucol_open("", &status); // Fallback to Unicode Collation Algorithm.
+    }
+    ASSERT(U_SUCCESS(status));
+
+    ucol_setAttribute(m_collator, UCOL_CASE_FIRST, m_lowerFirst ? UCOL_LOWER_FIRST : UCOL_UPPER_FIRST, &status);
+    ASSERT(U_SUCCESS(status));
+}
+
+void Collator::releaseCollator()
+{
+    {
+        Locker<Mutex> lock(cachedCollatorMutex());
+        if (cachedCollator)
+            ucol_close(cachedCollator);
+        cachedCollator = m_collator;
+        m_collator  = 0;
+    }
+}
+
+}
+
+#endif
index 50d880a33a4b8f68d1bfdbd3b9bf267de16906cc..347fc6452a5415be160d70e7deffa6c079783b72 100644 (file)
@@ -1,3 +1,15 @@
+2008-03-06  Alexey Proskuryakov  <ap@webkit.org>
+
+        Reviewed by Darin.
+
+        <rdar://problem/5687269> Need to create a Collator abstraction for WebCore and JavaScriptCore
+
+        Added a test to verify that collation is indeed locale-sensitive, and not just UCA.
+
+        * fast/xsl/sort-locale-expected.txt: Added.
+        * fast/xsl/sort-locale.xml: Added.
+        * fast/xsl/sort-locale.xsl: Added.
+
 2008-03-06  Dan Bernstein  <mitz@apple.com>
 
         Reviewed by Adele.
diff --git a/LayoutTests/fast/xsl/sort-locale-expected.txt b/LayoutTests/fast/xsl/sort-locale-expected.txt
new file mode 100644 (file)
index 0000000..b247571
--- /dev/null
@@ -0,0 +1,18 @@
+en
+
+peach
+péché
+pêche
+sin
+fr
+
+peach
+pêche
+péché
+sin
+fr-CA
+
+peach
+pêche
+péché
+sin
diff --git a/LayoutTests/fast/xsl/sort-locale.xml b/LayoutTests/fast/xsl/sort-locale.xml
new file mode 100644 (file)
index 0000000..800bb95
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet type="text/xsl" href="sort-locale.xsl"?>
+<list>
+    <item>peach</item>
+    <item>péché</item>
+    <item>sin</item>
+    <item>pêche</item>
+</list>
diff --git a/LayoutTests/fast/xsl/sort-locale.xsl b/LayoutTests/fast/xsl/sort-locale.xsl
new file mode 100644 (file)
index 0000000..8b545fa
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:template match="/">
+  <html>
+  <body>
+    <script>
+      if (window.layoutTestController)
+        layoutTestController.dumpAsText();
+    </script>
+    <h2>en</h2>
+    <table border="1">
+      <xsl:for-each select="list/item">
+          <xsl:sort select="." data-type="text" order="ascending" lang="en" />
+          <tr>
+            <td><xsl:value-of select="."/></td>
+          </tr>
+      </xsl:for-each>
+    </table>
+    <h2>fr</h2>
+    <table border="1">
+      <xsl:for-each select="list/item">
+          <xsl:sort select="." data-type="text" order="ascending" lang="fr" />
+          <tr>
+            <td><xsl:value-of select="."/></td>
+          </tr>
+      </xsl:for-each>
+    </table>
+    <h2>fr-CA</h2>
+    <table border="1">
+      <xsl:for-each select="list/item">
+          <xsl:sort select="." data-type="text" order="ascending" lang="fr-CA" />
+          <tr>
+            <td><xsl:value-of select="."/></td>
+          </tr>
+      </xsl:for-each>
+    </table>
+  </body>
+  </html>
+</xsl:template>
+</xsl:stylesheet>
index 34c09571e0a026ec16d9017bdf96833f11a976e7..1a034dca3b0affb9edb0b181216a1e66c3bd9ad5 100644 (file)
@@ -1,3 +1,14 @@
+2008-03-05  Alexey Proskuryakov  <ap@webkit.org>
+
+        Reviewed by Darin.
+
+        <rdar://problem/5687269> Need to create a Collator abstraction for WebCore and JavaScriptCore
+        
+        * ForwardingHeaders/wtf/unicode/Collator.h: Added.
+        * xml/XSLTUnicodeSort.cpp:
+        (WebCore::xsltUnicodeSortFunction):
+        * xml/XSLTUnicodeSort.h:
+
 2008-03-06  Darin Adler  <darin@apple.com>
 
         Reviewed by Mitz.
diff --git a/WebCore/ForwardingHeaders/wtf/unicode/Collator.h b/WebCore/ForwardingHeaders/wtf/unicode/Collator.h
new file mode 100644 (file)
index 0000000..8f341a1
--- /dev/null
@@ -0,0 +1 @@
+#include <JavaScriptCore/Collator.h>
index e1ecdc4becd616cd4f4a2a6993c1478b5c257a1b..ed66112175ca4da57d81a3ac1f28f4e1d08fd240 100644 (file)
 
 #if ENABLE(XSLT)
 
+#include "PlatformString.h"
+
 #include <libxslt/templates.h>
 #include <libxslt/xsltutils.h>
 
-#if USE(ICU_UNICODE)
-#include <unicode/ucnv.h>
-#include <unicode/ucol.h>
-#include <unicode/ustring.h>
-#define WTF_USE_ICU_COLLATION !UCONFIG_NO_COLLATION
-#endif
+#include <wtf/unicode/Collator.h>
 
 #if PLATFORM(MAC)
 #include "SoftLinking.h"
@@ -122,14 +119,6 @@ void xsltUnicodeSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, in
     xmlXPathObjectPtr tmp;    
     int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];
 
-#if USE(ICU_COLLATION)
-    UCollator *coll = 0;
-    UConverter *conv;
-    UErrorCode status;
-    UChar *target,*target2;
-    int targetlen, target2len;
-#endif
-
     if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
         (nbsorts >= XSLT_MAX_SORT))
         return;
@@ -201,28 +190,12 @@ void xsltUnicodeSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, in
     if (results == NULL)
         return;
 
-#if USE(ICU_COLLATION)
-    status = U_ZERO_ERROR;
-    conv = ucnv_open("UTF8", &status);
-    if (U_FAILURE(status))
-        xsltTransformError(ctxt, NULL, NULL, "xsltICUSortFunction: Error opening converter\n");
-
-    if (comp->has_lang) 
-        coll = ucol_open((const char*)comp->lang, &status);
-    if (U_FAILURE(status) || !comp->has_lang) {
-        status = U_ZERO_ERROR;
-        coll = ucol_open("en", &status);
-    }
-    if (U_FAILURE(status))
-        xsltTransformError(ctxt, NULL, NULL, "xsltICUSortFunction: Error opening collator\n");
-
-    if (comp->lower_first) 
-        ucol_setAttribute(coll,UCOL_CASE_FIRST,UCOL_LOWER_FIRST,&status);
-    else 
-        ucol_setAttribute(coll,UCOL_CASE_FIRST,UCOL_UPPER_FIRST,&status);
-    if (U_FAILURE(status))
-        xsltTransformError(ctxt, NULL, NULL, "xsltICUSortFunction: Error setting collator attribute\n");
-#endif
+    // We are passing a language identifier to a function that expects a locale identifier.
+    // The implementation of Collator should be lenient, and accept both "en-US" and "en_US", for example.
+    // This lets an author to really specify sorting rules, e.g. "de_DE@collation=phonebook", which isn't
+    // possible with language alone.
+    Collator collator(comp->has_lang ? (const char*)comp->lang : "en");
+    collator.setOrderLowerFirst(comp->lower_first);
 
     /* Shell's sort of node-set */
     for (incr = len / 2; incr > 0; incr /= 2) {
@@ -253,20 +226,9 @@ void xsltUnicodeSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, in
                             tst = 1;
                         else tst = -1;
                     } else {
-#if USE(ICU_COLLATION)
-                        targetlen = xmlStrlen(results[j]->stringval) + 1;
-                        target2len = xmlStrlen(results[j + incr]->stringval) + 1;
-                        target = (UChar*)xmlMalloc(targetlen * sizeof(UChar));
-                        target2 = (UChar*)xmlMalloc(target2len * sizeof(UChar));
-                        targetlen = ucnv_toUChars(conv, target, targetlen, (const char*)results[j]->stringval, -1, &status);
-                        target2len = ucnv_toUChars(conv, target2, target2len, (const char*)results[j+incr]->stringval, -1, &status);
-                        tst = ucol_strcoll(coll, target, u_strlen(target), target2, u_strlen(target2));
-                        xmlFree(target);
-                        xmlFree(target2);
-#else
-                        tst = xmlStrcmp(results[j]->stringval,
-                            results[j + incr]->stringval); 
-#endif
+                        String str1 = String::fromUTF8((const char*)results[j]->stringval);
+                        String str2 = String::fromUTF8((const char*)results[j + incr]->stringval);
+                        tst = collator.collate(str1.characters(), str1.length(), str2.characters(), str2.length());
                     }
                     if (descending)
                         tst = -tst;
@@ -319,20 +281,9 @@ void xsltUnicodeSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, in
                                     tst = 1;
                                 else tst = -1;
                             } else {
-#if USE(ICU_COLLATION)
-                                targetlen = xmlStrlen(res[j]->stringval) + 1;
-                                target2len = xmlStrlen(res[j + incr]->stringval) + 1;
-                                target = (UChar*)xmlMalloc(targetlen * sizeof(UChar));
-                                target2 = (UChar*)xmlMalloc(target2len * sizeof(UChar));
-                                targetlen = ucnv_toUChars(conv, target, targetlen, (const char*)res[j]->stringval, -1, &status);
-                                target2len = ucnv_toUChars(conv, target2, target2len, (const char*)res[j+incr]->stringval, -1, &status);
-                                tst = ucol_strcoll(coll, target, u_strlen(target), target2, u_strlen(target2));
-                                xmlFree(target);
-                                xmlFree(target2);
-#else
-                                tst = xmlStrcmp(res[j]->stringval,
-                                    res[j + incr]->stringval); 
-#endif
+                                String str1 = String::fromUTF8((const char*)res[j]->stringval);
+                                String str2 = String::fromUTF8((const char*)res[j + incr]->stringval);
+                                tst = collator.collate(str1.characters(), str1.length(), str2.characters(), str2.length());
                             }
                             if (desc)
                                 tst = -tst;
@@ -376,11 +327,6 @@ void xsltUnicodeSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, in
         }
     }
 
-#if USE(ICU_COLLATION)
-    ucol_close(coll);
-    ucnv_close(conv);
-#endif
-
     for (j = 0; j < nbsorts; j++) {
         comp = static_cast<xsltStylePreComp*>(sorts[j]->psvi);
         if (tempstype[j] == 1) {
index ff5b2537346482e4edd790de66748000141d2cb1..c8d395b9c0937f3a238409438d6b524bd357e140 100644 (file)
@@ -28,8 +28,6 @@
 #ifndef XSLTUnicodeSort_h
 #define XSLTUnicodeSort_h
 
-// FIXME: Only works as advertised for ICU with collation support enabled yet, falls back on binary comparison otherwise..
-// We need to make an abstraction for Unicode collation to implement this for other libraries.
 #if ENABLE(XSLT)
 
 #include <libxslt/xsltInternals.h>