Bug 505284 - bottom of fonts cut off in dialogs. r=karlt

This commit is contained in:
Takuro Ashie 2009-10-30 16:13:41 -07:00
Родитель 3913d8cc7a
Коммит 3327ced111
9 изменённых файлов: 811 добавлений и 776 удалений

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

@ -43,6 +43,7 @@ EXPORTS += gfxPDFSurface.h
ifdef WINCE
EXPORTS += gfxFT2Fonts.h \
gfxFT2FontBase.h \
gfxDDrawSurface.h \
$(NULL)
else
@ -67,8 +68,9 @@ ifdef MOZ_DFB
EXPORTS += gfxDirectFBSurface.h
endif
EXPORTS += gfxPlatformGtk.h gfxGdkNativeRenderer.h
EXPORTS += gfxPDFSurface.h gfxPSSurface.h
EXPORTS += gfxPlatformGtk.h gfxGdkNativeRenderer.h
EXPORTS += gfxPDFSurface.h gfxPSSurface.h
EXPORTS += gfxFT2FontBase.h
endif
@ -76,6 +78,7 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),qt)
EXPORTS += gfxQtPlatform.h gfxQPainterSurface.h
EXPORTS += gfxXlibSurface.h gfxQtNativeRenderer.h
EXPORTS += gfxFT2Fonts.h
EXPORTS += gfxFT2FontBase.h
endif
ifeq ($(MOZ_WIDGET_TOOLKIT),os2)
@ -89,6 +92,7 @@ endif
ifeq ($(MOZ_WIDGET_TOOLKIT),beos)
EXPORTS += gfxBeOSSurface.h gfxBeOSPlatform.h
EXPORTS += gfxPangoFonts.h
EXPORTS += gfxFT2FontBase.h
EXPORTS += gfxPDFSurface.h
endif

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

@ -0,0 +1,74 @@
/* -*- 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 Foundation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@mozilla.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* Behdad Esfahbod <behdad@gnome.org>
* Mats Palmgren <mats.palmgren@bredband.net>
* Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
* Takuro Ashie <ashie@clear-code.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_FT2FONTBASE_H
#define GFX_FT2FONTBASE_H
#include "cairo.h"
#include "gfxContext.h"
#include "gfxFont.h"
class gfxFT2FontBase : public gfxFont {
public:
gfxFT2FontBase(cairo_scaled_font_t *aScaledFont,
gfxFontEntry *aFontEntry,
const gfxFontStyle *aFontStyle);
virtual ~gfxFT2FontBase();
PRUint32 GetGlyph(PRUint32 aCharCode);
void GetGlyphExtents(PRUint32 aGlyph,
cairo_text_extents_t* aExtents);
virtual const gfxFont::Metrics& GetMetrics();
virtual nsString GetUniqueName();
virtual PRUint32 GetSpaceGlyph();
cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; };
virtual PRBool SetupCairoFont(gfxContext *aContext);
protected:
cairo_scaled_font_t *mScaledFont;
PRUint32 mSpaceGlyph;
PRBool mHasMetrics;
Metrics mMetrics;
};
#endif /* GFX_FT2FONTBASE_H */

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

@ -36,12 +36,13 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef GFX_GTKDFBFONTS_H
#define GFX_GTKDFBFONTS_H
#ifndef GFX_FT2FONTS_H
#define GFX_FT2FONTS_H
#include "cairo.h"
#include "gfxTypes.h"
#include "gfxFont.h"
#include "gfxFT2FontBase.h"
#include "gfxContext.h"
#include "gfxFontUtils.h"
#include "gfxUserFontSet.h"
@ -106,21 +107,14 @@ public:
};
class gfxFT2Font : public gfxFont {
class gfxFT2Font : public gfxFT2FontBase {
public: // new functions
gfxFT2Font(FontEntry *aFontEntry,
gfxFT2Font(cairo_scaled_font_t *aCairoFont,
FontEntry *aFontEntry,
const gfxFontStyle *aFontStyle);
virtual ~gfxFT2Font ();
virtual const gfxFont::Metrics& GetMetrics();
cairo_font_face_t *CairoFontFace();
cairo_scaled_font_t *CairoScaledFont();
virtual PRBool SetupCairoFont(gfxContext *aContext);
virtual nsString GetUniqueName();
virtual PRUint32 GetSpaceGlyph();
FontEntry *GetFontEntry();
@ -156,27 +150,7 @@ public: // new functions
return &entry->mData;
}
class FaceLock {
public:
FaceLock(gfxFT2Font *font);
~FaceLock();
FT_Face Face() { return mFace; }
protected:
cairo_scaled_font_t *mScaledFont;
FT_Face mFace;
};
protected:
cairo_scaled_font_t *mScaledFont;
PRBool mHasSpaceGlyph;
PRUint32 mSpaceGlyph;
PRBool mHasMetrics;
Metrics mMetrics;
gfxFloat mAdjustedSize;
void FillGlyphDataForChar(PRUint32 ch, CachedGlyphData *gd);
typedef nsBaseHashtableET<nsUint32HashKey, CachedGlyphData> CharGlyphMapEntryType;
@ -244,5 +218,5 @@ protected: // new functions
nsString mString;
};
#endif /* GFX_GTKDFBFONTS_H */
#endif /* GFX_FT2FONTS_H */

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

@ -53,6 +53,8 @@ CPPSRCS += gfxWindowsPlatform.cpp \
ifdef WINCE
CPPSRCS += gfxFT2Fonts.cpp \
gfxFT2FontBase.cpp \
gfxFT2Utils.cpp \
gfxDDrawSurface.cpp \
$(NULL)
EXTRA_DSO_LDOPTS += ddraw.lib
@ -96,6 +98,8 @@ endif
CPPSRCS += gfxPlatformGtk.cpp gfxGdkNativeRenderer.cpp
CPPSRCS += gfxPDFSurface.cpp gfxPSSurface.cpp
CPPSRCS += gfxFontconfigUtils.cpp
CPPSRCS += gfxFT2FontBase.cpp
CPPSRCS += gfxFT2Utils.cpp
CPPSRCS += nsUnicodeRange.cpp
ifdef MOZ_X11
@ -117,6 +121,8 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),qt)
CPPSRCS += gfxQtPlatform.cpp gfxQPainterSurface.cpp
CPPSRCS += gfxXlibSurface.cpp gfxQtNativeRenderer.cpp
CPPSRCS += gfxFT2Fonts.cpp
CPPSRCS += gfxFT2FontBase.cpp
CPPSRCS += gfxFT2Utils.cpp
CPPSRCS += gfxFontconfigUtils.cpp
CPPSRCS += nsUnicodeRange.cpp
#CSRCS = cairo-xlib-utils.c
@ -126,6 +132,8 @@ endif
ifeq ($(MOZ_WIDGET_TOOLKIT),beos)
CPPSRCS += gfxBeOSSurface.cpp gfxBeOSPlatform.cpp
CPPSRCS += gfxPangoFonts.cpp
CPPSRCS += gfxFT2FontBase.cpp
CPPSRCS += gfxFT2Utils.cpp
#CPPSRCS += gfxPDFSurface.cpp
CPPSRCS += gfxFontconfigUtils.cpp
CPPSRCS += nsUnicodeRange.cpp

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

