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