2010-03-10 15:46:41 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Corporation code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Mozilla Foundation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2006-2010
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Vladimir Vukicevic <vladimir@pobox.com>
|
|
|
|
* Masayuki Nakano <masayuki@d-toybox.com>
|
|
|
|
* John Daggett <jdaggett@mozilla.com>
|
|
|
|
* Jonathan Kew <jfkthame@gmail.com>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include "gfxMacFont.h"
|
|
|
|
#include "gfxCoreTextShaper.h"
|
2009-10-07 21:16:52 +04:00
|
|
|
#include "gfxHarfBuzzShaper.h"
|
2010-03-10 15:46:41 +03:00
|
|
|
#include "gfxPlatformMac.h"
|
|
|
|
#include "gfxContext.h"
|
2010-07-22 13:25:21 +04:00
|
|
|
#include "gfxUnicodeProperties.h"
|
2010-08-05 13:18:44 +04:00
|
|
|
#include "gfxFontUtils.h"
|
2010-03-10 15:46:41 +03:00
|
|
|
|
|
|
|
#include "cairo-quartz.h"
|
|
|
|
|
2010-08-05 13:18:44 +04:00
|
|
|
using namespace mozilla;
|
|
|
|
|
2010-03-10 15:46:41 +03:00
|
|
|
gfxMacFont::gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
|
|
|
|
PRBool aNeedsBold)
|
|
|
|
: gfxFont(aFontEntry, aFontStyle),
|
2010-06-11 23:14:38 +04:00
|
|
|
mCGFont(nsnull),
|
2010-03-10 15:46:41 +03:00
|
|
|
mFontFace(nsnull),
|
2009-10-07 21:16:52 +04:00
|
|
|
mScaledFont(nsnull)
|
2010-03-10 15:46:41 +03:00
|
|
|
{
|
2010-03-12 07:26:43 +03:00
|
|
|
if (aNeedsBold) {
|
2010-03-10 15:46:41 +03:00
|
|
|
mSyntheticBoldOffset = 1; // devunit offset when double-striking text to fake boldness
|
|
|
|
}
|
|
|
|
|
2011-06-24 21:55:27 +04:00
|
|
|
mCGFont = aFontEntry->GetFontRef();
|
2010-06-11 23:14:38 +04:00
|
|
|
if (!mCGFont) {
|
|
|
|
mIsValid = PR_FALSE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-03-10 15:46:41 +03:00
|
|
|
// InitMetrics will handle the sizeAdjust factor and set mAdjustedSize
|
|
|
|
InitMetrics();
|
2010-06-11 23:14:38 +04:00
|
|
|
if (!mIsValid) {
|
2010-03-10 15:46:41 +03:00
|
|
|
return;
|
2010-06-11 23:14:38 +04:00
|
|
|
}
|
2010-03-10 15:46:41 +03:00
|
|
|
|
2010-06-11 23:14:38 +04:00
|
|
|
mFontFace = cairo_quartz_font_face_create_for_cgfont(mCGFont);
|
2010-03-10 15:46:41 +03:00
|
|
|
|
|
|
|
cairo_status_t cairoerr = cairo_font_face_status(mFontFace);
|
|
|
|
if (cairoerr != CAIRO_STATUS_SUCCESS) {
|
|
|
|
mIsValid = PR_FALSE;
|
|
|
|
#ifdef DEBUG
|
|
|
|
char warnBuf[1024];
|
|
|
|
sprintf(warnBuf, "Failed to create Cairo font face: %s status: %d",
|
|
|
|
NS_ConvertUTF16toUTF8(GetName()).get(), cairoerr);
|
|
|
|
NS_WARNING(warnBuf);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_matrix_t sizeMatrix, ctm;
|
|
|
|
cairo_matrix_init_identity(&ctm);
|
|
|
|
cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize);
|
|
|
|
|
|
|
|
// synthetic oblique by skewing via the font matrix
|
|
|
|
PRBool needsOblique =
|
|
|
|
(mFontEntry != NULL) &&
|
2010-07-11 23:33:56 +04:00
|
|
|
(!mFontEntry->IsItalic() &&
|
|
|
|
(mStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)));
|
2010-03-10 15:46:41 +03:00
|
|
|
|
|
|
|
if (needsOblique) {
|
|
|
|
double skewfactor = (needsOblique ? Fix2X(kATSItalicQDSkew) : 0);
|
|
|
|
|
|
|
|
cairo_matrix_t style;
|
|
|
|
cairo_matrix_init(&style,
|
|
|
|
1, //xx
|
|
|
|
0, //yx
|
|
|
|
-1 * skewfactor, //xy
|
|
|
|
1, //yy
|
|
|
|
0, //x0
|
|
|
|
0); //y0
|
|
|
|
cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_font_options_t *fontOptions = cairo_font_options_create();
|
|
|
|
|
|
|
|
// turn off font anti-aliasing based on user pref setting
|
2010-07-11 23:33:56 +04:00
|
|
|
if (mAdjustedSize <=
|
|
|
|
(gfxFloat)gfxPlatformMac::GetPlatform()->GetAntiAliasingThreshold()) {
|
2010-03-10 15:46:41 +03:00
|
|
|
cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_NONE);
|
|
|
|
}
|
|
|
|
|
2010-07-11 23:33:56 +04:00
|
|
|
mScaledFont = cairo_scaled_font_create(mFontFace, &sizeMatrix, &ctm,
|
|
|
|
fontOptions);
|
2010-03-10 15:46:41 +03:00
|
|
|
cairo_font_options_destroy(fontOptions);
|
|
|
|
|
|
|
|
cairoerr = cairo_scaled_font_status(mScaledFont);
|
|
|
|
if (cairoerr != CAIRO_STATUS_SUCCESS) {
|
|
|
|
mIsValid = PR_FALSE;
|
|
|
|
#ifdef DEBUG
|
|
|
|
char warnBuf[1024];
|
|
|
|
sprintf(warnBuf, "Failed to create scaled font: %s status: %d",
|
|
|
|
NS_ConvertUTF16toUTF8(GetName()).get(), cairoerr);
|
|
|
|
NS_WARNING(warnBuf);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2009-10-07 21:16:52 +04:00
|
|
|
if (FontCanSupportHarfBuzz()) {
|
|
|
|
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
|
|
|
|
}
|
2010-03-10 15:46:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
gfxMacFont::~gfxMacFont()
|
|
|
|
{
|
|
|
|
if (mScaledFont) {
|
|
|
|
cairo_scaled_font_destroy(mScaledFont);
|
|
|
|
}
|
|
|
|
if (mFontFace) {
|
|
|
|
cairo_font_face_destroy(mFontFace);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-22 13:25:21 +04:00
|
|
|
PRBool
|
|
|
|
gfxMacFont::InitTextRun(gfxContext *aContext,
|
|
|
|
gfxTextRun *aTextRun,
|
|
|
|
const PRUnichar *aString,
|
|
|
|
PRUint32 aRunStart,
|
|
|
|
PRUint32 aRunLength,
|
2010-11-11 14:21:05 +03:00
|
|
|
PRInt32 aRunScript,
|
|
|
|
PRBool aPreferPlatformShaping)
|
2010-07-22 13:25:21 +04:00
|
|
|
{
|
|
|
|
if (!mIsValid) {
|
|
|
|
NS_WARNING("invalid font! expect incorrect text rendering");
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
2010-11-11 14:21:05 +03:00
|
|
|
PRBool ok = gfxFont::InitTextRun(aContext, aTextRun, aString,
|
|
|
|
aRunStart, aRunLength, aRunScript,
|
|
|
|
static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout());
|
2010-07-22 13:25:21 +04:00
|
|
|
|
2010-09-16 20:41:40 +04:00
|
|
|
aTextRun->AdjustAdvancesForSyntheticBold(aRunStart, aRunLength);
|
|
|
|
|
2010-07-22 13:25:21 +04:00
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2009-10-07 21:16:52 +04:00
|
|
|
void
|
|
|
|
gfxMacFont::CreatePlatformShaper()
|
|
|
|
{
|
|
|
|
mPlatformShaper = new gfxCoreTextShaper(this);
|
|
|
|
}
|
|
|
|
|
2010-03-10 15:46:41 +03:00
|
|
|
PRBool
|
|
|
|
gfxMacFont::SetupCairoFont(gfxContext *aContext)
|
|
|
|
{
|
|
|
|
if (cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) {
|
|
|
|
// Don't cairo_set_scaled_font as that would propagate the error to
|
|
|
|
// the cairo_t, precluding any further drawing.
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
cairo_set_scaled_font(aContext->GetCairo(), mScaledFont);
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
2011-06-22 12:49:57 +04:00
|
|
|
gfxFont::RunMetrics
|
|
|
|
gfxMacFont::Measure(gfxTextRun *aTextRun,
|
|
|
|
PRUint32 aStart, PRUint32 aEnd,
|
|
|
|
BoundingBoxType aBoundingBoxType,
|
|
|
|
gfxContext *aRefContext,
|
|
|
|
Spacing *aSpacing)
|
|
|
|
{
|
|
|
|
gfxFont::RunMetrics metrics =
|
|
|
|
gfxFont::Measure(aTextRun, aStart, aEnd,
|
|
|
|
aBoundingBoxType, aRefContext, aSpacing);
|
|
|
|
|
|
|
|
// if aBoundingBoxType is not TIGHT_HINTED_OUTLINE_EXTENTS then we need to add
|
|
|
|
// a pixel column each side of the bounding box in case of antialiasing "bleed"
|
|
|
|
if (aBoundingBoxType != TIGHT_HINTED_OUTLINE_EXTENTS &&
|
|
|
|
metrics.mBoundingBox.width > 0) {
|
|
|
|
metrics.mBoundingBox.x -= aTextRun->GetAppUnitsPerDevUnit();
|
|
|
|
metrics.mBoundingBox.width += aTextRun->GetAppUnitsPerDevUnit() * 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return metrics;
|
|
|
|
}
|
|
|
|
|
2010-03-10 15:46:41 +03:00
|
|
|
void
|
|
|
|
gfxMacFont::InitMetrics()
|
|
|
|
{
|
2010-07-11 23:33:56 +04:00
|
|
|
mIsValid = PR_FALSE;
|
|
|
|
::memset(&mMetrics, 0, sizeof(mMetrics));
|
|
|
|
|
2010-08-05 13:18:44 +04:00
|
|
|
PRUint32 upem = 0;
|
|
|
|
|
|
|
|
// try to get unitsPerEm from sfnt head table, to avoid calling CGFont
|
|
|
|
// if possible (bug 574368) and because CGFontGetUnitsPerEm does not
|
|
|
|
// return the true value for OpenType/CFF fonts (it normalizes to 1000,
|
|
|
|
// which then leads to metrics errors when we read the 'hmtx' table to
|
|
|
|
// get glyph advances for HarfBuzz, see bug 580863)
|
|
|
|
const PRUint32 kHeadTableTag = TRUETYPE_TAG('h','e','a','d');
|
2011-01-07 07:45:10 +03:00
|
|
|
AutoFallibleTArray<PRUint8,sizeof(HeadTable)> headData;
|
2010-08-05 13:18:44 +04:00
|
|
|
if (NS_SUCCEEDED(mFontEntry->GetFontTable(kHeadTableTag, headData)) &&
|
|
|
|
headData.Length() >= sizeof(HeadTable)) {
|
|
|
|
HeadTable *head = reinterpret_cast<HeadTable*>(headData.Elements());
|
|
|
|
upem = head->unitsPerEm;
|
|
|
|
} else {
|
|
|
|
upem = ::CGFontGetUnitsPerEm(mCGFont);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (upem < 16 || upem > 16384) {
|
|
|
|
// See http://www.microsoft.com/typography/otspec/head.htm
|
2010-06-11 23:14:38 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
char warnBuf[1024];
|
2010-08-05 13:18:44 +04:00
|
|
|
sprintf(warnBuf, "Bad font metrics for: %s (invalid unitsPerEm value)",
|
2010-06-11 23:14:38 +04:00
|
|
|
NS_ConvertUTF16toUTF8(mFontEntry->Name()).get());
|
|
|
|
NS_WARNING(warnBuf);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2010-03-10 15:46:41 +03:00
|
|
|
|
2011-06-02 16:56:50 +04:00
|
|
|
mAdjustedSize = NS_MAX(mStyle.size, 1.0);
|
2010-07-11 23:33:56 +04:00
|
|
|
mFUnitsConvFactor = mAdjustedSize / upem;
|
2010-03-10 15:46:41 +03:00
|
|
|
|
2010-10-07 11:59:16 +04:00
|
|
|
// For CFF fonts, when scaling values read from CGFont* APIs, we need to
|
|
|
|
// use CG's idea of unitsPerEm, which may differ from the "true" value in
|
|
|
|
// the head table of the font (see bug 580863)
|
|
|
|
gfxFloat cgConvFactor;
|
|
|
|
if (static_cast<MacOSFontEntry*>(mFontEntry.get())->IsCFF()) {
|
|
|
|
cgConvFactor = mAdjustedSize / ::CGFontGetUnitsPerEm(mCGFont);
|
|
|
|
} else {
|
|
|
|
cgConvFactor = mFUnitsConvFactor;
|
|
|
|
}
|
|
|
|
|
2010-07-11 23:33:56 +04:00
|
|
|
// Try to read 'sfnt' metrics; for local, non-sfnt fonts ONLY, fall back to
|
|
|
|
// platform APIs. The InitMetrics...() functions will set mIsValid on success.
|
|
|
|
if (!InitMetricsFromSfntTables(mMetrics) &&
|
|
|
|
(!mFontEntry->IsUserFont() || mFontEntry->IsLocalUserFont())) {
|
2011-06-24 21:55:27 +04:00
|
|
|
InitMetricsFromPlatform();
|
2010-07-11 23:33:56 +04:00
|
|
|
}
|
|
|
|
if (!mIsValid) {
|
2010-03-10 15:46:41 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-07-11 23:33:56 +04:00
|
|
|
if (mMetrics.xHeight == 0.0) {
|
2010-10-07 11:59:16 +04:00
|
|
|
mMetrics.xHeight = ::CGFontGetXHeight(mCGFont) * cgConvFactor;
|
2010-07-11 23:33:56 +04:00
|
|
|
}
|
2010-03-10 15:46:41 +03:00
|
|
|
|
2010-07-11 23:33:56 +04:00
|
|
|
if (mStyle.sizeAdjust != 0.0 && mStyle.size > 0.0 &&
|
|
|
|
mMetrics.xHeight > 0.0) {
|
|
|
|
// apply font-size-adjust, and recalculate metrics
|
|
|
|
gfxFloat aspect = mMetrics.xHeight / mStyle.size;
|
|
|
|
mAdjustedSize = mStyle.GetAdjustedSize(aspect);
|
|
|
|
mFUnitsConvFactor = mAdjustedSize / upem;
|
2010-10-07 11:59:16 +04:00
|
|
|
if (static_cast<MacOSFontEntry*>(mFontEntry.get())->IsCFF()) {
|
|
|
|
cgConvFactor = mAdjustedSize / ::CGFontGetUnitsPerEm(mCGFont);
|
|
|
|
} else {
|
|
|
|
cgConvFactor = mFUnitsConvFactor;
|
|
|
|
}
|
2010-07-11 23:33:56 +04:00
|
|
|
mMetrics.xHeight = 0.0;
|
|
|
|
if (!InitMetricsFromSfntTables(mMetrics) &&
|
|
|
|
(!mFontEntry->IsUserFont() || mFontEntry->IsLocalUserFont())) {
|
2011-06-24 21:55:27 +04:00
|
|
|
InitMetricsFromPlatform();
|
2010-07-11 23:33:56 +04:00
|
|
|
}
|
|
|
|
if (!mIsValid) {
|
|
|
|
// this shouldn't happen, as we succeeded earlier before applying
|
|
|
|
// the size-adjust factor! But check anyway, for paranoia's sake.
|
2010-03-10 15:46:41 +03:00
|
|
|
return;
|
|
|
|
}
|
2010-07-11 23:33:56 +04:00
|
|
|
if (mMetrics.xHeight == 0.0) {
|
2010-10-07 11:59:16 +04:00
|
|
|
mMetrics.xHeight = ::CGFontGetXHeight(mCGFont) * cgConvFactor;
|
2010-07-11 23:33:56 +04:00
|
|
|
}
|
2010-03-10 15:46:41 +03:00
|
|
|
}
|
|
|
|
|
2010-07-11 23:33:56 +04:00
|
|
|
// Once we reach here, we've got basic metrics and set mIsValid = TRUE;
|
|
|
|
// there should be no further points of actual failure in InitMetrics().
|
|
|
|
// (If one is introduced, be sure to reset mIsValid to FALSE!)
|
2010-03-10 15:46:41 +03:00
|
|
|
|
2010-07-11 23:33:56 +04:00
|
|
|
mMetrics.emHeight = mAdjustedSize;
|
2010-03-10 15:46:41 +03:00
|
|
|
|
2010-07-11 23:33:56 +04:00
|
|
|
// Measure/calculate additional metrics, independent of whether we used
|
|
|
|
// the tables directly or ATS metrics APIs
|
2010-03-10 15:46:41 +03:00
|
|
|
|
2010-06-11 23:14:38 +04:00
|
|
|
CFDataRef cmap =
|
|
|
|
::CGFontCopyTableForTag(mCGFont, TRUETYPE_TAG('c','m','a','p'));
|
|
|
|
|
2010-03-10 15:46:41 +03:00
|
|
|
PRUint32 glyphID;
|
2010-07-11 23:33:56 +04:00
|
|
|
if (mMetrics.aveCharWidth <= 0) {
|
2010-10-07 11:59:16 +04:00
|
|
|
mMetrics.aveCharWidth = GetCharWidth(cmap, 'x', &glyphID,
|
|
|
|
cgConvFactor);
|
2010-07-11 23:33:56 +04:00
|
|
|
if (glyphID == 0) {
|
|
|
|
// we didn't find 'x', so use maxAdvance rather than zero
|
|
|
|
mMetrics.aveCharWidth = mMetrics.maxAdvance;
|
|
|
|
}
|
|
|
|
}
|
2010-03-10 15:46:41 +03:00
|
|
|
mMetrics.aveCharWidth += mSyntheticBoldOffset;
|
2010-07-11 23:33:56 +04:00
|
|
|
mMetrics.maxAdvance += mSyntheticBoldOffset;
|
2010-03-10 15:46:41 +03:00
|
|
|
|
2010-10-07 11:59:16 +04:00
|
|
|
mMetrics.spaceWidth = GetCharWidth(cmap, ' ', &glyphID, cgConvFactor);
|
2010-07-11 23:33:56 +04:00
|
|
|
if (glyphID == 0) {
|
|
|
|
// no space glyph?!
|
|
|
|
mMetrics.spaceWidth = mMetrics.aveCharWidth;
|
2010-03-10 15:46:41 +03:00
|
|
|
}
|
|
|
|
mSpaceGlyph = glyphID;
|
|
|
|
|
2010-10-07 11:59:16 +04:00
|
|
|
mMetrics.zeroOrAveCharWidth = GetCharWidth(cmap, '0', &glyphID,
|
|
|
|
cgConvFactor);
|
2010-07-11 23:33:56 +04:00
|
|
|
if (glyphID == 0) {
|
2010-03-10 15:46:41 +03:00
|
|
|
mMetrics.zeroOrAveCharWidth = mMetrics.aveCharWidth;
|
2010-07-11 23:33:56 +04:00
|
|
|
}
|
2010-03-10 15:46:41 +03:00
|
|
|
|
2010-06-11 23:14:38 +04:00
|
|
|
if (cmap) {
|
|
|
|
::CFRelease(cmap);
|
|
|
|
}
|
2010-03-10 15:46:41 +03:00
|
|
|
|
2010-07-11 23:33:56 +04:00
|
|
|
CalculateDerivedMetrics(mMetrics);
|
2009-10-07 21:16:52 +04:00
|
|
|
|
2010-03-10 15:46:41 +03:00
|
|
|
SanitizeMetrics(&mMetrics, mFontEntry->mIsBadUnderlineFont);
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
fprintf (stderr, "Font: %p (%s) size: %f\n", this,
|
|
|
|
NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size);
|
|
|
|
// fprintf (stderr, " fbounds.origin.x %f y %f size.width %f height %f\n", fbounds.origin.x, fbounds.origin.y, fbounds.size.width, fbounds.size.height);
|
|
|
|
fprintf (stderr, " emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
|
|
|
|
fprintf (stderr, " maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance);
|
|
|
|
fprintf (stderr, " internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading);
|
|
|
|
fprintf (stderr, " spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight);
|
2009-10-07 21:16:52 +04:00
|
|
|
fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset);
|
2010-03-10 15:46:41 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-06-11 23:14:38 +04:00
|
|
|
gfxFloat
|
2010-07-11 23:33:56 +04:00
|
|
|
gfxMacFont::GetCharWidth(CFDataRef aCmap, PRUnichar aUniChar,
|
2010-10-07 11:59:16 +04:00
|
|
|
PRUint32 *aGlyphID, gfxFloat aConvFactor)
|
2010-03-10 15:46:41 +03:00
|
|
|
{
|
2010-06-11 23:14:38 +04:00
|
|
|
CGGlyph glyph = 0;
|
|
|
|
|
|
|
|
if (aCmap) {
|
|
|
|
glyph = gfxFontUtils::MapCharToGlyph(::CFDataGetBytePtr(aCmap),
|
|
|
|
::CFDataGetLength(aCmap),
|
|
|
|
aUniChar);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aGlyphID) {
|
|
|
|
*aGlyphID = glyph;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (glyph) {
|
|
|
|
int advance;
|
|
|
|
if (::CGFontGetGlyphAdvances(mCGFont, &glyph, 1, &advance)) {
|
2010-10-07 11:59:16 +04:00
|
|
|
return advance * aConvFactor;
|
2010-06-11 23:14:38 +04:00
|
|
|
}
|
2010-03-10 15:46:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-06-11 23:14:38 +04:00
|
|
|
/*static*/ void
|
|
|
|
gfxMacFont::DestroyBlobFunc(void* aUserData)
|
|
|
|
{
|
|
|
|
::CFRelease((CFDataRef)aUserData);
|
|
|
|
}
|
|
|
|
|
|
|
|
hb_blob_t *
|
|
|
|
gfxMacFont::GetFontTable(PRUint32 aTag)
|
2010-03-10 15:46:41 +03:00
|
|
|
{
|
2010-06-11 23:14:38 +04:00
|
|
|
CFDataRef dataRef = ::CGFontCopyTableForTag(mCGFont, aTag);
|
|
|
|
if (dataRef) {
|
|
|
|
return hb_blob_create((const char*)::CFDataGetBytePtr(dataRef),
|
|
|
|
::CFDataGetLength(dataRef),
|
|
|
|
HB_MEMORY_MODE_READONLY,
|
|
|
|
DestroyBlobFunc, (void*)dataRef);
|
2010-03-10 15:46:41 +03:00
|
|
|
}
|
|
|
|
|
2010-10-07 11:59:19 +04:00
|
|
|
if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
|
|
|
|
// for downloaded fonts, there may be layout tables cached in the entry
|
|
|
|
// even though they're absent from the sanitized platform font
|
2010-12-09 10:28:47 +03:00
|
|
|
hb_blob_t *blob;
|
|
|
|
if (mFontEntry->GetExistingFontTable(aTag, &blob)) {
|
|
|
|
return blob;
|
|
|
|
}
|
2010-10-07 11:59:19 +04:00
|
|
|
}
|
|
|
|
|
2010-06-11 23:14:38 +04:00
|
|
|
return nsnull;
|
2010-03-10 15:46:41 +03:00
|
|
|
}
|
2010-07-11 23:33:56 +04:00
|
|
|
|
2011-06-24 21:55:27 +04:00
|
|
|
// Try to initialize font metrics via platform APIs (CG/CT),
|
2010-07-11 23:33:56 +04:00
|
|
|
// and set mIsValid = TRUE on success.
|
|
|
|
// We ONLY call this for local (platform) fonts that are not sfnt format;
|
2011-06-24 21:55:27 +04:00
|
|
|
// for sfnts, including ALL downloadable fonts, we prefer to use
|
|
|
|
// InitMetricsFromSfntTables and avoid platform APIs.
|
|
|
|
void
|
|
|
|
gfxMacFont::InitMetricsFromPlatform()
|
|
|
|
{
|
|
|
|
if (gfxMacPlatformFontList::UseATSFontEntry()) {
|
|
|
|
ATSFontEntry *fe = static_cast<ATSFontEntry*>(GetFontEntry());
|
|
|
|
InitMetricsFromATSMetrics(fe->GetATSFontRef());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CTFontRef ctFont = ::CTFontCreateWithGraphicsFont(mCGFont,
|
|
|
|
mAdjustedSize,
|
|
|
|
NULL, NULL);
|
|
|
|
if (!ctFont) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mMetrics.underlineOffset = ::CTFontGetUnderlinePosition(ctFont);
|
|
|
|
mMetrics.underlineSize = ::CTFontGetUnderlineThickness(ctFont);
|
|
|
|
|
|
|
|
mMetrics.externalLeading = ::CTFontGetLeading(ctFont);
|
|
|
|
|
|
|
|
mMetrics.maxAscent = ::CTFontGetAscent(ctFont);
|
|
|
|
mMetrics.maxDescent = ::CTFontGetDescent(ctFont);
|
|
|
|
|
|
|
|
// this is not strictly correct, but neither CTFont nor CGFont seems to
|
|
|
|
// provide maxAdvance, unless we were to iterate over all the glyphs
|
|
|
|
// (which isn't worth the cost here)
|
|
|
|
CGRect r = ::CTFontGetBoundingBox(ctFont);
|
|
|
|
mMetrics.maxAdvance = r.size.width;
|
|
|
|
|
|
|
|
// aveCharWidth is also not provided, so leave it at zero
|
|
|
|
// (fallback code in gfxMacFont::InitMetrics will then try measuring 'x');
|
|
|
|
// this could lead to less-than-"perfect" text field sizing when width is
|
|
|
|
// specified as a number of characters, and the font in use is a non-sfnt
|
|
|
|
// legacy font, but that's a sufficiently obscure edge case that we can
|
|
|
|
// ignore the potential discrepancy.
|
|
|
|
mMetrics.aveCharWidth = 0;
|
|
|
|
|
|
|
|
mMetrics.xHeight = ::CTFontGetXHeight(ctFont);
|
|
|
|
|
|
|
|
::CFRelease(ctFont);
|
|
|
|
|
|
|
|
mIsValid = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For OS X 10.5, try to initialize font metrics via ATS font metrics APIs,
|
|
|
|
// and set mIsValid = TRUE on success.
|
2010-07-11 23:33:56 +04:00
|
|
|
void
|
2011-06-24 21:55:27 +04:00
|
|
|
gfxMacFont::InitMetricsFromATSMetrics(ATSFontRef aFontRef)
|
2010-07-11 23:33:56 +04:00
|
|
|
{
|
|
|
|
ATSFontMetrics atsMetrics;
|
|
|
|
OSStatus err;
|
|
|
|
|
2011-06-24 21:55:27 +04:00
|
|
|
err = ::ATSFontGetHorizontalMetrics(aFontRef, kATSOptionFlagsDefault,
|
2010-07-11 23:33:56 +04:00
|
|
|
&atsMetrics);
|
|
|
|
if (err != noErr) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
char warnBuf[1024];
|
|
|
|
sprintf(warnBuf, "Bad font metrics for: %s err: %8.8x",
|
|
|
|
NS_ConvertUTF16toUTF8(mFontEntry->Name()).get(), PRUint32(err));
|
|
|
|
NS_WARNING(warnBuf);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mMetrics.underlineOffset = atsMetrics.underlinePosition * mAdjustedSize;
|
|
|
|
mMetrics.underlineSize = atsMetrics.underlineThickness * mAdjustedSize;
|
|
|
|
|
|
|
|
mMetrics.externalLeading = atsMetrics.leading * mAdjustedSize;
|
|
|
|
|
|
|
|
mMetrics.maxAscent = atsMetrics.ascent * mAdjustedSize;
|
|
|
|
mMetrics.maxDescent = -atsMetrics.descent * mAdjustedSize;
|
|
|
|
|
|
|
|
mMetrics.maxAdvance = atsMetrics.maxAdvanceWidth * mAdjustedSize;
|
|
|
|
mMetrics.aveCharWidth = atsMetrics.avgAdvanceWidth * mAdjustedSize;
|
|
|
|
mMetrics.xHeight = atsMetrics.xHeight * mAdjustedSize;
|
|
|
|
|
|
|
|
mIsValid = PR_TRUE;
|
|
|
|
}
|