@ -0,0 +1,227 @@
/* -*- 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 Foundation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@mozilla.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* Behdad Esfahbod <behdad@gnome.org>
* Mats Palmgren <mats.palmgren@bredband.net>
* Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
* Takuro Ashie <ashie@clear-code.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 "gfxFT2FontBase.h"
#include "gfxFT2Utils.h"
gfxFT2FontBase::gfxFT2FontBase(cairo_scaled_font_t *aScaledFont,
gfxFontEntry *aFontEntry,
const gfxFontStyle *aFontStyle)
: gfxFont(aFontEntry, aFontStyle),
mScaledFont(aScaledFont),
mSpaceGlyph(0),
mHasMetrics(PR_FALSE)
{
cairo_scaled_font_reference(mScaledFont);
}
gfxFT2FontBase::~gfxFT2FontBase()
{
cairo_scaled_font_destroy(mScaledFont);
}
PRUint32
gfxFT2FontBase::GetGlyph(PRUint32 aCharCode)
{
// FcFreeTypeCharIndex needs to lock the FT_Face and can end up searching
// through all the postscript glyph names in the font. Therefore use a
// lightweight cache, which is stored on the cairo_font_face_t.
cairo_font_face_t *face =
cairo_scaled_font_get_font_face(CairoScaledFont());
if (cairo_font_face_status(face) != CAIRO_STATUS_SUCCESS)
return 0;
// This cache algorithm and size is based on what is done in
// cairo_scaled_font_text_to_glyphs and pango_fc_font_real_get_glyph. I
// think the concept is that adjacent characters probably come mostly from
// one Unicode block. This assumption is probably not so valid with
// scripts with large character sets as used for East Asian languages.
struct CmapCacheSlot {
PRUint32 mCharCode;
PRUint32 mGlyphIndex;
};
const PRUint32 kNumSlots = 256;
static cairo_user_data_key_t sCmapCacheKey;
CmapCacheSlot *slots = static_cast<CmapCacheSlot*>
(cairo_font_face_get_user_data(face, &sCmapCacheKey));
if (!slots) {
// cairo's caches can keep some cairo_font_faces alive past our last
// destroy, so the destroy function (free) for the cache must be
// callable from cairo without any assumptions about what other
// modules have not been shutdown.
slots = static_cast<CmapCacheSlot*>
(calloc(kNumSlots, sizeof(CmapCacheSlot)));
if (!slots)
return 0;
cairo_status_t status =
cairo_font_face_set_user_data(face, &sCmapCacheKey, slots, free);
if (status != CAIRO_STATUS_SUCCESS) { // OOM
free(slots);
return 0;
}
// Invalidate slot 0 by setting its char code to something that would
// never end up in slot 0. All other slots are already invalid
// because they have mCharCode = 0 and a glyph for char code 0 will
// always be in the slot 0.
slots[0].mCharCode = 1;
}
CmapCacheSlot *slot = &slots[aCharCode % kNumSlots];
if (slot->mCharCode != aCharCode) {
slot->mCharCode = aCharCode;
slot->mGlyphIndex = gfxFT2LockedFace(this).GetGlyph(aCharCode);
}
return slot->mGlyphIndex;
}
void
gfxFT2FontBase::GetGlyphExtents(PRUint32 aGlyph, cairo_text_extents_t* aExtents)
{
NS_PRECONDITION(aExtents != NULL, "aExtents must not be NULL");
cairo_glyph_t glyphs[1];
glyphs[0].index = aGlyph;
glyphs[0].x = 0.0;
glyphs[0].y = 0.0;
// cairo does some caching for us here but perhaps a small gain could be
// made by caching more. It is usually only the advance that is needed,
// so caching only the advance could allow many requests to be cached with
// little memory use. Ideally this cache would be merged with
// gfxGlyphExtents.
cairo_scaled_font_glyph_extents(CairoScaledFont(), glyphs, 1, aExtents);
}
const gfxFont::Metrics&
gfxFT2FontBase::GetMetrics()
{
if (mHasMetrics)
return mMetrics;
if (NS_UNLIKELY(GetStyle()->size <= 0.0)) {
new(&mMetrics) gfxFont::Metrics(); // zero initialize
mSpaceGlyph = 0;
} else {
gfxFT2LockedFace(this).GetMetrics(&mMetrics, &mSpaceGlyph);
}
SanitizeMetrics(&mMetrics, PR_FALSE);
#if 0
// printf("font name: %s %f\n", NS_ConvertUTF16toUTF8(GetName()).get(), GetStyle()->size);
// printf ("pango font %s\n", pango_font_description_to_string (pango_font_describe (font)));
fprintf (stderr, "Font: %s\n", NS_ConvertUTF16toUTF8(GetName()).get());
fprintf (stderr, " emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
fprintf (stderr, " maxAscent: %f maxDescent: %f\n", mMetrics.maxAscent, mMetrics.maxDescent);
fprintf (stderr, " internalLeading: %f externalLeading: %f\n", mMetrics.externalLeading, mMetrics.internalLeading);
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
mHasMetrics = PR_TRUE;
return mMetrics;
}
nsString
gfxFT2FontBase::GetUniqueName()
{
return GetName();
}
// Get the glyphID of a space
PRUint32
gfxFT2FontBase::GetSpaceGlyph()
{
NS_ASSERTION(GetStyle()->size != 0,
"forgot to short-circuit a text run with zero-sized font?");
GetMetrics();
return mSpaceGlyph;
}
PRBool
gfxFT2FontBase::SetupCairoFont(gfxContext *aContext)
{
cairo_t *cr = aContext->GetCairo();
// The scaled font ctm is not relevant right here because
// cairo_set_scaled_font does not record the scaled font itself, but
// merely the font_face, font_matrix, font_options. The scaled_font used
// for the target can be different from the scaled_font passed to
// cairo_set_scaled_font. (Unfortunately we have measured only for an
// identity ctm.)
cairo_scaled_font_t *cairoFont = CairoScaledFont();
if (cairo_scaled_font_status(cairoFont) != 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;
}
// Thoughts on which font_options to set on the context:
//
// cairoFont has been created for screen rendering.
//
// When the context is being used for screen rendering, we should set
// font_options such that the same scaled_font gets used (when the ctm is
// the same). The use of explicit font_options recorded in
// CreateScaledFont ensures that this will happen.
//
// XXXkt: For pdf and ps surfaces, I don't know whether it's better to
// remove surface-specific options, or try to draw with the same
// scaled_font that was used to measure. As the same font_face is being
// used, its font_options will often override some values anyway (unless
// perhaps we remove those from the FcPattern at face creation).
//
// I can't see any significant difference in printing, irrespective of
// what is set here. It's too late to change things here as measuring has
// already taken place. We should really be measuring with a different
// font for pdf and ps surfaces (bug 403513).
cairo_set_scaled_font(cr, cairoFont);
return PR_TRUE;
}

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

@ -50,6 +50,8 @@
#endif
#include "gfxTypes.h"
#include "gfxFT2Fonts.h"
#include "gfxFT2FontBase.h"
#include "gfxFT2Utils.h"
#include <locale.h>
#include "cairo-ft.h"
#include FT_TRUETYPE_TAGS_H
@ -711,8 +713,8 @@ gfxFT2FontGroup::AddRange(gfxTextRun *aTextRun, gfxFT2Font *font, const PRUnicha
{
const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
// we'll pass this in/figure it out dynamically, but at this point there can be only one face.
gfxFT2Font::FaceLock faceLock(font);
FT_Face face = faceLock.Face();
gfxFT2LockedFace faceLock(font);
FT_Face face = faceLock.get();
gfxTextRun::CompressedGlyph g;
@ -803,33 +805,14 @@ gfxFT2FontGroup::AddRange(gfxTextRun *aTextRun, gfxFT2Font *font, const PRUnicha
}
}
/*
* Stack-based face lock helper
*/
gfxFT2Font::FaceLock::FaceLock(gfxFT2Font *font)
{
mScaledFont = font->CairoScaledFont();
mFace = cairo_ft_scaled_font_lock_face(mScaledFont);
}
gfxFT2Font::FaceLock::~FaceLock()
{
cairo_ft_scaled_font_unlock_face(mScaledFont);
}
/**
* gfxFT2Font
*/
gfxFT2Font::gfxFT2Font(FontEntry *aFontEntry,
const gfxFontStyle *aFontStyle)
: gfxFont(aFontEntry, aFontStyle),
mScaledFont(nsnull),
mHasSpaceGlyph(PR_FALSE),
mSpaceGlyph(0),
mHasMetrics(PR_FALSE),
mAdjustedSize(0)
gfxFT2Font::gfxFT2Font(cairo_scaled_font_t *aCairoFont,
FontEntry *aFontEntry,
const gfxFontStyle *aFontStyle)
: gfxFT2FontBase(aCairoFont, aFontEntry, aFontStyle)
{
mFontEntry = aFontEntry;
NS_ASSERTION(mFontEntry, "Unable to find font entry for font. Something is whack.");
mCharGlyphCache.Init(64);
@ -837,155 +820,6 @@ gfxFT2Font::gfxFT2Font(FontEntry *aFontEntry,
gfxFT2Font::~gfxFT2Font()
{
if (mScaledFont) {
cairo_scaled_font_destroy(mScaledFont);
mScaledFont = nsnull;
}
}
const gfxFont::Metrics&
gfxFT2Font::GetMetrics()
{
if (mHasMetrics)
return mMetrics;
mMetrics.emHeight = GetStyle()->size;
gfxFT2Font::FaceLock faceLock(this);
FT_Face face = faceLock.Face();
if (!face) {
// Abort here already, otherwise we crash in the following
// this can happen if the font-size requested is zero.
// The metrics will be incomplete, but then we don't care.
return mMetrics;
}
mMetrics.emHeight = GetStyle()->size;
FT_UInt gid; // glyph ID
const double emUnit = 1.0 * face->units_per_EM;
const double xScale = face->size->metrics.x_ppem / emUnit;
const double yScale = face->size->metrics.y_ppem / emUnit;
// cache properties of space
GetSpaceGlyph();
// properties of 'x', also use its width as average width
gid = FT_Get_Char_Index(face, 'x'); // select the glyph
if (gid) {
// Load glyph into glyph slot. Here, use no_scale to get font units.
FT_Load_Glyph(face, gid, FT_LOAD_NO_SCALE);
mMetrics.xHeight = face->glyph->metrics.height * yScale;
mMetrics.aveCharWidth = face->glyph->metrics.width * xScale;
} else {
// this font doesn't have an 'x'...
// fake these metrics using a fraction of the font size
mMetrics.xHeight = mMetrics.emHeight * 0.5;
mMetrics.aveCharWidth = mMetrics.emHeight * 0.5;
}
// compute an adjusted size if we need to
if (mAdjustedSize == 0 && GetStyle()->sizeAdjust != 0) {
gfxFloat aspect = mMetrics.xHeight / GetStyle()->size;
mAdjustedSize = GetStyle()->GetAdjustedSize(aspect);
mMetrics.emHeight = mAdjustedSize;
}
// now load the OS/2 TrueType table to load access some more properties
TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
if (os2 && os2->version != 0xFFFF) { // should be there if not old Mac font
// if we are here we can improve the avgCharWidth
mMetrics.aveCharWidth = os2->xAvgCharWidth * xScale;
mMetrics.superscriptOffset = os2->ySuperscriptYOffset * yScale;
mMetrics.superscriptOffset = PR_MAX(1, mMetrics.superscriptOffset);
// some fonts have the incorrect sign (from gfxPangoFonts)
mMetrics.subscriptOffset = fabs(os2->ySubscriptYOffset * yScale);
mMetrics.subscriptOffset = PR_MAX(1, fabs(mMetrics.subscriptOffset));
mMetrics.strikeoutOffset = os2->yStrikeoutPosition * yScale;
mMetrics.strikeoutSize = os2->yStrikeoutSize * yScale;
} else {
// use fractions of emHeight instead of xHeight for these to be more robust
mMetrics.superscriptOffset = mMetrics.emHeight * 0.5;
mMetrics.subscriptOffset = mMetrics.emHeight * 0.2;
mMetrics.strikeoutOffset = mMetrics.emHeight * 0.3;
mMetrics.strikeoutSize = face->underline_thickness * yScale;
}
// seems that underlineOffset really has to be negative
mMetrics.underlineOffset = face->underline_position * yScale;
mMetrics.underlineSize = face->underline_thickness * yScale;
// descents are negative in FT but Thebes wants them positive
mMetrics.emAscent = face->ascender * yScale;
mMetrics.emDescent = -face->descender * yScale;
mMetrics.maxHeight = face->height * yScale;
mMetrics.maxAscent = face->bbox.yMax * yScale;
mMetrics.maxDescent = -face->bbox.yMin * yScale;
mMetrics.maxAdvance = face->max_advance_width * xScale;
// leading are not available directly (only for WinFNTs)
double lineHeight = mMetrics.maxAscent + mMetrics.maxDescent;
if (lineHeight > mMetrics.emHeight) {
mMetrics.internalLeading = lineHeight - mMetrics.emHeight;
} else {
mMetrics.internalLeading = 0;
}
mMetrics.externalLeading = 0; // normal value for OS/2 fonts, too
SanitizeMetrics(&mMetrics, PR_FALSE);
/*
printf("gfxOS2Font[%#x]::GetMetrics():\n"
" emHeight=%f == %f=gfxFont::style.size == %f=adjSz\n"
" maxHeight=%f xHeight=%f\n"
" aveCharWidth=%f==xWidth spaceWidth=%f\n"
" supOff=%f SubOff=%f strOff=%f strSz=%f\n"
" undOff=%f undSz=%f intLead=%f extLead=%f\n"
" emAsc=%f emDesc=%f maxH=%f\n"
" maxAsc=%f maxDes=%f maxAdv=%f\n",
(unsigned)this,
mMetrics.emHeight, GetStyle()->size, mAdjustedSize,
mMetrics.maxHeight, mMetrics.xHeight,
mMetrics.aveCharWidth, mMetrics.spaceWidth,
mMetrics.superscriptOffset, mMetrics.subscriptOffset,
mMetrics.strikeoutOffset, mMetrics.strikeoutSize,
mMetrics.underlineOffset, mMetrics.underlineSize,
mMetrics.internalLeading, mMetrics.externalLeading,
mMetrics.emAscent, mMetrics.emDescent, mMetrics.maxHeight,
mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance
);
*/
// XXX mMetrics.height needs to be set.
mHasMetrics = PR_TRUE;
return mMetrics;
}
nsString
gfxFT2Font::GetUniqueName()
{
return GetName();
}
PRUint32
gfxFT2Font::GetSpaceGlyph()
{
NS_ASSERTION (GetStyle()->size != 0, "forgot to short-circuit a text run with zero-sized font?");
if (!mHasSpaceGlyph) {
const CachedGlyphData *gdata = GetGlyphDataForChar(' ');
mSpaceGlyph = gdata->glyphIndex;
NS_ASSERTION(mSpaceGlyph != 0, "Font has no space glyph!");
mMetrics.spaceWidth = MOZ_FT_TRUNC(gdata->xAdvance);
mHasSpaceGlyph = PR_TRUE;
}
return mSpaceGlyph;
}
cairo_font_face_t *
@ -998,59 +832,45 @@ gfxFT2Font::CairoFontFace()
return GetFontEntry()->CairoFontFace();
}
cairo_scaled_font_t *
gfxFT2Font::CairoScaledFont()
static cairo_scaled_font_t *
CreateScaledFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle)
{
if (!mScaledFont) {
cairo_matrix_t sizeMatrix;
cairo_matrix_t identityMatrix;
cairo_scaled_font_t *scaledFont = NULL;
// XXX deal with adjusted size
cairo_matrix_init_scale(&sizeMatrix, mStyle.size, mStyle.size);
cairo_matrix_init_identity(&identityMatrix);
cairo_matrix_t sizeMatrix;
cairo_matrix_t identityMatrix;
// synthetic oblique by skewing via the font matrix
PRBool needsOblique = (!mFontEntry->mItalic && (mStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)));
// XXX deal with adjusted size
cairo_matrix_init_scale(&sizeMatrix, aStyle->size, aStyle->size);
cairo_matrix_init_identity(&identityMatrix);
if (needsOblique) {
const double kSkewFactor = 0.25;
// synthetic oblique by skewing via the font matrix
PRBool needsOblique = (!aFontEntry->mItalic && (aStyle->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)));
cairo_matrix_t style;
cairo_matrix_init(&style,
1, //xx
0, //yx
-1 * kSkewFactor, //xy
1, //yy
0, //x0
0); //y0
cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
}
if (needsOblique) {
const double kSkewFactor = 0.25;
cairo_font_options_t *fontOptions = cairo_font_options_create();
mScaledFont = cairo_scaled_font_create(CairoFontFace(), &sizeMatrix,
&identityMatrix, fontOptions);
cairo_font_options_destroy(fontOptions);
cairo_matrix_t style;
cairo_matrix_init(&style,
1, //xx
0, //yx
-1 * kSkewFactor, //xy
1, //yy
0, //x0
0); //y0
cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
}
NS_ASSERTION(mAdjustedSize == 0.0 ||
cairo_scaled_font_status(mScaledFont) == CAIRO_STATUS_SUCCESS,
cairo_font_options_t *fontOptions = cairo_font_options_create();
scaledFont = cairo_scaled_font_create(aFontEntry->CairoFontFace(),
&sizeMatrix,
&identityMatrix, fontOptions);
cairo_font_options_destroy(fontOptions);
NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS,
"Failed to make scaled font");
return mScaledFont;
}
PRBool
gfxFT2Font::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;
return scaledFont;
}
/**
@ -1076,7 +896,9 @@ gfxFT2Font::GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle)
{
nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(aFontEntry->Name(), aStyle);
if (!font) {
font = new gfxFT2Font(aFontEntry, aStyle);
cairo_scaled_font_t *scaledFont = CreateScaledFont(aFontEntry, aStyle);
font = new gfxFT2Font(scaledFont, aFontEntry, aStyle);
cairo_scaled_font_destroy(scaledFont);
if (!font)
return nsnull;
gfxFontCache::GetCache()->AddNew(font);
@ -1089,8 +911,8 @@ gfxFT2Font::GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle)
void
gfxFT2Font::FillGlyphDataForChar(PRUint32 ch, CachedGlyphData *gd)
{
gfxFT2Font::FaceLock faceLock(this);
FT_Face face = faceLock.Face();
gfxFT2LockedFace faceLock(this);
FT_Face face = faceLock.get();
FT_UInt gid = FT_Get_Char_Index(face, ch);

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

@ -0,0 +1,321 @@
/* -*- 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 Foundation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@mozilla.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* Behdad Esfahbod <behdad@gnome.org>
* Mats Palmgren <mats.palmgren@bredband.net>
* Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
* Takuro Ashie <ashie@clear-code.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 "gfxFT2FontBase.h"
#include "gfxFT2Utils.h"
#include FT_TRUETYPE_TAGS_H
#include FT_TRUETYPE_TABLES_H
// aScale is intended for a 16.16 x/y_scale of an FT_Size_Metrics
static inline FT_Long
ScaleRoundDesignUnits(FT_Short aDesignMetric, FT_Fixed aScale)
{
FT_Long fixed26dot6 = FT_MulFix(aDesignMetric, aScale);
return ROUND_26_6_TO_INT(fixed26dot6);
}
// Snap a line to pixels while keeping the center and size of the line as
// close to the original position as possible.
//
// Pango does similar snapping for underline and strikethrough when fonts are
// hinted, but nsCSSRendering::GetTextDecorationRectInternal always snaps the
// top and size of lines. Optimizing the distance between the line and
// baseline is probably good for the gap between text and underline, but
// optimizing the center of the line is better for positioning strikethough.
static void
SnapLineToPixels(gfxFloat& aOffset, gfxFloat& aSize)
{
gfxFloat snappedSize = PR_MAX(NS_floor(aSize + 0.5), 1.0);
// Correct offset for change in size
gfxFloat offset = aOffset - 0.5 * (aSize - snappedSize);
// Snap offset
aOffset = NS_floor(offset + 0.5);
aSize = snappedSize;
}
void
gfxFT2LockedFace::GetMetrics(gfxFont::Metrics* aMetrics,
PRUint32* aSpaceGlyph)
{
NS_PRECONDITION(aMetrics != NULL, "aMetrics must not be NULL");
NS_PRECONDITION(aSpaceGlyph != NULL, "aSpaceGlyph must not be NULL");
if (NS_UNLIKELY(!mFace)) {
// No face. This unfortunate situation might happen if the font
// file is (re)moved at the wrong time.
aMetrics->emHeight = mGfxFont->GetStyle()->size;
aMetrics->emAscent = 0.8 * aMetrics->emHeight;
aMetrics->emDescent = 0.2 * aMetrics->emHeight;
aMetrics->maxAscent = aMetrics->emAscent;
aMetrics->maxDescent = aMetrics->maxDescent;
aMetrics->maxHeight = aMetrics->emHeight;
aMetrics->internalLeading = 0.0;
aMetrics->externalLeading = 0.2 * aMetrics->emHeight;
aSpaceGlyph = 0;
aMetrics->spaceWidth = 0.5 * aMetrics->emHeight;
aMetrics->maxAdvance = aMetrics->spaceWidth;
aMetrics->aveCharWidth = aMetrics->spaceWidth;
aMetrics->zeroOrAveCharWidth = aMetrics->spaceWidth;
aMetrics->xHeight = 0.5 * aMetrics->emHeight;
aMetrics->underlineSize = aMetrics->emHeight / 14.0;
aMetrics->underlineOffset = -aMetrics->underlineSize;
aMetrics->strikeoutOffset = 0.25 * aMetrics->emHeight;
aMetrics->strikeoutSize = aMetrics->underlineSize;
aMetrics->superscriptOffset = aMetrics->xHeight;
aMetrics->subscriptOffset = aMetrics->xHeight;
return;
}
const FT_Size_Metrics& ftMetrics = mFace->size->metrics;
gfxFloat emHeight;
// Scale for vertical design metric conversion: pixels per design unit.
gfxFloat yScale;
if (FT_IS_SCALABLE(mFace)) {
// Prefer FT_Size_Metrics::x_scale to x_ppem as x_ppem does not
// have subpixel accuracy.
//
// FT_Size_Metrics::y_scale is in 16.16 fixed point format. Its
// (fractional) value is a factor that converts vertical metrics from
// design units to units of 1/64 pixels, so that the result may be
// interpreted as pixels in 26.6 fixed point format.
yScale = FLOAT_FROM_26_6(FLOAT_FROM_16_16(ftMetrics.y_scale));
emHeight = mFace->units_per_EM * yScale;
} else { // Not scalable.
// FT_Size_Metrics doc says x_scale is "only relevant for scalable
// font formats".
gfxFloat emUnit = mFace->units_per_EM;
emHeight = ftMetrics.y_ppem;
yScale = emHeight / emUnit;
}
TT_OS2 *os2 =
static_cast<TT_OS2*>(FT_Get_Sfnt_Table(mFace, ft_sfnt_os2));
aMetrics->maxAscent = FLOAT_FROM_26_6(ftMetrics.ascender);
aMetrics->maxDescent = -FLOAT_FROM_26_6(ftMetrics.descender);
aMetrics->maxAdvance = FLOAT_FROM_26_6(ftMetrics.max_advance);
gfxFloat lineHeight;
if (os2 && os2->sTypoAscender) {
aMetrics->emAscent = os2->sTypoAscender * yScale;
aMetrics->emDescent = -os2->sTypoDescender * yScale;
FT_Short typoHeight =
os2->sTypoAscender - os2->sTypoDescender + os2->sTypoLineGap;
lineHeight = typoHeight * yScale;
// maxAscent/maxDescent get used for frame heights, and some fonts
// don't have the HHEA table ascent/descent set (bug 279032).
if (aMetrics->emAscent > aMetrics->maxAscent)
aMetrics->maxAscent = aMetrics->emAscent;
if (aMetrics->emDescent > aMetrics->maxDescent)
aMetrics->maxDescent = aMetrics->emDescent;
} else {
aMetrics->emAscent = aMetrics->maxAscent;
aMetrics->emDescent = aMetrics->maxDescent;
lineHeight = FLOAT_FROM_26_6(ftMetrics.height);
}
cairo_text_extents_t extents;
*aSpaceGlyph = GetCharExtents(' ', &extents);
if (*aSpaceGlyph) {
aMetrics->spaceWidth = extents.x_advance;
} else {
aMetrics->spaceWidth = aMetrics->maxAdvance; // guess
}
aMetrics->zeroOrAveCharWidth = 0.0;
if (GetCharExtents('0', &extents)) {
aMetrics->zeroOrAveCharWidth = extents.x_advance;
}
// Prefering a measured x over sxHeight because sxHeight doesn't consider
// hinting, but maybe the x extents are not quite right in some fancy
// script fonts. CSS 2.1 suggests possibly using the height of an "o",
// which would have a more consistent glyph across fonts.
if (GetCharExtents('x', &extents) && extents.y_bearing < 0.0) {
aMetrics->xHeight = -extents.y_bearing;
aMetrics->aveCharWidth = extents.x_advance;
} else {
if (os2 && os2->sxHeight) {
aMetrics->xHeight = os2->sxHeight * yScale;
} else {
// CSS 2.1, section 4.3.2 Lengths: "In the cases where it is
// impossible or impractical to determine the x-height, a value of
// 0.5em should be used."
aMetrics->xHeight = 0.5 * emHeight;
}
aMetrics->aveCharWidth = 0.0; // updated below
}
// aveCharWidth is used for the width of text input elements so be
// liberal rather than conservative in the estimate.
if (os2 && os2->xAvgCharWidth) {
// Round to pixels as this is compared with maxAdvance to guess
// whether this is a fixed width font.
gfxFloat avgCharWidth =
ScaleRoundDesignUnits(os2->xAvgCharWidth, ftMetrics.x_scale);
aMetrics->aveCharWidth =
PR_MAX(aMetrics->aveCharWidth, avgCharWidth);
}
aMetrics->aveCharWidth =
PR_MAX(aMetrics->aveCharWidth, aMetrics->zeroOrAveCharWidth);
if (aMetrics->aveCharWidth == 0.0) {
aMetrics->aveCharWidth = aMetrics->spaceWidth;
}
if (aMetrics->zeroOrAveCharWidth == 0.0) {
aMetrics->zeroOrAveCharWidth = aMetrics->aveCharWidth;
}
// Apparently hinting can mean that max_advance is not always accurate.
aMetrics->maxAdvance =
PR_MAX(aMetrics->maxAdvance, aMetrics->aveCharWidth);
// gfxFont::Metrics::underlineOffset is the position of the top of the
// underline.
//
// FT_FaceRec documentation describes underline_position as "the
// center of the underlining stem". This was the original definition
// of the PostScript metric, but in the PostScript table of OpenType
// fonts the metric is "the top of the underline"
// (http://www.microsoft.com/typography/otspec/post.htm), and FreeType
// (up to version 2.3.7) doesn't make any adjustment.
//
// Therefore get the underline position directly from the table
// ourselves when this table exists. Use FreeType's metrics for
// other (including older PostScript) fonts.
if (mFace->underline_position && mFace->underline_thickness) {
aMetrics->underlineSize = mFace->underline_thickness * yScale;
TT_Postscript *post = static_cast<TT_Postscript*>
(FT_Get_Sfnt_Table(mFace, ft_sfnt_post));
if (post && post->underlinePosition) {
aMetrics->underlineOffset = post->underlinePosition * yScale;
} else {
aMetrics->underlineOffset = mFace->underline_position * yScale
+ 0.5 * aMetrics->underlineSize;
}
} else { // No underline info.
// Imitate Pango.
aMetrics->underlineSize = emHeight / 14.0;
aMetrics->underlineOffset = -aMetrics->underlineSize;
}
if (os2 && os2->yStrikeoutSize && os2->yStrikeoutPosition) {
aMetrics->strikeoutSize = os2->yStrikeoutSize * yScale;
aMetrics->strikeoutOffset = os2->yStrikeoutPosition * yScale;
} else { // No strikeout info.
aMetrics->strikeoutSize = aMetrics->underlineSize;
// Use OpenType spec's suggested position for Roman font.
aMetrics->strikeoutOffset = emHeight * 409.0 / 2048.0
+ 0.5 * aMetrics->strikeoutSize;
}
SnapLineToPixels(aMetrics->strikeoutOffset, aMetrics->strikeoutSize);
if (os2 && os2->ySuperscriptYOffset) {
gfxFloat val = ScaleRoundDesignUnits(os2->ySuperscriptYOffset,
ftMetrics.y_scale);
aMetrics->superscriptOffset = PR_MAX(1.0, val);
} else {
aMetrics->superscriptOffset = aMetrics->xHeight;
}
if (os2 && os2->ySubscriptYOffset) {
gfxFloat val = ScaleRoundDesignUnits(os2->ySubscriptYOffset,
ftMetrics.y_scale);
// some fonts have the incorrect sign.
val = fabs(val);
aMetrics->subscriptOffset = PR_MAX(1.0, val);
} else {
aMetrics->subscriptOffset = aMetrics->xHeight;
}
aMetrics->maxHeight = aMetrics->maxAscent + aMetrics->maxDescent;
// Make the line height an integer number of pixels so that lines will be
// equally spaced (rather than just being snapped to pixels, some up and
// some down). Layout calculates line height from the emHeight +
// internalLeading + externalLeading, but first each of these is rounded
// to layout units. To ensure that the result is an integer number of
// pixels, round each of the components to pixels.
aMetrics->emHeight = NS_floor(emHeight + 0.5);
// maxHeight will normally be an integer, but round anyway in case
// FreeType is configured differently.
aMetrics->internalLeading =
NS_floor(aMetrics->maxHeight - aMetrics->emHeight + 0.5);
// Text input boxes currently don't work well with lineHeight
// significantly less than maxHeight (with Verdana, for example).
lineHeight = NS_floor(PR_MAX(lineHeight, aMetrics->maxHeight) + 0.5);
aMetrics->externalLeading =
lineHeight - aMetrics->internalLeading - aMetrics->emHeight;
// Ensure emAscent + emDescent == emHeight
gfxFloat sum = aMetrics->emAscent + aMetrics->emDescent;
aMetrics->emAscent = sum > 0.0 ?
aMetrics->emAscent * aMetrics->emHeight / sum : 0.0;
aMetrics->emDescent = aMetrics->emHeight - aMetrics->emAscent;
}
PRUint32
gfxFT2LockedFace::GetGlyph(PRUint32 aCharCode)
{
if (NS_UNLIKELY(!mFace))
return 0;
return FT_Get_Char_Index(mFace, aCharCode);
}
PRUint32
gfxFT2LockedFace::GetCharExtents(char aChar, cairo_text_extents_t* aExtents)
{
NS_PRECONDITION(aExtents != NULL, "aExtents must not be NULL");
if (!mFace)
return 0;
FT_UInt gid = mGfxFont->GetGlyph(aChar);
if (gid) {
mGfxFont->GetGlyphExtents(gid, aExtents);
}
return gid;
}

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

@ -0,0 +1,95 @@
/* -*- 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 Foundation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@mozilla.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* Behdad Esfahbod <behdad@gnome.org>
* Mats Palmgren <mats.palmgren@bredband.net>
* Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
* Takuro Ashie <ashie@clear-code.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_FT2UTILS_H
#define GFX_FT2UTILS_H
#include "cairo-ft.h"
#include "gfxFT2FontBase.h"
typedef struct FT_FaceRec_* FT_Face;
class gfxFT2LockedFace {
public:
gfxFT2LockedFace(gfxFT2FontBase *aFont) :
mGfxFont(aFont),
mFace(cairo_ft_scaled_font_lock_face(aFont->CairoScaledFont()))
{ }
~gfxFT2LockedFace()
{
if (mFace) {
cairo_ft_scaled_font_unlock_face(mGfxFont->CairoScaledFont());
}
}
FT_Face get() { return mFace; };
/**
* Get the glyph id for a Unicode character representable by a single
* glyph, or return zero if there is no such glyph. This does no caching,
* so you probably want gfxFcFont::GetGlyph.
*/
virtual PRUint32 GetGlyph(PRUint32 aCharCode);
void GetMetrics(gfxFont::Metrics* aMetrics, PRUint32* aSpaceGlyph);
protected:
/**
* Get extents for a simple character representable by a single glyph.
* The return value is the glyph id of that glyph or zero if no such glyph
* exists. aExtents is only set when this returns a non-zero glyph id.
*/
PRUint32 GetCharExtents(char aChar, cairo_text_extents_t* aExtents);
nsRefPtr<gfxFT2FontBase> mGfxFont;
FT_Face mFace;
};
// Rounding and truncation functions for a FreeType fixed point number
// (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer
// part and low 6 bits for the fractional part.
#define FLOAT_FROM_26_6(x) ((x) / 64.0)
#define FLOAT_FROM_16_16(x) ((x) / 65536.0)
#define ROUND_26_6_TO_INT(x) ((x) >= 0 ? ((32 + (x)) >> 6) \
: -((32 - (x)) >> 6))
#endif /* GFX_FT2UTILS_H */

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

