mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
373 lines
12 KiB
C++
373 lines
12 KiB
C++
/* -*- 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 Foundation.
|
|
* 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 "gfxMacPlatformFontList.h"
|
|
#include "gfxMacFont.h"
|
|
#include "gfxCoreTextShaper.h"
|
|
#include "gfxUserFontSet.h"
|
|
|
|
#include "nsCRT.h"
|
|
#include "nsTArray.h"
|
|
#include "nsUnicodeRange.h"
|
|
|
|
#include "mozilla/Preferences.h"
|
|
|
|
#include "qcms.h"
|
|
|
|
#include <dlfcn.h>
|
|
|
|
using namespace mozilla;
|
|
|
|
// cribbed from CTFontManager.h
|
|
enum {
|
|
kAutoActivationDisabled = 1
|
|
};
|
|
typedef uint32_t AutoActivationSetting;
|
|
|
|
// bug 567552 - disable auto-activation of fonts
|
|
|
|
static void
|
|
DisableFontActivation()
|
|
{
|
|
// get the main bundle identifier
|
|
CFBundleRef mainBundle = ::CFBundleGetMainBundle();
|
|
CFStringRef mainBundleID = NULL;
|
|
|
|
if (mainBundle) {
|
|
mainBundleID = ::CFBundleGetIdentifier(mainBundle);
|
|
}
|
|
|
|
// if possible, fetch CTFontManagerSetAutoActivationSetting
|
|
void (*CTFontManagerSetAutoActivationSettingPtr)
|
|
(CFStringRef, AutoActivationSetting);
|
|
CTFontManagerSetAutoActivationSettingPtr =
|
|
(void (*)(CFStringRef, AutoActivationSetting))
|
|
dlsym(RTLD_DEFAULT, "CTFontManagerSetAutoActivationSetting");
|
|
|
|
// bug 567552 - disable auto-activation of fonts
|
|
if (CTFontManagerSetAutoActivationSettingPtr) {
|
|
CTFontManagerSetAutoActivationSettingPtr(mainBundleID,
|
|
kAutoActivationDisabled);
|
|
}
|
|
|
|
if (mainBundleID) {
|
|
::CFRelease(mainBundleID);
|
|
}
|
|
if (mainBundle) {
|
|
::CFRelease(mainBundle);
|
|
}
|
|
}
|
|
|
|
gfxPlatformMac::gfxPlatformMac()
|
|
{
|
|
mOSXVersion = 0;
|
|
OSXVersion();
|
|
if (mOSXVersion >= MAC_OS_X_VERSION_10_6_HEX) {
|
|
DisableFontActivation();
|
|
}
|
|
mFontAntiAliasingThreshold = ReadAntiAliasingThreshold();
|
|
}
|
|
|
|
gfxPlatformMac::~gfxPlatformMac()
|
|
{
|
|
gfxCoreTextShaper::Shutdown();
|
|
}
|
|
|
|
gfxPlatformFontList*
|
|
gfxPlatformMac::CreatePlatformFontList()
|
|
{
|
|
gfxPlatformFontList* list = new gfxMacPlatformFontList();
|
|
if (NS_SUCCEEDED(list->InitFontList())) {
|
|
return list;
|
|
}
|
|
gfxPlatformFontList::Shutdown();
|
|
return nsnull;
|
|
}
|
|
|
|
already_AddRefed<gfxASurface>
|
|
gfxPlatformMac::CreateOffscreenSurface(const gfxIntSize& size,
|
|
gfxASurface::gfxContentType contentType)
|
|
{
|
|
gfxASurface *newSurface = nsnull;
|
|
|
|
newSurface = new gfxQuartzSurface(size, gfxASurface::FormatFromContent(contentType));
|
|
|
|
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 (!gfxPlatformFontList::PlatformFontList()->
|
|
ResolveFontName(aFontName, resolvedName)) {
|
|
aAborted = PR_FALSE;
|
|
return NS_OK;
|
|
}
|
|
aAborted = !(*aCallback)(resolvedName, aClosure);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
gfxPlatformMac::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
|
|
{
|
|
gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
|
|
return NS_OK;
|
|
}
|
|
|
|
gfxFontGroup *
|
|
gfxPlatformMac::CreateFontGroup(const nsAString &aFamilies,
|
|
const gfxFontStyle *aStyle,
|
|
gfxUserFontSet *aUserFontSet)
|
|
{
|
|
return new gfxFontGroup(aFamilies, aStyle, aUserFontSet);
|
|
}
|
|
|
|
// these will move to gfxPlatform once all platforms support the fontlist
|
|
gfxFontEntry*
|
|
gfxPlatformMac::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
|
|
const nsAString& aFontName)
|
|
{
|
|
return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry,
|
|
aFontName);
|
|
}
|
|
|
|
gfxFontEntry*
|
|
gfxPlatformMac::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
|
|
const PRUint8 *aFontData, PRUint32 aLength)
|
|
{
|
|
// Ownership of aFontData is received here, and passed on to
|
|
// gfxPlatformFontList::MakePlatformFont(), which must ensure the data
|
|
// is released with NS_Free when no longer needed
|
|
return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry,
|
|
aFontData,
|
|
aLength);
|
|
}
|
|
|
|
PRBool
|
|
gfxPlatformMac::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
|
|
{
|
|
// check for strange format flags
|
|
NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
|
|
"strange font format hint set");
|
|
|
|
// accept supported formats
|
|
if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF |
|
|
gfxUserFontSet::FLAG_FORMAT_OPENTYPE |
|
|
gfxUserFontSet::FLAG_FORMAT_TRUETYPE |
|
|
gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT)) {
|
|
return PR_TRUE;
|
|
}
|
|
|
|
// reject all other formats, known and unknown
|
|
if (aFormatFlags != 0) {
|
|
return PR_FALSE;
|
|
}
|
|
|
|
// no format hint set, need to look at data
|
|
return PR_TRUE;
|
|
}
|
|
|
|
// these will also move to gfxPlatform once all platforms support the fontlist
|
|
nsresult
|
|
gfxPlatformMac::GetFontList(nsIAtom *aLangGroup,
|
|
const nsACString& aGenericFamily,
|
|
nsTArray<nsString>& aListOfFonts)
|
|
{
|
|
gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, aGenericFamily, aListOfFonts);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
gfxPlatformMac::UpdateFontList()
|
|
{
|
|
gfxPlatformFontList::PlatformFontList()->UpdateFontList();
|
|
return NS_OK;
|
|
}
|
|
|
|
PRInt32
|
|
gfxPlatformMac::OSXVersion()
|
|
{
|
|
if (!mOSXVersion) {
|
|
// minor version is not accurate, use gestaltSystemVersionMajor, gestaltSystemVersionMinor, gestaltSystemVersionBugFix for these
|
|
OSErr err = ::Gestalt(gestaltSystemVersion, reinterpret_cast<SInt32*>(&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;
|
|
}
|
|
|
|
PRUint32
|
|
gfxPlatformMac::ReadAntiAliasingThreshold()
|
|
{
|
|
PRUint32 threshold = 0; // default == no threshold
|
|
|
|
// first read prefs flag to determine whether to use the setting or not
|
|
PRBool useAntiAliasingThreshold = Preferences::GetBool("gfx.use_text_smoothing_setting", PR_FALSE);
|
|
|
|
// 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;
|
|
}
|
|
|
|
qcms_profile *
|
|
gfxPlatformMac::GetPlatformCMSOutputProfile()
|
|
{
|
|
qcms_profile *profile = nsnull;
|
|
CMProfileRef cmProfile;
|
|
CMProfileLocation *location;
|
|
UInt32 locationSize;
|
|
|
|
/* There a number of different ways that we could try to get a color
|
|
profile to use. On 10.5 all of these methods seem to give the same
|
|
results. On 10.6, the results are different and the following method,
|
|
using CGMainDisplayID() seems to best match what we are looking for.
|
|
Currently, both Google Chrome and Qt4 use a similar method.
|
|
|
|
CMTypes.h describes CMDisplayIDType:
|
|
"Data type for ColorSync DisplayID reference
|
|
On 8 & 9 this is a AVIDType
|
|
On X this is a CGSDisplayID"
|
|
|
|
CGMainDisplayID gives us a CGDirectDisplayID which presumeably
|
|
corresponds directly to a CGSDisplayID */
|
|
CGDirectDisplayID displayID = CGMainDisplayID();
|
|
|
|
CMError err = CMGetProfileByAVID(static_cast<CMDisplayIDType>(displayID), &cmProfile);
|
|
if (err != noErr)
|
|
return nsnull;
|
|
|
|
// get the size of location
|
|
err = NCMGetProfileLocation(cmProfile, NULL, &locationSize);
|
|
if (err != noErr)
|
|
return nsnull;
|
|
|
|
// allocate enough room for location
|
|
location = static_cast<CMProfileLocation*>(malloc(locationSize));
|
|
if (!location)
|
|
goto fail_close;
|
|
|
|
err = NCMGetProfileLocation(cmProfile, location, &locationSize);
|
|
if (err != noErr)
|
|
goto fail_location;
|
|
|
|
switch (location->locType) {
|
|
#ifndef __LP64__
|
|
case cmFileBasedProfile: {
|
|
FSRef fsRef;
|
|
if (!FSpMakeFSRef(&location->u.fileLoc.spec, &fsRef)) {
|
|
char path[512];
|
|
if (!FSRefMakePath(&fsRef, reinterpret_cast<UInt8*>(path), sizeof(path))) {
|
|
profile = qcms_profile_from_path(path);
|
|
#ifdef DEBUG_tor
|
|
if (profile)
|
|
fprintf(stderr,
|
|
"ICM profile read from %s fileLoc successfully\n", path);
|
|
#endif
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
case cmPathBasedProfile:
|
|
profile = qcms_profile_from_path(location->u.pathLoc.path);
|
|
#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;
|
|
}
|
|
|
|
fail_location:
|
|
free(location);
|
|
fail_close:
|
|
CMCloseProfile(cmProfile);
|
|
return profile;
|
|
}
|