Bumping manifests a=b2g-bump
[gecko.git] / gfx / thebes / gfxPlatform.cpp
blob95303c28b1b137bba649ac85dd86161259fe6666
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifdef MOZ_LOGGING
7 #define FORCE_PR_LOG /* Allow logging in the release build */
8 #endif
10 #include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTracker
11 #include "mozilla/layers/CompositorChild.h"
12 #include "mozilla/layers/CompositorParent.h"
13 #include "mozilla/layers/ImageBridgeChild.h"
14 #include "mozilla/layers/SharedBufferManagerChild.h"
15 #include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter
17 #include "prlog.h"
19 #include "gfxPlatform.h"
20 #include "gfxPrefs.h"
22 #ifdef XP_WIN
23 #include <process.h>
24 #define getpid _getpid
25 #else
26 #include <unistd.h>
27 #endif
29 #include "nsXULAppAPI.h"
30 #include "nsDirectoryServiceUtils.h"
31 #include "nsDirectoryServiceDefs.h"
33 #if defined(XP_WIN)
34 #include "gfxWindowsPlatform.h"
35 #include "gfxD2DSurface.h"
36 #elif defined(XP_MACOSX)
37 #include "gfxPlatformMac.h"
38 #include "gfxQuartzSurface.h"
39 #elif defined(MOZ_WIDGET_GTK)
40 #include "gfxPlatformGtk.h"
41 #elif defined(MOZ_WIDGET_QT)
42 #include "gfxQtPlatform.h"
43 #elif defined(ANDROID)
44 #include "gfxAndroidPlatform.h"
45 #endif
47 #include "nsGkAtoms.h"
48 #include "gfxPlatformFontList.h"
49 #include "gfxContext.h"
50 #include "gfxImageSurface.h"
51 #include "nsUnicodeProperties.h"
52 #include "harfbuzz/hb.h"
53 #include "gfxGraphiteShaper.h"
54 #include "gfx2DGlue.h"
55 #include "gfxGradientCache.h"
57 #include "nsUnicodeRange.h"
58 #include "nsServiceManagerUtils.h"
59 #include "nsTArray.h"
60 #include "nsILocaleService.h"
61 #include "nsIObserverService.h"
62 #include "MainThreadUtils.h"
64 #include "nsWeakReference.h"
66 #include "cairo.h"
67 #include "qcms.h"
69 #include "plstr.h"
70 #include "nsCRT.h"
71 #include "GLContext.h"
72 #include "GLContextProvider.h"
74 #ifdef MOZ_WIDGET_ANDROID
75 #include "TexturePoolOGL.h"
76 #endif
78 #include "mozilla/Hal.h"
79 #ifdef USE_SKIA
80 #include "skia/SkGraphics.h"
82 #include "SkiaGLGlue.h"
83 #else
84 class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted {
86 #endif
88 #include "mozilla/Preferences.h"
89 #include "mozilla/Assertions.h"
90 #include "mozilla/Attributes.h"
91 #include "mozilla/Mutex.h"
93 #include "nsIGfxInfo.h"
94 #include "nsIXULRuntime.h"
96 namespace mozilla {
97 namespace layers {
98 #ifdef MOZ_WIDGET_GONK
99 void InitGralloc();
100 #endif
101 void ShutdownTileCache();
105 using namespace mozilla;
106 using namespace mozilla::layers;
108 gfxPlatform *gPlatform = nullptr;
109 static bool gEverInitialized = false;
111 static Mutex* gGfxPlatformPrefsLock = nullptr;
113 // These two may point to the same profile
114 static qcms_profile *gCMSOutputProfile = nullptr;
115 static qcms_profile *gCMSsRGBProfile = nullptr;
117 static qcms_transform *gCMSRGBTransform = nullptr;
118 static qcms_transform *gCMSInverseRGBTransform = nullptr;
119 static qcms_transform *gCMSRGBATransform = nullptr;
121 static bool gCMSInitialized = false;
122 static eCMSMode gCMSMode = eCMSMode_Off;
124 static bool gCMSIntentInitialized = false;
125 static int gCMSIntent = QCMS_INTENT_DEFAULT;
128 static void ShutdownCMS();
130 #include "mozilla/gfx/2D.h"
131 #include "mozilla/gfx/SourceSurfaceCairo.h"
132 using namespace mozilla::gfx;
134 /* Class to listen for pref changes so that chrome code can dynamically
135 force sRGB as an output profile. See Bug #452125. */
136 class SRGBOverrideObserver MOZ_FINAL : public nsIObserver,
137 public nsSupportsWeakReference
139 ~SRGBOverrideObserver() {}
140 public:
141 NS_DECL_ISUPPORTS
142 NS_DECL_NSIOBSERVER
145 NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
147 #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
149 #define GFX_PREF_FALLBACK_USE_CMAPS "gfx.font_rendering.fallback.always_use_cmaps"
151 #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
153 #define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit"
154 #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries"
156 #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
158 #define BIDI_NUMERAL_PREF "bidi.numeral"
160 #define GFX_PREF_CMS_FORCE_SRGB "gfx.color_management.force_srgb"
162 NS_IMETHODIMP
163 SRGBOverrideObserver::Observe(nsISupports *aSubject,
164 const char *aTopic,
165 const char16_t* someData)
167 NS_ASSERTION(NS_strcmp(someData,
168 MOZ_UTF16(GFX_PREF_CMS_FORCE_SRGB)) == 0,
169 "Restarting CMS on wrong pref!");
170 ShutdownCMS();
171 return NS_OK;
174 static const char* kObservedPrefs[] = {
175 "gfx.downloadable_fonts.",
176 "gfx.font_rendering.",
177 BIDI_NUMERAL_PREF,
178 nullptr
181 class FontPrefsObserver MOZ_FINAL : public nsIObserver
183 ~FontPrefsObserver() {}
184 public:
185 NS_DECL_ISUPPORTS
186 NS_DECL_NSIOBSERVER
189 NS_IMPL_ISUPPORTS(FontPrefsObserver, nsIObserver)
191 NS_IMETHODIMP
192 FontPrefsObserver::Observe(nsISupports *aSubject,
193 const char *aTopic,
194 const char16_t *someData)
196 if (!someData) {
197 NS_ERROR("font pref observer code broken");
198 return NS_ERROR_UNEXPECTED;
200 NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone");
201 gfxPlatform::GetPlatform()->FontsPrefsChanged(NS_ConvertUTF16toUTF8(someData).get());
203 return NS_OK;
206 class MemoryPressureObserver MOZ_FINAL : public nsIObserver
208 ~MemoryPressureObserver() {}
209 public:
210 NS_DECL_ISUPPORTS
211 NS_DECL_NSIOBSERVER
214 NS_IMPL_ISUPPORTS(MemoryPressureObserver, nsIObserver)
216 NS_IMETHODIMP
217 MemoryPressureObserver::Observe(nsISupports *aSubject,
218 const char *aTopic,
219 const char16_t *someData)
221 NS_ASSERTION(strcmp(aTopic, "memory-pressure") == 0, "unexpected event topic");
222 Factory::PurgeAllCaches();
223 gfxGradientCache::PurgeAllCaches();
225 gfxPlatform::GetPlatform()->PurgeSkiaCache();
226 return NS_OK;
229 // this needs to match the list of pref font.default.xx entries listed in all.js!
230 // the order *must* match the order in eFontPrefLang
231 static const char *gPrefLangNames[] = {
232 "x-western",
233 "ja",
234 "zh-TW",
235 "zh-CN",
236 "zh-HK",
237 "ko",
238 "x-cyrillic",
239 "el",
240 "th",
241 "he",
242 "ar",
243 "x-devanagari",
244 "x-tamil",
245 "x-armn",
246 "x-beng",
247 "x-cans",
248 "x-ethi",
249 "x-geor",
250 "x-gujr",
251 "x-guru",
252 "x-khmr",
253 "x-mlym",
254 "x-orya",
255 "x-telu",
256 "x-knda",
257 "x-sinh",
258 "x-tibt",
259 "x-unicode",
262 gfxPlatform::gfxPlatform()
263 : mAzureCanvasBackendCollector(MOZ_THIS_IN_INITIALIZER_LIST(),
264 &gfxPlatform::GetAzureBackendInfo)
266 mAllowDownloadableFonts = UNINITIALIZED_VALUE;
267 mFallbackUsesCmaps = UNINITIALIZED_VALUE;
269 mWordCacheCharLimit = UNINITIALIZED_VALUE;
270 mWordCacheMaxEntries = UNINITIALIZED_VALUE;
271 mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
272 mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
273 mBidiNumeralOption = UNINITIALIZED_VALUE;
275 mSkiaGlue = nullptr;
277 uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
278 uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
279 InitBackendPrefs(canvasMask, BackendType::CAIRO,
280 contentMask, BackendType::CAIRO);
281 mTotalSystemMemory = mozilla::hal::GetTotalSystemMemory();
284 gfxPlatform*
285 gfxPlatform::GetPlatform()
287 if (!gPlatform) {
288 Init();
290 return gPlatform;
293 void RecordingPrefChanged(const char *aPrefName, void *aClosure)
295 if (Preferences::GetBool("gfx.2d.recording", false)) {
296 nsAutoCString fileName;
297 nsAdoptingString prefFileName = Preferences::GetString("gfx.2d.recordingfile");
299 if (prefFileName) {
300 fileName.Append(NS_ConvertUTF16toUTF8(prefFileName));
301 } else {
302 nsCOMPtr<nsIFile> tmpFile;
303 if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile)))) {
304 return;
306 fileName.AppendPrintf("moz2drec_%i_%i.aer", XRE_GetProcessType(), getpid());
308 nsresult rv = tmpFile->AppendNative(fileName);
309 if (NS_FAILED(rv))
310 return;
312 rv = tmpFile->GetNativePath(fileName);
313 if (NS_FAILED(rv))
314 return;
317 gPlatform->mRecorder = Factory::CreateEventRecorderForFile(fileName.BeginReading());
318 printf_stderr("Recording to %s\n", fileName.get());
319 Factory::SetGlobalEventRecorder(gPlatform->mRecorder);
320 } else {
321 Factory::SetGlobalEventRecorder(nullptr);
325 void
326 gfxPlatform::Init()
328 if (gEverInitialized) {
329 NS_RUNTIMEABORT("Already started???");
331 gEverInitialized = true;
333 // Initialize the preferences by creating the singleton.
334 gfxPrefs::GetSingleton();
336 gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock");
338 /* Initialize the GfxInfo service.
339 * Note: we can't call functions on GfxInfo that depend
340 * on gPlatform until after it has been initialized
341 * below. GfxInfo initialization annotates our
342 * crash reports so we want to do it before
343 * we try to load any drivers and do device detection
344 * incase that code crashes. See bug #591561. */
345 nsCOMPtr<nsIGfxInfo> gfxInfo;
346 /* this currently will only succeed on Windows */
347 gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
349 #if defined(XP_WIN)
350 gPlatform = new gfxWindowsPlatform;
351 #elif defined(XP_MACOSX)
352 gPlatform = new gfxPlatformMac;
353 #elif defined(MOZ_WIDGET_GTK)
354 gPlatform = new gfxPlatformGtk;
355 #elif defined(MOZ_WIDGET_QT)
356 gPlatform = new gfxQtPlatform;
357 #elif defined(ANDROID)
358 gPlatform = new gfxAndroidPlatform;
359 #else
360 #error "No gfxPlatform implementation available"
361 #endif
363 #ifdef DEBUG
364 mozilla::gl::GLContext::StaticInit();
365 #endif
367 InitLayersIPC();
369 nsresult rv;
371 #if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID) // temporary, until this is implemented on others
372 rv = gfxPlatformFontList::Init();
373 if (NS_FAILED(rv)) {
374 NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList");
376 #endif
378 gPlatform->mScreenReferenceSurface =
379 gPlatform->CreateOffscreenSurface(IntSize(1, 1),
380 gfxContentType::COLOR_ALPHA);
381 if (!gPlatform->mScreenReferenceSurface) {
382 NS_RUNTIMEABORT("Could not initialize mScreenReferenceSurface");
385 gPlatform->mScreenReferenceDrawTarget =
386 gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1),
387 SurfaceFormat::B8G8R8A8);
388 if (!gPlatform->mScreenReferenceDrawTarget) {
389 NS_RUNTIMEABORT("Could not initialize mScreenReferenceDrawTarget");
392 rv = gfxFontCache::Init();
393 if (NS_FAILED(rv)) {
394 NS_RUNTIMEABORT("Could not initialize gfxFontCache");
397 /* Create and register our CMS Override observer. */
398 gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
399 Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
401 gPlatform->mFontPrefsObserver = new FontPrefsObserver();
402 Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
404 mozilla::gl::GLContext::PlatformStartup();
406 #ifdef MOZ_WIDGET_ANDROID
407 // Texture pool init
408 mozilla::gl::TexturePoolOGL::Init();
409 #endif
411 #ifdef MOZ_WIDGET_GONK
412 mozilla::layers::InitGralloc();
413 #endif
415 Preferences::RegisterCallbackAndCall(RecordingPrefChanged, "gfx.2d.recording", nullptr);
417 CreateCMSOutputProfile();
419 // Listen to memory pressure event so we can purge DrawTarget caches
420 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
421 if (obs) {
422 gPlatform->mMemoryPressureObserver = new MemoryPressureObserver();
423 obs->AddObserver(gPlatform->mMemoryPressureObserver, "memory-pressure", false);
426 RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
429 static bool sLayersIPCIsUp = false;
431 void
432 gfxPlatform::Shutdown()
434 if (!gPlatform) {
435 return;
438 MOZ_ASSERT(!sLayersIPCIsUp);
440 // These may be called before the corresponding subsystems have actually
441 // started up. That's OK, they can handle it.
442 gfxFontCache::Shutdown();
443 gfxFontGroup::Shutdown();
444 gfxGradientCache::Shutdown();
445 gfxAlphaBoxBlur::ShutdownBlurCache();
446 gfxGraphiteShaper::Shutdown();
447 gfxPlatformFontList::Shutdown();
448 ShutdownTileCache();
450 // Free the various non-null transforms and loaded profiles
451 ShutdownCMS();
453 // In some cases, gPlatform may not be created but Shutdown() called,
454 // e.g., during xpcshell tests.
455 if (gPlatform) {
456 /* Unregister our CMS Override callback. */
457 NS_ASSERTION(gPlatform->mSRGBOverrideObserver, "mSRGBOverrideObserver has alreay gone");
458 Preferences::RemoveObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
459 gPlatform->mSRGBOverrideObserver = nullptr;
461 NS_ASSERTION(gPlatform->mFontPrefsObserver, "mFontPrefsObserver has alreay gone");
462 Preferences::RemoveObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
463 gPlatform->mFontPrefsObserver = nullptr;
465 NS_ASSERTION(gPlatform->mMemoryPressureObserver, "mMemoryPressureObserver has already gone");
466 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
467 if (obs) {
468 obs->RemoveObserver(gPlatform->mMemoryPressureObserver, "memory-pressure");
471 gPlatform->mMemoryPressureObserver = nullptr;
472 gPlatform->mSkiaGlue = nullptr;
475 #ifdef MOZ_WIDGET_ANDROID
476 // Shut down the texture pool
477 mozilla::gl::TexturePoolOGL::Shutdown();
478 #endif
480 // Shut down the default GL context provider.
481 mozilla::gl::GLContextProvider::Shutdown();
483 #if defined(XP_WIN)
484 // The above shutdown calls operate on the available context providers on
485 // most platforms. Windows is a "special snowflake", though, and has three
486 // context providers available, so we have to shut all of them down.
487 // We should only support the default GL provider on Windows; then, this
488 // could go away. Unfortunately, we currently support WGL (the default) for
489 // WebGL on Optimus.
490 mozilla::gl::GLContextProviderEGL::Shutdown();
491 #endif
493 delete gGfxPlatformPrefsLock;
495 gfxPrefs::DestroySingleton();
496 gfxFont::DestroySingletons();
498 delete gPlatform;
499 gPlatform = nullptr;
502 /* static */ void
503 gfxPlatform::InitLayersIPC()
505 if (sLayersIPCIsUp) {
506 return;
508 sLayersIPCIsUp = true;
510 AsyncTransactionTrackersHolder::Initialize();
512 if (XRE_GetProcessType() == GeckoProcessType_Default)
514 mozilla::layers::CompositorParent::StartUp();
515 #ifndef MOZ_WIDGET_GONK
516 if (gfxPrefs::AsyncVideoEnabled()) {
517 mozilla::layers::ImageBridgeChild::StartUp();
519 #else
520 mozilla::layers::ImageBridgeChild::StartUp();
521 SharedBufferManagerChild::StartUp();
522 #endif
526 /* static */ void
527 gfxPlatform::ShutdownLayersIPC()
529 if (!sLayersIPCIsUp) {
530 return;
532 sLayersIPCIsUp = false;
534 if (XRE_GetProcessType() == GeckoProcessType_Default)
536 // This must happen after the shutdown of media and widgets, which
537 // are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification.
538 layers::ImageBridgeChild::ShutDown();
539 #ifdef MOZ_WIDGET_GONK
540 layers::SharedBufferManagerChild::ShutDown();
541 #endif
543 layers::CompositorParent::ShutDown();
547 gfxPlatform::~gfxPlatform()
549 mScreenReferenceSurface = nullptr;
550 mScreenReferenceDrawTarget = nullptr;
552 // The cairo folks think we should only clean up in debug builds,
553 // but we're generally in the habit of trying to shut down as
554 // cleanly as possible even in production code, so call this
555 // cairo_debug_* function unconditionally.
557 // because cairo can assert and thus crash on shutdown, don't do this in release builds
558 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) || defined(NS_TRACE_MALLOC) || defined(MOZ_VALGRIND)
559 #ifdef USE_SKIA
560 // must do Skia cleanup before Cairo cleanup, because Skia may be referencing
561 // Cairo objects e.g. through SkCairoFTTypeface
562 SkGraphics::Term();
563 #endif
565 #if MOZ_TREE_CAIRO
566 cairo_debug_reset_static_data();
567 #endif
568 #endif
571 cairo_user_data_key_t kDrawTarget;
573 TemporaryRef<DrawTarget>
574 gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface, const IntSize& aSize)
576 SurfaceFormat format = Optimal2DFormatForContent(aSurface->GetContentType());
577 RefPtr<DrawTarget> drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(), aSize, &format);
578 aSurface->SetData(&kDrawTarget, drawTarget, nullptr);
579 return drawTarget.forget();
582 // This is a temporary function used by ContentClient to build a DrawTarget
583 // around the gfxASurface. This should eventually be replaced by plumbing
584 // the DrawTarget through directly
585 TemporaryRef<DrawTarget>
586 gfxPlatform::CreateDrawTargetForUpdateSurface(gfxASurface *aSurface, const IntSize& aSize)
588 #ifdef XP_MACOSX
589 // this is a bit of a hack that assumes that the buffer associated with the CGContext
590 // will live around long enough that nothing bad will happen.
591 if (aSurface->GetType() == gfxSurfaceType::Quartz) {
592 return Factory::CreateDrawTargetForCairoCGContext(static_cast<gfxQuartzSurface*>(aSurface)->GetCGContext(), aSize);
594 #endif
595 MOZ_CRASH();
596 return nullptr;
600 cairo_user_data_key_t kSourceSurface;
603 * Record the backend that was used to construct the SourceSurface.
604 * When getting the cached SourceSurface for a gfxASurface/DrawTarget pair,
605 * we check to make sure the DrawTarget's backend matches the backend
606 * for the cached SourceSurface, and only use it if they match. This
607 * can avoid expensive and unnecessary readbacks.
609 struct SourceSurfaceUserData
611 RefPtr<SourceSurface> mSrcSurface;
612 BackendType mBackendType;
615 void SourceBufferDestroy(void *srcSurfUD)
617 delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
620 UserDataKey kThebesSurface;
622 struct DependentSourceSurfaceUserData
624 nsRefPtr<gfxASurface> mSurface;
627 void SourceSurfaceDestroyed(void *aData)
629 delete static_cast<DependentSourceSurfaceUserData*>(aData);
632 void
633 gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
635 aSurface->SetData(&kSourceSurface, nullptr, nullptr);
638 /* static */ TemporaryRef<SourceSurface>
639 gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface)
641 if (!aSurface->CairoSurface() || aSurface->CairoStatus()) {
642 return nullptr;
645 if (!aTarget) {
646 aTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
647 if (!aTarget) {
648 return nullptr;
652 void *userData = aSurface->GetData(&kSourceSurface);
654 if (userData) {
655 SourceSurfaceUserData *surf = static_cast<SourceSurfaceUserData*>(userData);
657 if (surf->mSrcSurface->IsValid() && surf->mBackendType == aTarget->GetBackendType()) {
658 return surf->mSrcSurface;
660 // We can just continue here as when setting new user data the destroy
661 // function will be called for the old user data.
664 SurfaceFormat format;
665 if (aSurface->GetContentType() == gfxContentType::ALPHA) {
666 format = SurfaceFormat::A8;
667 } else if (aSurface->GetContentType() == gfxContentType::COLOR) {
668 format = SurfaceFormat::B8G8R8X8;
669 } else {
670 format = SurfaceFormat::B8G8R8A8;
673 if (aTarget->GetBackendType() == BackendType::CAIRO) {
674 // If we're going to be used with a CAIRO DrawTarget, then just create a
675 // SourceSurfaceCairo since we don't know the underlying type of the CAIRO
676 // DrawTarget and can't pick a better surface type. Doing this also avoids
677 // readback of aSurface's surface into memory if, for example, aSurface
678 // wraps an xlib cairo surface (which can be important to avoid a major
679 // slowdown).
680 NativeSurface surf;
681 surf.mFormat = format;
682 surf.mType = NativeSurfaceType::CAIRO_SURFACE;
683 surf.mSurface = aSurface->CairoSurface();
684 surf.mSize = ToIntSize(aSurface->GetSize());
685 // We return here regardless of whether CreateSourceSurfaceFromNativeSurface
686 // succeeds or not since we don't expect to be able to do any better below
687 // if it fails.
689 // Note that the returned SourceSurfaceCairo holds a strong reference to
690 // the cairo_surface_t* that it wraps, which essencially means it holds a
691 // strong reference to aSurface since aSurface shares its
692 // cairo_surface_t*'s reference count variable. As a result we can't cache
693 // srcBuffer on aSurface (see below) since aSurface would then hold a
694 // strong reference back to srcBuffer, creating a reference loop and a
695 // memory leak. Not caching is fine since wrapping is cheap enough (no
696 // copying) so we can just wrap again next time we're called.
697 return aTarget->CreateSourceSurfaceFromNativeSurface(surf);
700 RefPtr<SourceSurface> srcBuffer;
702 #ifdef XP_WIN
703 if (aSurface->GetType() == gfxSurfaceType::D2D &&
704 format != SurfaceFormat::A8) {
705 NativeSurface surf;
706 surf.mFormat = format;
707 surf.mType = NativeSurfaceType::D3D10_TEXTURE;
708 surf.mSurface = static_cast<gfxD2DSurface*>(aSurface)->GetTexture();
709 surf.mSize = ToIntSize(aSurface->GetSize());
710 mozilla::gfx::DrawTarget *dt = static_cast<mozilla::gfx::DrawTarget*>(aSurface->GetData(&kDrawTarget));
711 if (dt) {
712 dt->Flush();
714 srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
716 #endif
717 // Currently no other DrawTarget types implement CreateSourceSurfaceFromNativeSurface
719 if (!srcBuffer) {
720 // If aSurface wraps data, we can create a SourceSurfaceRawData that wraps
721 // the same data, then optimize it for aTarget:
722 RefPtr<DataSourceSurface> surf = GetWrappedDataSourceSurface(aSurface);
723 if (surf) {
724 srcBuffer = aTarget->OptimizeSourceSurface(surf);
725 if (srcBuffer == surf) {
726 // GetWrappedDataSourceSurface returns a SourceSurface that holds a
727 // strong reference to aSurface since it wraps aSurface's data and
728 // needs it to stay alive. As a result we can't cache srcBuffer on
729 // aSurface (below) since aSurface would then hold a strong reference
730 // back to srcBuffer, creating a reference loop and a memory leak. Not
731 // caching is fine since wrapping is cheap enough (no copying) so we
732 // can just wrap again next time we're called.
734 // Note that the check below doesn't catch this since srcBuffer will be a
735 // SourceSurfaceRawData object (even if aSurface is not a gfxImageSurface
736 // object), which is why we need this separate check.
737 return srcBuffer.forget();
742 if (!srcBuffer) {
743 MOZ_ASSERT(aTarget->GetBackendType() != BackendType::CAIRO,
744 "We already tried CreateSourceSurfaceFromNativeSurface with a "
745 "DrawTargetCairo above");
746 // We've run out of performant options. We now try creating a SourceSurface
747 // using a temporary DrawTargetCairo and then optimizing it to aTarget's
748 // actual type. The CreateSourceSurfaceFromNativeSurface() call will
749 // likely create a DataSourceSurface (possibly involving copying and/or
750 // readback), and the OptimizeSourceSurface may well copy again and upload
751 // to the GPU. So, while this code path is rarely hit, hitting it may be
752 // very slow.
753 NativeSurface surf;
754 surf.mFormat = format;
755 surf.mType = NativeSurfaceType::CAIRO_SURFACE;
756 surf.mSurface = aSurface->CairoSurface();
757 surf.mSize = ToIntSize(aSurface->GetSize());
758 RefPtr<DrawTarget> drawTarget =
759 Factory::CreateDrawTarget(BackendType::CAIRO, IntSize(1, 1), format);
760 srcBuffer = drawTarget->CreateSourceSurfaceFromNativeSurface(surf);
761 if (srcBuffer) {
762 srcBuffer = aTarget->OptimizeSourceSurface(srcBuffer);
766 if (!srcBuffer) {
767 return nullptr;
770 if ((srcBuffer->GetType() == SurfaceType::CAIRO &&
771 static_cast<SourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
772 aSurface->CairoSurface()) ||
773 (srcBuffer->GetType() == SurfaceType::CAIRO_IMAGE &&
774 static_cast<DataSourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
775 aSurface->CairoSurface())) {
776 // See the "Note that the returned SourceSurfaceCairo..." comment above.
777 return srcBuffer.forget();
780 // Add user data to aSurface so we can cache lookups in the future.
781 SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
782 srcSurfUD->mBackendType = aTarget->GetBackendType();
783 srcSurfUD->mSrcSurface = srcBuffer;
784 aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
786 return srcBuffer.forget();
789 TemporaryRef<DataSourceSurface>
790 gfxPlatform::GetWrappedDataSourceSurface(gfxASurface* aSurface)
792 nsRefPtr<gfxImageSurface> image = aSurface->GetAsImageSurface();
793 if (!image) {
794 return nullptr;
796 RefPtr<DataSourceSurface> result =
797 Factory::CreateWrappingDataSourceSurface(image->Data(),
798 image->Stride(),
799 ToIntSize(image->GetSize()),
800 ImageFormatToSurfaceFormat(image->Format()));
802 if (!result) {
803 return nullptr;
806 // If we wrapped the underlying data of aSurface, then we need to add user data
807 // to make sure aSurface stays alive until we are done with the data.
808 DependentSourceSurfaceUserData *srcSurfUD = new DependentSourceSurfaceUserData;
809 srcSurfUD->mSurface = aSurface;
810 result->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
812 return result.forget();
815 TemporaryRef<ScaledFont>
816 gfxPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
818 NativeFont nativeFont;
819 nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
820 nativeFont.mFont = aFont->GetCairoScaledFont();
821 RefPtr<ScaledFont> scaledFont =
822 Factory::CreateScaledFontForNativeFont(nativeFont,
823 aFont->GetAdjustedSize());
824 return scaledFont;
827 bool
828 gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget)
830 if (!aTarget) {
831 return false;
834 return SupportsAzureContentForType(aTarget->GetBackendType());
837 bool
838 gfxPlatform::UseAcceleratedSkiaCanvas()
840 return gfxPrefs::CanvasAzureAccelerated() &&
841 mPreferredCanvasBackend == BackendType::SKIA;
844 void
845 gfxPlatform::InitializeSkiaCacheLimits()
847 if (UseAcceleratedSkiaCanvas()) {
848 bool usingDynamicCache = gfxPrefs::CanvasSkiaGLDynamicCache();
849 int cacheItemLimit = gfxPrefs::CanvasSkiaGLCacheItems();
850 int cacheSizeLimit = gfxPrefs::CanvasSkiaGLCacheSize();
852 // Prefs are in megabytes, but we want the sizes in bytes
853 cacheSizeLimit *= 1024*1024;
855 if (usingDynamicCache) {
856 if (mTotalSystemMemory < 512*1024*1024) {
857 // We need a very minimal cache on anything smaller than 512mb.
858 // Note the large jump as we cross 512mb (from 2mb to 32mb).
859 cacheSizeLimit = 2*1024*1024;
860 } else if (mTotalSystemMemory > 0) {
861 cacheSizeLimit = mTotalSystemMemory / 16;
865 #ifdef DEBUG
866 printf_stderr("Determined SkiaGL cache limits: Size %i, Items: %i\n", cacheSizeLimit, cacheItemLimit);
867 #endif
869 #ifdef USE_SKIA_GPU
870 mSkiaGlue->GetGrContext()->setResourceCacheLimits(cacheItemLimit, cacheSizeLimit);
871 #endif
875 mozilla::gl::SkiaGLGlue*
876 gfxPlatform::GetSkiaGLGlue()
878 #ifdef USE_SKIA_GPU
879 if (!mSkiaGlue) {
880 /* Dummy context. We always draw into a FBO.
882 * FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it
883 * stands, this only works on the main thread.
885 mozilla::gl::SurfaceCaps caps = mozilla::gl::SurfaceCaps::ForRGBA();
886 nsRefPtr<mozilla::gl::GLContext> glContext = mozilla::gl::GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), caps);
887 if (!glContext) {
888 printf_stderr("Failed to create GLContext for SkiaGL!\n");
889 return nullptr;
891 mSkiaGlue = new mozilla::gl::SkiaGLGlue(glContext);
892 MOZ_ASSERT(mSkiaGlue->GetGrContext(), "No GrContext");
893 InitializeSkiaCacheLimits();
895 #endif
897 return mSkiaGlue;
900 void
901 gfxPlatform::PurgeSkiaCache()
903 #ifdef USE_SKIA_GPU
904 if (!mSkiaGlue)
905 return;
907 mSkiaGlue->GetGrContext()->freeGpuResources();
908 // GrContext::flush() doesn't call glFlush. Call it here.
909 mSkiaGlue->GetGLContext()->MakeCurrent();
910 mSkiaGlue->GetGLContext()->fFlush();
911 #endif
914 bool
915 gfxPlatform::HasEnoughTotalSystemMemoryForSkiaGL()
917 #ifdef MOZ_WIDGET_GONK
918 if (mTotalSystemMemory < 250*1024*1024) {
919 return false;
921 #endif
922 return true;
925 TemporaryRef<DrawTarget>
926 gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat)
928 // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
929 // create the best offscreen surface for the current system and situation. We
930 // can easily take advantage of this for the Cairo backend, so that's what we
931 // do.
932 // mozilla::gfx::Factory can get away without having all this knowledge for
933 // now, but this might need to change in the future (using
934 // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all
935 // backends).
936 if (aBackend == BackendType::CAIRO) {
937 nsRefPtr<gfxASurface> surf = CreateOffscreenSurface(aSize,
938 ContentForFormat(aFormat));
939 if (!surf || surf->CairoStatus()) {
940 return nullptr;
943 return CreateDrawTargetForSurface(surf, aSize);
944 } else {
945 return Factory::CreateDrawTarget(aBackend, aSize, aFormat);
949 TemporaryRef<DrawTarget>
950 gfxPlatform::CreateOffscreenCanvasDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
952 NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
953 RefPtr<DrawTarget> target = CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat);
954 if (target ||
955 mFallbackCanvasBackend == BackendType::NONE) {
956 return target.forget();
959 return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat);
962 TemporaryRef<DrawTarget>
963 gfxPlatform::CreateOffscreenContentDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
965 NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
966 return CreateDrawTargetForBackend(mContentBackend, aSize, aFormat);
969 TemporaryRef<DrawTarget>
970 gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat)
972 NS_ASSERTION(mContentBackend != BackendType::NONE, "No backend.");
974 RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(mContentBackend,
975 aData, aSize,
976 aStride, aFormat);
977 if (!dt) {
978 // Factory::CreateDrawTargetForData does not support mContentBackend; retry
979 // with BackendType::CAIRO:
980 dt = Factory::CreateDrawTargetForData(BackendType::CAIRO,
981 aData, aSize,
982 aStride, aFormat);
984 return dt.forget();
987 /* static */ BackendType
988 gfxPlatform::BackendTypeForName(const nsCString& aName)
990 if (aName.EqualsLiteral("cairo"))
991 return BackendType::CAIRO;
992 if (aName.EqualsLiteral("skia"))
993 return BackendType::SKIA;
994 if (aName.EqualsLiteral("direct2d"))
995 return BackendType::DIRECT2D;
996 if (aName.EqualsLiteral("cg"))
997 return BackendType::COREGRAPHICS;
998 return BackendType::NONE;
1001 nsresult
1002 gfxPlatform::GetFontList(nsIAtom *aLangGroup,
1003 const nsACString& aGenericFamily,
1004 nsTArray<nsString>& aListOfFonts)
1006 return NS_ERROR_NOT_IMPLEMENTED;
1009 nsresult
1010 gfxPlatform::UpdateFontList()
1012 return NS_ERROR_NOT_IMPLEMENTED;
1015 bool
1016 gfxPlatform::DownloadableFontsEnabled()
1018 if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
1019 mAllowDownloadableFonts =
1020 Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false);
1023 return mAllowDownloadableFonts;
1026 bool
1027 gfxPlatform::UseCmapsDuringSystemFallback()
1029 if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) {
1030 mFallbackUsesCmaps =
1031 Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false);
1034 return mFallbackUsesCmaps;
1037 bool
1038 gfxPlatform::OpenTypeSVGEnabled()
1040 if (mOpenTypeSVGEnabled == UNINITIALIZED_VALUE) {
1041 mOpenTypeSVGEnabled =
1042 Preferences::GetBool(GFX_PREF_OPENTYPE_SVG, false);
1045 return mOpenTypeSVGEnabled > 0;
1048 uint32_t
1049 gfxPlatform::WordCacheCharLimit()
1051 if (mWordCacheCharLimit == UNINITIALIZED_VALUE) {
1052 mWordCacheCharLimit =
1053 Preferences::GetInt(GFX_PREF_WORD_CACHE_CHARLIMIT, 32);
1054 if (mWordCacheCharLimit < 0) {
1055 mWordCacheCharLimit = 32;
1059 return uint32_t(mWordCacheCharLimit);
1062 uint32_t
1063 gfxPlatform::WordCacheMaxEntries()
1065 if (mWordCacheMaxEntries == UNINITIALIZED_VALUE) {
1066 mWordCacheMaxEntries =
1067 Preferences::GetInt(GFX_PREF_WORD_CACHE_MAXENTRIES, 10000);
1068 if (mWordCacheMaxEntries < 0) {
1069 mWordCacheMaxEntries = 10000;
1073 return uint32_t(mWordCacheMaxEntries);
1076 bool
1077 gfxPlatform::UseGraphiteShaping()
1079 if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) {
1080 mGraphiteShapingEnabled =
1081 Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
1084 return mGraphiteShapingEnabled;
1087 gfxFontEntry*
1088 gfxPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
1089 const uint8_t *aFontData,
1090 uint32_t aLength)
1092 // Default implementation does not handle activating downloaded fonts;
1093 // just free the data and return.
1094 // Platforms that support @font-face must override this,
1095 // using the data to instantiate the font, and taking responsibility
1096 // for freeing it when no longer required.
1097 if (aFontData) {
1098 NS_Free((void*)aFontData);
1100 return nullptr;
1103 static void
1104 AppendGenericFontFromPref(nsString& aFonts, nsIAtom *aLangGroup, const char *aGenericName)
1106 NS_ENSURE_TRUE_VOID(Preferences::GetRootBranch());
1108 nsAutoCString prefName, langGroupString;
1110 aLangGroup->ToUTF8String(langGroupString);
1112 nsAutoCString genericDotLang;
1113 if (aGenericName) {
1114 genericDotLang.Assign(aGenericName);
1115 } else {
1116 prefName.AssignLiteral("font.default.");
1117 prefName.Append(langGroupString);
1118 genericDotLang = Preferences::GetCString(prefName.get());
1121 genericDotLang.Append('.');
1122 genericDotLang.Append(langGroupString);
1124 // fetch font.name.xxx value
1125 prefName.AssignLiteral("font.name.");
1126 prefName.Append(genericDotLang);
1127 nsAdoptingString nameValue = Preferences::GetString(prefName.get());
1128 if (nameValue) {
1129 if (!aFonts.IsEmpty())
1130 aFonts.AppendLiteral(", ");
1131 aFonts += nameValue;
1134 // fetch font.name-list.xxx value
1135 prefName.AssignLiteral("font.name-list.");
1136 prefName.Append(genericDotLang);
1137 nsAdoptingString nameListValue = Preferences::GetString(prefName.get());
1138 if (nameListValue && !nameListValue.Equals(nameValue)) {
1139 if (!aFonts.IsEmpty())
1140 aFonts.AppendLiteral(", ");
1141 aFonts += nameListValue;
1145 void
1146 gfxPlatform::GetPrefFonts(nsIAtom *aLanguage, nsString& aFonts, bool aAppendUnicode)
1148 aFonts.Truncate();
1150 AppendGenericFontFromPref(aFonts, aLanguage, nullptr);
1151 if (aAppendUnicode)
1152 AppendGenericFontFromPref(aFonts, nsGkAtoms::Unicode, nullptr);
1155 bool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], uint32_t aLangArrayLen, PrefFontCallback aCallback,
1156 void *aClosure)
1158 NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
1160 uint32_t i;
1161 for (i = 0; i < aLangArrayLen; i++) {
1162 eFontPrefLang prefLang = aLangArray[i];
1163 const char *langGroup = GetPrefLangName(prefLang);
1165 nsAutoCString prefName;
1167 prefName.AssignLiteral("font.default.");
1168 prefName.Append(langGroup);
1169 nsAdoptingCString genericDotLang = Preferences::GetCString(prefName.get());
1171 genericDotLang.Append('.');
1172 genericDotLang.Append(langGroup);
1174 // fetch font.name.xxx value
1175 prefName.AssignLiteral("font.name.");
1176 prefName.Append(genericDotLang);
1177 nsAdoptingCString nameValue = Preferences::GetCString(prefName.get());
1178 if (nameValue) {
1179 if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(nameValue), aClosure))
1180 return false;
1183 // fetch font.name-list.xxx value
1184 prefName.AssignLiteral("font.name-list.");
1185 prefName.Append(genericDotLang);
1186 nsAdoptingCString nameListValue = Preferences::GetCString(prefName.get());
1187 if (nameListValue && !nameListValue.Equals(nameValue)) {
1188 const char kComma = ',';
1189 const char *p, *p_end;
1190 nsAutoCString list(nameListValue);
1191 list.BeginReading(p);
1192 list.EndReading(p_end);
1193 while (p < p_end) {
1194 while (nsCRT::IsAsciiSpace(*p)) {
1195 if (++p == p_end)
1196 break;
1198 if (p == p_end)
1199 break;
1200 const char *start = p;
1201 while (++p != p_end && *p != kComma)
1202 /* nothing */ ;
1203 nsAutoCString fontName(Substring(start, p));
1204 fontName.CompressWhitespace(false, true);
1205 if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(fontName), aClosure))
1206 return false;
1207 p++;
1212 return true;
1215 eFontPrefLang
1216 gfxPlatform::GetFontPrefLangFor(const char* aLang)
1218 if (!aLang || !aLang[0]) {
1219 return eFontPrefLang_Others;
1221 for (uint32_t i = 0; i < ArrayLength(gPrefLangNames); ++i) {
1222 if (!PL_strcasecmp(gPrefLangNames[i], aLang)) {
1223 return eFontPrefLang(i);
1226 return eFontPrefLang_Others;
1229 eFontPrefLang
1230 gfxPlatform::GetFontPrefLangFor(nsIAtom *aLang)
1232 if (!aLang)
1233 return eFontPrefLang_Others;
1234 nsAutoCString lang;
1235 aLang->ToUTF8String(lang);
1236 return GetFontPrefLangFor(lang.get());
1239 const char*
1240 gfxPlatform::GetPrefLangName(eFontPrefLang aLang)
1242 if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) {
1243 return gPrefLangNames[uint32_t(aLang)];
1245 return nullptr;
1248 eFontPrefLang
1249 gfxPlatform::GetFontPrefLangFor(uint8_t aUnicodeRange)
1251 switch (aUnicodeRange) {
1252 case kRangeSetLatin: return eFontPrefLang_Western;
1253 case kRangeCyrillic: return eFontPrefLang_Cyrillic;
1254 case kRangeGreek: return eFontPrefLang_Greek;
1255 case kRangeHebrew: return eFontPrefLang_Hebrew;
1256 case kRangeArabic: return eFontPrefLang_Arabic;
1257 case kRangeThai: return eFontPrefLang_Thai;
1258 case kRangeKorean: return eFontPrefLang_Korean;
1259 case kRangeJapanese: return eFontPrefLang_Japanese;
1260 case kRangeSChinese: return eFontPrefLang_ChineseCN;
1261 case kRangeTChinese: return eFontPrefLang_ChineseTW;
1262 case kRangeDevanagari: return eFontPrefLang_Devanagari;
1263 case kRangeTamil: return eFontPrefLang_Tamil;
1264 case kRangeArmenian: return eFontPrefLang_Armenian;
1265 case kRangeBengali: return eFontPrefLang_Bengali;
1266 case kRangeCanadian: return eFontPrefLang_Canadian;
1267 case kRangeEthiopic: return eFontPrefLang_Ethiopic;
1268 case kRangeGeorgian: return eFontPrefLang_Georgian;
1269 case kRangeGujarati: return eFontPrefLang_Gujarati;
1270 case kRangeGurmukhi: return eFontPrefLang_Gurmukhi;
1271 case kRangeKhmer: return eFontPrefLang_Khmer;
1272 case kRangeMalayalam: return eFontPrefLang_Malayalam;
1273 case kRangeOriya: return eFontPrefLang_Oriya;
1274 case kRangeTelugu: return eFontPrefLang_Telugu;
1275 case kRangeKannada: return eFontPrefLang_Kannada;
1276 case kRangeSinhala: return eFontPrefLang_Sinhala;
1277 case kRangeTibetan: return eFontPrefLang_Tibetan;
1278 case kRangeSetCJK: return eFontPrefLang_CJKSet;
1279 default: return eFontPrefLang_Others;
1283 bool
1284 gfxPlatform::IsLangCJK(eFontPrefLang aLang)
1286 switch (aLang) {
1287 case eFontPrefLang_Japanese:
1288 case eFontPrefLang_ChineseTW:
1289 case eFontPrefLang_ChineseCN:
1290 case eFontPrefLang_ChineseHK:
1291 case eFontPrefLang_Korean:
1292 case eFontPrefLang_CJKSet:
1293 return true;
1294 default:
1295 return false;
1299 mozilla::layers::DiagnosticTypes
1300 gfxPlatform::GetLayerDiagnosticTypes()
1302 mozilla::layers::DiagnosticTypes type = DiagnosticTypes::NO_DIAGNOSTIC;
1303 if (gfxPrefs::DrawLayerBorders()) {
1304 type |= mozilla::layers::DiagnosticTypes::LAYER_BORDERS;
1306 if (gfxPrefs::DrawTileBorders()) {
1307 type |= mozilla::layers::DiagnosticTypes::TILE_BORDERS;
1309 if (gfxPrefs::DrawBigImageBorders()) {
1310 type |= mozilla::layers::DiagnosticTypes::BIGIMAGE_BORDERS;
1312 if (gfxPrefs::FlashLayerBorders()) {
1313 type |= mozilla::layers::DiagnosticTypes::FLASH_BORDERS;
1315 return type;
1318 void
1319 gfxPlatform::GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
1321 if (IsLangCJK(aCharLang)) {
1322 AppendCJKPrefLangs(aPrefLangs, aLen, aCharLang, aPageLang);
1323 } else {
1324 AppendPrefLang(aPrefLangs, aLen, aCharLang);
1327 AppendPrefLang(aPrefLangs, aLen, eFontPrefLang_Others);
1330 void
1331 gfxPlatform::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
1333 // prefer the lang specified by the page *if* CJK
1334 if (IsLangCJK(aPageLang)) {
1335 AppendPrefLang(aPrefLangs, aLen, aPageLang);
1338 // if not set up, set up the default CJK order, based on accept lang settings and locale
1339 if (mCJKPrefLangs.Length() == 0) {
1341 // temp array
1342 eFontPrefLang tempPrefLangs[kMaxLenPrefLangList];
1343 uint32_t tempLen = 0;
1345 // Add the CJK pref fonts from accept languages, the order should be same order
1346 nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages");
1347 if (!list.IsEmpty()) {
1348 const char kComma = ',';
1349 const char *p, *p_end;
1350 list.BeginReading(p);
1351 list.EndReading(p_end);
1352 while (p < p_end) {
1353 while (nsCRT::IsAsciiSpace(*p)) {
1354 if (++p == p_end)
1355 break;
1357 if (p == p_end)
1358 break;
1359 const char *start = p;
1360 while (++p != p_end && *p != kComma)
1361 /* nothing */ ;
1362 nsAutoCString lang(Substring(start, p));
1363 lang.CompressWhitespace(false, true);
1364 eFontPrefLang fpl = gfxPlatform::GetFontPrefLangFor(lang.get());
1365 switch (fpl) {
1366 case eFontPrefLang_Japanese:
1367 case eFontPrefLang_Korean:
1368 case eFontPrefLang_ChineseCN:
1369 case eFontPrefLang_ChineseHK:
1370 case eFontPrefLang_ChineseTW:
1371 AppendPrefLang(tempPrefLangs, tempLen, fpl);
1372 break;
1373 default:
1374 break;
1376 p++;
1380 do { // to allow 'break' to abort this block if a call fails
1381 nsresult rv;
1382 nsCOMPtr<nsILocaleService> ls =
1383 do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
1384 if (NS_FAILED(rv))
1385 break;
1387 nsCOMPtr<nsILocale> appLocale;
1388 rv = ls->GetApplicationLocale(getter_AddRefs(appLocale));
1389 if (NS_FAILED(rv))
1390 break;
1392 nsString localeStr;
1393 rv = appLocale->
1394 GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr);
1395 if (NS_FAILED(rv))
1396 break;
1398 const nsAString& lang = Substring(localeStr, 0, 2);
1399 if (lang.EqualsLiteral("ja")) {
1400 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
1401 } else if (lang.EqualsLiteral("zh")) {
1402 const nsAString& region = Substring(localeStr, 3, 2);
1403 if (region.EqualsLiteral("CN")) {
1404 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
1405 } else if (region.EqualsLiteral("TW")) {
1406 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
1407 } else if (region.EqualsLiteral("HK")) {
1408 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
1410 } else if (lang.EqualsLiteral("ko")) {
1411 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
1413 } while (0);
1415 // last resort... (the order is same as old gfx.)
1416 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
1417 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
1418 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
1419 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
1420 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
1422 // copy into the cached array
1423 uint32_t j;
1424 for (j = 0; j < tempLen; j++) {
1425 mCJKPrefLangs.AppendElement(tempPrefLangs[j]);
1429 // append in cached CJK langs
1430 uint32_t i, numCJKlangs = mCJKPrefLangs.Length();
1432 for (i = 0; i < numCJKlangs; i++) {
1433 AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i]));
1438 void
1439 gfxPlatform::AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang)
1441 if (aLen >= kMaxLenPrefLangList) return;
1443 // make sure
1444 uint32_t i = 0;
1445 while (i < aLen && aPrefLangs[i] != aAddLang) {
1446 i++;
1449 if (i == aLen) {
1450 aPrefLangs[aLen] = aAddLang;
1451 aLen++;
1455 void
1456 gfxPlatform::InitBackendPrefs(uint32_t aCanvasBitmask, BackendType aCanvasDefault,
1457 uint32_t aContentBitmask, BackendType aContentDefault)
1459 mPreferredCanvasBackend = GetCanvasBackendPref(aCanvasBitmask);
1460 if (mPreferredCanvasBackend == BackendType::NONE) {
1461 mPreferredCanvasBackend = aCanvasDefault;
1463 mFallbackCanvasBackend =
1464 GetCanvasBackendPref(aCanvasBitmask & ~BackendTypeBit(mPreferredCanvasBackend));
1466 mContentBackendBitmask = aContentBitmask;
1467 mContentBackend = GetContentBackendPref(mContentBackendBitmask);
1468 if (mContentBackend == BackendType::NONE) {
1469 mContentBackend = aContentDefault;
1470 // mContentBackendBitmask is our canonical reference for supported
1471 // backends so we need to add the default if we are using it and
1472 // overriding the prefs.
1473 mContentBackendBitmask |= BackendTypeBit(aContentDefault);
1477 /* static */ BackendType
1478 gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask)
1480 return GetBackendPref("gfx.canvas.azure.backends", aBackendBitmask);
1483 /* static */ BackendType
1484 gfxPlatform::GetContentBackendPref(uint32_t &aBackendBitmask)
1486 return GetBackendPref("gfx.content.azure.backends", aBackendBitmask);
1489 /* static */ BackendType
1490 gfxPlatform::GetBackendPref(const char* aBackendPrefName, uint32_t &aBackendBitmask)
1492 nsTArray<nsCString> backendList;
1493 nsCString prefString;
1494 if (NS_SUCCEEDED(Preferences::GetCString(aBackendPrefName, &prefString))) {
1495 ParseString(prefString, ',', backendList);
1498 uint32_t allowedBackends = 0;
1499 BackendType result = BackendType::NONE;
1500 for (uint32_t i = 0; i < backendList.Length(); ++i) {
1501 BackendType type = BackendTypeForName(backendList[i]);
1502 if (BackendTypeBit(type) & aBackendBitmask) {
1503 allowedBackends |= BackendTypeBit(type);
1504 if (result == BackendType::NONE) {
1505 result = type;
1510 aBackendBitmask = allowedBackends;
1511 return result;
1514 bool
1515 gfxPlatform::OffMainThreadCompositingEnabled()
1517 return UsesOffMainThreadCompositing();
1520 eCMSMode
1521 gfxPlatform::GetCMSMode()
1523 if (gCMSInitialized == false) {
1524 gCMSInitialized = true;
1526 int32_t mode = gfxPrefs::CMSMode();
1527 if (mode >= 0 && mode < eCMSMode_AllCount) {
1528 gCMSMode = static_cast<eCMSMode>(mode);
1531 bool enableV4 = gfxPrefs::CMSEnableV4();
1532 if (enableV4) {
1533 qcms_enable_iccv4();
1536 return gCMSMode;
1540 gfxPlatform::GetRenderingIntent()
1542 if (!gCMSIntentInitialized) {
1543 gCMSIntentInitialized = true;
1545 // gfxPrefs.h is using 0 as the default for the rendering
1546 // intent preference, based on that being the value for
1547 // QCMS_INTENT_DEFAULT. Assert here to catch if that ever
1548 // changes and we can then figure out what to do about it.
1549 MOZ_ASSERT(QCMS_INTENT_DEFAULT == 0);
1551 /* Try to query the pref system for a rendering intent. */
1552 int32_t pIntent = gfxPrefs::CMSRenderingIntent();
1553 if ((pIntent >= QCMS_INTENT_MIN) && (pIntent <= QCMS_INTENT_MAX)) {
1554 gCMSIntent = pIntent;
1555 } else {
1556 /* If the pref is out of range, use embedded profile. */
1557 gCMSIntent = -1;
1560 return gCMSIntent;
1563 void
1564 gfxPlatform::TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *transform)
1567 if (transform) {
1568 /* we want the bytes in RGB order */
1569 #ifdef IS_LITTLE_ENDIAN
1570 /* ABGR puts the bytes in |RGBA| order on little endian */
1571 uint32_t packed = in.Packed(gfxRGBA::PACKED_ABGR);
1572 qcms_transform_data(transform,
1573 (uint8_t *)&packed, (uint8_t *)&packed,
1575 out.~gfxRGBA();
1576 new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ABGR);
1577 #else
1578 /* ARGB puts the bytes in |ARGB| order on big endian */
1579 uint32_t packed = in.Packed(gfxRGBA::PACKED_ARGB);
1580 /* add one to move past the alpha byte */
1581 qcms_transform_data(transform,
1582 (uint8_t *)&packed + 1, (uint8_t *)&packed + 1,
1584 out.~gfxRGBA();
1585 new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ARGB);
1586 #endif
1589 else if (&out != &in)
1590 out = in;
1593 void
1594 gfxPlatform::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
1596 mem = nullptr;
1597 size = 0;
1600 void
1601 gfxPlatform::GetCMSOutputProfileData(void *&mem, size_t &size)
1603 nsAdoptingCString fname = Preferences::GetCString("gfx.color_management.display_profile");
1604 if (!fname.IsEmpty()) {
1605 qcms_data_from_path(fname, &mem, &size);
1607 else {
1608 gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile(mem, size);
1612 void
1613 gfxPlatform::CreateCMSOutputProfile()
1615 if (!gCMSOutputProfile) {
1616 /* Determine if we're using the internal override to force sRGB as
1617 an output profile for reftests. See Bug 452125.
1619 Note that we don't normally (outside of tests) set a
1620 default value of this preference, which means nsIPrefBranch::GetBoolPref
1621 will typically throw (and leave its out-param untouched).
1623 if (Preferences::GetBool(GFX_PREF_CMS_FORCE_SRGB, false)) {
1624 gCMSOutputProfile = GetCMSsRGBProfile();
1627 if (!gCMSOutputProfile) {
1628 void* mem = nullptr;
1629 size_t size = 0;
1631 GetCMSOutputProfileData(mem, size);
1632 if ((mem != nullptr) && (size > 0)) {
1633 gCMSOutputProfile = qcms_profile_from_memory(mem, size);
1634 free(mem);
1638 /* Determine if the profile looks bogus. If so, close the profile
1639 * and use sRGB instead. See bug 460629, */
1640 if (gCMSOutputProfile && qcms_profile_is_bogus(gCMSOutputProfile)) {
1641 NS_ASSERTION(gCMSOutputProfile != GetCMSsRGBProfile(),
1642 "Builtin sRGB profile tagged as bogus!!!");
1643 qcms_profile_release(gCMSOutputProfile);
1644 gCMSOutputProfile = nullptr;
1647 if (!gCMSOutputProfile) {
1648 gCMSOutputProfile = GetCMSsRGBProfile();
1650 /* Precache the LUT16 Interpolations for the output profile. See
1651 bug 444661 for details. */
1652 qcms_profile_precache_output_transform(gCMSOutputProfile);
1656 qcms_profile *
1657 gfxPlatform::GetCMSOutputProfile()
1659 return gCMSOutputProfile;
1662 qcms_profile *
1663 gfxPlatform::GetCMSsRGBProfile()
1665 if (!gCMSsRGBProfile) {
1667 /* Create the profile using qcms. */
1668 gCMSsRGBProfile = qcms_profile_sRGB();
1670 return gCMSsRGBProfile;
1673 qcms_transform *
1674 gfxPlatform::GetCMSRGBTransform()
1676 if (!gCMSRGBTransform) {
1677 qcms_profile *inProfile, *outProfile;
1678 outProfile = GetCMSOutputProfile();
1679 inProfile = GetCMSsRGBProfile();
1681 if (!inProfile || !outProfile)
1682 return nullptr;
1684 gCMSRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
1685 outProfile, QCMS_DATA_RGB_8,
1686 QCMS_INTENT_PERCEPTUAL);
1689 return gCMSRGBTransform;
1692 qcms_transform *
1693 gfxPlatform::GetCMSInverseRGBTransform()
1695 if (!gCMSInverseRGBTransform) {
1696 qcms_profile *inProfile, *outProfile;
1697 inProfile = GetCMSOutputProfile();
1698 outProfile = GetCMSsRGBProfile();
1700 if (!inProfile || !outProfile)
1701 return nullptr;
1703 gCMSInverseRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
1704 outProfile, QCMS_DATA_RGB_8,
1705 QCMS_INTENT_PERCEPTUAL);
1708 return gCMSInverseRGBTransform;
1711 qcms_transform *
1712 gfxPlatform::GetCMSRGBATransform()
1714 if (!gCMSRGBATransform) {
1715 qcms_profile *inProfile, *outProfile;
1716 outProfile = GetCMSOutputProfile();
1717 inProfile = GetCMSsRGBProfile();
1719 if (!inProfile || !outProfile)
1720 return nullptr;
1722 gCMSRGBATransform = qcms_transform_create(inProfile, QCMS_DATA_RGBA_8,
1723 outProfile, QCMS_DATA_RGBA_8,
1724 QCMS_INTENT_PERCEPTUAL);
1727 return gCMSRGBATransform;
1730 /* Shuts down various transforms and profiles for CMS. */
1731 static void ShutdownCMS()
1734 if (gCMSRGBTransform) {
1735 qcms_transform_release(gCMSRGBTransform);
1736 gCMSRGBTransform = nullptr;
1738 if (gCMSInverseRGBTransform) {
1739 qcms_transform_release(gCMSInverseRGBTransform);
1740 gCMSInverseRGBTransform = nullptr;
1742 if (gCMSRGBATransform) {
1743 qcms_transform_release(gCMSRGBATransform);
1744 gCMSRGBATransform = nullptr;
1746 if (gCMSOutputProfile) {
1747 qcms_profile_release(gCMSOutputProfile);
1749 // handle the aliased case
1750 if (gCMSsRGBProfile == gCMSOutputProfile)
1751 gCMSsRGBProfile = nullptr;
1752 gCMSOutputProfile = nullptr;
1754 if (gCMSsRGBProfile) {
1755 qcms_profile_release(gCMSsRGBProfile);
1756 gCMSsRGBProfile = nullptr;
1759 // Reset the state variables
1760 gCMSIntent = -2;
1761 gCMSMode = eCMSMode_Off;
1762 gCMSInitialized = false;
1765 // default SetupClusterBoundaries, based on Unicode properties;
1766 // platform subclasses may override if they wish
1767 void
1768 gfxPlatform::SetupClusterBoundaries(gfxTextRun *aTextRun, const char16_t *aString)
1770 if (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) {
1771 // 8-bit text doesn't have clusters.
1772 // XXX is this true in all languages???
1773 // behdad: don't think so. Czech for example IIRC has a
1774 // 'ch' grapheme.
1775 // jfkthame: but that's not expected to behave as a grapheme cluster
1776 // for selection/editing/etc.
1777 return;
1780 aTextRun->SetupClusterBoundaries(0, aString, aTextRun->GetLength());
1783 int32_t
1784 gfxPlatform::GetBidiNumeralOption()
1786 if (mBidiNumeralOption == UNINITIALIZED_VALUE) {
1787 mBidiNumeralOption = Preferences::GetInt(BIDI_NUMERAL_PREF, 0);
1789 return mBidiNumeralOption;
1792 static void
1793 FlushFontAndWordCaches()
1795 gfxFontCache *fontCache = gfxFontCache::GetCache();
1796 if (fontCache) {
1797 fontCache->AgeAllGenerations();
1798 fontCache->FlushShapedWordCaches();
1802 void
1803 gfxPlatform::FontsPrefsChanged(const char *aPref)
1805 NS_ASSERTION(aPref != nullptr, "null preference");
1806 if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) {
1807 mAllowDownloadableFonts = UNINITIALIZED_VALUE;
1808 } else if (!strcmp(GFX_PREF_FALLBACK_USE_CMAPS, aPref)) {
1809 mFallbackUsesCmaps = UNINITIALIZED_VALUE;
1810 } else if (!strcmp(GFX_PREF_WORD_CACHE_CHARLIMIT, aPref)) {
1811 mWordCacheCharLimit = UNINITIALIZED_VALUE;
1812 FlushFontAndWordCaches();
1813 } else if (!strcmp(GFX_PREF_WORD_CACHE_MAXENTRIES, aPref)) {
1814 mWordCacheMaxEntries = UNINITIALIZED_VALUE;
1815 FlushFontAndWordCaches();
1816 } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
1817 mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
1818 FlushFontAndWordCaches();
1819 } else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) {
1820 mBidiNumeralOption = UNINITIALIZED_VALUE;
1821 } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) {
1822 mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
1823 gfxFontCache::GetCache()->AgeAllGenerations();
1828 PRLogModuleInfo*
1829 gfxPlatform::GetLog(eGfxLog aWhichLog)
1831 // logs shared across gfx
1832 #ifdef PR_LOGGING
1833 static PRLogModuleInfo *sFontlistLog = nullptr;
1834 static PRLogModuleInfo *sFontInitLog = nullptr;
1835 static PRLogModuleInfo *sTextrunLog = nullptr;
1836 static PRLogModuleInfo *sTextrunuiLog = nullptr;
1837 static PRLogModuleInfo *sCmapDataLog = nullptr;
1838 static PRLogModuleInfo *sTextPerfLog = nullptr;
1840 // Assume that if one is initialized, all are initialized
1841 if (!sFontlistLog) {
1842 sFontlistLog = PR_NewLogModule("fontlist");
1843 sFontInitLog = PR_NewLogModule("fontinit");
1844 sTextrunLog = PR_NewLogModule("textrun");
1845 sTextrunuiLog = PR_NewLogModule("textrunui");
1846 sCmapDataLog = PR_NewLogModule("cmapdata");
1847 sTextPerfLog = PR_NewLogModule("textperf");
1850 switch (aWhichLog) {
1851 case eGfxLog_fontlist:
1852 return sFontlistLog;
1853 break;
1854 case eGfxLog_fontinit:
1855 return sFontInitLog;
1856 break;
1857 case eGfxLog_textrun:
1858 return sTextrunLog;
1859 break;
1860 case eGfxLog_textrunui:
1861 return sTextrunuiLog;
1862 break;
1863 case eGfxLog_cmapdata:
1864 return sCmapDataLog;
1865 break;
1866 case eGfxLog_textperf:
1867 return sTextPerfLog;
1868 break;
1869 default:
1870 break;
1873 return nullptr;
1874 #else
1875 return nullptr;
1876 #endif
1880 gfxPlatform::GetScreenDepth() const
1882 NS_WARNING("GetScreenDepth not implemented on this platform -- returning 0!");
1883 return 0;
1886 mozilla::gfx::SurfaceFormat
1887 gfxPlatform::Optimal2DFormatForContent(gfxContentType aContent)
1889 switch (aContent) {
1890 case gfxContentType::COLOR:
1891 switch (GetOffscreenFormat()) {
1892 case gfxImageFormat::ARGB32:
1893 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
1894 case gfxImageFormat::RGB24:
1895 return mozilla::gfx::SurfaceFormat::B8G8R8X8;
1896 case gfxImageFormat::RGB16_565:
1897 return mozilla::gfx::SurfaceFormat::R5G6B5;
1898 default:
1899 NS_NOTREACHED("unknown gfxImageFormat for gfxContentType::COLOR");
1900 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
1902 case gfxContentType::ALPHA:
1903 return mozilla::gfx::SurfaceFormat::A8;
1904 case gfxContentType::COLOR_ALPHA:
1905 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
1906 default:
1907 NS_NOTREACHED("unknown gfxContentType");
1908 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
1912 gfxImageFormat
1913 gfxPlatform::OptimalFormatForContent(gfxContentType aContent)
1915 switch (aContent) {
1916 case gfxContentType::COLOR:
1917 return GetOffscreenFormat();
1918 case gfxContentType::ALPHA:
1919 return gfxImageFormat::A8;
1920 case gfxContentType::COLOR_ALPHA:
1921 return gfxImageFormat::ARGB32;
1922 default:
1923 NS_NOTREACHED("unknown gfxContentType");
1924 return gfxImageFormat::ARGB32;
1929 * There are a number of layers acceleration (or layers in general) preferences
1930 * that should be consistent for the lifetime of the application (bug 840967).
1931 * As such, we will evaluate them all as soon as one of them is evaluated
1932 * and remember the values. Changing these preferences during the run will
1933 * not have any effect until we restart.
1935 static bool sLayersSupportsD3D9 = false;
1936 static bool sLayersSupportsD3D11 = false;
1937 static bool sBufferRotationCheckPref = true;
1938 static bool sPrefBrowserTabsRemoteAutostart = false;
1940 static bool sLayersAccelerationPrefsInitialized = false;
1942 void
1943 InitLayersAccelerationPrefs()
1945 if (!sLayersAccelerationPrefsInitialized)
1947 // If this is called for the first time on a non-main thread, we're screwed.
1948 // At the moment there's no explicit guarantee that the main thread calls
1949 // this before the compositor thread, but let's at least make the assumption
1950 // explicit.
1951 MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread");
1953 gfxPrefs::GetSingleton();
1954 sPrefBrowserTabsRemoteAutostart = BrowserTabsRemoteAutostart();
1956 #ifdef XP_WIN
1957 if (gfxPrefs::LayersAccelerationForceEnabled()) {
1958 sLayersSupportsD3D9 = true;
1959 sLayersSupportsD3D11 = true;
1960 } else {
1961 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
1962 if (gfxInfo) {
1963 int32_t status;
1964 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status))) {
1965 if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
1966 sLayersSupportsD3D9 = true;
1969 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
1970 if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
1971 sLayersSupportsD3D11 = true;
1976 #endif
1978 sLayersAccelerationPrefsInitialized = true;
1982 bool
1983 gfxPlatform::CanUseDirect3D9()
1985 // this function is called from the compositor thread, so it is not
1986 // safe to init the prefs etc. from here.
1987 MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
1988 return sLayersSupportsD3D9;
1991 bool
1992 gfxPlatform::CanUseDirect3D11()
1994 // this function is called from the compositor thread, so it is not
1995 // safe to init the prefs etc. from here.
1996 MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
1997 return sLayersSupportsD3D11;
2000 bool
2001 gfxPlatform::BufferRotationEnabled()
2003 MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
2005 return sBufferRotationCheckPref && gfxPrefs::BufferRotationEnabled();
2008 void
2009 gfxPlatform::DisableBufferRotation()
2011 MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
2013 sBufferRotationCheckPref = false;
2016 TemporaryRef<ScaledFont>
2017 gfxPlatform::GetScaledFontForFontWithCairoSkia(DrawTarget* aTarget, gfxFont* aFont)
2019 NativeFont nativeFont;
2020 if (aTarget->GetBackendType() == BackendType::CAIRO || aTarget->GetBackendType() == BackendType::SKIA) {
2021 nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
2022 nativeFont.mFont = aFont->GetCairoScaledFont();
2023 return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize());
2026 return nullptr;
2029 /* static */ bool
2030 gfxPlatform::UsesOffMainThreadCompositing()
2032 InitLayersAccelerationPrefs();
2033 static bool firstTime = true;
2034 static bool result = false;
2036 if (firstTime) {
2037 result =
2038 sPrefBrowserTabsRemoteAutostart ||
2039 gfxPrefs::LayersOffMainThreadCompositionEnabled() ||
2040 gfxPrefs::LayersOffMainThreadCompositionForceEnabled() ||
2041 gfxPrefs::LayersOffMainThreadCompositionTestingEnabled();
2042 #if defined(MOZ_WIDGET_GTK)
2043 // Linux users who chose OpenGL are being grandfathered in to OMTC
2044 result |= gfxPrefs::LayersAccelerationForceEnabled();
2046 #if !defined(NIGHTLY_BUILD)
2047 // Yeah, these two env vars do the same thing.
2048 // I'm told that one of them is enabled on some test slaves config,
2049 // so be slightly careful if you think you can remove one of them.
2050 result &= PR_GetEnv("MOZ_USE_OMTC") || PR_GetEnv("MOZ_OMTC_ENABLED");
2051 #endif
2052 #endif
2053 firstTime = false;
2056 return result;