Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifdef MOZ_LOGGING
7 #define FORCE_PR_LOG /* Allow logging in the release build */
8 #endif
10 #include "mozilla/layers/CompositorChild.h"
11 #include "mozilla/layers/CompositorParent.h"
12 #include "mozilla/layers/ImageBridgeChild.h"
13 #include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter
15 #include "prlog.h"
17 #include "gfxPlatform.h"
18 #include "gfxPrefs.h"
20 #ifdef XP_WIN
21 #include <process.h>
22 #define getpid _getpid
23 #else
24 #include <unistd.h>
25 #endif
27 #include "nsXULAppAPI.h"
28 #include "nsDirectoryServiceUtils.h"
29 #include "nsDirectoryServiceDefs.h"
31 #if defined(XP_WIN)
32 #include "gfxWindowsPlatform.h"
33 #include "gfxD2DSurface.h"
34 #elif defined(XP_MACOSX)
35 #include "gfxPlatformMac.h"
36 #include "gfxQuartzSurface.h"
37 #elif defined(MOZ_WIDGET_GTK)
38 #include "gfxPlatformGtk.h"
39 #elif defined(MOZ_WIDGET_QT)
40 #include "gfxQtPlatform.h"
41 #elif defined(ANDROID)
42 #include "gfxAndroidPlatform.h"
43 #endif
45 #include "nsGkAtoms.h"
46 #include "gfxPlatformFontList.h"
47 #include "gfxContext.h"
48 #include "gfxImageSurface.h"
49 #include "nsUnicodeProperties.h"
50 #include "harfbuzz/hb.h"
51 #include "gfxGraphiteShaper.h"
52 #include "gfx2DGlue.h"
53 #include "gfxGradientCache.h"
55 #include "nsUnicodeRange.h"
56 #include "nsServiceManagerUtils.h"
57 #include "nsTArray.h"
58 #include "nsILocaleService.h"
59 #include "nsIObserverService.h"
60 #include "MainThreadUtils.h"
62 #include "nsWeakReference.h"
64 #include "cairo.h"
65 #include "qcms.h"
67 #include "plstr.h"
68 #include "nsCRT.h"
69 #include "GLContext.h"
70 #include "GLContextProvider.h"
72 #ifdef MOZ_WIDGET_ANDROID
73 #include "TexturePoolOGL.h"
74 #endif
76 #include "mozilla/Hal.h"
77 #ifdef USE_SKIA
78 #include "skia/SkGraphics.h"
80 #include "SkiaGLGlue.h"
81 #else
82 class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted {
83 };
84 #endif
86 #include "mozilla/Preferences.h"
87 #include "mozilla/Assertions.h"
88 #include "mozilla/Attributes.h"
89 #include "mozilla/Mutex.h"
91 #include "nsIGfxInfo.h"
92 #include "nsIXULRuntime.h"
94 #ifdef MOZ_WIDGET_GONK
95 namespace mozilla {
96 namespace layers {
97 void InitGralloc();
98 }
99 }
100 #endif
102 using namespace mozilla;
103 using namespace mozilla::layers;
105 gfxPlatform *gPlatform = nullptr;
106 static bool gEverInitialized = false;
108 static Mutex* gGfxPlatformPrefsLock = nullptr;
110 // These two may point to the same profile
111 static qcms_profile *gCMSOutputProfile = nullptr;
112 static qcms_profile *gCMSsRGBProfile = nullptr;
114 static qcms_transform *gCMSRGBTransform = nullptr;
115 static qcms_transform *gCMSInverseRGBTransform = nullptr;
116 static qcms_transform *gCMSRGBATransform = nullptr;
118 static bool gCMSInitialized = false;
119 static eCMSMode gCMSMode = eCMSMode_Off;
121 static bool gCMSIntentInitialized = false;
122 static int gCMSIntent = QCMS_INTENT_DEFAULT;
125 static void ShutdownCMS();
127 #include "mozilla/gfx/2D.h"
128 using namespace mozilla::gfx;
130 /* Class to listen for pref changes so that chrome code can dynamically
131 force sRGB as an output profile. See Bug #452125. */
132 class SRGBOverrideObserver MOZ_FINAL : public nsIObserver,
133 public nsSupportsWeakReference
134 {
135 public:
136 NS_DECL_ISUPPORTS
137 NS_DECL_NSIOBSERVER
138 };
140 NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
142 #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
144 #define GFX_PREF_HARFBUZZ_SCRIPTS "gfx.font_rendering.harfbuzz.scripts"
145 #define HARFBUZZ_SCRIPTS_DEFAULT mozilla::unicode::SHAPING_DEFAULT
146 #define GFX_PREF_FALLBACK_USE_CMAPS "gfx.font_rendering.fallback.always_use_cmaps"
148 #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
150 #define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit"
151 #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries"
153 #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
155 #define BIDI_NUMERAL_PREF "bidi.numeral"
157 #define GFX_PREF_CMS_FORCE_SRGB "gfx.color_management.force_srgb"
159 NS_IMETHODIMP
160 SRGBOverrideObserver::Observe(nsISupports *aSubject,
161 const char *aTopic,
162 const char16_t* someData)
163 {
164 NS_ASSERTION(NS_strcmp(someData,
165 MOZ_UTF16(GFX_PREF_CMS_FORCE_SRGB)) == 0,
166 "Restarting CMS on wrong pref!");
167 ShutdownCMS();
168 return NS_OK;
169 }
171 static const char* kObservedPrefs[] = {
172 "gfx.downloadable_fonts.",
173 "gfx.font_rendering.",
174 BIDI_NUMERAL_PREF,
175 nullptr
176 };
178 class FontPrefsObserver MOZ_FINAL : public nsIObserver
179 {
180 public:
181 NS_DECL_ISUPPORTS
182 NS_DECL_NSIOBSERVER
183 };
185 NS_IMPL_ISUPPORTS(FontPrefsObserver, nsIObserver)
187 NS_IMETHODIMP
188 FontPrefsObserver::Observe(nsISupports *aSubject,
189 const char *aTopic,
190 const char16_t *someData)
191 {
192 if (!someData) {
193 NS_ERROR("font pref observer code broken");
194 return NS_ERROR_UNEXPECTED;
195 }
196 NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone");
197 gfxPlatform::GetPlatform()->FontsPrefsChanged(NS_ConvertUTF16toUTF8(someData).get());
199 return NS_OK;
200 }
202 class MemoryPressureObserver MOZ_FINAL : public nsIObserver
203 {
204 public:
205 NS_DECL_ISUPPORTS
206 NS_DECL_NSIOBSERVER
207 };
209 NS_IMPL_ISUPPORTS(MemoryPressureObserver, nsIObserver)
211 NS_IMETHODIMP
212 MemoryPressureObserver::Observe(nsISupports *aSubject,
213 const char *aTopic,
214 const char16_t *someData)
215 {
216 NS_ASSERTION(strcmp(aTopic, "memory-pressure") == 0, "unexpected event topic");
217 Factory::PurgeAllCaches();
219 gfxPlatform::GetPlatform()->PurgeSkiaCache();
220 return NS_OK;
221 }
223 // this needs to match the list of pref font.default.xx entries listed in all.js!
224 // the order *must* match the order in eFontPrefLang
225 static const char *gPrefLangNames[] = {
226 "x-western",
227 "x-central-euro",
228 "ja",
229 "zh-TW",
230 "zh-CN",
231 "zh-HK",
232 "ko",
233 "x-cyrillic",
234 "x-baltic",
235 "el",
236 "tr",
237 "th",
238 "he",
239 "ar",
240 "x-devanagari",
241 "x-tamil",
242 "x-armn",
243 "x-beng",
244 "x-cans",
245 "x-ethi",
246 "x-geor",
247 "x-gujr",
248 "x-guru",
249 "x-khmr",
250 "x-mlym",
251 "x-orya",
252 "x-telu",
253 "x-knda",
254 "x-sinh",
255 "x-tibt",
256 "x-unicode",
257 };
259 gfxPlatform::gfxPlatform()
260 : mAzureCanvasBackendCollector(MOZ_THIS_IN_INITIALIZER_LIST(),
261 &gfxPlatform::GetAzureBackendInfo)
262 {
263 mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
264 mAllowDownloadableFonts = UNINITIALIZED_VALUE;
265 mFallbackUsesCmaps = UNINITIALIZED_VALUE;
267 mWordCacheCharLimit = UNINITIALIZED_VALUE;
268 mWordCacheMaxEntries = UNINITIALIZED_VALUE;
269 mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
270 mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
271 mBidiNumeralOption = UNINITIALIZED_VALUE;
273 mLayersPreferMemoryOverShmem = XRE_GetProcessType() == GeckoProcessType_Default;
275 mSkiaGlue = nullptr;
277 uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
278 uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
279 InitBackendPrefs(canvasMask, BackendType::CAIRO,
280 contentMask, BackendType::CAIRO);
281 }
283 gfxPlatform*
284 gfxPlatform::GetPlatform()
285 {
286 if (!gPlatform) {
287 Init();
288 }
289 return gPlatform;
290 }
292 void RecordingPrefChanged(const char *aPrefName, void *aClosure)
293 {
294 if (Preferences::GetBool("gfx.2d.recording", false)) {
295 nsAutoCString fileName;
296 nsAdoptingString prefFileName = Preferences::GetString("gfx.2d.recordingfile");
298 if (prefFileName) {
299 fileName.Append(NS_ConvertUTF16toUTF8(prefFileName));
300 } else {
301 nsCOMPtr<nsIFile> tmpFile;
302 if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile)))) {
303 return;
304 }
305 fileName.AppendPrintf("moz2drec_%i_%i.aer", XRE_GetProcessType(), getpid());
307 nsresult rv = tmpFile->AppendNative(fileName);
308 if (NS_FAILED(rv))
309 return;
311 rv = tmpFile->GetNativePath(fileName);
312 if (NS_FAILED(rv))
313 return;
314 }
316 gPlatform->mRecorder = Factory::CreateEventRecorderForFile(fileName.BeginReading());
317 printf_stderr("Recording to %s\n", fileName.get());
318 Factory::SetGlobalEventRecorder(gPlatform->mRecorder);
319 } else {
320 Factory::SetGlobalEventRecorder(nullptr);
321 }
322 }
324 void
325 gfxPlatform::Init()
326 {
327 if (gEverInitialized) {
328 NS_RUNTIMEABORT("Already started???");
329 }
330 gEverInitialized = true;
332 // Initialize the preferences by creating the singleton.
333 gfxPrefs::GetSingleton();
335 gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock");
337 /* Initialize the GfxInfo service.
338 * Note: we can't call functions on GfxInfo that depend
339 * on gPlatform until after it has been initialized
340 * below. GfxInfo initialization annotates our
341 * crash reports so we want to do it before
342 * we try to load any drivers and do device detection
343 * incase that code crashes. See bug #591561. */
344 nsCOMPtr<nsIGfxInfo> gfxInfo;
345 /* this currently will only succeed on Windows */
346 gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
348 #if defined(XP_WIN)
349 gPlatform = new gfxWindowsPlatform;
350 #elif defined(XP_MACOSX)
351 gPlatform = new gfxPlatformMac;
352 #elif defined(MOZ_WIDGET_GTK)
353 gPlatform = new gfxPlatformGtk;
354 #elif defined(MOZ_WIDGET_QT)
355 gPlatform = new gfxQtPlatform;
356 #elif defined(ANDROID)
357 gPlatform = new gfxAndroidPlatform;
358 #else
359 #error "No gfxPlatform implementation available"
360 #endif
362 #ifdef DEBUG
363 mozilla::gl::GLContext::StaticInit();
364 #endif
366 bool useOffMainThreadCompositing = OffMainThreadCompositionRequired() ||
367 GetPrefLayersOffMainThreadCompositionEnabled();
369 if (!OffMainThreadCompositionRequired()) {
370 useOffMainThreadCompositing &= GetPlatform()->SupportsOffMainThreadCompositing();
371 }
373 if (useOffMainThreadCompositing && (XRE_GetProcessType() == GeckoProcessType_Default)) {
374 CompositorParent::StartUp();
375 if (gfxPrefs::AsyncVideoEnabled()) {
376 ImageBridgeChild::StartUp();
377 }
378 }
380 nsresult rv;
382 #if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID) // temporary, until this is implemented on others
383 rv = gfxPlatformFontList::Init();
384 if (NS_FAILED(rv)) {
385 NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList");
386 }
387 #endif
389 gPlatform->mScreenReferenceSurface =
390 gPlatform->CreateOffscreenSurface(IntSize(1, 1),
391 gfxContentType::COLOR_ALPHA);
392 if (!gPlatform->mScreenReferenceSurface) {
393 NS_RUNTIMEABORT("Could not initialize mScreenReferenceSurface");
394 }
396 gPlatform->mScreenReferenceDrawTarget =
397 gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1),
398 SurfaceFormat::B8G8R8A8);
399 if (!gPlatform->mScreenReferenceDrawTarget) {
400 NS_RUNTIMEABORT("Could not initialize mScreenReferenceDrawTarget");
401 }
403 rv = gfxFontCache::Init();
404 if (NS_FAILED(rv)) {
405 NS_RUNTIMEABORT("Could not initialize gfxFontCache");
406 }
408 /* Create and register our CMS Override observer. */
409 gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
410 Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
412 gPlatform->mFontPrefsObserver = new FontPrefsObserver();
413 Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
415 mozilla::gl::GLContext::PlatformStartup();
417 #ifdef MOZ_WIDGET_ANDROID
418 // Texture pool init
419 mozilla::gl::TexturePoolOGL::Init();
420 #endif
422 #ifdef MOZ_WIDGET_GONK
423 mozilla::layers::InitGralloc();
424 #endif
426 Preferences::RegisterCallbackAndCall(RecordingPrefChanged, "gfx.2d.recording", nullptr);
428 CreateCMSOutputProfile();
430 // Listen to memory pressure event so we can purge DrawTarget caches
431 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
432 if (obs) {
433 gPlatform->mMemoryPressureObserver = new MemoryPressureObserver();
434 obs->AddObserver(gPlatform->mMemoryPressureObserver, "memory-pressure", false);
435 }
437 RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
438 }
440 void
441 gfxPlatform::Shutdown()
442 {
443 // These may be called before the corresponding subsystems have actually
444 // started up. That's OK, they can handle it.
445 gfxFontCache::Shutdown();
446 gfxFontGroup::Shutdown();
447 gfxGradientCache::Shutdown();
448 gfxGraphiteShaper::Shutdown();
449 #if defined(XP_MACOSX) || defined(XP_WIN) // temporary, until this is implemented on others
450 gfxPlatformFontList::Shutdown();
451 #endif
453 // Free the various non-null transforms and loaded profiles
454 ShutdownCMS();
456 // In some cases, gPlatform may not be created but Shutdown() called,
457 // e.g., during xpcshell tests.
458 if (gPlatform) {
459 /* Unregister our CMS Override callback. */
460 NS_ASSERTION(gPlatform->mSRGBOverrideObserver, "mSRGBOverrideObserver has alreay gone");
461 Preferences::RemoveObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
462 gPlatform->mSRGBOverrideObserver = nullptr;
464 NS_ASSERTION(gPlatform->mFontPrefsObserver, "mFontPrefsObserver has alreay gone");
465 Preferences::RemoveObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
466 gPlatform->mFontPrefsObserver = nullptr;
468 NS_ASSERTION(gPlatform->mMemoryPressureObserver, "mMemoryPressureObserver has already gone");
469 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
470 if (obs) {
471 obs->RemoveObserver(gPlatform->mMemoryPressureObserver, "memory-pressure");
472 }
474 gPlatform->mMemoryPressureObserver = nullptr;
475 gPlatform->mSkiaGlue = nullptr;
476 }
478 #ifdef MOZ_WIDGET_ANDROID
479 // Shut down the texture pool
480 mozilla::gl::TexturePoolOGL::Shutdown();
481 #endif
483 // Shut down the default GL context provider.
484 mozilla::gl::GLContextProvider::Shutdown();
486 #if defined(XP_WIN)
487 // The above shutdown calls operate on the available context providers on
488 // most platforms. Windows is a "special snowflake", though, and has three
489 // context providers available, so we have to shut all of them down.
490 // We should only support the default GL provider on Windows; then, this
491 // could go away. Unfortunately, we currently support WGL (the default) for
492 // WebGL on Optimus.
493 mozilla::gl::GLContextProviderEGL::Shutdown();
494 #endif
496 delete gGfxPlatformPrefsLock;
498 gfxPrefs::DestroySingleton();
499 gfxFont::DestroySingletons();
501 delete gPlatform;
502 gPlatform = nullptr;
503 }
505 gfxPlatform::~gfxPlatform()
506 {
507 mScreenReferenceSurface = nullptr;
508 mScreenReferenceDrawTarget = nullptr;
510 // The cairo folks think we should only clean up in debug builds,
511 // but we're generally in the habit of trying to shut down as
512 // cleanly as possible even in production code, so call this
513 // cairo_debug_* function unconditionally.
514 //
515 // because cairo can assert and thus crash on shutdown, don't do this in release builds
516 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) || defined(NS_TRACE_MALLOC) || defined(MOZ_VALGRIND)
517 #ifdef USE_SKIA
518 // must do Skia cleanup before Cairo cleanup, because Skia may be referencing
519 // Cairo objects e.g. through SkCairoFTTypeface
520 SkGraphics::Term();
521 #endif
523 #if MOZ_TREE_CAIRO
524 cairo_debug_reset_static_data();
525 #endif
526 #endif
527 }
529 bool
530 gfxPlatform::PreferMemoryOverShmem() const {
531 MOZ_ASSERT(!CompositorParent::IsInCompositorThread());
532 return mLayersPreferMemoryOverShmem;
533 }
535 already_AddRefed<gfxASurface>
536 gfxPlatform::CreateOffscreenImageSurface(const gfxIntSize& aSize,
537 gfxContentType aContentType)
538 {
539 nsRefPtr<gfxASurface> newSurface;
540 newSurface = new gfxImageSurface(aSize, OptimalFormatForContent(aContentType));
542 return newSurface.forget();
543 }
545 already_AddRefed<gfxASurface>
546 gfxPlatform::OptimizeImage(gfxImageSurface *aSurface,
547 gfxImageFormat format)
548 {
549 IntSize surfaceSize = aSurface->GetSize().ToIntSize();
551 #ifdef XP_WIN
552 if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
553 gfxWindowsPlatform::RENDER_DIRECT2D) {
554 return nullptr;
555 }
556 #endif
557 nsRefPtr<gfxASurface> optSurface = CreateOffscreenSurface(surfaceSize, gfxASurface::ContentFromFormat(format));
558 if (!optSurface || optSurface->CairoStatus() != 0)
559 return nullptr;
561 gfxContext tmpCtx(optSurface);
562 tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
563 tmpCtx.SetSource(aSurface);
564 tmpCtx.Paint();
566 return optSurface.forget();
567 }
569 cairo_user_data_key_t kDrawTarget;
571 RefPtr<DrawTarget>
572 gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface, const IntSize& aSize)
573 {
574 SurfaceFormat format = Optimal2DFormatForContent(aSurface->GetContentType());
575 RefPtr<DrawTarget> drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(), aSize, &format);
576 aSurface->SetData(&kDrawTarget, drawTarget, nullptr);
577 return drawTarget;
578 }
580 // This is a temporary function used by ContentClient to build a DrawTarget
581 // around the gfxASurface. This should eventually be replaced by plumbing
582 // the DrawTarget through directly
583 RefPtr<DrawTarget>
584 gfxPlatform::CreateDrawTargetForUpdateSurface(gfxASurface *aSurface, const IntSize& aSize)
585 {
586 #ifdef XP_MACOSX
587 // this is a bit of a hack that assumes that the buffer associated with the CGContext
588 // will live around long enough that nothing bad will happen.
589 if (aSurface->GetType() == gfxSurfaceType::Quartz) {
590 return Factory::CreateDrawTargetForCairoCGContext(static_cast<gfxQuartzSurface*>(aSurface)->GetCGContext(), aSize);
591 }
592 #endif
593 MOZ_CRASH();
594 return nullptr;
595 }
598 cairo_user_data_key_t kSourceSurface;
600 /**
601 * Record the backend that was used to construct the SourceSurface.
602 * When getting the cached SourceSurface for a gfxASurface/DrawTarget pair,
603 * we check to make sure the DrawTarget's backend matches the backend
604 * for the cached SourceSurface, and only use it if they match. This
605 * can avoid expensive and unnecessary readbacks.
606 */
607 struct SourceSurfaceUserData
608 {
609 RefPtr<SourceSurface> mSrcSurface;
610 BackendType mBackendType;
611 };
613 void SourceBufferDestroy(void *srcSurfUD)
614 {
615 delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
616 }
618 UserDataKey kThebesSurface;
620 struct DependentSourceSurfaceUserData
621 {
622 nsRefPtr<gfxASurface> mSurface;
623 };
625 void SourceSurfaceDestroyed(void *aData)
626 {
627 delete static_cast<DependentSourceSurfaceUserData*>(aData);
628 }
630 #if MOZ_TREE_CAIRO
631 void SourceSnapshotDetached(cairo_surface_t *nullSurf)
632 {
633 gfxImageSurface* origSurf =
634 static_cast<gfxImageSurface*>(cairo_surface_get_user_data(nullSurf, &kSourceSurface));
636 origSurf->SetData(&kSourceSurface, nullptr, nullptr);
637 }
638 #else
639 void SourceSnapshotDetached(void *nullSurf)
640 {
641 gfxImageSurface* origSurf = static_cast<gfxImageSurface*>(nullSurf);
642 origSurf->SetData(&kSourceSurface, nullptr, nullptr);
643 }
644 #endif
646 void
647 gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
648 {
649 aSurface->SetData(&kSourceSurface, nullptr, nullptr);
650 }
652 static TemporaryRef<DataSourceSurface>
653 CopySurface(gfxASurface* aSurface)
654 {
655 const nsIntSize size = aSurface->GetSize();
656 gfxImageFormat format = gfxPlatform::GetPlatform()->OptimalFormatForContent(aSurface->GetContentType());
657 RefPtr<DataSourceSurface> data =
658 Factory::CreateDataSourceSurface(ToIntSize(size),
659 ImageFormatToSurfaceFormat(format));
660 if (!data) {
661 return nullptr;
662 }
664 DataSourceSurface::MappedSurface map;
665 DebugOnly<bool> result = data->Map(DataSourceSurface::WRITE, &map);
666 MOZ_ASSERT(result, "Should always succeed mapping raw data surfaces!");
668 nsRefPtr<gfxImageSurface> image = new gfxImageSurface(map.mData, size, map.mStride, format);
669 nsRefPtr<gfxContext> ctx = new gfxContext(image);
671 ctx->SetSource(aSurface);
672 ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
673 ctx->Paint();
675 data->Unmap();
677 return data;
678 }
680 RefPtr<SourceSurface>
681 gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface)
682 {
683 if (!aSurface->CairoSurface() || aSurface->CairoStatus()) {
684 return nullptr;
685 }
687 if (!aTarget) {
688 if (ScreenReferenceDrawTarget()) {
689 aTarget = ScreenReferenceDrawTarget();
690 } else {
691 return nullptr;
692 }
693 }
695 void *userData = aSurface->GetData(&kSourceSurface);
697 if (userData) {
698 SourceSurfaceUserData *surf = static_cast<SourceSurfaceUserData*>(userData);
700 if (surf->mSrcSurface->IsValid() && surf->mBackendType == aTarget->GetType()) {
701 return surf->mSrcSurface;
702 }
703 // We can just continue here as when setting new user data the destroy
704 // function will be called for the old user data.
705 }
707 SurfaceFormat format;
708 if (aSurface->GetContentType() == gfxContentType::ALPHA) {
709 format = SurfaceFormat::A8;
710 } else if (aSurface->GetContentType() == gfxContentType::COLOR) {
711 format = SurfaceFormat::B8G8R8X8;
712 } else {
713 format = SurfaceFormat::B8G8R8A8;
714 }
716 RefPtr<SourceSurface> srcBuffer;
718 #ifdef XP_WIN
719 if (aSurface->GetType() == gfxSurfaceType::D2D &&
720 format != SurfaceFormat::A8) {
721 NativeSurface surf;
722 surf.mFormat = format;
723 surf.mType = NativeSurfaceType::D3D10_TEXTURE;
724 surf.mSurface = static_cast<gfxD2DSurface*>(aSurface)->GetTexture();
725 surf.mSize = ToIntSize(aSurface->GetSize());
726 mozilla::gfx::DrawTarget *dt = static_cast<mozilla::gfx::DrawTarget*>(aSurface->GetData(&kDrawTarget));
727 if (dt) {
728 dt->Flush();
729 }
730 srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
731 } else
732 #endif
733 if (aSurface->CairoSurface() && aTarget->GetType() == BackendType::CAIRO) {
734 // If this is an xlib cairo surface we don't want to fetch it into memory
735 // because this is a major slow down.
736 NativeSurface surf;
737 surf.mFormat = format;
738 surf.mType = NativeSurfaceType::CAIRO_SURFACE;
739 surf.mSurface = aSurface->CairoSurface();
740 surf.mSize = ToIntSize(aSurface->GetSize());
741 srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
743 if (srcBuffer) {
744 // It's cheap enough to make a new one so we won't keep it around and
745 // keeping it creates a cycle.
746 return srcBuffer;
747 }
748 }
750 if (!srcBuffer) {
751 nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();
753 RefPtr<DataSourceSurface> dataSurf;
755 if (imgSurface) {
756 dataSurf = GetWrappedDataSourceSurface(aSurface);
757 } else {
758 dataSurf = CopySurface(aSurface);
759 }
761 if (!dataSurf) {
762 return nullptr;
763 }
765 srcBuffer = aTarget->OptimizeSourceSurface(dataSurf);
767 if (imgSurface && srcBuffer == dataSurf) {
768 // Our wrapping surface will hold a reference to its image surface. We cause
769 // a reference cycle if we add it to the cache. And caching it is pretty
770 // pointless since we'll just wrap it again next use.
771 return srcBuffer;
772 }
773 }
775 // Add user data to aSurface so we can cache lookups in the future.
776 SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
777 srcSurfUD->mBackendType = aTarget->GetType();
778 srcSurfUD->mSrcSurface = srcBuffer;
779 aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
781 return srcBuffer;
782 }
784 RefPtr<DataSourceSurface>
785 gfxPlatform::GetWrappedDataSourceSurface(gfxASurface* aSurface)
786 {
787 nsRefPtr<gfxImageSurface> image = aSurface->GetAsImageSurface();
788 if (!image) {
789 return nullptr;
790 }
791 RefPtr<DataSourceSurface> result =
792 Factory::CreateWrappingDataSourceSurface(image->Data(),
793 image->Stride(),
794 ToIntSize(image->GetSize()),
795 ImageFormatToSurfaceFormat(image->Format()));
797 if (!result) {
798 return nullptr;
799 }
801 // If we wrapped the underlying data of aSurface, then we need to add user data
802 // to make sure aSurface stays alive until we are done with the data.
803 DependentSourceSurfaceUserData *srcSurfUD = new DependentSourceSurfaceUserData;
804 srcSurfUD->mSurface = aSurface;
805 result->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
807 return result;
808 }
810 TemporaryRef<ScaledFont>
811 gfxPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
812 {
813 NativeFont nativeFont;
814 nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
815 nativeFont.mFont = aFont->GetCairoScaledFont();
816 RefPtr<ScaledFont> scaledFont =
817 Factory::CreateScaledFontForNativeFont(nativeFont,
818 aFont->GetAdjustedSize());
819 return scaledFont;
820 }
822 cairo_user_data_key_t kDrawSourceSurface;
823 static void
824 DataSourceSurfaceDestroy(void *dataSourceSurface)
825 {
826 static_cast<DataSourceSurface*>(dataSourceSurface)->Release();
827 }
829 cairo_user_data_key_t kDrawTargetForSurface;
830 static void
831 DataDrawTargetDestroy(void *aTarget)
832 {
833 static_cast<DrawTarget*>(aTarget)->Release();
834 }
836 bool
837 gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget)
838 {
839 if (!aTarget) {
840 return false;
841 }
843 return SupportsAzureContentForType(aTarget->GetType());
844 }
846 bool
847 gfxPlatform::UseAcceleratedSkiaCanvas()
848 {
849 return gfxPrefs::CanvasAzureAccelerated() &&
850 mPreferredCanvasBackend == BackendType::SKIA;
851 }
853 void
854 gfxPlatform::InitializeSkiaCacheLimits()
855 {
856 if (UseAcceleratedSkiaCanvas()) {
857 bool usingDynamicCache = gfxPrefs::CanvasSkiaGLDynamicCache();
858 int cacheItemLimit = gfxPrefs::CanvasSkiaGLCacheItems();
859 int cacheSizeLimit = gfxPrefs::CanvasSkiaGLCacheSize();
861 // Prefs are in megabytes, but we want the sizes in bytes
862 cacheSizeLimit *= 1024*1024;
864 if (usingDynamicCache) {
865 uint32_t totalMemory = mozilla::hal::GetTotalSystemMemory();
867 if (totalMemory <= 256*1024*1024) {
868 // We need a very minimal cache on 256 meg devices
869 cacheSizeLimit = 2*1024*1024;
870 } else if (totalMemory > 0) {
871 cacheSizeLimit = totalMemory / 16;
872 }
873 }
875 #ifdef DEBUG
876 printf_stderr("Determined SkiaGL cache limits: Size %i, Items: %i\n", cacheSizeLimit, cacheItemLimit);
877 #endif
879 #ifdef USE_SKIA_GPU
880 mSkiaGlue->GetGrContext()->setTextureCacheLimits(cacheItemLimit, cacheSizeLimit);
881 #endif
882 }
883 }
885 mozilla::gl::SkiaGLGlue*
886 gfxPlatform::GetSkiaGLGlue()
887 {
888 #ifdef USE_SKIA_GPU
889 if (!mSkiaGlue) {
890 /* Dummy context. We always draw into a FBO.
891 *
892 * FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it
893 * stands, this only works on the main thread.
894 */
895 mozilla::gfx::SurfaceCaps caps = mozilla::gfx::SurfaceCaps::ForRGBA();
896 nsRefPtr<mozilla::gl::GLContext> glContext = mozilla::gl::GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), caps);
897 if (!glContext) {
898 printf_stderr("Failed to create GLContext for SkiaGL!\n");
899 return nullptr;
900 }
901 mSkiaGlue = new mozilla::gl::SkiaGLGlue(glContext);
902 MOZ_ASSERT(mSkiaGlue->GetGrContext(), "No GrContext");
903 InitializeSkiaCacheLimits();
904 }
905 #endif
907 return mSkiaGlue;
908 }
910 void
911 gfxPlatform::PurgeSkiaCache()
912 {
913 #ifdef USE_SKIA_GPU
914 if (!mSkiaGlue)
915 return;
917 mSkiaGlue->GetGrContext()->freeGpuResources();
918 #endif
919 }
921 already_AddRefed<gfxASurface>
922 gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
923 {
924 if (aTarget->GetType() == BackendType::CAIRO) {
925 cairo_surface_t* csurf =
926 static_cast<cairo_surface_t*>(aTarget->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE));
927 if (csurf) {
928 return gfxASurface::Wrap(csurf);
929 }
930 }
932 // The semantics of this part of the function are sort of weird. If we
933 // don't have direct support for the backend, we snapshot the first time
934 // and then return the snapshotted surface for the lifetime of the draw
935 // target. Sometimes it seems like this works out, but it seems like it
936 // might result in no updates ever.
937 RefPtr<SourceSurface> source = aTarget->Snapshot();
938 RefPtr<DataSourceSurface> data = source->GetDataSurface();
940 if (!data) {
941 return nullptr;
942 }
944 IntSize size = data->GetSize();
945 gfxImageFormat format = SurfaceFormatToImageFormat(data->GetFormat());
948 nsRefPtr<gfxASurface> surf =
949 new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height),
950 data->Stride(), format);
952 if (surf->CairoStatus()) {
953 return nullptr;
954 }
956 surf->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy);
957 // keep the draw target alive as long as we need its data
958 aTarget->AddRef();
959 surf->SetData(&kDrawTargetForSurface, aTarget, DataDrawTargetDestroy);
961 return surf.forget();
962 }
964 RefPtr<DrawTarget>
965 gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat)
966 {
967 // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
968 // create the best offscreen surface for the current system and situation. We
969 // can easily take advantage of this for the Cairo backend, so that's what we
970 // do.
971 // mozilla::gfx::Factory can get away without having all this knowledge for
972 // now, but this might need to change in the future (using
973 // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all
974 // backends).
975 if (aBackend == BackendType::CAIRO) {
976 nsRefPtr<gfxASurface> surf = CreateOffscreenSurface(aSize,
977 ContentForFormat(aFormat));
978 if (!surf || surf->CairoStatus()) {
979 return nullptr;
980 }
982 return CreateDrawTargetForSurface(surf, aSize);
983 } else {
984 return Factory::CreateDrawTarget(aBackend, aSize, aFormat);
985 }
986 }
988 RefPtr<DrawTarget>
989 gfxPlatform::CreateOffscreenCanvasDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
990 {
991 NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
992 RefPtr<DrawTarget> target = CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat);
993 if (target ||
994 mFallbackCanvasBackend == BackendType::NONE) {
995 return target;
996 }
998 return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat);
999 }
1001 RefPtr<DrawTarget>
1002 gfxPlatform::CreateOffscreenContentDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
1003 {
1004 NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
1005 return CreateDrawTargetForBackend(mContentBackend, aSize, aFormat);
1006 }
1008 RefPtr<DrawTarget>
1009 gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat)
1010 {
1011 NS_ASSERTION(mContentBackend != BackendType::NONE, "No backend.");
1012 if (mContentBackend == BackendType::CAIRO) {
1013 nsRefPtr<gfxImageSurface> image = new gfxImageSurface(aData, gfxIntSize(aSize.width, aSize.height), aStride, SurfaceFormatToImageFormat(aFormat));
1014 return Factory::CreateDrawTargetForCairoSurface(image->CairoSurface(), aSize);
1015 }
1016 return Factory::CreateDrawTargetForData(mContentBackend, aData, aSize, aStride, aFormat);
1017 }
1019 /* static */ BackendType
1020 gfxPlatform::BackendTypeForName(const nsCString& aName)
1021 {
1022 if (aName.EqualsLiteral("cairo"))
1023 return BackendType::CAIRO;
1024 if (aName.EqualsLiteral("skia"))
1025 return BackendType::SKIA;
1026 if (aName.EqualsLiteral("direct2d"))
1027 return BackendType::DIRECT2D;
1028 if (aName.EqualsLiteral("cg"))
1029 return BackendType::COREGRAPHICS;
1030 return BackendType::NONE;
1031 }
1033 nsresult
1034 gfxPlatform::GetFontList(nsIAtom *aLangGroup,
1035 const nsACString& aGenericFamily,
1036 nsTArray<nsString>& aListOfFonts)
1037 {
1038 return NS_ERROR_NOT_IMPLEMENTED;
1039 }
1041 nsresult
1042 gfxPlatform::UpdateFontList()
1043 {
1044 return NS_ERROR_NOT_IMPLEMENTED;
1045 }
1047 bool
1048 gfxPlatform::DownloadableFontsEnabled()
1049 {
1050 if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
1051 mAllowDownloadableFonts =
1052 Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false);
1053 }
1055 return mAllowDownloadableFonts;
1056 }
1058 bool
1059 gfxPlatform::UseCmapsDuringSystemFallback()
1060 {
1061 if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) {
1062 mFallbackUsesCmaps =
1063 Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false);
1064 }
1066 return mFallbackUsesCmaps;
1067 }
1069 bool
1070 gfxPlatform::OpenTypeSVGEnabled()
1071 {
1072 if (mOpenTypeSVGEnabled == UNINITIALIZED_VALUE) {
1073 mOpenTypeSVGEnabled =
1074 Preferences::GetBool(GFX_PREF_OPENTYPE_SVG, false);
1075 }
1077 return mOpenTypeSVGEnabled > 0;
1078 }
1080 uint32_t
1081 gfxPlatform::WordCacheCharLimit()
1082 {
1083 if (mWordCacheCharLimit == UNINITIALIZED_VALUE) {
1084 mWordCacheCharLimit =
1085 Preferences::GetInt(GFX_PREF_WORD_CACHE_CHARLIMIT, 32);
1086 if (mWordCacheCharLimit < 0) {
1087 mWordCacheCharLimit = 32;
1088 }
1089 }
1091 return uint32_t(mWordCacheCharLimit);
1092 }
1094 uint32_t
1095 gfxPlatform::WordCacheMaxEntries()
1096 {
1097 if (mWordCacheMaxEntries == UNINITIALIZED_VALUE) {
1098 mWordCacheMaxEntries =
1099 Preferences::GetInt(GFX_PREF_WORD_CACHE_MAXENTRIES, 10000);
1100 if (mWordCacheMaxEntries < 0) {
1101 mWordCacheMaxEntries = 10000;
1102 }
1103 }
1105 return uint32_t(mWordCacheMaxEntries);
1106 }
1108 bool
1109 gfxPlatform::UseGraphiteShaping()
1110 {
1111 if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) {
1112 mGraphiteShapingEnabled =
1113 Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
1114 }
1116 return mGraphiteShapingEnabled;
1117 }
1119 bool
1120 gfxPlatform::UseHarfBuzzForScript(int32_t aScriptCode)
1121 {
1122 if (mUseHarfBuzzScripts == UNINITIALIZED_VALUE) {
1123 mUseHarfBuzzScripts = Preferences::GetInt(GFX_PREF_HARFBUZZ_SCRIPTS, HARFBUZZ_SCRIPTS_DEFAULT);
1124 }
1126 int32_t shapingType = mozilla::unicode::ScriptShapingType(aScriptCode);
1128 return (mUseHarfBuzzScripts & shapingType) != 0;
1129 }
1131 gfxFontEntry*
1132 gfxPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
1133 const uint8_t *aFontData,
1134 uint32_t aLength)
1135 {
1136 // Default implementation does not handle activating downloaded fonts;
1137 // just free the data and return.
1138 // Platforms that support @font-face must override this,
1139 // using the data to instantiate the font, and taking responsibility
1140 // for freeing it when no longer required.
1141 if (aFontData) {
1142 NS_Free((void*)aFontData);
1143 }
1144 return nullptr;
1145 }
1147 static void
1148 AppendGenericFontFromPref(nsString& aFonts, nsIAtom *aLangGroup, const char *aGenericName)
1149 {
1150 NS_ENSURE_TRUE_VOID(Preferences::GetRootBranch());
1152 nsAutoCString prefName, langGroupString;
1154 aLangGroup->ToUTF8String(langGroupString);
1156 nsAutoCString genericDotLang;
1157 if (aGenericName) {
1158 genericDotLang.Assign(aGenericName);
1159 } else {
1160 prefName.AssignLiteral("font.default.");
1161 prefName.Append(langGroupString);
1162 genericDotLang = Preferences::GetCString(prefName.get());
1163 }
1165 genericDotLang.AppendLiteral(".");
1166 genericDotLang.Append(langGroupString);
1168 // fetch font.name.xxx value
1169 prefName.AssignLiteral("font.name.");
1170 prefName.Append(genericDotLang);
1171 nsAdoptingString nameValue = Preferences::GetString(prefName.get());
1172 if (nameValue) {
1173 if (!aFonts.IsEmpty())
1174 aFonts.AppendLiteral(", ");
1175 aFonts += nameValue;
1176 }
1178 // fetch font.name-list.xxx value
1179 prefName.AssignLiteral("font.name-list.");
1180 prefName.Append(genericDotLang);
1181 nsAdoptingString nameListValue = Preferences::GetString(prefName.get());
1182 if (nameListValue && !nameListValue.Equals(nameValue)) {
1183 if (!aFonts.IsEmpty())
1184 aFonts.AppendLiteral(", ");
1185 aFonts += nameListValue;
1186 }
1187 }
1189 void
1190 gfxPlatform::GetPrefFonts(nsIAtom *aLanguage, nsString& aFonts, bool aAppendUnicode)
1191 {
1192 aFonts.Truncate();
1194 AppendGenericFontFromPref(aFonts, aLanguage, nullptr);
1195 if (aAppendUnicode)
1196 AppendGenericFontFromPref(aFonts, nsGkAtoms::Unicode, nullptr);
1197 }
1199 bool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], uint32_t aLangArrayLen, PrefFontCallback aCallback,
1200 void *aClosure)
1201 {
1202 NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
1204 uint32_t i;
1205 for (i = 0; i < aLangArrayLen; i++) {
1206 eFontPrefLang prefLang = aLangArray[i];
1207 const char *langGroup = GetPrefLangName(prefLang);
1209 nsAutoCString prefName;
1211 prefName.AssignLiteral("font.default.");
1212 prefName.Append(langGroup);
1213 nsAdoptingCString genericDotLang = Preferences::GetCString(prefName.get());
1215 genericDotLang.AppendLiteral(".");
1216 genericDotLang.Append(langGroup);
1218 // fetch font.name.xxx value
1219 prefName.AssignLiteral("font.name.");
1220 prefName.Append(genericDotLang);
1221 nsAdoptingCString nameValue = Preferences::GetCString(prefName.get());
1222 if (nameValue) {
1223 if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(nameValue), aClosure))
1224 return false;
1225 }
1227 // fetch font.name-list.xxx value
1228 prefName.AssignLiteral("font.name-list.");
1229 prefName.Append(genericDotLang);
1230 nsAdoptingCString nameListValue = Preferences::GetCString(prefName.get());
1231 if (nameListValue && !nameListValue.Equals(nameValue)) {
1232 const char kComma = ',';
1233 const char *p, *p_end;
1234 nsAutoCString list(nameListValue);
1235 list.BeginReading(p);
1236 list.EndReading(p_end);
1237 while (p < p_end) {
1238 while (nsCRT::IsAsciiSpace(*p)) {
1239 if (++p == p_end)
1240 break;
1241 }
1242 if (p == p_end)
1243 break;
1244 const char *start = p;
1245 while (++p != p_end && *p != kComma)
1246 /* nothing */ ;
1247 nsAutoCString fontName(Substring(start, p));
1248 fontName.CompressWhitespace(false, true);
1249 if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(fontName), aClosure))
1250 return false;
1251 p++;
1252 }
1253 }
1254 }
1256 return true;
1257 }
1259 eFontPrefLang
1260 gfxPlatform::GetFontPrefLangFor(const char* aLang)
1261 {
1262 if (!aLang || !aLang[0]) {
1263 return eFontPrefLang_Others;
1264 }
1265 for (uint32_t i = 0; i < ArrayLength(gPrefLangNames); ++i) {
1266 if (!PL_strcasecmp(gPrefLangNames[i], aLang)) {
1267 return eFontPrefLang(i);
1268 }
1269 }
1270 return eFontPrefLang_Others;
1271 }
1273 eFontPrefLang
1274 gfxPlatform::GetFontPrefLangFor(nsIAtom *aLang)
1275 {
1276 if (!aLang)
1277 return eFontPrefLang_Others;
1278 nsAutoCString lang;
1279 aLang->ToUTF8String(lang);
1280 return GetFontPrefLangFor(lang.get());
1281 }
1283 const char*
1284 gfxPlatform::GetPrefLangName(eFontPrefLang aLang)
1285 {
1286 if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) {
1287 return gPrefLangNames[uint32_t(aLang)];
1288 }
1289 return nullptr;
1290 }
1292 eFontPrefLang
1293 gfxPlatform::GetFontPrefLangFor(uint8_t aUnicodeRange)
1294 {
1295 switch (aUnicodeRange) {
1296 case kRangeSetLatin: return eFontPrefLang_Western;
1297 case kRangeCyrillic: return eFontPrefLang_Cyrillic;
1298 case kRangeGreek: return eFontPrefLang_Greek;
1299 case kRangeTurkish: return eFontPrefLang_Turkish;
1300 case kRangeHebrew: return eFontPrefLang_Hebrew;
1301 case kRangeArabic: return eFontPrefLang_Arabic;
1302 case kRangeBaltic: return eFontPrefLang_Baltic;
1303 case kRangeThai: return eFontPrefLang_Thai;
1304 case kRangeKorean: return eFontPrefLang_Korean;
1305 case kRangeJapanese: return eFontPrefLang_Japanese;
1306 case kRangeSChinese: return eFontPrefLang_ChineseCN;
1307 case kRangeTChinese: return eFontPrefLang_ChineseTW;
1308 case kRangeDevanagari: return eFontPrefLang_Devanagari;
1309 case kRangeTamil: return eFontPrefLang_Tamil;
1310 case kRangeArmenian: return eFontPrefLang_Armenian;
1311 case kRangeBengali: return eFontPrefLang_Bengali;
1312 case kRangeCanadian: return eFontPrefLang_Canadian;
1313 case kRangeEthiopic: return eFontPrefLang_Ethiopic;
1314 case kRangeGeorgian: return eFontPrefLang_Georgian;
1315 case kRangeGujarati: return eFontPrefLang_Gujarati;
1316 case kRangeGurmukhi: return eFontPrefLang_Gurmukhi;
1317 case kRangeKhmer: return eFontPrefLang_Khmer;
1318 case kRangeMalayalam: return eFontPrefLang_Malayalam;
1319 case kRangeOriya: return eFontPrefLang_Oriya;
1320 case kRangeTelugu: return eFontPrefLang_Telugu;
1321 case kRangeKannada: return eFontPrefLang_Kannada;
1322 case kRangeSinhala: return eFontPrefLang_Sinhala;
1323 case kRangeTibetan: return eFontPrefLang_Tibetan;
1324 case kRangeSetCJK: return eFontPrefLang_CJKSet;
1325 default: return eFontPrefLang_Others;
1326 }
1327 }
1329 bool
1330 gfxPlatform::IsLangCJK(eFontPrefLang aLang)
1331 {
1332 switch (aLang) {
1333 case eFontPrefLang_Japanese:
1334 case eFontPrefLang_ChineseTW:
1335 case eFontPrefLang_ChineseCN:
1336 case eFontPrefLang_ChineseHK:
1337 case eFontPrefLang_Korean:
1338 case eFontPrefLang_CJKSet:
1339 return true;
1340 default:
1341 return false;
1342 }
1343 }
1345 mozilla::layers::DiagnosticTypes
1346 gfxPlatform::GetLayerDiagnosticTypes()
1347 {
1348 mozilla::layers::DiagnosticTypes type = DIAGNOSTIC_NONE;
1349 if (gfxPrefs::DrawLayerBorders()) {
1350 type |= mozilla::layers::DIAGNOSTIC_LAYER_BORDERS;
1351 }
1352 if (gfxPrefs::DrawTileBorders()) {
1353 type |= mozilla::layers::DIAGNOSTIC_TILE_BORDERS;
1354 }
1355 if (gfxPrefs::DrawBigImageBorders()) {
1356 type |= mozilla::layers::DIAGNOSTIC_BIGIMAGE_BORDERS;
1357 }
1358 if (gfxPrefs::FlashLayerBorders()) {
1359 type |= mozilla::layers::DIAGNOSTIC_FLASH_BORDERS;
1360 }
1361 return type;
1362 }
1364 void
1365 gfxPlatform::GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
1366 {
1367 if (IsLangCJK(aCharLang)) {
1368 AppendCJKPrefLangs(aPrefLangs, aLen, aCharLang, aPageLang);
1369 } else {
1370 AppendPrefLang(aPrefLangs, aLen, aCharLang);
1371 }
1373 AppendPrefLang(aPrefLangs, aLen, eFontPrefLang_Others);
1374 }
1376 void
1377 gfxPlatform::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
1378 {
1379 // prefer the lang specified by the page *if* CJK
1380 if (IsLangCJK(aPageLang)) {
1381 AppendPrefLang(aPrefLangs, aLen, aPageLang);
1382 }
1384 // if not set up, set up the default CJK order, based on accept lang settings and locale
1385 if (mCJKPrefLangs.Length() == 0) {
1387 // temp array
1388 eFontPrefLang tempPrefLangs[kMaxLenPrefLangList];
1389 uint32_t tempLen = 0;
1391 // Add the CJK pref fonts from accept languages, the order should be same order
1392 nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages");
1393 if (!list.IsEmpty()) {
1394 const char kComma = ',';
1395 const char *p, *p_end;
1396 list.BeginReading(p);
1397 list.EndReading(p_end);
1398 while (p < p_end) {
1399 while (nsCRT::IsAsciiSpace(*p)) {
1400 if (++p == p_end)
1401 break;
1402 }
1403 if (p == p_end)
1404 break;
1405 const char *start = p;
1406 while (++p != p_end && *p != kComma)
1407 /* nothing */ ;
1408 nsAutoCString lang(Substring(start, p));
1409 lang.CompressWhitespace(false, true);
1410 eFontPrefLang fpl = gfxPlatform::GetFontPrefLangFor(lang.get());
1411 switch (fpl) {
1412 case eFontPrefLang_Japanese:
1413 case eFontPrefLang_Korean:
1414 case eFontPrefLang_ChineseCN:
1415 case eFontPrefLang_ChineseHK:
1416 case eFontPrefLang_ChineseTW:
1417 AppendPrefLang(tempPrefLangs, tempLen, fpl);
1418 break;
1419 default:
1420 break;
1421 }
1422 p++;
1423 }
1424 }
1426 do { // to allow 'break' to abort this block if a call fails
1427 nsresult rv;
1428 nsCOMPtr<nsILocaleService> ls =
1429 do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
1430 if (NS_FAILED(rv))
1431 break;
1433 nsCOMPtr<nsILocale> appLocale;
1434 rv = ls->GetApplicationLocale(getter_AddRefs(appLocale));
1435 if (NS_FAILED(rv))
1436 break;
1438 nsString localeStr;
1439 rv = appLocale->
1440 GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr);
1441 if (NS_FAILED(rv))
1442 break;
1444 const nsAString& lang = Substring(localeStr, 0, 2);
1445 if (lang.EqualsLiteral("ja")) {
1446 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
1447 } else if (lang.EqualsLiteral("zh")) {
1448 const nsAString& region = Substring(localeStr, 3, 2);
1449 if (region.EqualsLiteral("CN")) {
1450 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
1451 } else if (region.EqualsLiteral("TW")) {
1452 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
1453 } else if (region.EqualsLiteral("HK")) {
1454 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
1455 }
1456 } else if (lang.EqualsLiteral("ko")) {
1457 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
1458 }
1459 } while (0);
1461 // last resort... (the order is same as old gfx.)
1462 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
1463 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
1464 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
1465 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
1466 AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
1468 // copy into the cached array
1469 uint32_t j;
1470 for (j = 0; j < tempLen; j++) {
1471 mCJKPrefLangs.AppendElement(tempPrefLangs[j]);
1472 }
1473 }
1475 // append in cached CJK langs
1476 uint32_t i, numCJKlangs = mCJKPrefLangs.Length();
1478 for (i = 0; i < numCJKlangs; i++) {
1479 AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i]));
1480 }
1482 }
1484 void
1485 gfxPlatform::AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang)
1486 {
1487 if (aLen >= kMaxLenPrefLangList) return;
1489 // make sure
1490 uint32_t i = 0;
1491 while (i < aLen && aPrefLangs[i] != aAddLang) {
1492 i++;
1493 }
1495 if (i == aLen) {
1496 aPrefLangs[aLen] = aAddLang;
1497 aLen++;
1498 }
1499 }
1501 void
1502 gfxPlatform::InitBackendPrefs(uint32_t aCanvasBitmask, BackendType aCanvasDefault,
1503 uint32_t aContentBitmask, BackendType aContentDefault)
1504 {
1505 mPreferredCanvasBackend = GetCanvasBackendPref(aCanvasBitmask);
1506 if (mPreferredCanvasBackend == BackendType::NONE) {
1507 mPreferredCanvasBackend = aCanvasDefault;
1508 }
1509 mFallbackCanvasBackend =
1510 GetCanvasBackendPref(aCanvasBitmask & ~BackendTypeBit(mPreferredCanvasBackend));
1512 mContentBackendBitmask = aContentBitmask;
1513 mContentBackend = GetContentBackendPref(mContentBackendBitmask);
1514 if (mContentBackend == BackendType::NONE) {
1515 mContentBackend = aContentDefault;
1516 // mContentBackendBitmask is our canonical reference for supported
1517 // backends so we need to add the default if we are using it and
1518 // overriding the prefs.
1519 mContentBackendBitmask |= BackendTypeBit(aContentDefault);
1520 }
1521 }
1523 /* static */ BackendType
1524 gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask)
1525 {
1526 return GetBackendPref("gfx.canvas.azure.backends", aBackendBitmask);
1527 }
1529 /* static */ BackendType
1530 gfxPlatform::GetContentBackendPref(uint32_t &aBackendBitmask)
1531 {
1532 return GetBackendPref("gfx.content.azure.backends", aBackendBitmask);
1533 }
1535 /* static */ BackendType
1536 gfxPlatform::GetBackendPref(const char* aBackendPrefName, uint32_t &aBackendBitmask)
1537 {
1538 nsTArray<nsCString> backendList;
1539 nsCString prefString;
1540 if (NS_SUCCEEDED(Preferences::GetCString(aBackendPrefName, &prefString))) {
1541 ParseString(prefString, ',', backendList);
1542 }
1544 uint32_t allowedBackends = 0;
1545 BackendType result = BackendType::NONE;
1546 for (uint32_t i = 0; i < backendList.Length(); ++i) {
1547 BackendType type = BackendTypeForName(backendList[i]);
1548 if (BackendTypeBit(type) & aBackendBitmask) {
1549 allowedBackends |= BackendTypeBit(type);
1550 if (result == BackendType::NONE) {
1551 result = type;
1552 }
1553 }
1554 }
1556 aBackendBitmask = allowedBackends;
1557 return result;
1558 }
1560 bool
1561 gfxPlatform::OffMainThreadCompositingEnabled()
1562 {
1563 return XRE_GetProcessType() == GeckoProcessType_Default ?
1564 CompositorParent::CompositorLoop() != nullptr :
1565 CompositorChild::ChildProcessHasCompositor();
1566 }
1568 eCMSMode
1569 gfxPlatform::GetCMSMode()
1570 {
1571 if (gCMSInitialized == false) {
1572 gCMSInitialized = true;
1574 int32_t mode = gfxPrefs::CMSMode();
1575 if (mode >= 0 && mode < eCMSMode_AllCount) {
1576 gCMSMode = static_cast<eCMSMode>(mode);
1577 }
1579 bool enableV4 = gfxPrefs::CMSEnableV4();
1580 if (enableV4) {
1581 qcms_enable_iccv4();
1582 }
1583 }
1584 return gCMSMode;
1585 }
1587 int
1588 gfxPlatform::GetRenderingIntent()
1589 {
1590 if (!gCMSIntentInitialized) {
1591 gCMSIntentInitialized = true;
1593 // gfxPrefs.h is using 0 as the default for the rendering
1594 // intent preference, based on that being the value for
1595 // QCMS_INTENT_DEFAULT. Assert here to catch if that ever
1596 // changes and we can then figure out what to do about it.
1597 MOZ_ASSERT(QCMS_INTENT_DEFAULT == 0);
1599 /* Try to query the pref system for a rendering intent. */
1600 int32_t pIntent = gfxPrefs::CMSRenderingIntent();
1601 if ((pIntent >= QCMS_INTENT_MIN) && (pIntent <= QCMS_INTENT_MAX)) {
1602 gCMSIntent = pIntent;
1603 } else {
1604 /* If the pref is out of range, use embedded profile. */
1605 gCMSIntent = -1;
1606 }
1607 }
1608 return gCMSIntent;
1609 }
1611 void
1612 gfxPlatform::TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *transform)
1613 {
1615 if (transform) {
1616 /* we want the bytes in RGB order */
1617 #ifdef IS_LITTLE_ENDIAN
1618 /* ABGR puts the bytes in |RGBA| order on little endian */
1619 uint32_t packed = in.Packed(gfxRGBA::PACKED_ABGR);
1620 qcms_transform_data(transform,
1621 (uint8_t *)&packed, (uint8_t *)&packed,
1622 1);
1623 out.~gfxRGBA();
1624 new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ABGR);
1625 #else
1626 /* ARGB puts the bytes in |ARGB| order on big endian */
1627 uint32_t packed = in.Packed(gfxRGBA::PACKED_ARGB);
1628 /* add one to move past the alpha byte */
1629 qcms_transform_data(transform,
1630 (uint8_t *)&packed + 1, (uint8_t *)&packed + 1,
1631 1);
1632 out.~gfxRGBA();
1633 new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ARGB);
1634 #endif
1635 }
1637 else if (&out != &in)
1638 out = in;
1639 }
1641 void
1642 gfxPlatform::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
1643 {
1644 mem = nullptr;
1645 size = 0;
1646 }
1648 void
1649 gfxPlatform::GetCMSOutputProfileData(void *&mem, size_t &size)
1650 {
1651 nsAdoptingCString fname = Preferences::GetCString("gfx.color_management.display_profile");
1652 if (!fname.IsEmpty()) {
1653 qcms_data_from_path(fname, &mem, &size);
1654 }
1655 else {
1656 gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile(mem, size);
1657 }
1658 }
1660 void
1661 gfxPlatform::CreateCMSOutputProfile()
1662 {
1663 if (!gCMSOutputProfile) {
1664 /* Determine if we're using the internal override to force sRGB as
1665 an output profile for reftests. See Bug 452125.
1667 Note that we don't normally (outside of tests) set a
1668 default value of this preference, which means nsIPrefBranch::GetBoolPref
1669 will typically throw (and leave its out-param untouched).
1670 */
1671 if (Preferences::GetBool(GFX_PREF_CMS_FORCE_SRGB, false)) {
1672 gCMSOutputProfile = GetCMSsRGBProfile();
1673 }
1675 if (!gCMSOutputProfile) {
1676 void* mem = nullptr;
1677 size_t size = 0;
1679 GetCMSOutputProfileData(mem, size);
1680 if ((mem != nullptr) && (size > 0)) {
1681 gCMSOutputProfile = qcms_profile_from_memory(mem, size);
1682 free(mem);
1683 }
1684 }
1686 /* Determine if the profile looks bogus. If so, close the profile
1687 * and use sRGB instead. See bug 460629, */
1688 if (gCMSOutputProfile && qcms_profile_is_bogus(gCMSOutputProfile)) {
1689 NS_ASSERTION(gCMSOutputProfile != GetCMSsRGBProfile(),
1690 "Builtin sRGB profile tagged as bogus!!!");
1691 qcms_profile_release(gCMSOutputProfile);
1692 gCMSOutputProfile = nullptr;
1693 }
1695 if (!gCMSOutputProfile) {
1696 gCMSOutputProfile = GetCMSsRGBProfile();
1697 }
1698 /* Precache the LUT16 Interpolations for the output profile. See
1699 bug 444661 for details. */
1700 qcms_profile_precache_output_transform(gCMSOutputProfile);
1701 }
1702 }
1704 qcms_profile *
1705 gfxPlatform::GetCMSOutputProfile()
1706 {
1707 return gCMSOutputProfile;
1708 }
1710 qcms_profile *
1711 gfxPlatform::GetCMSsRGBProfile()
1712 {
1713 if (!gCMSsRGBProfile) {
1715 /* Create the profile using qcms. */
1716 gCMSsRGBProfile = qcms_profile_sRGB();
1717 }
1718 return gCMSsRGBProfile;
1719 }
1721 qcms_transform *
1722 gfxPlatform::GetCMSRGBTransform()
1723 {
1724 if (!gCMSRGBTransform) {
1725 qcms_profile *inProfile, *outProfile;
1726 outProfile = GetCMSOutputProfile();
1727 inProfile = GetCMSsRGBProfile();
1729 if (!inProfile || !outProfile)
1730 return nullptr;
1732 gCMSRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
1733 outProfile, QCMS_DATA_RGB_8,
1734 QCMS_INTENT_PERCEPTUAL);
1735 }
1737 return gCMSRGBTransform;
1738 }
1740 qcms_transform *
1741 gfxPlatform::GetCMSInverseRGBTransform()
1742 {
1743 if (!gCMSInverseRGBTransform) {
1744 qcms_profile *inProfile, *outProfile;
1745 inProfile = GetCMSOutputProfile();
1746 outProfile = GetCMSsRGBProfile();
1748 if (!inProfile || !outProfile)
1749 return nullptr;
1751 gCMSInverseRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
1752 outProfile, QCMS_DATA_RGB_8,
1753 QCMS_INTENT_PERCEPTUAL);
1754 }
1756 return gCMSInverseRGBTransform;
1757 }
1759 qcms_transform *
1760 gfxPlatform::GetCMSRGBATransform()
1761 {
1762 if (!gCMSRGBATransform) {
1763 qcms_profile *inProfile, *outProfile;
1764 outProfile = GetCMSOutputProfile();
1765 inProfile = GetCMSsRGBProfile();
1767 if (!inProfile || !outProfile)
1768 return nullptr;
1770 gCMSRGBATransform = qcms_transform_create(inProfile, QCMS_DATA_RGBA_8,
1771 outProfile, QCMS_DATA_RGBA_8,
1772 QCMS_INTENT_PERCEPTUAL);
1773 }
1775 return gCMSRGBATransform;
1776 }
1778 /* Shuts down various transforms and profiles for CMS. */
1779 static void ShutdownCMS()
1780 {
1782 if (gCMSRGBTransform) {
1783 qcms_transform_release(gCMSRGBTransform);
1784 gCMSRGBTransform = nullptr;
1785 }
1786 if (gCMSInverseRGBTransform) {
1787 qcms_transform_release(gCMSInverseRGBTransform);
1788 gCMSInverseRGBTransform = nullptr;
1789 }
1790 if (gCMSRGBATransform) {
1791 qcms_transform_release(gCMSRGBATransform);
1792 gCMSRGBATransform = nullptr;
1793 }
1794 if (gCMSOutputProfile) {
1795 qcms_profile_release(gCMSOutputProfile);
1797 // handle the aliased case
1798 if (gCMSsRGBProfile == gCMSOutputProfile)
1799 gCMSsRGBProfile = nullptr;
1800 gCMSOutputProfile = nullptr;
1801 }
1802 if (gCMSsRGBProfile) {
1803 qcms_profile_release(gCMSsRGBProfile);
1804 gCMSsRGBProfile = nullptr;
1805 }
1807 // Reset the state variables
1808 gCMSIntent = -2;
1809 gCMSMode = eCMSMode_Off;
1810 gCMSInitialized = false;
1811 }
1813 // default SetupClusterBoundaries, based on Unicode properties;
1814 // platform subclasses may override if they wish
1815 void
1816 gfxPlatform::SetupClusterBoundaries(gfxTextRun *aTextRun, const char16_t *aString)
1817 {
1818 if (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) {
1819 // 8-bit text doesn't have clusters.
1820 // XXX is this true in all languages???
1821 // behdad: don't think so. Czech for example IIRC has a
1822 // 'ch' grapheme.
1823 // jfkthame: but that's not expected to behave as a grapheme cluster
1824 // for selection/editing/etc.
1825 return;
1826 }
1828 aTextRun->SetupClusterBoundaries(0, aString, aTextRun->GetLength());
1829 }
1831 int32_t
1832 gfxPlatform::GetBidiNumeralOption()
1833 {
1834 if (mBidiNumeralOption == UNINITIALIZED_VALUE) {
1835 mBidiNumeralOption = Preferences::GetInt(BIDI_NUMERAL_PREF, 0);
1836 }
1837 return mBidiNumeralOption;
1838 }
1840 static void
1841 FlushFontAndWordCaches()
1842 {
1843 gfxFontCache *fontCache = gfxFontCache::GetCache();
1844 if (fontCache) {
1845 fontCache->AgeAllGenerations();
1846 fontCache->FlushShapedWordCaches();
1847 }
1848 }
1850 void
1851 gfxPlatform::FontsPrefsChanged(const char *aPref)
1852 {
1853 NS_ASSERTION(aPref != nullptr, "null preference");
1854 if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) {
1855 mAllowDownloadableFonts = UNINITIALIZED_VALUE;
1856 } else if (!strcmp(GFX_PREF_FALLBACK_USE_CMAPS, aPref)) {
1857 mFallbackUsesCmaps = UNINITIALIZED_VALUE;
1858 } else if (!strcmp(GFX_PREF_WORD_CACHE_CHARLIMIT, aPref)) {
1859 mWordCacheCharLimit = UNINITIALIZED_VALUE;
1860 FlushFontAndWordCaches();
1861 } else if (!strcmp(GFX_PREF_WORD_CACHE_MAXENTRIES, aPref)) {
1862 mWordCacheMaxEntries = UNINITIALIZED_VALUE;
1863 FlushFontAndWordCaches();
1864 } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
1865 mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
1866 FlushFontAndWordCaches();
1867 } else if (!strcmp(GFX_PREF_HARFBUZZ_SCRIPTS, aPref)) {
1868 mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
1869 FlushFontAndWordCaches();
1870 } else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) {
1871 mBidiNumeralOption = UNINITIALIZED_VALUE;
1872 } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) {
1873 mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
1874 gfxFontCache::GetCache()->AgeAllGenerations();
1875 }
1876 }
1879 PRLogModuleInfo*
1880 gfxPlatform::GetLog(eGfxLog aWhichLog)
1881 {
1882 // logs shared across gfx
1883 #ifdef PR_LOGGING
1884 static PRLogModuleInfo *sFontlistLog = nullptr;
1885 static PRLogModuleInfo *sFontInitLog = nullptr;
1886 static PRLogModuleInfo *sTextrunLog = nullptr;
1887 static PRLogModuleInfo *sTextrunuiLog = nullptr;
1888 static PRLogModuleInfo *sCmapDataLog = nullptr;
1889 static PRLogModuleInfo *sTextPerfLog = nullptr;
1891 // Assume that if one is initialized, all are initialized
1892 if (!sFontlistLog) {
1893 sFontlistLog = PR_NewLogModule("fontlist");
1894 sFontInitLog = PR_NewLogModule("fontinit");
1895 sTextrunLog = PR_NewLogModule("textrun");
1896 sTextrunuiLog = PR_NewLogModule("textrunui");
1897 sCmapDataLog = PR_NewLogModule("cmapdata");
1898 sTextPerfLog = PR_NewLogModule("textperf");
1899 }
1901 switch (aWhichLog) {
1902 case eGfxLog_fontlist:
1903 return sFontlistLog;
1904 break;
1905 case eGfxLog_fontinit:
1906 return sFontInitLog;
1907 break;
1908 case eGfxLog_textrun:
1909 return sTextrunLog;
1910 break;
1911 case eGfxLog_textrunui:
1912 return sTextrunuiLog;
1913 break;
1914 case eGfxLog_cmapdata:
1915 return sCmapDataLog;
1916 break;
1917 case eGfxLog_textperf:
1918 return sTextPerfLog;
1919 break;
1920 default:
1921 break;
1922 }
1924 return nullptr;
1925 #else
1926 return nullptr;
1927 #endif
1928 }
1930 int
1931 gfxPlatform::GetScreenDepth() const
1932 {
1933 NS_WARNING("GetScreenDepth not implemented on this platform -- returning 0!");
1934 return 0;
1935 }
1937 mozilla::gfx::SurfaceFormat
1938 gfxPlatform::Optimal2DFormatForContent(gfxContentType aContent)
1939 {
1940 switch (aContent) {
1941 case gfxContentType::COLOR:
1942 switch (GetOffscreenFormat()) {
1943 case gfxImageFormat::ARGB32:
1944 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
1945 case gfxImageFormat::RGB24:
1946 return mozilla::gfx::SurfaceFormat::B8G8R8X8;
1947 case gfxImageFormat::RGB16_565:
1948 return mozilla::gfx::SurfaceFormat::R5G6B5;
1949 default:
1950 NS_NOTREACHED("unknown gfxImageFormat for gfxContentType::COLOR");
1951 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
1952 }
1953 case gfxContentType::ALPHA:
1954 return mozilla::gfx::SurfaceFormat::A8;
1955 case gfxContentType::COLOR_ALPHA:
1956 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
1957 default:
1958 NS_NOTREACHED("unknown gfxContentType");
1959 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
1960 }
1961 }
1963 gfxImageFormat
1964 gfxPlatform::OptimalFormatForContent(gfxContentType aContent)
1965 {
1966 switch (aContent) {
1967 case gfxContentType::COLOR:
1968 return GetOffscreenFormat();
1969 case gfxContentType::ALPHA:
1970 return gfxImageFormat::A8;
1971 case gfxContentType::COLOR_ALPHA:
1972 return gfxImageFormat::ARGB32;
1973 default:
1974 NS_NOTREACHED("unknown gfxContentType");
1975 return gfxImageFormat::ARGB32;
1976 }
1977 }
1979 /**
1980 * There are a number of layers acceleration (or layers in general) preferences
1981 * that should be consistent for the lifetime of the application (bug 840967).
1982 * As such, we will evaluate them all as soon as one of them is evaluated
1983 * and remember the values. Changing these preferences during the run will
1984 * not have any effect until we restart.
1985 */
1986 static bool sLayersSupportsD3D9 = false;
1987 static bool sBufferRotationCheckPref = true;
1988 static bool sPrefBrowserTabsRemoteAutostart = false;
1990 static bool sLayersAccelerationPrefsInitialized = false;
1992 void
1993 InitLayersAccelerationPrefs()
1994 {
1995 if (!sLayersAccelerationPrefsInitialized)
1996 {
1997 // If this is called for the first time on a non-main thread, we're screwed.
1998 // At the moment there's no explicit guarantee that the main thread calls
1999 // this before the compositor thread, but let's at least make the assumption
2000 // explicit.
2001 MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread");
2003 sPrefBrowserTabsRemoteAutostart = Preferences::GetBool("browser.tabs.remote.autostart", false);
2005 #ifdef XP_WIN
2006 if (gfxPrefs::LayersAccelerationForceEnabled()) {
2007 sLayersSupportsD3D9 = true;
2008 } else {
2009 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
2010 if (gfxInfo) {
2011 int32_t status;
2012 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status))) {
2013 if (status == nsIGfxInfo::FEATURE_NO_INFO) {
2014 sLayersSupportsD3D9 = true;
2015 }
2016 }
2017 }
2018 }
2019 #endif
2021 sLayersAccelerationPrefsInitialized = true;
2022 }
2023 }
2025 bool
2026 gfxPlatform::GetPrefLayersOffMainThreadCompositionEnabled()
2027 {
2028 InitLayersAccelerationPrefs();
2029 return gfxPrefs::LayersOffMainThreadCompositionEnabled() ||
2030 gfxPrefs::LayersOffMainThreadCompositionForceEnabled() ||
2031 gfxPrefs::LayersOffMainThreadCompositionTestingEnabled();
2032 }
2034 bool gfxPlatform::OffMainThreadCompositionRequired()
2035 {
2036 InitLayersAccelerationPrefs();
2037 #if defined(MOZ_WIDGET_GTK) && defined(NIGHTLY_BUILD)
2038 // Linux users who chose OpenGL are being grandfathered in to OMTC
2039 return sPrefBrowserTabsRemoteAutostart ||
2040 gfxPrefs::LayersAccelerationForceEnabled();
2041 #else
2042 return sPrefBrowserTabsRemoteAutostart;
2043 #endif
2044 }
2046 bool
2047 gfxPlatform::CanUseDirect3D9()
2048 {
2049 // this function is called from the compositor thread, so it is not
2050 // safe to init the prefs etc. from here.
2051 MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
2052 return sLayersSupportsD3D9;
2053 }
2055 bool
2056 gfxPlatform::BufferRotationEnabled()
2057 {
2058 MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
2060 return sBufferRotationCheckPref && gfxPrefs::BufferRotationEnabled();
2061 }
2063 void
2064 gfxPlatform::DisableBufferRotation()
2065 {
2066 MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
2068 sBufferRotationCheckPref = false;
2069 }
2071 TemporaryRef<ScaledFont>
2072 gfxPlatform::GetScaledFontForFontWithCairoSkia(DrawTarget* aTarget, gfxFont* aFont)
2073 {
2074 NativeFont nativeFont;
2075 if (aTarget->GetType() == BackendType::CAIRO || aTarget->GetType() == BackendType::SKIA) {
2076 nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
2077 nativeFont.mFont = aFont->GetCairoScaledFont();
2078 return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize());
2079 }
2081 return nullptr;
2082 }