gfx/thebes/gfxPlatform.cpp

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:fdfea81ae617
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 #ifdef MOZ_LOGGING
7 #define FORCE_PR_LOG /* Allow logging in the release build */
8 #endif
9
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
14
15 #include "prlog.h"
16
17 #include "gfxPlatform.h"
18 #include "gfxPrefs.h"
19
20 #ifdef XP_WIN
21 #include <process.h>
22 #define getpid _getpid
23 #else
24 #include <unistd.h>
25 #endif
26
27 #include "nsXULAppAPI.h"
28 #include "nsDirectoryServiceUtils.h"
29 #include "nsDirectoryServiceDefs.h"
30
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
44
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"
54
55 #include "nsUnicodeRange.h"
56 #include "nsServiceManagerUtils.h"
57 #include "nsTArray.h"
58 #include "nsILocaleService.h"
59 #include "nsIObserverService.h"
60 #include "MainThreadUtils.h"
61
62 #include "nsWeakReference.h"
63
64 #include "cairo.h"
65 #include "qcms.h"
66
67 #include "plstr.h"
68 #include "nsCRT.h"
69 #include "GLContext.h"
70 #include "GLContextProvider.h"
71
72 #ifdef MOZ_WIDGET_ANDROID
73 #include "TexturePoolOGL.h"
74 #endif
75
76 #include "mozilla/Hal.h"
77 #ifdef USE_SKIA
78 #include "skia/SkGraphics.h"
79
80 #include "SkiaGLGlue.h"
81 #else
82 class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted {
83 };
84 #endif
85
86 #include "mozilla/Preferences.h"
87 #include "mozilla/Assertions.h"
88 #include "mozilla/Attributes.h"
89 #include "mozilla/Mutex.h"
90
91 #include "nsIGfxInfo.h"
92 #include "nsIXULRuntime.h"
93
94 #ifdef MOZ_WIDGET_GONK
95 namespace mozilla {
96 namespace layers {
97 void InitGralloc();
98 }
99 }
100 #endif
101
102 using namespace mozilla;
103 using namespace mozilla::layers;
104
105 gfxPlatform *gPlatform = nullptr;
106 static bool gEverInitialized = false;
107
108 static Mutex* gGfxPlatformPrefsLock = nullptr;
109
110 // These two may point to the same profile
111 static qcms_profile *gCMSOutputProfile = nullptr;
112 static qcms_profile *gCMSsRGBProfile = nullptr;
113
114 static qcms_transform *gCMSRGBTransform = nullptr;
115 static qcms_transform *gCMSInverseRGBTransform = nullptr;
116 static qcms_transform *gCMSRGBATransform = nullptr;
117
118 static bool gCMSInitialized = false;
119 static eCMSMode gCMSMode = eCMSMode_Off;
120
121 static bool gCMSIntentInitialized = false;
122 static int gCMSIntent = QCMS_INTENT_DEFAULT;
123
124
125 static void ShutdownCMS();
126
127 #include "mozilla/gfx/2D.h"
128 using namespace mozilla::gfx;
129
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 };
139
140 NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
141
142 #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
143
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"
147
148 #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
149
150 #define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit"
151 #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries"
152
153 #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
154
155 #define BIDI_NUMERAL_PREF "bidi.numeral"
156
157 #define GFX_PREF_CMS_FORCE_SRGB "gfx.color_management.force_srgb"
158
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 }
170
171 static const char* kObservedPrefs[] = {
172 "gfx.downloadable_fonts.",
173 "gfx.font_rendering.",
174 BIDI_NUMERAL_PREF,
175 nullptr
176 };
177
178 class FontPrefsObserver MOZ_FINAL : public nsIObserver
179 {
180 public:
181 NS_DECL_ISUPPORTS
182 NS_DECL_NSIOBSERVER
183 };
184
185 NS_IMPL_ISUPPORTS(FontPrefsObserver, nsIObserver)
186
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());
198
199 return NS_OK;
200 }
201
202 class MemoryPressureObserver MOZ_FINAL : public nsIObserver
203 {
204 public:
205 NS_DECL_ISUPPORTS
206 NS_DECL_NSIOBSERVER
207 };
208
209 NS_IMPL_ISUPPORTS(MemoryPressureObserver, nsIObserver)
210
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();
218
219 gfxPlatform::GetPlatform()->PurgeSkiaCache();
220 return NS_OK;
221 }
222
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 };
258
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;
266
267 mWordCacheCharLimit = UNINITIALIZED_VALUE;
268 mWordCacheMaxEntries = UNINITIALIZED_VALUE;
269 mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
270 mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
271 mBidiNumeralOption = UNINITIALIZED_VALUE;
272
273 mLayersPreferMemoryOverShmem = XRE_GetProcessType() == GeckoProcessType_Default;
274
275 mSkiaGlue = nullptr;
276
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 }
282
283 gfxPlatform*
284 gfxPlatform::GetPlatform()
285 {
286 if (!gPlatform) {
287 Init();
288 }
289 return gPlatform;
290 }
291
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");
297
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());
306
307 nsresult rv = tmpFile->AppendNative(fileName);
308 if (NS_FAILED(rv))
309 return;
310
311 rv = tmpFile->GetNativePath(fileName);
312 if (NS_FAILED(rv))
313 return;
314 }
315
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 }
323
324 void
325 gfxPlatform::Init()
326 {
327 if (gEverInitialized) {
328 NS_RUNTIMEABORT("Already started???");
329 }
330 gEverInitialized = true;
331
332 // Initialize the preferences by creating the singleton.
333 gfxPrefs::GetSingleton();
334
335 gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock");
336
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");
347
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
361
362 #ifdef DEBUG
363 mozilla::gl::GLContext::StaticInit();
364 #endif
365
366 bool useOffMainThreadCompositing = OffMainThreadCompositionRequired() ||
367 GetPrefLayersOffMainThreadCompositionEnabled();
368
369 if (!OffMainThreadCompositionRequired()) {
370 useOffMainThreadCompositing &= GetPlatform()->SupportsOffMainThreadCompositing();
371 }
372
373 if (useOffMainThreadCompositing && (XRE_GetProcessType() == GeckoProcessType_Default)) {
374 CompositorParent::StartUp();
375 if (gfxPrefs::AsyncVideoEnabled()) {
376 ImageBridgeChild::StartUp();
377 }
378 }
379
380 nsresult rv;
381
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
388
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 }
395
396 gPlatform->mScreenReferenceDrawTarget =
397 gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1),
398 SurfaceFormat::B8G8R8A8);
399 if (!gPlatform->mScreenReferenceDrawTarget) {
400 NS_RUNTIMEABORT("Could not initialize mScreenReferenceDrawTarget");
401 }
402
403 rv = gfxFontCache::Init();
404 if (NS_FAILED(rv)) {
405 NS_RUNTIMEABORT("Could not initialize gfxFontCache");
406 }
407
408 /* Create and register our CMS Override observer. */
409 gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
410 Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
411
412 gPlatform->mFontPrefsObserver = new FontPrefsObserver();
413 Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
414
415 mozilla::gl::GLContext::PlatformStartup();
416
417 #ifdef MOZ_WIDGET_ANDROID
418 // Texture pool init
419 mozilla::gl::TexturePoolOGL::Init();
420 #endif
421
422 #ifdef MOZ_WIDGET_GONK
423 mozilla::layers::InitGralloc();
424 #endif
425
426 Preferences::RegisterCallbackAndCall(RecordingPrefChanged, "gfx.2d.recording", nullptr);
427
428 CreateCMSOutputProfile();
429
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 }
436
437 RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
438 }
439
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
452
453 // Free the various non-null transforms and loaded profiles
454 ShutdownCMS();
455
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;
463
464 NS_ASSERTION(gPlatform->mFontPrefsObserver, "mFontPrefsObserver has alreay gone");
465 Preferences::RemoveObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
466 gPlatform->mFontPrefsObserver = nullptr;
467
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 }
473
474 gPlatform->mMemoryPressureObserver = nullptr;
475 gPlatform->mSkiaGlue = nullptr;
476 }
477
478 #ifdef MOZ_WIDGET_ANDROID
479 // Shut down the texture pool
480 mozilla::gl::TexturePoolOGL::Shutdown();
481 #endif
482
483 // Shut down the default GL context provider.
484 mozilla::gl::GLContextProvider::Shutdown();
485
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
495
496 delete gGfxPlatformPrefsLock;
497
498 gfxPrefs::DestroySingleton();
499 gfxFont::DestroySingletons();
500
501 delete gPlatform;
502 gPlatform = nullptr;
503 }
504
505 gfxPlatform::~gfxPlatform()
506 {
507 mScreenReferenceSurface = nullptr;
508 mScreenReferenceDrawTarget = nullptr;
509
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
522
523 #if MOZ_TREE_CAIRO
524 cairo_debug_reset_static_data();
525 #endif
526 #endif
527 }
528
529 bool
530 gfxPlatform::PreferMemoryOverShmem() const {
531 MOZ_ASSERT(!CompositorParent::IsInCompositorThread());
532 return mLayersPreferMemoryOverShmem;
533 }
534
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));
541
542 return newSurface.forget();
543 }
544
545 already_AddRefed<gfxASurface>
546 gfxPlatform::OptimizeImage(gfxImageSurface *aSurface,
547 gfxImageFormat format)
548 {
549 IntSize surfaceSize = aSurface->GetSize().ToIntSize();
550
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;
560
561 gfxContext tmpCtx(optSurface);
562 tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
563 tmpCtx.SetSource(aSurface);
564 tmpCtx.Paint();
565
566 return optSurface.forget();
567 }
568
569 cairo_user_data_key_t kDrawTarget;
570
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 }
579
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 }
596
597
598 cairo_user_data_key_t kSourceSurface;
599
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 };
612
613 void SourceBufferDestroy(void *srcSurfUD)
614 {
615 delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
616 }
617
618 UserDataKey kThebesSurface;
619
620 struct DependentSourceSurfaceUserData
621 {
622 nsRefPtr<gfxASurface> mSurface;
623 };
624
625 void SourceSurfaceDestroyed(void *aData)
626 {
627 delete static_cast<DependentSourceSurfaceUserData*>(aData);
628 }
629
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));
635
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
645
646 void
647 gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
648 {
649 aSurface->SetData(&kSourceSurface, nullptr, nullptr);
650 }
651
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 }
663
664 DataSourceSurface::MappedSurface map;
665 DebugOnly<bool> result = data->Map(DataSourceSurface::WRITE, &map);
666 MOZ_ASSERT(result, "Should always succeed mapping raw data surfaces!");
667
668 nsRefPtr<gfxImageSurface> image = new gfxImageSurface(map.mData, size, map.mStride, format);
669 nsRefPtr<gfxContext> ctx = new gfxContext(image);
670
671 ctx->SetSource(aSurface);
672 ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
673 ctx->Paint();
674
675 data->Unmap();
676
677 return data;
678 }
679
680 RefPtr<SourceSurface>
681 gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface)
682 {
683 if (!aSurface->CairoSurface() || aSurface->CairoStatus()) {
684 return nullptr;
685 }
686
687 if (!aTarget) {
688 if (ScreenReferenceDrawTarget()) {
689 aTarget = ScreenReferenceDrawTarget();
690 } else {
691 return nullptr;
692 }
693 }
694
695 void *userData = aSurface->GetData(&kSourceSurface);
696
697 if (userData) {
698 SourceSurfaceUserData *surf = static_cast<SourceSurfaceUserData*>(userData);
699
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 }
706
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 }
715
716 RefPtr<SourceSurface> srcBuffer;
717
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);
742
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 }
749
750 if (!srcBuffer) {
751 nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();
752
753 RefPtr<DataSourceSurface> dataSurf;
754
755 if (imgSurface) {
756 dataSurf = GetWrappedDataSourceSurface(aSurface);
757 } else {
758 dataSurf = CopySurface(aSurface);
759 }
760
761 if (!dataSurf) {
762 return nullptr;
763 }
764
765 srcBuffer = aTarget->OptimizeSourceSurface(dataSurf);
766
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 }
774
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);
780
781 return srcBuffer;
782 }
783
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()));
796
797 if (!result) {
798 return nullptr;
799 }
800
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);
806
807 return result;
808 }
809
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 }
821
822 cairo_user_data_key_t kDrawSourceSurface;
823 static void
824 DataSourceSurfaceDestroy(void *dataSourceSurface)
825 {
826 static_cast<DataSourceSurface*>(dataSourceSurface)->Release();
827 }
828
829 cairo_user_data_key_t kDrawTargetForSurface;
830 static void
831 DataDrawTargetDestroy(void *aTarget)
832 {
833 static_cast<DrawTarget*>(aTarget)->Release();
834 }
835
836 bool
837 gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget)
838 {
839 if (!aTarget) {
840 return false;
841 }
842
843 return SupportsAzureContentForType(aTarget->GetType());
844 }
845
846 bool
847 gfxPlatform::UseAcceleratedSkiaCanvas()
848 {
849 return gfxPrefs::CanvasAzureAccelerated() &&
850 mPreferredCanvasBackend == BackendType::SKIA;
851 }
852
853 void
854 gfxPlatform::InitializeSkiaCacheLimits()
855 {
856 if (UseAcceleratedSkiaCanvas()) {
857 bool usingDynamicCache = gfxPrefs::CanvasSkiaGLDynamicCache();
858 int cacheItemLimit = gfxPrefs::CanvasSkiaGLCacheItems();
859 int cacheSizeLimit = gfxPrefs::CanvasSkiaGLCacheSize();
860
861 // Prefs are in megabytes, but we want the sizes in bytes
862 cacheSizeLimit *= 1024*1024;
863
864 if (usingDynamicCache) {
865 uint32_t totalMemory = mozilla::hal::GetTotalSystemMemory();
866
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 }
874
875 #ifdef DEBUG
876 printf_stderr("Determined SkiaGL cache limits: Size %i, Items: %i\n", cacheSizeLimit, cacheItemLimit);
877 #endif
878
879 #ifdef USE_SKIA_GPU
880 mSkiaGlue->GetGrContext()->setTextureCacheLimits(cacheItemLimit, cacheSizeLimit);
881 #endif
882 }
883 }
884
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
906
907 return mSkiaGlue;
908 }
909
910 void
911 gfxPlatform::PurgeSkiaCache()
912 {
913 #ifdef USE_SKIA_GPU
914 if (!mSkiaGlue)
915 return;
916
917 mSkiaGlue->GetGrContext()->freeGpuResources();
918 #endif
919 }
920
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 }
931
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();
939
940 if (!data) {
941 return nullptr;
942 }
943
944 IntSize size = data->GetSize();
945 gfxImageFormat format = SurfaceFormatToImageFormat(data->GetFormat());
946
947
948 nsRefPtr<gfxASurface> surf =
949 new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height),
950 data->Stride(), format);
951
952 if (surf->CairoStatus()) {
953 return nullptr;
954 }
955
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);
960
961 return surf.forget();
962 }
963
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 }
981
982 return CreateDrawTargetForSurface(surf, aSize);
983 } else {
984 return Factory::CreateDrawTarget(aBackend, aSize, aFormat);
985 }
986 }
987
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 }
997
998 return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat);
999 }
1000
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 }
1007
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 }
1018
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 }
1032
1033 nsresult
1034 gfxPlatform::GetFontList(nsIAtom *aLangGroup,
1035 const nsACString& aGenericFamily,
1036 nsTArray<nsString>& aListOfFonts)
1037 {
1038 return NS_ERROR_NOT_IMPLEMENTED;
1039 }
1040
1041 nsresult
1042 gfxPlatform::UpdateFontList()
1043 {
1044 return NS_ERROR_NOT_IMPLEMENTED;
1045 }
1046
1047 bool
1048 gfxPlatform::DownloadableFontsEnabled()
1049 {
1050 if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
1051 mAllowDownloadableFonts =
1052 Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false);
1053 }
1054
1055 return mAllowDownloadableFonts;
1056 }
1057
1058 bool
1059 gfxPlatform::UseCmapsDuringSystemFallback()
1060 {
1061 if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) {
1062 mFallbackUsesCmaps =
1063 Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false);
1064 }
1065
1066 return mFallbackUsesCmaps;
1067 }
1068
1069 bool
1070 gfxPlatform::OpenTypeSVGEnabled()
1071 {
1072 if (mOpenTypeSVGEnabled == UNINITIALIZED_VALUE) {
1073 mOpenTypeSVGEnabled =
1074 Preferences::GetBool(GFX_PREF_OPENTYPE_SVG, false);
1075 }
1076
1077 return mOpenTypeSVGEnabled > 0;
1078 }
1079
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 }
1090
1091 return uint32_t(mWordCacheCharLimit);
1092 }
1093
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 }
1104
1105 return uint32_t(mWordCacheMaxEntries);
1106 }
1107
1108 bool
1109 gfxPlatform::UseGraphiteShaping()
1110 {
1111 if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) {
1112 mGraphiteShapingEnabled =
1113 Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
1114 }
1115
1116 return mGraphiteShapingEnabled;
1117 }
1118
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 }
1125
1126 int32_t shapingType = mozilla::unicode::ScriptShapingType(aScriptCode);
1127
1128 return (mUseHarfBuzzScripts & shapingType) != 0;
1129 }
1130
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 }
1146
1147 static void
1148 AppendGenericFontFromPref(nsString& aFonts, nsIAtom *aLangGroup, const char *aGenericName)
1149 {
1150 NS_ENSURE_TRUE_VOID(Preferences::GetRootBranch());
1151
1152 nsAutoCString prefName, langGroupString;
1153
1154 aLangGroup->ToUTF8String(langGroupString);
1155
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 }
1164
1165 genericDotLang.AppendLiteral(".");
1166 genericDotLang.Append(langGroupString);
1167
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 }
1177
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 }
1188
1189 void
1190 gfxPlatform::GetPrefFonts(nsIAtom *aLanguage, nsString& aFonts, bool aAppendUnicode)
1191 {
1192 aFonts.Truncate();
1193
1194 AppendGenericFontFromPref(aFonts, aLanguage, nullptr);
1195 if (aAppendUnicode)
1196 AppendGenericFontFromPref(aFonts, nsGkAtoms::Unicode, nullptr);
1197 }
1198
1199 bool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], uint32_t aLangArrayLen, PrefFontCallback aCallback,
1200 void *aClosure)
1201 {
1202 NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
1203
1204 uint32_t i;
1205 for (i = 0; i < aLangArrayLen; i++) {
1206 eFontPrefLang prefLang = aLangArray[i];
1207 const char *langGroup = GetPrefLangName(prefLang);
1208
1209 nsAutoCString prefName;
1210
1211 prefName.AssignLiteral("font.default.");
1212 prefName.Append(langGroup);
1213 nsAdoptingCString genericDotLang = Preferences::GetCString(prefName.get());
1214
1215 genericDotLang.AppendLiteral(".");
1216 genericDotLang.Append(langGroup);
1217
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 }
1226
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 }
1255
1256 return true;
1257 }
1258
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 }
1272
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 }
1282
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 }
1291
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 }
1328
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 }
1344
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 }
1363
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 }
1372
1373 AppendPrefLang(aPrefLangs, aLen, eFontPrefLang_Others);
1374 }
1375
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 }
1383
1384 // if not set up, set up the default CJK order, based on accept lang settings and locale
1385 if (mCJKPrefLangs.Length() == 0) {
1386
1387 // temp array
1388 eFontPrefLang tempPrefLangs[kMaxLenPrefLangList];
1389 uint32_t tempLen = 0;
1390
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 }
1425
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;
1432
1433 nsCOMPtr<nsILocale> appLocale;
1434 rv = ls->GetApplicationLocale(getter_AddRefs(appLocale));
1435 if (NS_FAILED(rv))
1436 break;
1437
1438 nsString localeStr;
1439 rv = appLocale->
1440 GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr);
1441 if (NS_FAILED(rv))
1442 break;
1443
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);
1460
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);
1467
1468 // copy into the cached array
1469 uint32_t j;
1470 for (j = 0; j < tempLen; j++) {
1471 mCJKPrefLangs.AppendElement(tempPrefLangs[j]);
1472 }
1473 }
1474
1475 // append in cached CJK langs
1476 uint32_t i, numCJKlangs = mCJKPrefLangs.Length();
1477
1478 for (i = 0; i < numCJKlangs; i++) {
1479 AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i]));
1480 }
1481
1482 }
1483
1484 void
1485 gfxPlatform::AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang)
1486 {
1487 if (aLen >= kMaxLenPrefLangList) return;
1488
1489 // make sure
1490 uint32_t i = 0;
1491 while (i < aLen && aPrefLangs[i] != aAddLang) {
1492 i++;
1493 }
1494
1495 if (i == aLen) {
1496 aPrefLangs[aLen] = aAddLang;
1497 aLen++;
1498 }
1499 }
1500
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));
1511
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 }
1522
1523 /* static */ BackendType
1524 gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask)
1525 {
1526 return GetBackendPref("gfx.canvas.azure.backends", aBackendBitmask);
1527 }
1528
1529 /* static */ BackendType
1530 gfxPlatform::GetContentBackendPref(uint32_t &aBackendBitmask)
1531 {
1532 return GetBackendPref("gfx.content.azure.backends", aBackendBitmask);
1533 }
1534
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 }
1543
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 }
1555
1556 aBackendBitmask = allowedBackends;
1557 return result;
1558 }
1559
1560 bool
1561 gfxPlatform::OffMainThreadCompositingEnabled()
1562 {
1563 return XRE_GetProcessType() == GeckoProcessType_Default ?
1564 CompositorParent::CompositorLoop() != nullptr :
1565 CompositorChild::ChildProcessHasCompositor();
1566 }
1567
1568 eCMSMode
1569 gfxPlatform::GetCMSMode()
1570 {
1571 if (gCMSInitialized == false) {
1572 gCMSInitialized = true;
1573
1574 int32_t mode = gfxPrefs::CMSMode();
1575 if (mode >= 0 && mode < eCMSMode_AllCount) {
1576 gCMSMode = static_cast<eCMSMode>(mode);
1577 }
1578
1579 bool enableV4 = gfxPrefs::CMSEnableV4();
1580 if (enableV4) {
1581 qcms_enable_iccv4();
1582 }
1583 }
1584 return gCMSMode;
1585 }
1586
1587 int
1588 gfxPlatform::GetRenderingIntent()
1589 {
1590 if (!gCMSIntentInitialized) {
1591 gCMSIntentInitialized = true;
1592
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);
1598
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 }
1610
1611 void
1612 gfxPlatform::TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *transform)
1613 {
1614
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 }
1636
1637 else if (&out != &in)
1638 out = in;
1639 }
1640
1641 void
1642 gfxPlatform::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
1643 {
1644 mem = nullptr;
1645 size = 0;
1646 }
1647
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 }
1659
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.
1666
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 }
1674
1675 if (!gCMSOutputProfile) {
1676 void* mem = nullptr;
1677 size_t size = 0;
1678
1679 GetCMSOutputProfileData(mem, size);
1680 if ((mem != nullptr) && (size > 0)) {
1681 gCMSOutputProfile = qcms_profile_from_memory(mem, size);
1682 free(mem);
1683 }
1684 }
1685
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 }
1694
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 }
1703
1704 qcms_profile *
1705 gfxPlatform::GetCMSOutputProfile()
1706 {
1707 return gCMSOutputProfile;
1708 }
1709
1710 qcms_profile *
1711 gfxPlatform::GetCMSsRGBProfile()
1712 {
1713 if (!gCMSsRGBProfile) {
1714
1715 /* Create the profile using qcms. */
1716 gCMSsRGBProfile = qcms_profile_sRGB();
1717 }
1718 return gCMSsRGBProfile;
1719 }
1720
1721 qcms_transform *
1722 gfxPlatform::GetCMSRGBTransform()
1723 {
1724 if (!gCMSRGBTransform) {
1725 qcms_profile *inProfile, *outProfile;
1726 outProfile = GetCMSOutputProfile();
1727 inProfile = GetCMSsRGBProfile();
1728
1729 if (!inProfile || !outProfile)
1730 return nullptr;
1731
1732 gCMSRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
1733 outProfile, QCMS_DATA_RGB_8,
1734 QCMS_INTENT_PERCEPTUAL);
1735 }
1736
1737 return gCMSRGBTransform;
1738 }
1739
1740 qcms_transform *
1741 gfxPlatform::GetCMSInverseRGBTransform()
1742 {
1743 if (!gCMSInverseRGBTransform) {
1744 qcms_profile *inProfile, *outProfile;
1745 inProfile = GetCMSOutputProfile();
1746 outProfile = GetCMSsRGBProfile();
1747
1748 if (!inProfile || !outProfile)
1749 return nullptr;
1750
1751 gCMSInverseRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
1752 outProfile, QCMS_DATA_RGB_8,
1753 QCMS_INTENT_PERCEPTUAL);
1754 }
1755
1756 return gCMSInverseRGBTransform;
1757 }
1758
1759 qcms_transform *
1760 gfxPlatform::GetCMSRGBATransform()
1761 {
1762 if (!gCMSRGBATransform) {
1763 qcms_profile *inProfile, *outProfile;
1764 outProfile = GetCMSOutputProfile();
1765 inProfile = GetCMSsRGBProfile();
1766
1767 if (!inProfile || !outProfile)
1768 return nullptr;
1769
1770 gCMSRGBATransform = qcms_transform_create(inProfile, QCMS_DATA_RGBA_8,
1771 outProfile, QCMS_DATA_RGBA_8,
1772 QCMS_INTENT_PERCEPTUAL);
1773 }
1774
1775 return gCMSRGBATransform;
1776 }
1777
1778 /* Shuts down various transforms and profiles for CMS. */
1779 static void ShutdownCMS()
1780 {
1781
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);
1796
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 }
1806
1807 // Reset the state variables
1808 gCMSIntent = -2;
1809 gCMSMode = eCMSMode_Off;
1810 gCMSInitialized = false;
1811 }
1812
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 }
1827
1828 aTextRun->SetupClusterBoundaries(0, aString, aTextRun->GetLength());
1829 }
1830
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 }
1839
1840 static void
1841 FlushFontAndWordCaches()
1842 {
1843 gfxFontCache *fontCache = gfxFontCache::GetCache();
1844 if (fontCache) {
1845 fontCache->AgeAllGenerations();
1846 fontCache->FlushShapedWordCaches();
1847 }
1848 }
1849
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 }
1877
1878
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;
1890
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 }
1900
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 }
1923
1924 return nullptr;
1925 #else
1926 return nullptr;
1927 #endif
1928 }
1929
1930 int
1931 gfxPlatform::GetScreenDepth() const
1932 {
1933 NS_WARNING("GetScreenDepth not implemented on this platform -- returning 0!");
1934 return 0;
1935 }
1936
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 }
1962
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 }
1978
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;
1989
1990 static bool sLayersAccelerationPrefsInitialized = false;
1991
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");
2002
2003 sPrefBrowserTabsRemoteAutostart = Preferences::GetBool("browser.tabs.remote.autostart", false);
2004
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
2020
2021 sLayersAccelerationPrefsInitialized = true;
2022 }
2023 }
2024
2025 bool
2026 gfxPlatform::GetPrefLayersOffMainThreadCompositionEnabled()
2027 {
2028 InitLayersAccelerationPrefs();
2029 return gfxPrefs::LayersOffMainThreadCompositionEnabled() ||
2030 gfxPrefs::LayersOffMainThreadCompositionForceEnabled() ||
2031 gfxPrefs::LayersOffMainThreadCompositionTestingEnabled();
2032 }
2033
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 }
2045
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 }
2054
2055 bool
2056 gfxPlatform::BufferRotationEnabled()
2057 {
2058 MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
2059
2060 return sBufferRotationCheckPref && gfxPrefs::BufferRotationEnabled();
2061 }
2062
2063 void
2064 gfxPlatform::DisableBufferRotation()
2065 {
2066 MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
2067
2068 sBufferRotationCheckPref = false;
2069 }
2070
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 }
2080
2081 return nullptr;
2082 }

mercurial