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