1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/thebes/gfxAndroidPlatform.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,412 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim: set ts=8 sts=4 et sw=4 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "base/basictypes.h" 1.11 + 1.12 +#include "gfxAndroidPlatform.h" 1.13 +#include "mozilla/gfx/2D.h" 1.14 +#include "mozilla/Preferences.h" 1.15 + 1.16 +#include "gfx2DGlue.h" 1.17 +#include "gfxFT2FontList.h" 1.18 +#include "gfxImageSurface.h" 1.19 +#include "mozilla/dom/ContentChild.h" 1.20 +#include "nsXULAppAPI.h" 1.21 +#include "nsIScreen.h" 1.22 +#include "nsIScreenManager.h" 1.23 +#include "nsILocaleService.h" 1.24 +#include "nsServiceManagerUtils.h" 1.25 +#include "gfxPrefs.h" 1.26 +#include "cairo.h" 1.27 + 1.28 +#ifdef MOZ_WIDGET_ANDROID 1.29 +#include "AndroidBridge.h" 1.30 +#endif 1.31 + 1.32 +#ifdef MOZ_WIDGET_GONK 1.33 +#include <cutils/properties.h> 1.34 +#endif 1.35 + 1.36 +#include "ft2build.h" 1.37 +#include FT_FREETYPE_H 1.38 +#include FT_MODULE_H 1.39 + 1.40 +using namespace mozilla; 1.41 +using namespace mozilla::dom; 1.42 +using namespace mozilla::gfx; 1.43 + 1.44 +static FT_Library gPlatformFTLibrary = nullptr; 1.45 + 1.46 +class FreetypeReporter MOZ_FINAL : public nsIMemoryReporter, 1.47 + public CountingAllocatorBase<FreetypeReporter> 1.48 +{ 1.49 +public: 1.50 + NS_DECL_ISUPPORTS 1.51 + 1.52 + static void* Malloc(FT_Memory, long size) 1.53 + { 1.54 + return CountingMalloc(size); 1.55 + } 1.56 + 1.57 + static void Free(FT_Memory, void* p) 1.58 + { 1.59 + return CountingFree(p); 1.60 + } 1.61 + 1.62 + static void* 1.63 + Realloc(FT_Memory, long cur_size, long new_size, void* p) 1.64 + { 1.65 + return CountingRealloc(p, new_size); 1.66 + } 1.67 + 1.68 + NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, 1.69 + nsISupports* aData) 1.70 + { 1.71 + return MOZ_COLLECT_REPORT( 1.72 + "explicit/freetype", KIND_HEAP, UNITS_BYTES, MemoryAllocated(), 1.73 + "Memory used by Freetype."); 1.74 + } 1.75 +}; 1.76 + 1.77 +NS_IMPL_ISUPPORTS(FreetypeReporter, nsIMemoryReporter) 1.78 + 1.79 +template<> Atomic<size_t> CountingAllocatorBase<FreetypeReporter>::sAmount(0); 1.80 + 1.81 +static FT_MemoryRec_ sFreetypeMemoryRecord; 1.82 + 1.83 +gfxAndroidPlatform::gfxAndroidPlatform() 1.84 +{ 1.85 + // A custom allocator. It counts allocations, enabling memory reporting. 1.86 + sFreetypeMemoryRecord.user = nullptr; 1.87 + sFreetypeMemoryRecord.alloc = FreetypeReporter::Malloc; 1.88 + sFreetypeMemoryRecord.free = FreetypeReporter::Free; 1.89 + sFreetypeMemoryRecord.realloc = FreetypeReporter::Realloc; 1.90 + 1.91 + // These two calls are equivalent to FT_Init_FreeType(), but allow us to 1.92 + // provide a custom memory allocator. 1.93 + FT_New_Library(&sFreetypeMemoryRecord, &gPlatformFTLibrary); 1.94 + FT_Add_Default_Modules(gPlatformFTLibrary); 1.95 + 1.96 + RegisterStrongMemoryReporter(new FreetypeReporter()); 1.97 + 1.98 + nsCOMPtr<nsIScreenManager> screenMgr = do_GetService("@mozilla.org/gfx/screenmanager;1"); 1.99 + nsCOMPtr<nsIScreen> screen; 1.100 + screenMgr->GetPrimaryScreen(getter_AddRefs(screen)); 1.101 + mScreenDepth = 24; 1.102 + screen->GetColorDepth(&mScreenDepth); 1.103 + 1.104 + mOffscreenFormat = mScreenDepth == 16 1.105 + ? gfxImageFormat::RGB16_565 1.106 + : gfxImageFormat::RGB24; 1.107 + 1.108 + if (gfxPrefs::AndroidRGB16Force()) { 1.109 + mOffscreenFormat = gfxImageFormat::RGB16_565; 1.110 + } 1.111 + 1.112 +#ifdef MOZ_WIDGET_GONK 1.113 + char propQemu[PROPERTY_VALUE_MAX]; 1.114 + property_get("ro.kernel.qemu", propQemu, ""); 1.115 + mIsInGonkEmulator = !strncmp(propQemu, "1", 1); 1.116 +#endif 1.117 +} 1.118 + 1.119 +gfxAndroidPlatform::~gfxAndroidPlatform() 1.120 +{ 1.121 + FT_Done_Library(gPlatformFTLibrary); 1.122 + gPlatformFTLibrary = nullptr; 1.123 +} 1.124 + 1.125 +already_AddRefed<gfxASurface> 1.126 +gfxAndroidPlatform::CreateOffscreenSurface(const IntSize& size, 1.127 + gfxContentType contentType) 1.128 +{ 1.129 + nsRefPtr<gfxASurface> newSurface; 1.130 + newSurface = new gfxImageSurface(ThebesIntSize(size), 1.131 + OptimalFormatForContent(contentType)); 1.132 + 1.133 + return newSurface.forget(); 1.134 +} 1.135 + 1.136 +static bool 1.137 +IsJapaneseLocale() 1.138 +{ 1.139 + static bool sInitialized = false; 1.140 + static bool sIsJapanese = false; 1.141 + 1.142 + if (!sInitialized) { 1.143 + sInitialized = true; 1.144 + 1.145 + do { // to allow 'break' to abandon this block if a call fails 1.146 + nsresult rv; 1.147 + nsCOMPtr<nsILocaleService> ls = 1.148 + do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv); 1.149 + if (NS_FAILED(rv)) { 1.150 + break; 1.151 + } 1.152 + nsCOMPtr<nsILocale> appLocale; 1.153 + rv = ls->GetApplicationLocale(getter_AddRefs(appLocale)); 1.154 + if (NS_FAILED(rv)) { 1.155 + break; 1.156 + } 1.157 + nsString localeStr; 1.158 + rv = appLocale-> 1.159 + GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr); 1.160 + if (NS_FAILED(rv)) { 1.161 + break; 1.162 + } 1.163 + const nsAString& lang = nsDependentSubstring(localeStr, 0, 2); 1.164 + if (lang.EqualsLiteral("ja")) { 1.165 + sIsJapanese = true; 1.166 + } 1.167 + } while (false); 1.168 + } 1.169 + 1.170 + return sIsJapanese; 1.171 +} 1.172 + 1.173 +void 1.174 +gfxAndroidPlatform::GetCommonFallbackFonts(const uint32_t aCh, 1.175 + int32_t aRunScript, 1.176 + nsTArray<const char*>& aFontList) 1.177 +{ 1.178 + static const char kDroidSansJapanese[] = "Droid Sans Japanese"; 1.179 + static const char kMotoyaLMaru[] = "MotoyaLMaru"; 1.180 + 1.181 + if (IS_IN_BMP(aCh)) { 1.182 + // try language-specific "Droid Sans *" fonts for certain blocks, 1.183 + // as most devices probably have these 1.184 + uint8_t block = (aCh >> 8) & 0xff; 1.185 + switch (block) { 1.186 + case 0x05: 1.187 + aFontList.AppendElement("Droid Sans Hebrew"); 1.188 + aFontList.AppendElement("Droid Sans Armenian"); 1.189 + break; 1.190 + case 0x06: 1.191 + aFontList.AppendElement("Droid Sans Arabic"); 1.192 + break; 1.193 + case 0x09: 1.194 + aFontList.AppendElement("Droid Sans Devanagari"); 1.195 + break; 1.196 + case 0x0b: 1.197 + aFontList.AppendElement("Droid Sans Tamil"); 1.198 + break; 1.199 + case 0x0e: 1.200 + aFontList.AppendElement("Droid Sans Thai"); 1.201 + break; 1.202 + case 0x10: case 0x2d: 1.203 + aFontList.AppendElement("Droid Sans Georgian"); 1.204 + break; 1.205 + case 0x12: case 0x13: 1.206 + aFontList.AppendElement("Droid Sans Ethiopic"); 1.207 + break; 1.208 + case 0xf9: case 0xfa: 1.209 + if (IsJapaneseLocale()) { 1.210 + aFontList.AppendElement(kMotoyaLMaru); 1.211 + aFontList.AppendElement(kDroidSansJapanese); 1.212 + } 1.213 + break; 1.214 + default: 1.215 + if (block >= 0x2e && block <= 0x9f && IsJapaneseLocale()) { 1.216 + aFontList.AppendElement(kMotoyaLMaru); 1.217 + aFontList.AppendElement(kDroidSansJapanese); 1.218 + } 1.219 + break; 1.220 + } 1.221 + } 1.222 + // and try Droid Sans Fallback as a last resort 1.223 + aFontList.AppendElement("Droid Sans Fallback"); 1.224 +} 1.225 + 1.226 +nsresult 1.227 +gfxAndroidPlatform::GetFontList(nsIAtom *aLangGroup, 1.228 + const nsACString& aGenericFamily, 1.229 + nsTArray<nsString>& aListOfFonts) 1.230 +{ 1.231 + gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, 1.232 + aGenericFamily, 1.233 + aListOfFonts); 1.234 + return NS_OK; 1.235 +} 1.236 + 1.237 +void 1.238 +gfxAndroidPlatform::GetFontList(InfallibleTArray<FontListEntry>* retValue) 1.239 +{ 1.240 + gfxFT2FontList::PlatformFontList()->GetFontList(retValue); 1.241 +} 1.242 + 1.243 +nsresult 1.244 +gfxAndroidPlatform::UpdateFontList() 1.245 +{ 1.246 + gfxPlatformFontList::PlatformFontList()->UpdateFontList(); 1.247 + return NS_OK; 1.248 +} 1.249 + 1.250 +nsresult 1.251 +gfxAndroidPlatform::ResolveFontName(const nsAString& aFontName, 1.252 + FontResolverCallback aCallback, 1.253 + void *aClosure, 1.254 + bool& aAborted) 1.255 +{ 1.256 + nsAutoString resolvedName; 1.257 + if (!gfxPlatformFontList::PlatformFontList()-> 1.258 + ResolveFontName(aFontName, resolvedName)) { 1.259 + aAborted = false; 1.260 + return NS_OK; 1.261 + } 1.262 + aAborted = !(*aCallback)(resolvedName, aClosure); 1.263 + return NS_OK; 1.264 +} 1.265 + 1.266 +nsresult 1.267 +gfxAndroidPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) 1.268 +{ 1.269 + gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName); 1.270 + return NS_OK; 1.271 +} 1.272 + 1.273 +gfxPlatformFontList* 1.274 +gfxAndroidPlatform::CreatePlatformFontList() 1.275 +{ 1.276 + gfxPlatformFontList* list = new gfxFT2FontList(); 1.277 + if (NS_SUCCEEDED(list->InitFontList())) { 1.278 + return list; 1.279 + } 1.280 + gfxPlatformFontList::Shutdown(); 1.281 + return nullptr; 1.282 +} 1.283 + 1.284 +bool 1.285 +gfxAndroidPlatform::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) 1.286 +{ 1.287 + // check for strange format flags 1.288 + NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED), 1.289 + "strange font format hint set"); 1.290 + 1.291 + // accept supported formats 1.292 + if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_OPENTYPE | 1.293 + gfxUserFontSet::FLAG_FORMAT_WOFF | 1.294 + gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) { 1.295 + return true; 1.296 + } 1.297 + 1.298 + // reject all other formats, known and unknown 1.299 + if (aFormatFlags != 0) { 1.300 + return false; 1.301 + } 1.302 + 1.303 + // no format hint set, need to look at data 1.304 + return true; 1.305 +} 1.306 + 1.307 +gfxFontGroup * 1.308 +gfxAndroidPlatform::CreateFontGroup(const nsAString &aFamilies, 1.309 + const gfxFontStyle *aStyle, 1.310 + gfxUserFontSet* aUserFontSet) 1.311 +{ 1.312 + return new gfxFontGroup(aFamilies, aStyle, aUserFontSet); 1.313 +} 1.314 + 1.315 +FT_Library 1.316 +gfxAndroidPlatform::GetFTLibrary() 1.317 +{ 1.318 + return gPlatformFTLibrary; 1.319 +} 1.320 + 1.321 +gfxFontEntry* 1.322 +gfxAndroidPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, 1.323 + const uint8_t *aFontData, uint32_t aLength) 1.324 +{ 1.325 + return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry, 1.326 + aFontData, 1.327 + aLength); 1.328 +} 1.329 + 1.330 +gfxFontEntry* 1.331 +gfxAndroidPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, 1.332 + const nsAString& aFontName) 1.333 +{ 1.334 + return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry, 1.335 + aFontName); 1.336 +} 1.337 + 1.338 +TemporaryRef<ScaledFont> 1.339 +gfxAndroidPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont) 1.340 +{ 1.341 + return GetScaledFontForFontWithCairoSkia(aTarget, aFont); 1.342 +} 1.343 + 1.344 +bool 1.345 +gfxAndroidPlatform::FontHintingEnabled() 1.346 +{ 1.347 + // In "mobile" builds, we sometimes use non-reflow-zoom, so we 1.348 + // might not want hinting. Let's see. 1.349 + 1.350 +#ifdef MOZ_USING_ANDROID_JAVA_WIDGETS 1.351 + // On android-java, we currently only use gecko to render web 1.352 + // content that can always be be non-reflow-zoomed. So turn off 1.353 + // hinting. 1.354 + // 1.355 + // XXX when gecko-android-java is used as an "app runtime", we may 1.356 + // want to re-enable hinting for non-browser processes there. 1.357 + return false; 1.358 +#endif // MOZ_USING_ANDROID_JAVA_WIDGETS 1.359 + 1.360 +#ifdef MOZ_WIDGET_GONK 1.361 + // On B2G, the UX preference is currently to keep hinting disabled 1.362 + // for all text (see bug 829523). 1.363 + return false; 1.364 +#endif 1.365 + 1.366 + // Currently, we don't have any other targets, but if/when we do, 1.367 + // decide how to handle them here. 1.368 + 1.369 + NS_NOTREACHED("oops, what platform is this?"); 1.370 + return gfxPlatform::FontHintingEnabled(); 1.371 +} 1.372 + 1.373 +bool 1.374 +gfxAndroidPlatform::RequiresLinearZoom() 1.375 +{ 1.376 +#ifdef MOZ_USING_ANDROID_JAVA_WIDGETS 1.377 + // On android-java, we currently only use gecko to render web 1.378 + // content that can always be be non-reflow-zoomed. 1.379 + // 1.380 + // XXX when gecko-android-java is used as an "app runtime", we may 1.381 + // want to treat it like B2G and use linear zoom only for the web 1.382 + // browser process, not other apps. 1.383 + return true; 1.384 +#endif 1.385 + 1.386 +#ifdef MOZ_WIDGET_GONK 1.387 + // On B2G, we need linear zoom for the browser, but otherwise prefer 1.388 + // the improved glyph spacing that results from respecting the device 1.389 + // pixel resolution for glyph layout (see bug 816614). 1.390 + return XRE_GetProcessType() == GeckoProcessType_Content && 1.391 + ContentChild::GetSingleton()->IsForBrowser(); 1.392 +#endif 1.393 + 1.394 + NS_NOTREACHED("oops, what platform is this?"); 1.395 + return gfxPlatform::RequiresLinearZoom(); 1.396 +} 1.397 + 1.398 +int 1.399 +gfxAndroidPlatform::GetScreenDepth() const 1.400 +{ 1.401 + return mScreenDepth; 1.402 +} 1.403 + 1.404 +bool 1.405 +gfxAndroidPlatform::UseAcceleratedSkiaCanvas() 1.406 +{ 1.407 +#ifdef MOZ_WIDGET_ANDROID 1.408 + if (AndroidBridge::Bridge()->GetAPIVersion() < 11) { 1.409 + // It's slower than software due to not having a compositing fast path 1.410 + return false; 1.411 + } 1.412 +#endif 1.413 + 1.414 + return gfxPlatform::UseAcceleratedSkiaCanvas(); 1.415 +}