2007-03-22 10:30:00 -07:00
|
|
|
/* vim: set sw=4 sts=4 et cin: */
|
|
|
|
/* ***** 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 OS/2 code in Thebes.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Peter Weilbacher <mozilla@Weilbacher.org>.
|
2007-05-20 06:45:49 -07:00
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2006-2007
|
2007-03-22 10:30:00 -07:00
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
2007-05-20 06:45:49 -07:00
|
|
|
* authors of code taken from gfxPangoFonts:
|
|
|
|
* Mozilla Foundation
|
|
|
|
* Vladimir Vukicevic <vladimir@mozilla.com>
|
|
|
|
* Masayuki Nakano <masayuki@d-toybox.com>
|
2007-03-22 10:30:00 -07:00
|
|
|
*
|
|
|
|
* 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 "gfxContext.h"
|
|
|
|
|
|
|
|
#include "gfxOS2Platform.h"
|
|
|
|
#include "gfxOS2Surface.h"
|
|
|
|
#include "gfxOS2Fonts.h"
|
|
|
|
|
|
|
|
#include "nsIServiceManager.h"
|
|
|
|
#include "nsIPlatformCharset.h"
|
2008-05-28 05:38:09 -07:00
|
|
|
#include "nsIPrefBranch.h"
|
|
|
|
#include "nsIPrefService.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* class gfxOS2Font
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
gfxOS2Font::gfxOS2Font(const nsAString &aName, const gfxFontStyle *aFontStyle)
|
2007-05-20 06:45:49 -07:00
|
|
|
: gfxFont(aName, aFontStyle),
|
|
|
|
mFontFace(nsnull), mScaledFont(nsnull),
|
2008-05-28 05:38:09 -07:00
|
|
|
mMetrics(nsnull), mAdjustedSize(0),
|
|
|
|
mHinting(FC_HINT_MEDIUM), mAntialias(FcTrue)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-05-28 05:55:36 -07:00
|
|
|
#ifdef DEBUG_thebes_2
|
2007-05-20 06:45:49 -07:00
|
|
|
printf("gfxOS2Font[%#x]::gfxOS2Font(\"%s\", aFontStyle)\n",
|
|
|
|
(unsigned)this, NS_LossyConvertUTF16toASCII(aName).get());
|
2008-05-28 05:38:09 -07:00
|
|
|
#endif
|
|
|
|
// try to get the preferences for hinting, antialias, and embolden options
|
|
|
|
nsCOMPtr<nsIPrefBranch> prefbranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
|
|
|
if (prefbranch) {
|
|
|
|
int value;
|
|
|
|
nsresult rv = prefbranch->GetIntPref("gfx.os2.font.hinting", &value);
|
|
|
|
if (NS_SUCCEEDED(rv) && value >= FC_HINT_NONE && value <= FC_HINT_FULL)
|
|
|
|
mHinting = value;
|
|
|
|
|
|
|
|
PRBool enabled;
|
|
|
|
rv = prefbranch->GetBoolPref("gfx.os2.font.antialiasing", &enabled);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
mAntialias = enabled;
|
|
|
|
}
|
2008-05-28 05:55:36 -07:00
|
|
|
#ifdef DEBUG_thebes_2
|
2008-05-28 05:38:09 -07:00
|
|
|
printf(" font display options: hinting=%d, antialiasing=%s\n",
|
|
|
|
mHinting, mAntialias ? "on" : "off");
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
gfxOS2Font::~gfxOS2Font()
|
|
|
|
{
|
2007-05-20 06:45:49 -07:00
|
|
|
#ifdef DEBUG_thebes_2
|
|
|
|
printf("gfxOS2Font[%#x]::~gfxOS2Font()\n", (unsigned)this);
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2007-05-20 06:45:49 -07:00
|
|
|
if (mFontFace) {
|
|
|
|
cairo_font_face_destroy(mFontFace);
|
|
|
|
}
|
|
|
|
if (mScaledFont) {
|
|
|
|
cairo_scaled_font_destroy(mScaledFont);
|
|
|
|
}
|
|
|
|
if (mMetrics) {
|
2007-03-22 10:30:00 -07:00
|
|
|
delete mMetrics;
|
2007-05-20 06:45:49 -07:00
|
|
|
}
|
|
|
|
mFontFace = nsnull;
|
|
|
|
mScaledFont = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
mMetrics = nsnull;
|
|
|
|
}
|
|
|
|
|
2007-06-30 13:20:51 -07:00
|
|
|
// gfxOS2Font::GetMetrics()
|
|
|
|
// return the metrics of the current font using the gfxFont metrics structure.
|
|
|
|
// If the metrics are not available yet, compute them using the FreeType
|
|
|
|
// function on the font. (This is partly based on the respective function from
|
|
|
|
// gfxPangoFonts)
|
2007-05-20 06:45:49 -07:00
|
|
|
const gfxFont::Metrics& gfxOS2Font::GetMetrics()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-05-20 06:45:49 -07:00
|
|
|
#ifdef DEBUG_thebes_1
|
|
|
|
printf("gfxOS2Font[%#x]::GetMetrics()\n", (unsigned)this);
|
|
|
|
#endif
|
|
|
|
if (!mMetrics) {
|
2007-03-22 10:30:00 -07:00
|
|
|
mMetrics = new gfxFont::Metrics;
|
2007-08-19 05:05:23 -07:00
|
|
|
|
2007-08-19 05:27:23 -07:00
|
|
|
mMetrics->emHeight = GetStyle()->size;
|
|
|
|
|
|
|
|
FT_UInt gid; // glyph ID
|
2007-05-20 06:45:49 -07:00
|
|
|
FT_Face face = cairo_ft_scaled_font_lock_face(CairoScaledFont());
|
2007-10-19 12:24:03 -07:00
|
|
|
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;
|
|
|
|
}
|
2007-05-20 06:45:49 -07:00
|
|
|
|
2007-08-19 05:36:21 -07:00
|
|
|
double emUnit = 1.0 * face->units_per_EM;
|
|
|
|
double xScale = face->size->metrics.x_ppem / emUnit;
|
|
|
|
double yScale = face->size->metrics.y_ppem / emUnit;
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
// properties of space
|
|
|
|
gid = FT_Get_Char_Index(face, ' ');
|
2007-12-03 14:22:36 -08:00
|
|
|
// Load glyph into glyph slot. Use load_default here to get results in
|
|
|
|
// 26.6 fractional pixel format which is what is used for all other
|
|
|
|
// characters in gfxOS2FontGroup::CreateGlyphRunsFT.
|
|
|
|
FT_Load_Glyph(face, gid, FT_LOAD_DEFAULT);
|
2007-05-20 06:45:49 -07:00
|
|
|
// face->glyph->metrics.width doesn't work for spaces, use advance.x instead
|
2007-12-03 14:22:36 -08:00
|
|
|
mMetrics->spaceWidth = face->glyph->advance.x >> 6;
|
2007-05-20 06:45:49 -07:00
|
|
|
// save the space glyph
|
|
|
|
mSpaceGlyph = gid;
|
2007-08-19 05:05:23 -07:00
|
|
|
|
2007-08-19 05:27:23 -07:00
|
|
|
// properties of 'x', also use its width as average width
|
|
|
|
gid = FT_Get_Char_Index(face, 'x'); // select the glyph
|
|
|
|
if (gid) {
|
2007-12-03 14:22:36 -08:00
|
|
|
// Load glyph into glyph slot. Here, use no_scale to get font units.
|
2007-08-19 05:27:23 -07:00
|
|
|
FT_Load_Glyph(face, gid, FT_LOAD_NO_SCALE);
|
2007-08-19 05:36:21 -07:00
|
|
|
mMetrics->xHeight = face->glyph->metrics.height * yScale;
|
2007-12-02 08:37:16 -08:00
|
|
|
mMetrics->aveCharWidth = face->glyph->metrics.width * xScale;
|
2007-08-19 05:27:23 -07:00
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
|
2008-07-15 14:31:36 -07:00
|
|
|
// properties of '0', for 'ch' units
|
|
|
|
gid = FT_Get_Char_Index(face, '0');
|
|
|
|
if (gid) {
|
|
|
|
FT_Load_Glyph(face, gid, FT_LOAD_NO_SCALE);
|
|
|
|
mMetrics->zeroOrAveCharWidth = face->glyph->metrics.width * xScale;
|
|
|
|
} else {
|
|
|
|
// this font doesn't have a '0'
|
|
|
|
mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth;
|
|
|
|
}
|
|
|
|
|
2007-08-19 05:27:23 -07:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
// 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);
|
2007-08-19 05:27:23 -07:00
|
|
|
if (os2 && os2->version != 0xFFFF) { // should be there if not old Mac font
|
|
|
|
// if we are here we can improve the avgCharWidth
|
2007-08-19 05:36:21 -07:00
|
|
|
mMetrics->aveCharWidth = os2->xAvgCharWidth * xScale;
|
2007-08-19 05:27:23 -07:00
|
|
|
|
2007-08-19 05:36:21 -07:00
|
|
|
mMetrics->superscriptOffset = os2->ySuperscriptYOffset * yScale;
|
2007-06-24 04:10:03 -07:00
|
|
|
mMetrics->superscriptOffset = PR_MAX(1, mMetrics->superscriptOffset);
|
2007-05-20 06:45:49 -07:00
|
|
|
// some fonts have the incorrect sign (from gfxPangoFonts)
|
2007-08-19 05:36:21 -07:00
|
|
|
mMetrics->subscriptOffset = fabs(os2->ySubscriptYOffset * yScale);
|
2007-06-24 04:10:03 -07:00
|
|
|
mMetrics->subscriptOffset = PR_MAX(1, fabs(mMetrics->subscriptOffset));
|
2007-08-19 05:36:21 -07:00
|
|
|
mMetrics->strikeoutOffset = os2->yStrikeoutPosition * yScale;
|
2008-02-15 13:31:38 -08:00
|
|
|
mMetrics->strikeoutSize = os2->yStrikeoutSize * yScale;
|
2007-05-20 06:45:49 -07:00
|
|
|
} else {
|
2007-08-19 05:27:23 -07:00
|
|
|
// 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;
|
2007-08-19 05:36:21 -07:00
|
|
|
mMetrics->strikeoutSize = face->underline_thickness * yScale;
|
2007-05-20 06:45:49 -07:00
|
|
|
}
|
2007-06-30 13:20:51 -07:00
|
|
|
// seems that underlineOffset really has to be negative
|
2007-08-19 05:36:21 -07:00
|
|
|
mMetrics->underlineOffset = face->underline_position * yScale;
|
2008-02-15 13:31:38 -08:00
|
|
|
mMetrics->underlineSize = face->underline_thickness * yScale;
|
2007-08-19 05:05:23 -07:00
|
|
|
|
2007-06-24 04:10:03 -07:00
|
|
|
// descents are negative in FT but Thebes wants them positive
|
2007-08-19 05:36:21 -07:00
|
|
|
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;
|
2007-05-20 06:45:49 -07:00
|
|
|
// leading are not available directly (only for WinFNTs)
|
2007-06-24 04:10:03 -07:00
|
|
|
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
|
2007-08-19 05:05:23 -07:00
|
|
|
|
2008-03-12 19:36:58 -07:00
|
|
|
SanitizeMetrics(mMetrics, PR_FALSE);
|
2008-02-15 13:31:38 -08:00
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
#ifdef DEBUG_thebes_1
|
|
|
|
printf("gfxOS2Font[%#x]::GetMetrics():\n"
|
2007-08-19 05:05:23 -07:00
|
|
|
" %s (%s)\n"
|
2007-12-03 14:31:03 -08:00
|
|
|
" emHeight=%f == %f=gfxFont::style.size == %f=adjSz\n"
|
2007-08-19 05:05:23 -07:00
|
|
|
" 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",
|
2007-05-20 06:45:49 -07:00
|
|
|
(unsigned)this,
|
2007-06-30 13:20:51 -07:00
|
|
|
NS_LossyConvertUTF16toASCII(mName).get(),
|
2007-08-19 05:05:23 -07:00
|
|
|
os2 && os2->version != 0xFFFF ? "has OS/2 table" : "no OS/2 table!",
|
2007-12-03 14:31:03 -08:00
|
|
|
mMetrics->emHeight, GetStyle()->size, mAdjustedSize,
|
2007-08-19 05:05:23 -07:00
|
|
|
mMetrics->maxHeight, mMetrics->xHeight,
|
|
|
|
mMetrics->aveCharWidth, mMetrics->spaceWidth,
|
2007-06-30 13:20:51 -07:00
|
|
|
mMetrics->superscriptOffset, mMetrics->subscriptOffset,
|
|
|
|
mMetrics->strikeoutOffset, mMetrics->strikeoutSize,
|
|
|
|
mMetrics->underlineOffset, mMetrics->underlineSize,
|
2007-08-19 05:05:23 -07:00
|
|
|
mMetrics->internalLeading, mMetrics->externalLeading,
|
2007-06-30 13:20:51 -07:00
|
|
|
mMetrics->emAscent, mMetrics->emDescent, mMetrics->maxHeight,
|
2007-08-19 05:05:23 -07:00
|
|
|
mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance
|
2007-06-30 13:20:51 -07:00
|
|
|
);
|
2007-05-20 06:45:49 -07:00
|
|
|
#endif
|
|
|
|
cairo_ft_scaled_font_unlock_face(CairoScaledFont());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-05-20 06:45:49 -07:00
|
|
|
return *mMetrics;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-06-24 03:00:50 -07:00
|
|
|
// weight list copied from fontconfig.h
|
|
|
|
// unfortunately, the OS/2 version so far only supports regular and bold
|
|
|
|
static const PRInt8 nFcWeight = 2; // 10; // length of weight list
|
|
|
|
static const int fcWeight[] = {
|
|
|
|
//FC_WEIGHT_THIN,
|
|
|
|
//FC_WEIGHT_EXTRALIGHT, // == FC_WEIGHT_ULTRALIGHT
|
|
|
|
//FC_WEIGHT_LIGHT,
|
|
|
|
//FC_WEIGHT_BOOK,
|
|
|
|
FC_WEIGHT_REGULAR, // == FC_WEIGHT_NORMAL
|
|
|
|
//FC_WEIGHT_MEDIUM,
|
|
|
|
//FC_WEIGHT_DEMIBOLD, // == FC_WEIGHT_SEMIBOLD
|
|
|
|
FC_WEIGHT_BOLD,
|
|
|
|
//FC_WEIGHT_EXTRABOLD, // == FC_WEIGHT_ULTRABOLD
|
|
|
|
//FC_WEIGHT_BLACK // == FC_WEIGHT_HEAVY
|
|
|
|
};
|
|
|
|
|
|
|
|
// gfxOS2Font::CairoFontFace()
|
|
|
|
// return a font face usable by cairo for font rendering
|
|
|
|
// if none was created yet, use FontConfig patterns based on the current style
|
|
|
|
// to create a new font face
|
2007-05-20 06:45:49 -07:00
|
|
|
cairo_font_face_t *gfxOS2Font::CairoFontFace()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-05-20 06:45:49 -07:00
|
|
|
#ifdef DEBUG_thebes_2
|
|
|
|
printf("gfxOS2Font[%#x]::CairoFontFace()\n", (unsigned)this);
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2007-05-20 06:45:49 -07:00
|
|
|
if (!mFontFace) {
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef DEBUG_thebes
|
2007-05-20 06:45:49 -07:00
|
|
|
printf("gfxOS2Font[%#x]::CairoFontFace(): create it for %s, %f\n",
|
2007-12-03 14:31:03 -08:00
|
|
|
(unsigned)this, NS_LossyConvertUTF16toASCII(mName).get(), GetStyle()->size);
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2007-05-20 06:45:49 -07:00
|
|
|
FcPattern *fcPattern = FcPatternCreate();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
// add (family) name to pattern
|
|
|
|
// (the conversion should work, font names don't contain high bit chars)
|
|
|
|
FcPatternAddString(fcPattern, FC_FAMILY,
|
|
|
|
(FcChar8 *)NS_LossyConvertUTF16toASCII(mName).get());
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-06-24 03:00:50 -07:00
|
|
|
// adjust font weight using the offset
|
|
|
|
// The requirements outlined in gfxFont.h are difficult to meet without
|
|
|
|
// having a table of available font weights, so we map the gfxFont
|
|
|
|
// weight to possible FontConfig weights.
|
|
|
|
PRInt8 weight, offset;
|
2007-12-03 14:31:03 -08:00
|
|
|
GetStyle()->ComputeWeightAndOffset(&weight, &offset);
|
2007-06-24 03:00:50 -07:00
|
|
|
// gfxFont weight FC weight
|
|
|
|
// 400 80
|
|
|
|
// 700 200
|
|
|
|
PRInt16 fcW = 40 * weight - 80; // match gfxFont weight to base FC weight
|
2007-08-19 05:05:23 -07:00
|
|
|
// find the correct weight in the list
|
2007-06-24 03:00:50 -07:00
|
|
|
PRInt8 i = 0;
|
|
|
|
while (i < nFcWeight && fcWeight[i] < fcW) {
|
|
|
|
i++;
|
2007-05-20 06:45:49 -07:00
|
|
|
}
|
2007-06-24 03:00:50 -07:00
|
|
|
// add the offset, but observe the available number of weights
|
|
|
|
i += offset;
|
|
|
|
if (i < 0) {
|
|
|
|
i = 0;
|
|
|
|
} else if (i >= nFcWeight) {
|
|
|
|
i = nFcWeight - 1;
|
|
|
|
}
|
|
|
|
fcW = fcWeight[i];
|
|
|
|
|
|
|
|
// add weight to pattern
|
|
|
|
FcPatternAddInteger(fcPattern, FC_WEIGHT, fcW);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-06-24 03:00:50 -07:00
|
|
|
PRUint8 fcProperty;
|
2007-05-20 06:45:49 -07:00
|
|
|
// add style to pattern
|
2007-12-03 14:31:03 -08:00
|
|
|
switch (GetStyle()->style) {
|
2007-05-20 06:45:49 -07:00
|
|
|
case FONT_STYLE_ITALIC:
|
|
|
|
fcProperty = FC_SLANT_ITALIC;
|
|
|
|
break;
|
|
|
|
case FONT_STYLE_OBLIQUE:
|
|
|
|
fcProperty = FC_SLANT_OBLIQUE;
|
|
|
|
break;
|
|
|
|
case FONT_STYLE_NORMAL:
|
|
|
|
default:
|
|
|
|
fcProperty = FC_SLANT_ROMAN;
|
|
|
|
}
|
|
|
|
FcPatternAddInteger(fcPattern, FC_SLANT, fcProperty);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
// add the size we want
|
2007-08-19 05:27:23 -07:00
|
|
|
FcPatternAddDouble(fcPattern, FC_PIXEL_SIZE,
|
2007-12-03 14:31:03 -08:00
|
|
|
mAdjustedSize ? mAdjustedSize : GetStyle()->size);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
// finally find a matching font
|
|
|
|
FcResult fcRes;
|
|
|
|
FcPattern *fcMatch = FcFontMatch(NULL, fcPattern, &fcRes);
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef DEBUG_thebes
|
2007-05-20 06:45:49 -07:00
|
|
|
FcChar8 *str1, *str2;
|
|
|
|
int w1, w2, i1, i2;
|
|
|
|
double s1, s2;
|
|
|
|
FcPatternGetString(fcPattern, FC_FAMILY, 0, &str1);
|
|
|
|
FcPatternGetInteger(fcPattern, FC_WEIGHT, 0, &w1);
|
|
|
|
FcPatternGetInteger(fcPattern, FC_SLANT, 0, &i1);
|
|
|
|
FcPatternGetDouble(fcPattern, FC_PIXEL_SIZE, 0, &s1);
|
|
|
|
FcPatternGetString(fcMatch, FC_FAMILY, 0, &str2);
|
|
|
|
FcPatternGetInteger(fcMatch, FC_WEIGHT, 0, &w2);
|
|
|
|
FcPatternGetInteger(fcMatch, FC_SLANT, 0, &i2);
|
|
|
|
FcPatternGetDouble(fcMatch, FC_PIXEL_SIZE, 0, &s2);
|
|
|
|
printf(" input=%s,%d,%d,%f\n fcPattern=%s,%d,%d,%f\n fcMatch=%s,%d,%d,%f\n",
|
2007-12-03 14:31:03 -08:00
|
|
|
NS_LossyConvertUTF16toASCII(mName).get(),
|
|
|
|
GetStyle()->weight, GetStyle()->style, GetStyle()->size,
|
2007-05-20 06:45:49 -07:00
|
|
|
(char *)str1, w1, i1, s1,
|
|
|
|
(char *)str2, w2, i2, s2);
|
|
|
|
#endif
|
|
|
|
FcPatternDestroy(fcPattern);
|
2008-05-28 05:38:09 -07:00
|
|
|
|
2007-11-28 13:46:10 -08:00
|
|
|
if (mName == NS_LITERAL_STRING("Workplace Sans") && fcW >= FC_WEIGHT_DEMIBOLD) {
|
|
|
|
// if we are dealing with Workplace Sans and want a bold font, we
|
|
|
|
// need to artificially embolden it (no bold counterpart yet)
|
|
|
|
FcPatternAddBool(fcMatch, FC_EMBOLDEN, FcTrue);
|
2008-05-28 05:38:09 -07:00
|
|
|
} else {
|
|
|
|
// if we don't embolden, we can possibly switch off antialiasing
|
|
|
|
FcPatternAddBool(fcMatch, FC_ANTIALIAS, mAntialias);
|
2007-11-28 13:46:10 -08:00
|
|
|
}
|
2008-05-28 05:38:09 -07:00
|
|
|
FcPatternAddInteger(fcMatch, FC_HINT_STYLE, mHinting);
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
// and ask cairo to return a font face for this
|
|
|
|
mFontFace = cairo_ft_font_face_create_for_pattern(fcMatch);
|
2008-05-28 05:38:09 -07:00
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
FcPatternDestroy(fcMatch);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
NS_ASSERTION(mFontFace, "Failed to make font face");
|
|
|
|
return mFontFace;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
cairo_scaled_font_t *gfxOS2Font::CairoScaledFont()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-05-20 06:45:49 -07:00
|
|
|
#ifdef DEBUG_thebes_2
|
|
|
|
printf("gfxOS2Font[%#x]::CairoScaledFont()\n", (unsigned)this);
|
|
|
|
#endif
|
|
|
|
if (!mScaledFont) {
|
|
|
|
#ifdef DEBUG_thebes_2
|
|
|
|
printf("gfxOS2Font[%#x]::CairoScaledFont(): create it for %s, %f\n",
|
2007-12-03 14:31:03 -08:00
|
|
|
(unsigned)this, NS_LossyConvertUTF16toASCII(mName).get(), GetStyle()->size);
|
2007-05-20 06:45:49 -07:00
|
|
|
#endif
|
|
|
|
|
2007-12-03 14:31:03 -08:00
|
|
|
double size = mAdjustedSize ? mAdjustedSize : GetStyle()->size;
|
2007-05-20 06:45:49 -07:00
|
|
|
cairo_matrix_t fontMatrix;
|
|
|
|
cairo_matrix_init_scale(&fontMatrix, size, size);
|
|
|
|
cairo_font_options_t *fontOptions = cairo_font_options_create();
|
|
|
|
mScaledFont = cairo_scaled_font_create(CairoFontFace(), &fontMatrix,
|
|
|
|
reinterpret_cast<cairo_matrix_t*>(&mCTM),
|
|
|
|
fontOptions);
|
|
|
|
cairo_font_options_destroy(fontOptions);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-08-25 11:33:45 -07:00
|
|
|
NS_ASSERTION(cairo_scaled_font_status(mScaledFont) == CAIRO_STATUS_SUCCESS,
|
2007-10-19 12:24:03 -07:00
|
|
|
"Failed to make scaled font");
|
2007-05-20 06:45:49 -07:00
|
|
|
return mScaledFont;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
nsString gfxOS2Font::GetUniqueName()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-05-20 06:45:49 -07:00
|
|
|
#ifdef DEBUG_thebes
|
|
|
|
printf("gfxOS2Font::GetUniqueName()=%s\n", (char *)mName.get());
|
|
|
|
#endif
|
|
|
|
// gfxFont::mName should already be unique enough
|
|
|
|
// Atsui uses that, too, while Win appends size, and properties...
|
|
|
|
// doesn't seem to get called at all anyway
|
|
|
|
return mName;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-09-27 09:41:46 -07:00
|
|
|
PRBool gfxOS2Font::SetupCairoFont(gfxContext *aContext)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-05-20 06:45:49 -07:00
|
|
|
#ifdef DEBUG_thebes_2
|
|
|
|
printf("gfxOS2Font[%#x]::SetupCairoFont(%#x)\n",
|
2007-09-27 09:41:46 -07:00
|
|
|
(unsigned)this, (unsigned) aContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2007-05-20 06:45:49 -07:00
|
|
|
// gfxPangoFont checks the CTM but Windows doesn't so leave away here, too
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
// this implicitely ensures that mScaledFont is created if NULL
|
2007-08-06 05:30:13 -07:00
|
|
|
cairo_scaled_font_t *scaledFont = CairoScaledFont();
|
2007-08-25 11:33:45 -07:00
|
|
|
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;
|
2007-08-06 05:30:13 -07:00
|
|
|
}
|
2007-09-27 09:41:46 -07:00
|
|
|
cairo_set_scaled_font(aContext->GetCairo(), scaledFont);
|
2007-08-25 11:33:45 -07:00
|
|
|
return PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************
|
2007-05-20 06:45:49 -07:00
|
|
|
* class gfxOS2FontGroup
|
2007-03-22 10:30:00 -07:00
|
|
|
**********************************************************************/
|
2007-12-03 14:31:03 -08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Look up the font in the gfxFont cache. If we don't find it, create one.
|
|
|
|
* In either case, add a ref and return it ---
|
|
|
|
* except for OOM in which case we do nothing and return null.
|
|
|
|
*/
|
|
|
|
static already_AddRefed<gfxOS2Font> GetOrMakeFont(const nsAString& aName,
|
|
|
|
const gfxFontStyle *aStyle)
|
|
|
|
{
|
|
|
|
nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(aName, aStyle);
|
|
|
|
if (!font) {
|
|
|
|
font = new gfxOS2Font(aName, aStyle);
|
|
|
|
if (!font)
|
|
|
|
return nsnull;
|
|
|
|
gfxFontCache::GetCache()->AddNew(font);
|
|
|
|
}
|
|
|
|
gfxFont *f = nsnull;
|
|
|
|
font.swap(f);
|
|
|
|
return static_cast<gfxOS2Font *>(f);
|
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
gfxOS2FontGroup::gfxOS2FontGroup(const nsAString& aFamilies,
|
|
|
|
const gfxFontStyle* aStyle)
|
|
|
|
: gfxFontGroup(aFamilies, aStyle)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG_thebes_2
|
|
|
|
printf("gfxOS2FontGroup[%#x]::gfxOS2FontGroup(\"%s\", %#x)\n",
|
|
|
|
(unsigned)this, NS_LossyConvertUTF16toASCII(aFamilies).get(),
|
|
|
|
(unsigned)aStyle);
|
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-11-28 13:46:10 -08:00
|
|
|
// check for WarpSans and as we cannot display that (yet), replace
|
|
|
|
// it with Workplace Sans
|
|
|
|
int pos = 0;
|
|
|
|
if ((pos = mFamilies.Find("WarpSans", PR_FALSE, 0, -1)) > -1) {
|
|
|
|
mFamilies.Replace(pos, 8, NS_LITERAL_STRING("Workplace Sans"));
|
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
nsStringArray familyArray;
|
|
|
|
ForEachFont(FontCallback, &familyArray);
|
2007-11-17 14:22:04 -08:00
|
|
|
|
|
|
|
// To be able to easily search for glyphs in other fonts, append a few good
|
|
|
|
// replacement candidates to the list. The best ones are the Unicode fonts that
|
|
|
|
// are set up, and if the user was so clever to set up the User Defined fonts,
|
|
|
|
// then these are probable candidates, too.
|
|
|
|
nsString fontString;
|
|
|
|
gfxPlatform::GetPlatform()->GetPrefFonts("x-unicode", fontString, PR_FALSE);
|
|
|
|
ForEachFont(fontString, NS_LITERAL_CSTRING("x-unicode"), FontCallback, &familyArray);
|
|
|
|
gfxPlatform::GetPlatform()->GetPrefFonts("x-user-def", fontString, PR_FALSE);
|
|
|
|
ForEachFont(fontString, NS_LITERAL_CSTRING("x-user-def"), FontCallback, &familyArray);
|
|
|
|
|
2007-11-28 13:46:10 -08:00
|
|
|
// Should append some default font if there are no available fonts.
|
|
|
|
// Let's use Helv which should be available on any OS/2 system; if
|
|
|
|
// it's not there, Fontconfig replaces it with something else...
|
2007-05-20 06:45:49 -07:00
|
|
|
if (familyArray.Count() == 0) {
|
2007-11-28 13:46:10 -08:00
|
|
|
familyArray.AppendString(NS_LITERAL_STRING("Helv"));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-11-17 14:22:04 -08:00
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
for (int i = 0; i < familyArray.Count(); i++) {
|
2007-12-03 14:31:03 -08:00
|
|
|
nsRefPtr<gfxOS2Font> font = GetOrMakeFont(*familyArray[i], &mStyle);
|
|
|
|
if (font) {
|
|
|
|
mFonts.AppendElement(font);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-11-17 14:22:04 -08:00
|
|
|
|
|
|
|
#ifdef REALLY_DESPERATE_FONT_MATCHING
|
|
|
|
// just continue to append all fonts known to the system
|
|
|
|
nsStringArray fontList;
|
|
|
|
nsCAutoString generic;
|
2007-12-03 14:31:03 -08:00
|
|
|
if (!gfxPlatform::GetPlatform()->GetFontList(GetStyle()->langGroup, generic, fontList)) {
|
2007-11-17 14:22:04 -08:00
|
|
|
// we don't want MARKSYM in the list (which always matches every glyph)
|
|
|
|
// nor MT Extra or the Math1* fonts which seem to have the same problem
|
|
|
|
fontList.RemoveString(NS_LITERAL_STRING("MARKSYM"));
|
|
|
|
fontList.RemoveString(NS_LITERAL_STRING("MT Extra"));
|
|
|
|
fontList.RemoveString(NS_LITERAL_STRING("Math1"));
|
|
|
|
fontList.RemoveString(NS_LITERAL_STRING("Math2"));
|
|
|
|
fontList.RemoveString(NS_LITERAL_STRING("Math3"));
|
|
|
|
fontList.RemoveString(NS_LITERAL_STRING("Math4"));
|
|
|
|
fontList.RemoveString(NS_LITERAL_STRING("Math5"));
|
|
|
|
fontList.RemoveString(NS_LITERAL_STRING("Math1Mono"));
|
|
|
|
fontList.RemoveString(NS_LITERAL_STRING("Math2Mono"));
|
|
|
|
fontList.RemoveString(NS_LITERAL_STRING("Math3Mono"));
|
|
|
|
fontList.RemoveString(NS_LITERAL_STRING("Math4Mono"));
|
|
|
|
fontList.RemoveString(NS_LITERAL_STRING("Math5Mono"));
|
|
|
|
// start at 3 to ignore the generic entries
|
|
|
|
for (int i = 3; i < fontList.Count(); i++) {
|
|
|
|
// check for duplicates that we already found through the familyArray
|
|
|
|
if (familyArray.IndexOf(*fontList[i]) == -1) {
|
2007-12-03 14:31:03 -08:00
|
|
|
nsRefPtr<gfxOS2Font> font = GetOrMakeFont(*fontList[i], &mStyle);
|
|
|
|
if (font) {
|
|
|
|
mFonts.AppendElement(font);
|
|
|
|
}
|
2007-11-17 14:22:04 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
gfxOS2FontGroup::~gfxOS2FontGroup()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-05-20 06:45:49 -07:00
|
|
|
#ifdef DEBUG_thebes_2
|
|
|
|
printf("gfxOS2FontGroup[%#x]::~gfxOS2FontGroup()\n", (unsigned)this);
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
gfxFontGroup *gfxOS2FontGroup::Copy(const gfxFontStyle *aStyle)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-05-20 06:45:49 -07:00
|
|
|
return new gfxOS2FontGroup(mFamilies, aStyle);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
/**
|
|
|
|
* We use this to append an LTR or RTL Override character to the start of the
|
|
|
|
* string. This forces Pango to honour our direction even if there are neutral
|
|
|
|
* characters in the string.
|
|
|
|
*/
|
|
|
|
static PRInt32 AppendDirectionalIndicatorUTF8(PRBool aIsRTL, nsACString& aString)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-05-20 06:45:49 -07:00
|
|
|
static const PRUnichar overrides[2][2] = { { 0x202d, 0 }, { 0x202e, 0 }}; // LRO, RLO
|
|
|
|
AppendUTF16toUTF8(overrides[aIsRTL], aString);
|
|
|
|
return 3; // both overrides map to 3 bytes in UTF8
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
gfxTextRun *gfxOS2FontGroup::MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
|
|
|
|
const Parameters* aParams, PRUint32 aFlags)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-11-16 12:50:06 -08:00
|
|
|
gfxTextRun *textRun = gfxTextRun::Create(aParams, aString, aLength, this, aFlags);
|
2007-05-20 06:45:49 -07:00
|
|
|
if (!textRun)
|
|
|
|
return nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-12-11 12:51:07 -08:00
|
|
|
mEnableKerning = !(aFlags & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED);
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
textRun->RecordSurrogates(aString);
|
2007-08-19 05:05:23 -07:00
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
nsCAutoString utf8;
|
|
|
|
PRInt32 headerLen = AppendDirectionalIndicatorUTF8(textRun->IsRightToLeft(), utf8);
|
|
|
|
AppendUTF16toUTF8(Substring(aString, aString + aLength), utf8);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
#ifdef DEBUG_thebes_2
|
2007-08-19 05:05:23 -07:00
|
|
|
NS_ConvertUTF8toUTF16 u16(utf8);
|
|
|
|
printf("gfxOS2FontGroup[%#x]::MakeTextRun(PRUnichar %s, %d, %#x, %d)\n",
|
|
|
|
(unsigned)this, NS_LossyConvertUTF16toASCII(u16).get(), aLength, (unsigned)aParams, aFlags);
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2007-08-19 05:05:23 -07:00
|
|
|
|
|
|
|
InitTextRun(textRun, (PRUint8 *)utf8.get(), utf8.Length(), headerLen);
|
|
|
|
|
2007-09-27 09:41:46 -07:00
|
|
|
textRun->FetchGlyphExtents(aParams->mContext);
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
return textRun;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
gfxTextRun *gfxOS2FontGroup::MakeTextRun(const PRUint8* aString, PRUint32 aLength,
|
|
|
|
const Parameters* aParams, PRUint32 aFlags)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-05-20 06:45:49 -07:00
|
|
|
#ifdef DEBUG_thebes_2
|
2007-08-19 05:05:23 -07:00
|
|
|
const char *cStr = reinterpret_cast<const char *>(aString);
|
|
|
|
NS_ConvertASCIItoUTF16 us(cStr, aLength);
|
|
|
|
printf("gfxOS2FontGroup[%#x]::MakeTextRun(PRUint8 %s, %d, %#x, %d)\n",
|
|
|
|
(unsigned)this, NS_LossyConvertUTF16toASCII(us).get(), aLength, (unsigned)aParams, aFlags);
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2007-06-30 15:19:14 -07:00
|
|
|
NS_ASSERTION(aFlags & TEXT_IS_8BIT, "8bit should have been set");
|
2007-11-16 12:50:06 -08:00
|
|
|
gfxTextRun *textRun = gfxTextRun::Create(aParams, aString, aLength, this, aFlags);
|
2007-05-20 06:45:49 -07:00
|
|
|
if (!textRun)
|
|
|
|
return nsnull;
|
|
|
|
|
2007-12-11 12:51:07 -08:00
|
|
|
mEnableKerning = !(aFlags & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED);
|
|
|
|
|
2007-07-08 00:08:04 -07:00
|
|
|
const char *chars = reinterpret_cast<const char *>(aString);
|
2007-05-20 06:45:49 -07:00
|
|
|
PRBool isRTL = textRun->IsRightToLeft();
|
2007-06-30 15:19:14 -07:00
|
|
|
if ((aFlags & TEXT_IS_ASCII) && !isRTL) {
|
|
|
|
// We don't need to send an override character here, the characters must be all
|
|
|
|
// LTR
|
|
|
|
InitTextRun(textRun, (PRUint8 *)chars, aLength, 0);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2007-06-30 15:19:14 -07:00
|
|
|
// Although chars in not necessarily ASCII (as it may point to the low
|
|
|
|
// bytes of any UCS-2 characters < 256), NS_ConvertASCIItoUTF16 seems
|
|
|
|
// to DTRT.
|
|
|
|
NS_ConvertASCIItoUTF16 unicodeString(chars, aLength);
|
2007-05-20 06:45:49 -07:00
|
|
|
nsCAutoString utf8;
|
|
|
|
PRInt32 headerLen = AppendDirectionalIndicatorUTF8(isRTL, utf8);
|
|
|
|
AppendUTF16toUTF8(unicodeString, utf8);
|
2007-06-30 15:19:14 -07:00
|
|
|
InitTextRun(textRun, (PRUint8 *)utf8.get(), utf8.Length(), headerLen);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-09-27 09:41:46 -07:00
|
|
|
textRun->FetchGlyphExtents(aParams->mContext);
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
return textRun;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
void gfxOS2FontGroup::InitTextRun(gfxTextRun *aTextRun, const PRUint8 *aUTF8Text,
|
|
|
|
PRUint32 aUTF8Length,
|
2007-06-30 15:19:14 -07:00
|
|
|
PRUint32 aUTF8HeaderLength)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-05-20 06:45:49 -07:00
|
|
|
CreateGlyphRunsFT(aTextRun, aUTF8Text + aUTF8HeaderLength,
|
|
|
|
aUTF8Length - aUTF8HeaderLength);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
// Helper function to return the leading UTF-8 character in a char pointer
|
|
|
|
// as 32bit number. Also sets the length of the current character (i.e. the
|
|
|
|
// offset to the next one) in the second argument
|
|
|
|
PRUint32 getUTF8CharAndNext(const PRUint8 *aString, PRUint8 *aLength)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-05-20 06:45:49 -07:00
|
|
|
*aLength = 1;
|
|
|
|
if (aString[0] < 0x80) { // normal 7bit ASCII char
|
|
|
|
return aString[0];
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-05-20 06:45:49 -07:00
|
|
|
if ((aString[0] >> 5) == 6) { // two leading ones -> two bytes
|
|
|
|
*aLength = 2;
|
|
|
|
return ((aString[0] & 0x1F) << 6) + (aString[1] & 0x3F);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-05-20 06:45:49 -07:00
|
|
|
if ((aString[0] >> 4) == 14) { // three leading ones -> three bytes
|
|
|
|
*aLength = 3;
|
2007-11-17 11:58:50 -08:00
|
|
|
return ((aString[0] & 0x0F) << 12) + ((aString[1] & 0x3F) << 6) +
|
2007-05-20 06:45:49 -07:00
|
|
|
(aString[2] & 0x3F);
|
|
|
|
}
|
|
|
|
if ((aString[0] >> 4) == 15) { // four leading ones -> four bytes
|
|
|
|
*aLength = 4;
|
2007-11-17 11:58:50 -08:00
|
|
|
return ((aString[0] & 0x07) << 18) + ((aString[1] & 0x3F) << 12) +
|
2007-05-20 06:45:49 -07:00
|
|
|
((aString[2] & 0x3F) << 6) + (aString[3] & 0x3F);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-05-20 06:45:49 -07:00
|
|
|
return aString[0];
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
void gfxOS2FontGroup::CreateGlyphRunsFT(gfxTextRun *aTextRun, const PRUint8 *aUTF8,
|
|
|
|
PRUint32 aUTF8Length)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-05-20 06:45:49 -07:00
|
|
|
#ifdef DEBUG_thebes_2
|
|
|
|
printf("gfxOS2FontGroup::CreateGlyphRunsFT(%#x, _aUTF8_, %d)\n",
|
|
|
|
(unsigned)aTextRun, /*aUTF8,*/ aUTF8Length);
|
2007-08-19 05:05:23 -07:00
|
|
|
for (PRUint32 i = 0; i < FontListLength(); i++) {
|
|
|
|
gfxOS2Font *font = GetFontAt(i);
|
|
|
|
printf(" i=%d, name=%s, size=%f\n", i, NS_LossyConvertUTF16toASCII(font->GetName()).get(),
|
|
|
|
font->GetStyle()->size);
|
|
|
|
}
|
2007-05-20 06:45:49 -07:00
|
|
|
#endif
|
2007-11-17 14:22:04 -08:00
|
|
|
PRUint32 fontlistLast = FontListLength()-1;
|
|
|
|
gfxOS2Font *font0 = GetFontAt(0);
|
2007-05-20 06:45:49 -07:00
|
|
|
const PRUint8 *p = aUTF8;
|
|
|
|
PRUint32 utf16Offset = 0;
|
|
|
|
gfxTextRun::CompressedGlyph g;
|
|
|
|
const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
|
|
|
|
|
2007-11-17 14:22:04 -08:00
|
|
|
aTextRun->AddGlyphRun(font0, 0);
|
|
|
|
// a textRun likely has the same font for most of the characters, so we can
|
|
|
|
// lock it before the loop for efficiency
|
|
|
|
FT_Face face0 = cairo_ft_scaled_font_lock_face(font0->CairoScaledFont());
|
2007-05-20 06:45:49 -07:00
|
|
|
while (p < aUTF8 + aUTF8Length) {
|
2007-11-17 14:22:04 -08:00
|
|
|
PRBool glyphFound = PR_FALSE;
|
2007-05-20 06:45:49 -07:00
|
|
|
// convert UTF-8 character and step to the next one in line
|
|
|
|
PRUint8 chLen;
|
|
|
|
PRUint32 ch = getUTF8CharAndNext(p, &chLen);
|
|
|
|
p += chLen; // move to next char
|
|
|
|
#ifdef DEBUG_thebes_2
|
2007-11-17 14:22:04 -08:00
|
|
|
printf("\'%c\' (%d, %#x, %s) [%#x %#x]:", (char)ch, ch, ch, ch >=0x10000 ? "non-BMP!" : "BMP", ch >=0x10000 ? H_SURROGATE(ch) : 0, ch >=0x10000 ? L_SURROGATE(ch) : 0);
|
2007-05-20 06:45:49 -07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (ch == 0) {
|
2007-05-28 15:00:00 -07:00
|
|
|
// treat this null byte as a missing glyph, don't create a glyph for it
|
2007-05-20 06:45:49 -07:00
|
|
|
aTextRun->SetMissingGlyph(utf16Offset, 0);
|
|
|
|
} else {
|
2007-11-17 14:22:04 -08:00
|
|
|
// Try to get a glyph from all fonts available to us.
|
|
|
|
// Once we found it in one of the fonts we quit the loop early.
|
|
|
|
// If we don't find the glyph, we set the missing glyph symbol after
|
|
|
|
// trying the last font.
|
|
|
|
for (PRUint32 i = 0; i <= fontlistLast; i++) {
|
|
|
|
gfxOS2Font *font = font0;
|
|
|
|
FT_Face face = face0;
|
|
|
|
if (i > 0) {
|
|
|
|
font = GetFontAt(i);
|
|
|
|
face = cairo_ft_scaled_font_lock_face(font->CairoScaledFont());
|
|
|
|
#ifdef DEBUG_thebes_2
|
|
|
|
if (i == fontlistLast) {
|
|
|
|
printf("Last font %d (%s) for ch=%#x (pos=%d)",
|
|
|
|
i, NS_LossyConvertUTF16toASCII(font->GetName()).get(), ch, utf16Offset);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
// select the current font into the text run
|
|
|
|
aTextRun->AddGlyphRun(font, utf16Offset);
|
|
|
|
|
|
|
|
NS_ASSERTION(!IsInvalidChar(ch), "Invalid char detected");
|
|
|
|
FT_UInt gid = FT_Get_Char_Index(face, ch); // find the glyph id
|
|
|
|
PRInt32 advance = 0;
|
|
|
|
if (gid == font->GetSpaceGlyph()) {
|
|
|
|
advance = (int)(font->GetMetrics().spaceWidth * appUnitsPerDevUnit);
|
|
|
|
} else if (gid == 0) {
|
|
|
|
advance = -1; // trigger the missing glyphs case below
|
|
|
|
} else {
|
2007-12-11 12:51:07 -08:00
|
|
|
// find next character and its glyph -- in case they exist
|
|
|
|
// and exist in the current font face -- to compute kerning
|
|
|
|
PRUint32 chNext = 0;
|
|
|
|
FT_UInt gidNext = 0;
|
|
|
|
FT_Pos lsbDeltaNext = 0;
|
|
|
|
#ifdef DEBUG_thebes_2
|
|
|
|
printf("(kerning=%s/%s)", mEnableKerning ? "enable" : "disable", FT_HAS_KERNING(face) ? "yes" : "no");
|
|
|
|
#endif
|
|
|
|
if (mEnableKerning && FT_HAS_KERNING(face) && p < aUTF8 + aUTF8Length) {
|
|
|
|
chNext = getUTF8CharAndNext(p, &chLen);
|
|
|
|
if (chNext) {
|
|
|
|
gidNext = FT_Get_Char_Index(face, chNext);
|
|
|
|
if (gidNext && gidNext != font->GetSpaceGlyph()) {
|
|
|
|
FT_Load_Glyph(face, gidNext, FT_LOAD_DEFAULT);
|
|
|
|
lsbDeltaNext = face->glyph->lsb_delta;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// now load the current glyph
|
2007-11-17 14:22:04 -08:00
|
|
|
FT_Load_Glyph(face, gid, FT_LOAD_DEFAULT); // load glyph into the slot
|
2007-12-11 12:51:07 -08:00
|
|
|
advance = face->glyph->advance.x;
|
|
|
|
|
|
|
|
// now add kerning to the current glyph's advance
|
|
|
|
if (chNext && gidNext) {
|
|
|
|
FT_Vector kerning;
|
|
|
|
FT_Get_Kerning(face, gid, gidNext, FT_KERNING_DEFAULT, &kerning);
|
|
|
|
advance += kerning.x;
|
|
|
|
if (face->glyph->rsb_delta - lsbDeltaNext >= 32) {
|
|
|
|
advance -= 64;
|
|
|
|
} else if (face->glyph->rsb_delta - lsbDeltaNext < -32) {
|
|
|
|
advance += 64;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// now apply unit conversion and scaling
|
|
|
|
advance = (advance >> 6) * appUnitsPerDevUnit;
|
2007-11-17 14:22:04 -08:00
|
|
|
}
|
2007-05-20 06:45:49 -07:00
|
|
|
#ifdef DEBUG_thebes_2
|
2007-11-17 14:22:04 -08:00
|
|
|
printf(" gid=%d, advance=%d (%s)\n", gid, advance,
|
|
|
|
NS_LossyConvertUTF16toASCII(font->GetName()).get());
|
2007-05-20 06:45:49 -07:00
|
|
|
#endif
|
2007-08-19 05:05:23 -07:00
|
|
|
|
2007-11-17 14:22:04 -08:00
|
|
|
if (advance >= 0 &&
|
|
|
|
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
|
|
|
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(gid))
|
|
|
|
{
|
|
|
|
aTextRun->SetSimpleGlyph(utf16Offset,
|
|
|
|
g.SetSimpleGlyph(advance, gid));
|
|
|
|
glyphFound = PR_TRUE;
|
|
|
|
} else if (gid == 0) {
|
|
|
|
// gid = 0 only happens when the glyph is missing from the font
|
|
|
|
if (i == fontlistLast) {
|
|
|
|
// set the missing glyph only when it's missing from the very
|
|
|
|
// last font
|
|
|
|
aTextRun->SetMissingGlyph(utf16Offset, ch);
|
|
|
|
}
|
|
|
|
glyphFound = PR_FALSE;
|
|
|
|
} else {
|
|
|
|
gfxTextRun::DetailedGlyph details;
|
|
|
|
details.mGlyphID = gid;
|
|
|
|
NS_ASSERTION(details.mGlyphID == gid, "Seriously weird glyph ID detected!");
|
|
|
|
details.mAdvance = advance;
|
|
|
|
details.mXOffset = 0;
|
|
|
|
details.mYOffset = 0;
|
|
|
|
g.SetComplex(aTextRun->IsClusterStart(utf16Offset), PR_TRUE, 1);
|
|
|
|
aTextRun->SetGlyphs(utf16Offset, g, &details);
|
|
|
|
glyphFound = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i > 0) {
|
|
|
|
cairo_ft_scaled_font_unlock_face(font->CairoScaledFont());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (glyphFound) {
|
|
|
|
break;
|
|
|
|
}
|
2007-05-20 06:45:49 -07:00
|
|
|
}
|
2007-11-17 14:22:04 -08:00
|
|
|
} // for all fonts
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-11-17 14:22:04 -08:00
|
|
|
NS_ASSERTION(!IS_SURROGATE(ch), "Surrogates shouldn't appear in UTF8");
|
|
|
|
if (ch >= 0x10000) {
|
|
|
|
// This character is a surrogate pair in UTF16
|
|
|
|
++utf16Offset;
|
2007-05-20 06:45:49 -07:00
|
|
|
}
|
2007-11-17 14:22:04 -08:00
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
++utf16Offset;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-11-17 14:22:04 -08:00
|
|
|
cairo_ft_scaled_font_unlock_face(font0->CairoScaledFont());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-20 06:45:49 -07:00
|
|
|
PRBool gfxOS2FontGroup::FontCallback(const nsAString& aFontName,
|
|
|
|
const nsACString& aGenericName,
|
|
|
|
void *aClosure)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
nsStringArray *sa = static_cast<nsStringArray*>(aClosure);
|
2007-05-20 06:45:49 -07:00
|
|
|
if (sa->IndexOf(aFontName) < 0) {
|
|
|
|
sa->AppendString(aFontName);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-05-20 06:45:49 -07:00
|
|
|
return PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|