gecko/gfx/thebes/src/gfxPlatformMac.cpp

420 lines
14 KiB
C++
Raw Normal View History

/* -*- 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 <vladimir@pobox.com>
* Masayuki Nakano <masayuki@d-toybox.com>
*
* 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<gfxASurface>
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<gfxASurface>
gfxPlatformMac::OptimizeImage(gfxImageSurface *aSurface,
gfxASurface::gfxImageFormat format)
{
const gfxIntSize& surfaceSize = aSurface->GetSize();
nsRefPtr<gfxImageSurface> 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<gfxASurface> 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<nsIPrefBranch> 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<nsIPrefLocalizedString> 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<nsIPrefBranch> 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;
}