gfx/thebes/gfxPlatform.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: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #ifdef MOZ_LOGGING
michael@0 7 #define FORCE_PR_LOG /* Allow logging in the release build */
michael@0 8 #endif
michael@0 9
michael@0 10 #include "mozilla/layers/CompositorChild.h"
michael@0 11 #include "mozilla/layers/CompositorParent.h"
michael@0 12 #include "mozilla/layers/ImageBridgeChild.h"
michael@0 13 #include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter
michael@0 14
michael@0 15 #include "prlog.h"
michael@0 16
michael@0 17 #include "gfxPlatform.h"
michael@0 18 #include "gfxPrefs.h"
michael@0 19
michael@0 20 #ifdef XP_WIN
michael@0 21 #include <process.h>
michael@0 22 #define getpid _getpid
michael@0 23 #else
michael@0 24 #include <unistd.h>
michael@0 25 #endif
michael@0 26
michael@0 27 #include "nsXULAppAPI.h"
michael@0 28 #include "nsDirectoryServiceUtils.h"
michael@0 29 #include "nsDirectoryServiceDefs.h"
michael@0 30
michael@0 31 #if defined(XP_WIN)
michael@0 32 #include "gfxWindowsPlatform.h"
michael@0 33 #include "gfxD2DSurface.h"
michael@0 34 #elif defined(XP_MACOSX)
michael@0 35 #include "gfxPlatformMac.h"
michael@0 36 #include "gfxQuartzSurface.h"
michael@0 37 #elif defined(MOZ_WIDGET_GTK)
michael@0 38 #include "gfxPlatformGtk.h"
michael@0 39 #elif defined(MOZ_WIDGET_QT)
michael@0 40 #include "gfxQtPlatform.h"
michael@0 41 #elif defined(ANDROID)
michael@0 42 #include "gfxAndroidPlatform.h"
michael@0 43 #endif
michael@0 44
michael@0 45 #include "nsGkAtoms.h"
michael@0 46 #include "gfxPlatformFontList.h"
michael@0 47 #include "gfxContext.h"
michael@0 48 #include "gfxImageSurface.h"
michael@0 49 #include "nsUnicodeProperties.h"
michael@0 50 #include "harfbuzz/hb.h"
michael@0 51 #include "gfxGraphiteShaper.h"
michael@0 52 #include "gfx2DGlue.h"
michael@0 53 #include "gfxGradientCache.h"
michael@0 54
michael@0 55 #include "nsUnicodeRange.h"
michael@0 56 #include "nsServiceManagerUtils.h"
michael@0 57 #include "nsTArray.h"
michael@0 58 #include "nsILocaleService.h"
michael@0 59 #include "nsIObserverService.h"
michael@0 60 #include "MainThreadUtils.h"
michael@0 61
michael@0 62 #include "nsWeakReference.h"
michael@0 63
michael@0 64 #include "cairo.h"
michael@0 65 #include "qcms.h"
michael@0 66
michael@0 67 #include "plstr.h"
michael@0 68 #include "nsCRT.h"
michael@0 69 #include "GLContext.h"
michael@0 70 #include "GLContextProvider.h"
michael@0 71
michael@0 72 #ifdef MOZ_WIDGET_ANDROID
michael@0 73 #include "TexturePoolOGL.h"
michael@0 74 #endif
michael@0 75
michael@0 76 #include "mozilla/Hal.h"
michael@0 77 #ifdef USE_SKIA
michael@0 78 #include "skia/SkGraphics.h"
michael@0 79
michael@0 80 #include "SkiaGLGlue.h"
michael@0 81 #else
michael@0 82 class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted {
michael@0 83 };
michael@0 84 #endif
michael@0 85
michael@0 86 #include "mozilla/Preferences.h"
michael@0 87 #include "mozilla/Assertions.h"
michael@0 88 #include "mozilla/Attributes.h"
michael@0 89 #include "mozilla/Mutex.h"
michael@0 90
michael@0 91 #include "nsIGfxInfo.h"
michael@0 92 #include "nsIXULRuntime.h"
michael@0 93
michael@0 94 #ifdef MOZ_WIDGET_GONK
michael@0 95 namespace mozilla {
michael@0 96 namespace layers {
michael@0 97 void InitGralloc();
michael@0 98 }
michael@0 99 }
michael@0 100 #endif
michael@0 101
michael@0 102 using namespace mozilla;
michael@0 103 using namespace mozilla::layers;
michael@0 104
michael@0 105 gfxPlatform *gPlatform = nullptr;
michael@0 106 static bool gEverInitialized = false;
michael@0 107
michael@0 108 static Mutex* gGfxPlatformPrefsLock = nullptr;
michael@0 109
michael@0 110 // These two may point to the same profile
michael@0 111 static qcms_profile *gCMSOutputProfile = nullptr;
michael@0 112 static qcms_profile *gCMSsRGBProfile = nullptr;
michael@0 113
michael@0 114 static qcms_transform *gCMSRGBTransform = nullptr;
michael@0 115 static qcms_transform *gCMSInverseRGBTransform = nullptr;
michael@0 116 static qcms_transform *gCMSRGBATransform = nullptr;
michael@0 117
michael@0 118 static bool gCMSInitialized = false;
michael@0 119 static eCMSMode gCMSMode = eCMSMode_Off;
michael@0 120
michael@0 121 static bool gCMSIntentInitialized = false;
michael@0 122 static int gCMSIntent = QCMS_INTENT_DEFAULT;
michael@0 123
michael@0 124
michael@0 125 static void ShutdownCMS();
michael@0 126
michael@0 127 #include "mozilla/gfx/2D.h"
michael@0 128 using namespace mozilla::gfx;
michael@0 129
michael@0 130 /* Class to listen for pref changes so that chrome code can dynamically
michael@0 131 force sRGB as an output profile. See Bug #452125. */
michael@0 132 class SRGBOverrideObserver MOZ_FINAL : public nsIObserver,
michael@0 133 public nsSupportsWeakReference
michael@0 134 {
michael@0 135 public:
michael@0 136 NS_DECL_ISUPPORTS
michael@0 137 NS_DECL_NSIOBSERVER
michael@0 138 };
michael@0 139
michael@0 140 NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
michael@0 141
michael@0 142 #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
michael@0 143
michael@0 144 #define GFX_PREF_HARFBUZZ_SCRIPTS "gfx.font_rendering.harfbuzz.scripts"
michael@0 145 #define HARFBUZZ_SCRIPTS_DEFAULT mozilla::unicode::SHAPING_DEFAULT
michael@0 146 #define GFX_PREF_FALLBACK_USE_CMAPS "gfx.font_rendering.fallback.always_use_cmaps"
michael@0 147
michael@0 148 #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
michael@0 149
michael@0 150 #define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit"
michael@0 151 #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries"
michael@0 152
michael@0 153 #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
michael@0 154
michael@0 155 #define BIDI_NUMERAL_PREF "bidi.numeral"
michael@0 156
michael@0 157 #define GFX_PREF_CMS_FORCE_SRGB "gfx.color_management.force_srgb"
michael@0 158
michael@0 159 NS_IMETHODIMP
michael@0 160 SRGBOverrideObserver::Observe(nsISupports *aSubject,
michael@0 161 const char *aTopic,
michael@0 162 const char16_t* someData)
michael@0 163 {
michael@0 164 NS_ASSERTION(NS_strcmp(someData,
michael@0 165 MOZ_UTF16(GFX_PREF_CMS_FORCE_SRGB)) == 0,
michael@0 166 "Restarting CMS on wrong pref!");
michael@0 167 ShutdownCMS();
michael@0 168 return NS_OK;
michael@0 169 }
michael@0 170
michael@0 171 static const char* kObservedPrefs[] = {
michael@0 172 "gfx.downloadable_fonts.",
michael@0 173 "gfx.font_rendering.",
michael@0 174 BIDI_NUMERAL_PREF,
michael@0 175 nullptr
michael@0 176 };
michael@0 177
michael@0 178 class FontPrefsObserver MOZ_FINAL : public nsIObserver
michael@0 179 {
michael@0 180 public:
michael@0 181 NS_DECL_ISUPPORTS
michael@0 182 NS_DECL_NSIOBSERVER
michael@0 183 };
michael@0 184
michael@0 185 NS_IMPL_ISUPPORTS(FontPrefsObserver, nsIObserver)
michael@0 186
michael@0 187 NS_IMETHODIMP
michael@0 188 FontPrefsObserver::Observe(nsISupports *aSubject,
michael@0 189 const char *aTopic,
michael@0 190 const char16_t *someData)
michael@0 191 {
michael@0 192 if (!someData) {
michael@0 193 NS_ERROR("font pref observer code broken");
michael@0 194 return NS_ERROR_UNEXPECTED;
michael@0 195 }
michael@0 196 NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone");
michael@0 197 gfxPlatform::GetPlatform()->FontsPrefsChanged(NS_ConvertUTF16toUTF8(someData).get());
michael@0 198
michael@0 199 return NS_OK;
michael@0 200 }
michael@0 201
michael@0 202 class MemoryPressureObserver MOZ_FINAL : public nsIObserver
michael@0 203 {
michael@0 204 public:
michael@0 205 NS_DECL_ISUPPORTS
michael@0 206 NS_DECL_NSIOBSERVER
michael@0 207 };
michael@0 208
michael@0 209 NS_IMPL_ISUPPORTS(MemoryPressureObserver, nsIObserver)
michael@0 210
michael@0 211 NS_IMETHODIMP
michael@0 212 MemoryPressureObserver::Observe(nsISupports *aSubject,
michael@0 213 const char *aTopic,
michael@0 214 const char16_t *someData)
michael@0 215 {
michael@0 216 NS_ASSERTION(strcmp(aTopic, "memory-pressure") == 0, "unexpected event topic");
michael@0 217 Factory::PurgeAllCaches();
michael@0 218
michael@0 219 gfxPlatform::GetPlatform()->PurgeSkiaCache();
michael@0 220 return NS_OK;
michael@0 221 }
michael@0 222
michael@0 223 // this needs to match the list of pref font.default.xx entries listed in all.js!
michael@0 224 // the order *must* match the order in eFontPrefLang
michael@0 225 static const char *gPrefLangNames[] = {
michael@0 226 "x-western",
michael@0 227 "x-central-euro",
michael@0 228 "ja",
michael@0 229 "zh-TW",
michael@0 230 "zh-CN",
michael@0 231 "zh-HK",
michael@0 232 "ko",
michael@0 233 "x-cyrillic",
michael@0 234 "x-baltic",
michael@0 235 "el",
michael@0 236 "tr",
michael@0 237 "th",
michael@0 238 "he",
michael@0 239 "ar",
michael@0 240 "x-devanagari",
michael@0 241 "x-tamil",
michael@0 242 "x-armn",
michael@0 243 "x-beng",
michael@0 244 "x-cans",
michael@0 245 "x-ethi",
michael@0 246 "x-geor",
michael@0 247 "x-gujr",
michael@0 248 "x-guru",
michael@0 249 "x-khmr",
michael@0 250 "x-mlym",
michael@0 251 "x-orya",
michael@0 252 "x-telu",
michael@0 253 "x-knda",
michael@0 254 "x-sinh",
michael@0 255 "x-tibt",
michael@0 256 "x-unicode",
michael@0 257 };
michael@0 258
michael@0 259 gfxPlatform::gfxPlatform()
michael@0 260 : mAzureCanvasBackendCollector(MOZ_THIS_IN_INITIALIZER_LIST(),
michael@0 261 &gfxPlatform::GetAzureBackendInfo)
michael@0 262 {
michael@0 263 mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
michael@0 264 mAllowDownloadableFonts = UNINITIALIZED_VALUE;
michael@0 265 mFallbackUsesCmaps = UNINITIALIZED_VALUE;
michael@0 266
michael@0 267 mWordCacheCharLimit = UNINITIALIZED_VALUE;
michael@0 268 mWordCacheMaxEntries = UNINITIALIZED_VALUE;
michael@0 269 mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
michael@0 270 mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
michael@0 271 mBidiNumeralOption = UNINITIALIZED_VALUE;
michael@0 272
michael@0 273 mLayersPreferMemoryOverShmem = XRE_GetProcessType() == GeckoProcessType_Default;
michael@0 274
michael@0 275 mSkiaGlue = nullptr;
michael@0 276
michael@0 277 uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
michael@0 278 uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
michael@0 279 InitBackendPrefs(canvasMask, BackendType::CAIRO,
michael@0 280 contentMask, BackendType::CAIRO);
michael@0 281 }
michael@0 282
michael@0 283 gfxPlatform*
michael@0 284 gfxPlatform::GetPlatform()
michael@0 285 {
michael@0 286 if (!gPlatform) {
michael@0 287 Init();
michael@0 288 }
michael@0 289 return gPlatform;
michael@0 290 }
michael@0 291
michael@0 292 void RecordingPrefChanged(const char *aPrefName, void *aClosure)
michael@0 293 {
michael@0 294 if (Preferences::GetBool("gfx.2d.recording", false)) {
michael@0 295 nsAutoCString fileName;
michael@0 296 nsAdoptingString prefFileName = Preferences::GetString("gfx.2d.recordingfile");
michael@0 297
michael@0 298 if (prefFileName) {
michael@0 299 fileName.Append(NS_ConvertUTF16toUTF8(prefFileName));
michael@0 300 } else {
michael@0 301 nsCOMPtr<nsIFile> tmpFile;
michael@0 302 if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile)))) {
michael@0 303 return;
michael@0 304 }
michael@0 305 fileName.AppendPrintf("moz2drec_%i_%i.aer", XRE_GetProcessType(), getpid());
michael@0 306
michael@0 307 nsresult rv = tmpFile->AppendNative(fileName);
michael@0 308 if (NS_FAILED(rv))
michael@0 309 return;
michael@0 310
michael@0 311 rv = tmpFile->GetNativePath(fileName);
michael@0 312 if (NS_FAILED(rv))
michael@0 313 return;
michael@0 314 }
michael@0 315
michael@0 316 gPlatform->mRecorder = Factory::CreateEventRecorderForFile(fileName.BeginReading());
michael@0 317 printf_stderr("Recording to %s\n", fileName.get());
michael@0 318 Factory::SetGlobalEventRecorder(gPlatform->mRecorder);
michael@0 319 } else {
michael@0 320 Factory::SetGlobalEventRecorder(nullptr);
michael@0 321 }
michael@0 322 }
michael@0 323
michael@0 324 void
michael@0 325 gfxPlatform::Init()
michael@0 326 {
michael@0 327 if (gEverInitialized) {
michael@0 328 NS_RUNTIMEABORT("Already started???");
michael@0 329 }
michael@0 330 gEverInitialized = true;
michael@0 331
michael@0 332 // Initialize the preferences by creating the singleton.
michael@0 333 gfxPrefs::GetSingleton();
michael@0 334
michael@0 335 gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock");
michael@0 336
michael@0 337 /* Initialize the GfxInfo service.
michael@0 338 * Note: we can't call functions on GfxInfo that depend
michael@0 339 * on gPlatform until after it has been initialized
michael@0 340 * below. GfxInfo initialization annotates our
michael@0 341 * crash reports so we want to do it before
michael@0 342 * we try to load any drivers and do device detection
michael@0 343 * incase that code crashes. See bug #591561. */
michael@0 344 nsCOMPtr<nsIGfxInfo> gfxInfo;
michael@0 345 /* this currently will only succeed on Windows */
michael@0 346 gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
michael@0 347
michael@0 348 #if defined(XP_WIN)
michael@0 349 gPlatform = new gfxWindowsPlatform;
michael@0 350 #elif defined(XP_MACOSX)
michael@0 351 gPlatform = new gfxPlatformMac;
michael@0 352 #elif defined(MOZ_WIDGET_GTK)
michael@0 353 gPlatform = new gfxPlatformGtk;
michael@0 354 #elif defined(MOZ_WIDGET_QT)
michael@0 355 gPlatform = new gfxQtPlatform;
michael@0 356 #elif defined(ANDROID)
michael@0 357 gPlatform = new gfxAndroidPlatform;
michael@0 358 #else
michael@0 359 #error "No gfxPlatform implementation available"
michael@0 360 #endif
michael@0 361
michael@0 362 #ifdef DEBUG
michael@0 363 mozilla::gl::GLContext::StaticInit();
michael@0 364 #endif
michael@0 365
michael@0 366 bool useOffMainThreadCompositing = OffMainThreadCompositionRequired() ||
michael@0 367 GetPrefLayersOffMainThreadCompositionEnabled();
michael@0 368
michael@0 369 if (!OffMainThreadCompositionRequired()) {
michael@0 370 useOffMainThreadCompositing &= GetPlatform()->SupportsOffMainThreadCompositing();
michael@0 371 }
michael@0 372
michael@0 373 if (useOffMainThreadCompositing && (XRE_GetProcessType() == GeckoProcessType_Default)) {
michael@0 374 CompositorParent::StartUp();
michael@0 375 if (gfxPrefs::AsyncVideoEnabled()) {
michael@0 376 ImageBridgeChild::StartUp();
michael@0 377 }
michael@0 378 }
michael@0 379
michael@0 380 nsresult rv;
michael@0 381
michael@0 382 #if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID) // temporary, until this is implemented on others
michael@0 383 rv = gfxPlatformFontList::Init();
michael@0 384 if (NS_FAILED(rv)) {
michael@0 385 NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList");
michael@0 386 }
michael@0 387 #endif
michael@0 388
michael@0 389 gPlatform->mScreenReferenceSurface =
michael@0 390 gPlatform->CreateOffscreenSurface(IntSize(1, 1),
michael@0 391 gfxContentType::COLOR_ALPHA);
michael@0 392 if (!gPlatform->mScreenReferenceSurface) {
michael@0 393 NS_RUNTIMEABORT("Could not initialize mScreenReferenceSurface");
michael@0 394 }
michael@0 395
michael@0 396 gPlatform->mScreenReferenceDrawTarget =
michael@0 397 gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1),
michael@0 398 SurfaceFormat::B8G8R8A8);
michael@0 399 if (!gPlatform->mScreenReferenceDrawTarget) {
michael@0 400 NS_RUNTIMEABORT("Could not initialize mScreenReferenceDrawTarget");
michael@0 401 }
michael@0 402
michael@0 403 rv = gfxFontCache::Init();
michael@0 404 if (NS_FAILED(rv)) {
michael@0 405 NS_RUNTIMEABORT("Could not initialize gfxFontCache");
michael@0 406 }
michael@0 407
michael@0 408 /* Create and register our CMS Override observer. */
michael@0 409 gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
michael@0 410 Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
michael@0 411
michael@0 412 gPlatform->mFontPrefsObserver = new FontPrefsObserver();
michael@0 413 Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
michael@0 414
michael@0 415 mozilla::gl::GLContext::PlatformStartup();
michael@0 416
michael@0 417 #ifdef MOZ_WIDGET_ANDROID
michael@0 418 // Texture pool init
michael@0 419 mozilla::gl::TexturePoolOGL::Init();
michael@0 420 #endif
michael@0 421
michael@0 422 #ifdef MOZ_WIDGET_GONK
michael@0 423 mozilla::layers::InitGralloc();
michael@0 424 #endif
michael@0 425
michael@0 426 Preferences::RegisterCallbackAndCall(RecordingPrefChanged, "gfx.2d.recording", nullptr);
michael@0 427
michael@0 428 CreateCMSOutputProfile();
michael@0 429
michael@0 430 // Listen to memory pressure event so we can purge DrawTarget caches
michael@0 431 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
michael@0 432 if (obs) {
michael@0 433 gPlatform->mMemoryPressureObserver = new MemoryPressureObserver();
michael@0 434 obs->AddObserver(gPlatform->mMemoryPressureObserver, "memory-pressure", false);
michael@0 435 }
michael@0 436
michael@0 437 RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
michael@0 438 }
michael@0 439
michael@0 440 void
michael@0 441 gfxPlatform::Shutdown()
michael@0 442 {
michael@0 443 // These may be called before the corresponding subsystems have actually
michael@0 444 // started up. That's OK, they can handle it.
michael@0 445 gfxFontCache::Shutdown();
michael@0 446 gfxFontGroup::Shutdown();
michael@0 447 gfxGradientCache::Shutdown();
michael@0 448 gfxGraphiteShaper::Shutdown();
michael@0 449 #if defined(XP_MACOSX) || defined(XP_WIN) // temporary, until this is implemented on others
michael@0 450 gfxPlatformFontList::Shutdown();
michael@0 451 #endif
michael@0 452
michael@0 453 // Free the various non-null transforms and loaded profiles
michael@0 454 ShutdownCMS();
michael@0 455
michael@0 456 // In some cases, gPlatform may not be created but Shutdown() called,
michael@0 457 // e.g., during xpcshell tests.
michael@0 458 if (gPlatform) {
michael@0 459 /* Unregister our CMS Override callback. */
michael@0 460 NS_ASSERTION(gPlatform->mSRGBOverrideObserver, "mSRGBOverrideObserver has alreay gone");
michael@0 461 Preferences::RemoveObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
michael@0 462 gPlatform->mSRGBOverrideObserver = nullptr;
michael@0 463
michael@0 464 NS_ASSERTION(gPlatform->mFontPrefsObserver, "mFontPrefsObserver has alreay gone");
michael@0 465 Preferences::RemoveObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
michael@0 466 gPlatform->mFontPrefsObserver = nullptr;
michael@0 467
michael@0 468 NS_ASSERTION(gPlatform->mMemoryPressureObserver, "mMemoryPressureObserver has already gone");
michael@0 469 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
michael@0 470 if (obs) {
michael@0 471 obs->RemoveObserver(gPlatform->mMemoryPressureObserver, "memory-pressure");
michael@0 472 }
michael@0 473
michael@0 474 gPlatform->mMemoryPressureObserver = nullptr;
michael@0 475 gPlatform->mSkiaGlue = nullptr;
michael@0 476 }
michael@0 477
michael@0 478 #ifdef MOZ_WIDGET_ANDROID
michael@0 479 // Shut down the texture pool
michael@0 480 mozilla::gl::TexturePoolOGL::Shutdown();
michael@0 481 #endif
michael@0 482
michael@0 483 // Shut down the default GL context provider.
michael@0 484 mozilla::gl::GLContextProvider::Shutdown();
michael@0 485
michael@0 486 #if defined(XP_WIN)
michael@0 487 // The above shutdown calls operate on the available context providers on
michael@0 488 // most platforms. Windows is a "special snowflake", though, and has three
michael@0 489 // context providers available, so we have to shut all of them down.
michael@0 490 // We should only support the default GL provider on Windows; then, this
michael@0 491 // could go away. Unfortunately, we currently support WGL (the default) for
michael@0 492 // WebGL on Optimus.
michael@0 493 mozilla::gl::GLContextProviderEGL::Shutdown();
michael@0 494 #endif
michael@0 495
michael@0 496 delete gGfxPlatformPrefsLock;
michael@0 497
michael@0 498 gfxPrefs::DestroySingleton();
michael@0 499 gfxFont::DestroySingletons();
michael@0 500
michael@0 501 delete gPlatform;
michael@0 502 gPlatform = nullptr;
michael@0 503 }
michael@0 504
michael@0 505 gfxPlatform::~gfxPlatform()
michael@0 506 {
michael@0 507 mScreenReferenceSurface = nullptr;
michael@0 508 mScreenReferenceDrawTarget = nullptr;
michael@0 509
michael@0 510 // The cairo folks think we should only clean up in debug builds,
michael@0 511 // but we're generally in the habit of trying to shut down as
michael@0 512 // cleanly as possible even in production code, so call this
michael@0 513 // cairo_debug_* function unconditionally.
michael@0 514 //
michael@0 515 // because cairo can assert and thus crash on shutdown, don't do this in release builds
michael@0 516 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) || defined(NS_TRACE_MALLOC) || defined(MOZ_VALGRIND)
michael@0 517 #ifdef USE_SKIA
michael@0 518 // must do Skia cleanup before Cairo cleanup, because Skia may be referencing
michael@0 519 // Cairo objects e.g. through SkCairoFTTypeface
michael@0 520 SkGraphics::Term();
michael@0 521 #endif
michael@0 522
michael@0 523 #if MOZ_TREE_CAIRO
michael@0 524 cairo_debug_reset_static_data();
michael@0 525 #endif
michael@0 526 #endif
michael@0 527 }
michael@0 528
michael@0 529 bool
michael@0 530 gfxPlatform::PreferMemoryOverShmem() const {
michael@0 531 MOZ_ASSERT(!CompositorParent::IsInCompositorThread());
michael@0 532 return mLayersPreferMemoryOverShmem;
michael@0 533 }
michael@0 534
michael@0 535 already_AddRefed<gfxASurface>
michael@0 536 gfxPlatform::CreateOffscreenImageSurface(const gfxIntSize& aSize,
michael@0 537 gfxContentType aContentType)
michael@0 538 {
michael@0 539 nsRefPtr<gfxASurface> newSurface;
michael@0 540 newSurface = new gfxImageSurface(aSize, OptimalFormatForContent(aContentType));
michael@0 541
michael@0 542 return newSurface.forget();
michael@0 543 }
michael@0 544
michael@0 545 already_AddRefed<gfxASurface>
michael@0 546 gfxPlatform::OptimizeImage(gfxImageSurface *aSurface,
michael@0 547 gfxImageFormat format)
michael@0 548 {
michael@0 549 IntSize surfaceSize = aSurface->GetSize().ToIntSize();
michael@0 550
michael@0 551 #ifdef XP_WIN
michael@0 552 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
michael@0 553 gfxWindowsPlatform::RENDER_DIRECT2D) {
michael@0 554 return nullptr;
michael@0 555 }
michael@0 556 #endif
michael@0 557 nsRefPtr<gfxASurface> optSurface = CreateOffscreenSurface(surfaceSize, gfxASurface::ContentFromFormat(format));
michael@0 558 if (!optSurface || optSurface->CairoStatus() != 0)
michael@0 559 return nullptr;
michael@0 560
michael@0 561 gfxContext tmpCtx(optSurface);
michael@0 562 tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
michael@0 563 tmpCtx.SetSource(aSurface);
michael@0 564 tmpCtx.Paint();
michael@0 565
michael@0 566 return optSurface.forget();
michael@0 567 }
michael@0 568
michael@0 569 cairo_user_data_key_t kDrawTarget;
michael@0 570
michael@0 571 RefPtr<DrawTarget>
michael@0 572 gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface, const IntSize& aSize)
michael@0 573 {
michael@0 574 SurfaceFormat format = Optimal2DFormatForContent(aSurface->GetContentType());
michael@0 575 RefPtr<DrawTarget> drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(), aSize, &format);
michael@0 576 aSurface->SetData(&kDrawTarget, drawTarget, nullptr);
michael@0 577 return drawTarget;
michael@0 578 }
michael@0 579
michael@0 580 // This is a temporary function used by ContentClient to build a DrawTarget
michael@0 581 // around the gfxASurface. This should eventually be replaced by plumbing
michael@0 582 // the DrawTarget through directly
michael@0 583 RefPtr<DrawTarget>
michael@0 584 gfxPlatform::CreateDrawTargetForUpdateSurface(gfxASurface *aSurface, const IntSize& aSize)
michael@0 585 {
michael@0 586 #ifdef XP_MACOSX
michael@0 587 // this is a bit of a hack that assumes that the buffer associated with the CGContext
michael@0 588 // will live around long enough that nothing bad will happen.
michael@0 589 if (aSurface->GetType() == gfxSurfaceType::Quartz) {
michael@0 590 return Factory::CreateDrawTargetForCairoCGContext(static_cast<gfxQuartzSurface*>(aSurface)->GetCGContext(), aSize);
michael@0 591 }
michael@0 592 #endif
michael@0 593 MOZ_CRASH();
michael@0 594 return nullptr;
michael@0 595 }
michael@0 596
michael@0 597
michael@0 598 cairo_user_data_key_t kSourceSurface;
michael@0 599
michael@0 600 /**
michael@0 601 * Record the backend that was used to construct the SourceSurface.
michael@0 602 * When getting the cached SourceSurface for a gfxASurface/DrawTarget pair,
michael@0 603 * we check to make sure the DrawTarget's backend matches the backend
michael@0 604 * for the cached SourceSurface, and only use it if they match. This
michael@0 605 * can avoid expensive and unnecessary readbacks.
michael@0 606 */
michael@0 607 struct SourceSurfaceUserData
michael@0 608 {
michael@0 609 RefPtr<SourceSurface> mSrcSurface;
michael@0 610 BackendType mBackendType;
michael@0 611 };
michael@0 612
michael@0 613 void SourceBufferDestroy(void *srcSurfUD)
michael@0 614 {
michael@0 615 delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
michael@0 616 }
michael@0 617
michael@0 618 UserDataKey kThebesSurface;
michael@0 619
michael@0 620 struct DependentSourceSurfaceUserData
michael@0 621 {
michael@0 622 nsRefPtr<gfxASurface> mSurface;
michael@0 623 };
michael@0 624
michael@0 625 void SourceSurfaceDestroyed(void *aData)
michael@0 626 {
michael@0 627 delete static_cast<DependentSourceSurfaceUserData*>(aData);
michael@0 628 }
michael@0 629
michael@0 630 #if MOZ_TREE_CAIRO
michael@0 631 void SourceSnapshotDetached(cairo_surface_t *nullSurf)
michael@0 632 {
michael@0 633 gfxImageSurface* origSurf =
michael@0 634 static_cast<gfxImageSurface*>(cairo_surface_get_user_data(nullSurf, &kSourceSurface));
michael@0 635
michael@0 636 origSurf->SetData(&kSourceSurface, nullptr, nullptr);
michael@0 637 }
michael@0 638 #else
michael@0 639 void SourceSnapshotDetached(void *nullSurf)
michael@0 640 {
michael@0 641 gfxImageSurface* origSurf = static_cast<gfxImageSurface*>(nullSurf);
michael@0 642 origSurf->SetData(&kSourceSurface, nullptr, nullptr);
michael@0 643 }
michael@0 644 #endif
michael@0 645
michael@0 646 void
michael@0 647 gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
michael@0 648 {
michael@0 649 aSurface->SetData(&kSourceSurface, nullptr, nullptr);
michael@0 650 }
michael@0 651
michael@0 652 static TemporaryRef<DataSourceSurface>
michael@0 653 CopySurface(gfxASurface* aSurface)
michael@0 654 {
michael@0 655 const nsIntSize size = aSurface->GetSize();
michael@0 656 gfxImageFormat format = gfxPlatform::GetPlatform()->OptimalFormatForContent(aSurface->GetContentType());
michael@0 657 RefPtr<DataSourceSurface> data =
michael@0 658 Factory::CreateDataSourceSurface(ToIntSize(size),
michael@0 659 ImageFormatToSurfaceFormat(format));
michael@0 660 if (!data) {
michael@0 661 return nullptr;
michael@0 662 }
michael@0 663
michael@0 664 DataSourceSurface::MappedSurface map;
michael@0 665 DebugOnly<bool> result = data->Map(DataSourceSurface::WRITE, &map);
michael@0 666 MOZ_ASSERT(result, "Should always succeed mapping raw data surfaces!");
michael@0 667
michael@0 668 nsRefPtr<gfxImageSurface> image = new gfxImageSurface(map.mData, size, map.mStride, format);
michael@0 669 nsRefPtr<gfxContext> ctx = new gfxContext(image);
michael@0 670
michael@0 671 ctx->SetSource(aSurface);
michael@0 672 ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
michael@0 673 ctx->Paint();
michael@0 674
michael@0 675 data->Unmap();
michael@0 676
michael@0 677 return data;
michael@0 678 }
michael@0 679
michael@0 680 RefPtr<SourceSurface>
michael@0 681 gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface)
michael@0 682 {
michael@0 683 if (!aSurface->CairoSurface() || aSurface->CairoStatus()) {
michael@0 684 return nullptr;
michael@0 685 }
michael@0 686
michael@0 687 if (!aTarget) {
michael@0 688 if (ScreenReferenceDrawTarget()) {
michael@0 689 aTarget = ScreenReferenceDrawTarget();
michael@0 690 } else {
michael@0 691 return nullptr;
michael@0 692 }
michael@0 693 }
michael@0 694
michael@0 695 void *userData = aSurface->GetData(&kSourceSurface);
michael@0 696
michael@0 697 if (userData) {
michael@0 698 SourceSurfaceUserData *surf = static_cast<SourceSurfaceUserData*>(userData);
michael@0 699
michael@0 700 if (surf->mSrcSurface->IsValid() && surf->mBackendType == aTarget->GetType()) {
michael@0 701 return surf->mSrcSurface;
michael@0 702 }
michael@0 703 // We can just continue here as when setting new user data the destroy
michael@0 704 // function will be called for the old user data.
michael@0 705 }
michael@0 706
michael@0 707 SurfaceFormat format;
michael@0 708 if (aSurface->GetContentType() == gfxContentType::ALPHA) {
michael@0 709 format = SurfaceFormat::A8;
michael@0 710 } else if (aSurface->GetContentType() == gfxContentType::COLOR) {
michael@0 711 format = SurfaceFormat::B8G8R8X8;
michael@0 712 } else {
michael@0 713 format = SurfaceFormat::B8G8R8A8;
michael@0 714 }
michael@0 715
michael@0 716 RefPtr<SourceSurface> srcBuffer;
michael@0 717
michael@0 718 #ifdef XP_WIN
michael@0 719 if (aSurface->GetType() == gfxSurfaceType::D2D &&
michael@0 720 format != SurfaceFormat::A8) {
michael@0 721 NativeSurface surf;
michael@0 722 surf.mFormat = format;
michael@0 723 surf.mType = NativeSurfaceType::D3D10_TEXTURE;
michael@0 724 surf.mSurface = static_cast<gfxD2DSurface*>(aSurface)->GetTexture();
michael@0 725 surf.mSize = ToIntSize(aSurface->GetSize());
michael@0 726 mozilla::gfx::DrawTarget *dt = static_cast<mozilla::gfx::DrawTarget*>(aSurface->GetData(&kDrawTarget));
michael@0 727 if (dt) {
michael@0 728 dt->Flush();
michael@0 729 }
michael@0 730 srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
michael@0 731 } else
michael@0 732 #endif
michael@0 733 if (aSurface->CairoSurface() && aTarget->GetType() == BackendType::CAIRO) {
michael@0 734 // If this is an xlib cairo surface we don't want to fetch it into memory
michael@0 735 // because this is a major slow down.
michael@0 736 NativeSurface surf;
michael@0 737 surf.mFormat = format;
michael@0 738 surf.mType = NativeSurfaceType::CAIRO_SURFACE;
michael@0 739 surf.mSurface = aSurface->CairoSurface();
michael@0 740 surf.mSize = ToIntSize(aSurface->GetSize());
michael@0 741 srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
michael@0 742
michael@0 743 if (srcBuffer) {
michael@0 744 // It's cheap enough to make a new one so we won't keep it around and
michael@0 745 // keeping it creates a cycle.
michael@0 746 return srcBuffer;
michael@0 747 }
michael@0 748 }
michael@0 749
michael@0 750 if (!srcBuffer) {
michael@0 751 nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();
michael@0 752
michael@0 753 RefPtr<DataSourceSurface> dataSurf;
michael@0 754
michael@0 755 if (imgSurface) {
michael@0 756 dataSurf = GetWrappedDataSourceSurface(aSurface);
michael@0 757 } else {
michael@0 758 dataSurf = CopySurface(aSurface);
michael@0 759 }
michael@0 760
michael@0 761 if (!dataSurf) {
michael@0 762 return nullptr;
michael@0 763 }
michael@0 764
michael@0 765 srcBuffer = aTarget->OptimizeSourceSurface(dataSurf);
michael@0 766
michael@0 767 if (imgSurface && srcBuffer == dataSurf) {
michael@0 768 // Our wrapping surface will hold a reference to its image surface. We cause
michael@0 769 // a reference cycle if we add it to the cache. And caching it is pretty
michael@0 770 // pointless since we'll just wrap it again next use.
michael@0 771 return srcBuffer;
michael@0 772 }
michael@0 773 }
michael@0 774
michael@0 775 // Add user data to aSurface so we can cache lookups in the future.
michael@0 776 SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
michael@0 777 srcSurfUD->mBackendType = aTarget->GetType();
michael@0 778 srcSurfUD->mSrcSurface = srcBuffer;
michael@0 779 aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
michael@0 780
michael@0 781 return srcBuffer;
michael@0 782 }
michael@0 783
michael@0 784 RefPtr<DataSourceSurface>
michael@0 785 gfxPlatform::GetWrappedDataSourceSurface(gfxASurface* aSurface)
michael@0 786 {
michael@0 787 nsRefPtr<gfxImageSurface> image = aSurface->GetAsImageSurface();
michael@0 788 if (!image) {
michael@0 789 return nullptr;
michael@0 790 }
michael@0 791 RefPtr<DataSourceSurface> result =
michael@0 792 Factory::CreateWrappingDataSourceSurface(image->Data(),
michael@0 793 image->Stride(),
michael@0 794 ToIntSize(image->GetSize()),
michael@0 795 ImageFormatToSurfaceFormat(image->Format()));
michael@0 796
michael@0 797 if (!result) {
michael@0 798 return nullptr;
michael@0 799 }
michael@0 800
michael@0 801 // If we wrapped the underlying data of aSurface, then we need to add user data
michael@0 802 // to make sure aSurface stays alive until we are done with the data.
michael@0 803 DependentSourceSurfaceUserData *srcSurfUD = new DependentSourceSurfaceUserData;
michael@0 804 srcSurfUD->mSurface = aSurface;
michael@0 805 result->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
michael@0 806
michael@0 807 return result;
michael@0 808 }
michael@0 809
michael@0 810 TemporaryRef<ScaledFont>
michael@0 811 gfxPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
michael@0 812 {
michael@0 813 NativeFont nativeFont;
michael@0 814 nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
michael@0 815 nativeFont.mFont = aFont->GetCairoScaledFont();
michael@0 816 RefPtr<ScaledFont> scaledFont =
michael@0 817 Factory::CreateScaledFontForNativeFont(nativeFont,
michael@0 818 aFont->GetAdjustedSize());
michael@0 819 return scaledFont;
michael@0 820 }
michael@0 821
michael@0 822 cairo_user_data_key_t kDrawSourceSurface;
michael@0 823 static void
michael@0 824 DataSourceSurfaceDestroy(void *dataSourceSurface)
michael@0 825 {
michael@0 826 static_cast<DataSourceSurface*>(dataSourceSurface)->Release();
michael@0 827 }
michael@0 828
michael@0 829 cairo_user_data_key_t kDrawTargetForSurface;
michael@0 830 static void
michael@0 831 DataDrawTargetDestroy(void *aTarget)
michael@0 832 {
michael@0 833 static_cast<DrawTarget*>(aTarget)->Release();
michael@0 834 }
michael@0 835
michael@0 836 bool
michael@0 837 gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget)
michael@0 838 {
michael@0 839 if (!aTarget) {
michael@0 840 return false;
michael@0 841 }
michael@0 842
michael@0 843 return SupportsAzureContentForType(aTarget->GetType());
michael@0 844 }
michael@0 845
michael@0 846 bool
michael@0 847 gfxPlatform::UseAcceleratedSkiaCanvas()
michael@0 848 {
michael@0 849 return gfxPrefs::CanvasAzureAccelerated() &&
michael@0 850 mPreferredCanvasBackend == BackendType::SKIA;
michael@0 851 }
michael@0 852
michael@0 853 void
michael@0 854 gfxPlatform::InitializeSkiaCacheLimits()
michael@0 855 {
michael@0 856 if (UseAcceleratedSkiaCanvas()) {
michael@0 857 bool usingDynamicCache = gfxPrefs::CanvasSkiaGLDynamicCache();
michael@0 858 int cacheItemLimit = gfxPrefs::CanvasSkiaGLCacheItems();
michael@0 859 int cacheSizeLimit = gfxPrefs::CanvasSkiaGLCacheSize();
michael@0 860
michael@0 861 // Prefs are in megabytes, but we want the sizes in bytes
michael@0 862 cacheSizeLimit *= 1024*1024;
michael@0 863
michael@0 864 if (usingDynamicCache) {
michael@0 865 uint32_t totalMemory = mozilla::hal::GetTotalSystemMemory();
michael@0 866
michael@0 867 if (totalMemory <= 256*1024*1024) {
michael@0 868 // We need a very minimal cache on 256 meg devices
michael@0 869 cacheSizeLimit = 2*1024*1024;
michael@0 870 } else if (totalMemory > 0) {
michael@0 871 cacheSizeLimit = totalMemory / 16;
michael@0 872 }
michael@0 873 }
michael@0 874
michael@0 875 #ifdef DEBUG
michael@0 876 printf_stderr("Determined SkiaGL cache limits: Size %i, Items: %i\n", cacheSizeLimit, cacheItemLimit);
michael@0 877 #endif
michael@0 878
michael@0 879 #ifdef USE_SKIA_GPU
michael@0 880 mSkiaGlue->GetGrContext()->setTextureCacheLimits(cacheItemLimit, cacheSizeLimit);
michael@0 881 #endif
michael@0 882 }
michael@0 883 }
michael@0 884
michael@0 885 mozilla::gl::SkiaGLGlue*
michael@0 886 gfxPlatform::GetSkiaGLGlue()
michael@0 887 {
michael@0 888 #ifdef USE_SKIA_GPU
michael@0 889 if (!mSkiaGlue) {
michael@0 890 /* Dummy context. We always draw into a FBO.
michael@0 891 *
michael@0 892 * FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it
michael@0 893 * stands, this only works on the main thread.
michael@0 894 */
michael@0 895 mozilla::gfx::SurfaceCaps caps = mozilla::gfx::SurfaceCaps::ForRGBA();
michael@0 896 nsRefPtr<mozilla::gl::GLContext> glContext = mozilla::gl::GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), caps);
michael@0 897 if (!glContext) {
michael@0 898 printf_stderr("Failed to create GLContext for SkiaGL!\n");
michael@0 899 return nullptr;
michael@0 900 }
michael@0 901 mSkiaGlue = new mozilla::gl::SkiaGLGlue(glContext);
michael@0 902 MOZ_ASSERT(mSkiaGlue->GetGrContext(), "No GrContext");
michael@0 903 InitializeSkiaCacheLimits();
michael@0 904 }
michael@0 905 #endif
michael@0 906
michael@0 907 return mSkiaGlue;
michael@0 908 }
michael@0 909
michael@0 910 void
michael@0 911 gfxPlatform::PurgeSkiaCache()
michael@0 912 {
michael@0 913 #ifdef USE_SKIA_GPU
michael@0 914 if (!mSkiaGlue)
michael@0 915 return;
michael@0 916
michael@0 917 mSkiaGlue->GetGrContext()->freeGpuResources();
michael@0 918 #endif
michael@0 919 }
michael@0 920
michael@0 921 already_AddRefed<gfxASurface>
michael@0 922 gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
michael@0 923 {
michael@0 924 if (aTarget->GetType() == BackendType::CAIRO) {
michael@0 925 cairo_surface_t* csurf =
michael@0 926 static_cast<cairo_surface_t*>(aTarget->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE));
michael@0 927 if (csurf) {
michael@0 928 return gfxASurface::Wrap(csurf);
michael@0 929 }
michael@0 930 }
michael@0 931
michael@0 932 // The semantics of this part of the function are sort of weird. If we
michael@0 933 // don't have direct support for the backend, we snapshot the first time
michael@0 934 // and then return the snapshotted surface for the lifetime of the draw
michael@0 935 // target. Sometimes it seems like this works out, but it seems like it
michael@0 936 // might result in no updates ever.
michael@0 937 RefPtr<SourceSurface> source = aTarget->Snapshot();
michael@0 938 RefPtr<DataSourceSurface> data = source->GetDataSurface();
michael@0 939
michael@0 940 if (!data) {
michael@0 941 return nullptr;
michael@0 942 }
michael@0 943
michael@0 944 IntSize size = data->GetSize();
michael@0 945 gfxImageFormat format = SurfaceFormatToImageFormat(data->GetFormat());
michael@0 946
michael@0 947
michael@0 948 nsRefPtr<gfxASurface> surf =
michael@0 949 new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height),
michael@0 950 data->Stride(), format);
michael@0 951
michael@0 952 if (surf->CairoStatus()) {
michael@0 953 return nullptr;
michael@0 954 }
michael@0 955
michael@0 956 surf->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy);
michael@0 957 // keep the draw target alive as long as we need its data
michael@0 958 aTarget->AddRef();
michael@0 959 surf->SetData(&kDrawTargetForSurface, aTarget, DataDrawTargetDestroy);
michael@0 960
michael@0 961 return surf.forget();
michael@0 962 }
michael@0 963
michael@0 964 RefPtr<DrawTarget>
michael@0 965 gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat)
michael@0 966 {
michael@0 967 // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
michael@0 968 // create the best offscreen surface for the current system and situation. We
michael@0 969 // can easily take advantage of this for the Cairo backend, so that's what we
michael@0 970 // do.
michael@0 971 // mozilla::gfx::Factory can get away without having all this knowledge for
michael@0 972 // now, but this might need to change in the future (using
michael@0 973 // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all
michael@0 974 // backends).
michael@0 975 if (aBackend == BackendType::CAIRO) {
michael@0 976 nsRefPtr<gfxASurface> surf = CreateOffscreenSurface(aSize,
michael@0 977 ContentForFormat(aFormat));
michael@0 978 if (!surf || surf->CairoStatus()) {
michael@0 979 return nullptr;
michael@0 980 }
michael@0 981
michael@0 982 return CreateDrawTargetForSurface(surf, aSize);
michael@0 983 } else {
michael@0 984 return Factory::CreateDrawTarget(aBackend, aSize, aFormat);
michael@0 985 }
michael@0 986 }
michael@0 987
michael@0 988 RefPtr<DrawTarget>
michael@0 989 gfxPlatform::CreateOffscreenCanvasDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
michael@0 990 {
michael@0 991 NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
michael@0 992 RefPtr<DrawTarget> target = CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat);
michael@0 993 if (target ||
michael@0 994 mFallbackCanvasBackend == BackendType::NONE) {
michael@0 995 return target;
michael@0 996 }
michael@0 997
michael@0 998 return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat);
michael@0 999 }
michael@0 1000
michael@0 1001 RefPtr<DrawTarget>
michael@0 1002 gfxPlatform::CreateOffscreenContentDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
michael@0 1003 {
michael@0 1004 NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
michael@0 1005 return CreateDrawTargetForBackend(mContentBackend, aSize, aFormat);
michael@0 1006 }
michael@0 1007
michael@0 1008 RefPtr<DrawTarget>
michael@0 1009 gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat)
michael@0 1010 {
michael@0 1011 NS_ASSERTION(mContentBackend != BackendType::NONE, "No backend.");
michael@0 1012 if (mContentBackend == BackendType::CAIRO) {
michael@0 1013 nsRefPtr<gfxImageSurface> image = new gfxImageSurface(aData, gfxIntSize(aSize.width, aSize.height), aStride, SurfaceFormatToImageFormat(aFormat));
michael@0 1014 return Factory::CreateDrawTargetForCairoSurface(image->CairoSurface(), aSize);
michael@0 1015 }
michael@0 1016 return Factory::CreateDrawTargetForData(mContentBackend, aData, aSize, aStride, aFormat);
michael@0 1017 }
michael@0 1018
michael@0 1019 /* static */ BackendType
michael@0 1020 gfxPlatform::BackendTypeForName(const nsCString& aName)
michael@0 1021 {
michael@0 1022 if (aName.EqualsLiteral("cairo"))
michael@0 1023 return BackendType::CAIRO;
michael@0 1024 if (aName.EqualsLiteral("skia"))
michael@0 1025 return BackendType::SKIA;
michael@0 1026 if (aName.EqualsLiteral("direct2d"))
michael@0 1027 return BackendType::DIRECT2D;
michael@0 1028 if (aName.EqualsLiteral("cg"))
michael@0 1029 return BackendType::COREGRAPHICS;
michael@0 1030 return BackendType::NONE;
michael@0 1031 }
michael@0 1032
michael@0 1033 nsresult
michael@0 1034 gfxPlatform::GetFontList(nsIAtom *aLangGroup,
michael@0 1035 const nsACString& aGenericFamily,
michael@0 1036 nsTArray<nsString>& aListOfFonts)
michael@0 1037 {
michael@0 1038 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 1039 }
michael@0 1040
michael@0 1041 nsresult
michael@0 1042 gfxPlatform::UpdateFontList()
michael@0 1043 {
michael@0 1044 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 1045 }
michael@0 1046
michael@0 1047 bool
michael@0 1048 gfxPlatform::DownloadableFontsEnabled()
michael@0 1049 {
michael@0 1050 if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
michael@0 1051 mAllowDownloadableFonts =
michael@0 1052 Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false);
michael@0 1053 }
michael@0 1054
michael@0 1055 return mAllowDownloadableFonts;
michael@0 1056 }
michael@0 1057
michael@0 1058 bool
michael@0 1059 gfxPlatform::UseCmapsDuringSystemFallback()
michael@0 1060 {
michael@0 1061 if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) {
michael@0 1062 mFallbackUsesCmaps =
michael@0 1063 Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false);
michael@0 1064 }
michael@0 1065
michael@0 1066 return mFallbackUsesCmaps;
michael@0 1067 }
michael@0 1068
michael@0 1069 bool
michael@0 1070 gfxPlatform::OpenTypeSVGEnabled()
michael@0 1071 {
michael@0 1072 if (mOpenTypeSVGEnabled == UNINITIALIZED_VALUE) {
michael@0 1073 mOpenTypeSVGEnabled =
michael@0 1074 Preferences::GetBool(GFX_PREF_OPENTYPE_SVG, false);
michael@0 1075 }
michael@0 1076
michael@0 1077 return mOpenTypeSVGEnabled > 0;
michael@0 1078 }
michael@0 1079
michael@0 1080 uint32_t
michael@0 1081 gfxPlatform::WordCacheCharLimit()
michael@0 1082 {
michael@0 1083 if (mWordCacheCharLimit == UNINITIALIZED_VALUE) {
michael@0 1084 mWordCacheCharLimit =
michael@0 1085 Preferences::GetInt(GFX_PREF_WORD_CACHE_CHARLIMIT, 32);
michael@0 1086 if (mWordCacheCharLimit < 0) {
michael@0 1087 mWordCacheCharLimit = 32;
michael@0 1088 }
michael@0 1089 }
michael@0 1090
michael@0 1091 return uint32_t(mWordCacheCharLimit);
michael@0 1092 }
michael@0 1093
michael@0 1094 uint32_t
michael@0 1095 gfxPlatform::WordCacheMaxEntries()
michael@0 1096 {
michael@0 1097 if (mWordCacheMaxEntries == UNINITIALIZED_VALUE) {
michael@0 1098 mWordCacheMaxEntries =
michael@0 1099 Preferences::GetInt(GFX_PREF_WORD_CACHE_MAXENTRIES, 10000);
michael@0 1100 if (mWordCacheMaxEntries < 0) {
michael@0 1101 mWordCacheMaxEntries = 10000;
michael@0 1102 }
michael@0 1103 }
michael@0 1104
michael@0 1105 return uint32_t(mWordCacheMaxEntries);
michael@0 1106 }
michael@0 1107
michael@0 1108 bool
michael@0 1109 gfxPlatform::UseGraphiteShaping()
michael@0 1110 {
michael@0 1111 if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) {
michael@0 1112 mGraphiteShapingEnabled =
michael@0 1113 Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
michael@0 1114 }
michael@0 1115
michael@0 1116 return mGraphiteShapingEnabled;
michael@0 1117 }
michael@0 1118
michael@0 1119 bool
michael@0 1120 gfxPlatform::UseHarfBuzzForScript(int32_t aScriptCode)
michael@0 1121 {
michael@0 1122 if (mUseHarfBuzzScripts == UNINITIALIZED_VALUE) {
michael@0 1123 mUseHarfBuzzScripts = Preferences::GetInt(GFX_PREF_HARFBUZZ_SCRIPTS, HARFBUZZ_SCRIPTS_DEFAULT);
michael@0 1124 }
michael@0 1125
michael@0 1126 int32_t shapingType = mozilla::unicode::ScriptShapingType(aScriptCode);
michael@0 1127
michael@0 1128 return (mUseHarfBuzzScripts & shapingType) != 0;
michael@0 1129 }
michael@0 1130
michael@0 1131 gfxFontEntry*
michael@0 1132 gfxPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
michael@0 1133 const uint8_t *aFontData,
michael@0 1134 uint32_t aLength)
michael@0 1135 {
michael@0 1136 // Default implementation does not handle activating downloaded fonts;
michael@0 1137 // just free the data and return.
michael@0 1138 // Platforms that support @font-face must override this,
michael@0 1139 // using the data to instantiate the font, and taking responsibility
michael@0 1140 // for freeing it when no longer required.
michael@0 1141 if (aFontData) {
michael@0 1142 NS_Free((void*)aFontData);
michael@0 1143 }
michael@0 1144 return nullptr;
michael@0 1145 }
michael@0 1146
michael@0 1147 static void
michael@0 1148 AppendGenericFontFromPref(nsString& aFonts, nsIAtom *aLangGroup, const char *aGenericName)
michael@0 1149 {
michael@0 1150 NS_ENSURE_TRUE_VOID(Preferences::GetRootBranch());
michael@0 1151
michael@0 1152 nsAutoCString prefName, langGroupString;
michael@0 1153
michael@0 1154 aLangGroup->ToUTF8String(langGroupString);
michael@0 1155
michael@0 1156 nsAutoCString genericDotLang;
michael@0 1157 if (aGenericName) {
michael@0 1158 genericDotLang.Assign(aGenericName);
michael@0 1159 } else {
michael@0 1160 prefName.AssignLiteral("font.default.");
michael@0 1161 prefName.Append(langGroupString);
michael@0 1162 genericDotLang = Preferences::GetCString(prefName.get());
michael@0 1163 }
michael@0 1164
michael@0 1165 genericDotLang.AppendLiteral(".");
michael@0 1166 genericDotLang.Append(langGroupString);
michael@0 1167
michael@0 1168 // fetch font.name.xxx value
michael@0 1169 prefName.AssignLiteral("font.name.");
michael@0 1170 prefName.Append(genericDotLang);
michael@0 1171 nsAdoptingString nameValue = Preferences::GetString(prefName.get());
michael@0 1172 if (nameValue) {
michael@0 1173 if (!aFonts.IsEmpty())
michael@0 1174 aFonts.AppendLiteral(", ");
michael@0 1175 aFonts += nameValue;
michael@0 1176 }
michael@0 1177
michael@0 1178 // fetch font.name-list.xxx value
michael@0 1179 prefName.AssignLiteral("font.name-list.");
michael@0 1180 prefName.Append(genericDotLang);
michael@0 1181 nsAdoptingString nameListValue = Preferences::GetString(prefName.get());
michael@0 1182 if (nameListValue && !nameListValue.Equals(nameValue)) {
michael@0 1183 if (!aFonts.IsEmpty())
michael@0 1184 aFonts.AppendLiteral(", ");
michael@0 1185 aFonts += nameListValue;
michael@0 1186 }
michael@0 1187 }
michael@0 1188
michael@0 1189 void
michael@0 1190 gfxPlatform::GetPrefFonts(nsIAtom *aLanguage, nsString& aFonts, bool aAppendUnicode)
michael@0 1191 {
michael@0 1192 aFonts.Truncate();
michael@0 1193
michael@0 1194 AppendGenericFontFromPref(aFonts, aLanguage, nullptr);
michael@0 1195 if (aAppendUnicode)
michael@0 1196 AppendGenericFontFromPref(aFonts, nsGkAtoms::Unicode, nullptr);
michael@0 1197 }
michael@0 1198
michael@0 1199 bool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], uint32_t aLangArrayLen, PrefFontCallback aCallback,
michael@0 1200 void *aClosure)
michael@0 1201 {
michael@0 1202 NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
michael@0 1203
michael@0 1204 uint32_t i;
michael@0 1205 for (i = 0; i < aLangArrayLen; i++) {
michael@0 1206 eFontPrefLang prefLang = aLangArray[i];
michael@0 1207 const char *langGroup = GetPrefLangName(prefLang);
michael@0 1208
michael@0 1209 nsAutoCString prefName;
michael@0 1210
michael@0 1211 prefName.AssignLiteral("font.default.");
michael@0 1212 prefName.Append(langGroup);
michael@0 1213 nsAdoptingCString genericDotLang = Preferences::GetCString(prefName.get());
michael@0 1214
michael@0 1215 genericDotLang.AppendLiteral(".");
michael@0 1216 genericDotLang.Append(langGroup);
michael@0 1217
michael@0 1218 // fetch font.name.xxx value
michael@0 1219 prefName.AssignLiteral("font.name.");
michael@0 1220 prefName.Append(genericDotLang);
michael@0 1221 nsAdoptingCString nameValue = Preferences::GetCString(prefName.get());
michael@0 1222 if (nameValue) {
michael@0 1223 if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(nameValue), aClosure))
michael@0 1224 return false;
michael@0 1225 }
michael@0 1226
michael@0 1227 // fetch font.name-list.xxx value
michael@0 1228 prefName.AssignLiteral("font.name-list.");
michael@0 1229 prefName.Append(genericDotLang);
michael@0 1230 nsAdoptingCString nameListValue = Preferences::GetCString(prefName.get());
michael@0 1231 if (nameListValue && !nameListValue.Equals(nameValue)) {
michael@0 1232 const char kComma = ',';
michael@0 1233 const char *p, *p_end;
michael@0 1234 nsAutoCString list(nameListValue);
michael@0 1235 list.BeginReading(p);
michael@0 1236 list.EndReading(p_end);
michael@0 1237 while (p < p_end) {
michael@0 1238 while (nsCRT::IsAsciiSpace(*p)) {
michael@0 1239 if (++p == p_end)
michael@0 1240 break;
michael@0 1241 }
michael@0 1242 if (p == p_end)
michael@0 1243 break;
michael@0 1244 const char *start = p;
michael@0 1245 while (++p != p_end && *p != kComma)
michael@0 1246 /* nothing */ ;
michael@0 1247 nsAutoCString fontName(Substring(start, p));
michael@0 1248 fontName.CompressWhitespace(false, true);
michael@0 1249 if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(fontName), aClosure))
michael@0 1250 return false;
michael@0 1251 p++;
michael@0 1252 }
michael@0 1253 }
michael@0 1254 }
michael@0 1255
michael@0 1256 return true;
michael@0 1257 }
michael@0 1258
michael@0 1259 eFontPrefLang
michael@0 1260 gfxPlatform::GetFontPrefLangFor(const char* aLang)
michael@0 1261 {
michael@0 1262 if (!aLang || !aLang[0]) {
michael@0 1263 return eFontPrefLang_Others;
michael@0 1264 }
michael@0 1265 for (uint32_t i = 0; i < ArrayLength(gPrefLangNames); ++i) {
michael@0 1266 if (!PL_strcasecmp(gPrefLangNames[i], aLang)) {
michael@0 1267 return eFontPrefLang(i);
michael@0 1268 }
michael@0 1269 }
michael@0 1270 return eFontPrefLang_Others;
michael@0 1271 }
michael@0 1272
michael@0 1273 eFontPrefLang
michael@0 1274 gfxPlatform::GetFontPrefLangFor(nsIAtom *aLang)
michael@0 1275 {
michael@0 1276 if (!aLang)
michael@0 1277 return eFontPrefLang_Others;
michael@0 1278 nsAutoCString lang;
michael@0 1279 aLang->ToUTF8String(lang);
michael@0 1280 return GetFontPrefLangFor(lang.get());
michael@0 1281 }
michael@0 1282
michael@0 1283 const char*
michael@0 1284 gfxPlatform::GetPrefLangName(eFontPrefLang aLang)
michael@0 1285 {
michael@0 1286 if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) {
michael@0 1287 return gPrefLangNames[uint32_t(aLang)];
michael@0 1288 }
michael@0 1289 return nullptr;
michael@0 1290 }
michael@0 1291
michael@0 1292 eFontPrefLang
michael@0 1293 gfxPlatform::GetFontPrefLangFor(uint8_t aUnicodeRange)
michael@0 1294 {
michael@0 1295 switch (aUnicodeRange) {
michael@0 1296 case kRangeSetLatin: return eFontPrefLang_Western;
michael@0 1297 case kRangeCyrillic: return eFontPrefLang_Cyrillic;
michael@0 1298 case kRangeGreek: return eFontPrefLang_Greek;
michael@0 1299 case kRangeTurkish: return eFontPrefLang_Turkish;
michael@0 1300 case kRangeHebrew: return eFontPrefLang_Hebrew;
michael@0 1301 case kRangeArabic: return eFontPrefLang_Arabic;
michael@0 1302 case kRangeBaltic: return eFontPrefLang_Baltic;
michael@0 1303 case kRangeThai: return eFontPrefLang_Thai;
michael@0 1304 case kRangeKorean: return eFontPrefLang_Korean;
michael@0 1305 case kRangeJapanese: return eFontPrefLang_Japanese;
michael@0 1306 case kRangeSChinese: return eFontPrefLang_ChineseCN;
michael@0 1307 case kRangeTChinese: return eFontPrefLang_ChineseTW;
michael@0 1308 case kRangeDevanagari: return eFontPrefLang_Devanagari;
michael@0 1309 case kRangeTamil: return eFontPrefLang_Tamil;
michael@0 1310 case kRangeArmenian: return eFontPrefLang_Armenian;
michael@0 1311 case kRangeBengali: return eFontPrefLang_Bengali;
michael@0 1312 case kRangeCanadian: return eFontPrefLang_Canadian;
michael@0 1313 case kRangeEthiopic: return eFontPrefLang_Ethiopic;
michael@0 1314 case kRangeGeorgian: return eFontPrefLang_Georgian;
michael@0 1315 case kRangeGujarati: return eFontPrefLang_Gujarati;
michael@0 1316 case kRangeGurmukhi: return eFontPrefLang_Gurmukhi;
michael@0 1317 case kRangeKhmer: return eFontPrefLang_Khmer;
michael@0 1318 case kRangeMalayalam: return eFontPrefLang_Malayalam;
michael@0 1319 case kRangeOriya: return eFontPrefLang_Oriya;
michael@0 1320 case kRangeTelugu: return eFontPrefLang_Telugu;
michael@0 1321 case kRangeKannada: return eFontPrefLang_Kannada;
michael@0 1322 case kRangeSinhala: return eFontPrefLang_Sinhala;
michael@0 1323 case kRangeTibetan: return eFontPrefLang_Tibetan;
michael@0 1324 case kRangeSetCJK: return eFontPrefLang_CJKSet;
michael@0 1325 default: return eFontPrefLang_Others;
michael@0 1326 }
michael@0 1327 }
michael@0 1328
michael@0 1329 bool
michael@0 1330 gfxPlatform::IsLangCJK(eFontPrefLang aLang)
michael@0 1331 {
michael@0 1332 switch (aLang) {
michael@0 1333 case eFontPrefLang_Japanese:
michael@0 1334 case eFontPrefLang_ChineseTW:
michael@0 1335 case eFontPrefLang_ChineseCN:
michael@0 1336 case eFontPrefLang_ChineseHK:
michael@0 1337 case eFontPrefLang_Korean:
michael@0 1338 case eFontPrefLang_CJKSet:
michael@0 1339 return true;
michael@0 1340 default:
michael@0 1341 return false;
michael@0 1342 }
michael@0 1343 }
michael@0 1344
michael@0 1345 mozilla::layers::DiagnosticTypes
michael@0 1346 gfxPlatform::GetLayerDiagnosticTypes()
michael@0 1347 {
michael@0 1348 mozilla::layers::DiagnosticTypes type = DIAGNOSTIC_NONE;
michael@0 1349 if (gfxPrefs::DrawLayerBorders()) {
michael@0 1350 type |= mozilla::layers::DIAGNOSTIC_LAYER_BORDERS;
michael@0 1351 }
michael@0 1352 if (gfxPrefs::DrawTileBorders()) {
michael@0 1353 type |= mozilla::layers::DIAGNOSTIC_TILE_BORDERS;
michael@0 1354 }
michael@0 1355 if (gfxPrefs::DrawBigImageBorders()) {
michael@0 1356 type |= mozilla::layers::DIAGNOSTIC_BIGIMAGE_BORDERS;
michael@0 1357 }
michael@0 1358 if (gfxPrefs::FlashLayerBorders()) {
michael@0 1359 type |= mozilla::layers::DIAGNOSTIC_FLASH_BORDERS;
michael@0 1360 }
michael@0 1361 return type;
michael@0 1362 }
michael@0 1363
michael@0 1364 void
michael@0 1365 gfxPlatform::GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
michael@0 1366 {
michael@0 1367 if (IsLangCJK(aCharLang)) {
michael@0 1368 AppendCJKPrefLangs(aPrefLangs, aLen, aCharLang, aPageLang);
michael@0 1369 } else {
michael@0 1370 AppendPrefLang(aPrefLangs, aLen, aCharLang);
michael@0 1371 }
michael@0 1372
michael@0 1373 AppendPrefLang(aPrefLangs, aLen, eFontPrefLang_Others);
michael@0 1374 }
michael@0 1375
michael@0 1376 void
michael@0 1377 gfxPlatform::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
michael@0 1378 {
michael@0 1379 // prefer the lang specified by the page *if* CJK
michael@0 1380 if (IsLangCJK(aPageLang)) {
michael@0 1381 AppendPrefLang(aPrefLangs, aLen, aPageLang);
michael@0 1382 }
michael@0 1383
michael@0 1384 // if not set up, set up the default CJK order, based on accept lang settings and locale
michael@0 1385 if (mCJKPrefLangs.Length() == 0) {
michael@0 1386
michael@0 1387 // temp array
michael@0 1388 eFontPrefLang tempPrefLangs[kMaxLenPrefLangList];
michael@0 1389 uint32_t tempLen = 0;
michael@0 1390
michael@0 1391 // Add the CJK pref fonts from accept languages, the order should be same order
michael@0 1392 nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages");
michael@0 1393 if (!list.IsEmpty()) {
michael@0 1394 const char kComma = ',';
michael@0 1395 const char *p, *p_end;
michael@0 1396 list.BeginReading(p);
michael@0 1397 list.EndReading(p_end);
michael@0 1398 while (p < p_end) {
michael@0 1399 while (nsCRT::IsAsciiSpace(*p)) {
michael@0 1400 if (++p == p_end)
michael@0 1401 break;
michael@0 1402 }
michael@0 1403 if (p == p_end)
michael@0 1404 break;
michael@0 1405 const char *start = p;
michael@0 1406 while (++p != p_end && *p != kComma)
michael@0 1407 /* nothing */ ;
michael@0 1408 nsAutoCString lang(Substring(start, p));
michael@0 1409 lang.CompressWhitespace(false, true);
michael@0 1410 eFontPrefLang fpl = gfxPlatform::GetFontPrefLangFor(lang.get());
michael@0 1411 switch (fpl) {
michael@0 1412 case eFontPrefLang_Japanese:
michael@0 1413 case eFontPrefLang_Korean:
michael@0 1414 case eFontPrefLang_ChineseCN:
michael@0 1415 case eFontPrefLang_ChineseHK:
michael@0 1416 case eFontPrefLang_ChineseTW:
michael@0 1417 AppendPrefLang(tempPrefLangs, tempLen, fpl);
michael@0 1418 break;
michael@0 1419 default:
michael@0 1420 break;
michael@0 1421 }
michael@0 1422 p++;
michael@0 1423 }
michael@0 1424 }
michael@0 1425
michael@0 1426 do { // to allow 'break' to abort this block if a call fails
michael@0 1427 nsresult rv;
michael@0 1428 nsCOMPtr<nsILocaleService> ls =
michael@0 1429 do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
michael@0 1430 if (NS_FAILED(rv))
michael@0 1431 break;
michael@0 1432
michael@0 1433 nsCOMPtr<nsILocale> appLocale;
michael@0 1434 rv = ls->GetApplicationLocale(getter_AddRefs(appLocale));
michael@0 1435 if (NS_FAILED(rv))
michael@0 1436 break;
michael@0 1437
michael@0 1438 nsString localeStr;
michael@0 1439 rv = appLocale->
michael@0 1440 GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr);
michael@0 1441 if (NS_FAILED(rv))
michael@0 1442 break;
michael@0 1443
michael@0 1444 const nsAString& lang = Substring(localeStr, 0, 2);
michael@0 1445 if (lang.EqualsLiteral("ja")) {
michael@0 1446 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
michael@0 1447 } else if (lang.EqualsLiteral("zh")) {
michael@0 1448 const nsAString& region = Substring(localeStr, 3, 2);
michael@0 1449 if (region.EqualsLiteral("CN")) {
michael@0 1450 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
michael@0 1451 } else if (region.EqualsLiteral("TW")) {
michael@0 1452 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
michael@0 1453 } else if (region.EqualsLiteral("HK")) {
michael@0 1454 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
michael@0 1455 }
michael@0 1456 } else if (lang.EqualsLiteral("ko")) {
michael@0 1457 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
michael@0 1458 }
michael@0 1459 } while (0);
michael@0 1460
michael@0 1461 // last resort... (the order is same as old gfx.)
michael@0 1462 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
michael@0 1463 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
michael@0 1464 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
michael@0 1465 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
michael@0 1466 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
michael@0 1467
michael@0 1468 // copy into the cached array
michael@0 1469 uint32_t j;
michael@0 1470 for (j = 0; j < tempLen; j++) {
michael@0 1471 mCJKPrefLangs.AppendElement(tempPrefLangs[j]);
michael@0 1472 }
michael@0 1473 }
michael@0 1474
michael@0 1475 // append in cached CJK langs
michael@0 1476 uint32_t i, numCJKlangs = mCJKPrefLangs.Length();
michael@0 1477
michael@0 1478 for (i = 0; i < numCJKlangs; i++) {
michael@0 1479 AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i]));
michael@0 1480 }
michael@0 1481
michael@0 1482 }
michael@0 1483
michael@0 1484 void
michael@0 1485 gfxPlatform::AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang)
michael@0 1486 {
michael@0 1487 if (aLen >= kMaxLenPrefLangList) return;
michael@0 1488
michael@0 1489 // make sure
michael@0 1490 uint32_t i = 0;
michael@0 1491 while (i < aLen && aPrefLangs[i] != aAddLang) {
michael@0 1492 i++;
michael@0 1493 }
michael@0 1494
michael@0 1495 if (i == aLen) {
michael@0 1496 aPrefLangs[aLen] = aAddLang;
michael@0 1497 aLen++;
michael@0 1498 }
michael@0 1499 }
michael@0 1500
michael@0 1501 void
michael@0 1502 gfxPlatform::InitBackendPrefs(uint32_t aCanvasBitmask, BackendType aCanvasDefault,
michael@0 1503 uint32_t aContentBitmask, BackendType aContentDefault)
michael@0 1504 {
michael@0 1505 mPreferredCanvasBackend = GetCanvasBackendPref(aCanvasBitmask);
michael@0 1506 if (mPreferredCanvasBackend == BackendType::NONE) {
michael@0 1507 mPreferredCanvasBackend = aCanvasDefault;
michael@0 1508 }
michael@0 1509 mFallbackCanvasBackend =
michael@0 1510 GetCanvasBackendPref(aCanvasBitmask & ~BackendTypeBit(mPreferredCanvasBackend));
michael@0 1511
michael@0 1512 mContentBackendBitmask = aContentBitmask;
michael@0 1513 mContentBackend = GetContentBackendPref(mContentBackendBitmask);
michael@0 1514 if (mContentBackend == BackendType::NONE) {
michael@0 1515 mContentBackend = aContentDefault;
michael@0 1516 // mContentBackendBitmask is our canonical reference for supported
michael@0 1517 // backends so we need to add the default if we are using it and
michael@0 1518 // overriding the prefs.
michael@0 1519 mContentBackendBitmask |= BackendTypeBit(aContentDefault);
michael@0 1520 }
michael@0 1521 }
michael@0 1522
michael@0 1523 /* static */ BackendType
michael@0 1524 gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask)
michael@0 1525 {
michael@0 1526 return GetBackendPref("gfx.canvas.azure.backends", aBackendBitmask);
michael@0 1527 }
michael@0 1528
michael@0 1529 /* static */ BackendType
michael@0 1530 gfxPlatform::GetContentBackendPref(uint32_t &aBackendBitmask)
michael@0 1531 {
michael@0 1532 return GetBackendPref("gfx.content.azure.backends", aBackendBitmask);
michael@0 1533 }
michael@0 1534
michael@0 1535 /* static */ BackendType
michael@0 1536 gfxPlatform::GetBackendPref(const char* aBackendPrefName, uint32_t &aBackendBitmask)
michael@0 1537 {
michael@0 1538 nsTArray<nsCString> backendList;
michael@0 1539 nsCString prefString;
michael@0 1540 if (NS_SUCCEEDED(Preferences::GetCString(aBackendPrefName, &prefString))) {
michael@0 1541 ParseString(prefString, ',', backendList);
michael@0 1542 }
michael@0 1543
michael@0 1544 uint32_t allowedBackends = 0;
michael@0 1545 BackendType result = BackendType::NONE;
michael@0 1546 for (uint32_t i = 0; i < backendList.Length(); ++i) {
michael@0 1547 BackendType type = BackendTypeForName(backendList[i]);
michael@0 1548 if (BackendTypeBit(type) & aBackendBitmask) {
michael@0 1549 allowedBackends |= BackendTypeBit(type);
michael@0 1550 if (result == BackendType::NONE) {
michael@0 1551 result = type;
michael@0 1552 }
michael@0 1553 }
michael@0 1554 }
michael@0 1555
michael@0 1556 aBackendBitmask = allowedBackends;
michael@0 1557 return result;
michael@0 1558 }
michael@0 1559
michael@0 1560 bool
michael@0 1561 gfxPlatform::OffMainThreadCompositingEnabled()
michael@0 1562 {
michael@0 1563 return XRE_GetProcessType() == GeckoProcessType_Default ?
michael@0 1564 CompositorParent::CompositorLoop() != nullptr :
michael@0 1565 CompositorChild::ChildProcessHasCompositor();
michael@0 1566 }
michael@0 1567
michael@0 1568 eCMSMode
michael@0 1569 gfxPlatform::GetCMSMode()
michael@0 1570 {
michael@0 1571 if (gCMSInitialized == false) {
michael@0 1572 gCMSInitialized = true;
michael@0 1573
michael@0 1574 int32_t mode = gfxPrefs::CMSMode();
michael@0 1575 if (mode >= 0 && mode < eCMSMode_AllCount) {
michael@0 1576 gCMSMode = static_cast<eCMSMode>(mode);
michael@0 1577 }
michael@0 1578
michael@0 1579 bool enableV4 = gfxPrefs::CMSEnableV4();
michael@0 1580 if (enableV4) {
michael@0 1581 qcms_enable_iccv4();
michael@0 1582 }
michael@0 1583 }
michael@0 1584 return gCMSMode;
michael@0 1585 }
michael@0 1586
michael@0 1587 int
michael@0 1588 gfxPlatform::GetRenderingIntent()
michael@0 1589 {
michael@0 1590 if (!gCMSIntentInitialized) {
michael@0 1591 gCMSIntentInitialized = true;
michael@0 1592
michael@0 1593 // gfxPrefs.h is using 0 as the default for the rendering
michael@0 1594 // intent preference, based on that being the value for
michael@0 1595 // QCMS_INTENT_DEFAULT. Assert here to catch if that ever
michael@0 1596 // changes and we can then figure out what to do about it.
michael@0 1597 MOZ_ASSERT(QCMS_INTENT_DEFAULT == 0);
michael@0 1598
michael@0 1599 /* Try to query the pref system for a rendering intent. */
michael@0 1600 int32_t pIntent = gfxPrefs::CMSRenderingIntent();
michael@0 1601 if ((pIntent >= QCMS_INTENT_MIN) && (pIntent <= QCMS_INTENT_MAX)) {
michael@0 1602 gCMSIntent = pIntent;
michael@0 1603 } else {
michael@0 1604 /* If the pref is out of range, use embedded profile. */
michael@0 1605 gCMSIntent = -1;
michael@0 1606 }
michael@0 1607 }
michael@0 1608 return gCMSIntent;
michael@0 1609 }
michael@0 1610
michael@0 1611 void
michael@0 1612 gfxPlatform::TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *transform)
michael@0 1613 {
michael@0 1614
michael@0 1615 if (transform) {
michael@0 1616 /* we want the bytes in RGB order */
michael@0 1617 #ifdef IS_LITTLE_ENDIAN
michael@0 1618 /* ABGR puts the bytes in |RGBA| order on little endian */
michael@0 1619 uint32_t packed = in.Packed(gfxRGBA::PACKED_ABGR);
michael@0 1620 qcms_transform_data(transform,
michael@0 1621 (uint8_t *)&packed, (uint8_t *)&packed,
michael@0 1622 1);
michael@0 1623 out.~gfxRGBA();
michael@0 1624 new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ABGR);
michael@0 1625 #else
michael@0 1626 /* ARGB puts the bytes in |ARGB| order on big endian */
michael@0 1627 uint32_t packed = in.Packed(gfxRGBA::PACKED_ARGB);
michael@0 1628 /* add one to move past the alpha byte */
michael@0 1629 qcms_transform_data(transform,
michael@0 1630 (uint8_t *)&packed + 1, (uint8_t *)&packed + 1,
michael@0 1631 1);
michael@0 1632 out.~gfxRGBA();
michael@0 1633 new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ARGB);
michael@0 1634 #endif
michael@0 1635 }
michael@0 1636
michael@0 1637 else if (&out != &in)
michael@0 1638 out = in;
michael@0 1639 }
michael@0 1640
michael@0 1641 void
michael@0 1642 gfxPlatform::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
michael@0 1643 {
michael@0 1644 mem = nullptr;
michael@0 1645 size = 0;
michael@0 1646 }
michael@0 1647
michael@0 1648 void
michael@0 1649 gfxPlatform::GetCMSOutputProfileData(void *&mem, size_t &size)
michael@0 1650 {
michael@0 1651 nsAdoptingCString fname = Preferences::GetCString("gfx.color_management.display_profile");
michael@0 1652 if (!fname.IsEmpty()) {
michael@0 1653 qcms_data_from_path(fname, &mem, &size);
michael@0 1654 }
michael@0 1655 else {
michael@0 1656 gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile(mem, size);
michael@0 1657 }
michael@0 1658 }
michael@0 1659
michael@0 1660 void
michael@0 1661 gfxPlatform::CreateCMSOutputProfile()
michael@0 1662 {
michael@0 1663 if (!gCMSOutputProfile) {
michael@0 1664 /* Determine if we're using the internal override to force sRGB as
michael@0 1665 an output profile for reftests. See Bug 452125.
michael@0 1666
michael@0 1667 Note that we don't normally (outside of tests) set a
michael@0 1668 default value of this preference, which means nsIPrefBranch::GetBoolPref
michael@0 1669 will typically throw (and leave its out-param untouched).
michael@0 1670 */
michael@0 1671 if (Preferences::GetBool(GFX_PREF_CMS_FORCE_SRGB, false)) {
michael@0 1672 gCMSOutputProfile = GetCMSsRGBProfile();
michael@0 1673 }
michael@0 1674
michael@0 1675 if (!gCMSOutputProfile) {
michael@0 1676 void* mem = nullptr;
michael@0 1677 size_t size = 0;
michael@0 1678
michael@0 1679 GetCMSOutputProfileData(mem, size);
michael@0 1680 if ((mem != nullptr) && (size > 0)) {
michael@0 1681 gCMSOutputProfile = qcms_profile_from_memory(mem, size);
michael@0 1682 free(mem);
michael@0 1683 }
michael@0 1684 }
michael@0 1685
michael@0 1686 /* Determine if the profile looks bogus. If so, close the profile
michael@0 1687 * and use sRGB instead. See bug 460629, */
michael@0 1688 if (gCMSOutputProfile && qcms_profile_is_bogus(gCMSOutputProfile)) {
michael@0 1689 NS_ASSERTION(gCMSOutputProfile != GetCMSsRGBProfile(),
michael@0 1690 "Builtin sRGB profile tagged as bogus!!!");
michael@0 1691 qcms_profile_release(gCMSOutputProfile);
michael@0 1692 gCMSOutputProfile = nullptr;
michael@0 1693 }
michael@0 1694
michael@0 1695 if (!gCMSOutputProfile) {
michael@0 1696 gCMSOutputProfile = GetCMSsRGBProfile();
michael@0 1697 }
michael@0 1698 /* Precache the LUT16 Interpolations for the output profile. See
michael@0 1699 bug 444661 for details. */
michael@0 1700 qcms_profile_precache_output_transform(gCMSOutputProfile);
michael@0 1701 }
michael@0 1702 }
michael@0 1703
michael@0 1704 qcms_profile *
michael@0 1705 gfxPlatform::GetCMSOutputProfile()
michael@0 1706 {
michael@0 1707 return gCMSOutputProfile;
michael@0 1708 }
michael@0 1709
michael@0 1710 qcms_profile *
michael@0 1711 gfxPlatform::GetCMSsRGBProfile()
michael@0 1712 {
michael@0 1713 if (!gCMSsRGBProfile) {
michael@0 1714
michael@0 1715 /* Create the profile using qcms. */
michael@0 1716 gCMSsRGBProfile = qcms_profile_sRGB();
michael@0 1717 }
michael@0 1718 return gCMSsRGBProfile;
michael@0 1719 }
michael@0 1720
michael@0 1721 qcms_transform *
michael@0 1722 gfxPlatform::GetCMSRGBTransform()
michael@0 1723 {
michael@0 1724 if (!gCMSRGBTransform) {
michael@0 1725 qcms_profile *inProfile, *outProfile;
michael@0 1726 outProfile = GetCMSOutputProfile();
michael@0 1727 inProfile = GetCMSsRGBProfile();
michael@0 1728
michael@0 1729 if (!inProfile || !outProfile)
michael@0 1730 return nullptr;
michael@0 1731
michael@0 1732 gCMSRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
michael@0 1733 outProfile, QCMS_DATA_RGB_8,
michael@0 1734 QCMS_INTENT_PERCEPTUAL);
michael@0 1735 }
michael@0 1736
michael@0 1737 return gCMSRGBTransform;
michael@0 1738 }
michael@0 1739
michael@0 1740 qcms_transform *
michael@0 1741 gfxPlatform::GetCMSInverseRGBTransform()
michael@0 1742 {
michael@0 1743 if (!gCMSInverseRGBTransform) {
michael@0 1744 qcms_profile *inProfile, *outProfile;
michael@0 1745 inProfile = GetCMSOutputProfile();
michael@0 1746 outProfile = GetCMSsRGBProfile();
michael@0 1747
michael@0 1748 if (!inProfile || !outProfile)
michael@0 1749 return nullptr;
michael@0 1750
michael@0 1751 gCMSInverseRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
michael@0 1752 outProfile, QCMS_DATA_RGB_8,
michael@0 1753 QCMS_INTENT_PERCEPTUAL);
michael@0 1754 }
michael@0 1755
michael@0 1756 return gCMSInverseRGBTransform;
michael@0 1757 }
michael@0 1758
michael@0 1759 qcms_transform *
michael@0 1760 gfxPlatform::GetCMSRGBATransform()
michael@0 1761 {
michael@0 1762 if (!gCMSRGBATransform) {
michael@0 1763 qcms_profile *inProfile, *outProfile;
michael@0 1764 outProfile = GetCMSOutputProfile();
michael@0 1765 inProfile = GetCMSsRGBProfile();
michael@0 1766
michael@0 1767 if (!inProfile || !outProfile)
michael@0 1768 return nullptr;
michael@0 1769
michael@0 1770 gCMSRGBATransform = qcms_transform_create(inProfile, QCMS_DATA_RGBA_8,
michael@0 1771 outProfile, QCMS_DATA_RGBA_8,
michael@0 1772 QCMS_INTENT_PERCEPTUAL);
michael@0 1773 }
michael@0 1774
michael@0 1775 return gCMSRGBATransform;
michael@0 1776 }
michael@0 1777
michael@0 1778 /* Shuts down various transforms and profiles for CMS. */
michael@0 1779 static void ShutdownCMS()
michael@0 1780 {
michael@0 1781
michael@0 1782 if (gCMSRGBTransform) {
michael@0 1783 qcms_transform_release(gCMSRGBTransform);
michael@0 1784 gCMSRGBTransform = nullptr;
michael@0 1785 }
michael@0 1786 if (gCMSInverseRGBTransform) {
michael@0 1787 qcms_transform_release(gCMSInverseRGBTransform);
michael@0 1788 gCMSInverseRGBTransform = nullptr;
michael@0 1789 }
michael@0 1790 if (gCMSRGBATransform) {
michael@0 1791 qcms_transform_release(gCMSRGBATransform);
michael@0 1792 gCMSRGBATransform = nullptr;
michael@0 1793 }
michael@0 1794 if (gCMSOutputProfile) {
michael@0 1795 qcms_profile_release(gCMSOutputProfile);
michael@0 1796
michael@0 1797 // handle the aliased case
michael@0 1798 if (gCMSsRGBProfile == gCMSOutputProfile)
michael@0 1799 gCMSsRGBProfile = nullptr;
michael@0 1800 gCMSOutputProfile = nullptr;
michael@0 1801 }
michael@0 1802 if (gCMSsRGBProfile) {
michael@0 1803 qcms_profile_release(gCMSsRGBProfile);
michael@0 1804 gCMSsRGBProfile = nullptr;
michael@0 1805 }
michael@0 1806
michael@0 1807 // Reset the state variables
michael@0 1808 gCMSIntent = -2;
michael@0 1809 gCMSMode = eCMSMode_Off;
michael@0 1810 gCMSInitialized = false;
michael@0 1811 }
michael@0 1812
michael@0 1813 // default SetupClusterBoundaries, based on Unicode properties;
michael@0 1814 // platform subclasses may override if they wish
michael@0 1815 void
michael@0 1816 gfxPlatform::SetupClusterBoundaries(gfxTextRun *aTextRun, const char16_t *aString)
michael@0 1817 {
michael@0 1818 if (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) {
michael@0 1819 // 8-bit text doesn't have clusters.
michael@0 1820 // XXX is this true in all languages???
michael@0 1821 // behdad: don't think so. Czech for example IIRC has a
michael@0 1822 // 'ch' grapheme.
michael@0 1823 // jfkthame: but that's not expected to behave as a grapheme cluster
michael@0 1824 // for selection/editing/etc.
michael@0 1825 return;
michael@0 1826 }
michael@0 1827
michael@0 1828 aTextRun->SetupClusterBoundaries(0, aString, aTextRun->GetLength());
michael@0 1829 }
michael@0 1830
michael@0 1831 int32_t
michael@0 1832 gfxPlatform::GetBidiNumeralOption()
michael@0 1833 {
michael@0 1834 if (mBidiNumeralOption == UNINITIALIZED_VALUE) {
michael@0 1835 mBidiNumeralOption = Preferences::GetInt(BIDI_NUMERAL_PREF, 0);
michael@0 1836 }
michael@0 1837 return mBidiNumeralOption;
michael@0 1838 }
michael@0 1839
michael@0 1840 static void
michael@0 1841 FlushFontAndWordCaches()
michael@0 1842 {
michael@0 1843 gfxFontCache *fontCache = gfxFontCache::GetCache();
michael@0 1844 if (fontCache) {
michael@0 1845 fontCache->AgeAllGenerations();
michael@0 1846 fontCache->FlushShapedWordCaches();
michael@0 1847 }
michael@0 1848 }
michael@0 1849
michael@0 1850 void
michael@0 1851 gfxPlatform::FontsPrefsChanged(const char *aPref)
michael@0 1852 {
michael@0 1853 NS_ASSERTION(aPref != nullptr, "null preference");
michael@0 1854 if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) {
michael@0 1855 mAllowDownloadableFonts = UNINITIALIZED_VALUE;
michael@0 1856 } else if (!strcmp(GFX_PREF_FALLBACK_USE_CMAPS, aPref)) {
michael@0 1857 mFallbackUsesCmaps = UNINITIALIZED_VALUE;
michael@0 1858 } else if (!strcmp(GFX_PREF_WORD_CACHE_CHARLIMIT, aPref)) {
michael@0 1859 mWordCacheCharLimit = UNINITIALIZED_VALUE;
michael@0 1860 FlushFontAndWordCaches();
michael@0 1861 } else if (!strcmp(GFX_PREF_WORD_CACHE_MAXENTRIES, aPref)) {
michael@0 1862 mWordCacheMaxEntries = UNINITIALIZED_VALUE;
michael@0 1863 FlushFontAndWordCaches();
michael@0 1864 } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
michael@0 1865 mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
michael@0 1866 FlushFontAndWordCaches();
michael@0 1867 } else if (!strcmp(GFX_PREF_HARFBUZZ_SCRIPTS, aPref)) {
michael@0 1868 mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
michael@0 1869 FlushFontAndWordCaches();
michael@0 1870 } else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) {
michael@0 1871 mBidiNumeralOption = UNINITIALIZED_VALUE;
michael@0 1872 } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) {
michael@0 1873 mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
michael@0 1874 gfxFontCache::GetCache()->AgeAllGenerations();
michael@0 1875 }
michael@0 1876 }
michael@0 1877
michael@0 1878
michael@0 1879 PRLogModuleInfo*
michael@0 1880 gfxPlatform::GetLog(eGfxLog aWhichLog)
michael@0 1881 {
michael@0 1882 // logs shared across gfx
michael@0 1883 #ifdef PR_LOGGING
michael@0 1884 static PRLogModuleInfo *sFontlistLog = nullptr;
michael@0 1885 static PRLogModuleInfo *sFontInitLog = nullptr;
michael@0 1886 static PRLogModuleInfo *sTextrunLog = nullptr;
michael@0 1887 static PRLogModuleInfo *sTextrunuiLog = nullptr;
michael@0 1888 static PRLogModuleInfo *sCmapDataLog = nullptr;
michael@0 1889 static PRLogModuleInfo *sTextPerfLog = nullptr;
michael@0 1890
michael@0 1891 // Assume that if one is initialized, all are initialized
michael@0 1892 if (!sFontlistLog) {
michael@0 1893 sFontlistLog = PR_NewLogModule("fontlist");
michael@0 1894 sFontInitLog = PR_NewLogModule("fontinit");
michael@0 1895 sTextrunLog = PR_NewLogModule("textrun");
michael@0 1896 sTextrunuiLog = PR_NewLogModule("textrunui");
michael@0 1897 sCmapDataLog = PR_NewLogModule("cmapdata");
michael@0 1898 sTextPerfLog = PR_NewLogModule("textperf");
michael@0 1899 }
michael@0 1900
michael@0 1901 switch (aWhichLog) {
michael@0 1902 case eGfxLog_fontlist:
michael@0 1903 return sFontlistLog;
michael@0 1904 break;
michael@0 1905 case eGfxLog_fontinit:
michael@0 1906 return sFontInitLog;
michael@0 1907 break;
michael@0 1908 case eGfxLog_textrun:
michael@0 1909 return sTextrunLog;
michael@0 1910 break;
michael@0 1911 case eGfxLog_textrunui:
michael@0 1912 return sTextrunuiLog;
michael@0 1913 break;
michael@0 1914 case eGfxLog_cmapdata:
michael@0 1915 return sCmapDataLog;
michael@0 1916 break;
michael@0 1917 case eGfxLog_textperf:
michael@0 1918 return sTextPerfLog;
michael@0 1919 break;
michael@0 1920 default:
michael@0 1921 break;
michael@0 1922 }
michael@0 1923
michael@0 1924 return nullptr;
michael@0 1925 #else
michael@0 1926 return nullptr;
michael@0 1927 #endif
michael@0 1928 }
michael@0 1929
michael@0 1930 int
michael@0 1931 gfxPlatform::GetScreenDepth() const
michael@0 1932 {
michael@0 1933 NS_WARNING("GetScreenDepth not implemented on this platform -- returning 0!");
michael@0 1934 return 0;
michael@0 1935 }
michael@0 1936
michael@0 1937 mozilla::gfx::SurfaceFormat
michael@0 1938 gfxPlatform::Optimal2DFormatForContent(gfxContentType aContent)
michael@0 1939 {
michael@0 1940 switch (aContent) {
michael@0 1941 case gfxContentType::COLOR:
michael@0 1942 switch (GetOffscreenFormat()) {
michael@0 1943 case gfxImageFormat::ARGB32:
michael@0 1944 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
michael@0 1945 case gfxImageFormat::RGB24:
michael@0 1946 return mozilla::gfx::SurfaceFormat::B8G8R8X8;
michael@0 1947 case gfxImageFormat::RGB16_565:
michael@0 1948 return mozilla::gfx::SurfaceFormat::R5G6B5;
michael@0 1949 default:
michael@0 1950 NS_NOTREACHED("unknown gfxImageFormat for gfxContentType::COLOR");
michael@0 1951 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
michael@0 1952 }
michael@0 1953 case gfxContentType::ALPHA:
michael@0 1954 return mozilla::gfx::SurfaceFormat::A8;
michael@0 1955 case gfxContentType::COLOR_ALPHA:
michael@0 1956 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
michael@0 1957 default:
michael@0 1958 NS_NOTREACHED("unknown gfxContentType");
michael@0 1959 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
michael@0 1960 }
michael@0 1961 }
michael@0 1962
michael@0 1963 gfxImageFormat
michael@0 1964 gfxPlatform::OptimalFormatForContent(gfxContentType aContent)
michael@0 1965 {
michael@0 1966 switch (aContent) {
michael@0 1967 case gfxContentType::COLOR:
michael@0 1968 return GetOffscreenFormat();
michael@0 1969 case gfxContentType::ALPHA:
michael@0 1970 return gfxImageFormat::A8;
michael@0 1971 case gfxContentType::COLOR_ALPHA:
michael@0 1972 return gfxImageFormat::ARGB32;
michael@0 1973 default:
michael@0 1974 NS_NOTREACHED("unknown gfxContentType");
michael@0 1975 return gfxImageFormat::ARGB32;
michael@0 1976 }
michael@0 1977 }
michael@0 1978
michael@0 1979 /**
michael@0 1980 * There are a number of layers acceleration (or layers in general) preferences
michael@0 1981 * that should be consistent for the lifetime of the application (bug 840967).
michael@0 1982 * As such, we will evaluate them all as soon as one of them is evaluated
michael@0 1983 * and remember the values. Changing these preferences during the run will
michael@0 1984 * not have any effect until we restart.
michael@0 1985 */
michael@0 1986 static bool sLayersSupportsD3D9 = false;
michael@0 1987 static bool sBufferRotationCheckPref = true;
michael@0 1988 static bool sPrefBrowserTabsRemoteAutostart = false;
michael@0 1989
michael@0 1990 static bool sLayersAccelerationPrefsInitialized = false;
michael@0 1991
michael@0 1992 void
michael@0 1993 InitLayersAccelerationPrefs()
michael@0 1994 {
michael@0 1995 if (!sLayersAccelerationPrefsInitialized)
michael@0 1996 {
michael@0 1997 // If this is called for the first time on a non-main thread, we're screwed.
michael@0 1998 // At the moment there's no explicit guarantee that the main thread calls
michael@0 1999 // this before the compositor thread, but let's at least make the assumption
michael@0 2000 // explicit.
michael@0 2001 MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread");
michael@0 2002
michael@0 2003 sPrefBrowserTabsRemoteAutostart = Preferences::GetBool("browser.tabs.remote.autostart", false);
michael@0 2004
michael@0 2005 #ifdef XP_WIN
michael@0 2006 if (gfxPrefs::LayersAccelerationForceEnabled()) {
michael@0 2007 sLayersSupportsD3D9 = true;
michael@0 2008 } else {
michael@0 2009 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
michael@0 2010 if (gfxInfo) {
michael@0 2011 int32_t status;
michael@0 2012 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status))) {
michael@0 2013 if (status == nsIGfxInfo::FEATURE_NO_INFO) {
michael@0 2014 sLayersSupportsD3D9 = true;
michael@0 2015 }
michael@0 2016 }
michael@0 2017 }
michael@0 2018 }
michael@0 2019 #endif
michael@0 2020
michael@0 2021 sLayersAccelerationPrefsInitialized = true;
michael@0 2022 }
michael@0 2023 }
michael@0 2024
michael@0 2025 bool
michael@0 2026 gfxPlatform::GetPrefLayersOffMainThreadCompositionEnabled()
michael@0 2027 {
michael@0 2028 InitLayersAccelerationPrefs();
michael@0 2029 return gfxPrefs::LayersOffMainThreadCompositionEnabled() ||
michael@0 2030 gfxPrefs::LayersOffMainThreadCompositionForceEnabled() ||
michael@0 2031 gfxPrefs::LayersOffMainThreadCompositionTestingEnabled();
michael@0 2032 }
michael@0 2033
michael@0 2034 bool gfxPlatform::OffMainThreadCompositionRequired()
michael@0 2035 {
michael@0 2036 InitLayersAccelerationPrefs();
michael@0 2037 #if defined(MOZ_WIDGET_GTK) && defined(NIGHTLY_BUILD)
michael@0 2038 // Linux users who chose OpenGL are being grandfathered in to OMTC
michael@0 2039 return sPrefBrowserTabsRemoteAutostart ||
michael@0 2040 gfxPrefs::LayersAccelerationForceEnabled();
michael@0 2041 #else
michael@0 2042 return sPrefBrowserTabsRemoteAutostart;
michael@0 2043 #endif
michael@0 2044 }
michael@0 2045
michael@0 2046 bool
michael@0 2047 gfxPlatform::CanUseDirect3D9()
michael@0 2048 {
michael@0 2049 // this function is called from the compositor thread, so it is not
michael@0 2050 // safe to init the prefs etc. from here.
michael@0 2051 MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
michael@0 2052 return sLayersSupportsD3D9;
michael@0 2053 }
michael@0 2054
michael@0 2055 bool
michael@0 2056 gfxPlatform::BufferRotationEnabled()
michael@0 2057 {
michael@0 2058 MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
michael@0 2059
michael@0 2060 return sBufferRotationCheckPref && gfxPrefs::BufferRotationEnabled();
michael@0 2061 }
michael@0 2062
michael@0 2063 void
michael@0 2064 gfxPlatform::DisableBufferRotation()
michael@0 2065 {
michael@0 2066 MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
michael@0 2067
michael@0 2068 sBufferRotationCheckPref = false;
michael@0 2069 }
michael@0 2070
michael@0 2071 TemporaryRef<ScaledFont>
michael@0 2072 gfxPlatform::GetScaledFontForFontWithCairoSkia(DrawTarget* aTarget, gfxFont* aFont)
michael@0 2073 {
michael@0 2074 NativeFont nativeFont;
michael@0 2075 if (aTarget->GetType() == BackendType::CAIRO || aTarget->GetType() == BackendType::SKIA) {
michael@0 2076 nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
michael@0 2077 nativeFont.mFont = aFont->GetCairoScaledFont();
michael@0 2078 return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize());
michael@0 2079 }
michael@0 2080
michael@0 2081 return nullptr;
michael@0 2082 }

mercurial