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