gfx/thebes/gfxAndroidPlatform.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* vim: set ts=8 sts=4 et sw=4 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "base/basictypes.h"
michael@0 8
michael@0 9 #include "gfxAndroidPlatform.h"
michael@0 10 #include "mozilla/gfx/2D.h"
michael@0 11 #include "mozilla/Preferences.h"
michael@0 12
michael@0 13 #include "gfx2DGlue.h"
michael@0 14 #include "gfxFT2FontList.h"
michael@0 15 #include "gfxImageSurface.h"
michael@0 16 #include "mozilla/dom/ContentChild.h"
michael@0 17 #include "nsXULAppAPI.h"
michael@0 18 #include "nsIScreen.h"
michael@0 19 #include "nsIScreenManager.h"
michael@0 20 #include "nsILocaleService.h"
michael@0 21 #include "nsServiceManagerUtils.h"
michael@0 22 #include "gfxPrefs.h"
michael@0 23 #include "cairo.h"
michael@0 24
michael@0 25 #ifdef MOZ_WIDGET_ANDROID
michael@0 26 #include "AndroidBridge.h"
michael@0 27 #endif
michael@0 28
michael@0 29 #ifdef MOZ_WIDGET_GONK
michael@0 30 #include <cutils/properties.h>
michael@0 31 #endif
michael@0 32
michael@0 33 #include "ft2build.h"
michael@0 34 #include FT_FREETYPE_H
michael@0 35 #include FT_MODULE_H
michael@0 36
michael@0 37 using namespace mozilla;
michael@0 38 using namespace mozilla::dom;
michael@0 39 using namespace mozilla::gfx;
michael@0 40
michael@0 41 static FT_Library gPlatformFTLibrary = nullptr;
michael@0 42
michael@0 43 class FreetypeReporter MOZ_FINAL : public nsIMemoryReporter,
michael@0 44 public CountingAllocatorBase<FreetypeReporter>
michael@0 45 {
michael@0 46 public:
michael@0 47 NS_DECL_ISUPPORTS
michael@0 48
michael@0 49 static void* Malloc(FT_Memory, long size)
michael@0 50 {
michael@0 51 return CountingMalloc(size);
michael@0 52 }
michael@0 53
michael@0 54 static void Free(FT_Memory, void* p)
michael@0 55 {
michael@0 56 return CountingFree(p);
michael@0 57 }
michael@0 58
michael@0 59 static void*
michael@0 60 Realloc(FT_Memory, long cur_size, long new_size, void* p)
michael@0 61 {
michael@0 62 return CountingRealloc(p, new_size);
michael@0 63 }
michael@0 64
michael@0 65 NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
michael@0 66 nsISupports* aData)
michael@0 67 {
michael@0 68 return MOZ_COLLECT_REPORT(
michael@0 69 "explicit/freetype", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
michael@0 70 "Memory used by Freetype.");
michael@0 71 }
michael@0 72 };
michael@0 73
michael@0 74 NS_IMPL_ISUPPORTS(FreetypeReporter, nsIMemoryReporter)
michael@0 75
michael@0 76 template<> Atomic<size_t> CountingAllocatorBase<FreetypeReporter>::sAmount(0);
michael@0 77
michael@0 78 static FT_MemoryRec_ sFreetypeMemoryRecord;
michael@0 79
michael@0 80 gfxAndroidPlatform::gfxAndroidPlatform()
michael@0 81 {
michael@0 82 // A custom allocator. It counts allocations, enabling memory reporting.
michael@0 83 sFreetypeMemoryRecord.user = nullptr;
michael@0 84 sFreetypeMemoryRecord.alloc = FreetypeReporter::Malloc;
michael@0 85 sFreetypeMemoryRecord.free = FreetypeReporter::Free;
michael@0 86 sFreetypeMemoryRecord.realloc = FreetypeReporter::Realloc;
michael@0 87
michael@0 88 // These two calls are equivalent to FT_Init_FreeType(), but allow us to
michael@0 89 // provide a custom memory allocator.
michael@0 90 FT_New_Library(&sFreetypeMemoryRecord, &gPlatformFTLibrary);
michael@0 91 FT_Add_Default_Modules(gPlatformFTLibrary);
michael@0 92
michael@0 93 RegisterStrongMemoryReporter(new FreetypeReporter());
michael@0 94
michael@0 95 nsCOMPtr<nsIScreenManager> screenMgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
michael@0 96 nsCOMPtr<nsIScreen> screen;
michael@0 97 screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
michael@0 98 mScreenDepth = 24;
michael@0 99 screen->GetColorDepth(&mScreenDepth);
michael@0 100
michael@0 101 mOffscreenFormat = mScreenDepth == 16
michael@0 102 ? gfxImageFormat::RGB16_565
michael@0 103 : gfxImageFormat::RGB24;
michael@0 104
michael@0 105 if (gfxPrefs::AndroidRGB16Force()) {
michael@0 106 mOffscreenFormat = gfxImageFormat::RGB16_565;
michael@0 107 }
michael@0 108
michael@0 109 #ifdef MOZ_WIDGET_GONK
michael@0 110 char propQemu[PROPERTY_VALUE_MAX];
michael@0 111 property_get("ro.kernel.qemu", propQemu, "");
michael@0 112 mIsInGonkEmulator = !strncmp(propQemu, "1", 1);
michael@0 113 #endif
michael@0 114 }
michael@0 115
michael@0 116 gfxAndroidPlatform::~gfxAndroidPlatform()
michael@0 117 {
michael@0 118 FT_Done_Library(gPlatformFTLibrary);
michael@0 119 gPlatformFTLibrary = nullptr;
michael@0 120 }
michael@0 121
michael@0 122 already_AddRefed<gfxASurface>
michael@0 123 gfxAndroidPlatform::CreateOffscreenSurface(const IntSize& size,
michael@0 124 gfxContentType contentType)
michael@0 125 {
michael@0 126 nsRefPtr<gfxASurface> newSurface;
michael@0 127 newSurface = new gfxImageSurface(ThebesIntSize(size),
michael@0 128 OptimalFormatForContent(contentType));
michael@0 129
michael@0 130 return newSurface.forget();
michael@0 131 }
michael@0 132
michael@0 133 static bool
michael@0 134 IsJapaneseLocale()
michael@0 135 {
michael@0 136 static bool sInitialized = false;
michael@0 137 static bool sIsJapanese = false;
michael@0 138
michael@0 139 if (!sInitialized) {
michael@0 140 sInitialized = true;
michael@0 141
michael@0 142 do { // to allow 'break' to abandon this block if a call fails
michael@0 143 nsresult rv;
michael@0 144 nsCOMPtr<nsILocaleService> ls =
michael@0 145 do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
michael@0 146 if (NS_FAILED(rv)) {
michael@0 147 break;
michael@0 148 }
michael@0 149 nsCOMPtr<nsILocale> appLocale;
michael@0 150 rv = ls->GetApplicationLocale(getter_AddRefs(appLocale));
michael@0 151 if (NS_FAILED(rv)) {
michael@0 152 break;
michael@0 153 }
michael@0 154 nsString localeStr;
michael@0 155 rv = appLocale->
michael@0 156 GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr);
michael@0 157 if (NS_FAILED(rv)) {
michael@0 158 break;
michael@0 159 }
michael@0 160 const nsAString& lang = nsDependentSubstring(localeStr, 0, 2);
michael@0 161 if (lang.EqualsLiteral("ja")) {
michael@0 162 sIsJapanese = true;
michael@0 163 }
michael@0 164 } while (false);
michael@0 165 }
michael@0 166
michael@0 167 return sIsJapanese;
michael@0 168 }
michael@0 169
michael@0 170 void
michael@0 171 gfxAndroidPlatform::GetCommonFallbackFonts(const uint32_t aCh,
michael@0 172 int32_t aRunScript,
michael@0 173 nsTArray<const char*>& aFontList)
michael@0 174 {
michael@0 175 static const char kDroidSansJapanese[] = "Droid Sans Japanese";
michael@0 176 static const char kMotoyaLMaru[] = "MotoyaLMaru";
michael@0 177
michael@0 178 if (IS_IN_BMP(aCh)) {
michael@0 179 // try language-specific "Droid Sans *" fonts for certain blocks,
michael@0 180 // as most devices probably have these
michael@0 181 uint8_t block = (aCh >> 8) & 0xff;
michael@0 182 switch (block) {
michael@0 183 case 0x05:
michael@0 184 aFontList.AppendElement("Droid Sans Hebrew");
michael@0 185 aFontList.AppendElement("Droid Sans Armenian");
michael@0 186 break;
michael@0 187 case 0x06:
michael@0 188 aFontList.AppendElement("Droid Sans Arabic");
michael@0 189 break;
michael@0 190 case 0x09:
michael@0 191 aFontList.AppendElement("Droid Sans Devanagari");
michael@0 192 break;
michael@0 193 case 0x0b:
michael@0 194 aFontList.AppendElement("Droid Sans Tamil");
michael@0 195 break;
michael@0 196 case 0x0e:
michael@0 197 aFontList.AppendElement("Droid Sans Thai");
michael@0 198 break;
michael@0 199 case 0x10: case 0x2d:
michael@0 200 aFontList.AppendElement("Droid Sans Georgian");
michael@0 201 break;
michael@0 202 case 0x12: case 0x13:
michael@0 203 aFontList.AppendElement("Droid Sans Ethiopic");
michael@0 204 break;
michael@0 205 case 0xf9: case 0xfa:
michael@0 206 if (IsJapaneseLocale()) {
michael@0 207 aFontList.AppendElement(kMotoyaLMaru);
michael@0 208 aFontList.AppendElement(kDroidSansJapanese);
michael@0 209 }
michael@0 210 break;
michael@0 211 default:
michael@0 212 if (block >= 0x2e && block <= 0x9f && IsJapaneseLocale()) {
michael@0 213 aFontList.AppendElement(kMotoyaLMaru);
michael@0 214 aFontList.AppendElement(kDroidSansJapanese);
michael@0 215 }
michael@0 216 break;
michael@0 217 }
michael@0 218 }
michael@0 219 // and try Droid Sans Fallback as a last resort
michael@0 220 aFontList.AppendElement("Droid Sans Fallback");
michael@0 221 }
michael@0 222
michael@0 223 nsresult
michael@0 224 gfxAndroidPlatform::GetFontList(nsIAtom *aLangGroup,
michael@0 225 const nsACString& aGenericFamily,
michael@0 226 nsTArray<nsString>& aListOfFonts)
michael@0 227 {
michael@0 228 gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup,
michael@0 229 aGenericFamily,
michael@0 230 aListOfFonts);
michael@0 231 return NS_OK;
michael@0 232 }
michael@0 233
michael@0 234 void
michael@0 235 gfxAndroidPlatform::GetFontList(InfallibleTArray<FontListEntry>* retValue)
michael@0 236 {
michael@0 237 gfxFT2FontList::PlatformFontList()->GetFontList(retValue);
michael@0 238 }
michael@0 239
michael@0 240 nsresult
michael@0 241 gfxAndroidPlatform::UpdateFontList()
michael@0 242 {
michael@0 243 gfxPlatformFontList::PlatformFontList()->UpdateFontList();
michael@0 244 return NS_OK;
michael@0 245 }
michael@0 246
michael@0 247 nsresult
michael@0 248 gfxAndroidPlatform::ResolveFontName(const nsAString& aFontName,
michael@0 249 FontResolverCallback aCallback,
michael@0 250 void *aClosure,
michael@0 251 bool& aAborted)
michael@0 252 {
michael@0 253 nsAutoString resolvedName;
michael@0 254 if (!gfxPlatformFontList::PlatformFontList()->
michael@0 255 ResolveFontName(aFontName, resolvedName)) {
michael@0 256 aAborted = false;
michael@0 257 return NS_OK;
michael@0 258 }
michael@0 259 aAborted = !(*aCallback)(resolvedName, aClosure);
michael@0 260 return NS_OK;
michael@0 261 }
michael@0 262
michael@0 263 nsresult
michael@0 264 gfxAndroidPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
michael@0 265 {
michael@0 266 gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
michael@0 267 return NS_OK;
michael@0 268 }
michael@0 269
michael@0 270 gfxPlatformFontList*
michael@0 271 gfxAndroidPlatform::CreatePlatformFontList()
michael@0 272 {
michael@0 273 gfxPlatformFontList* list = new gfxFT2FontList();
michael@0 274 if (NS_SUCCEEDED(list->InitFontList())) {
michael@0 275 return list;
michael@0 276 }
michael@0 277 gfxPlatformFontList::Shutdown();
michael@0 278 return nullptr;
michael@0 279 }
michael@0 280
michael@0 281 bool
michael@0 282 gfxAndroidPlatform::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags)
michael@0 283 {
michael@0 284 // check for strange format flags
michael@0 285 NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
michael@0 286 "strange font format hint set");
michael@0 287
michael@0 288 // accept supported formats
michael@0 289 if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_OPENTYPE |
michael@0 290 gfxUserFontSet::FLAG_FORMAT_WOFF |
michael@0 291 gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) {
michael@0 292 return true;
michael@0 293 }
michael@0 294
michael@0 295 // reject all other formats, known and unknown
michael@0 296 if (aFormatFlags != 0) {
michael@0 297 return false;
michael@0 298 }
michael@0 299
michael@0 300 // no format hint set, need to look at data
michael@0 301 return true;
michael@0 302 }
michael@0 303
michael@0 304 gfxFontGroup *
michael@0 305 gfxAndroidPlatform::CreateFontGroup(const nsAString &aFamilies,
michael@0 306 const gfxFontStyle *aStyle,
michael@0 307 gfxUserFontSet* aUserFontSet)
michael@0 308 {
michael@0 309 return new gfxFontGroup(aFamilies, aStyle, aUserFontSet);
michael@0 310 }
michael@0 311
michael@0 312 FT_Library
michael@0 313 gfxAndroidPlatform::GetFTLibrary()
michael@0 314 {
michael@0 315 return gPlatformFTLibrary;
michael@0 316 }
michael@0 317
michael@0 318 gfxFontEntry*
michael@0 319 gfxAndroidPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
michael@0 320 const uint8_t *aFontData, uint32_t aLength)
michael@0 321 {
michael@0 322 return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry,
michael@0 323 aFontData,
michael@0 324 aLength);
michael@0 325 }
michael@0 326
michael@0 327 gfxFontEntry*
michael@0 328 gfxAndroidPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
michael@0 329 const nsAString& aFontName)
michael@0 330 {
michael@0 331 return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry,
michael@0 332 aFontName);
michael@0 333 }
michael@0 334
michael@0 335 TemporaryRef<ScaledFont>
michael@0 336 gfxAndroidPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
michael@0 337 {
michael@0 338 return GetScaledFontForFontWithCairoSkia(aTarget, aFont);
michael@0 339 }
michael@0 340
michael@0 341 bool
michael@0 342 gfxAndroidPlatform::FontHintingEnabled()
michael@0 343 {
michael@0 344 // In "mobile" builds, we sometimes use non-reflow-zoom, so we
michael@0 345 // might not want hinting. Let's see.
michael@0 346
michael@0 347 #ifdef MOZ_USING_ANDROID_JAVA_WIDGETS
michael@0 348 // On android-java, we currently only use gecko to render web
michael@0 349 // content that can always be be non-reflow-zoomed. So turn off
michael@0 350 // hinting.
michael@0 351 //
michael@0 352 // XXX when gecko-android-java is used as an "app runtime", we may
michael@0 353 // want to re-enable hinting for non-browser processes there.
michael@0 354 return false;
michael@0 355 #endif // MOZ_USING_ANDROID_JAVA_WIDGETS
michael@0 356
michael@0 357 #ifdef MOZ_WIDGET_GONK
michael@0 358 // On B2G, the UX preference is currently to keep hinting disabled
michael@0 359 // for all text (see bug 829523).
michael@0 360 return false;
michael@0 361 #endif
michael@0 362
michael@0 363 // Currently, we don't have any other targets, but if/when we do,
michael@0 364 // decide how to handle them here.
michael@0 365
michael@0 366 NS_NOTREACHED("oops, what platform is this?");
michael@0 367 return gfxPlatform::FontHintingEnabled();
michael@0 368 }
michael@0 369
michael@0 370 bool
michael@0 371 gfxAndroidPlatform::RequiresLinearZoom()
michael@0 372 {
michael@0 373 #ifdef MOZ_USING_ANDROID_JAVA_WIDGETS
michael@0 374 // On android-java, we currently only use gecko to render web
michael@0 375 // content that can always be be non-reflow-zoomed.
michael@0 376 //
michael@0 377 // XXX when gecko-android-java is used as an "app runtime", we may
michael@0 378 // want to treat it like B2G and use linear zoom only for the web
michael@0 379 // browser process, not other apps.
michael@0 380 return true;
michael@0 381 #endif
michael@0 382
michael@0 383 #ifdef MOZ_WIDGET_GONK
michael@0 384 // On B2G, we need linear zoom for the browser, but otherwise prefer
michael@0 385 // the improved glyph spacing that results from respecting the device
michael@0 386 // pixel resolution for glyph layout (see bug 816614).
michael@0 387 return XRE_GetProcessType() == GeckoProcessType_Content &&
michael@0 388 ContentChild::GetSingleton()->IsForBrowser();
michael@0 389 #endif
michael@0 390
michael@0 391 NS_NOTREACHED("oops, what platform is this?");
michael@0 392 return gfxPlatform::RequiresLinearZoom();
michael@0 393 }
michael@0 394
michael@0 395 int
michael@0 396 gfxAndroidPlatform::GetScreenDepth() const
michael@0 397 {
michael@0 398 return mScreenDepth;
michael@0 399 }
michael@0 400
michael@0 401 bool
michael@0 402 gfxAndroidPlatform::UseAcceleratedSkiaCanvas()
michael@0 403 {
michael@0 404 #ifdef MOZ_WIDGET_ANDROID
michael@0 405 if (AndroidBridge::Bridge()->GetAPIVersion() < 11) {
michael@0 406 // It's slower than software due to not having a compositing fast path
michael@0 407 return false;
michael@0 408 }
michael@0 409 #endif
michael@0 410
michael@0 411 return gfxPlatform::UseAcceleratedSkiaCanvas();
michael@0 412 }

mercurial