Bug 1897246 - Implement "Add to Home screen" menu functionality. r=android-reviewers,gl
[gecko.git] / gfx / thebes / gfxAndroidPlatform.cpp
blobfbc3d3fa80af126d9736770fcab372e18c74e0b7
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "base/basictypes.h"
9 #include "gfxAndroidPlatform.h"
10 #include "mozilla/gfx/2D.h"
11 #include "mozilla/gfx/gfxVars.h"
12 #include "mozilla/CountingAllocatorBase.h"
13 #include "mozilla/intl/LocaleService.h"
14 #include "mozilla/intl/OSPreferences.h"
15 #include "mozilla/java/GeckoAppShellWrappers.h"
16 #include "mozilla/jni/Utils.h"
17 #include "mozilla/layers/AndroidHardwareBuffer.h"
18 #include "mozilla/Preferences.h"
19 #include "mozilla/StaticPrefs_gfx.h"
20 #include "mozilla/StaticPrefs_webgl.h"
21 #include "mozilla/widget/AndroidVsync.h"
23 #include "gfx2DGlue.h"
24 #include "gfxFT2FontList.h"
25 #include "gfxImageSurface.h"
26 #include "gfxTextRun.h"
27 #include "nsXULAppAPI.h"
28 #include "nsIScreen.h"
29 #include "nsServiceManagerUtils.h"
30 #include "nsUnicodeProperties.h"
31 #include "cairo.h"
32 #include "VsyncSource.h"
34 #include "ft2build.h"
35 #include FT_FREETYPE_H
36 #include FT_MODULE_H
38 using namespace mozilla;
39 using namespace mozilla::dom;
40 using namespace mozilla::gfx;
41 using namespace mozilla::unicode;
42 using mozilla::intl::LocaleService;
43 using mozilla::intl::OSPreferences;
45 static FT_Library gPlatformFTLibrary = nullptr;
47 class FreetypeReporter final : public nsIMemoryReporter,
48 public CountingAllocatorBase<FreetypeReporter> {
49 private:
50 ~FreetypeReporter() {}
52 public:
53 NS_DECL_ISUPPORTS
55 static void* Malloc(FT_Memory, long size) { return CountingMalloc(size); }
57 static void Free(FT_Memory, void* p) { return CountingFree(p); }
59 static void* Realloc(FT_Memory, long cur_size, long new_size, void* p) {
60 return CountingRealloc(p, new_size);
63 NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
64 nsISupports* aData, bool aAnonymize) override {
65 MOZ_COLLECT_REPORT("explicit/freetype", KIND_HEAP, UNITS_BYTES,
66 MemoryAllocated(), "Memory used by Freetype.");
68 return NS_OK;
72 NS_IMPL_ISUPPORTS(FreetypeReporter, nsIMemoryReporter)
74 static FT_MemoryRec_ sFreetypeMemoryRecord;
76 gfxAndroidPlatform::gfxAndroidPlatform() {
77 // A custom allocator. It counts allocations, enabling memory reporting.
78 sFreetypeMemoryRecord.user = nullptr;
79 sFreetypeMemoryRecord.alloc = FreetypeReporter::Malloc;
80 sFreetypeMemoryRecord.free = FreetypeReporter::Free;
81 sFreetypeMemoryRecord.realloc = FreetypeReporter::Realloc;
83 // These two calls are equivalent to FT_Init_FreeType(), but allow us to
84 // provide a custom memory allocator.
85 FT_New_Library(&sFreetypeMemoryRecord, &gPlatformFTLibrary);
86 FT_Add_Default_Modules(gPlatformFTLibrary);
88 Factory::SetFTLibrary(gPlatformFTLibrary);
90 RegisterStrongMemoryReporter(new FreetypeReporter());
92 // Bug 1886573: At this point, we don't yet have primary screen depth.
93 // This setting of screen depth to 0 is preserving existing behavior,
94 // and should be fixed.
95 int32_t screenDepth = 0;
96 mOffscreenFormat = screenDepth == 16 ? SurfaceFormat::R5G6B5_UINT16
97 : SurfaceFormat::X8R8G8B8_UINT32;
99 if (StaticPrefs::gfx_android_rgb16_force_AtStartup()) {
100 mOffscreenFormat = SurfaceFormat::R5G6B5_UINT16;
104 gfxAndroidPlatform::~gfxAndroidPlatform() {
105 FT_Done_Library(gPlatformFTLibrary);
106 gPlatformFTLibrary = nullptr;
107 layers::AndroidHardwareBufferManager::Shutdown();
108 layers::AndroidHardwareBufferApi::Shutdown();
111 void gfxAndroidPlatform::InitAcceleration() { gfxPlatform::InitAcceleration(); }
113 already_AddRefed<gfxASurface> gfxAndroidPlatform::CreateOffscreenSurface(
114 const IntSize& aSize, gfxImageFormat aFormat) {
115 if (!Factory::AllowedSurfaceSize(aSize)) {
116 return nullptr;
119 RefPtr<gfxASurface> newSurface;
120 newSurface = new gfxImageSurface(aSize, aFormat);
122 return newSurface.forget();
125 static bool IsJapaneseLocale() {
126 static bool sInitialized = false;
127 static bool sIsJapanese = false;
129 if (!sInitialized) {
130 sInitialized = true;
132 nsAutoCString appLocale;
133 LocaleService::GetInstance()->GetAppLocaleAsBCP47(appLocale);
135 const nsDependentCSubstring lang(appLocale, 0, 2);
136 if (lang.EqualsLiteral("ja")) {
137 sIsJapanese = true;
138 } else {
139 OSPreferences::GetInstance()->GetSystemLocale(appLocale);
141 const nsDependentCSubstring lang(appLocale, 0, 2);
142 if (lang.EqualsLiteral("ja")) {
143 sIsJapanese = true;
148 return sIsJapanese;
151 void gfxAndroidPlatform::GetCommonFallbackFonts(
152 uint32_t aCh, Script aRunScript, eFontPresentation aPresentation,
153 nsTArray<const char*>& aFontList) {
154 static const char kDroidSansJapanese[] = "Droid Sans Japanese";
155 static const char kMotoyaLMaru[] = "MotoyaLMaru";
156 static const char kNotoSansCJKJP[] = "Noto Sans CJK JP";
157 static const char kNotoColorEmoji[] = "Noto Color Emoji";
159 if (PrefersColor(aPresentation)) {
160 aFontList.AppendElement(kNotoColorEmoji);
163 if (IS_IN_BMP(aCh)) {
164 // try language-specific "Droid Sans *" and "Noto Sans *" fonts for
165 // certain blocks, as most devices probably have these
166 uint8_t block = (aCh >> 8) & 0xff;
167 switch (block) {
168 case 0x05:
169 aFontList.AppendElement("Noto Sans Hebrew");
170 aFontList.AppendElement("Droid Sans Hebrew");
171 aFontList.AppendElement("Noto Sans Armenian");
172 aFontList.AppendElement("Droid Sans Armenian");
173 break;
174 case 0x06:
175 aFontList.AppendElement("Noto Sans Arabic");
176 aFontList.AppendElement("Droid Sans Arabic");
177 break;
178 case 0x09:
179 aFontList.AppendElement("Noto Sans Devanagari");
180 aFontList.AppendElement("Noto Sans Bengali");
181 aFontList.AppendElement("Droid Sans Devanagari");
182 break;
183 case 0x0a:
184 aFontList.AppendElement("Noto Sans Gurmukhi");
185 aFontList.AppendElement("Noto Sans Gujarati");
186 break;
187 case 0x0b:
188 aFontList.AppendElement("Noto Sans Tamil");
189 aFontList.AppendElement("Noto Sans Oriya");
190 aFontList.AppendElement("Droid Sans Tamil");
191 break;
192 case 0x0c:
193 aFontList.AppendElement("Noto Sans Telugu");
194 aFontList.AppendElement("Noto Sans Kannada");
195 break;
196 case 0x0d:
197 aFontList.AppendElement("Noto Sans Malayalam");
198 aFontList.AppendElement("Noto Sans Sinhala");
199 break;
200 case 0x0e:
201 aFontList.AppendElement("Noto Sans Thai");
202 aFontList.AppendElement("Noto Sans Lao");
203 aFontList.AppendElement("Droid Sans Thai");
204 break;
205 case 0x0f:
206 aFontList.AppendElement("Noto Sans Tibetan");
207 break;
208 case 0x10:
209 case 0x2d:
210 aFontList.AppendElement("Noto Sans Georgian");
211 aFontList.AppendElement("Droid Sans Georgian");
212 break;
213 case 0x12:
214 case 0x13:
215 aFontList.AppendElement("Noto Sans Ethiopic");
216 aFontList.AppendElement("Droid Sans Ethiopic");
217 break;
218 case 0x21:
219 case 0x23:
220 case 0x24:
221 case 0x26:
222 case 0x27:
223 case 0x29:
224 aFontList.AppendElement("Noto Sans Symbols");
225 break;
226 case 0xf9:
227 case 0xfa:
228 if (IsJapaneseLocale()) {
229 aFontList.AppendElement(kMotoyaLMaru);
230 aFontList.AppendElement(kNotoSansCJKJP);
231 aFontList.AppendElement(kDroidSansJapanese);
233 break;
234 default:
235 if (block >= 0x2e && block <= 0x9f && IsJapaneseLocale()) {
236 aFontList.AppendElement(kMotoyaLMaru);
237 aFontList.AppendElement(kNotoSansCJKJP);
238 aFontList.AppendElement(kDroidSansJapanese);
240 break;
243 // and try Droid Sans Fallback as a last resort
244 aFontList.AppendElement("Droid Sans Fallback");
247 bool gfxAndroidPlatform::CreatePlatformFontList() {
248 return gfxPlatformFontList::Initialize(new gfxFT2FontList);
251 void gfxAndroidPlatform::ReadSystemFontList(
252 mozilla::dom::SystemFontList* aFontList) {
253 gfxFT2FontList::PlatformFontList()->ReadSystemFontList(aFontList);
256 bool gfxAndroidPlatform::FontHintingEnabled() {
257 // In "mobile" builds, we sometimes use non-reflow-zoom, so we
258 // might not want hinting. Let's see.
260 #ifdef MOZ_WIDGET_ANDROID
261 // On Android, we currently only use gecko to render web
262 // content that can always be be non-reflow-zoomed. So turn off
263 // hinting.
265 // XXX when gecko-android-java is used as an "app runtime", we may
266 // want to re-enable hinting for non-browser processes there.
268 // If this value is changed, we must ensure that the argument passed
269 // to SkInitCairoFT() in GPUParent::RecvInit() is also updated.
270 return false;
271 #endif // MOZ_WIDGET_ANDROID
273 // Currently, we don't have any other targets, but if/when we do,
274 // decide how to handle them here.
276 MOZ_ASSERT_UNREACHABLE("oops, what platform is this?");
277 return gfxPlatform::FontHintingEnabled();
280 bool gfxAndroidPlatform::RequiresLinearZoom() {
281 #ifdef MOZ_WIDGET_ANDROID
282 // On Android, we currently only use gecko to render web
283 // content that can always be be non-reflow-zoomed.
285 // XXX when gecko-android-java is used as an "app runtime", we may
286 // want to use linear zoom only for the web browser process, not other apps.
287 return true;
288 #endif
290 MOZ_ASSERT_UNREACHABLE("oops, what platform is this?");
291 return gfxPlatform::RequiresLinearZoom();
294 bool gfxAndroidPlatform::CheckVariationFontSupport() {
295 // Don't attempt to use variations on Android API versions up to Marshmallow,
296 // because the system freetype version is too old and the parent process may
297 // access it during printing (bug 1845174).
298 return jni::GetAPIVersion() > 23;
301 class AndroidVsyncSource final : public VsyncSource,
302 public widget::AndroidVsync::Observer {
303 public:
304 AndroidVsyncSource() : mAndroidVsync(widget::AndroidVsync::GetInstance()) {}
306 bool IsVsyncEnabled() override {
307 MOZ_ASSERT(NS_IsMainThread());
308 return mObservingVsync;
311 void EnableVsync() override {
312 MOZ_ASSERT(NS_IsMainThread());
314 if (mObservingVsync) {
315 return;
318 float fps = java::GeckoAppShell::GetScreenRefreshRate();
319 MOZ_ASSERT(fps > 0.0f);
320 mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / fps);
321 mAndroidVsync->RegisterObserver(this, widget::AndroidVsync::RENDER);
322 mObservingVsync = true;
325 void DisableVsync() override {
326 MOZ_ASSERT(NS_IsMainThread());
328 if (!mObservingVsync) {
329 return;
331 mAndroidVsync->UnregisterObserver(this, widget::AndroidVsync::RENDER);
332 mObservingVsync = false;
335 TimeDuration GetVsyncRate() override { return mVsyncRate; }
337 void Shutdown() override { DisableVsync(); }
339 // Override for the widget::AndroidVsync::Observer method
340 void OnVsync(const TimeStamp& aTimeStamp) override {
341 // Use the timebase from the frame callback as the vsync time, unless it
342 // is in the future.
343 TimeStamp now = TimeStamp::Now();
344 TimeStamp vsyncTime = aTimeStamp < now ? aTimeStamp : now;
345 TimeStamp outputTime = vsyncTime + GetVsyncRate();
347 NotifyVsync(vsyncTime, outputTime);
350 void OnMaybeUpdateRefreshRate() override {
351 NS_DispatchToMainThread(
352 NS_NewRunnableFunction(__func__, [self = RefPtr{this}]() {
353 if (!self->mObservingVsync) {
354 return;
356 self->DisableVsync();
357 self->EnableVsync();
358 }));
361 private:
362 virtual ~AndroidVsyncSource() { DisableVsync(); }
364 RefPtr<widget::AndroidVsync> mAndroidVsync;
365 TimeDuration mVsyncRate;
366 bool mObservingVsync = false;
369 already_AddRefed<mozilla::gfx::VsyncSource>
370 gfxAndroidPlatform::CreateGlobalHardwareVsyncSource() {
371 RefPtr<AndroidVsyncSource> vsyncSource = new AndroidVsyncSource();
372 return vsyncSource.forget();