OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "platform/text/Hyphenation.h" | 5 #include "platform/text/Hyphenation.h" |
6 | 6 |
7 #include "base/files/file.h" | 7 #include "base/files/file.h" |
8 #include "base/files/memory_mapped_file.h" | 8 #include "base/files/memory_mapped_file.h" |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/timer/elapsed_timer.h" | 10 #include "base/timer/elapsed_timer.h" |
11 #include "mojo/public/cpp/system/platform_handle.h" | 11 #include "mojo/public/cpp/system/platform_handle.h" |
| 12 #include "platform/text/hyphenation/HyphenatorAOSP.h" |
12 #include "public/platform/Platform.h" | 13 #include "public/platform/Platform.h" |
13 #include "public/platform/ServiceRegistry.h" | 14 #include "public/platform/ServiceRegistry.h" |
14 #include "public/platform/modules/hyphenation/hyphenation.mojom-blink.h" | 15 #include "public/platform/modules/hyphenation/hyphenation.mojom-blink.h" |
15 | 16 |
16 namespace blink { | 17 namespace blink { |
17 | 18 |
| 19 using Hyphenator = android::Hyphenator; |
| 20 |
18 class HyphenationMinikin : public Hyphenation { | 21 class HyphenationMinikin : public Hyphenation { |
19 public: | 22 public: |
20 bool openDictionary(const AtomicString& locale); | 23 bool openDictionary(const AtomicString& locale); |
21 | 24 |
22 size_t lastHyphenLocation(const StringView& text, size_t beforeIndex) const
override; | 25 size_t lastHyphenLocation(const StringView& text, size_t beforeIndex) const
override; |
| 26 Vector<size_t, 8> hyphenLocations(const StringView&) const override; |
23 | 27 |
24 private: | 28 private: |
25 static base::PlatformFile openDictionaryFile(const AtomicString& locale); | 29 static base::PlatformFile openDictionaryFile(const AtomicString& locale); |
26 | 30 |
| 31 std::vector<uint8_t> hyphenate(const StringView&) const; |
| 32 |
27 base::MemoryMappedFile m_file; | 33 base::MemoryMappedFile m_file; |
| 34 std::unique_ptr<Hyphenator> m_hyphenator; |
28 }; | 35 }; |
29 | 36 |
30 static mojom::blink::HyphenationPtr connectToRemoteService() | 37 static mojom::blink::HyphenationPtr connectToRemoteService() |
31 { | 38 { |
32 mojom::blink::HyphenationPtr service; | 39 mojom::blink::HyphenationPtr service; |
33 Platform::current()->serviceRegistry()->connectToRemoteService( | 40 Platform::current()->serviceRegistry()->connectToRemoteService( |
34 mojo::GetProxy(&service)); | 41 mojo::GetProxy(&service)); |
35 return service; | 42 return service; |
36 } | 43 } |
37 | 44 |
(...skipping 26 matching lines...) Expand all Loading... |
64 bool HyphenationMinikin::openDictionary(const AtomicString& locale) | 71 bool HyphenationMinikin::openDictionary(const AtomicString& locale) |
65 { | 72 { |
66 base::PlatformFile file = openDictionaryFile(locale); | 73 base::PlatformFile file = openDictionaryFile(locale); |
67 if (file == base::kInvalidPlatformFile) | 74 if (file == base::kInvalidPlatformFile) |
68 return false; | 75 return false; |
69 if (!m_file.Initialize(base::File(file))) { | 76 if (!m_file.Initialize(base::File(file))) { |
70 DLOG(ERROR) << "mmap failed"; | 77 DLOG(ERROR) << "mmap failed"; |
71 return false; | 78 return false; |
72 } | 79 } |
73 | 80 |
74 // TODO(kojii): Create dictionary from m_file when Minikin is ready. | 81 m_hyphenator = wrapUnique(Hyphenator::loadBinary(m_file.data())); |
75 | 82 |
76 return true; | 83 return true; |
77 } | 84 } |
78 | 85 |
| 86 std::vector<uint8_t> HyphenationMinikin::hyphenate(const StringView& text) const |
| 87 { |
| 88 std::vector<uint8_t> result; |
| 89 if (text.is8Bit()) { |
| 90 String text16Bit = text.toString(); |
| 91 text16Bit.ensure16Bit(); |
| 92 m_hyphenator->hyphenate(&result, text16Bit.characters16(), text16Bit.len
gth()); |
| 93 } else { |
| 94 m_hyphenator->hyphenate(&result, text.characters16(), text.length()); |
| 95 } |
| 96 return result; |
| 97 } |
| 98 |
79 size_t HyphenationMinikin::lastHyphenLocation(const StringView& text, size_t bef
oreIndex) const | 99 size_t HyphenationMinikin::lastHyphenLocation(const StringView& text, size_t bef
oreIndex) const |
80 { | 100 { |
81 // TODO(kojii): Call minikin using the dictionary when Minikin is ready. | 101 if (text.length() < minimumPrefixLength + minimumSuffixLength) |
| 102 return 0; |
| 103 |
| 104 std::vector<uint8_t> result = hyphenate(text); |
| 105 static_assert(minimumPrefixLength >= 1, "Change the 'if' above if this fails
"); |
| 106 for (size_t i = text.length() - minimumSuffixLength - 1; |
| 107 i >= minimumPrefixLength; i--) { |
| 108 if (result[i]) |
| 109 return i; |
| 110 } |
82 return 0; | 111 return 0; |
83 } | 112 } |
84 | 113 |
| 114 Vector<size_t, 8> HyphenationMinikin::hyphenLocations(const StringView& text) co
nst |
| 115 { |
| 116 Vector<size_t, 8> hyphenLocations; |
| 117 if (text.length() < minimumPrefixLength + minimumSuffixLength) |
| 118 return hyphenLocations; |
| 119 |
| 120 std::vector<uint8_t> result = hyphenate(text); |
| 121 static_assert(minimumPrefixLength >= 1, "Change the 'if' above if this fails
"); |
| 122 for (size_t i = text.length() - minimumSuffixLength - 1; |
| 123 i >= minimumPrefixLength; i--) { |
| 124 if (result[i]) |
| 125 hyphenLocations.append(i); |
| 126 } |
| 127 return hyphenLocations; |
| 128 } |
| 129 |
| 130 using LocaleMap = HashMap<AtomicString, AtomicString, CaseFoldingHash>; |
| 131 |
| 132 static LocaleMap createLocaleFallbackMap() |
| 133 { |
| 134 // This data is from CLDR, compiled by AOSP. |
| 135 // https://android.googlesource.com/platform/frameworks/base/+/master/core/j
ava/android/text/Hyphenator.java |
| 136 using LocaleFallback = const char*[2]; |
| 137 static LocaleFallback localeFallbackData[] = { |
| 138 { "en-AS", "en-US" }, // English (American Samoa) |
| 139 { "en-GU", "en-US" }, // English (Guam) |
| 140 { "en-MH", "en-US" }, // English (Marshall Islands) |
| 141 { "en-MP", "en-US" }, // English (Northern Mariana Islands) |
| 142 { "en-PR", "en-US" }, // English (Puerto Rico) |
| 143 { "en-UM", "en-US" }, // English (United States Minor Outlying Islands) |
| 144 { "en-VI", "en-US" }, // English (Virgin Islands) |
| 145 { "no", "nb" }, |
| 146 { "am", "und-Ethi" }, // Amharic |
| 147 { "byn", "und-Ethi" }, // Blin |
| 148 { "gez", "und-Ethi" }, // Geʻez |
| 149 { "ti", "und-Ethi" }, // Tigrinya |
| 150 { "wal", "und-Ethi" }, // Wolaytta |
| 151 }; |
| 152 LocaleMap map; |
| 153 for (const auto& it : localeFallbackData) |
| 154 map.add(it[0], it[1]); |
| 155 return map; |
| 156 } |
| 157 |
85 PassRefPtr<Hyphenation> Hyphenation::platformGetHyphenation(const AtomicString&
locale) | 158 PassRefPtr<Hyphenation> Hyphenation::platformGetHyphenation(const AtomicString&
locale) |
86 { | 159 { |
87 RefPtr<HyphenationMinikin> hyphenation(adoptRef(new HyphenationMinikin)); | 160 RefPtr<HyphenationMinikin> hyphenation(adoptRef(new HyphenationMinikin)); |
88 if (!hyphenation->openDictionary(locale)) | 161 if (hyphenation->openDictionary(locale.lowerASCII())) |
89 return nullptr; | 162 return hyphenation.release(); |
90 return hyphenation.release(); | 163 hyphenation.clear(); |
| 164 |
| 165 DEFINE_STATIC_LOCAL(LocaleMap, localeFallback, (createLocaleFallbackMap())); |
| 166 const auto& it = localeFallback.find(locale); |
| 167 if (it != localeFallback.end()) |
| 168 return get(it->value); |
| 169 |
| 170 return nullptr; |
91 } | 171 } |
92 | 172 |
93 } // namespace blink | 173 } // namespace blink |
OLD | NEW |