/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is thebes gfx code. * * The Initial Developer of the Original Code is Mozilla Corporation. * Portions created by the Initial Developer are Copyright (C) 2006 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Vladimir Vukicevic * Masayuki Nakano * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "gfxPlatformMac.h" #include "gfxImageSurface.h" #include "gfxQuartzSurface.h" #include "gfxQuartzImageSurface.h" #include "gfxQuartzFontCache.h" #include "gfxAtsuiFonts.h" #include "nsIPrefBranch.h" #include "nsIPrefService.h" #include "nsIPrefLocalizedString.h" #include "nsServiceManagerUtils.h" #include "nsCRT.h" #ifdef MOZ_ENABLE_GLITZ #include "gfxGlitzSurface.h" #include "glitz-agl.h" #endif #include "lcms.h" gfxPlatformMac::gfxPlatformMac() { #ifdef MOZ_ENABLE_GLITZ if (UseGlitz()) glitz_agl_init(); #endif mOSXVersion = 0; mFontAntiAliasingThreshold = ReadAntiAliasingThreshold(); } already_AddRefed gfxPlatformMac::CreateOffscreenSurface(const gfxIntSize& size, gfxASurface::gfxImageFormat imageFormat) { gfxASurface *newSurface = nsnull; if (!UseGlitz()) { newSurface = new gfxQuartzSurface(size, imageFormat); } else { #ifdef MOZ_ENABLE_GLITZ int bpp, glitzf; switch (imageFormat) { case gfxASurface::ImageFormatARGB32: bpp = 32; glitzf = 0; // GLITZ_STANDARD_ARGB32; break; case gfxASurface::ImageFormatRGB24: bpp = 24; glitzf = 1; // GLITZ_STANDARD_RGB24; break; case gfxASurface::ImageFormatA8: bpp = 8; glitzf = 2; // GLITZ_STANDARD_A8; case gfxASurface::ImageFormatA1: bpp = 1; glitzf = 3; // GLITZ_STANDARD_A1; break; default: return nsnull; } // XXX look for the right kind of format based on bpp glitz_drawable_format_t templ; memset(&templ, 0, sizeof(templ)); templ.color.red_size = 8; templ.color.green_size = 8; templ.color.blue_size = 8; if (bpp == 32) templ.color.alpha_size = 8; else templ.color.alpha_size = 0; templ.doublebuffer = FALSE; templ.samples = 1; unsigned long mask = GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK | GLITZ_FORMAT_BLUE_SIZE_MASK | GLITZ_FORMAT_ALPHA_SIZE_MASK | GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_DOUBLEBUFFER_MASK; glitz_drawable_format_t *gdformat = glitz_agl_find_pbuffer_format(mask, &templ, 0); glitz_drawable_t *gdraw = glitz_agl_create_pbuffer_drawable(gdformat, width, height); glitz_format_t *gformat = glitz_find_standard_format(gdraw, (glitz_format_name_t) glitzf); glitz_surface_t *gsurf = glitz_surface_create(gdraw, gformat, width, height, 0, NULL); glitz_surface_attach(gsurf, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR); newSurface = new gfxGlitzSurface(gdraw, gsurf, PR_TRUE); #endif } NS_IF_ADDREF(newSurface); return newSurface; } already_AddRefed gfxPlatformMac::OptimizeImage(gfxImageSurface *aSurface, gfxASurface::gfxImageFormat format) { const gfxIntSize& surfaceSize = aSurface->GetSize(); nsRefPtr isurf = aSurface; if (format != aSurface->Format()) { isurf = new gfxImageSurface (surfaceSize, format); if (!isurf->CopyFrom (aSurface)) { // don't even bother doing anything more NS_ADDREF(aSurface); return aSurface; } } nsRefPtr ret = new gfxQuartzImageSurface(isurf); return ret.forget(); } nsresult gfxPlatformMac::ResolveFontName(const nsAString& aFontName, FontResolverCallback aCallback, void *aClosure, PRBool& aAborted) { nsAutoString resolvedName; if (!gfxQuartzFontCache::SharedFontCache()-> ResolveFontName(aFontName, resolvedName)) { aAborted = PR_FALSE; return NS_OK; } aAborted = !(*aCallback)(resolvedName, aClosure); return NS_OK; } nsresult gfxPlatformMac::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) { gfxQuartzFontCache::SharedFontCache()->GetStandardFamilyName(aFontName, aFamilyName); return NS_OK; } gfxFontGroup * gfxPlatformMac::CreateFontGroup(const nsAString &aFamilies, const gfxFontStyle *aStyle) { return new gfxAtsuiFontGroup(aFamilies, aStyle); } nsresult gfxPlatformMac::GetFontList(const nsACString& aLangGroup, const nsACString& aGenericFamily, nsStringArray& aListOfFonts) { gfxQuartzFontCache::SharedFontCache()-> GetFontList(aLangGroup, aGenericFamily, aListOfFonts); return NS_OK; } nsresult gfxPlatformMac::UpdateFontList() { gfxQuartzFontCache::SharedFontCache()->UpdateFontList(); return NS_OK; } PRInt32 gfxPlatformMac::OSXVersion() { if (!mOSXVersion) { // minor version is not accurate, use gestaltSystemVersionMajor, gestaltSystemVersionMinor, gestaltSystemVersionBugFix for these OSErr err = ::Gestalt(gestaltSystemVersion, (long int*) &mOSXVersion); if (err != noErr) { //This should probably be changed when our minimum version changes NS_ERROR("Couldn't determine OS X version, assuming 10.4"); mOSXVersion = MAC_OS_X_VERSION_10_4_HEX; } } return mOSXVersion; } void gfxPlatformMac::GetLangPrefs(eFontPrefLang aPrefLangs[], PRUint32 &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang) { if (IsLangCJK(aCharLang)) { AppendCJKPrefLangs(aPrefLangs, aLen, aCharLang, aPageLang); } else { AppendPrefLang(aPrefLangs, aLen, aCharLang); } AppendPrefLang(aPrefLangs, aLen, eFontPrefLang_Others); } void gfxPlatformMac::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], PRUint32 &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang) { nsCOMPtr prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); // prefer the lang specified by the page *if* CJK if (IsLangCJK(aPageLang)) { AppendPrefLang(aPrefLangs, aLen, aPageLang); } // if not set up, set up the default CJK order, based on accept lang settings and system script if (mCJKPrefLangs.Length() == 0) { // temp array eFontPrefLang tempPrefLangs[kMaxLenPrefLangList]; PRUint32 tempLen = 0; // Add the CJK pref fonts from accept languages, the order should be same order nsCAutoString list; nsresult rv; if (prefs) { nsCOMPtr prefString; rv = prefs->GetComplexValue("intl.accept_languages", NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(prefString)); if (prefString) { nsAutoString temp; prefString->ToString(getter_Copies(temp)); LossyCopyUTF16toASCII(temp, list); } } if (NS_SUCCEEDED(rv) && !list.IsEmpty()) { const char kComma = ','; const char *p, *p_end; list.BeginReading(p); list.EndReading(p_end); while (p < p_end) { while (nsCRT::IsAsciiSpace(*p)) { if (++p == p_end) break; } if (p == p_end) break; const char *start = p; while (++p != p_end && *p != kComma) /* nothing */ ; nsCAutoString lang(Substring(start, p)); lang.CompressWhitespace(PR_FALSE, PR_TRUE); eFontPrefLang fpl = gfxPlatform::GetFontPrefLangFor(lang.get()); switch (fpl) { case eFontPrefLang_Japanese: case eFontPrefLang_Korean: case eFontPrefLang_ChineseCN: case eFontPrefLang_ChineseHK: case eFontPrefLang_ChineseTW: AppendPrefLang(tempPrefLangs, tempLen, fpl); break; default: break; } p++; } } // Prefer the system locale if it is CJK. ScriptCode sysScript = ::GetScriptManagerVariable(smSysScript); // XXX Is not there the HK locale? switch (sysScript) { case smJapanese: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese); break; case smTradChinese: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW); break; case smKorean: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean); break; case smSimpChinese: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN); break; default: break; } // last resort... (the order is same as old gfx.) AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese); AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean); AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN); AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK); AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW); // copy into the cached array PRUint32 j; for (j = 0; j < tempLen; j++) { mCJKPrefLangs.AppendElement(tempPrefLangs[j]); } } // append in cached CJK langs PRUint32 i, numCJKlangs = mCJKPrefLangs.Length(); for (i = 0; i < numCJKlangs; i++) { AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i])); } } PRUint32 gfxPlatformMac::ReadAntiAliasingThreshold() { PRUint32 threshold = 0; // default == no threshold // first read prefs flag to determine whether to use the setting or not PRBool useAntiAliasingThreshold = PR_FALSE; nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); if (prefs) { PRBool enabled; nsresult rv = prefs->GetBoolPref("gfx.use_text_smoothing_setting", &enabled); if (NS_SUCCEEDED(rv)) { useAntiAliasingThreshold = enabled; } } // if the pref setting is disabled, return 0 which effectively disables this feature if (!useAntiAliasingThreshold) return threshold; // value set via Appearance pref panel, "Turn off text smoothing for font sizes xxx and smaller" CFNumberRef prefValue = (CFNumberRef)CFPreferencesCopyAppValue(CFSTR("AppleAntiAliasingThreshold"), kCFPreferencesCurrentApplication); if (prefValue) { if (!CFNumberGetValue(prefValue, kCFNumberIntType, &threshold)) { threshold = 0; } CFRelease(prefValue); } return threshold; } cmsHPROFILE gfxPlatformMac::GetPlatformCMSOutputProfile() { CMProfileLocation device; CMError err = CMGetDeviceProfile(cmDisplayDeviceClass, cmDefaultDeviceID, cmDefaultProfileID, &device); if (err != noErr) return nsnull; cmsHPROFILE profile = nsnull; switch (device.locType) { case cmFileBasedProfile: { FSRef fsRef; if (!FSpMakeFSRef(&device.u.fileLoc.spec, &fsRef)) { char path[512]; if (!FSRefMakePath(&fsRef, (UInt8*)(path), sizeof(path))) { profile = cmsOpenProfileFromFile(path, "r"); #ifdef DEBUG_tor if (profile) fprintf(stderr, "ICM profile read from %s fileLoc successfully\n", path); #endif } } break; } case cmPathBasedProfile: profile = cmsOpenProfileFromFile(device.u.pathLoc.path, "r"); #ifdef DEBUG_tor if (profile) fprintf(stderr, "ICM profile read from %s pathLoc successfully\n", device.u.pathLoc.path); #endif break; default: #ifdef DEBUG_tor fprintf(stderr, "Unhandled ColorSync profile location\n"); #endif break; } return profile; }