[macOS] Do not crash if there is an attempt to copy a file URL to the clipboard
[WebKit-https.git] / Source / WTF / wtf / text / mac / TextBreakIteratorInternalICUMac.mm
1 /*
2  * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  *
19  */
20
21 #include "config.h"
22 #include "TextBreakIteratorInternalICU.h"
23
24 #include "TextBreakIterator.h"
25 #include <wtf/RetainPtr.h>
26
27 namespace WTF {
28
29 static Variant<TextBreakIteratorICU, TextBreakIteratorPlatform> mapModeToBackingIterator(StringView string, TextBreakIterator::Mode mode, const AtomicString& locale)
30 {
31     switch (mode) {
32     case TextBreakIterator::Mode::Line:
33         return TextBreakIteratorICU(string, TextBreakIteratorICU::Mode::Line, locale.string().utf8().data());
34     case TextBreakIterator::Mode::Caret:
35         return TextBreakIteratorCF(string, TextBreakIteratorCF::Mode::Caret);
36     case TextBreakIterator::Mode::Delete:
37         return TextBreakIteratorCF(string, TextBreakIteratorCF::Mode::Delete);
38     }
39 }
40
41 TextBreakIterator::TextBreakIterator(StringView string, Mode mode, const AtomicString& locale)
42     : m_backing(mapModeToBackingIterator(string, mode, locale))
43     , m_mode(mode)
44     , m_locale(locale)
45 {
46 }
47
48 static const int maxLocaleStringLength = 32;
49
50 static inline RetainPtr<CFStringRef> textBreakLocalePreference()
51 {
52     RetainPtr<CFPropertyListRef> locale = adoptCF(CFPreferencesCopyValue(CFSTR("AppleTextBreakLocale"),
53         kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost));
54     if (!locale || CFGetTypeID(locale.get()) != CFStringGetTypeID())
55         return nullptr;
56     return static_cast<CFStringRef>(locale.get());
57 }
58
59 static RetainPtr<CFStringRef> topLanguagePreference()
60 {
61     RetainPtr<CFArrayRef> languagesArray = adoptCF(CFLocaleCopyPreferredLanguages());
62     if (!languagesArray)
63         return nullptr;
64     if (!CFArrayGetCount(languagesArray.get()))
65         return nullptr;
66     return static_cast<CFStringRef>(CFArrayGetValueAtIndex(languagesArray.get(), 0));
67 }
68
69 static void getLocale(CFStringRef locale, char localeStringBuffer[maxLocaleStringLength])
70 {
71     // Empty string means "root locale", and that is what we use if we can't get a preference.
72     localeStringBuffer[0] = 0;
73     if (!locale)
74         return;
75     CFStringGetCString(locale, localeStringBuffer, maxLocaleStringLength, kCFStringEncodingASCII);
76 }
77
78 static void getSearchLocale(char localeStringBuffer[maxLocaleStringLength])
79 {
80     getLocale(topLanguagePreference().get(), localeStringBuffer);
81 }
82
83 const char* currentSearchLocaleID()
84 {
85     static char localeStringBuffer[maxLocaleStringLength];
86     static bool gotSearchLocale = false;
87     if (!gotSearchLocale) {
88         getSearchLocale(localeStringBuffer);
89         gotSearchLocale = true;
90     }
91     return localeStringBuffer;
92 }
93
94 static void getTextBreakLocale(char localeStringBuffer[maxLocaleStringLength])
95 {
96     // If there is no text break locale, use the top language preference.
97     RetainPtr<CFStringRef> locale = textBreakLocalePreference();
98     if (locale) {
99         if (RetainPtr<CFStringRef> canonicalLocale = adoptCF(CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorDefault, locale.get())))
100             locale = canonicalLocale;
101     } else
102         locale = topLanguagePreference();
103     getLocale(locale.get(), localeStringBuffer);
104 }
105
106 const char* currentTextBreakLocaleID()
107 {
108     static char localeStringBuffer[maxLocaleStringLength];
109     static bool gotTextBreakLocale = false;
110     if (!gotTextBreakLocale) {
111         getTextBreakLocale(localeStringBuffer);
112         gotTextBreakLocale = true;
113     }
114     return localeStringBuffer;
115 }
116
117 }