1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Foundation code.
16 : *
17 : * The Initial Developer of the Original Code is Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2005
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Vladimir Vukicevic <vladimir@pobox.com>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifdef MOZ_LOGGING
39 : #define FORCE_PR_LOG /* Allow logging in the release build */
40 : #endif
41 : #include "prlog.h"
42 :
43 : #include "gfxPlatform.h"
44 :
45 : #if defined(XP_WIN)
46 : #include "gfxWindowsPlatform.h"
47 : #include "gfxD2DSurface.h"
48 : #elif defined(XP_MACOSX)
49 : #include "gfxPlatformMac.h"
50 : #elif defined(MOZ_WIDGET_GTK2)
51 : #include "gfxPlatformGtk.h"
52 : #elif defined(MOZ_WIDGET_QT)
53 : #include "gfxQtPlatform.h"
54 : #elif defined(XP_OS2)
55 : #include "gfxOS2Platform.h"
56 : #elif defined(ANDROID)
57 : #include "gfxAndroidPlatform.h"
58 : #endif
59 :
60 : #include "gfxAtoms.h"
61 : #include "gfxPlatformFontList.h"
62 : #include "gfxContext.h"
63 : #include "gfxImageSurface.h"
64 : #include "gfxUserFontSet.h"
65 : #include "nsUnicodeProperties.h"
66 : #include "harfbuzz/hb-unicode.h"
67 : #ifdef MOZ_GRAPHITE
68 : #include "gfxGraphiteShaper.h"
69 : #endif
70 :
71 : #include "nsUnicodeRange.h"
72 : #include "nsServiceManagerUtils.h"
73 : #include "nsTArray.h"
74 : #include "nsUnicharUtilCIID.h"
75 : #include "nsILocaleService.h"
76 :
77 : #include "nsWeakReference.h"
78 :
79 : #include "cairo.h"
80 : #include "qcms.h"
81 :
82 : #include "plstr.h"
83 : #include "nsCRT.h"
84 : #include "GLContext.h"
85 : #include "GLContextProvider.h"
86 :
87 : #include "mozilla/FunctionTimer.h"
88 : #include "mozilla/Preferences.h"
89 :
90 : #include "nsIGfxInfo.h"
91 :
92 : using namespace mozilla;
93 :
94 : gfxPlatform *gPlatform = nsnull;
95 : static bool gEverInitialized = false;
96 :
97 : // These two may point to the same profile
98 : static qcms_profile *gCMSOutputProfile = nsnull;
99 : static qcms_profile *gCMSsRGBProfile = nsnull;
100 :
101 : static qcms_transform *gCMSRGBTransform = nsnull;
102 : static qcms_transform *gCMSInverseRGBTransform = nsnull;
103 : static qcms_transform *gCMSRGBATransform = nsnull;
104 :
105 : static bool gCMSInitialized = false;
106 : static eCMSMode gCMSMode = eCMSMode_Off;
107 : static int gCMSIntent = -2;
108 :
109 : static void ShutdownCMS();
110 : static void MigratePrefs();
111 :
112 : #include "mozilla/gfx/2D.h"
113 : using namespace mozilla::gfx;
114 :
115 : // logs shared across gfx
116 : #ifdef PR_LOGGING
117 : static PRLogModuleInfo *sFontlistLog = nsnull;
118 : static PRLogModuleInfo *sFontInitLog = nsnull;
119 : static PRLogModuleInfo *sTextrunLog = nsnull;
120 : static PRLogModuleInfo *sTextrunuiLog = nsnull;
121 : static PRLogModuleInfo *sCmapDataLog = nsnull;
122 : #endif
123 :
124 : /* Class to listen for pref changes so that chrome code can dynamically
125 : force sRGB as an output profile. See Bug #452125. */
126 : class SRGBOverrideObserver : public nsIObserver,
127 : public nsSupportsWeakReference
128 6 : {
129 : public:
130 : NS_DECL_ISUPPORTS
131 : NS_DECL_NSIOBSERVER
132 : };
133 :
134 45 : NS_IMPL_ISUPPORTS2(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
135 :
136 : NS_IMETHODIMP
137 0 : SRGBOverrideObserver::Observe(nsISupports *aSubject,
138 : const char *aTopic,
139 : const PRUnichar *someData)
140 : {
141 0 : NS_ASSERTION(NS_strcmp(someData,
142 : NS_LITERAL_STRING("gfx.color_mangement.force_srgb").get()),
143 : "Restarting CMS on wrong pref!");
144 0 : ShutdownCMS();
145 0 : return NS_OK;
146 : }
147 :
148 : #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
149 : #define GFX_DOWNLOADABLE_FONTS_SANITIZE "gfx.downloadable_fonts.sanitize"
150 :
151 : #define GFX_PREF_HARFBUZZ_SCRIPTS "gfx.font_rendering.harfbuzz.scripts"
152 : #define HARFBUZZ_SCRIPTS_DEFAULT mozilla::unicode::SHAPING_DEFAULT
153 : #define GFX_PREF_FALLBACK_USE_CMAPS "gfx.font_rendering.fallback.always_use_cmaps"
154 :
155 : #ifdef MOZ_GRAPHITE
156 : #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
157 : #endif
158 :
159 : #define BIDI_NUMERAL_PREF "bidi.numeral"
160 :
161 : static const char* kObservedPrefs[] = {
162 : "gfx.downloadable_fonts.",
163 : "gfx.font_rendering.",
164 : "bidi.numeral",
165 : nsnull
166 : };
167 :
168 : class FontPrefsObserver : public nsIObserver
169 3 : {
170 : public:
171 : NS_DECL_ISUPPORTS
172 : NS_DECL_NSIOBSERVER
173 : };
174 :
175 108 : NS_IMPL_ISUPPORTS1(FontPrefsObserver, nsIObserver)
176 :
177 : NS_IMETHODIMP
178 0 : FontPrefsObserver::Observe(nsISupports *aSubject,
179 : const char *aTopic,
180 : const PRUnichar *someData)
181 : {
182 0 : if (!someData) {
183 0 : NS_ERROR("font pref observer code broken");
184 0 : return NS_ERROR_UNEXPECTED;
185 : }
186 0 : NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone");
187 0 : gfxPlatform::GetPlatform()->FontsPrefsChanged(NS_ConvertUTF16toUTF8(someData).get());
188 :
189 0 : return NS_OK;
190 : }
191 :
192 :
193 :
194 : // this needs to match the list of pref font.default.xx entries listed in all.js!
195 : // the order *must* match the order in eFontPrefLang
196 : static const char *gPrefLangNames[] = {
197 : "x-western",
198 : "x-central-euro",
199 : "ja",
200 : "zh-TW",
201 : "zh-CN",
202 : "zh-HK",
203 : "ko",
204 : "x-cyrillic",
205 : "x-baltic",
206 : "el",
207 : "tr",
208 : "th",
209 : "he",
210 : "ar",
211 : "x-devanagari",
212 : "x-tamil",
213 : "x-armn",
214 : "x-beng",
215 : "x-cans",
216 : "x-ethi",
217 : "x-geor",
218 : "x-gujr",
219 : "x-guru",
220 : "x-khmr",
221 : "x-mlym",
222 : "x-orya",
223 : "x-telu",
224 : "x-knda",
225 : "x-sinh",
226 : "x-tibt",
227 : "x-unicode",
228 : "x-user-def"
229 : };
230 :
231 3 : gfxPlatform::gfxPlatform()
232 3 : : mAzureBackendCollector(this, &gfxPlatform::GetAzureBackendInfo)
233 : {
234 3 : mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
235 3 : mAllowDownloadableFonts = UNINITIALIZED_VALUE;
236 3 : mDownloadableFontsSanitize = UNINITIALIZED_VALUE;
237 3 : mFallbackUsesCmaps = UNINITIALIZED_VALUE;
238 :
239 : #ifdef MOZ_GRAPHITE
240 3 : mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
241 : #endif
242 3 : mBidiNumeralOption = UNINITIALIZED_VALUE;
243 :
244 3 : if (Preferences::GetBool("gfx.canvas.azure.prefer-skia", false)) {
245 0 : mPreferredDrawTargetBackend = BACKEND_SKIA;
246 : } else {
247 3 : mPreferredDrawTargetBackend = BACKEND_NONE;
248 : }
249 3 : }
250 :
251 : gfxPlatform*
252 14 : gfxPlatform::GetPlatform()
253 : {
254 14 : if (!gPlatform) {
255 3 : Init();
256 : }
257 14 : return gPlatform;
258 : }
259 :
260 : void
261 3 : gfxPlatform::Init()
262 : {
263 3 : if (gEverInitialized) {
264 0 : NS_RUNTIMEABORT("Already started???");
265 : }
266 3 : gEverInitialized = true;
267 :
268 3 : gfxAtoms::RegisterAtoms();
269 :
270 : #ifdef PR_LOGGING
271 3 : sFontlistLog = PR_NewLogModule("fontlist");;
272 3 : sFontInitLog = PR_NewLogModule("fontinit");;
273 3 : sTextrunLog = PR_NewLogModule("textrun");;
274 3 : sTextrunuiLog = PR_NewLogModule("textrunui");;
275 3 : sCmapDataLog = PR_NewLogModule("cmapdata");;
276 : #endif
277 :
278 :
279 : /* Initialize the GfxInfo service.
280 : * Note: we can't call functions on GfxInfo that depend
281 : * on gPlatform until after it has been initialized
282 : * below. GfxInfo initialization annotates our
283 : * crash reports so we want to do it before
284 : * we try to load any drivers and do device detection
285 : * incase that code crashes. See bug #591561. */
286 6 : nsCOMPtr<nsIGfxInfo> gfxInfo;
287 : /* this currently will only succeed on Windows */
288 3 : gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
289 :
290 : #if defined(XP_WIN)
291 : gPlatform = new gfxWindowsPlatform;
292 : #elif defined(XP_MACOSX)
293 : gPlatform = new gfxPlatformMac;
294 : #elif defined(MOZ_WIDGET_GTK2)
295 3 : gPlatform = new gfxPlatformGtk;
296 : #elif defined(MOZ_WIDGET_QT)
297 : gPlatform = new gfxQtPlatform;
298 : #elif defined(XP_OS2)
299 : gPlatform = new gfxOS2Platform;
300 : #elif defined(ANDROID)
301 : gPlatform = new gfxAndroidPlatform;
302 : #else
303 : #error "No gfxPlatform implementation available"
304 : #endif
305 :
306 : #ifdef DEBUG
307 3 : mozilla::gl::GLContext::StaticInit();
308 : #endif
309 :
310 : nsresult rv;
311 :
312 : #if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID) // temporary, until this is implemented on others
313 : rv = gfxPlatformFontList::Init();
314 : if (NS_FAILED(rv)) {
315 : NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList");
316 : }
317 : #endif
318 :
319 : gPlatform->mScreenReferenceSurface =
320 : gPlatform->CreateOffscreenSurface(gfxIntSize(1,1),
321 3 : gfxASurface::CONTENT_COLOR_ALPHA);
322 3 : if (!gPlatform->mScreenReferenceSurface) {
323 0 : NS_RUNTIMEABORT("Could not initialize mScreenReferenceSurface");
324 : }
325 :
326 3 : rv = gfxFontCache::Init();
327 3 : if (NS_FAILED(rv)) {
328 0 : NS_RUNTIMEABORT("Could not initialize gfxFontCache");
329 : }
330 :
331 : /* Pref migration hook. */
332 3 : MigratePrefs();
333 :
334 : /* Create and register our CMS Override observer. */
335 3 : gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
336 3 : Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, "gfx.color_management.force_srgb");
337 :
338 3 : gPlatform->mFontPrefsObserver = new FontPrefsObserver();
339 3 : Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
340 :
341 : // Force registration of the gfx component, thus arranging for
342 : // ::Shutdown to be called.
343 : nsCOMPtr<nsISupports> forceReg
344 3 : = do_CreateInstance("@mozilla.org/gfx/init;1");
345 3 : }
346 :
347 : void
348 4 : gfxPlatform::Shutdown()
349 : {
350 : // These may be called before the corresponding subsystems have actually
351 : // started up. That's OK, they can handle it.
352 4 : gfxFontCache::Shutdown();
353 4 : gfxFontGroup::Shutdown();
354 : #ifdef MOZ_GRAPHITE
355 4 : gfxGraphiteShaper::Shutdown();
356 : #endif
357 : #if defined(XP_MACOSX) || defined(XP_WIN) // temporary, until this is implemented on others
358 : gfxPlatformFontList::Shutdown();
359 : #endif
360 :
361 : // Free the various non-null transforms and loaded profiles
362 4 : ShutdownCMS();
363 :
364 : // In some cases, gPlatform may not be created but Shutdown() called,
365 : // e.g., during xpcshell tests.
366 4 : if (gPlatform) {
367 : /* Unregister our CMS Override callback. */
368 3 : NS_ASSERTION(gPlatform->mSRGBOverrideObserver, "mSRGBOverrideObserver has alreay gone");
369 3 : Preferences::RemoveObserver(gPlatform->mSRGBOverrideObserver, "gfx.color_management.force_srgb");
370 3 : gPlatform->mSRGBOverrideObserver = nsnull;
371 :
372 3 : NS_ASSERTION(gPlatform->mFontPrefsObserver, "mFontPrefsObserver has alreay gone");
373 3 : Preferences::RemoveObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
374 3 : gPlatform->mFontPrefsObserver = nsnull;
375 : }
376 :
377 : // Shut down the default GL context provider.
378 4 : mozilla::gl::GLContextProvider::Shutdown();
379 :
380 : // We always have OSMesa at least potentially available; shut it down too.
381 4 : mozilla::gl::GLContextProviderOSMesa::Shutdown();
382 :
383 : #if defined(XP_WIN)
384 : // The above shutdown calls operate on the available context providers on
385 : // most platforms. Windows is a "special snowflake", though, and has three
386 : // context providers available, so we have to shut all of them down.
387 : // We should only support the default GL provider on Windows; then, this
388 : // could go away. Unfortunately, we currently support WGL (the default) for
389 : // WebGL on Optimus.
390 : mozilla::gl::GLContextProviderEGL::Shutdown();
391 : #endif
392 :
393 4 : delete gPlatform;
394 4 : gPlatform = nsnull;
395 4 : }
396 :
397 6 : gfxPlatform::~gfxPlatform()
398 : {
399 : // The cairo folks think we should only clean up in debug builds,
400 : // but we're generally in the habit of trying to shut down as
401 : // cleanly as possible even in production code, so call this
402 : // cairo_debug_* function unconditionally.
403 : //
404 : // because cairo can assert and thus crash on shutdown, don't do this in release builds
405 : #if MOZ_TREE_CAIRO && (defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) || defined(NS_TRACE_MALLOC))
406 3 : cairo_debug_reset_static_data();
407 : #endif
408 :
409 : #if 0
410 : // It would be nice to do this (although it might need to be after
411 : // the cairo shutdown that happens in ~gfxPlatform). It even looks
412 : // idempotent. But it has fatal assertions that fire if stuff is
413 : // leaked, and we hit them.
414 : FcFini();
415 : #endif
416 6 : }
417 :
418 : already_AddRefed<gfxASurface>
419 14 : gfxPlatform::OptimizeImage(gfxImageSurface *aSurface,
420 : gfxASurface::gfxImageFormat format)
421 : {
422 14 : const gfxIntSize& surfaceSize = aSurface->GetSize();
423 :
424 : #ifdef XP_WIN
425 : if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
426 : gfxWindowsPlatform::RENDER_DIRECT2D) {
427 : return nsnull;
428 : }
429 : #endif
430 28 : nsRefPtr<gfxASurface> optSurface = CreateOffscreenSurface(surfaceSize, gfxASurface::ContentFromFormat(format));
431 14 : if (!optSurface || optSurface->CairoStatus() != 0)
432 0 : return nsnull;
433 :
434 28 : gfxContext tmpCtx(optSurface);
435 14 : tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
436 14 : tmpCtx.SetSource(aSurface);
437 14 : tmpCtx.Paint();
438 :
439 14 : gfxASurface *ret = optSurface;
440 14 : NS_ADDREF(ret);
441 14 : return ret;
442 : }
443 :
444 : cairo_user_data_key_t kDrawTarget;
445 :
446 : RefPtr<DrawTarget>
447 0 : gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface)
448 : {
449 0 : RefPtr<DrawTarget> drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface());
450 0 : aSurface->SetData(&kDrawTarget, drawTarget, NULL);
451 : return drawTarget;
452 : }
453 :
454 : cairo_user_data_key_t kSourceSurface;
455 :
456 0 : void SourceBufferDestroy(void *srcBuffer)
457 : {
458 0 : static_cast<SourceSurface*>(srcBuffer)->Release();
459 0 : }
460 :
461 0 : void SourceSnapshotDetached(cairo_surface_t *nullSurf)
462 : {
463 : gfxImageSurface* origSurf =
464 0 : static_cast<gfxImageSurface*>(cairo_surface_get_user_data(nullSurf, &kSourceSurface));
465 :
466 0 : origSurf->SetData(&kSourceSurface, NULL, NULL);
467 0 : }
468 :
469 : RefPtr<SourceSurface>
470 0 : gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface)
471 : {
472 0 : void *userData = aSurface->GetData(&kSourceSurface);
473 :
474 0 : if (userData) {
475 0 : return static_cast<SourceSurface*>(userData);
476 : }
477 :
478 : SurfaceFormat format;
479 0 : if (aSurface->GetContentType() == gfxASurface::CONTENT_ALPHA) {
480 0 : format = FORMAT_A8;
481 0 : } else if (aSurface->GetContentType() == gfxASurface::CONTENT_COLOR) {
482 0 : format = FORMAT_B8G8R8X8;
483 : } else {
484 0 : format = FORMAT_B8G8R8A8;
485 : }
486 :
487 0 : RefPtr<SourceSurface> srcBuffer;
488 :
489 : #ifdef XP_WIN
490 : if (aSurface->GetType() == gfxASurface::SurfaceTypeD2D) {
491 : NativeSurface surf;
492 : surf.mFormat = format;
493 : surf.mType = NATIVE_SURFACE_D3D10_TEXTURE;
494 : surf.mSurface = static_cast<gfxD2DSurface*>(aSurface)->GetTexture();
495 : mozilla::gfx::DrawTarget *dt = static_cast<mozilla::gfx::DrawTarget*>(aSurface->GetData(&kDrawTarget));
496 : if (dt) {
497 : dt->Flush();
498 : }
499 : srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
500 : }
501 : #endif
502 :
503 0 : if (!srcBuffer) {
504 0 : nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();
505 :
506 0 : if (!imgSurface) {
507 0 : imgSurface = new gfxImageSurface(aSurface->GetSize(), gfxASurface::FormatFromContent(aSurface->GetContentType()));
508 0 : nsRefPtr<gfxContext> ctx = new gfxContext(imgSurface);
509 0 : ctx->SetSource(aSurface);
510 0 : ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
511 0 : ctx->Paint();
512 : }
513 :
514 0 : gfxImageFormat cairoFormat = imgSurface->Format();
515 0 : switch(cairoFormat) {
516 : case gfxASurface::ImageFormatARGB32:
517 0 : format = FORMAT_B8G8R8A8;
518 0 : break;
519 : case gfxASurface::ImageFormatRGB24:
520 0 : format = FORMAT_B8G8R8X8;
521 0 : break;
522 : case gfxASurface::ImageFormatA8:
523 0 : format = FORMAT_A8;
524 0 : break;
525 : case gfxASurface::ImageFormatRGB16_565:
526 0 : format = FORMAT_R5G6B5;
527 0 : break;
528 : default:
529 0 : NS_RUNTIMEABORT("Invalid surface format!");
530 : }
531 :
532 : srcBuffer = aTarget->CreateSourceSurfaceFromData(imgSurface->Data(),
533 0 : IntSize(imgSurface->GetSize().width, imgSurface->GetSize().height),
534 : imgSurface->Stride(),
535 0 : format);
536 :
537 : cairo_surface_t *nullSurf =
538 0 : cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
539 : cairo_surface_set_user_data(nullSurf,
540 : &kSourceSurface,
541 : imgSurface,
542 0 : NULL);
543 0 : cairo_surface_attach_snapshot(imgSurface->CairoSurface(), nullSurf, SourceSnapshotDetached);
544 0 : cairo_surface_destroy(nullSurf);
545 : }
546 :
547 0 : srcBuffer->AddRef();
548 0 : aSurface->SetData(&kSourceSurface, srcBuffer, SourceBufferDestroy);
549 :
550 0 : return srcBuffer;
551 : }
552 :
553 : RefPtr<ScaledFont>
554 0 : gfxPlatform::GetScaledFontForFont(gfxFont *aFont)
555 : {
556 : NativeFont nativeFont;
557 0 : nativeFont.mType = NATIVE_FONT_CAIRO_FONT_FACE;
558 0 : nativeFont.mFont = aFont;
559 : RefPtr<ScaledFont> scaledFont =
560 : Factory::CreateScaledFontForNativeFont(nativeFont,
561 0 : aFont->GetAdjustedSize());
562 : return scaledFont;
563 : }
564 :
565 : cairo_user_data_key_t kDrawSourceSurface;
566 : static void
567 0 : DataSourceSurfaceDestroy(void *dataSourceSurface)
568 : {
569 0 : static_cast<DataSourceSurface*>(dataSourceSurface)->Release();
570 0 : }
571 :
572 : UserDataKey kThebesSurfaceKey;
573 : void
574 0 : DestroyThebesSurface(void *data)
575 : {
576 0 : gfxASurface *surface = static_cast<gfxASurface*>(data);
577 0 : surface->Release();
578 0 : }
579 :
580 : already_AddRefed<gfxASurface>
581 0 : gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
582 : {
583 : // If we have already created a thebes surface, we can just return it.
584 0 : void *surface = aTarget->GetUserData(&kThebesSurfaceKey);
585 0 : if (surface) {
586 0 : nsRefPtr<gfxASurface> surf = static_cast<gfxASurface*>(surface);
587 0 : return surf.forget();
588 : }
589 :
590 0 : nsRefPtr<gfxASurface> surf;
591 0 : if (aTarget->GetType() == BACKEND_CAIRO) {
592 : cairo_surface_t* csurf =
593 0 : static_cast<cairo_surface_t*>(aTarget->GetNativeSurface(NATIVE_SURFACE_CAIRO_SURFACE));
594 0 : surf = gfxASurface::Wrap(csurf);
595 : } else {
596 : // The semantics of this part of the function are sort of weird. If we
597 : // don't have direct support for the backend, we snapshot the first time
598 : // and then return the snapshotted surface for the lifetime of the draw
599 : // target. Sometimes it seems like this works out, but it seems like it
600 : // might result in no updates ever.
601 0 : RefPtr<SourceSurface> source = aTarget->Snapshot();
602 0 : RefPtr<DataSourceSurface> data = source->GetDataSurface();
603 :
604 0 : if (!data) {
605 0 : return NULL;
606 : }
607 :
608 0 : IntSize size = data->GetSize();
609 0 : gfxASurface::gfxImageFormat format = gfxASurface::FormatFromContent(ContentForFormat(data->GetFormat()));
610 :
611 : surf =
612 0 : new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height),
613 0 : data->Stride(), format);
614 :
615 0 : surf->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy);
616 : }
617 :
618 : // add a reference to be held by the drawTarget
619 : // careful, the reference graph is getting complicated here
620 0 : surf->AddRef();
621 0 : aTarget->AddUserData(&kThebesSurfaceKey, surf.get(), DestroyThebesSurface);
622 :
623 0 : return surf.forget();
624 : }
625 :
626 : RefPtr<DrawTarget>
627 0 : gfxPlatform::CreateOffscreenDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
628 : {
629 : BackendType backend;
630 0 : if (!SupportsAzure(backend)) {
631 0 : return NULL;
632 : }
633 :
634 : // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
635 : // create the best offscreen surface for the current system and situation. We
636 : // can easily take advantage of this for the Cairo backend, so that's what we
637 : // do.
638 : // mozilla::gfx::Factory can get away without having all this knowledge for
639 : // now, but this might need to change in the future (using
640 : // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all
641 : // backends).
642 0 : if (backend == BACKEND_CAIRO) {
643 : nsRefPtr<gfxASurface> surf = CreateOffscreenSurface(ThebesIntSize(aSize),
644 0 : ContentForFormat(aFormat));
645 :
646 0 : return CreateDrawTargetForSurface(surf);
647 : } else {
648 0 : return Factory::CreateDrawTarget(backend, aSize, aFormat);
649 : }
650 : }
651 :
652 : nsresult
653 0 : gfxPlatform::GetFontList(nsIAtom *aLangGroup,
654 : const nsACString& aGenericFamily,
655 : nsTArray<nsString>& aListOfFonts)
656 : {
657 0 : return NS_ERROR_NOT_IMPLEMENTED;
658 : }
659 :
660 : nsresult
661 0 : gfxPlatform::UpdateFontList()
662 : {
663 0 : return NS_ERROR_NOT_IMPLEMENTED;
664 : }
665 :
666 : bool
667 0 : gfxPlatform::DownloadableFontsEnabled()
668 : {
669 0 : if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
670 : mAllowDownloadableFonts =
671 0 : Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false);
672 : }
673 :
674 0 : return mAllowDownloadableFonts;
675 : }
676 :
677 : bool
678 0 : gfxPlatform::SanitizeDownloadedFonts()
679 : {
680 0 : if (mDownloadableFontsSanitize == UNINITIALIZED_VALUE) {
681 : mDownloadableFontsSanitize =
682 0 : Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_SANITIZE, true);
683 : }
684 :
685 0 : return mDownloadableFontsSanitize;
686 : }
687 :
688 : bool
689 0 : gfxPlatform::UseCmapsDuringSystemFallback()
690 : {
691 0 : if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) {
692 : mFallbackUsesCmaps =
693 0 : Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false);
694 : }
695 :
696 0 : return mFallbackUsesCmaps;
697 : }
698 :
699 : #ifdef MOZ_GRAPHITE
700 : bool
701 0 : gfxPlatform::UseGraphiteShaping()
702 : {
703 0 : if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) {
704 : mGraphiteShapingEnabled =
705 0 : Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
706 : }
707 :
708 0 : return mGraphiteShapingEnabled;
709 : }
710 : #endif
711 :
712 : bool
713 0 : gfxPlatform::UseHarfBuzzForScript(PRInt32 aScriptCode)
714 : {
715 0 : if (mUseHarfBuzzScripts == UNINITIALIZED_VALUE) {
716 0 : mUseHarfBuzzScripts = Preferences::GetInt(GFX_PREF_HARFBUZZ_SCRIPTS, HARFBUZZ_SCRIPTS_DEFAULT);
717 : }
718 :
719 0 : PRInt32 shapingType = mozilla::unicode::ScriptShapingType(aScriptCode);
720 :
721 0 : return (mUseHarfBuzzScripts & shapingType) != 0;
722 : }
723 :
724 : gfxFontEntry*
725 0 : gfxPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
726 : const PRUint8 *aFontData,
727 : PRUint32 aLength)
728 : {
729 : // Default implementation does not handle activating downloaded fonts;
730 : // just free the data and return.
731 : // Platforms that support @font-face must override this,
732 : // using the data to instantiate the font, and taking responsibility
733 : // for freeing it when no longer required.
734 0 : if (aFontData) {
735 0 : NS_Free((void*)aFontData);
736 : }
737 0 : return nsnull;
738 : }
739 :
740 : static void
741 0 : AppendGenericFontFromPref(nsString& aFonts, nsIAtom *aLangGroup, const char *aGenericName)
742 : {
743 0 : NS_ENSURE_TRUE(Preferences::GetRootBranch(), );
744 :
745 0 : nsCAutoString prefName, langGroupString;
746 :
747 0 : aLangGroup->ToUTF8String(langGroupString);
748 :
749 0 : nsCAutoString genericDotLang;
750 0 : if (aGenericName) {
751 0 : genericDotLang.Assign(aGenericName);
752 : } else {
753 0 : prefName.AssignLiteral("font.default.");
754 0 : prefName.Append(langGroupString);
755 0 : genericDotLang = Preferences::GetCString(prefName.get());
756 : }
757 :
758 0 : genericDotLang.AppendLiteral(".");
759 0 : genericDotLang.Append(langGroupString);
760 :
761 : // fetch font.name.xxx value
762 0 : prefName.AssignLiteral("font.name.");
763 0 : prefName.Append(genericDotLang);
764 0 : nsAdoptingString nameValue = Preferences::GetString(prefName.get());
765 0 : if (nameValue) {
766 0 : if (!aFonts.IsEmpty())
767 0 : aFonts.AppendLiteral(", ");
768 0 : aFonts += nameValue;
769 : }
770 :
771 : // fetch font.name-list.xxx value
772 0 : prefName.AssignLiteral("font.name-list.");
773 0 : prefName.Append(genericDotLang);
774 0 : nsAdoptingString nameListValue = Preferences::GetString(prefName.get());
775 0 : if (nameListValue && !nameListValue.Equals(nameValue)) {
776 0 : if (!aFonts.IsEmpty())
777 0 : aFonts.AppendLiteral(", ");
778 0 : aFonts += nameListValue;
779 : }
780 : }
781 :
782 : void
783 0 : gfxPlatform::GetPrefFonts(nsIAtom *aLanguage, nsString& aFonts, bool aAppendUnicode)
784 : {
785 0 : aFonts.Truncate();
786 :
787 0 : AppendGenericFontFromPref(aFonts, aLanguage, nsnull);
788 0 : if (aAppendUnicode)
789 0 : AppendGenericFontFromPref(aFonts, gfxAtoms::x_unicode, nsnull);
790 0 : }
791 :
792 0 : bool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], PRUint32 aLangArrayLen, PrefFontCallback aCallback,
793 : void *aClosure)
794 : {
795 0 : NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
796 :
797 : PRUint32 i;
798 0 : for (i = 0; i < aLangArrayLen; i++) {
799 0 : eFontPrefLang prefLang = aLangArray[i];
800 0 : const char *langGroup = GetPrefLangName(prefLang);
801 :
802 0 : nsCAutoString prefName;
803 :
804 0 : prefName.AssignLiteral("font.default.");
805 0 : prefName.Append(langGroup);
806 0 : nsAdoptingCString genericDotLang = Preferences::GetCString(prefName.get());
807 :
808 0 : genericDotLang.AppendLiteral(".");
809 0 : genericDotLang.Append(langGroup);
810 :
811 : // fetch font.name.xxx value
812 0 : prefName.AssignLiteral("font.name.");
813 0 : prefName.Append(genericDotLang);
814 0 : nsAdoptingCString nameValue = Preferences::GetCString(prefName.get());
815 0 : if (nameValue) {
816 0 : if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(nameValue), aClosure))
817 0 : return false;
818 : }
819 :
820 : // fetch font.name-list.xxx value
821 0 : prefName.AssignLiteral("font.name-list.");
822 0 : prefName.Append(genericDotLang);
823 0 : nsAdoptingCString nameListValue = Preferences::GetCString(prefName.get());
824 0 : if (nameListValue && !nameListValue.Equals(nameValue)) {
825 0 : const char kComma = ',';
826 : const char *p, *p_end;
827 0 : nsCAutoString list(nameListValue);
828 0 : list.BeginReading(p);
829 0 : list.EndReading(p_end);
830 0 : while (p < p_end) {
831 0 : while (nsCRT::IsAsciiSpace(*p)) {
832 0 : if (++p == p_end)
833 0 : break;
834 : }
835 0 : if (p == p_end)
836 0 : break;
837 0 : const char *start = p;
838 0 : while (++p != p_end && *p != kComma)
839 : /* nothing */ ;
840 0 : nsCAutoString fontName(Substring(start, p));
841 0 : fontName.CompressWhitespace(false, true);
842 0 : if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(fontName), aClosure))
843 0 : return false;
844 0 : p++;
845 : }
846 : }
847 : }
848 :
849 0 : return true;
850 : }
851 :
852 : eFontPrefLang
853 0 : gfxPlatform::GetFontPrefLangFor(const char* aLang)
854 : {
855 0 : if (!aLang || !aLang[0])
856 0 : return eFontPrefLang_Others;
857 0 : for (PRUint32 i = 0; i < PRUint32(eFontPrefLang_LangCount); ++i) {
858 0 : if (!PL_strcasecmp(gPrefLangNames[i], aLang))
859 0 : return eFontPrefLang(i);
860 : }
861 0 : return eFontPrefLang_Others;
862 : }
863 :
864 : eFontPrefLang
865 0 : gfxPlatform::GetFontPrefLangFor(nsIAtom *aLang)
866 : {
867 0 : if (!aLang)
868 0 : return eFontPrefLang_Others;
869 0 : nsCAutoString lang;
870 0 : aLang->ToUTF8String(lang);
871 0 : return GetFontPrefLangFor(lang.get());
872 : }
873 :
874 : const char*
875 0 : gfxPlatform::GetPrefLangName(eFontPrefLang aLang)
876 : {
877 0 : if (PRUint32(aLang) < PRUint32(eFontPrefLang_AllCount))
878 0 : return gPrefLangNames[PRUint32(aLang)];
879 0 : return nsnull;
880 : }
881 :
882 : eFontPrefLang
883 0 : gfxPlatform::GetFontPrefLangFor(PRUint8 aUnicodeRange)
884 : {
885 0 : switch (aUnicodeRange) {
886 0 : case kRangeSetLatin: return eFontPrefLang_Western;
887 0 : case kRangeCyrillic: return eFontPrefLang_Cyrillic;
888 0 : case kRangeGreek: return eFontPrefLang_Greek;
889 0 : case kRangeTurkish: return eFontPrefLang_Turkish;
890 0 : case kRangeHebrew: return eFontPrefLang_Hebrew;
891 0 : case kRangeArabic: return eFontPrefLang_Arabic;
892 0 : case kRangeBaltic: return eFontPrefLang_Baltic;
893 0 : case kRangeThai: return eFontPrefLang_Thai;
894 0 : case kRangeKorean: return eFontPrefLang_Korean;
895 0 : case kRangeJapanese: return eFontPrefLang_Japanese;
896 0 : case kRangeSChinese: return eFontPrefLang_ChineseCN;
897 0 : case kRangeTChinese: return eFontPrefLang_ChineseTW;
898 0 : case kRangeDevanagari: return eFontPrefLang_Devanagari;
899 0 : case kRangeTamil: return eFontPrefLang_Tamil;
900 0 : case kRangeArmenian: return eFontPrefLang_Armenian;
901 0 : case kRangeBengali: return eFontPrefLang_Bengali;
902 0 : case kRangeCanadian: return eFontPrefLang_Canadian;
903 0 : case kRangeEthiopic: return eFontPrefLang_Ethiopic;
904 0 : case kRangeGeorgian: return eFontPrefLang_Georgian;
905 0 : case kRangeGujarati: return eFontPrefLang_Gujarati;
906 0 : case kRangeGurmukhi: return eFontPrefLang_Gurmukhi;
907 0 : case kRangeKhmer: return eFontPrefLang_Khmer;
908 0 : case kRangeMalayalam: return eFontPrefLang_Malayalam;
909 0 : case kRangeOriya: return eFontPrefLang_Oriya;
910 0 : case kRangeTelugu: return eFontPrefLang_Telugu;
911 0 : case kRangeKannada: return eFontPrefLang_Kannada;
912 0 : case kRangeSinhala: return eFontPrefLang_Sinhala;
913 0 : case kRangeTibetan: return eFontPrefLang_Tibetan;
914 0 : case kRangeSetCJK: return eFontPrefLang_CJKSet;
915 0 : default: return eFontPrefLang_Others;
916 : }
917 : }
918 :
919 : bool
920 0 : gfxPlatform::IsLangCJK(eFontPrefLang aLang)
921 : {
922 0 : switch (aLang) {
923 : case eFontPrefLang_Japanese:
924 : case eFontPrefLang_ChineseTW:
925 : case eFontPrefLang_ChineseCN:
926 : case eFontPrefLang_ChineseHK:
927 : case eFontPrefLang_Korean:
928 : case eFontPrefLang_CJKSet:
929 0 : return true;
930 : default:
931 0 : return false;
932 : }
933 : }
934 :
935 : void
936 0 : gfxPlatform::GetLangPrefs(eFontPrefLang aPrefLangs[], PRUint32 &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
937 : {
938 0 : if (IsLangCJK(aCharLang)) {
939 0 : AppendCJKPrefLangs(aPrefLangs, aLen, aCharLang, aPageLang);
940 : } else {
941 0 : AppendPrefLang(aPrefLangs, aLen, aCharLang);
942 : }
943 :
944 0 : AppendPrefLang(aPrefLangs, aLen, eFontPrefLang_Others);
945 0 : }
946 :
947 : void
948 0 : gfxPlatform::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], PRUint32 &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
949 : {
950 : // prefer the lang specified by the page *if* CJK
951 0 : if (IsLangCJK(aPageLang)) {
952 0 : AppendPrefLang(aPrefLangs, aLen, aPageLang);
953 : }
954 :
955 : // if not set up, set up the default CJK order, based on accept lang settings and locale
956 0 : if (mCJKPrefLangs.Length() == 0) {
957 :
958 : // temp array
959 : eFontPrefLang tempPrefLangs[kMaxLenPrefLangList];
960 0 : PRUint32 tempLen = 0;
961 :
962 : // Add the CJK pref fonts from accept languages, the order should be same order
963 0 : nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages");
964 0 : if (!list.IsEmpty()) {
965 0 : const char kComma = ',';
966 : const char *p, *p_end;
967 0 : list.BeginReading(p);
968 0 : list.EndReading(p_end);
969 0 : while (p < p_end) {
970 0 : while (nsCRT::IsAsciiSpace(*p)) {
971 0 : if (++p == p_end)
972 0 : break;
973 : }
974 0 : if (p == p_end)
975 0 : break;
976 0 : const char *start = p;
977 0 : while (++p != p_end && *p != kComma)
978 : /* nothing */ ;
979 0 : nsCAutoString lang(Substring(start, p));
980 0 : lang.CompressWhitespace(false, true);
981 0 : eFontPrefLang fpl = gfxPlatform::GetFontPrefLangFor(lang.get());
982 0 : switch (fpl) {
983 : case eFontPrefLang_Japanese:
984 : case eFontPrefLang_Korean:
985 : case eFontPrefLang_ChineseCN:
986 : case eFontPrefLang_ChineseHK:
987 : case eFontPrefLang_ChineseTW:
988 0 : AppendPrefLang(tempPrefLangs, tempLen, fpl);
989 0 : break;
990 : default:
991 0 : break;
992 : }
993 0 : p++;
994 : }
995 : }
996 :
997 : do { // to allow 'break' to abort this block if a call fails
998 : nsresult rv;
999 : nsCOMPtr<nsILocaleService> ls =
1000 0 : do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
1001 0 : if (NS_FAILED(rv))
1002 : break;
1003 :
1004 0 : nsCOMPtr<nsILocale> appLocale;
1005 0 : rv = ls->GetApplicationLocale(getter_AddRefs(appLocale));
1006 0 : if (NS_FAILED(rv))
1007 : break;
1008 :
1009 0 : nsString localeStr;
1010 0 : rv = appLocale->
1011 0 : GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr);
1012 0 : if (NS_FAILED(rv))
1013 : break;
1014 :
1015 0 : const nsAString& lang = Substring(localeStr, 0, 2);
1016 0 : if (lang.EqualsLiteral("ja")) {
1017 0 : AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
1018 0 : } else if (lang.EqualsLiteral("zh")) {
1019 0 : const nsAString& region = Substring(localeStr, 3, 2);
1020 0 : if (region.EqualsLiteral("CN")) {
1021 0 : AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
1022 0 : } else if (region.EqualsLiteral("TW")) {
1023 0 : AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
1024 0 : } else if (region.EqualsLiteral("HK")) {
1025 0 : AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
1026 : }
1027 0 : } else if (lang.EqualsLiteral("ko")) {
1028 0 : AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
1029 : }
1030 : } while (0);
1031 :
1032 : // last resort... (the order is same as old gfx.)
1033 0 : AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese);
1034 0 : AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean);
1035 0 : AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
1036 0 : AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
1037 0 : AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
1038 :
1039 : // copy into the cached array
1040 : PRUint32 j;
1041 0 : for (j = 0; j < tempLen; j++) {
1042 0 : mCJKPrefLangs.AppendElement(tempPrefLangs[j]);
1043 : }
1044 : }
1045 :
1046 : // append in cached CJK langs
1047 0 : PRUint32 i, numCJKlangs = mCJKPrefLangs.Length();
1048 :
1049 0 : for (i = 0; i < numCJKlangs; i++) {
1050 0 : AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i]));
1051 : }
1052 :
1053 0 : }
1054 :
1055 : void
1056 0 : gfxPlatform::AppendPrefLang(eFontPrefLang aPrefLangs[], PRUint32& aLen, eFontPrefLang aAddLang)
1057 : {
1058 0 : if (aLen >= kMaxLenPrefLangList) return;
1059 :
1060 : // make sure
1061 0 : PRUint32 i = 0;
1062 0 : while (i < aLen && aPrefLangs[i] != aAddLang) {
1063 0 : i++;
1064 : }
1065 :
1066 0 : if (i == aLen) {
1067 0 : aPrefLangs[aLen] = aAddLang;
1068 0 : aLen++;
1069 : }
1070 : }
1071 :
1072 : bool
1073 0 : gfxPlatform::UseAzureContentDrawing()
1074 : {
1075 : static bool sAzureContentDrawingEnabled;
1076 : static bool sAzureContentDrawingPrefCached = false;
1077 :
1078 0 : if (!sAzureContentDrawingPrefCached) {
1079 0 : sAzureContentDrawingPrefCached = true;
1080 : mozilla::Preferences::AddBoolVarCache(&sAzureContentDrawingEnabled,
1081 0 : "gfx.content.azure.enabled");
1082 : }
1083 :
1084 0 : return sAzureContentDrawingEnabled;
1085 : }
1086 :
1087 : eCMSMode
1088 15 : gfxPlatform::GetCMSMode()
1089 : {
1090 15 : if (gCMSInitialized == false) {
1091 4 : gCMSInitialized = true;
1092 : nsresult rv;
1093 :
1094 : PRInt32 mode;
1095 4 : rv = Preferences::GetInt("gfx.color_management.mode", &mode);
1096 4 : if (NS_SUCCEEDED(rv) && (mode >= 0) && (mode < eCMSMode_AllCount)) {
1097 4 : gCMSMode = static_cast<eCMSMode>(mode);
1098 : }
1099 :
1100 : bool enableV4;
1101 4 : rv = Preferences::GetBool("gfx.color_management.enablev4", &enableV4);
1102 4 : if (NS_SUCCEEDED(rv) && enableV4) {
1103 0 : qcms_enable_iccv4();
1104 : }
1105 : }
1106 15 : return gCMSMode;
1107 : }
1108 :
1109 : /* Chris Murphy (CM consultant) suggests this as a default in the event that we
1110 : cannot reproduce relative + Black Point Compensation. BPC brings an
1111 : unacceptable performance overhead, so we go with perceptual. */
1112 : #define INTENT_DEFAULT QCMS_INTENT_PERCEPTUAL
1113 : #define INTENT_MIN 0
1114 : #define INTENT_MAX 3
1115 :
1116 : int
1117 4 : gfxPlatform::GetRenderingIntent()
1118 : {
1119 4 : if (gCMSIntent == -2) {
1120 :
1121 : /* Try to query the pref system for a rendering intent. */
1122 : PRInt32 pIntent;
1123 3 : if (NS_SUCCEEDED(Preferences::GetInt("gfx.color_management.rendering_intent", &pIntent))) {
1124 : /* If the pref is within range, use it as an override. */
1125 3 : if ((pIntent >= INTENT_MIN) && (pIntent <= INTENT_MAX)) {
1126 3 : gCMSIntent = pIntent;
1127 : }
1128 : /* If the pref is out of range, use embedded profile. */
1129 : else {
1130 0 : gCMSIntent = -1;
1131 : }
1132 : }
1133 : /* If we didn't get a valid intent from prefs, use the default. */
1134 : else {
1135 0 : gCMSIntent = INTENT_DEFAULT;
1136 : }
1137 : }
1138 4 : return gCMSIntent;
1139 : }
1140 :
1141 : void
1142 0 : gfxPlatform::TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *transform)
1143 : {
1144 :
1145 0 : if (transform) {
1146 : /* we want the bytes in RGB order */
1147 : #ifdef IS_LITTLE_ENDIAN
1148 : /* ABGR puts the bytes in |RGBA| order on little endian */
1149 0 : PRUint32 packed = in.Packed(gfxRGBA::PACKED_ABGR);
1150 : qcms_transform_data(transform,
1151 : (PRUint8 *)&packed, (PRUint8 *)&packed,
1152 0 : 1);
1153 0 : out.~gfxRGBA();
1154 0 : new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ABGR);
1155 : #else
1156 : /* ARGB puts the bytes in |ARGB| order on big endian */
1157 : PRUint32 packed = in.Packed(gfxRGBA::PACKED_ARGB);
1158 : /* add one to move past the alpha byte */
1159 : qcms_transform_data(transform,
1160 : (PRUint8 *)&packed + 1, (PRUint8 *)&packed + 1,
1161 : 1);
1162 : out.~gfxRGBA();
1163 : new (&out) gfxRGBA(packed, gfxRGBA::PACKED_ARGB);
1164 : #endif
1165 : }
1166 :
1167 0 : else if (&out != &in)
1168 0 : out = in;
1169 0 : }
1170 :
1171 : qcms_profile *
1172 0 : gfxPlatform::GetPlatformCMSOutputProfile()
1173 : {
1174 0 : return nsnull;
1175 : }
1176 :
1177 : qcms_profile *
1178 0 : gfxPlatform::GetCMSOutputProfile()
1179 : {
1180 0 : if (!gCMSOutputProfile) {
1181 : NS_TIME_FUNCTION;
1182 :
1183 : /* Determine if we're using the internal override to force sRGB as
1184 : an output profile for reftests. See Bug 452125.
1185 :
1186 : Note that we don't normally (outside of tests) set a
1187 : default value of this preference, which means nsIPrefBranch::GetBoolPref
1188 : will typically throw (and leave its out-param untouched).
1189 : */
1190 0 : if (Preferences::GetBool("gfx.color_management.force_srgb", false)) {
1191 0 : gCMSOutputProfile = GetCMSsRGBProfile();
1192 : }
1193 :
1194 0 : if (!gCMSOutputProfile) {
1195 0 : nsAdoptingCString fname = Preferences::GetCString("gfx.color_management.display_profile");
1196 0 : if (!fname.IsEmpty()) {
1197 0 : gCMSOutputProfile = qcms_profile_from_path(fname);
1198 : }
1199 : }
1200 :
1201 0 : if (!gCMSOutputProfile) {
1202 : gCMSOutputProfile =
1203 0 : gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile();
1204 : }
1205 :
1206 : /* Determine if the profile looks bogus. If so, close the profile
1207 : * and use sRGB instead. See bug 460629, */
1208 0 : if (gCMSOutputProfile && qcms_profile_is_bogus(gCMSOutputProfile)) {
1209 0 : NS_ASSERTION(gCMSOutputProfile != GetCMSsRGBProfile(),
1210 : "Builtin sRGB profile tagged as bogus!!!");
1211 0 : qcms_profile_release(gCMSOutputProfile);
1212 0 : gCMSOutputProfile = nsnull;
1213 : }
1214 :
1215 0 : if (!gCMSOutputProfile) {
1216 0 : gCMSOutputProfile = GetCMSsRGBProfile();
1217 : }
1218 : /* Precache the LUT16 Interpolations for the output profile. See
1219 : bug 444661 for details. */
1220 0 : qcms_profile_precache_output_transform(gCMSOutputProfile);
1221 : }
1222 :
1223 0 : return gCMSOutputProfile;
1224 : }
1225 :
1226 : qcms_profile *
1227 0 : gfxPlatform::GetCMSsRGBProfile()
1228 : {
1229 0 : if (!gCMSsRGBProfile) {
1230 :
1231 : /* Create the profile using qcms. */
1232 0 : gCMSsRGBProfile = qcms_profile_sRGB();
1233 : }
1234 0 : return gCMSsRGBProfile;
1235 : }
1236 :
1237 : qcms_transform *
1238 0 : gfxPlatform::GetCMSRGBTransform()
1239 : {
1240 0 : if (!gCMSRGBTransform) {
1241 : qcms_profile *inProfile, *outProfile;
1242 0 : outProfile = GetCMSOutputProfile();
1243 0 : inProfile = GetCMSsRGBProfile();
1244 :
1245 0 : if (!inProfile || !outProfile)
1246 0 : return nsnull;
1247 :
1248 : gCMSRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
1249 : outProfile, QCMS_DATA_RGB_8,
1250 0 : QCMS_INTENT_PERCEPTUAL);
1251 : }
1252 :
1253 0 : return gCMSRGBTransform;
1254 : }
1255 :
1256 : qcms_transform *
1257 0 : gfxPlatform::GetCMSInverseRGBTransform()
1258 : {
1259 0 : if (!gCMSInverseRGBTransform) {
1260 : qcms_profile *inProfile, *outProfile;
1261 0 : inProfile = GetCMSOutputProfile();
1262 0 : outProfile = GetCMSsRGBProfile();
1263 :
1264 0 : if (!inProfile || !outProfile)
1265 0 : return nsnull;
1266 :
1267 : gCMSInverseRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
1268 : outProfile, QCMS_DATA_RGB_8,
1269 0 : QCMS_INTENT_PERCEPTUAL);
1270 : }
1271 :
1272 0 : return gCMSInverseRGBTransform;
1273 : }
1274 :
1275 : qcms_transform *
1276 0 : gfxPlatform::GetCMSRGBATransform()
1277 : {
1278 0 : if (!gCMSRGBATransform) {
1279 : qcms_profile *inProfile, *outProfile;
1280 0 : outProfile = GetCMSOutputProfile();
1281 0 : inProfile = GetCMSsRGBProfile();
1282 :
1283 0 : if (!inProfile || !outProfile)
1284 0 : return nsnull;
1285 :
1286 : gCMSRGBATransform = qcms_transform_create(inProfile, QCMS_DATA_RGBA_8,
1287 : outProfile, QCMS_DATA_RGBA_8,
1288 0 : QCMS_INTENT_PERCEPTUAL);
1289 : }
1290 :
1291 0 : return gCMSRGBATransform;
1292 : }
1293 :
1294 : /* Shuts down various transforms and profiles for CMS. */
1295 4 : static void ShutdownCMS()
1296 : {
1297 :
1298 4 : if (gCMSRGBTransform) {
1299 0 : qcms_transform_release(gCMSRGBTransform);
1300 0 : gCMSRGBTransform = nsnull;
1301 : }
1302 4 : if (gCMSInverseRGBTransform) {
1303 0 : qcms_transform_release(gCMSInverseRGBTransform);
1304 0 : gCMSInverseRGBTransform = nsnull;
1305 : }
1306 4 : if (gCMSRGBATransform) {
1307 0 : qcms_transform_release(gCMSRGBATransform);
1308 0 : gCMSRGBATransform = nsnull;
1309 : }
1310 4 : if (gCMSOutputProfile) {
1311 0 : qcms_profile_release(gCMSOutputProfile);
1312 :
1313 : // handle the aliased case
1314 0 : if (gCMSsRGBProfile == gCMSOutputProfile)
1315 0 : gCMSsRGBProfile = nsnull;
1316 0 : gCMSOutputProfile = nsnull;
1317 : }
1318 4 : if (gCMSsRGBProfile) {
1319 0 : qcms_profile_release(gCMSsRGBProfile);
1320 0 : gCMSsRGBProfile = nsnull;
1321 : }
1322 :
1323 : // Reset the state variables
1324 4 : gCMSIntent = -2;
1325 4 : gCMSMode = eCMSMode_Off;
1326 4 : gCMSInitialized = false;
1327 4 : }
1328 :
1329 3 : static void MigratePrefs()
1330 : {
1331 : /* Migrate from the boolean color_management.enabled pref - we now use
1332 : color_management.mode. */
1333 3 : if (Preferences::HasUserValue("gfx.color_management.enabled")) {
1334 0 : if (Preferences::GetBool("gfx.color_management.enabled", false)) {
1335 0 : Preferences::SetInt("gfx.color_management.mode", static_cast<PRInt32>(eCMSMode_All));
1336 : }
1337 0 : Preferences::ClearUser("gfx.color_management.enabled");
1338 : }
1339 3 : }
1340 :
1341 : // default SetupClusterBoundaries, based on Unicode properties;
1342 : // platform subclasses may override if they wish
1343 : void
1344 0 : gfxPlatform::SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString)
1345 : {
1346 0 : if (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) {
1347 : // 8-bit text doesn't have clusters.
1348 : // XXX is this true in all languages???
1349 : // behdad: don't think so. Czech for example IIRC has a
1350 : // 'ch' grapheme.
1351 : // jfkthame: but that's not expected to behave as a grapheme cluster
1352 : // for selection/editing/etc.
1353 0 : return;
1354 : }
1355 :
1356 : gfxShapedWord::SetupClusterBoundaries(aTextRun->GetCharacterGlyphs(),
1357 0 : aString, aTextRun->GetLength());
1358 : }
1359 :
1360 : PRInt32
1361 0 : gfxPlatform::GetBidiNumeralOption()
1362 : {
1363 0 : if (mBidiNumeralOption == UNINITIALIZED_VALUE) {
1364 0 : mBidiNumeralOption = Preferences::GetInt(BIDI_NUMERAL_PREF, 0);
1365 : }
1366 0 : return mBidiNumeralOption;
1367 : }
1368 :
1369 : void
1370 0 : gfxPlatform::FontsPrefsChanged(const char *aPref)
1371 : {
1372 0 : NS_ASSERTION(aPref != nsnull, "null preference");
1373 0 : if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) {
1374 0 : mAllowDownloadableFonts = UNINITIALIZED_VALUE;
1375 0 : } else if (!strcmp(GFX_DOWNLOADABLE_FONTS_SANITIZE, aPref)) {
1376 0 : mDownloadableFontsSanitize = UNINITIALIZED_VALUE;
1377 0 : } else if (!strcmp(GFX_PREF_FALLBACK_USE_CMAPS, aPref)) {
1378 0 : mFallbackUsesCmaps = UNINITIALIZED_VALUE;
1379 : #ifdef MOZ_GRAPHITE
1380 0 : } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
1381 0 : mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
1382 0 : gfxFontCache *fontCache = gfxFontCache::GetCache();
1383 0 : if (fontCache) {
1384 0 : fontCache->AgeAllGenerations();
1385 0 : fontCache->FlushShapedWordCaches();
1386 : }
1387 : #endif
1388 0 : } else if (!strcmp(GFX_PREF_HARFBUZZ_SCRIPTS, aPref)) {
1389 0 : mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
1390 0 : gfxFontCache *fontCache = gfxFontCache::GetCache();
1391 0 : if (fontCache) {
1392 0 : fontCache->AgeAllGenerations();
1393 0 : fontCache->FlushShapedWordCaches();
1394 : }
1395 0 : } else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) {
1396 0 : mBidiNumeralOption = UNINITIALIZED_VALUE;
1397 : }
1398 0 : }
1399 :
1400 :
1401 : PRLogModuleInfo*
1402 0 : gfxPlatform::GetLog(eGfxLog aWhichLog)
1403 : {
1404 : #ifdef PR_LOGGING
1405 0 : switch (aWhichLog) {
1406 : case eGfxLog_fontlist:
1407 0 : return sFontlistLog;
1408 : break;
1409 : case eGfxLog_fontinit:
1410 0 : return sFontInitLog;
1411 : break;
1412 : case eGfxLog_textrun:
1413 0 : return sTextrunLog;
1414 : break;
1415 : case eGfxLog_textrunui:
1416 0 : return sTextrunuiLog;
1417 : break;
1418 : case eGfxLog_cmapdata:
1419 0 : return sCmapDataLog;
1420 : break;
1421 : default:
1422 : break;
1423 : }
1424 :
1425 0 : return nsnull;
1426 : #else
1427 : return nsnull;
1428 : #endif
1429 : }
|