Thu, 22 Jan 2015 13:21:57 +0100
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 | } |