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/. */
5
6 #include "mozilla/layers/CompositorBridgeChild.h"
7 #include "mozilla/layers/CompositorThread.h"
8 #include "mozilla/layers/ImageBridgeChild.h"
9 #include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter
10 #include "mozilla/gfx/gfxVars.h"
11 #include "mozilla/gfx/GPUProcessManager.h"
12 #include "mozilla/gfx/GraphicsMessages.h"
13 #include "mozilla/ClearOnShutdown.h"
14 #include "mozilla/Telemetry.h"
15 #include "mozilla/TimeStamp.h"
16 #include "mozilla/Unused.h"
17
18 #include "mozilla/Logging.h"
19 #include "mozilla/Services.h"
20
21 #include "gfxCrashReporterUtils.h"
22 #include "gfxPlatform.h"
23 #include "gfxPrefs.h"
24 #include "gfxEnv.h"
25 #include "gfxTextRun.h"
26 #include "gfxConfig.h"
27 #include "MediaPrefs.h"
28
29 #ifdef XP_WIN
30 #include <process.h>
31 #define getpid _getpid
32 #else
33 #include <unistd.h>
34 #endif
35
36 #include "nsXULAppAPI.h"
37 #include "nsDirectoryServiceUtils.h"
38 #include "nsDirectoryServiceDefs.h"
39
40 #if defined(XP_WIN)
41 #include "gfxWindowsPlatform.h"
42 #elif defined(XP_MACOSX)
43 #include "gfxPlatformMac.h"
44 #include "gfxQuartzSurface.h"
45 #elif defined(MOZ_WIDGET_GTK)
46 #include "gfxPlatformGtk.h"
47 #elif defined(ANDROID)
48 #include "gfxAndroidPlatform.h"
49 #endif
50
51 #ifdef XP_WIN
52 #include "mozilla/WindowsVersion.h"
53 #endif
54
55 #include "nsGkAtoms.h"
56 #include "gfxPlatformFontList.h"
57 #include "gfxContext.h"
58 #include "gfxImageSurface.h"
59 #include "nsUnicodeProperties.h"
60 #include "harfbuzz/hb.h"
61 #include "gfxGraphiteShaper.h"
62 #include "gfx2DGlue.h"
63 #include "gfxGradientCache.h"
64 #include "gfxUtils.h" // for NextPowerOfTwo
65
66 #include "nsUnicodeRange.h"
67 #include "nsServiceManagerUtils.h"
68 #include "nsTArray.h"
69 #include "nsILocaleService.h"
70 #include "nsIObserverService.h"
71 #include "nsIScreenManager.h"
72 #include "FrameMetrics.h"
73 #include "MainThreadUtils.h"
74 #ifdef MOZ_CRASHREPORTER
75 #include "nsExceptionHandler.h"
76 #endif
77
78 #include "nsWeakReference.h"
79
80 #include "cairo.h"
81 #include "qcms.h"
82
83 #include "imgITools.h"
84
85 #include "plstr.h"
86 #include "nsCRT.h"
87 #include "GLContext.h"
88 #include "GLContextProvider.h"
89 #include "mozilla/gfx/Logging.h"
90
91 #if defined(MOZ_WIDGET_GTK)
92 #include "gfxPlatformGtk.h" // xxx - for UseFcFontList
93 #endif
94
95 #ifdef MOZ_WIDGET_ANDROID
96 #include "TexturePoolOGL.h"
97 #endif
98
99 #ifdef USE_SKIA
100 # ifdef __GNUC__
101 # pragma GCC diagnostic push
102 # pragma GCC diagnostic ignored "-Wshadow"
103 # endif
104 # include "skia/include/core/SkGraphics.h"
105 # ifdef USE_SKIA_GPU
106 # include "skia/include/gpu/GrContext.h"
107 # include "skia/include/gpu/gl/GrGLInterface.h"
108 # include "SkiaGLGlue.h"
109 # endif
110 # ifdef MOZ_ENABLE_FREETYPE
111 # include "skia/include/ports/SkTypeface_cairo.h"
112 # endif
113 # ifdef __GNUC__
114 # pragma GCC diagnostic pop // -Wshadow
115 # endif
116 static const uint32_t kDefaultGlyphCacheSize = -1;
117
118 #endif
119
120 #if !defined(USE_SKIA) || !defined(USE_SKIA_GPU)
121 class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted {
122 };
123 #endif
124
125 #include "mozilla/Preferences.h"
126 #include "mozilla/Assertions.h"
127 #include "mozilla/Atomics.h"
128 #include "mozilla/Attributes.h"
129 #include "mozilla/Mutex.h"
130
131 #include "nsAlgorithm.h"
132 #include "nsIGfxInfo.h"
133 #include "nsIXULRuntime.h"
134 #include "VsyncSource.h"
135 #include "SoftwareVsyncSource.h"
136 #include "nscore.h" // for NS_FREE_PERMANENT_DATA
137 #include "mozilla/dom/ContentChild.h"
138 #include "gfxVR.h"
139 #include "VRManagerChild.h"
140 #include "mozilla/gfx/GPUParent.h"
141 #include "prsystem.h"
142
143 namespace mozilla {
144 namespace layers {
145 void ShutdownTileCache();
146 } // namespace layers
147 } // namespace mozilla
148
149 using namespace mozilla;
150 using namespace mozilla::layers;
151 using namespace mozilla::gl;
152 using namespace mozilla::gfx;
153
154 gfxPlatform *gPlatform = nullptr;
155 static bool gEverInitialized = false;
156
157 static Mutex* gGfxPlatformPrefsLock = nullptr;
158
159 // These two may point to the same profile
160 static qcms_profile *gCMSOutputProfile = nullptr;
161 static qcms_profile *gCMSsRGBProfile = nullptr;
162
163 static qcms_transform *gCMSRGBTransform = nullptr;
164 static qcms_transform *gCMSInverseRGBTransform = nullptr;
165 static qcms_transform *gCMSRGBATransform = nullptr;
166
167 static bool gCMSInitialized = false;
168 static eCMSMode gCMSMode = eCMSMode_Off;
169
170 static void ShutdownCMS();
171
172 #include "mozilla/gfx/2D.h"
173 #include "mozilla/gfx/SourceSurfaceCairo.h"
174 using namespace mozilla::gfx;
175
176 /* Class to listen for pref changes so that chrome code can dynamically
177 force sRGB as an output profile. See Bug #452125. */
178 class SRGBOverrideObserver final : public nsIObserver,
179 public nsSupportsWeakReference
180 {
~SRGBOverrideObserver()181 ~SRGBOverrideObserver() {}
182 public:
183 NS_DECL_ISUPPORTS
184 NS_DECL_NSIOBSERVER
185 };
186
187 /// This override of the LogForwarder, initially used for the critical graphics
188 /// errors, is sending the log to the crash annotations as well, but only
189 /// if the capacity set with the method below is >= 2. We always retain the
190 /// very first critical message, and the latest capacity-1 messages are
191 /// rotated through. Note that we don't expect the total number of times
192 /// this gets called to be large - it is meant for critical errors only.
193
194 class CrashStatsLogForwarder: public mozilla::gfx::LogForwarder
195 {
196 public:
197 explicit CrashStatsLogForwarder(const char* aKey);
198 virtual void Log(const std::string& aString) override;
199 virtual void CrashAction(LogReason aReason) override;
200 virtual bool UpdateStringsVector(const std::string& aString) override;
201
202 virtual LoggingRecord LoggingRecordCopy() override;
203
204 void SetCircularBufferSize(uint32_t aCapacity);
205
206 private:
207 // Helper for the Log()
208 void UpdateCrashReport();
209
210 private:
211 LoggingRecord mBuffer;
212 nsCString mCrashCriticalKey;
213 uint32_t mMaxCapacity;
214 int32_t mIndex;
215 Mutex mMutex;
216 };
217
CrashStatsLogForwarder(const char * aKey)218 CrashStatsLogForwarder::CrashStatsLogForwarder(const char* aKey)
219 : mBuffer()
220 , mCrashCriticalKey(aKey)
221 , mMaxCapacity(0)
222 , mIndex(-1)
223 , mMutex("CrashStatsLogForwarder")
224 {
225 }
226
SetCircularBufferSize(uint32_t aCapacity)227 void CrashStatsLogForwarder::SetCircularBufferSize(uint32_t aCapacity)
228 {
229 MutexAutoLock lock(mMutex);
230
231 mMaxCapacity = aCapacity;
232 mBuffer.reserve(static_cast<size_t>(aCapacity));
233 }
234
235 LoggingRecord
LoggingRecordCopy()236 CrashStatsLogForwarder::LoggingRecordCopy()
237 {
238 MutexAutoLock lock(mMutex);
239 return mBuffer;
240 }
241
242 bool
UpdateStringsVector(const std::string & aString)243 CrashStatsLogForwarder::UpdateStringsVector(const std::string& aString)
244 {
245 // We want at least the first one and the last one. Otherwise, no point.
246 if (mMaxCapacity < 2) {
247 return false;
248 }
249
250 mIndex += 1;
251 MOZ_ASSERT(mIndex >= 0);
252
253 // index will count 0, 1, 2, ..., max-1, 1, 2, ..., max-1, 1, 2, ...
254 int32_t index = mIndex ? (mIndex-1) % (mMaxCapacity-1) + 1 : 0;
255 MOZ_ASSERT(index >= 0 && index < (int32_t)mMaxCapacity);
256 MOZ_ASSERT(index <= mIndex && index <= (int32_t)mBuffer.size());
257
258 bool ignored;
259 double tStamp = (TimeStamp::NowLoRes()-TimeStamp::ProcessCreation(ignored)).ToSecondsSigDigits();
260
261 // Checking for index >= mBuffer.size(), rather than index == mBuffer.size()
262 // just out of paranoia, but we know index <= mBuffer.size().
263 LoggingRecordEntry newEntry(mIndex,aString,tStamp);
264 if (index >= static_cast<int32_t>(mBuffer.size())) {
265 mBuffer.push_back(newEntry);
266 } else {
267 mBuffer[index] = newEntry;
268 }
269 return true;
270 }
271
UpdateCrashReport()272 void CrashStatsLogForwarder::UpdateCrashReport()
273 {
274 std::stringstream message;
275 std::string logAnnotation;
276
277 switch (XRE_GetProcessType()) {
278 case GeckoProcessType_Default:
279 logAnnotation = "|[";
280 break;
281 case GeckoProcessType_Content:
282 logAnnotation = "|[C";
283 break;
284 case GeckoProcessType_GPU:
285 logAnnotation = "|[G";
286 break;
287 default:
288 logAnnotation = "|[X";
289 break;
290 }
291
292 for (LoggingRecord::iterator it = mBuffer.begin(); it != mBuffer.end(); ++it) {
293 message << logAnnotation << Get<0>(*it) << "]" << Get<1>(*it) << " (t=" << Get<2>(*it) << ") ";
294 }
295
296 #ifdef MOZ_CRASHREPORTER
297 nsCString reportString(message.str().c_str());
298 nsresult annotated = CrashReporter::AnnotateCrashReport(mCrashCriticalKey, reportString);
299 #else
300 nsresult annotated = NS_ERROR_NOT_IMPLEMENTED;
301 #endif
302 if (annotated != NS_OK) {
303 printf("Crash Annotation %s: %s",
304 mCrashCriticalKey.get(), message.str().c_str());
305 }
306 }
307
308 class LogForwarderEvent : public Runnable
309 {
~LogForwarderEvent()310 virtual ~LogForwarderEvent() {}
311
312 NS_DECL_ISUPPORTS_INHERITED
313
LogForwarderEvent(const nsCString & aMessage)314 explicit LogForwarderEvent(const nsCString& aMessage) : mMessage(aMessage) {}
315
Run()316 NS_IMETHOD Run() override {
317 MOZ_ASSERT(NS_IsMainThread() && (XRE_IsContentProcess() || XRE_IsGPUProcess()));
318
319 if (XRE_IsContentProcess()) {
320 dom::ContentChild* cc = dom::ContentChild::GetSingleton();
321 Unused << cc->SendGraphicsError(mMessage);
322 } else if (XRE_IsGPUProcess()) {
323 GPUParent* gp = GPUParent::GetSingleton();
324 Unused << gp->SendGraphicsError(mMessage);
325 }
326
327 return NS_OK;
328 }
329
330 protected:
331 nsCString mMessage;
332 };
333
334 NS_IMPL_ISUPPORTS_INHERITED0(LogForwarderEvent, Runnable);
335
Log(const std::string & aString)336 void CrashStatsLogForwarder::Log(const std::string& aString)
337 {
338 MutexAutoLock lock(mMutex);
339
340 if (UpdateStringsVector(aString)) {
341 UpdateCrashReport();
342 }
343
344 // Add it to the parent strings
345 if (!XRE_IsParentProcess()) {
346 nsCString stringToSend(aString.c_str());
347 if (NS_IsMainThread()) {
348 if (XRE_IsContentProcess()) {
349 dom::ContentChild* cc = dom::ContentChild::GetSingleton();
350 Unused << cc->SendGraphicsError(stringToSend);
351 } else if (XRE_IsGPUProcess()) {
352 GPUParent* gp = GPUParent::GetSingleton();
353 Unused << gp->SendGraphicsError(stringToSend);
354 }
355 } else {
356 nsCOMPtr<nsIRunnable> r1 = new LogForwarderEvent(stringToSend);
357 NS_DispatchToMainThread(r1);
358 }
359 }
360 }
361
362 class CrashTelemetryEvent : public Runnable
363 {
~CrashTelemetryEvent()364 virtual ~CrashTelemetryEvent() {}
365
366 NS_DECL_ISUPPORTS_INHERITED
367
CrashTelemetryEvent(uint32_t aReason)368 explicit CrashTelemetryEvent(uint32_t aReason) : mReason(aReason) {}
369
Run()370 NS_IMETHOD Run() override {
371 MOZ_ASSERT(NS_IsMainThread());
372 Telemetry::Accumulate(Telemetry::GFX_CRASH, mReason);
373 return NS_OK;
374 }
375
376 protected:
377 uint32_t mReason;
378 };
379
380 NS_IMPL_ISUPPORTS_INHERITED0(CrashTelemetryEvent, Runnable);
381
382 void
CrashAction(LogReason aReason)383 CrashStatsLogForwarder::CrashAction(LogReason aReason)
384 {
385 #ifndef RELEASE_OR_BETA
386 // Non-release builds crash by default, but will use telemetry
387 // if this environment variable is present.
388 static bool useTelemetry = gfxEnv::GfxDevCrashTelemetry();
389 #else
390 // Release builds use telemetry by default, but will crash instead
391 // if this environment variable is present.
392 static bool useTelemetry = !gfxEnv::GfxDevCrashMozCrash();
393 #endif
394
395 if (useTelemetry) {
396 // The callers need to assure that aReason is in the range
397 // that the telemetry call below supports.
398 if (NS_IsMainThread()) {
399 Telemetry::Accumulate(Telemetry::GFX_CRASH, (uint32_t)aReason);
400 } else {
401 nsCOMPtr<nsIRunnable> r1 = new CrashTelemetryEvent((uint32_t)aReason);
402 NS_DispatchToMainThread(r1);
403 }
404 } else {
405 // ignoring aReason, we can get the information we need from the stack
406 MOZ_CRASH("GFX_CRASH");
407 }
408 }
409
NS_IMPL_ISUPPORTS(SRGBOverrideObserver,nsIObserver,nsISupportsWeakReference)410 NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
411
412 #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
413
414 #define GFX_PREF_FALLBACK_USE_CMAPS "gfx.font_rendering.fallback.always_use_cmaps"
415
416 #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
417
418 #define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit"
419 #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries"
420
421 #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
422
423 #define BIDI_NUMERAL_PREF "bidi.numeral"
424
425 #define GFX_PREF_CMS_FORCE_SRGB "gfx.color_management.force_srgb"
426
427 NS_IMETHODIMP
428 SRGBOverrideObserver::Observe(nsISupports *aSubject,
429 const char *aTopic,
430 const char16_t* someData)
431 {
432 NS_ASSERTION(NS_strcmp(someData,
433 (u"" GFX_PREF_CMS_FORCE_SRGB)) == 0,
434 "Restarting CMS on wrong pref!");
435 ShutdownCMS();
436 // Update current cms profile.
437 gfxPlatform::CreateCMSOutputProfile();
438 return NS_OK;
439 }
440
441 static const char* kObservedPrefs[] = {
442 "gfx.downloadable_fonts.",
443 "gfx.font_rendering.",
444 BIDI_NUMERAL_PREF,
445 nullptr
446 };
447
448 class FontPrefsObserver final : public nsIObserver
449 {
~FontPrefsObserver()450 ~FontPrefsObserver() {}
451 public:
452 NS_DECL_ISUPPORTS
453 NS_DECL_NSIOBSERVER
454 };
455
NS_IMPL_ISUPPORTS(FontPrefsObserver,nsIObserver)456 NS_IMPL_ISUPPORTS(FontPrefsObserver, nsIObserver)
457
458 NS_IMETHODIMP
459 FontPrefsObserver::Observe(nsISupports *aSubject,
460 const char *aTopic,
461 const char16_t *someData)
462 {
463 if (!someData) {
464 NS_ERROR("font pref observer code broken");
465 return NS_ERROR_UNEXPECTED;
466 }
467 NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone");
468 gfxPlatform::GetPlatform()->FontsPrefsChanged(NS_ConvertUTF16toUTF8(someData).get());
469
470 return NS_OK;
471 }
472
473 class MemoryPressureObserver final : public nsIObserver
474 {
~MemoryPressureObserver()475 ~MemoryPressureObserver() {}
476 public:
477 NS_DECL_ISUPPORTS
478 NS_DECL_NSIOBSERVER
479 };
480
NS_IMPL_ISUPPORTS(MemoryPressureObserver,nsIObserver)481 NS_IMPL_ISUPPORTS(MemoryPressureObserver, nsIObserver)
482
483 NS_IMETHODIMP
484 MemoryPressureObserver::Observe(nsISupports *aSubject,
485 const char *aTopic,
486 const char16_t *someData)
487 {
488 NS_ASSERTION(strcmp(aTopic, "memory-pressure") == 0, "unexpected event topic");
489 Factory::PurgeAllCaches();
490 gfxGradientCache::PurgeAllCaches();
491
492 gfxPlatform::PurgeSkiaFontCache();
493 gfxPlatform::GetPlatform()->PurgeSkiaGPUCache();
494 return NS_OK;
495 }
496
gfxPlatform()497 gfxPlatform::gfxPlatform()
498 : mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureBackendInfo)
499 , mApzSupportCollector(this, &gfxPlatform::GetApzSupportInfo)
500 , mTilesInfoCollector(this, &gfxPlatform::GetTilesSupportInfo)
501 , mCompositorBackend(layers::LayersBackend::LAYERS_NONE)
502 , mScreenDepth(0)
503 , mDeviceCounter(0)
504 {
505 mAllowDownloadableFonts = UNINITIALIZED_VALUE;
506 mFallbackUsesCmaps = UNINITIALIZED_VALUE;
507
508 mWordCacheCharLimit = UNINITIALIZED_VALUE;
509 mWordCacheMaxEntries = UNINITIALIZED_VALUE;
510 mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
511 mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
512 mBidiNumeralOption = UNINITIALIZED_VALUE;
513
514 mSkiaGlue = nullptr;
515
516 uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
517 uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
518 #ifdef USE_SKIA
519 canvasMask |= BackendTypeBit(BackendType::SKIA);
520 contentMask |= BackendTypeBit(BackendType::SKIA);
521 #endif
522 InitBackendPrefs(canvasMask, BackendType::CAIRO,
523 contentMask, BackendType::CAIRO);
524
525 mTotalSystemMemory = PR_GetPhysicalMemorySize();
526
527 VRManager::ManagerInit();
528 }
529
530 gfxPlatform*
GetPlatform()531 gfxPlatform::GetPlatform()
532 {
533 if (!gPlatform) {
534 Init();
535 }
536 return gPlatform;
537 }
538
539 bool
Initialized()540 gfxPlatform::Initialized()
541 {
542 return !!gPlatform;
543 }
544
RecordingPrefChanged(const char * aPrefName,void * aClosure)545 void RecordingPrefChanged(const char *aPrefName, void *aClosure)
546 {
547 if (Preferences::GetBool("gfx.2d.recording", false)) {
548 nsAutoCString fileName;
549 nsAdoptingString prefFileName = Preferences::GetString("gfx.2d.recordingfile");
550
551 if (prefFileName) {
552 fileName.Append(NS_ConvertUTF16toUTF8(prefFileName));
553 } else {
554 nsCOMPtr<nsIFile> tmpFile;
555 if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile)))) {
556 return;
557 }
558 fileName.AppendPrintf("moz2drec_%i_%i.aer", XRE_GetProcessType(), getpid());
559
560 nsresult rv = tmpFile->AppendNative(fileName);
561 if (NS_FAILED(rv))
562 return;
563
564 rv = tmpFile->GetNativePath(fileName);
565 if (NS_FAILED(rv))
566 return;
567 }
568
569 gPlatform->mRecorder = Factory::CreateEventRecorderForFile(fileName.BeginReading());
570 printf_stderr("Recording to %s\n", fileName.get());
571 Factory::SetGlobalEventRecorder(gPlatform->mRecorder);
572 } else {
573 Factory::SetGlobalEventRecorder(nullptr);
574 }
575 }
576
577 #if defined(USE_SKIA)
GetSkiaGlyphCacheSize()578 static uint32_t GetSkiaGlyphCacheSize()
579 {
580 // Only increase font cache size on non-android to save memory.
581 #if !defined(MOZ_WIDGET_ANDROID)
582 // 10mb as the default cache size on desktop due to talos perf tweaking.
583 // Chromium uses 20mb and skia default uses 2mb.
584 // We don't need to change the font cache count since we usually
585 // cache thrash due to asian character sets in talos.
586 // Only increase memory on the content proces
587 uint32_t cacheSize = 10 * 1024 * 1024;
588 if (mozilla::BrowserTabsRemoteAutostart()) {
589 return XRE_IsContentProcess() ? cacheSize : kDefaultGlyphCacheSize;
590 }
591
592 return cacheSize;
593 #else
594 return kDefaultGlyphCacheSize;
595 #endif // MOZ_WIDGET_ANDROID
596 }
597 #endif
598
599 void
Init()600 gfxPlatform::Init()
601 {
602 MOZ_RELEASE_ASSERT(!XRE_IsGPUProcess(), "GFX: Not allowed in GPU process.");
603 MOZ_RELEASE_ASSERT(NS_IsMainThread(), "GFX: Not in main thread.");
604
605 if (gEverInitialized) {
606 NS_RUNTIMEABORT("Already started???");
607 }
608 gEverInitialized = true;
609
610 // Initialize the preferences by creating the singleton.
611 gfxPrefs::GetSingleton();
612 MediaPrefs::GetSingleton();
613 gfxVars::Initialize();
614
615 gfxConfig::Init();
616
617 if (XRE_IsParentProcess()) {
618 GPUProcessManager::Initialize();
619
620 if (Preferences::GetBool("media.wmf.skip-blacklist")) {
621 gfxVars::SetPDMWMFDisableD3D11Dlls(nsCString());
622 gfxVars::SetPDMWMFDisableD3D9Dlls(nsCString());
623 } else {
624 gfxVars::SetPDMWMFDisableD3D11Dlls(Preferences::GetCString("media.wmf.disable-d3d11-for-dlls"));
625 gfxVars::SetPDMWMFDisableD3D9Dlls(Preferences::GetCString("media.wmf.disable-d3d9-for-dlls"));
626 }
627 }
628
629 // Drop a note in the crash report if we end up forcing an option that could
630 // destabilize things. New items should be appended at the end (of an existing
631 // or in a new section), so that we don't have to know the version to interpret
632 // these cryptic strings.
633 {
634 nsAutoCString forcedPrefs;
635 // D2D prefs
636 forcedPrefs.AppendPrintf("FP(D%d%d",
637 gfxPrefs::Direct2DDisabled(),
638 gfxPrefs::Direct2DForceEnabled());
639 // Layers prefs
640 forcedPrefs.AppendPrintf("-L%d%d%d%d",
641 gfxPrefs::LayersAMDSwitchableGfxEnabled(),
642 gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly(),
643 gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly(),
644 gfxPrefs::LayersD3D11ForceWARP());
645 // WebGL prefs
646 forcedPrefs.AppendPrintf("-W%d%d%d%d%d%d%d%d",
647 gfxPrefs::WebGLANGLEForceD3D11(),
648 gfxPrefs::WebGLANGLEForceWARP(),
649 gfxPrefs::WebGLDisabled(),
650 gfxPrefs::WebGLDisableANGLE(),
651 gfxPrefs::WebGLDXGLEnabled(),
652 gfxPrefs::WebGLForceEnabled(),
653 gfxPrefs::WebGLForceLayersReadback(),
654 gfxPrefs::WebGLForceMSAA());
655 // Prefs that don't fit into any of the other sections
656 forcedPrefs.AppendPrintf("-T%d%d%d%d) ",
657 gfxPrefs::AndroidRGB16Force(),
658 gfxPrefs::CanvasAzureAccelerated(),
659 gfxPrefs::DisableGralloc(),
660 gfxPrefs::ForceShmemTiles());
661 ScopedGfxFeatureReporter::AppNote(forcedPrefs);
662 }
663
664 InitMoz2DLogging();
665
666 gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock");
667
668 /* Initialize the GfxInfo service.
669 * Note: we can't call functions on GfxInfo that depend
670 * on gPlatform until after it has been initialized
671 * below. GfxInfo initialization annotates our
672 * crash reports so we want to do it before
673 * we try to load any drivers and do device detection
674 * incase that code crashes. See bug #591561. */
675 nsCOMPtr<nsIGfxInfo> gfxInfo;
676 /* this currently will only succeed on Windows */
677 gfxInfo = services::GetGfxInfo();
678
679 #if defined(XP_WIN)
680 gPlatform = new gfxWindowsPlatform;
681 #elif defined(XP_MACOSX)
682 gPlatform = new gfxPlatformMac;
683 #elif defined(MOZ_WIDGET_GTK)
684 gPlatform = new gfxPlatformGtk;
685 #elif defined(ANDROID)
686 gPlatform = new gfxAndroidPlatform;
687 #else
688 #error "No gfxPlatform implementation available"
689 #endif
690 gPlatform->InitAcceleration();
691
692 if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
693 GPUProcessManager* gpu = GPUProcessManager::Get();
694 gpu->LaunchGPUProcess();
695 }
696
697 if (XRE_IsParentProcess()) {
698 if (gfxPlatform::ForceSoftwareVsync()) {
699 gPlatform->mVsyncSource = (gPlatform)->gfxPlatform::CreateHardwareVsyncSource();
700 } else {
701 gPlatform->mVsyncSource = gPlatform->CreateHardwareVsyncSource();
702 }
703 }
704
705 #ifdef USE_SKIA
706 SkGraphics::Init();
707 # ifdef MOZ_ENABLE_FREETYPE
708 SkInitCairoFT(gPlatform->FontHintingEnabled());
709 # endif
710 #endif
711
712 #ifdef MOZ_GL_DEBUG
713 GLContext::StaticInit();
714 #endif
715
716 InitLayersIPC();
717
718 gPlatform->PopulateScreenInfo();
719 gPlatform->ComputeTileSize();
720
721 nsresult rv;
722
723 bool usePlatformFontList = true;
724 #if defined(MOZ_WIDGET_GTK)
725 usePlatformFontList = gfxPlatformGtk::UseFcFontList();
726 #endif
727
728 if (usePlatformFontList) {
729 rv = gfxPlatformFontList::Init();
730 if (NS_FAILED(rv)) {
731 NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList");
732 }
733 }
734
735 gPlatform->mScreenReferenceSurface =
736 gPlatform->CreateOffscreenSurface(IntSize(1, 1),
737 SurfaceFormat::A8R8G8B8_UINT32);
738 if (!gPlatform->mScreenReferenceSurface) {
739 NS_RUNTIMEABORT("Could not initialize mScreenReferenceSurface");
740 }
741
742 gPlatform->mScreenReferenceDrawTarget =
743 gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1),
744 SurfaceFormat::B8G8R8A8);
745 if (!gPlatform->mScreenReferenceDrawTarget ||
746 !gPlatform->mScreenReferenceDrawTarget->IsValid()) {
747 NS_RUNTIMEABORT("Could not initialize mScreenReferenceDrawTarget");
748 }
749
750 rv = gfxFontCache::Init();
751 if (NS_FAILED(rv)) {
752 NS_RUNTIMEABORT("Could not initialize gfxFontCache");
753 }
754
755 /* Create and register our CMS Override observer. */
756 gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
757 Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
758
759 gPlatform->mFontPrefsObserver = new FontPrefsObserver();
760 Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
761
762 GLContext::PlatformStartup();
763
764 #ifdef MOZ_WIDGET_ANDROID
765 // Texture pool init
766 TexturePoolOGL::Init();
767 #endif
768
769 Preferences::RegisterCallbackAndCall(RecordingPrefChanged, "gfx.2d.recording", nullptr);
770
771 CreateCMSOutputProfile();
772
773 // Listen to memory pressure event so we can purge DrawTarget caches
774 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
775 if (obs) {
776 gPlatform->mMemoryPressureObserver = new MemoryPressureObserver();
777 obs->AddObserver(gPlatform->mMemoryPressureObserver, "memory-pressure", false);
778 }
779
780 // Request the imgITools service, implicitly initializing ImageLib.
781 nsCOMPtr<imgITools> imgTools = do_GetService("@mozilla.org/image/tools;1");
782 if (!imgTools) {
783 NS_RUNTIMEABORT("Could not initialize ImageLib");
784 }
785
786 RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
787
788 #ifdef USE_SKIA
789 uint32_t skiaCacheSize = GetSkiaGlyphCacheSize();
790 if (skiaCacheSize != kDefaultGlyphCacheSize) {
791 SkGraphics::SetFontCacheLimit(skiaCacheSize);
792 }
793 #endif
794
795 InitNullMetadata();
796 InitOpenGLConfig();
797
798 if (obs) {
799 obs->NotifyObservers(nullptr, "gfx-features-ready", nullptr);
800 }
801 }
802
803 /* static */ void
InitMoz2DLogging()804 gfxPlatform::InitMoz2DLogging()
805 {
806 auto fwd = new CrashStatsLogForwarder("GraphicsCriticalError");
807 fwd->SetCircularBufferSize(gfxPrefs::GfxLoggingCrashLength());
808
809 mozilla::gfx::Config cfg;
810 cfg.mLogForwarder = fwd;
811 cfg.mMaxTextureSize = gfxPrefs::MaxTextureSize();
812 cfg.mMaxAllocSize = gfxPrefs::MaxAllocSize();
813
814 gfx::Factory::Init(cfg);
815 }
816
817 static bool sLayersIPCIsUp = false;
818
819 /* static */ void
InitNullMetadata()820 gfxPlatform::InitNullMetadata()
821 {
822 ScrollMetadata::sNullMetadata = new ScrollMetadata();
823 ClearOnShutdown(&ScrollMetadata::sNullMetadata);
824 }
825
826 void
Shutdown()827 gfxPlatform::Shutdown()
828 {
829 // In some cases, gPlatform may not be created but Shutdown() called,
830 // e.g., during xpcshell tests.
831 if (!gPlatform) {
832 return;
833 }
834
835 MOZ_ASSERT(!sLayersIPCIsUp);
836
837 // These may be called before the corresponding subsystems have actually
838 // started up. That's OK, they can handle it.
839 gfxFontCache::Shutdown();
840 gfxFontGroup::Shutdown();
841 gfxGradientCache::Shutdown();
842 gfxAlphaBoxBlur::ShutdownBlurCache();
843 gfxGraphiteShaper::Shutdown();
844 gfxPlatformFontList::Shutdown();
845 ShutdownTileCache();
846
847 // Free the various non-null transforms and loaded profiles
848 ShutdownCMS();
849
850 /* Unregister our CMS Override callback. */
851 NS_ASSERTION(gPlatform->mSRGBOverrideObserver, "mSRGBOverrideObserver has alreay gone");
852 Preferences::RemoveObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
853 gPlatform->mSRGBOverrideObserver = nullptr;
854
855 NS_ASSERTION(gPlatform->mFontPrefsObserver, "mFontPrefsObserver has alreay gone");
856 Preferences::RemoveObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
857 gPlatform->mFontPrefsObserver = nullptr;
858
859 NS_ASSERTION(gPlatform->mMemoryPressureObserver, "mMemoryPressureObserver has already gone");
860 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
861 if (obs) {
862 obs->RemoveObserver(gPlatform->mMemoryPressureObserver, "memory-pressure");
863 }
864
865 gPlatform->mMemoryPressureObserver = nullptr;
866 gPlatform->mSkiaGlue = nullptr;
867
868 if (XRE_IsParentProcess()) {
869 gPlatform->mVsyncSource->Shutdown();
870 }
871
872 gPlatform->mVsyncSource = nullptr;
873
874 #ifdef MOZ_WIDGET_ANDROID
875 // Shut down the texture pool
876 TexturePoolOGL::Shutdown();
877 #endif
878
879 // Shut down the default GL context provider.
880 GLContextProvider::Shutdown();
881
882 #if defined(XP_WIN)
883 // The above shutdown calls operate on the available context providers on
884 // most platforms. Windows is a "special snowflake", though, and has three
885 // context providers available, so we have to shut all of them down.
886 // We should only support the default GL provider on Windows; then, this
887 // could go away. Unfortunately, we currently support WGL (the default) for
888 // WebGL on Optimus.
889 GLContextProviderEGL::Shutdown();
890 #endif
891
892 if (XRE_IsParentProcess()) {
893 GPUProcessManager::Shutdown();
894 }
895
896 gfx::Factory::ShutDown();
897
898 delete gGfxPlatformPrefsLock;
899
900 gfxVars::Shutdown();
901 gfxPrefs::DestroySingleton();
902 gfxFont::DestroySingletons();
903
904 gfxConfig::Shutdown();
905
906 gPlatform->WillShutdown();
907
908 delete gPlatform;
909 gPlatform = nullptr;
910 }
911
912 /* static */ void
InitLayersIPC()913 gfxPlatform::InitLayersIPC()
914 {
915 if (sLayersIPCIsUp) {
916 return;
917 }
918 sLayersIPCIsUp = true;
919
920 if (XRE_IsParentProcess())
921 {
922 layers::CompositorThreadHolder::Start();
923 }
924 }
925
926 /* static */ void
ShutdownLayersIPC()927 gfxPlatform::ShutdownLayersIPC()
928 {
929 if (!sLayersIPCIsUp) {
930 return;
931 }
932 sLayersIPCIsUp = false;
933
934 if (XRE_IsContentProcess()) {
935 gfx::VRManagerChild::ShutDown();
936 // cf bug 1215265.
937 if (gfxPrefs::ChildProcessShutdown()) {
938 layers::CompositorBridgeChild::ShutDown();
939 layers::ImageBridgeChild::ShutDown();
940 }
941 } else if (XRE_IsParentProcess()) {
942 gfx::VRManagerChild::ShutDown();
943 layers::CompositorBridgeChild::ShutDown();
944 layers::ImageBridgeChild::ShutDown();
945
946 // This has to happen after shutting down the child protocols.
947 layers::CompositorThreadHolder::Shutdown();
948 } else {
949 // TODO: There are other kind of processes and we should make sure gfx
950 // stuff is either not created there or shut down properly.
951 }
952 }
953
954 void
WillShutdown()955 gfxPlatform::WillShutdown()
956 {
957 // Destoy these first in case they depend on backend-specific resources.
958 // Otherwise, the backend's destructor would be called before the
959 // base gfxPlatform destructor.
960 mScreenReferenceSurface = nullptr;
961 mScreenReferenceDrawTarget = nullptr;
962 }
963
~gfxPlatform()964 gfxPlatform::~gfxPlatform()
965 {
966 // The cairo folks think we should only clean up in debug builds,
967 // but we're generally in the habit of trying to shut down as
968 // cleanly as possible even in production code, so call this
969 // cairo_debug_* function unconditionally.
970 //
971 // because cairo can assert and thus crash on shutdown, don't do this in release builds
972 #ifdef NS_FREE_PERMANENT_DATA
973 #ifdef USE_SKIA
974 // must do Skia cleanup before Cairo cleanup, because Skia may be referencing
975 // Cairo objects e.g. through SkCairoFTTypeface
976 SkGraphics::PurgeFontCache();
977 #endif
978
979 #if MOZ_TREE_CAIRO
980 cairo_debug_reset_static_data();
981 #endif
982 #endif
983 }
984
985 /* static */ already_AddRefed<DrawTarget>
CreateDrawTargetForSurface(gfxASurface * aSurface,const IntSize & aSize)986 gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface, const IntSize& aSize)
987 {
988 SurfaceFormat format = aSurface->GetSurfaceFormat();
989 RefPtr<DrawTarget> drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(), aSize, &format);
990 if (!drawTarget) {
991 gfxWarning() << "gfxPlatform::CreateDrawTargetForSurface failed in CreateDrawTargetForCairoSurface";
992 return nullptr;
993 }
994 return drawTarget.forget();
995 }
996
997 cairo_user_data_key_t kSourceSurface;
998
999 /**
1000 * Record the backend that was used to construct the SourceSurface.
1001 * When getting the cached SourceSurface for a gfxASurface/DrawTarget pair,
1002 * we check to make sure the DrawTarget's backend matches the backend
1003 * for the cached SourceSurface, and only use it if they match. This
1004 * can avoid expensive and unnecessary readbacks.
1005 */
1006 struct SourceSurfaceUserData
1007 {
1008 RefPtr<SourceSurface> mSrcSurface;
1009 BackendType mBackendType;
1010 };
1011
SourceBufferDestroy(void * srcSurfUD)1012 void SourceBufferDestroy(void *srcSurfUD)
1013 {
1014 delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
1015 }
1016
1017 UserDataKey kThebesSurface;
1018
1019 struct DependentSourceSurfaceUserData
1020 {
1021 RefPtr<gfxASurface> mSurface;
1022 };
1023
SourceSurfaceDestroyed(void * aData)1024 void SourceSurfaceDestroyed(void *aData)
1025 {
1026 delete static_cast<DependentSourceSurfaceUserData*>(aData);
1027 }
1028
1029 void
ClearSourceSurfaceForSurface(gfxASurface * aSurface)1030 gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
1031 {
1032 aSurface->SetData(&kSourceSurface, nullptr, nullptr);
1033 }
1034
1035 /* static */ already_AddRefed<SourceSurface>
GetSourceSurfaceForSurface(DrawTarget * aTarget,gfxASurface * aSurface,bool aIsPlugin)1036 gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget,
1037 gfxASurface *aSurface,
1038 bool aIsPlugin)
1039 {
1040 if (!aSurface->CairoSurface() || aSurface->CairoStatus()) {
1041 return nullptr;
1042 }
1043
1044 if (!aTarget) {
1045 aTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
1046 }
1047
1048 void *userData = aSurface->GetData(&kSourceSurface);
1049
1050 if (userData) {
1051 SourceSurfaceUserData *surf = static_cast<SourceSurfaceUserData*>(userData);
1052
1053 if (surf->mSrcSurface->IsValid() && surf->mBackendType == aTarget->GetBackendType()) {
1054 RefPtr<SourceSurface> srcSurface(surf->mSrcSurface);
1055 return srcSurface.forget();
1056 }
1057 // We can just continue here as when setting new user data the destroy
1058 // function will be called for the old user data.
1059 }
1060
1061 SurfaceFormat format = aSurface->GetSurfaceFormat();
1062
1063 if (aTarget->GetBackendType() == BackendType::CAIRO) {
1064 // If we're going to be used with a CAIRO DrawTarget, then just create a
1065 // SourceSurfaceCairo since we don't know the underlying type of the CAIRO
1066 // DrawTarget and can't pick a better surface type. Doing this also avoids
1067 // readback of aSurface's surface into memory if, for example, aSurface
1068 // wraps an xlib cairo surface (which can be important to avoid a major
1069 // slowdown).
1070 //
1071 // We return here regardless of whether CreateSourceSurfaceFromNativeSurface
1072 // succeeds or not since we don't expect to be able to do any better below
1073 // if it fails.
1074 //
1075 // Note that the returned SourceSurfaceCairo holds a strong reference to
1076 // the cairo_surface_t* that it wraps, which essencially means it holds a
1077 // strong reference to aSurface since aSurface shares its
1078 // cairo_surface_t*'s reference count variable. As a result we can't cache
1079 // srcBuffer on aSurface (see below) since aSurface would then hold a
1080 // strong reference back to srcBuffer, creating a reference loop and a
1081 // memory leak. Not caching is fine since wrapping is cheap enough (no
1082 // copying) so we can just wrap again next time we're called.
1083 return Factory::CreateSourceSurfaceForCairoSurface(aSurface->CairoSurface(),
1084 aSurface->GetSize(), format);
1085 }
1086
1087 RefPtr<SourceSurface> srcBuffer;
1088
1089 // Currently no other DrawTarget types implement CreateSourceSurfaceFromNativeSurface
1090
1091 if (!srcBuffer) {
1092 // If aSurface wraps data, we can create a SourceSurfaceRawData that wraps
1093 // the same data, then optimize it for aTarget:
1094 RefPtr<DataSourceSurface> surf = GetWrappedDataSourceSurface(aSurface);
1095 if (surf) {
1096 srcBuffer = aIsPlugin ? aTarget->OptimizeSourceSurfaceForUnknownAlpha(surf)
1097 : aTarget->OptimizeSourceSurface(surf);
1098
1099 if (srcBuffer == surf) {
1100 // GetWrappedDataSourceSurface returns a SourceSurface that holds a
1101 // strong reference to aSurface since it wraps aSurface's data and
1102 // needs it to stay alive. As a result we can't cache srcBuffer on
1103 // aSurface (below) since aSurface would then hold a strong reference
1104 // back to srcBuffer, creating a reference loop and a memory leak. Not
1105 // caching is fine since wrapping is cheap enough (no copying) so we
1106 // can just wrap again next time we're called.
1107 //
1108 // Note that the check below doesn't catch this since srcBuffer will be a
1109 // SourceSurfaceRawData object (even if aSurface is not a gfxImageSurface
1110 // object), which is why we need this separate check.
1111 return srcBuffer.forget();
1112 }
1113 }
1114 }
1115
1116 if (!srcBuffer) {
1117 MOZ_ASSERT(aTarget->GetBackendType() != BackendType::CAIRO,
1118 "We already tried CreateSourceSurfaceFromNativeSurface with a "
1119 "DrawTargetCairo above");
1120 // We've run out of performant options. We now try creating a SourceSurface
1121 // using a temporary DrawTargetCairo and then optimizing it to aTarget's
1122 // actual type. The CreateSourceSurfaceFromNativeSurface() call will
1123 // likely create a DataSourceSurface (possibly involving copying and/or
1124 // readback), and the OptimizeSourceSurface may well copy again and upload
1125 // to the GPU. So, while this code path is rarely hit, hitting it may be
1126 // very slow.
1127 srcBuffer = Factory::CreateSourceSurfaceForCairoSurface(aSurface->CairoSurface(),
1128 aSurface->GetSize(), format);
1129 if (srcBuffer) {
1130 srcBuffer = aTarget->OptimizeSourceSurface(srcBuffer);
1131 }
1132 }
1133
1134 if (!srcBuffer) {
1135 return nullptr;
1136 }
1137
1138 if ((srcBuffer->GetType() == SurfaceType::CAIRO &&
1139 static_cast<SourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
1140 aSurface->CairoSurface()) ||
1141 (srcBuffer->GetType() == SurfaceType::CAIRO_IMAGE &&
1142 static_cast<DataSourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
1143 aSurface->CairoSurface())) {
1144 // See the "Note that the returned SourceSurfaceCairo..." comment above.
1145 return srcBuffer.forget();
1146 }
1147
1148 // Add user data to aSurface so we can cache lookups in the future.
1149 SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
1150 srcSurfUD->mBackendType = aTarget->GetBackendType();
1151 srcSurfUD->mSrcSurface = srcBuffer;
1152 aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
1153
1154 return srcBuffer.forget();
1155 }
1156
1157 already_AddRefed<DataSourceSurface>
GetWrappedDataSourceSurface(gfxASurface * aSurface)1158 gfxPlatform::GetWrappedDataSourceSurface(gfxASurface* aSurface)
1159 {
1160 RefPtr<gfxImageSurface> image = aSurface->GetAsImageSurface();
1161 if (!image) {
1162 return nullptr;
1163 }
1164 RefPtr<DataSourceSurface> result =
1165 Factory::CreateWrappingDataSourceSurface(image->Data(),
1166 image->Stride(),
1167 image->GetSize(),
1168 ImageFormatToSurfaceFormat(image->Format()));
1169
1170 if (!result) {
1171 return nullptr;
1172 }
1173
1174 // If we wrapped the underlying data of aSurface, then we need to add user data
1175 // to make sure aSurface stays alive until we are done with the data.
1176 DependentSourceSurfaceUserData *srcSurfUD = new DependentSourceSurfaceUserData;
1177 srcSurfUD->mSurface = aSurface;
1178 result->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
1179
1180 return result.forget();
1181 }
1182
1183 already_AddRefed<ScaledFont>
GetScaledFontForFont(DrawTarget * aTarget,gfxFont * aFont)1184 gfxPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
1185 {
1186 NativeFont nativeFont;
1187 nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
1188 nativeFont.mFont = aFont->GetCairoScaledFont();
1189 return Factory::CreateScaledFontForNativeFont(nativeFont,
1190 aFont->GetAdjustedSize());
1191 }
1192
1193 void
ComputeTileSize()1194 gfxPlatform::ComputeTileSize()
1195 {
1196 // The tile size should be picked in the parent processes
1197 // and sent to the child processes over IPDL GetTileSize.
1198 if (!XRE_IsParentProcess()) {
1199 return;
1200 }
1201
1202 int32_t w = gfxPrefs::LayersTileWidth();
1203 int32_t h = gfxPrefs::LayersTileHeight();
1204
1205 if (gfxPrefs::LayersTilesAdjust()) {
1206 gfx::IntSize screenSize = GetScreenSize();
1207 if (screenSize.width > 0) {
1208 // Choose a size so that there are between 2 and 4 tiles per screen width.
1209 // FIXME: we should probably make sure this is within the max texture size,
1210 // but I think everything should at least support 1024
1211 w = h = clamped(int32_t(RoundUpPow2(screenSize.width)) / 4, 256, 1024);
1212 }
1213 }
1214
1215 // Don't allow changing the tile size after we've set it.
1216 // Right now the code assumes that the tile size doesn't change.
1217 MOZ_ASSERT(gfxVars::TileSize().width == -1 &&
1218 gfxVars::TileSize().height == -1);
1219
1220 gfxVars::SetTileSize(IntSize(w, h));
1221 }
1222
1223 void
PopulateScreenInfo()1224 gfxPlatform::PopulateScreenInfo()
1225 {
1226 nsCOMPtr<nsIScreenManager> manager = do_GetService("@mozilla.org/gfx/screenmanager;1");
1227 MOZ_ASSERT(manager, "failed to get nsIScreenManager");
1228
1229 nsCOMPtr<nsIScreen> screen;
1230 manager->GetPrimaryScreen(getter_AddRefs(screen));
1231 if (!screen) {
1232 // This can happen in xpcshell, for instance
1233 return;
1234 }
1235
1236 screen->GetColorDepth(&mScreenDepth);
1237
1238 int left, top;
1239 screen->GetRect(&left, &top, &mScreenSize.width, &mScreenSize.height);
1240 }
1241
1242 bool
SupportsAzureContentForDrawTarget(DrawTarget * aTarget)1243 gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget)
1244 {
1245 if (!aTarget || !aTarget->IsValid()) {
1246 return false;
1247 }
1248
1249 #ifdef USE_SKIA_GPU
1250 // Skia content rendering doesn't support GPU acceleration, so we can't
1251 // use the same backend if the current backend is accelerated.
1252 if ((aTarget->GetType() == DrawTargetType::HARDWARE_RASTER)
1253 && (aTarget->GetBackendType() == BackendType::SKIA))
1254 {
1255 return false;
1256 }
1257 #endif
1258
1259 return SupportsAzureContentForType(aTarget->GetBackendType());
1260 }
1261
AllowOpenGLCanvas()1262 bool gfxPlatform::AllowOpenGLCanvas()
1263 {
1264 // For now, only allow Skia+OpenGL, unless it's blocked.
1265 // Allow acceleration on Skia if the preference is set, unless it's blocked
1266 // as long as we have the accelerated layers
1267
1268 // The compositor backend is only set correctly in the parent process,
1269 // so we let content process always assume correct compositor backend.
1270 // The callers have to do the right thing.
1271 bool correctBackend = !XRE_IsParentProcess() ||
1272 ((mCompositorBackend == LayersBackend::LAYERS_OPENGL) &&
1273 (GetContentBackendFor(mCompositorBackend) == BackendType::SKIA));
1274
1275 if (gfxPrefs::CanvasAzureAccelerated() && correctBackend) {
1276 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
1277 int32_t status;
1278 nsCString discardFailureId;
1279 return !gfxInfo ||
1280 (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION,
1281 discardFailureId,
1282 &status)) &&
1283 status == nsIGfxInfo::FEATURE_STATUS_OK);
1284 }
1285 return false;
1286 }
1287
1288 void
InitializeSkiaCacheLimits()1289 gfxPlatform::InitializeSkiaCacheLimits()
1290 {
1291 if (AllowOpenGLCanvas()) {
1292 #ifdef USE_SKIA_GPU
1293 bool usingDynamicCache = gfxPrefs::CanvasSkiaGLDynamicCache();
1294 int cacheItemLimit = gfxPrefs::CanvasSkiaGLCacheItems();
1295 uint64_t cacheSizeLimit = std::max(gfxPrefs::CanvasSkiaGLCacheSize(), (int32_t)0);
1296
1297 // Prefs are in megabytes, but we want the sizes in bytes
1298 cacheSizeLimit *= 1024*1024;
1299
1300 if (usingDynamicCache) {
1301 if (mTotalSystemMemory < 512*1024*1024) {
1302 // We need a very minimal cache on anything smaller than 512mb.
1303 // Note the large jump as we cross 512mb (from 2mb to 32mb).
1304 cacheSizeLimit = 2*1024*1024;
1305 } else if (mTotalSystemMemory > 0) {
1306 cacheSizeLimit = mTotalSystemMemory / 16;
1307 }
1308 }
1309
1310 // Ensure cache size doesn't overflow on 32-bit platforms.
1311 cacheSizeLimit = std::min(cacheSizeLimit, (uint64_t)SIZE_MAX);
1312
1313 #ifdef DEBUG
1314 printf_stderr("Determined SkiaGL cache limits: Size %" PRIu64 ", Items: %i\n", cacheSizeLimit, cacheItemLimit);
1315 #endif
1316
1317 mSkiaGlue->GetGrContext()->setResourceCacheLimits(cacheItemLimit, (size_t)cacheSizeLimit);
1318 #endif
1319 }
1320 }
1321
1322 SkiaGLGlue*
GetSkiaGLGlue()1323 gfxPlatform::GetSkiaGLGlue()
1324 {
1325 #ifdef USE_SKIA_GPU
1326 // Check the accelerated Canvas is enabled for the first time,
1327 // because the callers should check it before using.
1328 if (!mSkiaGlue && !AllowOpenGLCanvas()) {
1329 return nullptr;
1330 }
1331
1332 if (!mSkiaGlue) {
1333 /* Dummy context. We always draw into a FBO.
1334 *
1335 * FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it
1336 * stands, this only works on the main thread.
1337 */
1338 RefPtr<GLContext> glContext;
1339 nsCString discardFailureId;
1340 glContext = GLContextProvider::CreateHeadless(CreateContextFlags::REQUIRE_COMPAT_PROFILE |
1341 CreateContextFlags::ALLOW_OFFLINE_RENDERER,
1342 &discardFailureId);
1343 if (!glContext) {
1344 printf_stderr("Failed to create GLContext for SkiaGL!\n");
1345 return nullptr;
1346 }
1347 mSkiaGlue = new SkiaGLGlue(glContext);
1348 MOZ_ASSERT(mSkiaGlue->GetGrContext(), "No GrContext");
1349 InitializeSkiaCacheLimits();
1350 }
1351 #endif
1352
1353 return mSkiaGlue;
1354 }
1355
1356 void
PurgeSkiaFontCache()1357 gfxPlatform::PurgeSkiaFontCache()
1358 {
1359 #ifdef USE_SKIA
1360 if (gfxPlatform::GetPlatform()->GetDefaultContentBackend() == BackendType::SKIA) {
1361 SkGraphics::PurgeFontCache();
1362 }
1363 #endif
1364 }
1365
1366 void
PurgeSkiaGPUCache()1367 gfxPlatform::PurgeSkiaGPUCache()
1368 {
1369 #ifdef USE_SKIA_GPU
1370 if (!mSkiaGlue)
1371 return;
1372
1373 mSkiaGlue->GetGrContext()->freeGpuResources();
1374 // GrContext::flush() doesn't call glFlush. Call it here.
1375 mSkiaGlue->GetGLContext()->MakeCurrent();
1376 mSkiaGlue->GetGLContext()->fFlush();
1377 #endif
1378 }
1379
1380 bool
HasEnoughTotalSystemMemoryForSkiaGL()1381 gfxPlatform::HasEnoughTotalSystemMemoryForSkiaGL()
1382 {
1383 return true;
1384 }
1385
1386 already_AddRefed<DrawTarget>
CreateDrawTargetForBackend(BackendType aBackend,const IntSize & aSize,SurfaceFormat aFormat)1387 gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat)
1388 {
1389 // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
1390 // create the best offscreen surface for the current system and situation. We
1391 // can easily take advantage of this for the Cairo backend, so that's what we
1392 // do.
1393 // mozilla::gfx::Factory can get away without having all this knowledge for
1394 // now, but this might need to change in the future (using
1395 // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all
1396 // backends).
1397 if (aBackend == BackendType::CAIRO) {
1398 RefPtr<gfxASurface> surf = CreateOffscreenSurface(aSize, SurfaceFormatToImageFormat(aFormat));
1399 if (!surf || surf->CairoStatus()) {
1400 return nullptr;
1401 }
1402
1403 return CreateDrawTargetForSurface(surf, aSize);
1404 } else {
1405 return Factory::CreateDrawTarget(aBackend, aSize, aFormat);
1406 }
1407 }
1408
1409 already_AddRefed<DrawTarget>
CreateOffscreenCanvasDrawTarget(const IntSize & aSize,SurfaceFormat aFormat)1410 gfxPlatform::CreateOffscreenCanvasDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
1411 {
1412 NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
1413 RefPtr<DrawTarget> target = CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat);
1414 if (target ||
1415 mFallbackCanvasBackend == BackendType::NONE) {
1416 return target.forget();
1417 }
1418
1419 #ifdef XP_WIN
1420 // On Windows, the fallback backend (Cairo) should use its image backend.
1421 return Factory::CreateDrawTarget(mFallbackCanvasBackend, aSize, aFormat);
1422 #else
1423 return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat);
1424 #endif
1425 }
1426
1427 already_AddRefed<DrawTarget>
CreateOffscreenContentDrawTarget(const IntSize & aSize,SurfaceFormat aFormat)1428 gfxPlatform::CreateOffscreenContentDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
1429 {
1430 NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
1431 return CreateDrawTargetForBackend(mContentBackend, aSize, aFormat);
1432 }
1433
1434 already_AddRefed<DrawTarget>
CreateSimilarSoftwareDrawTarget(DrawTarget * aDT,const IntSize & aSize,SurfaceFormat aFormat)1435 gfxPlatform::CreateSimilarSoftwareDrawTarget(DrawTarget* aDT,
1436 const IntSize& aSize,
1437 SurfaceFormat aFormat)
1438 {
1439 RefPtr<DrawTarget> dt;
1440
1441 if (Factory::DoesBackendSupportDataDrawtarget(aDT->GetBackendType())) {
1442 dt = aDT->CreateSimilarDrawTarget(aSize, aFormat);
1443 } else {
1444 dt = Factory::CreateDrawTarget(BackendType::SKIA, aSize, aFormat);
1445 }
1446
1447 return dt.forget();
1448 }
1449
1450 /* static */ already_AddRefed<DrawTarget>
CreateDrawTargetForData(unsigned char * aData,const IntSize & aSize,int32_t aStride,SurfaceFormat aFormat)1451 gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat)
1452 {
1453 BackendType backendType = gfxVars::ContentBackend();
1454 NS_ASSERTION(backendType != BackendType::NONE, "No backend.");
1455
1456 if (!Factory::DoesBackendSupportDataDrawtarget(backendType)) {
1457 backendType = BackendType::CAIRO;
1458 }
1459
1460 RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(backendType,
1461 aData, aSize,
1462 aStride, aFormat);
1463
1464 return dt.forget();
1465 }
1466
1467 /* static */ BackendType
BackendTypeForName(const nsCString & aName)1468 gfxPlatform::BackendTypeForName(const nsCString& aName)
1469 {
1470 if (aName.EqualsLiteral("cairo"))
1471 return BackendType::CAIRO;
1472 if (aName.EqualsLiteral("skia"))
1473 return BackendType::SKIA;
1474 if (aName.EqualsLiteral("direct2d"))
1475 return BackendType::DIRECT2D;
1476 if (aName.EqualsLiteral("direct2d1.1"))
1477 return BackendType::DIRECT2D1_1;
1478 return BackendType::NONE;
1479 }
1480
1481 nsresult
GetFontList(nsIAtom * aLangGroup,const nsACString & aGenericFamily,nsTArray<nsString> & aListOfFonts)1482 gfxPlatform::GetFontList(nsIAtom *aLangGroup,
1483 const nsACString& aGenericFamily,
1484 nsTArray<nsString>& aListOfFonts)
1485 {
1486 gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup,
1487 aGenericFamily,
1488 aListOfFonts);
1489 return NS_OK;
1490 }
1491
1492 nsresult
UpdateFontList()1493 gfxPlatform::UpdateFontList()
1494 {
1495 gfxPlatformFontList::PlatformFontList()->UpdateFontList();
1496 return NS_OK;
1497 }
1498
1499 nsresult
GetStandardFamilyName(const nsAString & aFontName,nsAString & aFamilyName)1500 gfxPlatform::GetStandardFamilyName(const nsAString& aFontName,
1501 nsAString& aFamilyName)
1502 {
1503 gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName,
1504 aFamilyName);
1505 return NS_OK;
1506 }
1507
1508 bool
DownloadableFontsEnabled()1509 gfxPlatform::DownloadableFontsEnabled()
1510 {
1511 if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
1512 mAllowDownloadableFonts =
1513 Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false);
1514 }
1515
1516 return mAllowDownloadableFonts;
1517 }
1518
1519 bool
UseCmapsDuringSystemFallback()1520 gfxPlatform::UseCmapsDuringSystemFallback()
1521 {
1522 if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) {
1523 mFallbackUsesCmaps =
1524 Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false);
1525 }
1526
1527 return mFallbackUsesCmaps;
1528 }
1529
1530 bool
OpenTypeSVGEnabled()1531 gfxPlatform::OpenTypeSVGEnabled()
1532 {
1533 if (mOpenTypeSVGEnabled == UNINITIALIZED_VALUE) {
1534 mOpenTypeSVGEnabled =
1535 Preferences::GetBool(GFX_PREF_OPENTYPE_SVG, false);
1536 }
1537
1538 return mOpenTypeSVGEnabled > 0;
1539 }
1540
1541 uint32_t
WordCacheCharLimit()1542 gfxPlatform::WordCacheCharLimit()
1543 {
1544 if (mWordCacheCharLimit == UNINITIALIZED_VALUE) {
1545 mWordCacheCharLimit =
1546 Preferences::GetInt(GFX_PREF_WORD_CACHE_CHARLIMIT, 32);
1547 if (mWordCacheCharLimit < 0) {
1548 mWordCacheCharLimit = 32;
1549 }
1550 }
1551
1552 return uint32_t(mWordCacheCharLimit);
1553 }
1554
1555 uint32_t
WordCacheMaxEntries()1556 gfxPlatform::WordCacheMaxEntries()
1557 {
1558 if (mWordCacheMaxEntries == UNINITIALIZED_VALUE) {
1559 mWordCacheMaxEntries =
1560 Preferences::GetInt(GFX_PREF_WORD_CACHE_MAXENTRIES, 10000);
1561 if (mWordCacheMaxEntries < 0) {
1562 mWordCacheMaxEntries = 10000;
1563 }
1564 }
1565
1566 return uint32_t(mWordCacheMaxEntries);
1567 }
1568
1569 bool
UseGraphiteShaping()1570 gfxPlatform::UseGraphiteShaping()
1571 {
1572 if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) {
1573 mGraphiteShapingEnabled =
1574 Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
1575 }
1576
1577 return mGraphiteShapingEnabled;
1578 }
1579
1580 gfxFontEntry*
LookupLocalFont(const nsAString & aFontName,uint16_t aWeight,int16_t aStretch,uint8_t aStyle)1581 gfxPlatform::LookupLocalFont(const nsAString& aFontName,
1582 uint16_t aWeight,
1583 int16_t aStretch,
1584 uint8_t aStyle)
1585 {
1586 return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aFontName,
1587 aWeight,
1588 aStretch,
1589 aStyle);
1590 }
1591
1592 gfxFontEntry*
MakePlatformFont(const nsAString & aFontName,uint16_t aWeight,int16_t aStretch,uint8_t aStyle,const uint8_t * aFontData,uint32_t aLength)1593 gfxPlatform::MakePlatformFont(const nsAString& aFontName,
1594 uint16_t aWeight,
1595 int16_t aStretch,
1596 uint8_t aStyle,
1597 const uint8_t* aFontData,
1598 uint32_t aLength)
1599 {
1600 return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aFontName,
1601 aWeight,
1602 aStretch,
1603 aStyle,
1604 aFontData,
1605 aLength);
1606 }
1607
1608 mozilla::layers::DiagnosticTypes
GetLayerDiagnosticTypes()1609 gfxPlatform::GetLayerDiagnosticTypes()
1610 {
1611 mozilla::layers::DiagnosticTypes type = DiagnosticTypes::NO_DIAGNOSTIC;
1612 if (gfxPrefs::DrawLayerBorders()) {
1613 type |= mozilla::layers::DiagnosticTypes::LAYER_BORDERS;
1614 }
1615 if (gfxPrefs::DrawTileBorders()) {
1616 type |= mozilla::layers::DiagnosticTypes::TILE_BORDERS;
1617 }
1618 if (gfxPrefs::DrawBigImageBorders()) {
1619 type |= mozilla::layers::DiagnosticTypes::BIGIMAGE_BORDERS;
1620 }
1621 if (gfxPrefs::FlashLayerBorders()) {
1622 type |= mozilla::layers::DiagnosticTypes::FLASH_BORDERS;
1623 }
1624 return type;
1625 }
1626
1627 void
InitBackendPrefs(uint32_t aCanvasBitmask,BackendType aCanvasDefault,uint32_t aContentBitmask,BackendType aContentDefault)1628 gfxPlatform::InitBackendPrefs(uint32_t aCanvasBitmask, BackendType aCanvasDefault,
1629 uint32_t aContentBitmask, BackendType aContentDefault)
1630 {
1631 mPreferredCanvasBackend = GetCanvasBackendPref(aCanvasBitmask);
1632 if (mPreferredCanvasBackend == BackendType::NONE) {
1633 mPreferredCanvasBackend = aCanvasDefault;
1634 }
1635
1636 if (mPreferredCanvasBackend == BackendType::DIRECT2D1_1) {
1637 // Falling back to D2D 1.0 won't help us here. When D2D 1.1 DT creation
1638 // fails it means the surface was too big or there's something wrong with
1639 // the device. D2D 1.0 will encounter a similar situation.
1640 mFallbackCanvasBackend =
1641 GetCanvasBackendPref(aCanvasBitmask &
1642 ~(BackendTypeBit(mPreferredCanvasBackend) | BackendTypeBit(BackendType::DIRECT2D)));
1643 } else {
1644 mFallbackCanvasBackend =
1645 GetCanvasBackendPref(aCanvasBitmask & ~BackendTypeBit(mPreferredCanvasBackend));
1646 }
1647
1648 mContentBackendBitmask = aContentBitmask;
1649 mContentBackend = GetContentBackendPref(mContentBackendBitmask);
1650 if (mContentBackend == BackendType::NONE) {
1651 mContentBackend = aContentDefault;
1652 // mContentBackendBitmask is our canonical reference for supported
1653 // backends so we need to add the default if we are using it and
1654 // overriding the prefs.
1655 mContentBackendBitmask |= BackendTypeBit(aContentDefault);
1656 }
1657
1658 if (XRE_IsParentProcess()) {
1659 gfxVars::SetContentBackend(mContentBackend);
1660 }
1661 }
1662
1663 /* static */ BackendType
GetCanvasBackendPref(uint32_t aBackendBitmask)1664 gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask)
1665 {
1666 return GetBackendPref("gfx.canvas.azure.backends", aBackendBitmask);
1667 }
1668
1669 /* static */ BackendType
GetContentBackendPref(uint32_t & aBackendBitmask)1670 gfxPlatform::GetContentBackendPref(uint32_t &aBackendBitmask)
1671 {
1672 return GetBackendPref("gfx.content.azure.backends", aBackendBitmask);
1673 }
1674
1675 /* static */ BackendType
GetBackendPref(const char * aBackendPrefName,uint32_t & aBackendBitmask)1676 gfxPlatform::GetBackendPref(const char* aBackendPrefName, uint32_t &aBackendBitmask)
1677 {
1678 nsTArray<nsCString> backendList;
1679 nsCString prefString;
1680 if (NS_SUCCEEDED(Preferences::GetCString(aBackendPrefName, &prefString))) {
1681 ParseString(prefString, ',', backendList);
1682 }
1683
1684 uint32_t allowedBackends = 0;
1685 BackendType result = BackendType::NONE;
1686 for (uint32_t i = 0; i < backendList.Length(); ++i) {
1687 BackendType type = BackendTypeForName(backendList[i]);
1688 if (BackendTypeBit(type) & aBackendBitmask) {
1689 allowedBackends |= BackendTypeBit(type);
1690 if (result == BackendType::NONE) {
1691 result = type;
1692 }
1693 }
1694 }
1695
1696 aBackendBitmask = allowedBackends;
1697 return result;
1698 }
1699
1700 bool
InSafeMode()1701 gfxPlatform::InSafeMode()
1702 {
1703 static bool sSafeModeInitialized = false;
1704 static bool sInSafeMode = false;
1705
1706 if (!sSafeModeInitialized) {
1707 sSafeModeInitialized = true;
1708 nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
1709 if (xr) {
1710 xr->GetInSafeMode(&sInSafeMode);
1711 }
1712 }
1713 return sInSafeMode;
1714 }
1715
1716 bool
OffMainThreadCompositingEnabled()1717 gfxPlatform::OffMainThreadCompositingEnabled()
1718 {
1719 return UsesOffMainThreadCompositing();
1720 }
1721
1722 eCMSMode
GetCMSMode()1723 gfxPlatform::GetCMSMode()
1724 {
1725 if (!gCMSInitialized) {
1726 int32_t mode = gfxPrefs::CMSMode();
1727 if (mode >= 0 && mode < eCMSMode_AllCount) {
1728 gCMSMode = static_cast<eCMSMode>(mode);
1729 }
1730
1731 bool enableV4 = gfxPrefs::CMSEnableV4();
1732 if (enableV4) {
1733 qcms_enable_iccv4();
1734 }
1735 gCMSInitialized = true;
1736 }
1737 return gCMSMode;
1738 }
1739
1740 int
GetRenderingIntent()1741 gfxPlatform::GetRenderingIntent()
1742 {
1743 // gfxPrefs.h is using 0 as the default for the rendering
1744 // intent preference, based on that being the value for
1745 // QCMS_INTENT_DEFAULT. Assert here to catch if that ever
1746 // changes and we can then figure out what to do about it.
1747 MOZ_ASSERT(QCMS_INTENT_DEFAULT == 0);
1748
1749 /* Try to query the pref system for a rendering intent. */
1750 int32_t pIntent = gfxPrefs::CMSRenderingIntent();
1751 if ((pIntent < QCMS_INTENT_MIN) || (pIntent > QCMS_INTENT_MAX)) {
1752 /* If the pref is out of range, use embedded profile. */
1753 pIntent = -1;
1754 }
1755 return pIntent;
1756 }
1757
1758 void
TransformPixel(const Color & in,Color & out,qcms_transform * transform)1759 gfxPlatform::TransformPixel(const Color& in, Color& out, qcms_transform *transform)
1760 {
1761
1762 if (transform) {
1763 /* we want the bytes in RGB order */
1764 #ifdef IS_LITTLE_ENDIAN
1765 /* ABGR puts the bytes in |RGBA| order on little endian */
1766 uint32_t packed = in.ToABGR();
1767 qcms_transform_data(transform,
1768 (uint8_t *)&packed, (uint8_t *)&packed,
1769 1);
1770 out = Color::FromABGR(packed);
1771 #else
1772 /* ARGB puts the bytes in |ARGB| order on big endian */
1773 uint32_t packed = in.UnusualToARGB();
1774 /* add one to move past the alpha byte */
1775 qcms_transform_data(transform,
1776 (uint8_t *)&packed + 1, (uint8_t *)&packed + 1,
1777 1);
1778 out = Color::UnusualFromARGB(packed);
1779 #endif
1780 }
1781
1782 else if (&out != &in)
1783 out = in;
1784 }
1785
1786 void
GetPlatformCMSOutputProfile(void * & mem,size_t & size)1787 gfxPlatform::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
1788 {
1789 mem = nullptr;
1790 size = 0;
1791 }
1792
1793 void
GetCMSOutputProfileData(void * & mem,size_t & size)1794 gfxPlatform::GetCMSOutputProfileData(void *&mem, size_t &size)
1795 {
1796 nsAdoptingCString fname = Preferences::GetCString("gfx.color_management.display_profile");
1797 if (!fname.IsEmpty()) {
1798 qcms_data_from_path(fname, &mem, &size);
1799 }
1800 else {
1801 gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile(mem, size);
1802 }
1803 }
1804
1805 void
CreateCMSOutputProfile()1806 gfxPlatform::CreateCMSOutputProfile()
1807 {
1808 if (!gCMSOutputProfile) {
1809 /* Determine if we're using the internal override to force sRGB as
1810 an output profile for reftests. See Bug 452125.
1811
1812 Note that we don't normally (outside of tests) set a
1813 default value of this preference, which means nsIPrefBranch::GetBoolPref
1814 will typically throw (and leave its out-param untouched).
1815 */
1816 if (Preferences::GetBool(GFX_PREF_CMS_FORCE_SRGB, false)) {
1817 gCMSOutputProfile = GetCMSsRGBProfile();
1818 }
1819
1820 if (!gCMSOutputProfile) {
1821 void* mem = nullptr;
1822 size_t size = 0;
1823
1824 GetCMSOutputProfileData(mem, size);
1825 if ((mem != nullptr) && (size > 0)) {
1826 gCMSOutputProfile = qcms_profile_from_memory(mem, size);
1827 free(mem);
1828 }
1829 }
1830
1831 /* Determine if the profile looks bogus. If so, close the profile
1832 * and use sRGB instead. See bug 460629, */
1833 if (gCMSOutputProfile && qcms_profile_is_bogus(gCMSOutputProfile)) {
1834 NS_ASSERTION(gCMSOutputProfile != GetCMSsRGBProfile(),
1835 "Builtin sRGB profile tagged as bogus!!!");
1836 qcms_profile_release(gCMSOutputProfile);
1837 gCMSOutputProfile = nullptr;
1838 }
1839
1840 if (!gCMSOutputProfile) {
1841 gCMSOutputProfile = GetCMSsRGBProfile();
1842 }
1843 /* Precache the LUT16 Interpolations for the output profile. See
1844 bug 444661 for details. */
1845 qcms_profile_precache_output_transform(gCMSOutputProfile);
1846 }
1847 }
1848
1849 qcms_profile *
GetCMSOutputProfile()1850 gfxPlatform::GetCMSOutputProfile()
1851 {
1852 return gCMSOutputProfile;
1853 }
1854
1855 qcms_profile *
GetCMSsRGBProfile()1856 gfxPlatform::GetCMSsRGBProfile()
1857 {
1858 if (!gCMSsRGBProfile) {
1859
1860 /* Create the profile using qcms. */
1861 gCMSsRGBProfile = qcms_profile_sRGB();
1862 }
1863 return gCMSsRGBProfile;
1864 }
1865
1866 qcms_transform *
GetCMSRGBTransform()1867 gfxPlatform::GetCMSRGBTransform()
1868 {
1869 if (!gCMSRGBTransform) {
1870 qcms_profile *inProfile, *outProfile;
1871 outProfile = GetCMSOutputProfile();
1872 inProfile = GetCMSsRGBProfile();
1873
1874 if (!inProfile || !outProfile)
1875 return nullptr;
1876
1877 gCMSRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
1878 outProfile, QCMS_DATA_RGB_8,
1879 QCMS_INTENT_PERCEPTUAL);
1880 }
1881
1882 return gCMSRGBTransform;
1883 }
1884
1885 qcms_transform *
GetCMSInverseRGBTransform()1886 gfxPlatform::GetCMSInverseRGBTransform()
1887 {
1888 if (!gCMSInverseRGBTransform) {
1889 qcms_profile *inProfile, *outProfile;
1890 inProfile = GetCMSOutputProfile();
1891 outProfile = GetCMSsRGBProfile();
1892
1893 if (!inProfile || !outProfile)
1894 return nullptr;
1895
1896 gCMSInverseRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
1897 outProfile, QCMS_DATA_RGB_8,
1898 QCMS_INTENT_PERCEPTUAL);
1899 }
1900
1901 return gCMSInverseRGBTransform;
1902 }
1903
1904 qcms_transform *
GetCMSRGBATransform()1905 gfxPlatform::GetCMSRGBATransform()
1906 {
1907 if (!gCMSRGBATransform) {
1908 qcms_profile *inProfile, *outProfile;
1909 outProfile = GetCMSOutputProfile();
1910 inProfile = GetCMSsRGBProfile();
1911
1912 if (!inProfile || !outProfile)
1913 return nullptr;
1914
1915 gCMSRGBATransform = qcms_transform_create(inProfile, QCMS_DATA_RGBA_8,
1916 outProfile, QCMS_DATA_RGBA_8,
1917 QCMS_INTENT_PERCEPTUAL);
1918 }
1919
1920 return gCMSRGBATransform;
1921 }
1922
1923 /* Shuts down various transforms and profiles for CMS. */
ShutdownCMS()1924 static void ShutdownCMS()
1925 {
1926
1927 if (gCMSRGBTransform) {
1928 qcms_transform_release(gCMSRGBTransform);
1929 gCMSRGBTransform = nullptr;
1930 }
1931 if (gCMSInverseRGBTransform) {
1932 qcms_transform_release(gCMSInverseRGBTransform);
1933 gCMSInverseRGBTransform = nullptr;
1934 }
1935 if (gCMSRGBATransform) {
1936 qcms_transform_release(gCMSRGBATransform);
1937 gCMSRGBATransform = nullptr;
1938 }
1939 if (gCMSOutputProfile) {
1940 qcms_profile_release(gCMSOutputProfile);
1941
1942 // handle the aliased case
1943 if (gCMSsRGBProfile == gCMSOutputProfile)
1944 gCMSsRGBProfile = nullptr;
1945 gCMSOutputProfile = nullptr;
1946 }
1947 if (gCMSsRGBProfile) {
1948 qcms_profile_release(gCMSsRGBProfile);
1949 gCMSsRGBProfile = nullptr;
1950 }
1951
1952 // Reset the state variables
1953 gCMSMode = eCMSMode_Off;
1954 gCMSInitialized = false;
1955 }
1956
1957 // default SetupClusterBoundaries, based on Unicode properties;
1958 // platform subclasses may override if they wish
1959 void
SetupClusterBoundaries(gfxTextRun * aTextRun,const char16_t * aString)1960 gfxPlatform::SetupClusterBoundaries(gfxTextRun *aTextRun, const char16_t *aString)
1961 {
1962 if (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) {
1963 // 8-bit text doesn't have clusters.
1964 // XXX is this true in all languages???
1965 // behdad: don't think so. Czech for example IIRC has a
1966 // 'ch' grapheme.
1967 // jfkthame: but that's not expected to behave as a grapheme cluster
1968 // for selection/editing/etc.
1969 return;
1970 }
1971
1972 aTextRun->SetupClusterBoundaries(0, aString, aTextRun->GetLength());
1973 }
1974
1975 int32_t
GetBidiNumeralOption()1976 gfxPlatform::GetBidiNumeralOption()
1977 {
1978 if (mBidiNumeralOption == UNINITIALIZED_VALUE) {
1979 mBidiNumeralOption = Preferences::GetInt(BIDI_NUMERAL_PREF, 0);
1980 }
1981 return mBidiNumeralOption;
1982 }
1983
1984 /* static */ void
FlushFontAndWordCaches()1985 gfxPlatform::FlushFontAndWordCaches()
1986 {
1987 gfxFontCache *fontCache = gfxFontCache::GetCache();
1988 if (fontCache) {
1989 fontCache->AgeAllGenerations();
1990 fontCache->FlushShapedWordCaches();
1991 }
1992
1993 gfxPlatform::PurgeSkiaFontCache();
1994 }
1995
1996 void
FontsPrefsChanged(const char * aPref)1997 gfxPlatform::FontsPrefsChanged(const char *aPref)
1998 {
1999 NS_ASSERTION(aPref != nullptr, "null preference");
2000 if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) {
2001 mAllowDownloadableFonts = UNINITIALIZED_VALUE;
2002 } else if (!strcmp(GFX_PREF_FALLBACK_USE_CMAPS, aPref)) {
2003 mFallbackUsesCmaps = UNINITIALIZED_VALUE;
2004 } else if (!strcmp(GFX_PREF_WORD_CACHE_CHARLIMIT, aPref)) {
2005 mWordCacheCharLimit = UNINITIALIZED_VALUE;
2006 FlushFontAndWordCaches();
2007 } else if (!strcmp(GFX_PREF_WORD_CACHE_MAXENTRIES, aPref)) {
2008 mWordCacheMaxEntries = UNINITIALIZED_VALUE;
2009 FlushFontAndWordCaches();
2010 } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
2011 mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
2012 FlushFontAndWordCaches();
2013 } else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) {
2014 mBidiNumeralOption = UNINITIALIZED_VALUE;
2015 } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) {
2016 mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
2017 gfxFontCache::GetCache()->AgeAllGenerations();
2018 }
2019 }
2020
2021
2022 mozilla::LogModule*
GetLog(eGfxLog aWhichLog)2023 gfxPlatform::GetLog(eGfxLog aWhichLog)
2024 {
2025 // logs shared across gfx
2026 static LazyLogModule sFontlistLog("fontlist");
2027 static LazyLogModule sFontInitLog("fontinit");
2028 static LazyLogModule sTextrunLog("textrun");
2029 static LazyLogModule sTextrunuiLog("textrunui");
2030 static LazyLogModule sCmapDataLog("cmapdata");
2031 static LazyLogModule sTextPerfLog("textperf");
2032
2033 switch (aWhichLog) {
2034 case eGfxLog_fontlist:
2035 return sFontlistLog;
2036 case eGfxLog_fontinit:
2037 return sFontInitLog;
2038 case eGfxLog_textrun:
2039 return sTextrunLog;
2040 case eGfxLog_textrunui:
2041 return sTextrunuiLog;
2042 case eGfxLog_cmapdata:
2043 return sCmapDataLog;
2044 case eGfxLog_textperf:
2045 return sTextPerfLog;
2046 }
2047
2048 MOZ_ASSERT_UNREACHABLE("Unexpected log type");
2049 return nullptr;
2050 }
2051
2052 mozilla::gfx::SurfaceFormat
Optimal2DFormatForContent(gfxContentType aContent)2053 gfxPlatform::Optimal2DFormatForContent(gfxContentType aContent)
2054 {
2055 switch (aContent) {
2056 case gfxContentType::COLOR:
2057 switch (GetOffscreenFormat()) {
2058 case SurfaceFormat::A8R8G8B8_UINT32:
2059 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2060 case SurfaceFormat::X8R8G8B8_UINT32:
2061 return mozilla::gfx::SurfaceFormat::B8G8R8X8;
2062 case SurfaceFormat::R5G6B5_UINT16:
2063 return mozilla::gfx::SurfaceFormat::R5G6B5_UINT16;
2064 default:
2065 NS_NOTREACHED("unknown gfxImageFormat for gfxContentType::COLOR");
2066 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2067 }
2068 case gfxContentType::ALPHA:
2069 return mozilla::gfx::SurfaceFormat::A8;
2070 case gfxContentType::COLOR_ALPHA:
2071 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2072 default:
2073 NS_NOTREACHED("unknown gfxContentType");
2074 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2075 }
2076 }
2077
2078 gfxImageFormat
OptimalFormatForContent(gfxContentType aContent)2079 gfxPlatform::OptimalFormatForContent(gfxContentType aContent)
2080 {
2081 switch (aContent) {
2082 case gfxContentType::COLOR:
2083 return GetOffscreenFormat();
2084 case gfxContentType::ALPHA:
2085 return SurfaceFormat::A8;
2086 case gfxContentType::COLOR_ALPHA:
2087 return SurfaceFormat::A8R8G8B8_UINT32;
2088 default:
2089 NS_NOTREACHED("unknown gfxContentType");
2090 return SurfaceFormat::A8R8G8B8_UINT32;
2091 }
2092 }
2093
2094 /**
2095 * There are a number of layers acceleration (or layers in general) preferences
2096 * that should be consistent for the lifetime of the application (bug 840967).
2097 * As such, we will evaluate them all as soon as one of them is evaluated
2098 * and remember the values. Changing these preferences during the run will
2099 * not have any effect until we restart.
2100 */
2101 static mozilla::Atomic<bool> sLayersSupportsHardwareVideoDecoding(false);
2102 static bool sLayersHardwareVideoDecodingFailed = false;
2103 static bool sBufferRotationCheckPref = true;
2104
2105 static mozilla::Atomic<bool> sLayersAccelerationPrefsInitialized(false);
2106
VideoDecodingFailedChangedCallback(const char * aPref,void *)2107 void VideoDecodingFailedChangedCallback(const char* aPref, void*)
2108 {
2109 sLayersHardwareVideoDecodingFailed = Preferences::GetBool(aPref, false);
2110 gfxPlatform::GetPlatform()->UpdateCanUseHardwareVideoDecoding();
2111 }
2112
2113 void
UpdateCanUseHardwareVideoDecoding()2114 gfxPlatform::UpdateCanUseHardwareVideoDecoding()
2115 {
2116 if (XRE_IsParentProcess()) {
2117 gfxVars::SetCanUseHardwareVideoDecoding(CanUseHardwareVideoDecoding());
2118 }
2119 }
2120
2121 void
InitAcceleration()2122 gfxPlatform::InitAcceleration()
2123 {
2124 if (sLayersAccelerationPrefsInitialized) {
2125 return;
2126 }
2127
2128 InitCompositorAccelerationPrefs();
2129
2130 // If this is called for the first time on a non-main thread, we're screwed.
2131 // At the moment there's no explicit guarantee that the main thread calls
2132 // this before the compositor thread, but let's at least make the assumption
2133 // explicit.
2134 MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread");
2135
2136 gfxPrefs::GetSingleton();
2137
2138 if (XRE_IsParentProcess()) {
2139 gfxVars::SetBrowserTabsRemoteAutostart(BrowserTabsRemoteAutostart());
2140 gfxVars::SetOffscreenFormat(GetOffscreenFormat());
2141 gfxVars::SetRequiresAcceleratedGLContextForCompositorOGL(
2142 RequiresAcceleratedGLContextForCompositorOGL());
2143 }
2144
2145 nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
2146 nsCString discardFailureId;
2147 int32_t status;
2148
2149 if (Preferences::GetBool("media.hardware-video-decoding.enabled", false) &&
2150 #ifdef XP_WIN
2151 Preferences::GetBool("media.windows-media-foundation.use-dxva", true) &&
2152 #endif
2153 NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING,
2154 discardFailureId, &status))) {
2155 if (status == nsIGfxInfo::FEATURE_STATUS_OK || gfxPrefs::HardwareVideoDecodingForceEnabled()) {
2156 sLayersSupportsHardwareVideoDecoding = true;
2157 }
2158 }
2159
2160 sLayersAccelerationPrefsInitialized = true;
2161
2162 if (XRE_IsParentProcess()) {
2163 Preferences::RegisterCallbackAndCall(VideoDecodingFailedChangedCallback,
2164 "media.hardware-video-decoding.failed",
2165 nullptr,
2166 Preferences::ExactMatch);
2167 InitGPUProcessPrefs();
2168 }
2169 }
2170
2171 void
InitGPUProcessPrefs()2172 gfxPlatform::InitGPUProcessPrefs()
2173 {
2174 // We want to hide this from about:support, so only set a default if the
2175 // pref is known to be true.
2176 if (!gfxPrefs::GPUProcessDevEnabled() && !gfxPrefs::GPUProcessDevForceEnabled()) {
2177 return;
2178 }
2179
2180 FeatureState& gpuProc = gfxConfig::GetFeature(Feature::GPU_PROCESS);
2181
2182 gpuProc.SetDefaultFromPref(
2183 gfxPrefs::GetGPUProcessDevEnabledPrefName(),
2184 true,
2185 gfxPrefs::GetGPUProcessDevEnabledPrefDefault());
2186
2187 if (gfxPrefs::GPUProcessDevForceEnabled()) {
2188 gpuProc.UserForceEnable("User force-enabled via pref");
2189 }
2190
2191 // We require E10S - otherwise, there is very little benefit to the GPU
2192 // process, since the UI process must still use acceleration for
2193 // performance.
2194 if (!BrowserTabsRemoteAutostart()) {
2195 gpuProc.ForceDisable(
2196 FeatureStatus::Unavailable,
2197 "Multi-process mode is not enabled",
2198 NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_E10S"));
2199 return;
2200 }
2201 if (InSafeMode()) {
2202 gpuProc.ForceDisable(
2203 FeatureStatus::Blocked,
2204 "Safe-mode is enabled",
2205 NS_LITERAL_CSTRING("FEATURE_FAILURE_SAFE_MODE"));
2206 return;
2207 }
2208 if (gfxPrefs::LayerScopeEnabled()) {
2209 gpuProc.ForceDisable(
2210 FeatureStatus::Blocked,
2211 "LayerScope does not work in the GPU process",
2212 NS_LITERAL_CSTRING("FEATURE_FAILURE_LAYERSCOPE"));
2213 return;
2214 }
2215 }
2216
2217 void
InitCompositorAccelerationPrefs()2218 gfxPlatform::InitCompositorAccelerationPrefs()
2219 {
2220 const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
2221
2222 FeatureState& feature = gfxConfig::GetFeature(Feature::HW_COMPOSITING);
2223
2224 // Base value - does the platform allow acceleration?
2225 if (feature.SetDefault(AccelerateLayersByDefault(),
2226 FeatureStatus::Blocked,
2227 "Acceleration blocked by platform"))
2228 {
2229 if (gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly()) {
2230 feature.UserDisable("Disabled by pref",
2231 NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_PREF"));
2232 } else if (acceleratedEnv && *acceleratedEnv == '0') {
2233 feature.UserDisable("Disabled by envvar",
2234 NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_ENV"));
2235 }
2236 } else {
2237 if (acceleratedEnv && *acceleratedEnv == '1') {
2238 feature.UserEnable("Enabled by envvar");
2239 }
2240 }
2241
2242 // This has specific meaning elsewhere, so we always record it.
2243 if (gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly()) {
2244 feature.UserForceEnable("Force-enabled by pref");
2245 }
2246
2247 // Safe mode trumps everything.
2248 if (InSafeMode()) {
2249 feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by safe-mode",
2250 NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_SAFEMODE"));
2251 }
2252 }
2253
2254 bool
CanUseHardwareVideoDecoding()2255 gfxPlatform::CanUseHardwareVideoDecoding()
2256 {
2257 // this function is called from the compositor thread, so it is not
2258 // safe to init the prefs etc. from here.
2259 MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
2260 return sLayersSupportsHardwareVideoDecoding && !sLayersHardwareVideoDecodingFailed;
2261 }
2262
2263 bool
AccelerateLayersByDefault()2264 gfxPlatform::AccelerateLayersByDefault()
2265 {
2266 #if defined(MOZ_GL_PROVIDER) || defined(MOZ_WIDGET_UIKIT)
2267 return true;
2268 #else
2269 return false;
2270 #endif
2271 }
2272
2273 bool
BufferRotationEnabled()2274 gfxPlatform::BufferRotationEnabled()
2275 {
2276 MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
2277
2278 return sBufferRotationCheckPref && gfxPrefs::BufferRotationEnabled();
2279 }
2280
2281 void
DisableBufferRotation()2282 gfxPlatform::DisableBufferRotation()
2283 {
2284 MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
2285
2286 sBufferRotationCheckPref = false;
2287 }
2288
2289 already_AddRefed<ScaledFont>
GetScaledFontForFontWithCairoSkia(DrawTarget * aTarget,gfxFont * aFont)2290 gfxPlatform::GetScaledFontForFontWithCairoSkia(DrawTarget* aTarget, gfxFont* aFont)
2291 {
2292 NativeFont nativeFont;
2293 if (aTarget->GetBackendType() == BackendType::CAIRO || aTarget->GetBackendType() == BackendType::SKIA) {
2294 nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
2295 nativeFont.mFont = aFont->GetCairoScaledFont();
2296 return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize());
2297 }
2298
2299 return nullptr;
2300 }
2301
2302 /* static */ bool
UsesOffMainThreadCompositing()2303 gfxPlatform::UsesOffMainThreadCompositing()
2304 {
2305 if (XRE_GetProcessType() == GeckoProcessType_GPU) {
2306 return true;
2307 }
2308
2309 static bool firstTime = true;
2310 static bool result = false;
2311
2312 if (firstTime) {
2313 MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
2314 result =
2315 gfxVars::BrowserTabsRemoteAutostart() ||
2316 !gfxPrefs::LayersOffMainThreadCompositionForceDisabled();
2317 #if defined(MOZ_WIDGET_GTK)
2318 // Linux users who chose OpenGL are being grandfathered in to OMTC
2319 result |= gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly();
2320
2321 #endif
2322 firstTime = false;
2323 }
2324
2325 return result;
2326 }
2327
2328 /***
2329 * The preference "layout.frame_rate" has 3 meanings depending on the value:
2330 *
2331 * -1 = Auto (default), use hardware vsync or software vsync @ 60 hz if hw vsync fails.
2332 * 0 = ASAP mode - used during talos testing.
2333 * X = Software vsync at a rate of X times per second.
2334 */
2335 already_AddRefed<mozilla::gfx::VsyncSource>
CreateHardwareVsyncSource()2336 gfxPlatform::CreateHardwareVsyncSource()
2337 {
2338 RefPtr<mozilla::gfx::VsyncSource> softwareVsync = new SoftwareVsyncSource();
2339 return softwareVsync.forget();
2340 }
2341
2342 /* static */ bool
IsInLayoutAsapMode()2343 gfxPlatform::IsInLayoutAsapMode()
2344 {
2345 // There are 2 modes of ASAP mode.
2346 // 1 is that the refresh driver and compositor are in lock step
2347 // the second is that the compositor goes ASAP and the refresh driver
2348 // goes at whatever the configurated rate is. This only checks the version
2349 // talos uses, which is the refresh driver and compositor are in lockstep.
2350 return gfxPrefs::LayoutFrameRate() == 0;
2351 }
2352
2353 /* static */ bool
ForceSoftwareVsync()2354 gfxPlatform::ForceSoftwareVsync()
2355 {
2356 return gfxPrefs::LayoutFrameRate() > 0;
2357 }
2358
2359 /* static */ int
GetSoftwareVsyncRate()2360 gfxPlatform::GetSoftwareVsyncRate()
2361 {
2362 int preferenceRate = gfxPrefs::LayoutFrameRate();
2363 if (preferenceRate <= 0) {
2364 return gfxPlatform::GetDefaultFrameRate();
2365 }
2366 return preferenceRate;
2367 }
2368
2369 /* static */ int
GetDefaultFrameRate()2370 gfxPlatform::GetDefaultFrameRate()
2371 {
2372 return 60;
2373 }
2374
2375 void
GetApzSupportInfo(mozilla::widget::InfoObject & aObj)2376 gfxPlatform::GetApzSupportInfo(mozilla::widget::InfoObject& aObj)
2377 {
2378 if (!gfxPlatform::AsyncPanZoomEnabled()) {
2379 return;
2380 }
2381
2382 if (SupportsApzWheelInput()) {
2383 aObj.DefineProperty("ApzWheelInput", 1);
2384 }
2385
2386 if (SupportsApzTouchInput()) {
2387 aObj.DefineProperty("ApzTouchInput", 1);
2388 }
2389
2390 if (SupportsApzDragInput()) {
2391 aObj.DefineProperty("ApzDragInput", 1);
2392 }
2393 }
2394
2395 void
GetTilesSupportInfo(mozilla::widget::InfoObject & aObj)2396 gfxPlatform::GetTilesSupportInfo(mozilla::widget::InfoObject& aObj)
2397 {
2398 if (!gfxPrefs::LayersTilesEnabled()) {
2399 return;
2400 }
2401
2402 IntSize tileSize = gfxVars::TileSize();
2403 aObj.DefineProperty("TileHeight", tileSize.height);
2404 aObj.DefineProperty("TileWidth", tileSize.width);
2405 }
2406
2407 /*static*/ bool
AsyncPanZoomEnabled()2408 gfxPlatform::AsyncPanZoomEnabled()
2409 {
2410 #if !defined(MOZ_B2G) && !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_UIKIT)
2411 // For XUL applications (everything but B2G on mobile and desktop, and
2412 // Firefox on Android) we only want to use APZ when E10S is enabled. If
2413 // we ever get input events off the main thread we can consider relaxing
2414 // this requirement.
2415 if (!BrowserTabsRemoteAutostart()) {
2416 return false;
2417 }
2418 #endif
2419 #ifdef MOZ_WIDGET_ANDROID
2420 return true;
2421 #else
2422 return gfxPrefs::AsyncPanZoomEnabledDoNotUseDirectly();
2423 #endif
2424 }
2425
2426 /*static*/ bool
PerfWarnings()2427 gfxPlatform::PerfWarnings()
2428 {
2429 return gfxPrefs::PerfWarnings();
2430 }
2431
2432 void
GetAcceleratedCompositorBackends(nsTArray<LayersBackend> & aBackends)2433 gfxPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends)
2434 {
2435 if (gfxConfig::IsEnabled(Feature::OPENGL_COMPOSITING)) {
2436 aBackends.AppendElement(LayersBackend::LAYERS_OPENGL);
2437 }
2438 else {
2439 static int tell_me_once = 0;
2440 if (!tell_me_once) {
2441 NS_WARNING("OpenGL-accelerated layers are not supported on this system");
2442 tell_me_once = 1;
2443 }
2444 #ifdef MOZ_WIDGET_ANDROID
2445 NS_RUNTIMEABORT("OpenGL-accelerated layers are a hard requirement on this platform. "
2446 "Cannot continue without support for them");
2447 #endif
2448 }
2449 }
2450
2451 void
GetCompositorBackends(bool useAcceleration,nsTArray<mozilla::layers::LayersBackend> & aBackends)2452 gfxPlatform::GetCompositorBackends(bool useAcceleration, nsTArray<mozilla::layers::LayersBackend>& aBackends)
2453 {
2454 if (useAcceleration) {
2455 GetAcceleratedCompositorBackends(aBackends);
2456 }
2457 aBackends.AppendElement(LayersBackend::LAYERS_BASIC);
2458 }
2459
2460 void
NotifyCompositorCreated(LayersBackend aBackend)2461 gfxPlatform::NotifyCompositorCreated(LayersBackend aBackend)
2462 {
2463 if (mCompositorBackend == aBackend) {
2464 return;
2465 }
2466
2467 if (mCompositorBackend != LayersBackend::LAYERS_NONE) {
2468 gfxCriticalNote << "Compositors might be mixed ("
2469 << int(mCompositorBackend) << "," << int(aBackend) << ")";
2470 }
2471
2472 // Set the backend before we notify so it's available immediately.
2473 mCompositorBackend = aBackend;
2474
2475 // Notify that we created a compositor, so telemetry can update.
2476 NS_DispatchToMainThread(NS_NewRunnableFunction([] {
2477 if (nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService()) {
2478 obsvc->NotifyObservers(nullptr, "compositor:created", nullptr);
2479 }
2480 }));
2481 }
2482
2483 void
FetchAndImportContentDeviceData()2484 gfxPlatform::FetchAndImportContentDeviceData()
2485 {
2486 MOZ_ASSERT(XRE_IsContentProcess());
2487
2488 mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
2489
2490 mozilla::gfx::ContentDeviceData data;
2491 cc->SendGetGraphicsDeviceInitData(&data);
2492
2493 ImportContentDeviceData(data);
2494 }
2495
2496 void
ImportContentDeviceData(const mozilla::gfx::ContentDeviceData & aData)2497 gfxPlatform::ImportContentDeviceData(const mozilla::gfx::ContentDeviceData& aData)
2498 {
2499 MOZ_ASSERT(XRE_IsContentProcess());
2500
2501 const DevicePrefs& prefs = aData.prefs();
2502 gfxConfig::Inherit(Feature::HW_COMPOSITING, prefs.hwCompositing());
2503 gfxConfig::Inherit(Feature::OPENGL_COMPOSITING, prefs.oglCompositing());
2504 }
2505
2506 void
BuildContentDeviceData(mozilla::gfx::ContentDeviceData * aOut)2507 gfxPlatform::BuildContentDeviceData(mozilla::gfx::ContentDeviceData* aOut)
2508 {
2509 MOZ_ASSERT(XRE_IsParentProcess());
2510
2511 // Make sure our settings are synchronized from the GPU process.
2512 GPUProcessManager::Get()->EnsureGPUReady();
2513
2514 aOut->prefs().hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING);
2515 aOut->prefs().oglCompositing() = gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
2516 }
2517
2518 void
ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData & aData)2519 gfxPlatform::ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData)
2520 {
2521 MOZ_ASSERT(XRE_IsParentProcess());
2522
2523 gfxConfig::ImportChange(Feature::OPENGL_COMPOSITING, aData.oglCompositing());
2524 }
2525
2526 bool
SupportsApzDragInput() const2527 gfxPlatform::SupportsApzDragInput() const
2528 {
2529 return gfxPrefs::APZDragEnabled();
2530 }
2531
2532 void
BumpDeviceCounter()2533 gfxPlatform::BumpDeviceCounter()
2534 {
2535 mDeviceCounter++;
2536 }
2537
2538 void
InitOpenGLConfig()2539 gfxPlatform::InitOpenGLConfig()
2540 {
2541 #ifdef XP_WIN
2542 // Don't enable by default on Windows, since it could show up in about:support even
2543 // though it'll never get used. Only attempt if user enables the pref
2544 if (!Preferences::GetBool("layers.prefer-opengl")){
2545 return;
2546 }
2547 #endif
2548
2549 FeatureState& openGLFeature = gfxConfig::GetFeature(Feature::OPENGL_COMPOSITING);
2550
2551 // Check to see hw comp supported
2552 if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
2553 openGLFeature.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled",
2554 NS_LITERAL_CSTRING("FEATURE_FAILURE_OPENGL_NEED_HWCOMP"));
2555 return;
2556 }
2557
2558 #ifdef XP_WIN
2559 openGLFeature.SetDefaultFromPref(
2560 gfxPrefs::GetLayersPreferOpenGLPrefName(),
2561 true,
2562 gfxPrefs::GetLayersPreferOpenGLPrefDefault());
2563 #else
2564 openGLFeature.EnableByDefault();
2565 #endif
2566
2567 // When layers acceleration is force-enabled, enable it even for blacklisted
2568 // devices.
2569 if (gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly()) {
2570 openGLFeature.UserForceEnable("Force-enabled by pref");
2571 return;
2572 }
2573
2574 nsCString message;
2575 nsCString failureId;
2576 if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &message, failureId)) {
2577 openGLFeature.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
2578 }
2579 }
2580
2581 bool
IsGfxInfoStatusOkay(int32_t aFeature,nsCString * aOutMessage,nsCString & aFailureId)2582 gfxPlatform::IsGfxInfoStatusOkay(int32_t aFeature, nsCString* aOutMessage, nsCString& aFailureId)
2583 {
2584 nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
2585 if (!gfxInfo) {
2586 return true;
2587 }
2588
2589 int32_t status;
2590 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, aFailureId, &status)) &&
2591 status != nsIGfxInfo::FEATURE_STATUS_OK)
2592 {
2593 aOutMessage->AssignLiteral("#BLOCKLIST_");
2594 aOutMessage->AppendASCII(aFailureId.get());
2595 return false;
2596 }
2597
2598 return true;
2599 }
2600