bug 502906 - part 2 - split out gfxCoreTextShaper and gfxMacFont. r=jdaggett

--HG--
rename : gfx/thebes/src/gfxCoreTextFonts.cpp => gfx/thebes/src/gfxCoreTextShaper.cpp
rename : gfx/thebes/public/gfxCoreTextFonts.h => gfx/thebes/src/gfxCoreTextShaper.h
This commit is contained in:
Jonathan Kew 2010-03-10 12:46:41 +00:00
Родитель 5058eb564c
Коммит d56e0f4d7b
13 изменённых файлов: 570 добавлений и 501 удалений

Просмотреть файл

@ -112,7 +112,6 @@ EXPORTS += gfxPlatformMac.h \
gfxQuartzImageSurface.h \
gfxQuartzPDFSurface.h \
gfxQuartzNativeDrawing.h \
gfxCoreTextFonts.h \
$(NULL)
endif

Просмотреть файл

@ -634,6 +634,42 @@ private:
PRUint32 mAppUnitsPerDevUnit;
};
/**
* gfxFontShaper
*
* This class implements text shaping (character to glyph mapping and
* glyph layout). There is a gfxFontShaper subclass for each text layout
* technology (uniscribe, core text, harfbuzz,....) we support.
*
* The shaper is responsible for setting up glyph data in gfxTextRuns.
*
* A generic, platform-independent shaper relies only on the standard
* gfxFont interface and can work with any concrete subclass of gfxFont.
*
* Platform-specific implementations designed to interface to platform
* shaping APIs such as Uniscribe or CoreText may rely on features of a
* specific font subclass to access native font references
* (such as CTFont, HFONT, DWriteFont, etc).
*/
class gfxFontShaper {
public:
gfxFontShaper(gfxFont *aFont)
: mFont(aFont) { }
virtual ~gfxFontShaper() { }
virtual void InitTextRun(gfxContext *aContext,
gfxTextRun *aTextRun,
const PRUnichar *aString,
PRUint32 aRunStart,
PRUint32 aRunLength) = 0;
protected:
// the font this shaper is working with
gfxFont * mFont;
};
/* a SPECIFIC single font family */
class THEBES_API gfxFont {
public:
@ -680,7 +716,7 @@ protected:
public:
virtual ~gfxFont();
PRBool Valid() {
PRBool Valid() const {
return mIsValid;
}
@ -714,7 +750,7 @@ public:
const nsString& GetName() const { return mFontEntry->Name(); }
const gfxFontStyle *GetStyle() const { return &mStyle; }
virtual nsString GetUniqueName() = 0;
virtual nsString GetUniqueName() { return GetName(); }
// Font metrics
struct Metrics {
@ -873,11 +909,16 @@ public:
return mFontEntry->HasCharacter(ch);
}
virtual void InitTextRun(gfxTextRun *aTextRun,
const PRUnichar *aString,
PRUint32 aRunStart,
PRUint32 aRunLength) {
NS_NOTREACHED("oops, somebody didn't override InitTextRun");
void InitTextRun(gfxContext *aContext,
gfxTextRun *aTextRun,
const PRUnichar *aString,
PRUint32 aRunStart,
PRUint32 aRunLength) {
NS_ASSERTION(mShaper != nsnull, "no shaper?!");
if (!mShaper) {
return;
}
mShaper->InitTextRun(aContext, aTextRun, aString, aRunStart, aRunLength);
}
protected:
@ -891,6 +932,8 @@ protected:
// synthetic bolding for environments where this is not supported by the platform
PRUint32 mSyntheticBoldOffset; // number of devunit pixels to offset double-strike, 0 ==> no bolding
nsAutoPtr<gfxFontShaper> mShaper;
// some fonts have bad metrics, this method sanitize them.
// if this font has bad underline offset, aIsBadUnderlineFont should be true.
void SanitizeMetrics(gfxFont::Metrics *aMetrics, PRBool aIsBadUnderlineFont);
@ -1866,7 +1909,8 @@ protected:
// you should call this with the *first* bad font.
void InitMetricsForBadFont(gfxFont* aBadFont);
void InitTextRun(gfxTextRun *aTextRun,
void InitTextRun(gfxContext *aContext,
gfxTextRun *aTextRun,
const PRUnichar *aString,
PRUint32 aLength);

Просмотреть файл

@ -98,9 +98,6 @@ public:
// lower threshold on font anti-aliasing
PRUint32 GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; }
// record Unicode cluster boundaries in the text run
virtual void SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString);
private:
virtual qcms_profile* GetPlatformCMSOutputProfile();

Просмотреть файл

@ -170,7 +170,8 @@ CPPSRCS += \
gfxQuartzImageSurface.cpp \
gfxQuartzPDFSurface.cpp \
gfxPlatformMac.cpp \
gfxCoreTextFonts.cpp \
gfxMacFont.cpp \
gfxCoreTextShaper.cpp \
$(NULL)
#CPPSRCS += gfxPDFSurface.cpp
CPPSRCS += nsUnicodeRange.cpp

Просмотреть файл

@ -50,13 +50,12 @@
#include "gfxContext.h"
#include "gfxPlatform.h"
#include "gfxPlatformMac.h"
#include "gfxCoreTextFonts.h"
#include "gfxCoreTextShaper.h"
#include "gfxMacFont.h"
#include "gfxFontTest.h"
#include "gfxFontUtils.h"
#include "cairo-quartz.h"
#include "gfxQuartzSurface.h"
#include "gfxMacPlatformFontList.h"
#include "gfxUserFontSet.h"
@ -70,360 +69,45 @@
static PRLogModuleInfo *gCoreTextTextRunLog = PR_NewLogModule("coreTextTextRun");
#endif
#define ROUND(x) (floor((x) + 0.5))
// standard font descriptors that we construct the first time they're needed
CTFontDescriptorRef gfxCoreTextFont::sDefaultFeaturesDescriptor = NULL;
CTFontDescriptorRef gfxCoreTextFont::sDisableLigaturesDescriptor = NULL;
CTFontDescriptorRef gfxCoreTextShaper::sDefaultFeaturesDescriptor = NULL;
CTFontDescriptorRef gfxCoreTextShaper::sDisableLigaturesDescriptor = NULL;
#ifdef DEBUG_jonathan
static void dumpFontDescCallback(const void *key, const void *value, void *context)
gfxCoreTextShaper::gfxCoreTextShaper(gfxMacFont *aFont)
: gfxFontShaper(aFont)
{
CFStringRef attribute = (CFStringRef)key;
CFTypeRef setting = (CFTypeRef)value;
fprintf(stderr, "attr: "); CFShow(attribute);
fprintf(stderr, " = "); CFShow(setting);
fprintf(stderr, "\n");
}
static void
dumpFontDescriptor(CTFontRef font)
{
CTFontDescriptorRef desc = CTFontCopyFontDescriptor(font);
CFDictionaryRef dict = CTFontDescriptorCopyAttributes(desc);
CFRelease(desc);
CFDictionaryApplyFunction(dict, &dumpFontDescCallback, 0);
CFRelease(dict);
}
#endif
gfxCoreTextFont::gfxCoreTextFont(MacOSFontEntry *aFontEntry,
const gfxFontStyle *aFontStyle,
PRBool aNeedsBold)
: gfxFont(aFontEntry, aFontStyle),
mFontStyle(aFontStyle),
mCTFont(nsnull),
mAttributesDict(nsnull),
mHasMetrics(PR_FALSE),
mFontFace(nsnull),
mScaledFont(nsnull),
mAdjustedSize(0.0f)
{
mATSFont = aFontEntry->GetFontRef();
// determine whether synthetic bolding is needed
PRInt8 baseWeight, weightDistance;
mFontStyle->ComputeWeightAndOffset(&baseWeight, &weightDistance);
PRUint16 targetWeight = (baseWeight * 100) + (weightDistance * 100);
// synthetic bolding occurs when font itself is not a bold-face and either the absolute weight
// is at least 600 or the relative weight (e.g. 402) implies a darker face than the ones available.
// note: this means that (1) lighter styles *never* synthetic bold and (2) synthetic bolding always occurs
// at the first bolder step beyond available faces, no matter how light the boldest face
if (!aFontEntry->IsBold()
&& ((weightDistance == 0 && targetWeight >= 600) || (weightDistance > 0 && aNeedsBold)))
{
mSyntheticBoldOffset = 1; // devunit offset when double-striking text to fake boldness
}
// InitMetrics will create the mCTFont (possibly taking account of sizeAdjust)
InitMetrics();
if (!mIsValid) {
return;
}
// Create our CTFontRef
mCTFont = ::CTFontCreateWithPlatformFont(aFont->GetATSFontRef(),
aFont->GetAdjustedSize(),
NULL,
GetDefaultFeaturesDescriptor());
// Set up the default attribute dictionary that we will need each time we create a CFAttributedString
mAttributesDict =
::CFDictionaryCreate(kCFAllocatorDefault,
(const void**) &kCTFontAttributeName,
(const void**) &mCTFont,
1, // count of attributes
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
// Remaining initialization is largely based on CommonInit() in the gfxAtsuiFont code
CGFontRef cgFont = ::CGFontCreateWithPlatformFont(&mATSFont);
mFontFace = cairo_quartz_font_face_create_for_cgfont(cgFont);
::CGFontRelease(cgFont);
cairo_status_t cairoerr = cairo_font_face_status(mFontFace);
if (cairoerr != CAIRO_STATUS_SUCCESS) {
mIsValid = PR_FALSE;
#ifdef DEBUG
char warnBuf[1024];
sprintf(warnBuf, "Failed to create Cairo font face: %s status: %d",
NS_ConvertUTF16toUTF8(GetName()).get(), cairoerr);
NS_WARNING(warnBuf);
#endif
return;
}
cairo_matrix_t sizeMatrix, ctm;
cairo_matrix_init_identity(&ctm);
cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize);
// synthetic oblique by skewing via the font matrix
PRBool needsOblique =
(mFontEntry != NULL) &&
(!mFontEntry->IsItalic() && (mFontStyle->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)));
if (needsOblique) {
double skewfactor = (needsOblique ? Fix2X(kATSItalicQDSkew) : 0);
cairo_matrix_t style;
cairo_matrix_init(&style,
1, //xx
0, //yx
-1 * skewfactor, //xy
1, //yy
0, //x0
0); //y0
cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
}
cairo_font_options_t *fontOptions = cairo_font_options_create();
// if this fails (out of memory), the pointer is still safe to use
// although we're almost certainly going to fail below anyway
// turn off font anti-aliasing based on user pref setting
if (mAdjustedSize <= (float) gfxPlatformMac::GetPlatform()->GetAntiAliasingThreshold()) {
cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_NONE);
//printf("font: %s, size: %f, disabling anti-aliasing\n", NS_ConvertUTF16toUTF8(GetName()).get(), mAdjustedSize);
}
mScaledFont = cairo_scaled_font_create(mFontFace, &sizeMatrix, &ctm, fontOptions);
cairo_font_options_destroy(fontOptions);
cairoerr = cairo_scaled_font_status(mScaledFont);
if (cairoerr != CAIRO_STATUS_SUCCESS) {
mIsValid = PR_FALSE;
#ifdef DEBUG
char warnBuf[1024];
sprintf(warnBuf, "Failed to create scaled font: %s status: %d",
NS_ConvertUTF16toUTF8(GetName()).get(), cairoerr);
NS_WARNING(warnBuf);
#endif
}
mAttributesDict = ::CFDictionaryCreate(kCFAllocatorDefault,
(const void**) &kCTFontAttributeName,
(const void**) &mCTFont,
1, // count of attributes
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
static double
RoundToNearestMultiple(double aValue, double aFraction)
gfxCoreTextShaper::~gfxCoreTextShaper()
{
return floor(aValue/aFraction + 0.5)*aFraction;
}
PRBool
gfxCoreTextFont::SetupCairoFont(gfxContext *aContext)
{
cairo_scaled_font_t *scaledFont = CairoScaledFont();
if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
// Don't cairo_set_scaled_font as that would propagate the error to
// the cairo_t, precluding any further drawing.
return PR_FALSE;
}
cairo_set_scaled_font(aContext->GetCairo(), scaledFont);
return PR_TRUE;
}
float
gfxCoreTextFont::GetCharWidth(PRUnichar aUniChar, PRUint32 *aGlyphID)
{
UniChar c = aUniChar;
CGGlyph glyph;
if (::CTFontGetGlyphsForCharacters(mCTFont, &c, &glyph, 1)) {
CGSize advance;
::CTFontGetAdvancesForGlyphs(mCTFont,
kCTFontHorizontalOrientation,
&glyph,
&advance,
1);
if (aGlyphID != nsnull)
*aGlyphID = glyph;
return advance.width;
}
// couldn't get glyph for the char
if (aGlyphID != nsnull)
*aGlyphID = 0;
return 0;
}
float
gfxCoreTextFont::GetCharHeight(PRUnichar aUniChar)
{
UniChar c = aUniChar;
CGGlyph glyph;
if (::CTFontGetGlyphsForCharacters(mCTFont, &c, &glyph, 1)) {
CGRect boundingRect;
::CTFontGetBoundingRectsForGlyphs(mCTFont,
kCTFontHorizontalOrientation,
&glyph,
&boundingRect,
1);
return boundingRect.size.height;
}
// couldn't get glyph for the char
return 0;
}
gfxCoreTextFont::~gfxCoreTextFont()
{
if (mScaledFont)
cairo_scaled_font_destroy(mScaledFont);
if (mFontFace)
cairo_font_face_destroy(mFontFace);
if (mAttributesDict)
if (mAttributesDict) {
::CFRelease(mAttributesDict);
if (mCTFont)
}
if (mCTFont) {
::CFRelease(mCTFont);
}
MacOSFontEntry*
gfxCoreTextFont::GetFontEntry()
{
return static_cast<MacOSFontEntry*>(mFontEntry.get());
}
PRBool
gfxCoreTextFont::TestCharacterMap(PRUint32 aCh)
{
return mIsValid && GetFontEntry()->TestCharacterMap(aCh);
}
}
void
gfxCoreTextFont::InitMetrics()
{
if (mHasMetrics)
return;
gfxFloat size =
PR_MAX(((mAdjustedSize != 0.0f) ? mAdjustedSize : GetStyle()->size), 1.0f);
if (mCTFont != NULL) {
::CFRelease(mCTFont);
mCTFont = NULL;
}
ATSFontMetrics atsMetrics;
OSStatus err;
err = ::ATSFontGetHorizontalMetrics(mATSFont, kATSOptionFlagsDefault,
&atsMetrics);
if (err != noErr) {
mIsValid = PR_FALSE;
#ifdef DEBUG
char warnBuf[1024];
sprintf(warnBuf, "Bad font metrics for: %s err: %8.8x",
NS_ConvertUTF16toUTF8(GetName()).get(), PRUint32(err));
NS_WARNING(warnBuf);
#endif
return;
}
// prefer to get xHeight from ATS metrics (unhinted) rather than Core Text (hinted),
// see bug 429605.
if (atsMetrics.xHeight > 0) {
mMetrics.xHeight = atsMetrics.xHeight * size;
} else {
mCTFont = ::CTFontCreateWithPlatformFont(mATSFont, size, NULL, GetDefaultFeaturesDescriptor());
mMetrics.xHeight = ::CTFontGetXHeight(mCTFont);
}
if (mAdjustedSize == 0.0f) {
if (mMetrics.xHeight != 0.0f && GetStyle()->sizeAdjust != 0.0f) {
gfxFloat aspect = mMetrics.xHeight / size;
mAdjustedSize = GetStyle()->GetAdjustedSize(aspect);
// the recursive call to InitMetrics will re-create mCTFont, with adjusted size,
// and then continue to set up the rest of the metrics fields
InitMetrics();
return;
}
mAdjustedSize = size;
}
// create the CTFontRef if we didn't already do so above
if (mCTFont == NULL)
mCTFont = ::CTFontCreateWithPlatformFont(mATSFont, size, NULL, GetDefaultFeaturesDescriptor());
mMetrics.superscriptOffset = mMetrics.xHeight;
mMetrics.subscriptOffset = mMetrics.xHeight;
mMetrics.underlineSize = ::CTFontGetUnderlineThickness(mCTFont);
mMetrics.underlineOffset = ::CTFontGetUnderlinePosition(mCTFont);
mMetrics.strikeoutSize = mMetrics.underlineSize;
mMetrics.strikeoutOffset = mMetrics.xHeight / 2;
mMetrics.externalLeading = ::CTFontGetLeading(mCTFont);
mMetrics.emHeight = size;
// mMetrics.maxAscent = CTFontGetAscent(mCTFont);
// mMetrics.maxDescent = CTFontGetDescent(mCTFont);
// using the ATS metrics rather than CT gives us results more consistent with the ATSUI path
mMetrics.maxAscent =
NS_ceil(RoundToNearestMultiple(atsMetrics.ascent * size, 1/1024.0));
mMetrics.maxDescent =
NS_ceil(-RoundToNearestMultiple(atsMetrics.descent * size, 1/1024.0));
mMetrics.maxHeight = mMetrics.maxAscent + mMetrics.maxDescent;
if (mMetrics.maxHeight - mMetrics.emHeight > 0.0)
mMetrics.internalLeading = mMetrics.maxHeight - mMetrics.emHeight;
else
mMetrics.internalLeading = 0.0;
mMetrics.maxAdvance = atsMetrics.maxAdvanceWidth * size + mSyntheticBoldOffset;
mMetrics.emAscent = mMetrics.maxAscent * mMetrics.emHeight / mMetrics.maxHeight;
mMetrics.emDescent = mMetrics.emHeight - mMetrics.emAscent;
PRUint32 glyphID;
float xWidth = GetCharWidth('x', &glyphID);
if (atsMetrics.avgAdvanceWidth != 0.0)
mMetrics.aveCharWidth = PR_MIN(atsMetrics.avgAdvanceWidth * size, xWidth);
else if (glyphID != 0)
mMetrics.aveCharWidth = xWidth;
else
mMetrics.aveCharWidth = mMetrics.maxAdvance;
mMetrics.aveCharWidth += mSyntheticBoldOffset;
if (GetFontEntry()->IsFixedPitch()) {
// Some Quartz fonts are fixed pitch, but there's some glyph with a bigger
// advance than the average character width... this forces
// those fonts to be recognized like fixed pitch fonts by layout.
mMetrics.maxAdvance = mMetrics.aveCharWidth;
}
mMetrics.spaceWidth = GetCharWidth(' ', &glyphID);
mSpaceGlyph = glyphID;
mMetrics.zeroOrAveCharWidth = GetCharWidth('0', &glyphID);
if (glyphID == 0)
mMetrics.zeroOrAveCharWidth = mMetrics.aveCharWidth;
mHasMetrics = PR_TRUE;
SanitizeMetrics(&mMetrics, GetFontEntry()->mIsBadUnderlineFont);
#if 0
fprintf (stderr, "Font: %p (%s) size: %f\n", this,
NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size);
// fprintf (stderr, " fbounds.origin.x %f y %f size.width %f height %f\n", fbounds.origin.x, fbounds.origin.y, fbounds.size.width, fbounds.size.height);
fprintf (stderr, " emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
fprintf (stderr, " maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance);
fprintf (stderr, " internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading);
fprintf (stderr, " spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight);
fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f suOff: %f suSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize,
mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset);
#endif
}
void
gfxCoreTextFont::InitTextRun(gfxTextRun *aTextRun,
const PRUnichar *aString,
PRUint32 aRunStart,
PRUint32 aRunLength)
gfxCoreTextShaper::InitTextRun(gfxContext *aContext,
gfxTextRun *aTextRun,
const PRUnichar *aString,
PRUint32 aRunStart,
PRUint32 aRunLength)
{
// aRunStart and aRunLength define the section of the textRun and of aString
// that is to be drawn with this particular font
@ -483,9 +167,10 @@ gfxCoreTextFont::InitTextRun(gfxTextRun *aTextRun,
if (disableLigatures) {
// For letterspacing (or maybe other situations) we need to make a copy of the CTFont
// with the ligature feature disabled
gfxMacFont *font = static_cast<gfxMacFont*>(mFont);
CTFontRef ctFont =
gfxCoreTextFont::CreateCTFontWithDisabledLigatures(GetATSFont(),
::CTFontGetSize(GetCTFont()));
CreateCTFontWithDisabledLigatures(font->GetATSFontRef(),
::CTFontGetSize(mCTFont));
attrObj =
::CFDictionaryCreate(kCFAllocatorDefault,
@ -497,7 +182,7 @@ gfxCoreTextFont::InitTextRun(gfxTextRun *aTextRun,
// Having created the dict, we're finished with our ligature-disabled CTFontRef
::CFRelease(ctFont);
} else {
attrObj = GetAttributesDictionary();
attrObj = mAttributesDict;
::CFRetain(attrObj);
}
@ -532,11 +217,11 @@ gfxCoreTextFont::InitTextRun(gfxTextRun *aTextRun,
// without requiring a separate allocation
nsresult
gfxCoreTextFont::SetGlyphsFromRun(gfxTextRun *aTextRun,
CTRunRef aCTRun,
PRInt32 aStringOffset, // offset in the string used to build the CTLine
PRInt32 aRunStart, // starting offset of this font run in the gfxTextRun
PRInt32 aRunLength) // length of this font run in characters
gfxCoreTextShaper::SetGlyphsFromRun(gfxTextRun *aTextRun,
CTRunRef aCTRun,
PRInt32 aStringOffset, // offset in the string used to build the CTLine
PRInt32 aRunStart, // starting offset of this font run in the gfxTextRun
PRInt32 aRunLength) // length of this font run in characters
{
// The textRun has been bidi-wrapped; aStringOffset is the number
// of chars at the beginning of the CTLine that we should skip.
@ -548,8 +233,9 @@ gfxCoreTextFont::SetGlyphsFromRun(gfxTextRun *aTextRun,
PRInt32 direction = isLTR ? 1 : -1;
PRInt32 numGlyphs = ::CTRunGetGlyphCount(aCTRun);
if (numGlyphs == 0)
if (numGlyphs == 0) {
return NS_OK;
}
// character offsets get really confusing here, as we have to keep track of
// (a) the text in the actual textRun we're constructing
@ -565,8 +251,9 @@ gfxCoreTextFont::SetGlyphsFromRun(gfxTextRun *aTextRun,
CFRange stringRange = ::CTRunGetStringRange(aCTRun);
// skip the run if it is entirely outside the actual range of the font run
if (stringRange.location - aStringOffset + stringRange.length <= 0 ||
stringRange.location - aStringOffset >= aRunLength)
stringRange.location - aStringOffset >= aRunLength) {
return NS_OK;
}
// retrieve the laid-out glyph data from the CTRun
nsAutoArrayPtr<CGGlyph> glyphsArray;
@ -587,8 +274,9 @@ gfxCoreTextFont::SetGlyphsFromRun(gfxTextRun *aTextRun,
glyphs = ::CTRunGetGlyphsPtr(aCTRun);
if (!glyphs) {
glyphsArray = new (std::nothrow) CGGlyph[numGlyphs];
if (!glyphsArray)
if (!glyphsArray) {
return NS_ERROR_OUT_OF_MEMORY;
}
::CTRunGetGlyphs(aCTRun, ::CFRangeMake(0, 0), glyphsArray.get());
glyphs = glyphsArray.get();
}
@ -596,8 +284,9 @@ gfxCoreTextFont::SetGlyphsFromRun(gfxTextRun *aTextRun,
positions = ::CTRunGetPositionsPtr(aCTRun);
if (!positions) {
positionsArray = new (std::nothrow) CGPoint[numGlyphs];
if (!positionsArray)
if (!positionsArray) {
return NS_ERROR_OUT_OF_MEMORY;
}
::CTRunGetPositions(aCTRun, ::CFRangeMake(0, 0), positionsArray.get());
positions = positionsArray.get();
}
@ -607,8 +296,9 @@ gfxCoreTextFont::SetGlyphsFromRun(gfxTextRun *aTextRun,
glyphToChar = ::CTRunGetStringIndicesPtr(aCTRun);
if (!glyphToChar) {
glyphToCharArray = new (std::nothrow) CFIndex[numGlyphs];
if (!glyphToCharArray)
if (!glyphToCharArray) {
return NS_ERROR_OUT_OF_MEMORY;
}
::CTRunGetStringIndices(aCTRun, ::CFRangeMake(0, 0), glyphToCharArray.get());
glyphToChar = glyphToCharArray.get();
}
@ -631,11 +321,13 @@ gfxCoreTextFont::SetGlyphsFromRun(gfxTextRun *aTextRun,
static const PRInt32 NO_GLYPH = -1;
nsAutoTArray<PRInt32,SMALL_GLYPH_RUN> charToGlyphArray;
if (!charToGlyphArray.SetLength(stringRange.length))
if (!charToGlyphArray.SetLength(stringRange.length)) {
return NS_ERROR_OUT_OF_MEMORY;
}
PRInt32 *charToGlyph = charToGlyphArray.Elements();
for (PRInt32 offset = 0; offset < stringRange.length; ++offset)
for (PRInt32 offset = 0; offset < stringRange.length; ++offset) {
charToGlyph[offset] = NO_GLYPH;
}
for (PRInt32 i = 0; i < numGlyphs; ++i) {
PRInt32 loc = glyphToChar[i] - stringRange.location;
if (loc >= 0 && loc < stringRange.length) {
@ -742,13 +434,15 @@ gfxCoreTextFont::SetGlyphsFromRun(gfxTextRun *aTextRun,
// adjusting for the offset of the stringRange relative to the textRun.
PRInt32 baseCharIndex, endCharIndex;
if (isLTR) {
while (charEnd < stringRange.length && charToGlyph[charEnd] == NO_GLYPH)
while (charEnd < stringRange.length && charToGlyph[charEnd] == NO_GLYPH) {
charEnd++;
}
baseCharIndex = charStart + stringRange.location - aStringOffset + aRunStart;
endCharIndex = charEnd + stringRange.location - aStringOffset + aRunStart;
} else {
while (charEnd >= 0 && charToGlyph[charEnd] == NO_GLYPH)
while (charEnd >= 0 && charToGlyph[charEnd] == NO_GLYPH) {
charEnd--;
}
baseCharIndex = charEnd + stringRange.location - aStringOffset + aRunStart + 1;
endCharIndex = charStart + stringRange.location - aStringOffset + aRunStart + 1;
}
@ -766,10 +460,11 @@ gfxCoreTextFont::SetGlyphsFromRun(gfxTextRun *aTextRun,
// Now we're ready to set the glyph info in the textRun; measure the glyph width
// of the first (perhaps only) glyph, to see if it is "Simple"
double toNextGlyph;
if (glyphStart < numGlyphs-1)
if (glyphStart < numGlyphs-1) {
toNextGlyph = positions[glyphStart+1].x - positions[glyphStart].x;
else
} else {
toNextGlyph = positions[0].x + runWidth - positions[glyphStart].x;
}
PRInt32 advance = PRInt32(toNextGlyph * appUnitsPerDevUnit);
// Check if it's a simple one-to-one mapping
@ -792,12 +487,14 @@ gfxCoreTextFont::SetGlyphsFromRun(gfxTextRun *aTextRun,
details->mXOffset = 0;
details->mYOffset = -positions[glyphStart].y * appUnitsPerDevUnit;
details->mAdvance = advance;
if (++glyphStart >= glyphEnd)
if (++glyphStart >= glyphEnd) {
break;
if (glyphStart < numGlyphs-1)
}
if (glyphStart < numGlyphs-1) {
toNextGlyph = positions[glyphStart+1].x - positions[glyphStart].x;
else
} else {
toNextGlyph = positions[0].x + runWidth - positions[glyphStart].x;
}
advance = PRInt32(toNextGlyph * appUnitsPerDevUnit);
}
@ -827,10 +524,11 @@ gfxCoreTextFont::SetGlyphsFromRun(gfxTextRun *aTextRun,
// This will turn off line-edge swashes by default, because we don't know the actual line breaks
// when doing glyph shaping.
void
gfxCoreTextFont::CreateDefaultFeaturesDescriptor()
gfxCoreTextShaper::CreateDefaultFeaturesDescriptor()
{
if (sDefaultFeaturesDescriptor != NULL)
if (sDefaultFeaturesDescriptor != NULL) {
return;
}
SInt16 val = kSmartSwashType;
CFNumberRef swashesType =
@ -899,7 +597,7 @@ gfxCoreTextFont::CreateDefaultFeaturesDescriptor()
// Create a CTFontRef, with the Common Ligatures feature disabled [static]
CTFontRef
gfxCoreTextFont::CreateCTFontWithDisabledLigatures(ATSFontRef aFontRef, CGFloat aSize)
gfxCoreTextShaper::CreateCTFontWithDisabledLigatures(ATSFontRef aFontRef, CGFloat aSize)
{
if (sDisableLigaturesDescriptor == NULL) {
// initialize cached descriptor to turn off the Common Ligatures feature
@ -953,7 +651,7 @@ gfxCoreTextFont::CreateCTFontWithDisabledLigatures(ATSFontRef aFontRef, CGFloat
}
void
gfxCoreTextFont::Shutdown() // [static]
gfxCoreTextShaper::Shutdown() // [static]
{
if (sDisableLigaturesDescriptor != NULL) {
::CFRelease(sDisableLigaturesDescriptor);

Просмотреть файл

@ -38,118 +38,60 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef GFX_CORETEXTFONTS_H
#define GFX_CORETEXTFONTS_H
#ifndef GFX_CORETEXTSHAPER_H
#define GFX_CORETEXTSHAPER_H
#include "cairo.h"
#include "gfxTypes.h"
#include "gfxFont.h"
#include "gfxFontUtils.h"
#include "gfxPlatform.h"
#include "gfxMacPlatformFontList.h"
#include <Carbon/Carbon.h>
class MacOSFontEntry;
class gfxMacFont;
class gfxCoreTextFont : public gfxFont {
class gfxCoreTextShaper : public gfxFontShaper {
public:
gfxCoreTextShaper(gfxMacFont *aFont);
gfxCoreTextFont(MacOSFontEntry *aFontEntry,
const gfxFontStyle *fontStyle, PRBool aNeedsBold);
virtual ~gfxCoreTextShaper();
virtual ~gfxCoreTextFont();
virtual const gfxFont::Metrics& GetMetrics() {
NS_ASSERTION(mHasMetrics == PR_TRUE, "metrics not initialized");
return mMetrics;
}
float GetCharWidth(PRUnichar c, PRUint32 *aGlyphID = nsnull);
float GetCharHeight(PRUnichar c);
ATSFontRef GetATSFont() {
return mATSFont;
}
CTFontRef GetCTFont() {
return mCTFont;
}
CFDictionaryRef GetAttributesDictionary() {
return mAttributesDict;
}
cairo_font_face_t *CairoFontFace() {
return mFontFace;
}
cairo_scaled_font_t *CairoScaledFont() {
return mScaledFont;
}
virtual nsString GetUniqueName() {
return GetName();
}
virtual PRUint32 GetSpaceGlyph() {
return mSpaceGlyph;
}
PRBool TestCharacterMap(PRUint32 aCh);
MacOSFontEntry* GetFontEntry();
virtual void InitTextRun(gfxContext *aContext,
gfxTextRun *aTextRun,
const PRUnichar *aString,
PRUint32 aRunStart,
PRUint32 aRunLength);
// clean up static objects that may have been cached
static void Shutdown();
static CTFontRef CreateCTFontWithDisabledLigatures(ATSFontRef aFontRef, CGFloat aSize);
protected:
const gfxFontStyle *mFontStyle;
ATSFontRef mATSFont;
CTFontRef mCTFont;
CFDictionaryRef mAttributesDict;
PRBool mHasMetrics;
nsString mUniqueName;
cairo_font_face_t *mFontFace;
cairo_scaled_font_t *mScaledFont;
gfxFont::Metrics mMetrics;
gfxFloat mAdjustedSize;
PRUint32 mSpaceGlyph;
void InitMetrics();
virtual void InitTextRun(gfxTextRun *aTextRun,
const PRUnichar *aString,
PRUint32 aRunStart,
PRUint32 aRunLength);
nsresult SetGlyphsFromRun(gfxTextRun *aTextRun,
CTRunRef aCTRun,
PRInt32 aStringOffset,
PRInt32 aLayoutStart,
PRInt32 aLayoutLength);
virtual PRBool SetupCairoFont(gfxContext *aContext);
static void CreateDefaultFeaturesDescriptor();
static CTFontDescriptorRef GetDefaultFeaturesDescriptor() {
if (sDefaultFeaturesDescriptor == NULL)
if (sDefaultFeaturesDescriptor == NULL) {
CreateDefaultFeaturesDescriptor();
}
return sDefaultFeaturesDescriptor;
}
static CTFontRef CreateCTFontWithDisabledLigatures(ATSFontRef aFontRef, CGFloat aSize);
// cached font descriptor, created the first time it's needed
static CTFontDescriptorRef sDefaultFeaturesDescriptor;
// cached descriptor for adding disable-ligatures setting to a font
static CTFontDescriptorRef sDisableLigaturesDescriptor;
};
#endif /* GFX_CORETEXTFONTS_H */
#endif /* GFX_CORETEXTSHAPER_H */

Просмотреть файл

@ -796,7 +796,9 @@ gfxFont::RunMetrics::CombineWith(const RunMetrics& aOther, PRBool aOtherIsOnLeft
}
gfxFont::gfxFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle) :
mFontEntry(aFontEntry), mIsValid(PR_TRUE), mStyle(*aFontStyle), mSyntheticBoldOffset(0)
mFontEntry(aFontEntry), mIsValid(PR_TRUE),
mStyle(*aFontStyle), mSyntheticBoldOffset(0),
mShaper(nsnull)
{
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
++gFontCount;
@ -1792,7 +1794,7 @@ gfxFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
nsAutoString utf16;
AppendASCIItoUTF16(cString, utf16);
InitTextRun(textRun, utf16.get(), utf16.Length());
InitTextRun(aParams->mContext, textRun, utf16.get(), utf16.Length());
textRun->FetchGlyphExtents(aParams->mContext);
@ -1810,7 +1812,7 @@ gfxFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
gfxPlatform::GetPlatform()->SetupClusterBoundaries(textRun, aString);
InitTextRun(textRun, aString, aLength);
InitTextRun(aParams->mContext, textRun, aString, aLength);
textRun->FetchGlyphExtents(aParams->mContext);
@ -1822,7 +1824,8 @@ gfxFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
// without requiring a separate allocation
void
gfxFontGroup::InitTextRun(gfxTextRun *aTextRun,
gfxFontGroup::InitTextRun(gfxContext *aContext,
gfxTextRun *aTextRun,
const PRUnichar *aString,
PRUint32 aLength)
{
@ -1845,8 +1848,9 @@ gfxFontGroup::InitTextRun(gfxTextRun *aTextRun,
// create the glyph run for this range
aTextRun->AddGlyphRun(matchedFont, runStart, (matchedLength > 0));
// do glyph layout and record the resulting positioned glyphs in the run
matchedFont->InitTextRun(aTextRun, aString, runStart, matchedLength);
// do glyph layout and record the resulting positioned glyphs
matchedFont->InitTextRun(aContext, aTextRun, aString,
runStart, matchedLength);
} else {
// no font available, so record missing glyph info instead
if (unmatched == NULL) {

Просмотреть файл

@ -0,0 +1,324 @@
/* -*- 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 Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2006-2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* John Daggett <jdaggett@mozilla.com>
* Jonathan Kew <jfkthame@gmail.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 "gfxMacFont.h"
#include "gfxCoreTextShaper.h"
#include "gfxPlatformMac.h"
#include "gfxContext.h"
#include "cairo-quartz.h"
gfxMacFont::gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
PRBool aNeedsBold)
: gfxFont(aFontEntry, aFontStyle),
mATSFont(aFontEntry->GetFontRef()),
mFontFace(nsnull),
mScaledFont(nsnull),
mAdjustedSize(0.0)
{
// determine whether synthetic bolding is needed
PRInt8 baseWeight, weightDistance;
mStyle.ComputeWeightAndOffset(&baseWeight, &weightDistance);
PRUint16 targetWeight = (baseWeight * 100) + (weightDistance * 100);
// synthetic bolding occurs when font itself is not a bold-face and either the absolute weight
// is at least 600 or the relative weight (e.g. 402) implies a darker face than the ones available.
// note: this means that (1) lighter styles *never* synthetic bold and (2) synthetic bolding always occurs
// at the first bolder step beyond available faces, no matter how light the boldest face
if (!aFontEntry->IsBold()
&& ((weightDistance == 0 && targetWeight >= 600) || (weightDistance > 0 && aNeedsBold)))
{
mSyntheticBoldOffset = 1; // devunit offset when double-striking text to fake boldness
}
// InitMetrics will handle the sizeAdjust factor and set mAdjustedSize
InitMetrics();
if (!mIsValid)
return;
CGFontRef cgFont = ::CGFontCreateWithPlatformFont(&mATSFont);
mFontFace = cairo_quartz_font_face_create_for_cgfont(cgFont);
::CGFontRelease(cgFont);
cairo_status_t cairoerr = cairo_font_face_status(mFontFace);
if (cairoerr != CAIRO_STATUS_SUCCESS) {
mIsValid = PR_FALSE;
#ifdef DEBUG
char warnBuf[1024];
sprintf(warnBuf, "Failed to create Cairo font face: %s status: %d",
NS_ConvertUTF16toUTF8(GetName()).get(), cairoerr);
NS_WARNING(warnBuf);
#endif
return;
}
cairo_matrix_t sizeMatrix, ctm;
cairo_matrix_init_identity(&ctm);
cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize);
// synthetic oblique by skewing via the font matrix
PRBool needsOblique =
(mFontEntry != NULL) &&
(!mFontEntry->IsItalic() && (mStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)));
if (needsOblique) {
double skewfactor = (needsOblique ? Fix2X(kATSItalicQDSkew) : 0);
cairo_matrix_t style;
cairo_matrix_init(&style,
1, //xx
0, //yx
-1 * skewfactor, //xy
1, //yy
0, //x0
0); //y0
cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
}
cairo_font_options_t *fontOptions = cairo_font_options_create();
// turn off font anti-aliasing based on user pref setting
if (mAdjustedSize <= (float) gfxPlatformMac::GetPlatform()->GetAntiAliasingThreshold()) {
cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_NONE);
}
mScaledFont = cairo_scaled_font_create(mFontFace, &sizeMatrix, &ctm, fontOptions);
cairo_font_options_destroy(fontOptions);
cairoerr = cairo_scaled_font_status(mScaledFont);
if (cairoerr != CAIRO_STATUS_SUCCESS) {
mIsValid = PR_FALSE;
#ifdef DEBUG
char warnBuf[1024];
sprintf(warnBuf, "Failed to create scaled font: %s status: %d",
NS_ConvertUTF16toUTF8(GetName()).get(), cairoerr);
NS_WARNING(warnBuf);
#endif
}
mShaper = new gfxCoreTextShaper(this);
}
gfxMacFont::~gfxMacFont()
{
if (mScaledFont) {
cairo_scaled_font_destroy(mScaledFont);
}
if (mFontFace) {
cairo_font_face_destroy(mFontFace);
}
}
PRBool
gfxMacFont::SetupCairoFont(gfxContext *aContext)
{
if (cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) {
// Don't cairo_set_scaled_font as that would propagate the error to
// the cairo_t, precluding any further drawing.
return PR_FALSE;
}
cairo_set_scaled_font(aContext->GetCairo(), mScaledFont);
return PR_TRUE;
}
static double
RoundToNearestMultiple(double aValue, double aFraction)
{
return floor(aValue/aFraction + 0.5) * aFraction;
}
void
gfxMacFont::InitMetrics()
{
gfxFloat size =
PR_MAX(((mAdjustedSize != 0.0f) ? mAdjustedSize : mStyle.size), 1.0f);
ATSFontMetrics atsMetrics;
OSStatus err;
err = ::ATSFontGetHorizontalMetrics(mATSFont, kATSOptionFlagsDefault,
&atsMetrics);
if (err != noErr) {
mIsValid = PR_FALSE;
#ifdef DEBUG
char warnBuf[1024];
sprintf(warnBuf, "Bad font metrics for: %s err: %8.8x",
NS_ConvertUTF16toUTF8(mFontEntry->Name()).get(), PRUint32(err));
NS_WARNING(warnBuf);
#endif
return;
}
// create a temporary local CTFont for glyph measurement
CTFontRef aCTFont =
::CTFontCreateWithPlatformFont(mATSFont, size, NULL, NULL);
// prefer to get xHeight from ATS metrics (unhinted) rather than Core Text (hinted),
// see bug 429605.
if (atsMetrics.xHeight > 0)
mMetrics.xHeight = atsMetrics.xHeight * size;
else
mMetrics.xHeight = GetCharHeight(aCTFont, 'x');
if (mAdjustedSize == 0.0f) {
if (mMetrics.xHeight != 0.0f && mStyle.sizeAdjust != 0.0f) {
gfxFloat aspect = mMetrics.xHeight / size;
mAdjustedSize = mStyle.GetAdjustedSize(aspect);
// the recursive call to InitMetrics will see the adjusted size,
// and set up the rest of the metrics fields accordingly
InitMetrics();
// release our temporary CTFont
::CFRelease(aCTFont);
return;
}
mAdjustedSize = size;
}
mMetrics.superscriptOffset = mMetrics.xHeight;
mMetrics.subscriptOffset = mMetrics.xHeight;
mMetrics.underlineOffset = atsMetrics.underlinePosition * size;
mMetrics.underlineSize = atsMetrics.underlineThickness * size;
mMetrics.strikeoutSize = mMetrics.underlineSize;
mMetrics.strikeoutOffset = mMetrics.xHeight / 2;
mMetrics.externalLeading = atsMetrics.leading * size;
mMetrics.emHeight = size;
mMetrics.maxAscent =
NS_ceil(RoundToNearestMultiple(atsMetrics.ascent * size, 1/1024.0));
mMetrics.maxDescent =
NS_ceil(-RoundToNearestMultiple(atsMetrics.descent * size, 1/1024.0));
mMetrics.maxHeight = mMetrics.maxAscent + mMetrics.maxDescent;
if (mMetrics.maxHeight - mMetrics.emHeight > 0.0)
mMetrics.internalLeading = mMetrics.maxHeight - mMetrics.emHeight;
else
mMetrics.internalLeading = 0.0;
mMetrics.maxAdvance = atsMetrics.maxAdvanceWidth * size + mSyntheticBoldOffset;
mMetrics.emAscent = mMetrics.maxAscent * mMetrics.emHeight / mMetrics.maxHeight;
mMetrics.emDescent = mMetrics.emHeight - mMetrics.emAscent;
PRUint32 glyphID;
float xWidth = GetCharWidth(aCTFont, 'x', &glyphID);
if (atsMetrics.avgAdvanceWidth != 0.0)
mMetrics.aveCharWidth = PR_MIN(atsMetrics.avgAdvanceWidth * size, xWidth);
else if (glyphID != 0)
mMetrics.aveCharWidth = xWidth;
else
mMetrics.aveCharWidth = mMetrics.maxAdvance;
mMetrics.aveCharWidth += mSyntheticBoldOffset;
if (mFontEntry->IsFixedPitch()) {
// Some Quartz fonts are fixed pitch, but there's some glyph with a bigger
// advance than the average character width... this forces
// those fonts to be recognized like fixed pitch fonts by layout.
mMetrics.maxAdvance = mMetrics.aveCharWidth;
}
mMetrics.spaceWidth = GetCharWidth(aCTFont, ' ', &glyphID);
mSpaceGlyph = glyphID;
mMetrics.zeroOrAveCharWidth = GetCharWidth(aCTFont, '0', &glyphID);
if (glyphID == 0)
mMetrics.zeroOrAveCharWidth = mMetrics.aveCharWidth;
::CFRelease(aCTFont);
SanitizeMetrics(&mMetrics, mFontEntry->mIsBadUnderlineFont);
mIsValid = PR_TRUE;
#if 0
fprintf (stderr, "Font: %p (%s) size: %f\n", this,
NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size);
// fprintf (stderr, " fbounds.origin.x %f y %f size.width %f height %f\n", fbounds.origin.x, fbounds.origin.y, fbounds.size.width, fbounds.size.height);
fprintf (stderr, " emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
fprintf (stderr, " maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance);
fprintf (stderr, " internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading);
fprintf (stderr, " spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight);
fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f suOff: %f suSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset);
#endif
}
float
gfxMacFont::GetCharWidth(CTFontRef aCTFont, PRUnichar aUniChar,
PRUint32 *aGlyphID)
{
UniChar c = aUniChar;
CGGlyph glyph;
if (::CTFontGetGlyphsForCharacters(aCTFont, &c, &glyph, 1)) {
CGSize advance;
::CTFontGetAdvancesForGlyphs(aCTFont,
kCTFontHorizontalOrientation,
&glyph,
&advance,
1);
if (aGlyphID != nsnull)
*aGlyphID = glyph;
return advance.width;
}
// couldn't get glyph for the char
if (aGlyphID != nsnull)
*aGlyphID = 0;
return 0;
}
float
gfxMacFont::GetCharHeight(CTFontRef aCTFont, PRUnichar aUniChar)
{
UniChar c = aUniChar;
CGGlyph glyph;
if (::CTFontGetGlyphsForCharacters(aCTFont, &c, &glyph, 1)) {
CGRect boundingRect;
::CTFontGetBoundingRectsForGlyphs(aCTFont,
kCTFontHorizontalOrientation,
&glyph,
&boundingRect,
1);
return boundingRect.size.height;
}
return 0;
}

Просмотреть файл

@ -0,0 +1,91 @@
/* -*- 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 Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2006-2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* John Daggett <jdaggett@mozilla.com>
* Jonathan Kew <jfkthame@gmail.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 ***** */
#ifndef GFX_MACFONT_H
#define GFX_MACFONT_H
#include "gfxFont.h"
#include "gfxMacPlatformFontList.h"
#include "cairo.h"
class gfxMacFont : public gfxFont
{
public:
gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
PRBool aNeedsBold);
virtual ~gfxMacFont();
ATSFontRef GetATSFontRef() const { return mATSFont; }
// TODO: probably should move this up to gfxFont
// and ensure it is handled uniformly across all platforms
float GetAdjustedSize() const { return mAdjustedSize; }
/* overrides for the pure virtual methods in gfxFont */
virtual const gfxFont::Metrics& GetMetrics() {
return mMetrics;
}
virtual PRUint32 GetSpaceGlyph() {
return mSpaceGlyph;
}
virtual PRBool SetupCairoFont(gfxContext *aContext);
protected:
void InitMetrics();
float GetCharWidth(CTFontRef aCTFont, PRUnichar aUniChar,
PRUint32 *aGlyphID);
float GetCharHeight(CTFontRef aCTFont, PRUnichar aUniChar);
ATSFontRef mATSFont;
cairo_font_face_t *mFontFace;
cairo_scaled_font_t *mScaledFont;
Metrics mMetrics;
PRUint32 mSpaceGlyph;
float mAdjustedSize;
};
#endif /* GFX_MACFONT_H */

Просмотреть файл

@ -45,7 +45,6 @@
#include "nsRefPtrHashtable.h"
#include "gfxPlatformFontList.h"
#include "gfxCoreTextFonts.h"
#include "gfxPlatform.h"
#include <Carbon/Carbon.h>

Просмотреть файл

@ -44,6 +44,7 @@
#include "gfxPlatformMac.h"
#include "gfxMacPlatformFontList.h"
#include "gfxMacFont.h"
#include "gfxUserFontSet.h"
#include "nsServiceManagerUtils.h"
@ -311,7 +312,7 @@ MacOSFontEntry::GetFontTable(PRUint32 aTableTag, nsTArray<PRUint8>& aBuffer)
gfxFont*
MacOSFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, PRBool aNeedsBold)
{
return new gfxCoreTextFont(this, aFontStyle, aNeedsBold);
return new gfxMacFont(this, aFontStyle, aNeedsBold);
}

Просмотреть файл

@ -1003,7 +1003,7 @@ static nsIUGenCategory*
GetGenCategory()
{
if (!gGenCategory) {
nsresult rv = CallGetService(NS_UNICHARUTIL_CONTRACTID, &gGenCategory);
nsresult rv = CallGetService(NS_UNICHARCATEGORY_CONTRACTID, &gGenCategory);
if (NS_FAILED(rv)) {
NS_ERROR("Failed to get the Unicode character category service!");
gGenCategory = nsnull;

Просмотреть файл

@ -43,8 +43,9 @@
#include "gfxQuartzImageSurface.h"
#include "gfxMacPlatformFontList.h"
#include "gfxMacFont.h"
#include "gfxCoreTextShaper.h"
#include "gfxUserFontSet.h"
#include "gfxCoreTextFonts.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
@ -64,7 +65,7 @@ gfxPlatformMac::gfxPlatformMac()
gfxPlatformMac::~gfxPlatformMac()
{
gfxCoreTextFont::Shutdown();
gfxCoreTextShaper::Shutdown();
}
gfxPlatformFontList*
@ -327,35 +328,3 @@ fail_close:
CMCloseProfile(cmProfile);
return profile;
}
void
gfxPlatformMac::SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString)
{
TextBreakLocatorRef locator;
OSStatus status = UCCreateTextBreakLocator(NULL, 0, kUCTextBreakClusterMask,
&locator);
if (status != noErr)
return;
UniCharArrayOffset breakOffset = 0;
UCTextBreakOptions options = kUCTextBreakLeadingEdgeMask;
PRUint32 length = aTextRun->GetLength();
while (breakOffset < length) {
UniCharArrayOffset next;
status = UCFindTextBreak(locator, kUCTextBreakClusterMask, options,
aString, length, breakOffset, &next);
if (status != noErr)
break;
options |= kUCTextBreakIterateMask;
PRUint32 i;
for (i = breakOffset + 1; i < next; ++i) {
gfxTextRun::CompressedGlyph g;
// Remember that this character is not the start of a cluster by
// setting its glyph data to "not a cluster start", "is a
// ligature start", with no glyphs.
aTextRun->SetGlyphs(i, g.SetComplex(PR_FALSE, PR_TRUE, 0), nsnull);
}
breakOffset = next;
}
UCDisposeTextBreakLocator(&locator);
}