1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "nsThebesFontEnumerator.h"
7 #include <stdint.h> // for uint32_t
8 #include "gfxPlatform.h" // for gfxPlatform
9 #include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
10 #include "mozilla/UniquePtr.h"
11 #include "mozilla/dom/Promise.h" // for mozilla::dom::Promise
12 #include "nsCOMPtr.h" // for nsCOMPtr
13 #include "nsDebug.h" // for NS_ENSURE_ARG_POINTER
14 #include "nsError.h" // for NS_OK, NS_FAILED, nsresult
15 #include "nsAtom.h" // for nsAtom, NS_Atomize
16 #include "nsID.h"
17 #include "nsMemory.h" // for nsMemory
18 #include "nsString.h" // for nsAutoCString, nsAutoString, etc
19 #include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc
20 #include "nscore.h" // for char16_t, NS_IMETHODIMP
21
22 using mozilla::MakeUnique;
23 using mozilla::Runnable;
24 using mozilla::UniquePtr;
25
26 NS_IMPL_ISUPPORTS(nsThebesFontEnumerator, nsIFontEnumerator)
27
28 nsThebesFontEnumerator::nsThebesFontEnumerator() = default;
29
30 NS_IMETHODIMP
EnumerateAllFonts(nsTArray<nsString> & aResult)31 nsThebesFontEnumerator::EnumerateAllFonts(nsTArray<nsString>& aResult) {
32 return EnumerateFonts(nullptr, nullptr, aResult);
33 }
34
35 NS_IMETHODIMP
EnumerateFonts(const char * aLangGroup,const char * aGeneric,nsTArray<nsString> & aResult)36 nsThebesFontEnumerator::EnumerateFonts(const char* aLangGroup,
37 const char* aGeneric,
38 nsTArray<nsString>& aResult) {
39 nsAutoCString generic;
40 if (aGeneric)
41 generic.Assign(aGeneric);
42 else
43 generic.SetIsVoid(true);
44
45 RefPtr<nsAtom> langGroupAtom;
46 if (aLangGroup) {
47 nsAutoCString lowered;
48 lowered.Assign(aLangGroup);
49 ToLowerCase(lowered);
50 langGroupAtom = NS_Atomize(lowered);
51 }
52
53 return gfxPlatform::GetPlatform()->GetFontList(langGroupAtom, generic,
54 aResult);
55 }
56
57 struct EnumerateFontsPromise final {
EnumerateFontsPromiseEnumerateFontsPromise58 explicit EnumerateFontsPromise(mozilla::dom::Promise* aPromise)
59 : mPromise(aPromise) {
60 MOZ_ASSERT(aPromise);
61 MOZ_ASSERT(NS_IsMainThread());
62 }
63
64 RefPtr<mozilla::dom::Promise> mPromise;
65 };
66
67 class EnumerateFontsResult final : public Runnable {
68 public:
EnumerateFontsResult(nsresult aRv,UniquePtr<EnumerateFontsPromise> aEnumerateFontsPromise,nsTArray<nsString> aFontList)69 EnumerateFontsResult(nsresult aRv,
70 UniquePtr<EnumerateFontsPromise> aEnumerateFontsPromise,
71 nsTArray<nsString> aFontList)
72 : Runnable("EnumerateFontsResult"),
73 mRv(aRv),
74 mEnumerateFontsPromise(std::move(aEnumerateFontsPromise)),
75 mFontList(std::move(aFontList)),
76 mWorkerThread(do_GetCurrentThread()) {
77 MOZ_ASSERT(!NS_IsMainThread());
78 }
79
Run()80 NS_IMETHOD Run() override {
81 MOZ_ASSERT(NS_IsMainThread());
82
83 if (NS_FAILED(mRv)) {
84 mEnumerateFontsPromise->mPromise->MaybeReject(mRv);
85 } else {
86 mEnumerateFontsPromise->mPromise->MaybeResolve(mFontList);
87 }
88
89 mWorkerThread->Shutdown();
90
91 return NS_OK;
92 }
93
94 private:
95 nsresult mRv;
96 UniquePtr<EnumerateFontsPromise> mEnumerateFontsPromise;
97 nsTArray<nsString> mFontList;
98 nsCOMPtr<nsIThread> mWorkerThread;
99 };
100
101 class EnumerateFontsTask final : public Runnable {
102 public:
EnumerateFontsTask(nsAtom * aLangGroupAtom,const nsAutoCString & aGeneric,UniquePtr<EnumerateFontsPromise> aEnumerateFontsPromise,nsIEventTarget * aMainThreadTarget)103 EnumerateFontsTask(nsAtom* aLangGroupAtom, const nsAutoCString& aGeneric,
104 UniquePtr<EnumerateFontsPromise> aEnumerateFontsPromise,
105 nsIEventTarget* aMainThreadTarget)
106 : Runnable("EnumerateFontsTask"),
107 mLangGroupAtom(aLangGroupAtom),
108 mGeneric(aGeneric),
109 mEnumerateFontsPromise(std::move(aEnumerateFontsPromise)),
110 mMainThreadTarget(aMainThreadTarget) {
111 MOZ_ASSERT(NS_IsMainThread());
112 }
113
Run()114 NS_IMETHOD Run() override {
115 MOZ_ASSERT(!NS_IsMainThread());
116
117 nsTArray<nsString> fontList;
118
119 nsresult rv = gfxPlatform::GetPlatform()->GetFontList(mLangGroupAtom,
120 mGeneric, fontList);
121 nsCOMPtr<nsIRunnable> runnable = new EnumerateFontsResult(
122 rv, std::move(mEnumerateFontsPromise), std::move(fontList));
123 mMainThreadTarget->Dispatch(runnable.forget());
124
125 return NS_OK;
126 }
127
128 private:
129 RefPtr<nsAtom> mLangGroupAtom;
130 nsAutoCStringN<16> mGeneric;
131 UniquePtr<EnumerateFontsPromise> mEnumerateFontsPromise;
132 RefPtr<nsIEventTarget> mMainThreadTarget;
133 };
134
135 NS_IMETHODIMP
EnumerateAllFontsAsync(JSContext * aCx,JS::MutableHandleValue aRval)136 nsThebesFontEnumerator::EnumerateAllFontsAsync(JSContext* aCx,
137 JS::MutableHandleValue aRval) {
138 return EnumerateFontsAsync(nullptr, nullptr, aCx, aRval);
139 }
140
141 NS_IMETHODIMP
EnumerateFontsAsync(const char * aLangGroup,const char * aGeneric,JSContext * aCx,JS::MutableHandleValue aRval)142 nsThebesFontEnumerator::EnumerateFontsAsync(const char* aLangGroup,
143 const char* aGeneric,
144 JSContext* aCx,
145 JS::MutableHandleValue aRval) {
146 MOZ_ASSERT(NS_IsMainThread());
147
148 nsCOMPtr<nsIGlobalObject> global = xpc::CurrentNativeGlobal(aCx);
149 NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
150
151 mozilla::ErrorResult errv;
152 RefPtr<mozilla::dom::Promise> promise =
153 mozilla::dom::Promise::Create(global, errv);
154 if (errv.Failed()) {
155 return errv.StealNSResult();
156 }
157
158 auto enumerateFontsPromise = MakeUnique<EnumerateFontsPromise>(promise);
159
160 nsCOMPtr<nsIThread> thread;
161 nsresult rv = NS_NewNamedThread("FontEnumThread", getter_AddRefs(thread));
162 NS_ENSURE_SUCCESS(rv, rv);
163
164 RefPtr<nsAtom> langGroupAtom;
165 if (aLangGroup) {
166 nsAutoCStringN<16> lowered;
167 lowered.Assign(aLangGroup);
168 ToLowerCase(lowered);
169 langGroupAtom = NS_Atomize(lowered);
170 }
171
172 nsAutoCString generic;
173 if (aGeneric) {
174 generic.Assign(aGeneric);
175 } else {
176 generic.SetIsVoid(true);
177 }
178
179 nsCOMPtr<nsIEventTarget> target =
180 global->EventTargetFor(mozilla::TaskCategory::Other);
181 nsCOMPtr<nsIRunnable> runnable = new EnumerateFontsTask(
182 langGroupAtom, generic, std::move(enumerateFontsPromise), target);
183 thread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
184
185 if (!ToJSValue(aCx, promise, aRval)) {
186 return NS_ERROR_FAILURE;
187 }
188
189 return NS_OK;
190 }
191
192 NS_IMETHODIMP
HaveFontFor(const char * aLangGroup,bool * aResult)193 nsThebesFontEnumerator::HaveFontFor(const char* aLangGroup, bool* aResult) {
194 NS_ENSURE_ARG_POINTER(aResult);
195
196 *aResult = true;
197 return NS_OK;
198 }
199
200 NS_IMETHODIMP
GetDefaultFont(const char * aLangGroup,const char * aGeneric,char16_t ** aResult)201 nsThebesFontEnumerator::GetDefaultFont(const char* aLangGroup,
202 const char* aGeneric,
203 char16_t** aResult) {
204 if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aLangGroup) ||
205 NS_WARN_IF(!aGeneric)) {
206 return NS_ERROR_INVALID_ARG;
207 }
208
209 *aResult = nullptr;
210 nsAutoCString defaultFontName(gfxPlatform::GetPlatform()->GetDefaultFontName(
211 nsDependentCString(aLangGroup), nsDependentCString(aGeneric)));
212 if (!defaultFontName.IsEmpty()) {
213 *aResult = UTF8ToNewUnicode(defaultFontName);
214 }
215 return NS_OK;
216 }
217
218 NS_IMETHODIMP
UpdateFontList(bool * _retval)219 nsThebesFontEnumerator::UpdateFontList(bool* _retval) {
220 gfxPlatform::GetPlatform()->UpdateFontList();
221 *_retval = false; // always return false for now
222 return NS_OK;
223 }
224
225 NS_IMETHODIMP
GetStandardFamilyName(const char16_t * aName,char16_t ** aResult)226 nsThebesFontEnumerator::GetStandardFamilyName(const char16_t* aName,
227 char16_t** aResult) {
228 NS_ENSURE_ARG_POINTER(aResult);
229 NS_ENSURE_ARG_POINTER(aName);
230
231 nsAutoString name(aName);
232 if (name.IsEmpty()) {
233 *aResult = nullptr;
234 return NS_OK;
235 }
236
237 nsAutoCString family;
238 gfxPlatform::GetPlatform()->GetStandardFamilyName(
239 NS_ConvertUTF16toUTF8(aName), family);
240 if (family.IsEmpty()) {
241 *aResult = nullptr;
242 return NS_OK;
243 }
244 *aResult = UTF8ToNewUnicode(family);
245 return NS_OK;
246 }
247