michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* vim: set ts=8 sts=4 et sw=4 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "base/basictypes.h" michael@0: michael@0: #include "gfxAndroidPlatform.h" michael@0: #include "mozilla/gfx/2D.h" michael@0: #include "mozilla/Preferences.h" michael@0: michael@0: #include "gfx2DGlue.h" michael@0: #include "gfxFT2FontList.h" michael@0: #include "gfxImageSurface.h" michael@0: #include "mozilla/dom/ContentChild.h" michael@0: #include "nsXULAppAPI.h" michael@0: #include "nsIScreen.h" michael@0: #include "nsIScreenManager.h" michael@0: #include "nsILocaleService.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "gfxPrefs.h" michael@0: #include "cairo.h" michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: #include "AndroidBridge.h" michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: #include michael@0: #endif michael@0: michael@0: #include "ft2build.h" michael@0: #include FT_FREETYPE_H michael@0: #include FT_MODULE_H michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: using namespace mozilla::gfx; michael@0: michael@0: static FT_Library gPlatformFTLibrary = nullptr; michael@0: michael@0: class FreetypeReporter MOZ_FINAL : public nsIMemoryReporter, michael@0: public CountingAllocatorBase michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: static void* Malloc(FT_Memory, long size) michael@0: { michael@0: return CountingMalloc(size); michael@0: } michael@0: michael@0: static void Free(FT_Memory, void* p) michael@0: { michael@0: return CountingFree(p); michael@0: } michael@0: michael@0: static void* michael@0: Realloc(FT_Memory, long cur_size, long new_size, void* p) michael@0: { michael@0: return CountingRealloc(p, new_size); michael@0: } michael@0: michael@0: NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, michael@0: nsISupports* aData) michael@0: { michael@0: return MOZ_COLLECT_REPORT( michael@0: "explicit/freetype", KIND_HEAP, UNITS_BYTES, MemoryAllocated(), michael@0: "Memory used by Freetype."); michael@0: } michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(FreetypeReporter, nsIMemoryReporter) michael@0: michael@0: template<> Atomic CountingAllocatorBase::sAmount(0); michael@0: michael@0: static FT_MemoryRec_ sFreetypeMemoryRecord; michael@0: michael@0: gfxAndroidPlatform::gfxAndroidPlatform() michael@0: { michael@0: // A custom allocator. It counts allocations, enabling memory reporting. michael@0: sFreetypeMemoryRecord.user = nullptr; michael@0: sFreetypeMemoryRecord.alloc = FreetypeReporter::Malloc; michael@0: sFreetypeMemoryRecord.free = FreetypeReporter::Free; michael@0: sFreetypeMemoryRecord.realloc = FreetypeReporter::Realloc; michael@0: michael@0: // These two calls are equivalent to FT_Init_FreeType(), but allow us to michael@0: // provide a custom memory allocator. michael@0: FT_New_Library(&sFreetypeMemoryRecord, &gPlatformFTLibrary); michael@0: FT_Add_Default_Modules(gPlatformFTLibrary); michael@0: michael@0: RegisterStrongMemoryReporter(new FreetypeReporter()); michael@0: michael@0: nsCOMPtr screenMgr = do_GetService("@mozilla.org/gfx/screenmanager;1"); michael@0: nsCOMPtr screen; michael@0: screenMgr->GetPrimaryScreen(getter_AddRefs(screen)); michael@0: mScreenDepth = 24; michael@0: screen->GetColorDepth(&mScreenDepth); michael@0: michael@0: mOffscreenFormat = mScreenDepth == 16 michael@0: ? gfxImageFormat::RGB16_565 michael@0: : gfxImageFormat::RGB24; michael@0: michael@0: if (gfxPrefs::AndroidRGB16Force()) { michael@0: mOffscreenFormat = gfxImageFormat::RGB16_565; michael@0: } michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: char propQemu[PROPERTY_VALUE_MAX]; michael@0: property_get("ro.kernel.qemu", propQemu, ""); michael@0: mIsInGonkEmulator = !strncmp(propQemu, "1", 1); michael@0: #endif michael@0: } michael@0: michael@0: gfxAndroidPlatform::~gfxAndroidPlatform() michael@0: { michael@0: FT_Done_Library(gPlatformFTLibrary); michael@0: gPlatformFTLibrary = nullptr; michael@0: } michael@0: michael@0: already_AddRefed michael@0: gfxAndroidPlatform::CreateOffscreenSurface(const IntSize& size, michael@0: gfxContentType contentType) michael@0: { michael@0: nsRefPtr newSurface; michael@0: newSurface = new gfxImageSurface(ThebesIntSize(size), michael@0: OptimalFormatForContent(contentType)); michael@0: michael@0: return newSurface.forget(); michael@0: } michael@0: michael@0: static bool michael@0: IsJapaneseLocale() michael@0: { michael@0: static bool sInitialized = false; michael@0: static bool sIsJapanese = false; michael@0: michael@0: if (!sInitialized) { michael@0: sInitialized = true; michael@0: michael@0: do { // to allow 'break' to abandon this block if a call fails michael@0: nsresult rv; michael@0: nsCOMPtr ls = michael@0: do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) { michael@0: break; michael@0: } michael@0: nsCOMPtr appLocale; michael@0: rv = ls->GetApplicationLocale(getter_AddRefs(appLocale)); michael@0: if (NS_FAILED(rv)) { michael@0: break; michael@0: } michael@0: nsString localeStr; michael@0: rv = appLocale-> michael@0: GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr); michael@0: if (NS_FAILED(rv)) { michael@0: break; michael@0: } michael@0: const nsAString& lang = nsDependentSubstring(localeStr, 0, 2); michael@0: if (lang.EqualsLiteral("ja")) { michael@0: sIsJapanese = true; michael@0: } michael@0: } while (false); michael@0: } michael@0: michael@0: return sIsJapanese; michael@0: } michael@0: michael@0: void michael@0: gfxAndroidPlatform::GetCommonFallbackFonts(const uint32_t aCh, michael@0: int32_t aRunScript, michael@0: nsTArray& aFontList) michael@0: { michael@0: static const char kDroidSansJapanese[] = "Droid Sans Japanese"; michael@0: static const char kMotoyaLMaru[] = "MotoyaLMaru"; michael@0: michael@0: if (IS_IN_BMP(aCh)) { michael@0: // try language-specific "Droid Sans *" fonts for certain blocks, michael@0: // as most devices probably have these michael@0: uint8_t block = (aCh >> 8) & 0xff; michael@0: switch (block) { michael@0: case 0x05: michael@0: aFontList.AppendElement("Droid Sans Hebrew"); michael@0: aFontList.AppendElement("Droid Sans Armenian"); michael@0: break; michael@0: case 0x06: michael@0: aFontList.AppendElement("Droid Sans Arabic"); michael@0: break; michael@0: case 0x09: michael@0: aFontList.AppendElement("Droid Sans Devanagari"); michael@0: break; michael@0: case 0x0b: michael@0: aFontList.AppendElement("Droid Sans Tamil"); michael@0: break; michael@0: case 0x0e: michael@0: aFontList.AppendElement("Droid Sans Thai"); michael@0: break; michael@0: case 0x10: case 0x2d: michael@0: aFontList.AppendElement("Droid Sans Georgian"); michael@0: break; michael@0: case 0x12: case 0x13: michael@0: aFontList.AppendElement("Droid Sans Ethiopic"); michael@0: break; michael@0: case 0xf9: case 0xfa: michael@0: if (IsJapaneseLocale()) { michael@0: aFontList.AppendElement(kMotoyaLMaru); michael@0: aFontList.AppendElement(kDroidSansJapanese); michael@0: } michael@0: break; michael@0: default: michael@0: if (block >= 0x2e && block <= 0x9f && IsJapaneseLocale()) { michael@0: aFontList.AppendElement(kMotoyaLMaru); michael@0: aFontList.AppendElement(kDroidSansJapanese); michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: // and try Droid Sans Fallback as a last resort michael@0: aFontList.AppendElement("Droid Sans Fallback"); michael@0: } michael@0: michael@0: nsresult michael@0: gfxAndroidPlatform::GetFontList(nsIAtom *aLangGroup, michael@0: const nsACString& aGenericFamily, michael@0: nsTArray& aListOfFonts) michael@0: { michael@0: gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, michael@0: aGenericFamily, michael@0: aListOfFonts); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: gfxAndroidPlatform::GetFontList(InfallibleTArray* retValue) michael@0: { michael@0: gfxFT2FontList::PlatformFontList()->GetFontList(retValue); michael@0: } michael@0: michael@0: nsresult michael@0: gfxAndroidPlatform::UpdateFontList() michael@0: { michael@0: gfxPlatformFontList::PlatformFontList()->UpdateFontList(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: gfxAndroidPlatform::ResolveFontName(const nsAString& aFontName, michael@0: FontResolverCallback aCallback, michael@0: void *aClosure, michael@0: bool& aAborted) michael@0: { michael@0: nsAutoString resolvedName; michael@0: if (!gfxPlatformFontList::PlatformFontList()-> michael@0: ResolveFontName(aFontName, resolvedName)) { michael@0: aAborted = false; michael@0: return NS_OK; michael@0: } michael@0: aAborted = !(*aCallback)(resolvedName, aClosure); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: gfxAndroidPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) michael@0: { michael@0: gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName); michael@0: return NS_OK; michael@0: } michael@0: michael@0: gfxPlatformFontList* michael@0: gfxAndroidPlatform::CreatePlatformFontList() michael@0: { michael@0: gfxPlatformFontList* list = new gfxFT2FontList(); michael@0: if (NS_SUCCEEDED(list->InitFontList())) { michael@0: return list; michael@0: } michael@0: gfxPlatformFontList::Shutdown(); michael@0: return nullptr; michael@0: } michael@0: michael@0: bool michael@0: gfxAndroidPlatform::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) michael@0: { michael@0: // check for strange format flags michael@0: NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED), michael@0: "strange font format hint set"); michael@0: michael@0: // accept supported formats michael@0: if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_OPENTYPE | michael@0: gfxUserFontSet::FLAG_FORMAT_WOFF | michael@0: gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) { michael@0: return true; michael@0: } michael@0: michael@0: // reject all other formats, known and unknown michael@0: if (aFormatFlags != 0) { michael@0: return false; michael@0: } michael@0: michael@0: // no format hint set, need to look at data michael@0: return true; michael@0: } michael@0: michael@0: gfxFontGroup * michael@0: gfxAndroidPlatform::CreateFontGroup(const nsAString &aFamilies, michael@0: const gfxFontStyle *aStyle, michael@0: gfxUserFontSet* aUserFontSet) michael@0: { michael@0: return new gfxFontGroup(aFamilies, aStyle, aUserFontSet); michael@0: } michael@0: michael@0: FT_Library michael@0: gfxAndroidPlatform::GetFTLibrary() michael@0: { michael@0: return gPlatformFTLibrary; michael@0: } michael@0: michael@0: gfxFontEntry* michael@0: gfxAndroidPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, michael@0: const uint8_t *aFontData, uint32_t aLength) michael@0: { michael@0: return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry, michael@0: aFontData, michael@0: aLength); michael@0: } michael@0: michael@0: gfxFontEntry* michael@0: gfxAndroidPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, michael@0: const nsAString& aFontName) michael@0: { michael@0: return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry, michael@0: aFontName); michael@0: } michael@0: michael@0: TemporaryRef michael@0: gfxAndroidPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont) michael@0: { michael@0: return GetScaledFontForFontWithCairoSkia(aTarget, aFont); michael@0: } michael@0: michael@0: bool michael@0: gfxAndroidPlatform::FontHintingEnabled() michael@0: { michael@0: // In "mobile" builds, we sometimes use non-reflow-zoom, so we michael@0: // might not want hinting. Let's see. michael@0: michael@0: #ifdef MOZ_USING_ANDROID_JAVA_WIDGETS michael@0: // On android-java, we currently only use gecko to render web michael@0: // content that can always be be non-reflow-zoomed. So turn off michael@0: // hinting. michael@0: // michael@0: // XXX when gecko-android-java is used as an "app runtime", we may michael@0: // want to re-enable hinting for non-browser processes there. michael@0: return false; michael@0: #endif // MOZ_USING_ANDROID_JAVA_WIDGETS michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: // On B2G, the UX preference is currently to keep hinting disabled michael@0: // for all text (see bug 829523). michael@0: return false; michael@0: #endif michael@0: michael@0: // Currently, we don't have any other targets, but if/when we do, michael@0: // decide how to handle them here. michael@0: michael@0: NS_NOTREACHED("oops, what platform is this?"); michael@0: return gfxPlatform::FontHintingEnabled(); michael@0: } michael@0: michael@0: bool michael@0: gfxAndroidPlatform::RequiresLinearZoom() michael@0: { michael@0: #ifdef MOZ_USING_ANDROID_JAVA_WIDGETS michael@0: // On android-java, we currently only use gecko to render web michael@0: // content that can always be be non-reflow-zoomed. michael@0: // michael@0: // XXX when gecko-android-java is used as an "app runtime", we may michael@0: // want to treat it like B2G and use linear zoom only for the web michael@0: // browser process, not other apps. michael@0: return true; michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: // On B2G, we need linear zoom for the browser, but otherwise prefer michael@0: // the improved glyph spacing that results from respecting the device michael@0: // pixel resolution for glyph layout (see bug 816614). michael@0: return XRE_GetProcessType() == GeckoProcessType_Content && michael@0: ContentChild::GetSingleton()->IsForBrowser(); michael@0: #endif michael@0: michael@0: NS_NOTREACHED("oops, what platform is this?"); michael@0: return gfxPlatform::RequiresLinearZoom(); michael@0: } michael@0: michael@0: int michael@0: gfxAndroidPlatform::GetScreenDepth() const michael@0: { michael@0: return mScreenDepth; michael@0: } michael@0: michael@0: bool michael@0: gfxAndroidPlatform::UseAcceleratedSkiaCanvas() michael@0: { michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: if (AndroidBridge::Bridge()->GetAPIVersion() < 11) { michael@0: // It's slower than software due to not having a compositing fast path michael@0: return false; michael@0: } michael@0: #endif michael@0: michael@0: return gfxPlatform::UseAcceleratedSkiaCanvas(); michael@0: }