Bug 1764201 Part 3: Remove screen info stuff from gfxPlatform. r=jgilbert,geckoview...
[gecko.git] / gfx / thebes / gfxAndroidPlatform.cpp
blob46cf1735724bc5f82be431c1fef9307e2765ea86
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"
22 #include "mozilla/widget/Screen.h"
23 #include "mozilla/widget/ScreenManager.h"
25 #include "gfx2DGlue.h"
26 #include "gfxFT2FontList.h"
27 #include "gfxImageSurface.h"
28 #include "gfxTextRun.h"
29 #include "nsXULAppAPI.h"
30 #include "nsIScreen.h"
31 #include "nsServiceManagerUtils.h"
32 #include "nsUnicodeProperties.h"
33 #include "cairo.h"
34 #include "VsyncSource.h"
36 #include "ft2build.h"
37 #include FT_FREETYPE_H
38 #include FT_MODULE_H
40 using namespace mozilla;
41 using namespace mozilla::dom;
42 using namespace mozilla::gfx;
43 using namespace mozilla::unicode;
44 using mozilla::intl::LocaleService;
45 using mozilla::intl::OSPreferences;
47 static FT_Library gPlatformFTLibrary = nullptr;
49 class FreetypeReporter final : public nsIMemoryReporter,
50 public CountingAllocatorBase<FreetypeReporter> {
51 private:
52 ~FreetypeReporter() {}
54 public:
55 NS_DECL_ISUPPORTS
57 static void* Malloc(FT_Memory, long size) { return CountingMalloc(size); }
59 static void Free(FT_Memory, void* p) { return CountingFree(p); }
61 static void* Realloc(FT_Memory, long cur_size, long new_size, void* p) {
62 return CountingRealloc(p, new_size);
65 NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
66 nsISupports* aData, bool aAnonymize) override {
67 MOZ_COLLECT_REPORT("explicit/freetype", KIND_HEAP, UNITS_BYTES,
68 MemoryAllocated(), "Memory used by Freetype.");
70 return NS_OK;
74 NS_IMPL_ISUPPORTS(FreetypeReporter, nsIMemoryReporter)
76 static FT_MemoryRec_ sFreetypeMemoryRecord;
78 gfxAndroidPlatform::gfxAndroidPlatform() {
79 // A custom allocator. It counts allocations, enabling memory reporting.
80 sFreetypeMemoryRecord.user = nullptr;
81 sFreetypeMemoryRecord.alloc = FreetypeReporter::Malloc;
82 sFreetypeMemoryRecord.free = FreetypeReporter::Free;
83 sFreetypeMemoryRecord.realloc = FreetypeReporter::Realloc;
85 // These two calls are equivalent to FT_Init_FreeType(), but allow us to
86 // provide a custom memory allocator.
87 FT_New_Library(&sFreetypeMemoryRecord, &gPlatformFTLibrary);
88 FT_Add_Default_Modules(gPlatformFTLibrary);
90 Factory::SetFTLibrary(gPlatformFTLibrary);
92 RegisterStrongMemoryReporter(new FreetypeReporter());
94 // Get the screen depth of the primary screen to determine our offscreen
95 // format.
96 int32_t screenDepth = 0;
97 if (RefPtr<widget::Screen> screen =
98 widget::ScreenManager::GetSingleton().GetPrimaryScreen()) {
99 screen->GetColorDepth(&screenDepth);
102 mOffscreenFormat = screenDepth == 16 ? SurfaceFormat::R5G6B5_UINT16
103 : SurfaceFormat::X8R8G8B8_UINT32;
105 if (StaticPrefs::gfx_android_rgb16_force_AtStartup()) {
106 mOffscreenFormat = SurfaceFormat::R5G6B5_UINT16;
110 gfxAndroidPlatform::~gfxAndroidPlatform() {
111 FT_Done_Library(gPlatformFTLibrary);
112 gPlatformFTLibrary = nullptr;
113 layers::AndroidHardwareBufferManager::Shutdown();
114 layers::AndroidHardwareBufferApi::Shutdown();
117 void gfxAndroidPlatform::InitAcceleration() { gfxPlatform::InitAcceleration(); }
119 already_AddRefed<gfxASurface> gfxAndroidPlatform::CreateOffscreenSurface(
120 const IntSize& aSize, gfxImageFormat aFormat) {
121 if (!Factory::AllowedSurfaceSize(aSize)) {
122 return nullptr;
125 RefPtr<gfxASurface> newSurface;
126 newSurface = new gfxImageSurface(aSize, aFormat);
128 return newSurface.forget();
131 static bool IsJapaneseLocale() {
132 static bool sInitialized = false;
133 static bool sIsJapanese = false;
135 if (!sInitialized) {
136 sInitialized = true;
138 nsAutoCString appLocale;
139 LocaleService::GetInstance()->GetAppLocaleAsBCP47(appLocale);
141 const nsDependentCSubstring lang(appLocale, 0, 2);
142 if (lang.EqualsLiteral("ja")) {
143 sIsJapanese = true;
144 } else {
145 OSPreferences::GetInstance()->GetSystemLocale(appLocale);
147 const nsDependentCSubstring lang(appLocale, 0, 2);
148 if (lang.EqualsLiteral("ja")) {
149 sIsJapanese = true;
154 return sIsJapanese;
157 void gfxAndroidPlatform::GetCommonFallbackFonts(
158 uint32_t aCh, Script aRunScript, eFontPresentation aPresentation,
159 nsTArray<const char*>& aFontList) {
160 static const char kDroidSansJapanese[] = "Droid Sans Japanese";
161 static const char kMotoyaLMaru[] = "MotoyaLMaru";
162 static const char kNotoSansCJKJP[] = "Noto Sans CJK JP";
163 static const char kNotoColorEmoji[] = "Noto Color Emoji";
165 if (PrefersColor(aPresentation)) {
166 aFontList.AppendElement(kNotoColorEmoji);
169 if (IS_IN_BMP(aCh)) {
170 // try language-specific "Droid Sans *" and "Noto Sans *" fonts for
171 // certain blocks, as most devices probably have these
172 uint8_t block = (aCh >> 8) & 0xff;
173 switch (block) {
174 case 0x05:
175 aFontList.AppendElement("Noto Sans Hebrew");
176 aFontList.AppendElement("Droid Sans Hebrew");
177 aFontList.AppendElement("Noto Sans Armenian");
178 aFontList.AppendElement("Droid Sans Armenian");
179 break;
180 case 0x06:
181 aFontList.AppendElement("Noto Sans Arabic");
182 aFontList.AppendElement("Droid Sans Arabic");
183 break;
184 case 0x09:
185 aFontList.AppendElement("Noto Sans Devanagari");
186 aFontList.AppendElement("Noto Sans Bengali");
187 aFontList.AppendElement("Droid Sans Devanagari");
188 break;
189 case 0x0a:
190 aFontList.AppendElement("Noto Sans Gurmukhi");
191 aFontList.AppendElement("Noto Sans Gujarati");
192 break;
193 case 0x0b:
194 aFontList.AppendElement("Noto Sans Tamil");
195 aFontList.AppendElement("Noto Sans Oriya");
196 aFontList.AppendElement("Droid Sans Tamil");
197 break;
198 case 0x0c:
199 aFontList.AppendElement("Noto Sans Telugu");
200 aFontList.AppendElement("Noto Sans Kannada");
201 break;
202 case 0x0d:
203 aFontList.AppendElement("Noto Sans Malayalam");
204 aFontList.AppendElement("Noto Sans Sinhala");
205 break;
206 case 0x0e:
207 aFontList.AppendElement("Noto Sans Thai");
208 aFontList.AppendElement("Noto Sans Lao");
209 aFontList.AppendElement("Droid Sans Thai");
210 break;
211 case 0x0f:
212 aFontList.AppendElement("Noto Sans Tibetan");
213 break;
214 case 0x10:
215 case 0x2d:
216 aFontList.AppendElement("Noto Sans Georgian");
217 aFontList.AppendElement("Droid Sans Georgian");
218 break;
219 case 0x12:
220 case 0x13:
221 aFontList.AppendElement("Noto Sans Ethiopic");
222 aFontList.AppendElement("Droid Sans Ethiopic");
223 break;
224 case 0x21:
225 case 0x23:
226 case 0x24:
227 case 0x26:
228 case 0x27:
229 case 0x29:
230 aFontList.AppendElement("Noto Sans Symbols");
231 break;
232 case 0xf9:
233 case 0xfa:
234 if (IsJapaneseLocale()) {
235 aFontList.AppendElement(kMotoyaLMaru);
236 aFontList.AppendElement(kNotoSansCJKJP);
237 aFontList.AppendElement(kDroidSansJapanese);
239 break;
240 default:
241 if (block >= 0x2e && block <= 0x9f && IsJapaneseLocale()) {
242 aFontList.AppendElement(kMotoyaLMaru);
243 aFontList.AppendElement(kNotoSansCJKJP);
244 aFontList.AppendElement(kDroidSansJapanese);
246 break;
249 // and try Droid Sans Fallback as a last resort
250 aFontList.AppendElement("Droid Sans Fallback");
253 bool gfxAndroidPlatform::CreatePlatformFontList() {
254 return gfxPlatformFontList::Initialize(new gfxFT2FontList);
257 void gfxAndroidPlatform::ReadSystemFontList(
258 mozilla::dom::SystemFontList* aFontList) {
259 gfxFT2FontList::PlatformFontList()->ReadSystemFontList(aFontList);
262 bool gfxAndroidPlatform::FontHintingEnabled() {
263 // In "mobile" builds, we sometimes use non-reflow-zoom, so we
264 // might not want hinting. Let's see.
266 #ifdef MOZ_WIDGET_ANDROID
267 // On Android, we currently only use gecko to render web
268 // content that can always be be non-reflow-zoomed. So turn off
269 // hinting.
271 // XXX when gecko-android-java is used as an "app runtime", we may
272 // want to re-enable hinting for non-browser processes there.
274 // If this value is changed, we must ensure that the argument passed
275 // to SkInitCairoFT() in GPUParent::RecvInit() is also updated.
276 return false;
277 #endif // MOZ_WIDGET_ANDROID
279 // Currently, we don't have any other targets, but if/when we do,
280 // decide how to handle them here.
282 MOZ_ASSERT_UNREACHABLE("oops, what platform is this?");
283 return gfxPlatform::FontHintingEnabled();
286 bool gfxAndroidPlatform::RequiresLinearZoom() {
287 #ifdef MOZ_WIDGET_ANDROID
288 // On Android, we currently only use gecko to render web
289 // content that can always be be non-reflow-zoomed.
291 // XXX when gecko-android-java is used as an "app runtime", we may
292 // want to use linear zoom only for the web browser process, not other apps.
293 return true;
294 #endif
296 MOZ_ASSERT_UNREACHABLE("oops, what platform is this?");
297 return gfxPlatform::RequiresLinearZoom();
300 bool gfxAndroidPlatform::CheckVariationFontSupport() {
301 // Don't attempt to use variations on Android API versions up to Marshmallow,
302 // because the system freetype version is too old and the parent process may
303 // access it during printing (bug 1845174).
304 return jni::GetAPIVersion() > 23;
307 class AndroidVsyncSource final : public VsyncSource,
308 public widget::AndroidVsync::Observer {
309 public:
310 AndroidVsyncSource() : mAndroidVsync(widget::AndroidVsync::GetInstance()) {}
312 bool IsVsyncEnabled() override {
313 MOZ_ASSERT(NS_IsMainThread());
314 return mObservingVsync;
317 void EnableVsync() override {
318 MOZ_ASSERT(NS_IsMainThread());
320 if (mObservingVsync) {
321 return;
324 float fps = java::GeckoAppShell::GetScreenRefreshRate();
325 MOZ_ASSERT(fps > 0.0f);
326 mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / fps);
327 mAndroidVsync->RegisterObserver(this, widget::AndroidVsync::RENDER);
328 mObservingVsync = true;
331 void DisableVsync() override {
332 MOZ_ASSERT(NS_IsMainThread());
334 if (!mObservingVsync) {
335 return;
337 mAndroidVsync->UnregisterObserver(this, widget::AndroidVsync::RENDER);
338 mObservingVsync = false;
341 TimeDuration GetVsyncRate() override { return mVsyncRate; }
343 void Shutdown() override { DisableVsync(); }
345 // Override for the widget::AndroidVsync::Observer method
346 void OnVsync(const TimeStamp& aTimeStamp) override {
347 // Use the timebase from the frame callback as the vsync time, unless it
348 // is in the future.
349 TimeStamp now = TimeStamp::Now();
350 TimeStamp vsyncTime = aTimeStamp < now ? aTimeStamp : now;
351 TimeStamp outputTime = vsyncTime + GetVsyncRate();
353 NotifyVsync(vsyncTime, outputTime);
356 void OnMaybeUpdateRefreshRate() override {
357 NS_DispatchToMainThread(
358 NS_NewRunnableFunction(__func__, [self = RefPtr{this}]() {
359 if (!self->mObservingVsync) {
360 return;
362 self->DisableVsync();
363 self->EnableVsync();
364 }));
367 private:
368 virtual ~AndroidVsyncSource() { DisableVsync(); }
370 RefPtr<widget::AndroidVsync> mAndroidVsync;
371 TimeDuration mVsyncRate;
372 bool mObservingVsync = false;
375 already_AddRefed<mozilla::gfx::VsyncSource>
376 gfxAndroidPlatform::CreateGlobalHardwareVsyncSource() {
377 RefPtr<AndroidVsyncSource> vsyncSource = new AndroidVsyncSource();
378 return vsyncSource.forget();