@ -56,6 +56,8 @@
#include "gfxContext.h"
#include "gfxPlatformGtk.h"
#include "gfxPangoFonts.h"
#include "gfxFT2FontBase.h"
#include "gfxFT2Utils.h"
#include "gfxFontconfigUtils.h"
#include "gfxUserFontSet.h"
@ -126,21 +128,6 @@ public:
#define FC_FULLNAME "fullname"
#endif
// Rounding and truncation functions for a FreeType fixed point number
// (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer
// part and low 6 bits for the fractional part.
#define FLOAT_FROM_26_6(x) ((x) / 64.0)
#define FLOAT_FROM_16_16(x) ((x) / 65536.0)
#define ROUND_26_6_TO_INT(x) ((x) >= 0 ? ((32 + (x)) >> 6) \
: -((32 - (x)) >> 6))
// aScale is intended for a 16.16 x/y_scale of an FT_Size_Metrics
static inline FT_Long
ScaleRoundDesignUnits(FT_Short aDesignMetric, FT_Fixed aScale)
{
FT_Long fixed26dot6 = FT_MulFix(aDesignMetric, aScale);
return ROUND_26_6_TO_INT(fixed26dot6);
}
static PRFuncPtr
FindFunctionSymbol(const char *name)
{
@ -519,84 +506,46 @@ gfxDownloadedFcFontEntry::GetPangoCoverage()
* cairo_scaled_font created from an FcPattern.
*/
class gfxFcFont : public gfxFont {
class gfxFcFont : public gfxFT2FontBase {
public:
virtual ~gfxFcFont ();
static already_AddRefed<gfxFcFont> GetOrMakeFont(FcPattern *aPattern);
virtual const gfxFont::Metrics& GetMetrics();
virtual nsString GetUniqueName();
// Get the glyphID of a space
virtual PRUint32 GetSpaceGlyph() {
NS_ASSERTION(GetStyle()->size != 0,
"forgot to short-circuit a text run with zero-sized font?");
GetMetrics();
return mSpaceGlyph;
}
cairo_scaled_font_t *CairoScaledFont() { return mCairoFont; }
PRUint32 GetGlyph(PRUint32 aCharCode);
void GetGlyphExtents(PRUint32 aGlyph, cairo_text_extents_t* aExtents);
protected:
cairo_scaled_font_t *mCairoFont;
PRUint32 mSpaceGlyph;
Metrics mMetrics;
PRPackedBool mHasMetrics;
gfxFcFont(cairo_scaled_font_t *aCairoFont,
gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle);
virtual PRBool SetupCairoFont(gfxContext *aContext);
// key for locating a gfxFcFont corresponding to a cairo_scaled_font
static cairo_user_data_key_t sGfxFontKey;
};
class LockedFTFace {
class gfxFcLockedFace : public gfxFT2LockedFace {
public:
LockedFTFace(gfxFcFont *aFont)
: mGfxFont(aFont),
mFace(cairo_ft_scaled_font_lock_face(aFont->CairoScaledFont()))
{
}
~LockedFTFace()
{
if (mFace) {
cairo_ft_scaled_font_unlock_face(mGfxFont->CairoScaledFont());
}
}
FT_Face get()
{
return mFace;
}
/**
* Get the glyph id for a Unicode character representable by a single
* glyph, or return zero if there is no such glyph. This does no caching,
* so you probably want gfxFcFont::GetGlyph.
*/
PRUint32 GetGlyph(PRUint32 aCharCode);
void GetMetrics(gfxFont::Metrics* aMetrics, PRUint32* aSpaceGlyph);
private:
/**
* Get extents for a simple character representable by a single glyph.
* The return value is the glyph id of that glyph or zero if no such glyph
* exists. aExtents is only set when this returns a non-zero glyph id.
*/
PRUint32 GetCharExtents(char aChar, cairo_text_extents_t* aExtents);
nsRefPtr<gfxFcFont> mGfxFont;
FT_Face mFace;
gfxFcLockedFace(gfxFT2FontBase *aFont) : gfxFT2LockedFace(aFont) {};
~gfxFcLockedFace() {};
virtual PRUint32 GetGlyph(PRUint32 aCharCode);
};
PRUint32
gfxFcLockedFace::GetGlyph(PRUint32 aCharCode)
{
if (NS_UNLIKELY(!mFace))
return 0;
// FcFreeTypeCharIndex will search starting from the most recently
// selected charmap. This can cause non-determistic behavior when more
// than one charmap supports a character but with different glyphs, as
// with older versions of MS Gothic, for example. Always prefer a Unicode
// charmap, if there is one. (FcFreeTypeCharIndex usually does the
// appropriate Unicode conversion, but some fonts have non-Roman glyphs
// for FT_ENCODING_APPLE_ROMAN characters.)
if (!mFace->charmap || mFace->charmap->encoding != FT_ENCODING_UNICODE) {
FT_Select_Charmap(mFace, FT_ENCODING_UNICODE);
}
return FcFreeTypeCharIndex(mFace, aCharCode);
}
/**
* gfxPangoFcFont:
*
@ -2107,18 +2056,14 @@ cairo_user_data_key_t gfxFcFont::sGfxFontKey;
gfxFcFont::gfxFcFont(cairo_scaled_font_t *aCairoFont,
gfxFontEntry *aFontEntry,
const gfxFontStyle *aFontStyle)
: gfxFont(aFontEntry, aFontStyle),
mCairoFont(aCairoFont),
mHasMetrics(PR_FALSE)
: gfxFT2FontBase(aCairoFont, aFontEntry, aFontStyle)
{
cairo_scaled_font_reference(mCairoFont);
cairo_scaled_font_set_user_data(mCairoFont, &sGfxFontKey, this, NULL);
cairo_scaled_font_set_user_data(mScaledFont, &sGfxFontKey, this, NULL);
}
gfxFcFont::~gfxFcFont()
{
cairo_scaled_font_set_user_data(mCairoFont, &sGfxFontKey, NULL, NULL);
cairo_scaled_font_destroy(mCairoFont);
cairo_scaled_font_set_user_data(mScaledFont, &sGfxFontKey, NULL, NULL);
}
/* static */ void
@ -2211,7 +2156,7 @@ GetFTLibrary()
if (!font)
return NULL;
LockedFTFace face(font);
gfxFcLockedFace face(font);
if (!face.get())
return NULL;
@ -2402,400 +2347,6 @@ gfxPangoFontGroup::GetBaseFontSet()
return fontSet;
}
PRUint32
gfxFcFont::GetGlyph(PRUint32 aCharCode)
{
// FcFreeTypeCharIndex needs to lock the FT_Face and can end up searching
// through all the postscript glyph names in the font. Therefore use a
// lightweight cache, which is stored on the cairo_font_face_t.
cairo_font_face_t *face =
cairo_scaled_font_get_font_face(CairoScaledFont());
if (cairo_font_face_status(face) != CAIRO_STATUS_SUCCESS)
return 0;
// This cache algorithm and size is based on what is done in
// cairo_scaled_font_text_to_glyphs and pango_fc_font_real_get_glyph. I
// think the concept is that adjacent characters probably come mostly from
// one Unicode block. This assumption is probably not so valid with
// scripts with large character sets as used for East Asian languages.
struct CmapCacheSlot {
PRUint32 mCharCode;
PRUint32 mGlyphIndex;
};
const PRUint32 kNumSlots = 256;
static cairo_user_data_key_t sCmapCacheKey;
CmapCacheSlot *slots = static_cast<CmapCacheSlot*>
(cairo_font_face_get_user_data(face, &sCmapCacheKey));
if (!slots) {
// cairo's caches can keep some cairo_font_faces alive past our last
// destroy, so the destroy function (free) for the cache must be
// callable from cairo without any assumptions about what other
// modules have not been shutdown.
slots = static_cast<CmapCacheSlot*>
(calloc(kNumSlots, sizeof(CmapCacheSlot)));
if (!slots)
return 0;
cairo_status_t status =
cairo_font_face_set_user_data(face, &sCmapCacheKey, slots, free);
if (status != CAIRO_STATUS_SUCCESS) { // OOM
free(slots);
return 0;
}
// Invalidate slot 0 by setting its char code to something that would
// never end up in slot 0. All other slots are already invalid
// because they have mCharCode = 0 and a glyph for char code 0 will
// always be in the slot 0.
slots[0].mCharCode = 1;
}
CmapCacheSlot *slot = &slots[aCharCode % kNumSlots];
if (slot->mCharCode != aCharCode) {
slot->mCharCode = aCharCode;
slot->mGlyphIndex = LockedFTFace(this).GetGlyph(aCharCode);
}
return slot->mGlyphIndex;
}
void
gfxFcFont::GetGlyphExtents(PRUint32 aGlyph, cairo_text_extents_t* aExtents)
{
NS_PRECONDITION(aExtents != NULL, "aExtents must not be NULL");
cairo_glyph_t glyphs[1];
glyphs[0].index = aGlyph;
glyphs[0].x = 0.0;
glyphs[0].y = 0.0;
// cairo does some caching for us here but perhaps a small gain could be
// made by caching more. It is usually only the advance that is needed,
// so caching only the advance could allow many requests to be cached with
// little memory use. Ideally this cache would be merged with
// gfxGlyphExtents.
cairo_scaled_font_glyph_extents(CairoScaledFont(), glyphs, 1, aExtents);
}
PRUint32
LockedFTFace::GetGlyph(PRUint32 aCharCode)
{
if (NS_UNLIKELY(!mFace))
return 0;
// FcFreeTypeCharIndex will search starting from the most recently
// selected charmap. This can cause non-determistic behavior when more
// than one charmap supports a character but with different glyphs, as
// with older versions of MS Gothic, for example. Always prefer a Unicode
// charmap, if there is one. (FcFreeTypeCharIndex usually does the
// appropriate Unicode conversion, but some fonts have non-Roman glyphs
// for FT_ENCODING_APPLE_ROMAN characters.)
if (!mFace->charmap || mFace->charmap->encoding != FT_ENCODING_UNICODE) {
FT_Select_Charmap(mFace, FT_ENCODING_UNICODE);
}
return FcFreeTypeCharIndex(mFace, aCharCode);
}
PRUint32
LockedFTFace::GetCharExtents(char aChar,
cairo_text_extents_t* aExtents)
{
NS_PRECONDITION(aExtents != NULL, "aExtents must not be NULL");
if (!mFace)
return 0;
FT_UInt gid = mGfxFont->GetGlyph(aChar);
if (gid) {
mGfxFont->GetGlyphExtents(gid, aExtents);
}
return gid;
}
// Snap a line to pixels while keeping the center and size of the line as
// close to the original position as possible.
//
// Pango does similar snapping for underline and strikethrough when fonts are
// hinted, but nsCSSRendering::GetTextDecorationRectInternal always snaps the
// top and size of lines. Optimizing the distance between the line and
// baseline is probably good for the gap between text and underline, but
// optimizing the center of the line is better for positioning strikethough.
static void
SnapLineToPixels(gfxFloat& aOffset, gfxFloat& aSize)
{
gfxFloat snappedSize = PR_MAX(NS_floor(aSize + 0.5), 1.0);
// Correct offset for change in size
gfxFloat offset = aOffset - 0.5 * (aSize - snappedSize);
// Snap offset
aOffset = NS_floor(offset + 0.5);
aSize = snappedSize;
}
void
LockedFTFace::GetMetrics(gfxFont::Metrics* aMetrics, PRUint32* aSpaceGlyph)
{
NS_PRECONDITION(aMetrics != NULL, "aMetrics must not be NULL");
NS_PRECONDITION(aSpaceGlyph != NULL, "aSpaceGlyph must not be NULL");
if (NS_UNLIKELY(!mFace)) {
// No face. This unfortunate situation might happen if the font
// file is (re)moved at the wrong time.
aMetrics->emHeight = mGfxFont->GetStyle()->size;
aMetrics->emAscent = 0.8 * aMetrics->emHeight;
aMetrics->emDescent = 0.2 * aMetrics->emHeight;
aMetrics->maxAscent = aMetrics->emAscent;
aMetrics->maxDescent = aMetrics->maxDescent;
aMetrics->maxHeight = aMetrics->emHeight;
aMetrics->internalLeading = 0.0;
aMetrics->externalLeading = 0.2 * aMetrics->emHeight;
aSpaceGlyph = 0;
aMetrics->spaceWidth = 0.5 * aMetrics->emHeight;
aMetrics->maxAdvance = aMetrics->spaceWidth;
aMetrics->aveCharWidth = aMetrics->spaceWidth;
aMetrics->zeroOrAveCharWidth = aMetrics->spaceWidth;
aMetrics->xHeight = 0.5 * aMetrics->emHeight;
aMetrics->underlineSize = aMetrics->emHeight / 14.0;
aMetrics->underlineOffset = -aMetrics->underlineSize;
aMetrics->strikeoutOffset = 0.25 * aMetrics->emHeight;
aMetrics->strikeoutSize = aMetrics->underlineSize;
aMetrics->superscriptOffset = aMetrics->xHeight;
aMetrics->subscriptOffset = aMetrics->xHeight;
return;
}
const FT_Size_Metrics& ftMetrics = mFace->size->metrics;
gfxFloat emHeight;
// Scale for vertical design metric conversion: pixels per design unit.
gfxFloat yScale;
if (FT_IS_SCALABLE(mFace)) {
// Prefer FT_Size_Metrics::x_scale to x_ppem as x_ppem does not
// have subpixel accuracy.
//
// FT_Size_Metrics::y_scale is in 16.16 fixed point format. Its
// (fractional) value is a factor that converts vertical metrics from
// design units to units of 1/64 pixels, so that the result may be
// interpreted as pixels in 26.6 fixed point format.
yScale = FLOAT_FROM_26_6(FLOAT_FROM_16_16(ftMetrics.y_scale));
emHeight = mFace->units_per_EM * yScale;
} else { // Not scalable.
// FT_Size_Metrics doc says x_scale is "only relevant for scalable
// font formats".
gfxFloat emUnit = mFace->units_per_EM;
emHeight = ftMetrics.y_ppem;
yScale = emHeight / emUnit;
}
TT_OS2 *os2 =
static_cast<TT_OS2*>(FT_Get_Sfnt_Table(mFace, ft_sfnt_os2));
aMetrics->maxAscent = FLOAT_FROM_26_6(ftMetrics.ascender);
aMetrics->maxDescent = -FLOAT_FROM_26_6(ftMetrics.descender);
aMetrics->maxAdvance = FLOAT_FROM_26_6(ftMetrics.max_advance);
gfxFloat lineHeight;
if (os2 && os2->sTypoAscender) {
aMetrics->emAscent = os2->sTypoAscender * yScale;
aMetrics->emDescent = -os2->sTypoDescender * yScale;
FT_Short typoHeight =
os2->sTypoAscender - os2->sTypoDescender + os2->sTypoLineGap;
lineHeight = typoHeight * yScale;
// maxAscent/maxDescent get used for frame heights, and some fonts
// don't have the HHEA table ascent/descent set (bug 279032).
if (aMetrics->emAscent > aMetrics->maxAscent)
aMetrics->maxAscent = aMetrics->emAscent;
if (aMetrics->emDescent > aMetrics->maxDescent)
aMetrics->maxDescent = aMetrics->emDescent;
} else {
aMetrics->emAscent = aMetrics->maxAscent;
aMetrics->emDescent = aMetrics->maxDescent;
lineHeight = FLOAT_FROM_26_6(ftMetrics.height);
}
cairo_text_extents_t extents;
*aSpaceGlyph = GetCharExtents(' ', &extents);
if (*aSpaceGlyph) {
aMetrics->spaceWidth = extents.x_advance;
} else {
aMetrics->spaceWidth = aMetrics->maxAdvance; // guess
}
aMetrics->zeroOrAveCharWidth = 0.0;
if (GetCharExtents('0', &extents)) {
aMetrics->zeroOrAveCharWidth = extents.x_advance;
}
// Prefering a measured x over sxHeight because sxHeight doesn't consider
// hinting, but maybe the x extents are not quite right in some fancy
// script fonts. CSS 2.1 suggests possibly using the height of an "o",
// which would have a more consistent glyph across fonts.
if (GetCharExtents('x', &extents) && extents.y_bearing < 0.0) {
aMetrics->xHeight = -extents.y_bearing;
aMetrics->aveCharWidth = extents.x_advance;
} else {
if (os2 && os2->sxHeight) {
aMetrics->xHeight = os2->sxHeight * yScale;
} else {
// CSS 2.1, section 4.3.2 Lengths: "In the cases where it is
// impossible or impractical to determine the x-height, a value of
// 0.5em should be used."
aMetrics->xHeight = 0.5 * emHeight;
}
aMetrics->aveCharWidth = 0.0; // updated below
}
// aveCharWidth is used for the width of text input elements so be
// liberal rather than conservative in the estimate.
if (os2 && os2->xAvgCharWidth) {
// Round to pixels as this is compared with maxAdvance to guess
// whether this is a fixed width font.
gfxFloat avgCharWidth =
ScaleRoundDesignUnits(os2->xAvgCharWidth, ftMetrics.x_scale);
aMetrics->aveCharWidth =
PR_MAX(aMetrics->aveCharWidth, avgCharWidth);
}
aMetrics->aveCharWidth =
PR_MAX(aMetrics->aveCharWidth, aMetrics->zeroOrAveCharWidth);
if (aMetrics->aveCharWidth == 0.0) {
aMetrics->aveCharWidth = aMetrics->spaceWidth;
}
if (aMetrics->zeroOrAveCharWidth == 0.0) {
aMetrics->zeroOrAveCharWidth = aMetrics->aveCharWidth;
}
// Apparently hinting can mean that max_advance is not always accurate.
aMetrics->maxAdvance =
PR_MAX(aMetrics->maxAdvance, aMetrics->aveCharWidth);
// gfxFont::Metrics::underlineOffset is the position of the top of the
// underline.
//
// FT_FaceRec documentation describes underline_position as "the
// center of the underlining stem". This was the original definition
// of the PostScript metric, but in the PostScript table of OpenType
// fonts the metric is "the top of the underline"
// (http://www.microsoft.com/typography/otspec/post.htm), and FreeType
// (up to version 2.3.7) doesn't make any adjustment.
//
// Therefore get the underline position directly from the table
// ourselves when this table exists. Use FreeType's metrics for
// other (including older PostScript) fonts.
if (mFace->underline_position && mFace->underline_thickness) {
aMetrics->underlineSize = mFace->underline_thickness * yScale;
TT_Postscript *post = static_cast<TT_Postscript*>
(FT_Get_Sfnt_Table(mFace, ft_sfnt_post));
if (post && post->underlinePosition) {
aMetrics->underlineOffset = post->underlinePosition * yScale;
} else {
aMetrics->underlineOffset = mFace->underline_position * yScale
+ 0.5 * aMetrics->underlineSize;
}
} else { // No underline info.
// Imitate Pango.
aMetrics->underlineSize = emHeight / 14.0;
aMetrics->underlineOffset = -aMetrics->underlineSize;
}
if (os2 && os2->yStrikeoutSize && os2->yStrikeoutPosition) {
aMetrics->strikeoutSize = os2->yStrikeoutSize * yScale;
aMetrics->strikeoutOffset = os2->yStrikeoutPosition * yScale;
} else { // No strikeout info.
aMetrics->strikeoutSize = aMetrics->underlineSize;
// Use OpenType spec's suggested position for Roman font.
aMetrics->strikeoutOffset = emHeight * 409.0 / 2048.0
+ 0.5 * aMetrics->strikeoutSize;
}
SnapLineToPixels(aMetrics->strikeoutOffset, aMetrics->strikeoutSize);
if (os2 && os2->ySuperscriptYOffset) {
gfxFloat val = ScaleRoundDesignUnits(os2->ySuperscriptYOffset,
ftMetrics.y_scale);
aMetrics->superscriptOffset = PR_MAX(1.0, val);
} else {
aMetrics->superscriptOffset = aMetrics->xHeight;
}
if (os2 && os2->ySubscriptYOffset) {
gfxFloat val = ScaleRoundDesignUnits(os2->ySubscriptYOffset,
ftMetrics.y_scale);
// some fonts have the incorrect sign.
val = fabs(val);
aMetrics->subscriptOffset = PR_MAX(1.0, val);
} else {
aMetrics->subscriptOffset = aMetrics->xHeight;
}
aMetrics->maxHeight = aMetrics->maxAscent + aMetrics->maxDescent;
// Make the line height an integer number of pixels so that lines will be
// equally spaced (rather than just being snapped to pixels, some up and
// some down). Layout calculates line height from the emHeight +
// internalLeading + externalLeading, but first each of these is rounded
// to layout units. To ensure that the result is an integer number of
// pixels, round each of the components to pixels.
aMetrics->emHeight = NS_floor(emHeight + 0.5);
// maxHeight will normally be an integer, but round anyway in case
// FreeType is configured differently.
aMetrics->internalLeading =
NS_floor(aMetrics->maxHeight - aMetrics->emHeight + 0.5);
// Text input boxes currently don't work well with lineHeight
// significantly less than maxHeight (with Verdana, for example).
lineHeight = NS_floor(PR_MAX(lineHeight, aMetrics->maxHeight) + 0.5);
aMetrics->externalLeading =
lineHeight - aMetrics->internalLeading - aMetrics->emHeight;
// Ensure emAscent + emDescent == emHeight
gfxFloat sum = aMetrics->emAscent + aMetrics->emDescent;
aMetrics->emAscent = sum > 0.0 ?
aMetrics->emAscent * aMetrics->emHeight / sum : 0.0;
aMetrics->emDescent = aMetrics->emHeight - aMetrics->emAscent;
}
const gfxFont::Metrics&
gfxFcFont::GetMetrics()
{
if (mHasMetrics)
return mMetrics;
if (NS_UNLIKELY(GetStyle()->size <= 0.0)) {
new(&mMetrics) gfxFont::Metrics(); // zero initialize
mSpaceGlyph = 0;
} else {
LockedFTFace(this).GetMetrics(&mMetrics, &mSpaceGlyph);
}
SanitizeMetrics(&mMetrics, PR_FALSE);
#if 0
// printf("font name: %s %f\n", NS_ConvertUTF16toUTF8(GetName()).get(), GetStyle()->size);
// printf ("pango font %s\n", pango_font_description_to_string (pango_font_describe (font)));
fprintf (stderr, "Font: %s\n", NS_ConvertUTF16toUTF8(GetName()).get());
fprintf (stderr, " emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
fprintf (stderr, " maxAscent: %f maxDescent: %f\n", mMetrics.maxAscent, mMetrics.maxDescent);
fprintf (stderr, " internalLeading: %f externalLeading: %f\n", mMetrics.externalLeading, mMetrics.internalLeading);
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
mHasMetrics = PR_TRUE;
return mMetrics;
}
nsString
gfxFcFont::GetUniqueName()
{
return GetName();
}
/**
** gfxTextRun
*
@ -3113,47 +2664,6 @@ CreateScaledFont(FcPattern *aPattern)
return scaledFont;
}
PRBool
gfxFcFont::SetupCairoFont(gfxContext *aContext)
{
cairo_t *cr = aContext->GetCairo();
// The scaled font ctm is not relevant right here because
// cairo_set_scaled_font does not record the scaled font itself, but
// merely the font_face, font_matrix, font_options. The scaled_font used
// for the target can be different from the scaled_font passed to
// cairo_set_scaled_font. (Unfortunately we have measured only for an
// identity ctm.)
cairo_scaled_font_t *cairoFont = CairoScaledFont();
if (cairo_scaled_font_status(cairoFont) != 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;
}
// Thoughts on which font_options to set on the context:
//
// cairoFont has been created for screen rendering.
//
// When the context is being used for screen rendering, we should set
// font_options such that the same scaled_font gets used (when the ctm is
// the same). The use of explicit font_options recorded in
// CreateScaledFont ensures that this will happen.
//
// XXXkt: For pdf and ps surfaces, I don't know whether it's better to
// remove surface-specific options, or try to draw with the same
// scaled_font that was used to measure. As the same font_face is being
// used, its font_options will often override some values anyway (unless
// perhaps we remove those from the FcPattern at face creation).
//
// I can't see any significant difference in printing, irrespective of
// what is set here. It's too late to change things here as measuring has
// already taken place. We should really be measuring with a different
// font for pdf and ps surfaces (bug 403513).
cairo_set_scaled_font(cr, cairoFont);
return PR_TRUE;
}
static void
SetupClusterBoundaries(gfxTextRun* aTextRun, const gchar *aUTF8, PRUint32 aUTF8Length,
PRUint32 aUTF16Offset, PangoAnalysis *aAnalysis)