зеркало из https://github.com/mozilla/gecko-dev.git
b=341694, bring Mac Cocoa+Cairo text layout/font selection/rendering to a useful baseline for further work, r=me
This commit is contained in:
Родитель
c8bfbaca8d
Коммит
4ab24bc9d1
|
@ -80,7 +80,7 @@ typedef struct cairo_quartzgl_surface {
|
||||||
AGLContext aglContext;
|
AGLContext aglContext;
|
||||||
CGContextRef cgContext;
|
CGContextRef cgContext;
|
||||||
|
|
||||||
cairo_rectangle_t extents;
|
cairo_rectangle_fixed_t extents;
|
||||||
|
|
||||||
/* These are stored while drawing operations are in place, set up
|
/* These are stored while drawing operations are in place, set up
|
||||||
* by quartzgl_setup_source() and quartzgl_finish_source()
|
* by quartzgl_setup_source() and quartzgl_finish_source()
|
||||||
|
@ -438,7 +438,7 @@ SurfacePatternDrawFunc (void *info, CGContextRef context)
|
||||||
{
|
{
|
||||||
cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) info;
|
cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) info;
|
||||||
cairo_surface_t *pat_surf = spat->surface;
|
cairo_surface_t *pat_surf = spat->surface;
|
||||||
cairo_rectangle_t extents;
|
cairo_rectangle_fixed_t extents;
|
||||||
cairo_status_t status;
|
cairo_status_t status;
|
||||||
|
|
||||||
cairo_quartzgl_surface_t *quartz_surf = NULL;
|
cairo_quartzgl_surface_t *quartz_surf = NULL;
|
||||||
|
@ -455,7 +455,7 @@ SurfacePatternDrawFunc (void *info, CGContextRef context)
|
||||||
|
|
||||||
cairo_surface_t *dummy = cairo_quartzgl_surface_create (CAIRO_FORMAT_ARGB32, 1, 1, TRUE);
|
cairo_surface_t *dummy = cairo_quartzgl_surface_create (CAIRO_FORMAT_ARGB32, 1, 1, TRUE);
|
||||||
|
|
||||||
cairo_rectangle_t rect;
|
cairo_rectangle_fixed_t rect;
|
||||||
_cairo_surface_get_extents (pat_surf, &rect);
|
_cairo_surface_get_extents (pat_surf, &rect);
|
||||||
|
|
||||||
cairo_surface_t *new_surf = NULL;
|
cairo_surface_t *new_surf = NULL;
|
||||||
|
@ -506,7 +506,7 @@ _cairo_quartzgl_cairo_repeating_surface_pattern_to_quartz (cairo_quartzgl_surfac
|
||||||
{
|
{
|
||||||
cairo_surface_pattern_t *spat;
|
cairo_surface_pattern_t *spat;
|
||||||
cairo_surface_t *pat_surf;
|
cairo_surface_t *pat_surf;
|
||||||
cairo_rectangle_t extents;
|
cairo_rectangle_fixed_t extents;
|
||||||
|
|
||||||
CGRect pbounds;
|
CGRect pbounds;
|
||||||
CGAffineTransform ptransform, stransform;
|
CGAffineTransform ptransform, stransform;
|
||||||
|
@ -843,9 +843,9 @@ _cairo_quartzgl_surface_acquire_source_image (void *abstract_surface,
|
||||||
|
|
||||||
static cairo_status_t
|
static cairo_status_t
|
||||||
_cairo_quartzgl_surface_acquire_dest_image (void *abstract_surface,
|
_cairo_quartzgl_surface_acquire_dest_image (void *abstract_surface,
|
||||||
cairo_rectangle_t *interest_rect,
|
cairo_rectangle_fixed_t *interest_rect,
|
||||||
cairo_image_surface_t **image_out,
|
cairo_image_surface_t **image_out,
|
||||||
cairo_rectangle_t *image_rect,
|
cairo_rectangle_fixed_t *image_rect,
|
||||||
void **image_extra)
|
void **image_extra)
|
||||||
{
|
{
|
||||||
cairo_quartzgl_surface_t *surface = (cairo_quartzgl_surface_t *) abstract_surface;
|
cairo_quartzgl_surface_t *surface = (cairo_quartzgl_surface_t *) abstract_surface;
|
||||||
|
@ -867,9 +867,9 @@ _cairo_quartzgl_surface_acquire_dest_image (void *abstract_surface,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_cairo_quartzgl_surface_release_dest_image (void *abstract_surface,
|
_cairo_quartzgl_surface_release_dest_image (void *abstract_surface,
|
||||||
cairo_rectangle_t *interest_rect,
|
cairo_rectangle_fixed_t *interest_rect,
|
||||||
cairo_image_surface_t *image,
|
cairo_image_surface_t *image,
|
||||||
cairo_rectangle_t *image_rect,
|
cairo_rectangle_fixed_t *image_rect,
|
||||||
void *image_extra)
|
void *image_extra)
|
||||||
{
|
{
|
||||||
cairo_quartzgl_surface_t *surface = (cairo_quartzgl_surface_t *) abstract_surface;
|
cairo_quartzgl_surface_t *surface = (cairo_quartzgl_surface_t *) abstract_surface;
|
||||||
|
@ -1041,7 +1041,7 @@ _cairo_quartzgl_surface_clone_similar (void *abstract_surface,
|
||||||
|
|
||||||
static cairo_int_status_t
|
static cairo_int_status_t
|
||||||
_cairo_quartzgl_surface_get_extents (void *abstract_surface,
|
_cairo_quartzgl_surface_get_extents (void *abstract_surface,
|
||||||
cairo_rectangle_t *extents)
|
cairo_rectangle_fixed_t *extents)
|
||||||
{
|
{
|
||||||
cairo_quartzgl_surface_t *surface = (cairo_quartzgl_surface_t *) abstract_surface;
|
cairo_quartzgl_surface_t *surface = (cairo_quartzgl_surface_t *) abstract_surface;
|
||||||
|
|
||||||
|
@ -1469,7 +1469,8 @@ _cairo_quartzgl_surface_create_internal (CGContextRef cgContext,
|
||||||
|
|
||||||
memset(surface, 0, sizeof(cairo_quartzgl_surface_t));
|
memset(surface, 0, sizeof(cairo_quartzgl_surface_t));
|
||||||
|
|
||||||
_cairo_surface_init(&surface->base, &cairo_quartzgl_surface_backend);
|
_cairo_surface_init(&surface->base, &cairo_quartzgl_surface_backend,
|
||||||
|
CAIRO_CONTENT_COLOR_ALPHA);
|
||||||
|
|
||||||
/* Save our extents */
|
/* Save our extents */
|
||||||
surface->extents.x = surface->extents.y = 0;
|
surface->extents.x = surface->extents.y = 0;
|
||||||
|
|
|
@ -50,22 +50,26 @@ class gfxAtsuiFont : public gfxFont {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
gfxAtsuiFont(ATSUFontID fontID,
|
gfxAtsuiFont(ATSUFontID fontID,
|
||||||
gfxAtsuiFontGroup *fontGroup);
|
const gfxFontStyle *fontStyle);
|
||||||
virtual ~gfxAtsuiFont();
|
virtual ~gfxAtsuiFont();
|
||||||
|
|
||||||
virtual const gfxFont::Metrics& GetMetrics();
|
virtual const gfxFont::Metrics& GetMetrics();
|
||||||
|
|
||||||
|
float GetCharWidth (PRUnichar c);
|
||||||
|
|
||||||
ATSUFontID GetATSUFontID() { return mATSUFontID; }
|
ATSUFontID GetATSUFontID() { return mATSUFontID; }
|
||||||
|
|
||||||
cairo_font_face_t *CairoFontFace() { return mFontFace; }
|
cairo_font_face_t *CairoFontFace() { return mFontFace; }
|
||||||
cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; }
|
cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; }
|
||||||
|
|
||||||
protected:
|
ATSUStyle GetATSUStyle() { return mATSUStyle; }
|
||||||
ATSUFontID mATSUFontID;
|
|
||||||
|
|
||||||
const gfxAtsuiFontGroup *mFontGroup;
|
protected:
|
||||||
const gfxFontStyle *mFontStyle;
|
const gfxFontStyle *mFontStyle;
|
||||||
|
|
||||||
|
ATSUFontID mATSUFontID;
|
||||||
|
ATSUStyle mATSUStyle;
|
||||||
|
|
||||||
cairo_font_face_t *mFontFace;
|
cairo_font_face_t *mFontFace;
|
||||||
cairo_scaled_font_t *mScaledFont;
|
cairo_scaled_font_t *mScaledFont;
|
||||||
|
|
||||||
|
@ -83,7 +87,7 @@ public:
|
||||||
return MakeTextRun(NS_ConvertASCIItoUTF16(aCString));
|
return MakeTextRun(NS_ConvertASCIItoUTF16(aCString));
|
||||||
}
|
}
|
||||||
|
|
||||||
ATSUFontFallbacks *GetATSUFontFallbacks() { return &mFallbacks; }
|
ATSUFontFallbacks *GetATSUFontFallbacksPtr() { return &mFallbacks; }
|
||||||
|
|
||||||
gfxAtsuiFont* GetFontAt(PRInt32 i) {
|
gfxAtsuiFont* GetFontAt(PRInt32 i) {
|
||||||
return NS_STATIC_CAST(gfxAtsuiFont*, NS_STATIC_CAST(gfxFont*, mFonts[i]));
|
return NS_STATIC_CAST(gfxAtsuiFont*, NS_STATIC_CAST(gfxFont*, mFonts[i]));
|
||||||
|
@ -91,7 +95,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static PRBool FindATSUFont(const nsAString& aName,
|
static PRBool FindATSUFont(const nsAString& aName,
|
||||||
const nsAString& aGenericName,
|
const nsACString& aGenericName,
|
||||||
void *closure);
|
void *closure);
|
||||||
|
|
||||||
ATSUFontFallbacks mFallbacks;
|
ATSUFontFallbacks mFallbacks;
|
||||||
|
@ -113,9 +117,9 @@ private:
|
||||||
nsString mString;
|
nsString mString;
|
||||||
gfxAtsuiFontGroup *mGroup;
|
gfxAtsuiFontGroup *mGroup;
|
||||||
|
|
||||||
ATSUStyle mATSUStyle;
|
|
||||||
|
|
||||||
ATSUTextLayout mATSULayout;
|
ATSUTextLayout mATSULayout;
|
||||||
|
|
||||||
|
nsTArray<ATSUStyle> mStylesToDispose;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* GFX_ATSUIFONTS_H */
|
#endif /* GFX_ATSUIFONTS_H */
|
||||||
|
|
|
@ -84,8 +84,10 @@ ifneq (,$(filter $(MOZ_GFX_TOOLKIT),mac cocoa))
|
||||||
CPPSRCS += gfxQuartzSurface.cpp gfxPlatformMac.cpp gfxAtsuiFonts.cpp
|
CPPSRCS += gfxQuartzSurface.cpp gfxPlatformMac.cpp gfxAtsuiFonts.cpp
|
||||||
#CPPSRCS += gfxPDFSurface.cpp
|
#CPPSRCS += gfxPDFSurface.cpp
|
||||||
|
|
||||||
|
CMMSRCS = gfxQuartzFontCache.mm
|
||||||
|
|
||||||
# Always link with OpenGL/AGL
|
# Always link with OpenGL/AGL
|
||||||
EXTRA_DSO_LDOPTS += -framework OpenGL -framework AGL
|
EXTRA_DSO_LDOPTS += -framework OpenGL -framework AGL -framework Cocoa
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef MOZ_ENABLE_GLITZ
|
ifdef MOZ_ENABLE_GLITZ
|
||||||
|
|
|
@ -37,6 +37,8 @@
|
||||||
|
|
||||||
#include "prtypes.h"
|
#include "prtypes.h"
|
||||||
#include "prmem.h"
|
#include "prmem.h"
|
||||||
|
#include "nsString.h"
|
||||||
|
|
||||||
#include "gfxTypes.h"
|
#include "gfxTypes.h"
|
||||||
|
|
||||||
#include "nsPromiseFlatString.h"
|
#include "nsPromiseFlatString.h"
|
||||||
|
@ -46,16 +48,71 @@
|
||||||
|
|
||||||
#include "cairo-atsui.h"
|
#include "cairo-atsui.h"
|
||||||
|
|
||||||
|
#include "gfxQuartzSurface.h"
|
||||||
|
#include "gfxQuartzFontCache.h"
|
||||||
|
|
||||||
|
/* We might still need this for fast-pathing, but we'll see */
|
||||||
|
#if 0
|
||||||
|
OSStatus ATSUGetStyleGroup(ATSUStyle style, void **styleGroup);
|
||||||
|
OSStatus ATSUDisposeStyleGroup(void *styleGroup);
|
||||||
|
OSStatus ATSUConvertCharToGlyphs(void *styleGroup,
|
||||||
|
PRunichar *buffer
|
||||||
|
unsigned int bufferLength,
|
||||||
|
void *glyphVector);
|
||||||
|
OSStatus ATSInitializeGlyphVector(int size, void *glyphVectorPtr);
|
||||||
|
OSStatus ATSClearGlyphVector(void *glyphVectorPtr);
|
||||||
|
#endif
|
||||||
|
|
||||||
THEBES_IMPL_REFCOUNTING(gfxAtsuiFont)
|
THEBES_IMPL_REFCOUNTING(gfxAtsuiFont)
|
||||||
|
|
||||||
gfxAtsuiFont::gfxAtsuiFont(ATSUFontID fontID,
|
gfxAtsuiFont::gfxAtsuiFont(ATSUFontID fontID,
|
||||||
gfxAtsuiFontGroup *fontGroup)
|
const gfxFontStyle *fontStyle)
|
||||||
: gfxFont(EmptyString(), fontGroup),
|
: gfxFont(EmptyString(), fontStyle),
|
||||||
mATSUFontID(fontID), mFontGroup(fontGroup)
|
mFontStyle(fontStyle), mATSUFontID(fontID), mATSUStyle(nsnull)
|
||||||
{
|
{
|
||||||
ATSFontRef fontRef = FMGetATSFontRefFromFont(fontID);
|
ATSFontRef fontRef = FMGetATSFontRefFromFont(fontID);
|
||||||
|
|
||||||
mFontStyle = mFontGroup->GetStyle();
|
/* Create the ATSUStyle */
|
||||||
|
|
||||||
|
ATSUAttributeTag styleTags[] = {
|
||||||
|
kATSUFontTag,
|
||||||
|
kATSUSizeTag,
|
||||||
|
kATSUFontMatrixTag,
|
||||||
|
kATSUKerningInhibitFactorTag
|
||||||
|
};
|
||||||
|
|
||||||
|
ByteCount styleArgSizes[] = {
|
||||||
|
sizeof(ATSUFontID),
|
||||||
|
sizeof(Fixed),
|
||||||
|
sizeof(CGAffineTransform),
|
||||||
|
sizeof(Fract)
|
||||||
|
};
|
||||||
|
|
||||||
|
//fprintf (stderr, "string: '%s', size: %f\n", NS_ConvertUTF16toUTF8(aString).get(), aGroup->GetStyle()->size);
|
||||||
|
|
||||||
|
// fSize is in points (72dpi)
|
||||||
|
Fixed fSize = FloatToFixed(mStyle->size);
|
||||||
|
ATSUFontID fid = fontID;
|
||||||
|
// make the font render right-side up
|
||||||
|
CGAffineTransform transform = CGAffineTransformMakeScale(1, -1);
|
||||||
|
// we can't do kerning until layout draws what it measures, instead of splitting things up
|
||||||
|
Fract inhibitKerningFactor = FloatToFract(1.0);
|
||||||
|
|
||||||
|
ATSUAttributeValuePtr styleArgs[] = {
|
||||||
|
&fid,
|
||||||
|
&fSize,
|
||||||
|
&transform,
|
||||||
|
&inhibitKerningFactor
|
||||||
|
};
|
||||||
|
|
||||||
|
ATSUCreateStyle(&mATSUStyle);
|
||||||
|
ATSUSetAttributes(mATSUStyle,
|
||||||
|
sizeof(styleTags)/sizeof(ATSUAttributeTag),
|
||||||
|
styleTags,
|
||||||
|
styleArgSizes,
|
||||||
|
styleArgs);
|
||||||
|
|
||||||
|
/* Now pull out the metrics */
|
||||||
|
|
||||||
ATSFontMetrics atsMetrics;
|
ATSFontMetrics atsMetrics;
|
||||||
ATSFontGetHorizontalMetrics(fontRef, kATSOptionFlagsDefault,
|
ATSFontGetHorizontalMetrics(fontRef, kATSOptionFlagsDefault,
|
||||||
|
@ -82,7 +139,7 @@ gfxAtsuiFont::gfxAtsuiFont(ATSUFontID fontID,
|
||||||
if (atsMetrics.avgAdvanceWidth != 0.0)
|
if (atsMetrics.avgAdvanceWidth != 0.0)
|
||||||
mMetrics.aveCharWidth = atsMetrics.avgAdvanceWidth * size;
|
mMetrics.aveCharWidth = atsMetrics.avgAdvanceWidth * size;
|
||||||
else
|
else
|
||||||
mMetrics.aveCharWidth = mMetrics.maxAdvance;
|
mMetrics.aveCharWidth = GetCharWidth('a');
|
||||||
|
|
||||||
mMetrics.underlineOffset = atsMetrics.underlinePosition * size;
|
mMetrics.underlineOffset = atsMetrics.underlinePosition * size;
|
||||||
mMetrics.underlineSize = atsMetrics.underlineThickness * size;
|
mMetrics.underlineSize = atsMetrics.underlineThickness * size;
|
||||||
|
@ -93,7 +150,7 @@ gfxAtsuiFont::gfxAtsuiFont(ATSUFontID fontID,
|
||||||
mMetrics.strikeoutOffset = mMetrics.xHeight / 2.0;
|
mMetrics.strikeoutOffset = mMetrics.xHeight / 2.0;
|
||||||
mMetrics.strikeoutSize = mMetrics.underlineSize;
|
mMetrics.strikeoutSize = mMetrics.underlineSize;
|
||||||
|
|
||||||
mMetrics.spaceWidth = mMetrics.aveCharWidth;
|
mMetrics.spaceWidth = GetCharWidth(' ');
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
fprintf (stderr, "Font: %p size: %f", this, size);
|
fprintf (stderr, "Font: %p size: %f", this, size);
|
||||||
|
@ -115,10 +172,37 @@ gfxAtsuiFont::gfxAtsuiFont(ATSUFontID fontID,
|
||||||
cairo_font_options_destroy(fontOptions);
|
cairo_font_options_destroy(fontOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
gfxAtsuiFont::GetCharWidth(PRUnichar c)
|
||||||
|
{
|
||||||
|
// this sucks. There is a faster way to go from a char -> glyphs, but it
|
||||||
|
// requires using oodles of apple private interfaces. If we start caching
|
||||||
|
// gfxAtsuiFonts, then it might make sense to do that.
|
||||||
|
ATSUTextLayout layout;
|
||||||
|
|
||||||
|
UniCharCount one = 1;
|
||||||
|
ATSUCreateTextLayoutWithTextPtr(&c, 0, 1, 1, 1, &one, &mATSUStyle, &layout);
|
||||||
|
|
||||||
|
ATSTrapezoid trap;
|
||||||
|
ItemCount numBounds;
|
||||||
|
ATSUGetGlyphBounds(layout, FloatToFixed(0.0), FloatToFixed(0.0),
|
||||||
|
0, 1, kATSUseFractionalOrigins, 1, &trap, &numBounds);
|
||||||
|
|
||||||
|
float f =
|
||||||
|
FixedToFloat(PR_MAX(trap.upperRight.x, trap.lowerRight.x)) -
|
||||||
|
FixedToFloat(PR_MIN(trap.upperLeft.x, trap.lowerLeft.x));
|
||||||
|
|
||||||
|
ATSUDisposeTextLayout(layout);
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
gfxAtsuiFont::~gfxAtsuiFont()
|
gfxAtsuiFont::~gfxAtsuiFont()
|
||||||
{
|
{
|
||||||
cairo_scaled_font_destroy(mScaledFont);
|
cairo_scaled_font_destroy(mScaledFont);
|
||||||
cairo_font_face_destroy(mFontFace);
|
cairo_font_face_destroy(mFontFace);
|
||||||
|
|
||||||
|
ATSUDisposeStyle(mATSUStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
const gfxFont::Metrics&
|
const gfxFont::Metrics&
|
||||||
|
@ -133,6 +217,21 @@ gfxAtsuiFontGroup::gfxAtsuiFontGroup(const nsAString& families,
|
||||||
{
|
{
|
||||||
ForEachFont(FindATSUFont, this);
|
ForEachFont(FindATSUFont, this);
|
||||||
|
|
||||||
|
if (mFonts.Length() == 0) {
|
||||||
|
// XXX this will generate a list of the lang groups for which we have no
|
||||||
|
// default fonts for on the mac; we should fix this!
|
||||||
|
// Known:
|
||||||
|
// ja x-beng x-devanagari x-tamil x-geor x-ethi x-gujr x-mlym x-armn
|
||||||
|
|
||||||
|
//fprintf (stderr, "gfxAtsuiFontGroup: %s [%s] -> %d fonts found\n", NS_ConvertUTF16toUTF8(families).get(), aStyle->langGroup.get(), mFonts.Length());
|
||||||
|
|
||||||
|
// If we get here, we most likely didn't have a default font for
|
||||||
|
// a specific langGroup. Let's just pick the default OSX
|
||||||
|
// user font.
|
||||||
|
ATSUFontID fontID = gfxQuartzFontCache::SharedFontCache()->GetDefaultATSUFontID (aStyle);
|
||||||
|
mFonts.AppendElement(new gfxAtsuiFont(fontID, aStyle));
|
||||||
|
}
|
||||||
|
|
||||||
// Create the fallback structure
|
// Create the fallback structure
|
||||||
ATSUCreateFontFallbacks(&mFallbacks);
|
ATSUCreateFontFallbacks(&mFallbacks);
|
||||||
|
|
||||||
|
@ -145,7 +244,7 @@ gfxAtsuiFontGroup::gfxAtsuiFontGroup(const nsAString& families,
|
||||||
fids = static_fids;
|
fids = static_fids;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < mFonts.Length(); i++) {
|
for (unsigned int i = 0; i < mFonts.Length(); i++) {
|
||||||
nsRefPtr<gfxAtsuiFont> atsuiFont = NS_STATIC_CAST(gfxAtsuiFont*, NS_STATIC_CAST(gfxFont*, mFonts[i]));
|
gfxAtsuiFont* atsuiFont = NS_STATIC_CAST(gfxAtsuiFont*, NS_STATIC_CAST(gfxFont*, mFonts[i]));
|
||||||
fids[i] = atsuiFont->GetATSUFontID();
|
fids[i] = atsuiFont->GetATSUFontID();
|
||||||
}
|
}
|
||||||
ATSUSetObjFontFallbacks(mFallbacks,
|
ATSUSetObjFontFallbacks(mFallbacks,
|
||||||
|
@ -157,98 +256,22 @@ gfxAtsuiFontGroup::gfxAtsuiFontGroup(const nsAString& families,
|
||||||
PR_Free(fids);
|
PR_Free(fids);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This function will /really/ want to just keep a hash lookup table
|
|
||||||
* based on name and style attributes that we compute; doing stuff with
|
|
||||||
* Pascal strings and whatnot is /so/ 1980's.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
06:19 < AngryLuke> vlad, which method in NSFontManager does what you want?
|
|
||||||
06:21 < vlad_> ideally fontWithFamily:traits:weight:size:, but I really need to
|
|
||||||
just iterate through all the fonts in a particular family
|
|
||||||
06:21 < vlad_> and examine their traits
|
|
||||||
06:22 < AngryLuke> vlad, NSFontManager is using the private FontObject APIs for
|
|
||||||
this it seems
|
|
||||||
06:22 < vlad_> AngryLuke: fun
|
|
||||||
06:22 < vlad_> AngryLuke: so what's the "right" way of doing this?
|
|
||||||
06:23 < AngryLuke> vlad, crying ;) I ended up just using the FontManager,
|
|
||||||
despite the fact it is deprecated. But that won't work for
|
|
||||||
Unicode fonts with no FOND
|
|
||||||
06:23 < AngryLuke> ATS has no functions for this
|
|
||||||
06:23 < AngryLuke> and NSFontManager is the only other way that is public.
|
|
||||||
*/
|
|
||||||
|
|
||||||
PRBool
|
PRBool
|
||||||
gfxAtsuiFontGroup::FindATSUFont(const nsAString& aName,
|
gfxAtsuiFontGroup::FindATSUFont(const nsAString& aName,
|
||||||
const nsAString& aGenericName,
|
const nsACString& aGenericName,
|
||||||
void *closure)
|
void *closure)
|
||||||
{
|
{
|
||||||
OSStatus status;
|
|
||||||
gfxAtsuiFontGroup *fontGroup = (gfxAtsuiFontGroup*) closure;
|
gfxAtsuiFontGroup *fontGroup = (gfxAtsuiFontGroup*) closure;
|
||||||
const gfxFontStyle *fontStyle = fontGroup->GetStyle();
|
const gfxFontStyle *fontStyle = fontGroup->GetStyle();
|
||||||
|
|
||||||
PRInt16 baseWeight, offsetWeight;
|
gfxQuartzFontCache *fc = gfxQuartzFontCache::SharedFontCache();
|
||||||
fontStyle->ComputeWeightAndOffset(&baseWeight, &offsetWeight);
|
ATSUFontID fontID = fc->FindATSUFontIDForFamilyAndStyle (aName, fontStyle);
|
||||||
baseWeight += offsetWeight;
|
|
||||||
baseWeight = PR_MIN(9, PR_MAX(0, baseWeight));
|
|
||||||
|
|
||||||
Boolean isBold = (baseWeight >= 7) ? TRUE : FALSE;
|
if (fontID != kATSUInvalidFontID) {
|
||||||
Boolean isItalic = ((fontStyle->style & FONT_STYLE_ITALIC) != 0) ? TRUE : FALSE;
|
/*printf ("FindATSUFont! %s %d -> %d\n", NS_ConvertUTF16toUTF8(aName).get(), fontStyle->weight, (int)fontID);*/
|
||||||
|
fontGroup->mFonts.AppendElement(new gfxAtsuiFont(fontID, fontStyle));
|
||||||
#if 0
|
|
||||||
|
|
||||||
Str255 pascalName;
|
|
||||||
CopyCStringToPascalString(nsPromiseFlatCString(NS_ConvertUTF16toUTF8(aName)).get(),
|
|
||||||
pascalName);
|
|
||||||
|
|
||||||
FMFontFamily fmFamily = FMGetFontFamilyFromName(pascalName);
|
|
||||||
if (fmFamily == kInvalidFontFamily)
|
|
||||||
return PR_TRUE;
|
|
||||||
|
|
||||||
FMFontFamilyInstanceIterator famFontIterator;
|
|
||||||
status = FMCreateFontFamilyInstanceIterator(fmFamily, &famFontIterator);
|
|
||||||
if (status != noErr) {
|
|
||||||
fprintf(stderr, "FMCreateFontFamilyInstanceIterator returned error %d\n", (int) status);
|
|
||||||
return PR_TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FMFont famFont;
|
|
||||||
FMFontStyle famFontStyle;
|
|
||||||
FMFontSize famFontSize;
|
|
||||||
|
|
||||||
while ((status = FMGetNextFontFamilyInstance(famFontIterator,
|
|
||||||
&famFont,
|
|
||||||
&famFontStyle,
|
|
||||||
&famFontSize)) == noErr)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != kFMIterationCompleted) {
|
|
||||||
fprintf (stderr, "FMGetNextFontFamilyInstance returned error %d\n", (int) status);
|
|
||||||
return PR_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
FMDisposeFontFamilyInstanceIterator(&familyFontIterator);
|
|
||||||
#else
|
|
||||||
ATSUFontID fontID;
|
|
||||||
|
|
||||||
status = ATSUFindFontFromName(NS_ConvertUTF16toUTF8(aName).get(), aName.Length(),
|
|
||||||
/* nsPromiseFlatString(aName).get(),
|
|
||||||
aName.Length() * 2,*/
|
|
||||||
kFontFamilyName,
|
|
||||||
kFontNoPlatformCode /* kFontUnicodePlatform */,
|
|
||||||
kFontNoScriptCode,
|
|
||||||
kFontNoLanguageCode,
|
|
||||||
&fontID);
|
|
||||||
|
|
||||||
//fprintf (stderr, "FindATSUFont: %s -> %d (status: %d)\n", NS_ConvertUTF16toUTF8(aName).get(), (int) fontID, (int) status);
|
|
||||||
|
|
||||||
if (fontID != kATSUInvalidFontID)
|
|
||||||
fontGroup->mFonts.AppendElement(new gfxAtsuiFont(fontID, fontGroup));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,145 +296,194 @@ gfxAtsuiTextRun::gfxAtsuiTextRun(const nsAString& aString, gfxAtsuiFontGroup *aG
|
||||||
: mString(aString), mGroup(aGroup)
|
: mString(aString), mGroup(aGroup)
|
||||||
{
|
{
|
||||||
OSStatus status;
|
OSStatus status;
|
||||||
const gfxFontStyle *fontStyle = mGroup->GetStyle();
|
gfxAtsuiFont *atsuiFont = mGroup->GetFontAt(0);
|
||||||
|
ATSUStyle mainStyle = atsuiFont->GetATSUStyle();
|
||||||
PRInt16 baseWeight, offsetWeight;
|
|
||||||
fontStyle->ComputeWeightAndOffset(&baseWeight, &offsetWeight);
|
|
||||||
baseWeight += offsetWeight;
|
|
||||||
if (baseWeight < 0) baseWeight = 0;
|
|
||||||
else if (baseWeight > 9) baseWeight = 9;
|
|
||||||
|
|
||||||
// we can't do kerning until layout draws what it measures, instead of splitting things up
|
|
||||||
ATSUAttributeTag styleTags[] = {
|
|
||||||
kATSUFontTag,
|
|
||||||
kATSUSizeTag,
|
|
||||||
kATSUKerningInhibitFactorTag,
|
|
||||||
kATSUQDBoldfaceTag,
|
|
||||||
kATSUQDItalicTag,
|
|
||||||
};
|
|
||||||
|
|
||||||
ByteCount styleArgSizes[] = {
|
|
||||||
sizeof(ATSUFontID),
|
|
||||||
sizeof(Fixed),
|
|
||||||
sizeof(Fract),
|
|
||||||
sizeof(Boolean),
|
|
||||||
sizeof(Boolean)
|
|
||||||
};
|
|
||||||
|
|
||||||
//fprintf (stderr, "string: '%s', size: %f\n", NS_ConvertUTF16toUTF8(aString).get(), aGroup->GetStyle()->size);
|
|
||||||
|
|
||||||
// fSize is in points (72dpi)
|
|
||||||
Fixed fSize = FloatToFixed(aGroup->GetStyle()->size);
|
|
||||||
nsRefPtr<gfxAtsuiFont> atsuiFont = mGroup->GetFontAt(0);
|
|
||||||
ATSUFontID fid = atsuiFont->GetATSUFontID();
|
|
||||||
Fract inhibitKerningFactor = FloatToFract(1.0);
|
|
||||||
/* Why am I even setting these? the fid font will end up being used no matter what;
|
|
||||||
* need smarter font selection earlier on...
|
|
||||||
*/
|
|
||||||
Boolean isBold = (baseWeight >= 7) ? TRUE : FALSE;
|
|
||||||
Boolean isItalic = ((fontStyle->style & FONT_STYLE_ITALIC) != 0) ? TRUE : FALSE;
|
|
||||||
|
|
||||||
|
|
||||||
//fprintf (stderr, " bold: %d italic: %d\n", isBold, isItalic);
|
|
||||||
|
|
||||||
ATSUAttributeValuePtr styleArgs[] = {
|
|
||||||
&fid,
|
|
||||||
&fSize,
|
|
||||||
&inhibitKerningFactor,
|
|
||||||
&isBold,
|
|
||||||
&isItalic
|
|
||||||
};
|
|
||||||
|
|
||||||
status = ATSUCreateStyle(&mATSUStyle);
|
|
||||||
status = ATSUSetAttributes(mATSUStyle,
|
|
||||||
sizeof(styleTags)/sizeof(ATSUAttributeTag),
|
|
||||||
styleTags,
|
|
||||||
styleArgSizes,
|
|
||||||
styleArgs);
|
|
||||||
if (status != noErr)
|
|
||||||
fprintf (stderr, "ATUSetAttributes gave error: %d\n", (int) status);
|
|
||||||
|
|
||||||
UniCharCount runLengths = kATSUToTextEnd;
|
|
||||||
|
|
||||||
|
UniCharCount runLengths = mString.Length();
|
||||||
status = ATSUCreateTextLayoutWithTextPtr
|
status = ATSUCreateTextLayoutWithTextPtr
|
||||||
(nsPromiseFlatString(mString).get(),
|
(nsPromiseFlatString(mString).get(),
|
||||||
kATSUFromTextBeginning,
|
0,
|
||||||
kATSUToTextEnd,
|
mString.Length(),
|
||||||
mString.Length(),
|
mString.Length(),
|
||||||
1,
|
1,
|
||||||
&runLengths,
|
&runLengths,
|
||||||
&mATSUStyle,
|
&mainStyle,
|
||||||
&mATSULayout);
|
&mATSULayout);
|
||||||
|
|
||||||
|
// Set up line layout
|
||||||
|
ATSLineLayoutOptions lineLayoutOptions = kATSLineKeepSpacesOutOfMargin | kATSLineHasNoHangers;
|
||||||
|
ATSUAttributeTag layoutTags[] = { kATSULineLayoutOptionsTag };
|
||||||
|
ByteCount layoutArgSizes[] = { sizeof(ATSLineLayoutOptions) };
|
||||||
|
ATSUAttributeValuePtr layoutArgs[] = { &lineLayoutOptions };
|
||||||
|
ATSUSetLayoutControls(mATSULayout,
|
||||||
|
sizeof(layoutTags) / sizeof(ATSUAttributeTag),
|
||||||
|
layoutTags,
|
||||||
|
layoutArgSizes,
|
||||||
|
layoutArgs);
|
||||||
|
|
||||||
// Set up our font fallbacks
|
// Set up our font fallbacks
|
||||||
ATSUAttributeTag lineTags[] = { kATSULineFontFallbacksTag };
|
ATSUAttributeTag lineTags[] = { kATSULineFontFallbacksTag };
|
||||||
ByteCount lineArgSizes[] = { sizeof(ATSUFontFallbacks) };
|
ByteCount lineArgSizes[] = { sizeof(ATSUFontFallbacks) };
|
||||||
ATSUAttributeValuePtr lineArgs[] = { mGroup->GetATSUFontFallbacks() };
|
ATSUAttributeValuePtr lineArgs[] = { mGroup->GetATSUFontFallbacksPtr() };
|
||||||
status = ATSUSetLineControls(mATSULayout,
|
status = ATSUSetLineControls(mATSULayout,
|
||||||
0,
|
0,
|
||||||
sizeof(lineTags) / sizeof(ATSUAttributeTag),
|
sizeof(lineTags) / sizeof(ATSUAttributeTag),
|
||||||
lineTags,
|
lineTags,
|
||||||
lineArgSizes,
|
lineArgSizes,
|
||||||
lineArgs);
|
lineArgs);
|
||||||
if (status != noErr)
|
if (status != noErr) {
|
||||||
fprintf(stderr, "ATSUSetLineControls gave error: %d\n", (int) status);
|
fprintf(stderr, "ATSUSetLineControls gave error: %d\n", (int) status);
|
||||||
|
}
|
||||||
|
|
||||||
ATSUSetTransientFontMatching(mATSULayout, true);
|
/* Now go through and update the styles for the text, based on font matching. */
|
||||||
|
|
||||||
|
UniCharArrayOffset runStart = 0;
|
||||||
|
UniCharCount runLength = mString.Length();
|
||||||
|
while (runStart < runLength) {
|
||||||
|
ATSUFontID substituteFontID;
|
||||||
|
UniCharArrayOffset changedOffset;
|
||||||
|
UniCharCount changedLength;
|
||||||
|
|
||||||
|
OSStatus status = ATSUMatchFontsToText (mATSULayout, runStart, kATSUToTextEnd,
|
||||||
|
&substituteFontID, &changedOffset, &changedLength);
|
||||||
|
if (status == noErr) {
|
||||||
|
// everything's good, finish up
|
||||||
|
break;
|
||||||
|
} else if (status == kATSUFontsMatched) {
|
||||||
|
ATSUStyle subStyle;
|
||||||
|
ATSUCreateStyle (&subStyle);
|
||||||
|
ATSUCopyAttributes (mainStyle, subStyle);
|
||||||
|
|
||||||
|
ATSUAttributeTag fontTags[] = { kATSUFontTag };
|
||||||
|
ByteCount fontArgSizes[] = { sizeof(ATSUFontID) };
|
||||||
|
ATSUAttributeValuePtr fontArgs[] = { &substituteFontID };
|
||||||
|
|
||||||
|
ATSUSetAttributes (subStyle, 1, fontTags, fontArgSizes, fontArgs);
|
||||||
|
|
||||||
|
ATSUSetRunStyle (mATSULayout, subStyle, changedOffset, changedLength);
|
||||||
|
|
||||||
|
mStylesToDispose.AppendElement(subStyle);
|
||||||
|
|
||||||
|
} else if (status == kATSUFontsNotMatched) {
|
||||||
|
/* I need to select the last resort font; how the heck do I do that? */
|
||||||
|
}
|
||||||
|
|
||||||
|
runStart = changedOffset+changedLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gfxAtsuiTextRun::~gfxAtsuiTextRun()
|
gfxAtsuiTextRun::~gfxAtsuiTextRun()
|
||||||
{
|
{
|
||||||
ATSUDisposeTextLayout(mATSULayout);
|
ATSUDisposeTextLayout(mATSULayout);
|
||||||
ATSUDisposeStyle(mATSUStyle);
|
|
||||||
|
for (PRUint32 i = 0; i < mStylesToDispose.Length(); i++) {
|
||||||
|
ATSUStyle s = mStylesToDispose[i];
|
||||||
|
ATSUDisposeStyle(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct CairoGlyphBuffer {
|
||||||
|
CairoGlyphBuffer() {
|
||||||
|
size = 128;
|
||||||
|
glyphs = staticGlyphBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
~CairoGlyphBuffer() {
|
||||||
|
if (glyphs != staticGlyphBuf)
|
||||||
|
PR_Free(glyphs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnsureSize(PRUint32 numGlyphs) {
|
||||||
|
if (size < numGlyphs) {
|
||||||
|
if (glyphs != staticGlyphBuf)
|
||||||
|
PR_Free (staticGlyphBuf);
|
||||||
|
glyphs = (cairo_glyph_t*) PR_Malloc(sizeof(cairo_glyph_t) * numGlyphs);
|
||||||
|
size = numGlyphs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRUint32 size;
|
||||||
|
cairo_glyph_t *glyphs;
|
||||||
|
private:
|
||||||
|
cairo_glyph_t staticGlyphBuf[128];
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
gfxAtsuiTextRun::Draw(gfxContext *aContext, gfxPoint pt)
|
gfxAtsuiTextRun::Draw(gfxContext *aContext, gfxPoint pt)
|
||||||
{
|
{
|
||||||
cairo_t *cr = aContext->GetCairo();
|
gfxFloat offsetX, offsetY;
|
||||||
nsRefPtr<gfxAtsuiFont> atsuiFont = mGroup->GetFontAt(0);
|
nsRefPtr<gfxASurface> surf = aContext->CurrentSurface (&offsetX, &offsetY);
|
||||||
cairo_set_font_face(cr, atsuiFont->CairoFontFace());
|
|
||||||
cairo_set_font_size(cr, mGroup->GetStyle()->size);
|
|
||||||
|
|
||||||
ItemCount cnt;
|
cairo_t *cr = aContext->GetCairo();
|
||||||
ATSLayoutRecord *layoutRecords = nsnull;
|
double fontSize = mGroup->GetStyle()->size;
|
||||||
OSStatus status = ATSUDirectGetLayoutDataArrayPtrFromTextLayout
|
|
||||||
(mATSULayout,
|
cairo_save (cr);
|
||||||
kATSUFromTextBeginning,
|
cairo_translate (cr, pt.x, pt.y);
|
||||||
kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
|
|
||||||
(void**)&layoutRecords,
|
OSStatus status;
|
||||||
&cnt);
|
|
||||||
|
ByteCount bufferSize = 4096;
|
||||||
|
ATSUGlyphInfoArray *glyphInfo = (ATSUGlyphInfoArray*) PR_Malloc (bufferSize);
|
||||||
|
status = ATSUGetGlyphInfo (mATSULayout, kATSUFromTextBeginning, kATSUToTextEnd, &bufferSize, glyphInfo);
|
||||||
|
if (status == buffersTooSmall) {
|
||||||
|
ATSUGetGlyphInfo (mATSULayout, kATSUFromTextBeginning, kATSUToTextEnd, &bufferSize, NULL);
|
||||||
|
PR_Free(glyphInfo);
|
||||||
|
glyphInfo = (ATSUGlyphInfoArray*) PR_Malloc (bufferSize);
|
||||||
|
|
||||||
|
status = ATSUGetGlyphInfo (mATSULayout, kATSUFromTextBeginning, kATSUToTextEnd, &bufferSize, glyphInfo);
|
||||||
|
}
|
||||||
|
|
||||||
if (status != noErr) {
|
if (status != noErr) {
|
||||||
fprintf(stderr, "ATSUDirectGetLayoutDataArrayPtrFromTextLayout failed, %d\n", noErr);
|
fprintf (stderr, "ATSUGetGlyphInfo returned error %d\n", (int) status);
|
||||||
|
PR_Free (glyphInfo);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_glyph_t *cglyphs = (cairo_glyph_t *) PR_Malloc (cnt * sizeof(cairo_glyph_t));
|
CairoGlyphBuffer cairoGlyphs;
|
||||||
if (!cglyphs)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//fprintf (stderr, "String: '%s'\n", NS_ConvertUTF16toUTF8(mString).get());
|
ItemCount i = 0;
|
||||||
|
while (i < glyphInfo->numGlyphs) {
|
||||||
|
ATSUStyle runStyle = glyphInfo->glyphs[i].style;
|
||||||
|
|
||||||
PRUint32 cgindex = 0;
|
ItemCount lastRunGlyph;
|
||||||
for (PRUint32 i = 0; i < cnt; i++) {
|
for (lastRunGlyph = i+1; lastRunGlyph < glyphInfo->numGlyphs; lastRunGlyph++) {
|
||||||
//fprintf(stderr, "[%d 0x%04x %f] ", i, layoutRecords[i].glyphID, FixedToFloat(layoutRecords[i].realPos));
|
if (glyphInfo->glyphs[lastRunGlyph].style != runStyle)
|
||||||
if (!(layoutRecords[i].flags & kATSGlyphInfoIsWhiteSpace)) {
|
break;
|
||||||
cglyphs[cgindex].index = layoutRecords[i].glyphID;
|
|
||||||
cglyphs[cgindex].x = pt.x + FixedToFloat(layoutRecords[i].realPos);
|
|
||||||
cglyphs[cgindex].y = pt.y;
|
|
||||||
cgindex++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ItemCount numGlyphs = lastRunGlyph-i;
|
||||||
|
ATSUFontID runFontID;
|
||||||
|
ByteCount unused;
|
||||||
|
status = ATSUGetAttribute (runStyle, kATSUFontTag, sizeof(ATSUFontID), &runFontID, &unused);
|
||||||
|
if (status != noErr || runFontID == kATSUInvalidFontID) {
|
||||||
|
i += numGlyphs;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cairoGlyphs.EnsureSize(numGlyphs);
|
||||||
|
cairo_glyph_t *runGlyphs = cairoGlyphs.glyphs;
|
||||||
|
|
||||||
|
for (ItemCount k = i; k < lastRunGlyph; k++) {
|
||||||
|
runGlyphs->index = glyphInfo->glyphs[k].glyphID;
|
||||||
|
runGlyphs->x = glyphInfo->glyphs[k].idealX; /* screenX */
|
||||||
|
runGlyphs->y = glyphInfo->glyphs[k].deltaY;
|
||||||
|
|
||||||
|
runGlyphs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_font_face_t *runFace = cairo_atsui_font_face_create_for_atsu_font_id (runFontID);
|
||||||
|
cairo_set_font_face (cr, runFace);
|
||||||
|
cairo_set_font_size (cr, fontSize);
|
||||||
|
|
||||||
|
cairo_show_glyphs (cr, cairoGlyphs.glyphs, numGlyphs);
|
||||||
|
cairo_font_face_destroy (runFace);
|
||||||
|
|
||||||
|
i += numGlyphs;
|
||||||
}
|
}
|
||||||
//fprintf (stderr, "\n");
|
|
||||||
|
|
||||||
ATSUDirectReleaseLayoutDataArrayPtr(NULL,
|
PR_Free (glyphInfo);
|
||||||
kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
|
|
||||||
(void**)&layoutRecords);
|
cairo_restore (cr);
|
||||||
|
|
||||||
cairo_show_glyphs(cr, cglyphs, cgindex);
|
|
||||||
|
|
||||||
PR_Free(cglyphs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gfxFloat
|
gfxFloat
|
||||||
|
@ -430,19 +502,32 @@ gfxAtsuiTextRun::Measure(gfxContext *aContext)
|
||||||
1,
|
1,
|
||||||
&trap,
|
&trap,
|
||||||
&numBounds);
|
&numBounds);
|
||||||
if (status != noErr)
|
if (status != noErr) {
|
||||||
fprintf(stderr, "ATSUGetGlyphBounds returned error %d!\n", (int) status);
|
fprintf(stderr, "ATSUGetGlyphBounds returned error %d!\n", (int) status);
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
float f = FixedToFloat(PR_MAX(trap.upperRight.x, trap.lowerRight.x)) - FixedToFloat(PR_MIN(trap.upperLeft.x, trap.lowerLeft.x));
|
#if 0
|
||||||
|
printf ("Measure: '%s' trap: %f %f %f %f\n",
|
||||||
|
NS_ConvertUTF16toUTF8(mString).get(),
|
||||||
|
FixedToFloat(trap.upperLeft.x), FixedToFloat(trap.lowerLeft.x),
|
||||||
|
FixedToFloat(trap.upperRight.x), FixedToFloat(trap.lowerRight.x));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float f =
|
||||||
|
FixedToFloat(PR_MAX(trap.upperRight.x, trap.lowerRight.x)) -
|
||||||
|
FixedToFloat(PR_MIN(trap.upperLeft.x, trap.lowerLeft.x));
|
||||||
|
|
||||||
//fprintf (stderr, "measured: %f\n", f);
|
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gfxAtsuiTextRun::SetSpacing(const nsTArray<gfxFloat> &spacingArray)
|
gfxAtsuiTextRun::SetSpacing(const nsTArray<gfxFloat> &spacingArray)
|
||||||
{
|
{
|
||||||
// XXX implement me!
|
// We can implement this, but there's really a mismatch between
|
||||||
|
// the spacings given here and cluster spacings. So we're
|
||||||
|
// going to do nothing until we figure out what the layout API
|
||||||
|
// will look like for this.
|
||||||
}
|
}
|
||||||
|
|
||||||
const nsTArray<gfxFloat> *const
|
const nsTArray<gfxFloat> *const
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* -*- 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 Corporation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Vladimir Vukicevic <vladimir@pobox.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 GFXQUARTZFONTCACHE_H_
|
||||||
|
#define GFXQUARTZFONTCACHE_H_
|
||||||
|
|
||||||
|
#include "gfxAtsuiFonts.h"
|
||||||
|
|
||||||
|
// XXX this is called a Cache because optimistically it will
|
||||||
|
// cache [family, weight, traits, language] -> fontid so that
|
||||||
|
// it doesn't have to do the lookup each time. It doesn't
|
||||||
|
// do this yet.
|
||||||
|
|
||||||
|
class gfxQuartzFontCache {
|
||||||
|
public:
|
||||||
|
static gfxQuartzFontCache* SharedFontCache() {
|
||||||
|
if (!sSharedFontCache)
|
||||||
|
sSharedFontCache = new gfxQuartzFontCache();
|
||||||
|
return sSharedFontCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
ATSUFontID FindATSUFontIDForFamilyAndStyle (const nsAString& aFamily,
|
||||||
|
const gfxFontStyle* aStyle);
|
||||||
|
|
||||||
|
ATSUFontID GetDefaultATSUFontID (const gfxFontStyle* aStyle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static gfxQuartzFontCache *sSharedFontCache;
|
||||||
|
|
||||||
|
gfxQuartzFontCache();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* MACFONTCACHE_H_ */
|
|
@ -0,0 +1,369 @@
|
||||||
|
/* -*- Mode: ObjC; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||||
|
* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: BSD
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 Mozilla Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
|
||||||
|
* its contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#include <Carbon.h>
|
||||||
|
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
|
||||||
|
#include "gfxPlatformMac.h"
|
||||||
|
#include "gfxQuartzFontCache.h"
|
||||||
|
|
||||||
|
// _atsFontID is private; add it in our new category to NSFont
|
||||||
|
@interface NSFont (MozillaCategory)
|
||||||
|
- (ATSUFontID)_atsFontID;
|
||||||
|
@end
|
||||||
|
|
||||||
|
gfxQuartzFontCache *gfxQuartzFontCache::sSharedFontCache = nsnull;
|
||||||
|
|
||||||
|
gfxQuartzFontCache::gfxQuartzFontCache() {
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SYNTHESIZED_FONT_TRAITS (NSBoldFontMask | NSItalicFontMask)
|
||||||
|
|
||||||
|
|
||||||
|
#define IMPORTANT_FONT_TRAITS (0 \
|
||||||
|
| NSBoldFontMask \
|
||||||
|
| NSCompressedFontMask \
|
||||||
|
| NSCondensedFontMask \
|
||||||
|
| NSExpandedFontMask \
|
||||||
|
| NSItalicFontMask \
|
||||||
|
| NSNarrowFontMask \
|
||||||
|
| NSPosterFontMask \
|
||||||
|
| NSSmallCapsFontMask \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define DESIRED_WEIGHT 5
|
||||||
|
|
||||||
|
#define APPLE_BOLD_WEIGHT 9
|
||||||
|
|
||||||
|
#define CSS_NORMAL_WEIGHT_BASE 4
|
||||||
|
#define CSS_BOLD_WEIGHT_BASE 7
|
||||||
|
|
||||||
|
#define INDEX_FONT_POSTSCRIPT_NAME 0
|
||||||
|
#define INDEX_FONT_EXTRA_NAME 1
|
||||||
|
#define INDEX_FONT_WEIGHT 2
|
||||||
|
#define INDEX_FONT_TRAITS 3
|
||||||
|
|
||||||
|
// see docs for NSFontManager-availableMembersOfFontFamily:
|
||||||
|
static const int CSSWeightToAppleWeight[] = {
|
||||||
|
// 0 invalid
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
8,
|
||||||
|
9,
|
||||||
|
10,
|
||||||
|
12
|
||||||
|
};
|
||||||
|
|
||||||
|
// from the given CSS Weight, how many steps do we need to take in Apple Weights
|
||||||
|
// to get to the next CSS weight
|
||||||
|
static const int AppleWeightStepsToNextCSSWeight[] = {
|
||||||
|
// 0 is invalid
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return PR_TRUE if the candidate font is acceptable for
|
||||||
|
* the given desired traits.
|
||||||
|
*/
|
||||||
|
static PRBool
|
||||||
|
acceptableChoice (NSFontTraitMask desiredTraits, int desiredWeight,
|
||||||
|
NSFontTraitMask candidateTraits, int candidateWeight)
|
||||||
|
{
|
||||||
|
// remove the traits we can synthesize, and compare the others
|
||||||
|
desiredTraits &= ~SYNTHESIZED_FONT_TRAITS;
|
||||||
|
return (candidateTraits & desiredTraits) == desiredTraits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return PR_TRUE if the candidate font is better than the chosen font,
|
||||||
|
* for the given desired traits
|
||||||
|
*/
|
||||||
|
static PRBool
|
||||||
|
betterChoice(NSFontTraitMask desiredTraits, int desiredWeight,
|
||||||
|
NSFontTraitMask chosenTraits, int chosenWeight,
|
||||||
|
NSFontTraitMask candidateTraits, int candidateWeight)
|
||||||
|
{
|
||||||
|
if (!acceptableChoice(desiredTraits, desiredWeight, candidateTraits, candidateWeight))
|
||||||
|
return PR_FALSE;
|
||||||
|
|
||||||
|
// A list of the traits we care about.
|
||||||
|
// The top item in the list is the worst trait to mismatch; if a font has this
|
||||||
|
// and we didn't ask for it, we'd prefer any other font in the family.
|
||||||
|
const NSFontTraitMask masks[] = {
|
||||||
|
NSPosterFontMask,
|
||||||
|
NSSmallCapsFontMask,
|
||||||
|
NSItalicFontMask,
|
||||||
|
NSCompressedFontMask,
|
||||||
|
NSCondensedFontMask,
|
||||||
|
NSExpandedFontMask,
|
||||||
|
NSNarrowFontMask,
|
||||||
|
NSBoldFontMask,
|
||||||
|
0 };
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
NSFontTraitMask mask;
|
||||||
|
while ((mask = masks[i++])) {
|
||||||
|
BOOL desired = (desiredTraits & mask) != 0;
|
||||||
|
BOOL chosenHasUnwantedTrait = (desired != ((chosenTraits & mask) != 0));
|
||||||
|
BOOL candidateHasUnwantedTrait = (desired != ((candidateTraits & mask) != 0));
|
||||||
|
if (!candidateHasUnwantedTrait && chosenHasUnwantedTrait)
|
||||||
|
return PR_TRUE;
|
||||||
|
if (!chosenHasUnwantedTrait && candidateHasUnwantedTrait)
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int chosenWeightDelta = chosenWeight - desiredWeight;
|
||||||
|
int candidateWeightDelta = candidateWeight - desiredWeight;
|
||||||
|
|
||||||
|
int chosenWeightDeltaMagnitude = ABS(chosenWeightDelta);
|
||||||
|
int candidateWeightDeltaMagnitude = ABS(candidateWeightDelta);
|
||||||
|
|
||||||
|
// Smaller magnitude wins.
|
||||||
|
// If both have same magnitude, tie breaker is that the smaller weight wins.
|
||||||
|
// Otherwise, first font in the array wins (should almost never happen).
|
||||||
|
if (candidateWeightDeltaMagnitude < chosenWeightDeltaMagnitude)
|
||||||
|
return PR_TRUE;
|
||||||
|
|
||||||
|
if (candidateWeightDeltaMagnitude == chosenWeightDeltaMagnitude && candidateWeight < chosenWeight)
|
||||||
|
return PR_TRUE;
|
||||||
|
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSFont*
|
||||||
|
FindFontWeight (NSFontManager *fontManager, NSFont *font, int desiredWeight, int weightSteps, float size)
|
||||||
|
{
|
||||||
|
NSFont *newFont;
|
||||||
|
|
||||||
|
int currentWeight = [fontManager weightOfFont:font];
|
||||||
|
if (currentWeight != desiredWeight) {
|
||||||
|
//fprintf (stderr, "desiredWeight: %d currentWeight: %d\n", desiredWeight, currentWeight);
|
||||||
|
newFont = [fontManager fontWithFamily:[font familyName] traits:[fontManager traitsOfFont:font] weight:desiredWeight size:size];
|
||||||
|
if (newFont) {
|
||||||
|
font = newFont;
|
||||||
|
currentWeight = [fontManager weightOfFont:font];
|
||||||
|
//fprintf (stderr, "picked new font, weight: %d\n", currentWeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weightSteps == 0) {
|
||||||
|
return font;
|
||||||
|
} else if (weightSteps < 0) {
|
||||||
|
while (weightSteps != 0) {
|
||||||
|
newFont = [fontManager convertWeight:NO ofFont:font];
|
||||||
|
if (newFont == font)
|
||||||
|
return font;
|
||||||
|
font = newFont;
|
||||||
|
weightSteps++;
|
||||||
|
}
|
||||||
|
} else if (weightSteps > 0) {
|
||||||
|
while (weightSteps != 0) {
|
||||||
|
newFont = [fontManager convertWeight:YES ofFont:font];
|
||||||
|
if (newFont == font)
|
||||||
|
return font;
|
||||||
|
font = newFont;
|
||||||
|
weightSteps--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
ATSUFontID
|
||||||
|
gfxQuartzFontCache::FindATSUFontIDForFamilyAndStyle (const nsAString& aFamily,
|
||||||
|
const gfxFontStyle *aStyle)
|
||||||
|
{
|
||||||
|
NSString *desiredFamily = [NSString stringWithCharacters:aFamily.BeginReading() length:aFamily.Length()];
|
||||||
|
NSFontTraitMask desiredTraits = 0;
|
||||||
|
int desiredWeight;
|
||||||
|
PRInt16 baseCSSWeight, weightOffset;
|
||||||
|
|
||||||
|
//printf ("FindATSUFontIDForFamilyAndStyle: %s\n", [desiredFamily cString]);
|
||||||
|
|
||||||
|
aStyle->ComputeWeightAndOffset(&baseCSSWeight, &weightOffset);
|
||||||
|
desiredWeight = CSSWeightToAppleWeight[PR_MIN(PR_MAX(baseCSSWeight, 1), 9)];
|
||||||
|
|
||||||
|
// Oblique should really be synthesized italic; fix that later.
|
||||||
|
if (aStyle->style & FONT_STYLE_ITALIC || aStyle->style & FONT_STYLE_OBLIQUE)
|
||||||
|
desiredTraits |= NSItalicFontMask;
|
||||||
|
|
||||||
|
// we should really do the right thing with the offsets here, but that's harder.
|
||||||
|
if (desiredWeight >= APPLE_BOLD_WEIGHT)
|
||||||
|
desiredTraits |= NSBoldFontMask;
|
||||||
|
|
||||||
|
NSFontManager *fontManager = [NSFontManager sharedFontManager];
|
||||||
|
NSFont *font = nsnull;
|
||||||
|
|
||||||
|
// Look for an exact match first.
|
||||||
|
NSEnumerator *availableFonts = [[fontManager availableFonts] objectEnumerator];
|
||||||
|
NSString *availableFont;
|
||||||
|
while ((availableFont = [availableFonts nextObject])) {
|
||||||
|
if ([desiredFamily caseInsensitiveCompare:availableFont] == NSOrderedSame) {
|
||||||
|
NSFont *nameMatchedFont = [NSFont fontWithName:availableFont size:aStyle->size];
|
||||||
|
NSFontTraitMask traits = [fontManager traitsOfFont:nameMatchedFont];
|
||||||
|
|
||||||
|
if ((traits & desiredTraits) == desiredTraits) {
|
||||||
|
font = [fontManager convertFont:nameMatchedFont toHaveTrait:desiredTraits];
|
||||||
|
font = FindFontWeight (fontManager, font, desiredWeight, weightOffset, aStyle->size);
|
||||||
|
//fprintf (stderr, "Exact match found; weight: %d\n", [fontManager weightOfFont:font]);
|
||||||
|
return [font _atsFontID];
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do a simple case insensitive search for a matching font family.
|
||||||
|
// NSFontManager requires exact name matches.
|
||||||
|
// This addresses the problem of matching arial to Arial, etc., but perhaps not all the issues.
|
||||||
|
NSEnumerator *e = [[fontManager availableFontFamilies] objectEnumerator];
|
||||||
|
NSString *availableFamily;
|
||||||
|
while ((availableFamily = [e nextObject])) {
|
||||||
|
if ([desiredFamily caseInsensitiveCompare:availableFamily] == NSOrderedSame) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we can't find a match for this at all, then bail
|
||||||
|
if (availableFamily == nsnull)
|
||||||
|
return kATSUInvalidFontID;
|
||||||
|
|
||||||
|
// Found a family, now figure out what weight and traits to use.
|
||||||
|
BOOL choseFont = false;
|
||||||
|
int chosenWeight = 0;
|
||||||
|
NSFontTraitMask chosenTraits = 0;
|
||||||
|
|
||||||
|
NSArray *fonts = [fontManager availableMembersOfFontFamily:availableFamily];
|
||||||
|
unsigned n = [fonts count];
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
NSArray *fontInfo = [fonts objectAtIndex:i];
|
||||||
|
|
||||||
|
// Array indices must be hard coded because of lame AppKit API.
|
||||||
|
int fontWeight = [[fontInfo objectAtIndex:INDEX_FONT_WEIGHT] intValue];
|
||||||
|
NSFontTraitMask fontTraits = [[fontInfo objectAtIndex:INDEX_FONT_TRAITS] unsignedIntValue];
|
||||||
|
|
||||||
|
BOOL newWinner;
|
||||||
|
if (!choseFont)
|
||||||
|
newWinner = acceptableChoice(desiredTraits, desiredWeight, fontTraits, fontWeight);
|
||||||
|
else
|
||||||
|
newWinner = betterChoice(desiredTraits, desiredWeight, chosenTraits, chosenWeight, fontTraits, fontWeight);
|
||||||
|
|
||||||
|
if (newWinner) {
|
||||||
|
choseFont = YES;
|
||||||
|
chosenWeight = fontWeight;
|
||||||
|
chosenTraits = fontTraits;
|
||||||
|
|
||||||
|
if (chosenWeight == desiredWeight &&
|
||||||
|
(chosenTraits & IMPORTANT_FONT_TRAITS) == (desiredTraits & IMPORTANT_FONT_TRAITS))
|
||||||
|
{
|
||||||
|
// this one is good enough; don't bother looking for something better
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we couldn't find anything that was valid in the family
|
||||||
|
if (!choseFont)
|
||||||
|
return kATSUInvalidFontID;
|
||||||
|
|
||||||
|
// grab the actual font
|
||||||
|
font = [fontManager fontWithFamily:availableFamily traits:chosenTraits weight:chosenWeight size:aStyle->size];
|
||||||
|
if (!font)
|
||||||
|
return kATSUInvalidFontID;
|
||||||
|
|
||||||
|
//fprintf (stderr, "No exact match found; basic match weight: %d\n", [fontManager weightOfFont:font]);
|
||||||
|
font = FindFontWeight (fontManager, font, desiredWeight, weightOffset, aStyle->size);
|
||||||
|
//fprintf (stderr, " after FindFontWeight: %d\n", [fontManager weightOfFont:font]);
|
||||||
|
chosenWeight = [fontManager weightOfFont:font];
|
||||||
|
|
||||||
|
// Figure out whether we need to synthesize
|
||||||
|
NSFontTraitMask actualTraits = 0;
|
||||||
|
if (desiredTraits & (NSItalicFontMask | NSBoldFontMask))
|
||||||
|
actualTraits = [fontManager traitsOfFont:font];
|
||||||
|
|
||||||
|
bool syntheticBold = (baseCSSWeight >= CSS_BOLD_WEIGHT_BASE && weightOffset <= 0) && (chosenWeight < APPLE_BOLD_WEIGHT);
|
||||||
|
bool syntheticOblique = (desiredTraits & NSItalicFontMask) && !(actualTraits & NSItalicFontMask);
|
||||||
|
|
||||||
|
// There are some malformed fonts that will be correctly returned
|
||||||
|
// by -fontWithFamily:traits:weight:size: as a match for a
|
||||||
|
// particular trait, though -[NSFontManager traitsOfFont:]
|
||||||
|
// incorrectly claims the font does not have the specified
|
||||||
|
// trait. This could result in applying synthetic bold on top of
|
||||||
|
// an already-bold font, as reported in
|
||||||
|
// <http://bugzilla.opendarwin.org/show_bug.cgi?id=6146>. To work
|
||||||
|
// around this problem, if we got an apparent exact match, but the
|
||||||
|
// requested traits aren't present in the matched font, we'll try
|
||||||
|
// to get a font from the same family without those traits (to
|
||||||
|
// apply the synthetic traits to later).
|
||||||
|
NSFontTraitMask nonSyntheticTraits = desiredTraits;
|
||||||
|
|
||||||
|
if (syntheticBold)
|
||||||
|
nonSyntheticTraits &= ~NSBoldFontMask;
|
||||||
|
|
||||||
|
if (syntheticOblique)
|
||||||
|
nonSyntheticTraits &= ~NSItalicFontMask;
|
||||||
|
|
||||||
|
if (nonSyntheticTraits != desiredTraits) {
|
||||||
|
NSFont *fontWithoutSyntheticTraits = [fontManager fontWithFamily:availableFamily traits:nonSyntheticTraits weight:chosenWeight size:aStyle->size];
|
||||||
|
if (fontWithoutSyntheticTraits)
|
||||||
|
font = fontWithoutSyntheticTraits;
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf ("Font: %s -> %d\n", [availableFamily cString], GetNSFontATSUFontId(font));
|
||||||
|
return [font _atsFontID];
|
||||||
|
}
|
||||||
|
|
||||||
|
ATSUFontID
|
||||||
|
gfxQuartzFontCache::GetDefaultATSUFontID (const gfxFontStyle* aStyle)
|
||||||
|
{
|
||||||
|
return [[NSFont userFontOfSize:aStyle->size] _atsFontID];
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче