Bug 1700051: part 46) Const-qualify `mozInlineSpellStatus::mAnchorRange`. r=smaug
[gecko.git] / gfx / thebes / gfxAndroidPlatform.cpp
blob4bd3ce274af662bdbb8e6d20957319d892c38ee3
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/jni/Utils.h"
16 #include "mozilla/layers/AndroidHardwareBuffer.h"
17 #include "mozilla/Preferences.h"
18 #include "mozilla/StaticPrefs_gfx.h"
19 #include "mozilla/StaticPrefs_webgl.h"
20 #include "mozilla/widget/AndroidVsync.h"
22 #include "gfx2DGlue.h"
23 #include "gfxFT2FontList.h"
24 #include "gfxImageSurface.h"
25 #include "gfxTextRun.h"
26 #include "nsXULAppAPI.h"
27 #include "nsIScreen.h"
28 #include "nsServiceManagerUtils.h"
29 #include "nsUnicodeProperties.h"
30 #include "cairo.h"
31 #include "VsyncSource.h"
33 #include "ft2build.h"
34 #include FT_FREETYPE_H
35 #include FT_MODULE_H
37 using namespace mozilla;
38 using namespace mozilla::dom;
39 using namespace mozilla::gfx;
40 using namespace mozilla::unicode;
41 using mozilla::intl::LocaleService;
42 using mozilla::intl::OSPreferences;
44 static FT_Library gPlatformFTLibrary = nullptr;
46 class FreetypeReporter final : public nsIMemoryReporter,
47 public CountingAllocatorBase<FreetypeReporter> {
48 private:
49 ~FreetypeReporter() {}
51 public:
52 NS_DECL_ISUPPORTS
54 static void* Malloc(FT_Memory, long size) { return CountingMalloc(size); }
56 static void Free(FT_Memory, void* p) { return CountingFree(p); }
58 static void* Realloc(FT_Memory, long cur_size, long new_size, void* p) {
59 return CountingRealloc(p, new_size);
62 NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
63 nsISupports* aData, bool aAnonymize) override {
64 MOZ_COLLECT_REPORT("explicit/freetype", KIND_HEAP, UNITS_BYTES,
65 MemoryAllocated(), "Memory used by Freetype.");
67 return NS_OK;
71 NS_IMPL_ISUPPORTS(FreetypeReporter, nsIMemoryReporter)
73 template <>
74 CountingAllocatorBase<FreetypeReporter>::AmountType
75 CountingAllocatorBase<FreetypeReporter>::sAmount(0);
77 static FT_MemoryRec_ sFreetypeMemoryRecord;
79 gfxAndroidPlatform::gfxAndroidPlatform() {
80 // A custom allocator. It counts allocations, enabling memory reporting.
81 sFreetypeMemoryRecord.user = nullptr;
82 sFreetypeMemoryRecord.alloc = FreetypeReporter::Malloc;
83 sFreetypeMemoryRecord.free = FreetypeReporter::Free;
84 sFreetypeMemoryRecord.realloc = FreetypeReporter::Realloc;
86 // These two calls are equivalent to FT_Init_FreeType(), but allow us to
87 // provide a custom memory allocator.
88 FT_New_Library(&sFreetypeMemoryRecord, &gPlatformFTLibrary);
89 FT_Add_Default_Modules(gPlatformFTLibrary);
91 Factory::SetFTLibrary(gPlatformFTLibrary);
93 RegisterStrongMemoryReporter(new FreetypeReporter());
95 mOffscreenFormat = GetScreenDepth() == 16 ? SurfaceFormat::R5G6B5_UINT16
96 : SurfaceFormat::X8R8G8B8_UINT32;
98 if (StaticPrefs::gfx_android_rgb16_force_AtStartup()) {
99 mOffscreenFormat = SurfaceFormat::R5G6B5_UINT16;
103 gfxAndroidPlatform::~gfxAndroidPlatform() {
104 FT_Done_Library(gPlatformFTLibrary);
105 gPlatformFTLibrary = nullptr;
106 layers::AndroidHardwareBufferManager::Shutdown();
107 layers::AndroidHardwareBufferApi::Shutdown();
110 void gfxAndroidPlatform::InitAcceleration() {
111 gfxPlatform::InitAcceleration();
112 if (XRE_IsParentProcess() && jni::GetAPIVersion() >= 26) {
113 if (StaticPrefs::gfx_use_ahardwarebuffer_content_AtStartup()) {
114 gfxVars::SetUseAHardwareBufferContent(true);
116 if (StaticPrefs::webgl_enable_ahardwarebuffer()) {
117 gfxVars::SetUseAHardwareBufferSharedSurface(true);
120 if (gfx::gfxVars::UseAHardwareBufferContent() ||
121 gfxVars::UseAHardwareBufferSharedSurface()) {
122 layers::AndroidHardwareBufferApi::Init();
123 layers::AndroidHardwareBufferManager::Init();
127 already_AddRefed<gfxASurface> gfxAndroidPlatform::CreateOffscreenSurface(
128 const IntSize& aSize, gfxImageFormat aFormat) {
129 if (!Factory::AllowedSurfaceSize(aSize)) {
130 return nullptr;
133 RefPtr<gfxASurface> newSurface;
134 newSurface = new gfxImageSurface(aSize, aFormat);
136 return newSurface.forget();
139 static bool IsJapaneseLocale() {
140 static bool sInitialized = false;
141 static bool sIsJapanese = false;
143 if (!sInitialized) {
144 sInitialized = true;
146 nsAutoCString appLocale;
147 LocaleService::GetInstance()->GetAppLocaleAsBCP47(appLocale);
149 const nsDependentCSubstring lang(appLocale, 0, 2);
150 if (lang.EqualsLiteral("ja")) {
151 sIsJapanese = true;
152 } else {
153 OSPreferences::GetInstance()->GetSystemLocale(appLocale);
155 const nsDependentCSubstring lang(appLocale, 0, 2);
156 if (lang.EqualsLiteral("ja")) {
157 sIsJapanese = true;
162 return sIsJapanese;
165 void gfxAndroidPlatform::GetCommonFallbackFonts(
166 uint32_t aCh, Script aRunScript, eFontPresentation aPresentation,
167 nsTArray<const char*>& aFontList) {
168 static const char kDroidSansJapanese[] = "Droid Sans Japanese";
169 static const char kMotoyaLMaru[] = "MotoyaLMaru";
170 static const char kNotoSansCJKJP[] = "Noto Sans CJK JP";
171 static const char kNotoColorEmoji[] = "Noto Color Emoji";
173 if (PrefersColor(aPresentation)) {
174 aFontList.AppendElement(kNotoColorEmoji);
177 if (IS_IN_BMP(aCh)) {
178 // try language-specific "Droid Sans *" and "Noto Sans *" fonts for
179 // certain blocks, as most devices probably have these
180 uint8_t block = (aCh >> 8) & 0xff;
181 switch (block) {
182 case 0x05:
183 aFontList.AppendElement("Noto Sans Hebrew");
184 aFontList.AppendElement("Droid Sans Hebrew");
185 aFontList.AppendElement("Noto Sans Armenian");
186 aFontList.AppendElement("Droid Sans Armenian");
187 break;
188 case 0x06:
189 aFontList.AppendElement("Noto Sans Arabic");
190 aFontList.AppendElement("Droid Sans Arabic");
191 break;
192 case 0x09:
193 aFontList.AppendElement("Noto Sans Devanagari");
194 aFontList.AppendElement("Noto Sans Bengali");
195 aFontList.AppendElement("Droid Sans Devanagari");
196 break;
197 case 0x0a:
198 aFontList.AppendElement("Noto Sans Gurmukhi");
199 aFontList.AppendElement("Noto Sans Gujarati");
200 break;
201 case 0x0b:
202 aFontList.AppendElement("Noto Sans Tamil");
203 aFontList.AppendElement("Noto Sans Oriya");
204 aFontList.AppendElement("Droid Sans Tamil");
205 break;
206 case 0x0c:
207 aFontList.AppendElement("Noto Sans Telugu");
208 aFontList.AppendElement("Noto Sans Kannada");
209 break;
210 case 0x0d:
211 aFontList.AppendElement("Noto Sans Malayalam");
212 aFontList.AppendElement("Noto Sans Sinhala");
213 break;
214 case 0x0e:
215 aFontList.AppendElement("Noto Sans Thai");
216 aFontList.AppendElement("Noto Sans Lao");
217 aFontList.AppendElement("Droid Sans Thai");
218 break;
219 case 0x0f:
220 aFontList.AppendElement("Noto Sans Tibetan");
221 break;
222 case 0x10:
223 case 0x2d:
224 aFontList.AppendElement("Noto Sans Georgian");
225 aFontList.AppendElement("Droid Sans Georgian");
226 break;
227 case 0x12:
228 case 0x13:
229 aFontList.AppendElement("Noto Sans Ethiopic");
230 aFontList.AppendElement("Droid Sans Ethiopic");
231 break;
232 case 0x21:
233 case 0x23:
234 case 0x24:
235 case 0x26:
236 case 0x27:
237 case 0x29:
238 aFontList.AppendElement("Noto Sans Symbols");
239 break;
240 case 0xf9:
241 case 0xfa:
242 if (IsJapaneseLocale()) {
243 aFontList.AppendElement(kMotoyaLMaru);
244 aFontList.AppendElement(kNotoSansCJKJP);
245 aFontList.AppendElement(kDroidSansJapanese);
247 break;
248 default:
249 if (block >= 0x2e && block <= 0x9f && IsJapaneseLocale()) {
250 aFontList.AppendElement(kMotoyaLMaru);
251 aFontList.AppendElement(kNotoSansCJKJP);
252 aFontList.AppendElement(kDroidSansJapanese);
254 break;
257 // and try Droid Sans Fallback as a last resort
258 aFontList.AppendElement("Droid Sans Fallback");
261 gfxPlatformFontList* gfxAndroidPlatform::CreatePlatformFontList() {
262 gfxPlatformFontList* list = new gfxFT2FontList();
263 if (NS_SUCCEEDED(list->InitFontList())) {
264 return list;
266 gfxPlatformFontList::Shutdown();
267 return nullptr;
270 void gfxAndroidPlatform::ReadSystemFontList(
271 nsTArray<SystemFontListEntry>* aFontList) {
272 gfxFT2FontList::PlatformFontList()->ReadSystemFontList(aFontList);
275 bool gfxAndroidPlatform::FontHintingEnabled() {
276 // In "mobile" builds, we sometimes use non-reflow-zoom, so we
277 // might not want hinting. Let's see.
279 #ifdef MOZ_WIDGET_ANDROID
280 // On Android, we currently only use gecko to render web
281 // content that can always be be non-reflow-zoomed. So turn off
282 // hinting.
284 // XXX when gecko-android-java is used as an "app runtime", we may
285 // want to re-enable hinting for non-browser processes there.
286 return false;
287 #endif // MOZ_WIDGET_ANDROID
289 // Currently, we don't have any other targets, but if/when we do,
290 // decide how to handle them here.
292 MOZ_ASSERT_UNREACHABLE("oops, what platform is this?");
293 return gfxPlatform::FontHintingEnabled();
296 bool gfxAndroidPlatform::RequiresLinearZoom() {
297 #ifdef MOZ_WIDGET_ANDROID
298 // On Android, we currently only use gecko to render web
299 // content that can always be be non-reflow-zoomed.
301 // XXX when gecko-android-java is used as an "app runtime", we may
302 // want to use linear zoom only for the web browser process, not other apps.
303 return true;
304 #endif
306 MOZ_ASSERT_UNREACHABLE("oops, what platform is this?");
307 return gfxPlatform::RequiresLinearZoom();
310 class AndroidVsyncSource final : public VsyncSource {
311 public:
312 class Display final : public VsyncSource::Display,
313 public widget::AndroidVsync::Observer {
314 public:
315 Display() : mAndroidVsync(widget::AndroidVsync::GetInstance()) {}
316 ~Display() { DisableVsync(); }
318 bool IsVsyncEnabled() override {
319 MOZ_ASSERT(NS_IsMainThread());
320 return mObservingVsync;
323 void EnableVsync() override {
324 MOZ_ASSERT(NS_IsMainThread());
326 if (mObservingVsync) {
327 return;
329 mAndroidVsync->RegisterObserver(this, widget::AndroidVsync::RENDER);
330 mObservingVsync = true;
333 void DisableVsync() override {
334 MOZ_ASSERT(NS_IsMainThread());
336 if (!mObservingVsync) {
337 return;
339 mAndroidVsync->UnregisterObserver(this, widget::AndroidVsync::RENDER);
340 mObservingVsync = false;
343 TimeDuration GetVsyncRate() override {
344 return mAndroidVsync->GetVsyncRate();
347 void Shutdown() override { DisableVsync(); }
349 // Override for the widget::AndroidVsync::Observer method
350 void OnVsync(const TimeStamp& aTimeStamp) override {
351 // Use the timebase from the frame callback as the vsync time, unless it
352 // is in the future.
353 TimeStamp now = TimeStamp::Now();
354 TimeStamp vsyncTime = aTimeStamp < now ? aTimeStamp : now;
355 TimeStamp outputTime = vsyncTime + GetVsyncRate();
357 NotifyVsync(vsyncTime, outputTime);
360 private:
361 RefPtr<widget::AndroidVsync> mAndroidVsync;
362 bool mObservingVsync = false;
363 TimeDuration mVsyncDuration;
366 Display& GetGlobalDisplay() final { return GetDisplayInstance(); }
368 private:
369 virtual ~AndroidVsyncSource() = default;
371 static Display& GetDisplayInstance() {
372 static RefPtr<Display> globalDisplay = new Display();
373 return *globalDisplay;
377 already_AddRefed<mozilla::gfx::VsyncSource>
378 gfxAndroidPlatform::CreateHardwareVsyncSource() {
379 // Vsync was introduced since JB (API 16~18) but inaccurate. Enable only for
380 // KK (API 19) and later.
381 if (jni::GetAPIVersion() >= 19) {
382 RefPtr<AndroidVsyncSource> vsyncSource = new AndroidVsyncSource();
383 return vsyncSource.forget();
386 NS_WARNING("Vsync not supported. Falling back to software vsync");
387 return gfxPlatform::CreateHardwareVsyncSource();