/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- *//* vim: set ts=8 sts=4 et sw=4 tw=80: *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"base/basictypes.h"#include"gfxAndroidPlatform.h"#include"mozilla/gfx/2D.h"#include"mozilla/CountingAllocatorBase.h"#include"mozilla/Preferences.h"#include"gfx2DGlue.h"#include"gfxFT2FontList.h"#include"gfxImageSurface.h"#include"gfxTextRun.h"#include"mozilla/dom/ContentChild.h"#include"nsXULAppAPI.h"#include"nsIScreen.h"#include"nsIScreenManager.h"#include"nsILocaleService.h"#include"nsServiceManagerUtils.h"#include"gfxPrefs.h"#include"cairo.h"#include"VsyncSource.h"#ifdef MOZ_WIDGET_ANDROID#include"AndroidBridge.h"#endif#ifdef MOZ_WIDGET_GONK#include<cutils/properties.h>#include"mozilla/layers/CompositorBridgeParent.h"#include"HwcComposer2D.h"#endif#include"ft2build.h"#includeFT_FREETYPE_H#includeFT_MODULE_Husingnamespacemozilla;usingnamespacemozilla::dom;usingnamespacemozilla::gfx;staticFT_LibrarygPlatformFTLibrary=nullptr;classFreetypeReporterfinal:publicnsIMemoryReporter,publicCountingAllocatorBase<FreetypeReporter>{private:~FreetypeReporter(){}public:NS_DECL_ISUPPORTSstaticvoid*Malloc(FT_Memory,longsize){returnCountingMalloc(size);}staticvoidFree(FT_Memory,void*p){returnCountingFree(p);}staticvoid*Realloc(FT_Memory,longcur_size,longnew_size,void*p){returnCountingRealloc(p,new_size);}NS_IMETHODCollectReports(nsIHandleReportCallback*aHandleReport,nsISupports*aData,boolaAnonymize){returnMOZ_COLLECT_REPORT("explicit/freetype",KIND_HEAP,UNITS_BYTES,MemoryAllocated(),"Memory used by Freetype.");}};NS_IMPL_ISUPPORTS(FreetypeReporter,nsIMemoryReporter)template<>Atomic<size_t>CountingAllocatorBase<FreetypeReporter>::sAmount(0);staticFT_MemoryRec_sFreetypeMemoryRecord;gfxAndroidPlatform::gfxAndroidPlatform(){// A custom allocator. It counts allocations, enabling memory reporting.sFreetypeMemoryRecord.user=nullptr;sFreetypeMemoryRecord.alloc=FreetypeReporter::Malloc;sFreetypeMemoryRecord.free=FreetypeReporter::Free;sFreetypeMemoryRecord.realloc=FreetypeReporter::Realloc;// These two calls are equivalent to FT_Init_FreeType(), but allow us to// provide a custom memory allocator.FT_New_Library(&sFreetypeMemoryRecord,&gPlatformFTLibrary);FT_Add_Default_Modules(gPlatformFTLibrary);RegisterStrongMemoryReporter(newFreetypeReporter());mOffscreenFormat=GetScreenDepth()==16?SurfaceFormat::R5G6B5_UINT16:SurfaceFormat::X8R8G8B8_UINT32;if(gfxPrefs::AndroidRGB16Force()){mOffscreenFormat=SurfaceFormat::R5G6B5_UINT16;}#ifdef MOZ_WIDGET_GONKcharpropQemu[PROPERTY_VALUE_MAX];property_get("ro.kernel.qemu",propQemu,"");mIsInGonkEmulator=!strncmp(propQemu,"1",1);#endif}gfxAndroidPlatform::~gfxAndroidPlatform(){FT_Done_Library(gPlatformFTLibrary);gPlatformFTLibrary=nullptr;}already_AddRefed<gfxASurface>gfxAndroidPlatform::CreateOffscreenSurface(constIntSize&aSize,gfxImageFormataFormat){RefPtr<gfxASurface>newSurface;newSurface=newgfxImageSurface(aSize,aFormat);returnnewSurface.forget();}staticboolIsJapaneseLocale(){staticboolsInitialized=false;staticboolsIsJapanese=false;if(!sInitialized){sInitialized=true;do{// to allow 'break' to abandon this block if a call failsnsresultrv;nsCOMPtr<nsILocaleService>ls=do_GetService(NS_LOCALESERVICE_CONTRACTID,&rv);if(NS_FAILED(rv)){break;}nsCOMPtr<nsILocale>appLocale;rv=ls->GetApplicationLocale(getter_AddRefs(appLocale));if(NS_FAILED(rv)){break;}nsStringlocaleStr;rv=appLocale->GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE),localeStr);if(NS_FAILED(rv)){break;}constnsAString&lang=nsDependentSubstring(localeStr,0,2);if(lang.EqualsLiteral("ja")){sIsJapanese=true;}}while(false);}returnsIsJapanese;}voidgfxAndroidPlatform::GetCommonFallbackFonts(uint32_taCh,uint32_taNextCh,ScriptaRunScript,nsTArray<constchar*>&aFontList){staticconstcharkDroidSansJapanese[]="Droid Sans Japanese";staticconstcharkMotoyaLMaru[]="MotoyaLMaru";staticconstcharkNotoColorEmoji[]="Noto Color Emoji";#ifdef MOZ_WIDGET_GONKstaticconstcharkFirefoxEmoji[]="Firefox Emoji";#endifif(aNextCh==0xfe0fu){// if char is followed by VS16, try for a color emoji glyph#ifdef MOZ_WIDGET_GONKaFontList.AppendElement(kFirefoxEmoji);#endifaFontList.AppendElement(kNotoColorEmoji);}if(!IS_IN_BMP(aCh)){uint32_tp=aCh>>16;if(p==1){// try color emoji font, unless VS15 (text style) presentif(aNextCh!=0xfe0fu&&aNextCh!=0xfe0eu){#ifdef MOZ_WIDGET_GONKaFontList.AppendElement(kFirefoxEmoji);#endifaFontList.AppendElement(kNotoColorEmoji);}}}else{// try language-specific "Droid Sans *" and "Noto Sans *" fonts for// certain blocks, as most devices probably have theseuint8_tblock=(aCh>>8)&0xff;switch(block){case0x05:aFontList.AppendElement("Droid Sans Hebrew");aFontList.AppendElement("Droid Sans Armenian");break;case0x06:aFontList.AppendElement("Droid Sans Arabic");break;case0x09:aFontList.AppendElement("Noto Sans Devanagari");aFontList.AppendElement("Droid Sans Devanagari");break;case0x0b:aFontList.AppendElement("Noto Sans Tamil");aFontList.AppendElement("Droid Sans Tamil");break;case0x0e:aFontList.AppendElement("Noto Sans Thai");aFontList.AppendElement("Droid Sans Thai");break;case0x10:case0x2d:aFontList.AppendElement("Droid Sans Georgian");break;case0x12:case0x13:aFontList.AppendElement("Droid Sans Ethiopic");break;case0xf9:case0xfa:if(IsJapaneseLocale()){aFontList.AppendElement(kMotoyaLMaru);aFontList.AppendElement(kDroidSansJapanese);}break;default:if(block>=0x2e&&block<=0x9f&&IsJapaneseLocale()){aFontList.AppendElement(kMotoyaLMaru);aFontList.AppendElement(kDroidSansJapanese);}break;}}// and try Droid Sans Fallback as a last resortaFontList.AppendElement("Droid Sans Fallback");}voidgfxAndroidPlatform::GetSystemFontList(InfallibleTArray<FontListEntry>*retValue){gfxFT2FontList::PlatformFontList()->GetSystemFontList(retValue);}gfxPlatformFontList*gfxAndroidPlatform::CreatePlatformFontList(){gfxPlatformFontList*list=newgfxFT2FontList();if(NS_SUCCEEDED(list->InitFontList())){returnlist;}gfxPlatformFontList::Shutdown();returnnullptr;}boolgfxAndroidPlatform::IsFontFormatSupported(nsIURI*aFontURI,uint32_taFormatFlags){// check for strange format flagsNS_ASSERTION(!(aFormatFlags&gfxUserFontSet::FLAG_FORMAT_NOT_USED),"strange font format hint set");// accept supported formatsif(aFormatFlags&gfxUserFontSet::FLAG_FORMATS_COMMON){returntrue;}// reject all other formats, known and unknownif(aFormatFlags!=0){returnfalse;}// no format hint set, need to look at datareturntrue;}gfxFontGroup*gfxAndroidPlatform::CreateFontGroup(constFontFamilyList&aFontFamilyList,constgfxFontStyle*aStyle,gfxTextPerfMetrics*aTextPerf,gfxUserFontSet*aUserFontSet,gfxFloataDevToCssSize){returnnewgfxFontGroup(aFontFamilyList,aStyle,aTextPerf,aUserFontSet,aDevToCssSize);}FT_LibrarygfxAndroidPlatform::GetFTLibrary(){returngPlatformFTLibrary;}already_AddRefed<ScaledFont>gfxAndroidPlatform::GetScaledFontForFont(DrawTarget*aTarget,gfxFont*aFont){returnGetScaledFontForFontWithCairoSkia(aTarget,aFont);}boolgfxAndroidPlatform::FontHintingEnabled(){// In "mobile" builds, we sometimes use non-reflow-zoom, so we// might not want hinting. Let's see.#ifdef MOZ_USING_ANDROID_JAVA_WIDGETS// On android-java, we currently only use gecko to render web// content that can always be be non-reflow-zoomed. So turn off// hinting.// // XXX when gecko-android-java is used as an "app runtime", we may// want to re-enable hinting for non-browser processes there.returnfalse;#endif // MOZ_USING_ANDROID_JAVA_WIDGETS#ifdef MOZ_WIDGET_GONK// On B2G, the UX preference is currently to keep hinting disabled// for all text (see bug 829523).returnfalse;#endif// Currently, we don't have any other targets, but if/when we do,// decide how to handle them here.NS_NOTREACHED("oops, what platform is this?");returngfxPlatform::FontHintingEnabled();}boolgfxAndroidPlatform::RequiresLinearZoom(){#ifdef MOZ_USING_ANDROID_JAVA_WIDGETS// On android-java, we currently only use gecko to render web// content that can always be be non-reflow-zoomed.//// XXX when gecko-android-java is used as an "app runtime", we may// want to treat it like B2G and use linear zoom only for the web// browser process, not other apps.returntrue;#endif#ifdef MOZ_WIDGET_GONK// On B2G, we need linear zoom for the browser, but otherwise prefer// the improved glyph spacing that results from respecting the device// pixel resolution for glyph layout (see bug 816614).returnXRE_IsContentProcess()&&ContentChild::GetSingleton()->IsForBrowser();#endifNS_NOTREACHED("oops, what platform is this?");returngfxPlatform::RequiresLinearZoom();}#ifdef MOZ_WIDGET_GONKclassGonkVsyncSourcefinal:publicVsyncSource{public:GonkVsyncSource(){}virtualDisplay&GetGlobalDisplay()override{returnmGlobalDisplay;}classGonkDisplayfinal:publicVsyncSource::Display{public:GonkDisplay():mVsyncEnabled(false){}~GonkDisplay(){MOZ_ASSERT(NS_IsMainThread());}virtualvoidShutdown()override{MOZ_ASSERT(NS_IsMainThread());DisableVsync();}virtualvoidEnableVsync()override{MOZ_ASSERT(NS_IsMainThread());if(IsVsyncEnabled()){return;}mVsyncEnabled=HwcComposer2D::GetInstance()->EnableVsync(true);}virtualvoidDisableVsync()override{MOZ_ASSERT(NS_IsMainThread());if(!IsVsyncEnabled()){return;}mVsyncEnabled=HwcComposer2D::GetInstance()->EnableVsync(false);}virtualboolIsVsyncEnabled()override{MOZ_ASSERT(NS_IsMainThread());returnmVsyncEnabled;}private:boolmVsyncEnabled;};// GonkDisplayprivate:virtual~GonkVsyncSource(){}GonkDisplaymGlobalDisplay;};// GonkVsyncSource#endifalready_AddRefed<mozilla::gfx::VsyncSource>gfxAndroidPlatform::CreateHardwareVsyncSource(){// Only enable true hardware vsync on kit-kat and L device. Jelly Bean has// inaccurate hardware vsync so disable on JB. Android pre-JB doesn't have// hardware vsync.// L is android version 21, L-MR1 is 22, kit-kat is 19, 20 is kit-kat for// wearables.#if defined(MOZ_WIDGET_GONK) && (ANDROID_VERSION == 19 || ANDROID_VERSION >= 21)RefPtr<GonkVsyncSource>vsyncSource=newGonkVsyncSource();VsyncSource::Display&display=vsyncSource->GetGlobalDisplay();display.EnableVsync();if(!display.IsVsyncEnabled()){NS_WARNING("Error enabling gonk vsync. Falling back to software vsync");returngfxPlatform::CreateHardwareVsyncSource();}display.DisableVsync();returnvsyncSource.forget();#elsereturngfxPlatform::CreateHardwareVsyncSource();#endif}