|
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 } |