--- mozilla/config/autoconf.mk.in.foo 2004-03-20 21:31:17.000000000 -0500 +++ mozilla/config/autoconf.mk.in 2004-10-18 22:49:40.000000000 -0400 @@ -376,6 +376,10 @@ MOZ_XFT_LIBS = @MOZ_XFT_LIBS@ MOZ_ENABLE_COREXFONTS = @MOZ_ENABLE_COREXFONTS@ +MOZ_ENABLE_PANGO = @MOZ_ENABLE_PANGO@ +MOZ_PANGO_CFLAGS = @MOZ_PANGO_CFLAGS@ +MOZ_PANGO_LIBS = @MOZ_PANGO_LIBS@ + MOZ_EXTRA_X11CONVERTERS = @MOZ_EXTRA_X11CONVERTERS@ MOZ_ENABLE_XINERAMA = @MOZ_ENABLE_XINERAMA@ --- mozilla/gfx/src/gtk/nsGfxFactoryGTK.cpp.foo 2003-09-07 18:20:38.000000000 -0400 +++ mozilla/gfx/src/gtk/nsGfxFactoryGTK.cpp 2004-10-18 22:49:40.000000000 -0400 @@ -62,6 +62,9 @@ #ifdef NATIVE_THEME_SUPPORT #include "nsNativeThemeGTK.h" #endif +#ifdef MOZ_ENABLE_PANGO +#include "nsFontMetricsPango.h" +#endif #ifdef MOZ_ENABLE_XFT #include "nsFontMetricsXft.h" #endif @@ -112,6 +115,13 @@ if (aOuter) return NS_ERROR_NO_AGGREGATION; +#ifdef MOZ_ENABLE_PANGO + if (NS_IsPangoEnabled()) { + result = new nsFontMetricsPango(); + if (!result) + return NS_ERROR_OUT_OF_MEMORY; + } else { +#endif #ifdef MOZ_ENABLE_XFT if (NS_IsXftEnabled()) { result = new nsFontMetricsXft(); @@ -127,6 +137,9 @@ #ifdef MOZ_ENABLE_XFT } #endif +#ifdef MOZ_ENABLE_PANGO + } +#endif NS_ADDREF(result); nsresult rv = result->QueryInterface(aIID, aResult); @@ -148,6 +161,13 @@ if (aOuter) return NS_ERROR_NO_AGGREGATION; +#ifdef MOZ_ENABLE_PANGO + if (NS_IsPangoEnabled()) { + result = new nsFontEnumeratorPango(); + if (!result) + return NS_ERROR_OUT_OF_MEMORY; + } else { +#endif #ifdef MOZ_ENABLE_XFT if (NS_IsXftEnabled()) { result = new nsFontEnumeratorXft(); @@ -163,6 +183,9 @@ #ifdef MOZ_ENABLE_XFT } #endif +#ifdef MOZ_ENABLE_PANGO + } +#endif NS_ADDREF(result); nsresult rv = result->QueryInterface(aIID, aResult); --- /dev/null 2004-02-18 10:26:44.000000000 -0500 +++ mozilla/gfx/src/gtk/mozilla-decoder.h 2004-10-18 22:49:40.000000000 -0400 @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:expandtab:shiftwidth=4:tabstop=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.org code. + * + * The Initial Developer of the Original Code is Christopher Blizzard + * . Portions created by the Initial Developer + * are Copyright (C) 2004 the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 _MOZILLA_DECODER_H +#define _MOZILLA_DECODER_H + +#include + +G_BEGIN_DECLS + +#define MOZILLA_TYPE_DECODER (mozilla_decoder_get_type()) +#define MOZILLA_DECODER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOZILLA_TYPE_DECODER, MozillaDecoder)) +#define MOZILLA_IS_DECODER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOZILLA_TYPE_DECODER)) + +typedef struct _MozillaDecoder MozillaDecoder; +typedef struct _MozillaDecoderClass MozillaDecoderClass; + +#define MOZILLA_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOZILLA_TYPE_DECODER, MozillaDecoderClass)) +#define MOZILLA_IS_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOZILLA_TYPE_DECODER)) +#define MOZILLA_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOZILLA_TYPE_DECODER, MozillaDecoderClass)) + +struct _MozillaDecoder +{ + PangoFcDecoder parent_instance; +}; + +struct _MozillaDecoderClass +{ + PangoFcDecoderClass parent_class; +}; + +GType mozilla_decoder_get_type (void); +int mozilla_decoders_init (void); + +G_END_DECLS + +#endif /*_MOZILLA_DECODER_H */ --- /dev/null 2004-02-18 10:26:44.000000000 -0500 +++ mozilla/gfx/src/gtk/mozilla-decoder.cpp 2004-10-18 22:49:40.000000000 -0400 @@ -0,0 +1,376 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:expandtab:shiftwidth=4:tabstop=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.org code. + * + * The Initial Developer of the Original Code is Christopher Blizzard + * . Portions created by the Initial Developer + * are Copyright (C) 2004 the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#define PANGO_ENABLE_BACKEND +#define PANGO_ENABLE_ENGINE + +#include "mozilla-decoder.h" +#include +#include +#include +#include + +#include "nsString.h" +#include "nsIPersistentProperties2.h" +#include "nsNetUtil.h" +#include "nsReadableUtils.h" +#include "nsICharsetConverterManager.h" +#include "nsICharRepresentable.h" +#include "nsCompressedCharMap.h" + +#undef DEBUG_CUSTOM_ENCODER + +G_DEFINE_TYPE (MozillaDecoder, mozilla_decoder, PANGO_TYPE_FC_DECODER) + +MozillaDecoder *mozilla_decoder_new (void); + +static FcCharSet *mozilla_decoder_get_charset (PangoFcDecoder *decoder, + PangoFcFont *fcfont); +static PangoGlyph mozilla_decoder_get_glyph (PangoFcDecoder *decoder, + PangoFcFont *fcfont, + guint32 wc); + +static PangoFcDecoder *mozilla_find_decoder (FcPattern *pattern, + gpointer user_data); + +typedef struct _MozillaDecoderPrivate MozillaDecoderPrivate; + +#define MOZILLA_DECODER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MOZILLA_TYPE_DECODER, MozillaDecoderPrivate)) + +struct _MozillaDecoderPrivate { + char *family; + char *encoder; + char *cmap; + gboolean is_wide; + FcCharSet *charset; + nsCOMPtr uEncoder; +}; + +static nsICharsetConverterManager *gCharsetManager = NULL; + +static NS_DEFINE_CID(kCharsetConverterManagerCID, + NS_ICHARSETCONVERTERMANAGER_CID); + +// Hash tables that hold the custom encodings and custom cmaps used in +// various fonts. +GHashTable *encoder_hash = NULL; +GHashTable *cmap_hash = NULL; +GHashTable *wide_hash = NULL; + +void +mozilla_decoder_init (MozillaDecoder *decoder) +{ +} + +void +mozilla_decoder_class_init (MozillaDecoderClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + PangoFcDecoderClass *parent_class = PANGO_FC_DECODER_CLASS (klass); + + /* object_class->finalize = test_finalize; */ + + parent_class->get_charset = mozilla_decoder_get_charset; + parent_class->get_glyph = mozilla_decoder_get_glyph; + + g_type_class_add_private (object_class, sizeof (MozillaDecoderPrivate)); +} + +MozillaDecoder * +mozilla_decoder_new(void) +{ + return (MozillaDecoder *)g_object_new(MOZILLA_TYPE_DECODER, NULL); +} + +#ifdef DEBUG_CUSTOM_ENCODER +void +dump_hash(char *key, char *val, void *arg) +{ + printf("%s -> %s\n", key, val); +} +#endif + +/** + * mozilla_decoders_init: + * + * #mozilla_decoders_init: + * + * This initializes all of the application-specific custom decoders + * that Mozilla uses. This should only be called once during the + * lifetime of the application. + * + * Return value: zero on success, not zero on failure. + * + **/ + +int +mozilla_decoders_init(void) +{ + static PRBool initialized = PR_FALSE; + if (initialized) + return 0; + + encoder_hash = g_hash_table_new(g_str_hash, g_str_equal); + cmap_hash = g_hash_table_new(g_str_hash, g_str_equal); + wide_hash = g_hash_table_new(g_str_hash, g_str_equal); + + PRBool dumb = PR_FALSE; + nsCOMPtr props; + nsCOMPtr encodeEnum; + + NS_LoadPersistentPropertiesFromURISpec(getter_AddRefs(props), + NS_LITERAL_CSTRING("resource://gre/res/fonts/pangoFontEncoding.properties")); + + if (!props) + goto loser; + + // Enumerate the properties in this file and figure out all of the + // fonts for which we have custom encodings. + props->Enumerate(getter_AddRefs(encodeEnum)); + if (!encodeEnum) + goto loser; + + while (encodeEnum->HasMoreElements(&dumb), dumb) { + nsCOMPtr prop; + encodeEnum->GetNext(getter_AddRefs(prop)); + if (!prop) + goto loser; + + nsCAutoString name; + prop->GetKey(name); + nsAutoString value; + prop->GetValue(value); + + if (!StringBeginsWith(name, NS_LITERAL_CSTRING("encoding."))) { + printf("string doesn't begin with encoding?\n"); + continue; + } + + name = Substring(name, 9); + + if (StringEndsWith(name, NS_LITERAL_CSTRING(".ttf"))) { + name = Substring(name, 0, name.Length() - 4); + + // Strip off a .wide if it's there. + if (StringEndsWith(value, NS_LITERAL_STRING(".wide"))) { + g_hash_table_insert(wide_hash, g_strdup(name.get()), + g_strdup("wide")); + value = Substring(value, 0, name.Length() - 5); + } + + g_hash_table_insert(encoder_hash, + g_strdup(name.get()), + g_strdup(NS_ConvertUTF16toUTF8(value).get())); + } + else if (StringEndsWith(name, NS_LITERAL_CSTRING(".ftcmap"))) { + name = Substring(name, 0, name.Length() - 7); + g_hash_table_insert(cmap_hash, + g_strdup(name.get()), + g_strdup(NS_ConvertUTF16toUTF8(value).get())); + } + else { + printf("unknown suffix used for mapping\n"); + } + } + + pango_fc_font_map_add_decoder_find_func(PANGO_FC_FONT_MAP(pango_xft_get_font_map(GDK_DISPLAY(),gdk_x11_get_default_screen())), + mozilla_find_decoder, + NULL, + NULL); + + initialized = PR_TRUE; + +#ifdef DEBUG_CUSTOM_ENCODER + printf("*** encoders\n"); + g_hash_table_foreach(encoder_hash, (GHFunc)dump_hash, NULL); + + printf("*** cmaps\n"); + g_hash_table_foreach(cmap_hash, (GHFunc)dump_hash, NULL); +#endif + + return 0; + + loser: + return -1; +} + +FcCharSet * +mozilla_decoder_get_charset (PangoFcDecoder *decoder, + PangoFcFont *fcfont) +{ + MozillaDecoderPrivate *priv = MOZILLA_DECODER_GET_PRIVATE(decoder); + + if (priv->charset) + return priv->charset; + + // First time this has been accessed. Populate the charset. + priv->charset = FcCharSetCreate(); + + if (!gCharsetManager) { + nsServiceManager::GetService(kCharsetConverterManagerCID, + NS_GET_IID(nsICharsetConverterManager), (nsISupports**)&gCharsetManager); + } + + nsCOMPtr encoder; + nsCOMPtr represent; + + if (!gCharsetManager) + goto end; + + gCharsetManager->GetUnicodeEncoderRaw(priv->encoder, getter_AddRefs(encoder)); + if (!encoder) + goto end; + + encoder->SetOutputErrorBehavior(encoder->kOnError_Replace, nsnull, '?'); + + priv->uEncoder = encoder; + + represent = do_QueryInterface(encoder); + if (!represent) + goto end; + + PRUint32 map[UCS2_MAP_LEN]; + memset(map, 0, sizeof(map)); + + represent->FillInfo(map); + + for (int i = 0; i < NUM_UNICODE_CHARS; i++) { + if (IS_REPRESENTABLE(map, i)) + FcCharSetAddChar(priv->charset, i); + } + + end: + return priv->charset; +} + +PangoGlyph +mozilla_decoder_get_glyph (PangoFcDecoder *decoder, + PangoFcFont *fcfont, + guint32 wc) +{ + MozillaDecoderPrivate *priv = MOZILLA_DECODER_GET_PRIVATE(decoder); + + PangoGlyph retval = 0; + PRUnichar inchar = wc; + PRInt32 inlen = 1; + char outchar[2] = {0,0}; + PRInt32 outlen = 2; + + priv->uEncoder->Convert(&inchar, &inlen, outchar, &outlen); + if (outlen != 1) { + printf("Warning: mozilla_decoder_get_glyph doesn't support more than one character conversions.\n"); + return 0; + } + + FT_Face face = pango_fc_font_lock_face(fcfont); + +#ifdef DEBUG_CUSTOM_ENCODER + char *filename; + FcPatternGetString(fcfont->font_pattern, FC_FILE, 0, (FcChar8 **)&filename); + printf("filename is %s\n", filename); +#endif + + // Make sure to set the right charmap before trying to get the + // glyph + if (priv->cmap) { + if (!strcmp(priv->cmap, "mac_roman")) { + FT_Select_Charmap(face, ft_encoding_apple_roman); + } + else if (!strcmp(priv->cmap, "unicode")) { + FT_Select_Charmap(face, ft_encoding_unicode); + } + else { + printf("Warning: Invalid charmap entry for family %s\n", + priv->family); + } + } + + // Standard 8 bit to glyph translation + if (!priv->is_wide) { + FcChar32 blah = PRUint8(outchar[0]); + retval = FT_Get_Char_Index(face, blah); +#ifdef DEBUG_CUSTOM_ENCODER + printf("wc 0x%x outchar[0] 0x%x index 0x%x retval 0x%x face %p\n", + wc, outchar[0], blah, retval, (void *)face); +#endif + } + else { + printf("Warning: We don't support .wide fonts!\n"); + retval = 0; + } + + pango_fc_font_unlock_face(fcfont); + + return retval; +} + +PangoFcDecoder * +mozilla_find_decoder (FcPattern *pattern, gpointer user_data) +{ + // Compare the family name of the font that's been opened to see + // if we have a custom decoder. + const char *orig = NULL; + FcPatternGetString(pattern, FC_FAMILY, 0, (FcChar8 **)&orig); + + nsCAutoString family; + family.Assign(orig); + + family.StripWhitespace(); + ToLowerCase(family); + + char *encoder = (char *)g_hash_table_lookup(encoder_hash, family.get()); + if (!encoder) + return NULL; + + MozillaDecoder *decoder = mozilla_decoder_new(); + + MozillaDecoderPrivate *priv = MOZILLA_DECODER_GET_PRIVATE(decoder); + + priv->family = g_strdup(family.get()); + priv->encoder = g_strdup(encoder); + + char *cmap = (char *)g_hash_table_lookup(cmap_hash, family.get()); + if (cmap) + priv->cmap = g_strdup(cmap); + + char *wide = (char *)g_hash_table_lookup(wide_hash, family.get()); + if (wide) + priv->is_wide = TRUE; + + return PANGO_FC_DECODER(decoder); +} --- mozilla/gfx/src/gtk/gfxgtk.pkg.foo 2004-01-06 20:21:35.000000000 -0500 +++ mozilla/gfx/src/gtk/gfxgtk.pkg 2004-10-18 22:49:40.000000000 -0400 @@ -7,3 +7,6 @@ #if MOZ_ENABLE_XFT dist/bin/res/fonts/fontEncoding.properties #endif +#if MOZ_ENABLE_PANGO +dist/bin/res/fonts/pangoFontEncoding.properties +#endif --- mozilla/gfx/src/gtk/nsFontMetricsXft.cpp.foo 2004-04-05 15:18:43.000000000 -0400 +++ mozilla/gfx/src/gtk/nsFontMetricsXft.cpp 2004-10-18 22:49:40.000000000 -0400 @@ -238,7 +238,7 @@ static int CalculateSlant (PRUint8 aStyle); static int CalculateWeight (PRUint16 aWeight); -static void AddLangGroup (FcPattern *aPattern, nsIAtom *aLangGroup); +/* static */ void AddLangGroup (FcPattern *aPattern, nsIAtom *aLangGroup); static void AddFFRE (FcPattern *aPattern, nsCString *aFamily, PRBool aWeak); static void FFREToFamily (nsACString &aFFREName, nsACString &oFamily); @@ -449,7 +449,7 @@ // Make sure that the pixel size is at least greater than zero if (mPixelSize < 1) { #ifdef DEBUG - printf("*** Warning: nsFontMetricsXft was passed a pixel size of %d\n", + printf("*** Warning: nsFontMetricsXft was passed a pixel size of %f\n", mPixelSize); #endif mPixelSize = 1; @@ -474,6 +474,26 @@ if (NS_FAILED(RealizeFont())) return NS_ERROR_FAILURE; +#ifdef DEBUG_foo + printf("%i\n", mXHeight); + printf("%i\n", mSuperscriptOffset); + printf("%i\n", mSubscriptOffset); + printf("%i\n", mStrikeoutOffset); + printf("%i\n", mStrikeoutSize); + printf("%i\n", mUnderlineOffset); + printf("%i\n", mUnderlineSize); + printf("%i\n", mMaxHeight); + printf("%i\n", mLeading); + printf("%i\n", mEmHeight); + printf("%i\n", mEmAscent); + printf("%i\n", mEmDescent); + printf("%i\n", mMaxAscent); + printf("%i\n", mMaxDescent); + printf("%i\n", mMaxAdvance); + printf("%i\n", mSpaceWidth); + printf("%i\n", mAveCharWidth); +#endif /* DEBUG_foo */ + return NS_OK; } @@ -530,6 +550,10 @@ f = mDeviceContext->DevUnitsToAppUnits(); aWidth = NSToCoordRound(glyphInfo.xOff * f); +#ifdef DEBUG_foo + printf("GetWidth (char *) %d\n", aWidth); +#endif + return NS_OK; } @@ -553,6 +577,10 @@ if (aFontID) *aFontID = 0; +#ifdef DEBUG_foo + printf("GetWidth %d\n", aWidth); +#endif + return NS_OK; } @@ -586,6 +614,11 @@ if (nsnull != aFontID) *aFontID = 0; +#ifdef DEBUG_foo + printf("GetTextDimensions %d %d %d\n", aDimensions.width, + aDimensions.ascent, aDimensions.descent); +#endif + return NS_OK; } @@ -645,6 +678,10 @@ nsAutoDrawSpecBuffer drawBuffer(data.draw, &data.color); data.drawBuffer = &drawBuffer; +#ifdef DEBUG_foo + printf("DrawString (char *)\n"); +#endif + return EnumerateGlyphs(aString, aLength, &nsFontMetricsXft::DrawStringCallback, &data); } @@ -675,6 +712,10 @@ nsAutoDrawSpecBuffer drawBuffer(data.draw, &data.color); data.drawBuffer = &drawBuffer; +#ifdef DEBUG_foo + printf("DrawString\n"); +#endif + return EnumerateGlyphs(aString, aLength, &nsFontMetricsXft::DrawStringCallback, &data); } @@ -714,6 +755,15 @@ aBoundingMetrics.ascent = NSToCoordRound(aBoundingMetrics.ascent * P2T); aBoundingMetrics.descent = NSToCoordRound(aBoundingMetrics.descent * P2T); +#ifdef DEBUG_foo + printf("GetBoundingMetrics (char *)%d %d %d %d %d\n", + aBoundingMetrics.leftBearing, + aBoundingMetrics.rightBearing, + aBoundingMetrics.width, + aBoundingMetrics.ascent, + aBoundingMetrics.descent); +#endif + return NS_OK; } @@ -755,6 +805,15 @@ if (nsnull != aFontID) *aFontID = 0; +#ifdef DEBUG_foo + printf("GetBoundingMetrics %d %d %d %d %d\n", + aBoundingMetrics.leftBearing, + aBoundingMetrics.rightBearing, + aBoundingMetrics.width, + aBoundingMetrics.ascent, + aBoundingMetrics.descent); +#endif + return NS_OK; } @@ -766,6 +825,12 @@ return nsnull; } +nsresult +nsFontMetricsXft::SetRightToLeftText(PRBool aIsRTL) +{ + return NS_OK; +} + PRUint32 nsFontMetricsXft::GetHints(void) { --- mozilla/gfx/src/gtk/Makefile.in.foo 2003-11-10 07:24:51.000000000 -0500 +++ mozilla/gfx/src/gtk/Makefile.in 2004-10-18 22:51:01.000000000 -0400 @@ -102,6 +102,12 @@ nsFontMetricsXft.cpp endif +ifdef MOZ_ENABLE_PANGO +CPPSRCS += \ + nsFontMetricsPango.cpp \ + mozilla-decoder.cpp +endif + ifdef MOZ_ENABLE_GTK CPPSRCS += \ nsRegionGTK.cpp \ @@ -155,10 +161,10 @@ endif ifdef MOZ_ENABLE_XFT -libs:: fontEncoding.properties +libs:: fontEncoding.properties pangoFontEncoding.properties $(INSTALL) $^ $(DIST)/bin/res/fonts -install:: fontEncoding.properties +install:: fontEncoding.properties pangoFontEncoding.properties $(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/res/fonts endif --- /dev/null 2004-02-18 10:26:44.000000000 -0500 +++ mozilla/gfx/src/gtk/pangoFontEncoding.properties 2004-10-18 22:49:40.000000000 -0400 @@ -0,0 +1,120 @@ +# ***** 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 MathML Project. +# +# The Initial Developer of the Original Code is +# The University of Queensland. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Roger B. Sidje +# Jungshik Shin +# Christopher Blizzard +# +# 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 ***** + +# LOCALIZATION NOTE: FILE +# Do not translate anything in this file + +# This file contains supported custom encodings for pango font +# rendering. For information about the specific encodings, look at +# fontEncoding.properties. It contains a lot more verbiage than you +# will find here. There are a lot of encodings supported in the old +# encoding file that pango supports directly, so there should be +# little reason to use those custom encodings. The pango custom code +# doesn't support .wide fonts, so consider yourself warned! +# + +# To be honest, we basically support mathml and that's about it. + +encoding.cmr10.ttf = x-ttf-cmr +encoding.cmmi10.ttf = x-ttf-cmmi +encoding.cmsy10.ttf = x-ttf-cmsy +encoding.cmex10.ttf = x-ttf-cmex + +encoding.cmr10.ftcmap = unicode +encoding.cmmi10.ftcmap = unicode +encoding.cmsy10.ftcmap = unicode +encoding.cmex10.ftcmap = unicode + +encoding.math1.ttf = x-mathematica1 +encoding.math1-bold.ttf = x-mathematica1 +encoding.math1mono.ttf = x-mathematica1 +encoding.math1mono-bold.ttf = x-mathematica1 + +encoding.math2.ttf = x-mathematica2 +encoding.math2-bold.ttf = x-mathematica2 +encoding.math2mono.ttf = x-mathematica2 +encoding.math2mono-bold.ttf = x-mathematica2 + +encoding.math3.ttf = x-mathematica3 +encoding.math3-bold.ttf = x-mathematica3 +encoding.math3mono.ttf = x-mathematica3 +encoding.math3mono-bold.ttf = x-mathematica3 + +encoding.math4.ttf = x-mathematica4 +encoding.math4-bold.ttf = x-mathematica4 +encoding.math4mono.ttf = x-mathematica4 +encoding.math4mono-bold.ttf = x-mathematica4 + +encoding.math5.ttf = x-mathematica5 +encoding.math5-bold.ttf = x-mathematica5 +encoding.math5bold.ttf = x-mathematica5 +encoding.math5mono.ttf = x-mathematica5 +encoding.math5mono-bold.ttf = x-mathematica5 +encoding.math5monobold.ttf = x-mathematica5 + +encoding.math1.ftcmap = mac_roman +encoding.math1-bold.ftcmap = mac_roman +encoding.math1mono.ftcmap = mac_roman +encoding.math1mono-bold.ftcmap = mac_roman + +encoding.math2.ftcmap = mac_roman +encoding.math2-bold.ftcmap = mac_roman +encoding.math2mono.ftcmap = mac_roman +encoding.math2mono-bold.ftcmap = mac_roman + +encoding.math3.ftcmap = mac_roman +encoding.math3-bold.ftcmap = mac_roman +encoding.math3mono.ftcmap = mac_roman +encoding.math3mono-bold.ftcmap = mac_roman + +encoding.math4.ftcmap = mac_roman +encoding.math4-bold.ftcmap = mac_roman +encoding.math4mono.ftcmap = mac_roman +encoding.math4mono-bold.ftcmap = mac_roman + +encoding.math5.ftcmap = mac_roman +encoding.math5-bold.ftcmap = mac_roman +encoding.math5bold.ftcmap = mac_roman +encoding.math5mono.ftcmap = mac_roman +encoding.math5mono-bold.ftcmap = mac_roman +encoding.math5monobold.ftcmap = mac_roman + +encoding.mtextra.ttf = x-mtextra +encoding.mtextra.ftcmap = mac_roman + --- mozilla/gfx/src/gtk/nsFontMetricsUtils.cpp.foo 2002-10-11 22:03:32.000000000 -0400 +++ mozilla/gfx/src/gtk/nsFontMetricsUtils.cpp 2004-10-18 22:51:32.000000000 -0400 @@ -50,11 +50,20 @@ #include "nsFontMetricsGTK.h" #endif +#ifdef MOZ_ENABLE_PANGO +#include "nsFontMetricsPango.h" +#endif + #include "nsFontMetricsUtils.h" PRUint32 NS_FontMetricsGetHints(void) { +#ifdef MOZ_ENABLE_PANGO + if (NS_IsPangoEnabled()) { + return nsFontMetricsPango::GetHints(); + } +#endif #ifdef MOZ_ENABLE_XFT if (NS_IsXftEnabled()) { return nsFontMetricsXft::GetHints(); @@ -69,6 +78,11 @@ nsresult NS_FontMetricsFamilyExists(nsIDeviceContext *aDevice, const nsString &aName) { +#ifdef MOZ_ENABLE_PANGO + if (NS_IsPangoEnabled()) { + return nsFontMetricsPango::FamilyExists(aDevice, aName); + } +#endif #ifdef MOZ_ENABLE_XFT // try to fall through to the core fonts if xft fails if (NS_IsXftEnabled()) { @@ -121,3 +135,17 @@ } #endif /* MOZ_ENABLE_XFT */ + +#ifdef MOZ_ENABLE_PANGO + +PRBool +NS_IsPangoEnabled(void) +{ + char *val = PR_GetEnv("MOZ_ENABLE_PANGO"); + if (val) + return TRUE; + + return FALSE; +} + +#endif --- /dev/null 2004-02-18 10:26:44.000000000 -0500 +++ mozilla/gfx/src/gtk/nsFontMetricsPango.cpp 2004-10-18 22:49:40.000000000 -0400 @@ -0,0 +1,1662 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:expandtab:shiftwidth=4:tabstop=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.org code. + * + * The Initial Developer of the Original Code is Christopher Blizzard + * . Portions created by the Initial Developer + * are Copyright (C) 2004 the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 "nsFont.h" +#include "nsIDeviceContext.h" +#include "nsICharsetConverterManager.h" +#include "nsIPref.h" +#include "nsIServiceManagerUtils.h" + +#define PANGO_ENABLE_BACKEND +#define PANGO_ENABLE_ENGINE + +#include "nsFontMetricsPango.h" +#include "nsRenderingContextGTK.h" +#include "nsDeviceContextGTK.h" + +#include "nsUnicharUtils.h" +#include "nsQuickSort.h" + +#include +#include +#include +#include +#include + +#include "mozilla-decoder.h" + +#define FORCE_PR_LOG +#include "prlog.h" + +// Globals + +static PRLogModuleInfo *gPangoFontLog; +static int gNumInstances; + +// Defines + +// This is the scaling factor that we keep fonts limited to against +// the display size. If a pixel size is requested that is more than +// this factor larger than the height of the display, it's clamped to +// that value instead of the requested size. +#define FONT_MAX_FONT_SCALE 2 + +static NS_DEFINE_CID(kCharsetConverterManagerCID, + NS_ICHARSETCONVERTERMANAGER_CID); + +struct MozPangoLangGroup { + const char *mozLangGroup; + const char *PangoLang; +}; + +static const MozPangoLangGroup MozPangoLangGroups[] = { + { "x-western", "en" }, + { "x-central-euro", "pl" }, + { "x-cyrillic", "ru" }, + { "x-baltic", "lv" }, + { "x-devanagari", "hi" }, + { "x-tamil", "ta" }, + { "x-unicode", 0 }, + { "x-user-def", 0 }, +}; + +#define NUM_PANGO_LANG_GROUPS (sizeof (MozPangoLangGroups) / \ + sizeof (MozPangoLangGroups[0])) + +#ifdef DEBUG +#define DUMP_PRUNICHAR(ustr, ulen) for (PRUint32 llen=0;llen> 6) +#define CONVERT_DESIGN_UNITS_TO_PIXELS(v, s) \ + MOZ_FT_TRUNC(MOZ_FT_ROUND(FT_MulFix((v) , (s)))) + +// Static function decls + +static PRBool IsASCIIFontName (const nsString& aName); +static int FFRECountHyphens (nsACString &aFFREName); + +static PangoLanguage *GetPangoLanguage(nsIAtom *aLangGroup); +static const MozPangoLangGroup* FindPangoLangGroup (nsACString &aLangGroup); + +static void FreeGlobals (void); + +static PangoStyle CalculateStyle (PRUint8 aStyle); +static PangoWeight CalculateWeight (PRUint16 aWeight); + +static nsresult EnumFontsPango (nsIAtom* aLangGroup, const char* aGeneric, + PRUint32* aCount, PRUnichar*** aResult); +static int CompareFontNames (const void* aArg1, const void* aArg2, + void* aClosure); + +extern void AddLangGroup (FcPattern *aPattern, nsIAtom *aLangGroup); + +nsFontMetricsPango::nsFontMetricsPango() +{ + if (!gPangoFontLog) + gPangoFontLog = PR_NewLogModule("PangoFont"); + + gNumInstances++; + + mPangoFontDesc = nsnull; + mPangoContext = nsnull; + mLTRPangoContext = nsnull; + mRTLPangoContext = nsnull; + mPangoAttrList = nsnull; + mIsRTL = PR_FALSE; + + static PRBool initialized = PR_FALSE; + if (initialized) + return; + + // Initialized the custom decoders + if (!mozilla_decoders_init()) + initialized = PR_TRUE; +} + +nsFontMetricsPango::~nsFontMetricsPango() +{ + delete mFont; + + if (mDeviceContext) + mDeviceContext->FontMetricsDeleted(this); + + if (mPangoFontDesc) + pango_font_description_free(mPangoFontDesc); + + if (mLTRPangoContext) + g_object_unref(mLTRPangoContext); + + if (mRTLPangoContext) + g_object_unref(mRTLPangoContext); + + if (mPangoAttrList) + pango_attr_list_unref(mPangoAttrList); + + // XXX clean up all the pango objects + + if (--gNumInstances == 0) + FreeGlobals(); +} + + +NS_IMPL_ISUPPORTS1(nsFontMetricsPango, nsIFontMetrics) + +// nsIFontMetrics impl + +NS_IMETHODIMP +nsFontMetricsPango::Init(const nsFont& aFont, nsIAtom* aLangGroup, + nsIDeviceContext *aContext) +{ + mFont = new nsFont(aFont); + mLangGroup = aLangGroup; + + // Hang on to the device context + mDeviceContext = aContext; + + mPointSize = NSTwipsToFloatPoints(mFont->size); + + // Make sure to clamp the pixel size to something reasonable so we + // don't make the X server blow up. + nscoord screenPixels = gdk_screen_height(); + mPointSize = PR_MIN(screenPixels * FONT_MAX_FONT_SCALE, mPointSize); + + // enumerate over the font names passed in + mFont->EnumerateFamilies(nsFontMetricsPango::EnumFontCallback, this); + + nsCOMPtr prefService; + prefService = do_GetService(NS_PREF_CONTRACTID); + if (!prefService) + return NS_ERROR_FAILURE; + + nsXPIDLCString value; + + // Set up the default font name if it's not set + if (!mGenericFont) { + prefService->CopyCharPref("font.default", getter_Copies(value)); + + if (value.get()) + mDefaultFont = value.get(); + else + mDefaultFont = "serif"; + + mGenericFont = &mDefaultFont; + } + + // set up the minimum sizes for fonts + if (mLangGroup) { + nsCAutoString name("font.min-size."); + + if (mGenericFont->Equals("monospace")) + name.Append("fixed"); + else + name.Append("variable"); + + name.Append(char('.')); + + const char* langGroup; + mLangGroup->GetUTF8String(&langGroup); + + name.Append(langGroup); + + PRInt32 minimumInt = 0; + float minimum; + nsresult res; + res = prefService->GetIntPref(name.get(), &minimumInt); + if (NS_FAILED(res)) + prefService->GetDefaultIntPref(name.get(), &minimumInt); + + if (minimumInt < 0) + minimumInt = 0; + + minimum = minimumInt; + + // The minimum size is specified in pixels, not in points. + // Convert the size from pixels to points. + minimum = NSTwipsToFloatPoints(NSFloatPixelsToTwips(minimum, mDeviceContext->DevUnitsToAppUnits())); + if (mPointSize < minimum) + mPointSize = minimum; + } + + // Make sure that the pixel size is at least greater than zero + if (mPointSize < 1) { +#ifdef DEBUG + printf("*** Warning: nsFontMetricsPango created with point size %f\n", + mPointSize); +#endif + mPointSize = 1; + } + + nsresult rv = RealizeFont(); + if (NS_FAILED(rv)) + return rv; + + // Cache font metrics for the 'x' character + return CacheFontMetrics(); +} + +nsresult +nsFontMetricsPango::CacheFontMetrics(void) +{ + // Get our scale factor + float f; + float val; + f = mDeviceContext->DevUnitsToAppUnits(); + + mPangoAttrList = pango_attr_list_new(); + + GList *items = pango_itemize(mPangoContext, + "a", 0, 1, mPangoAttrList, NULL); + + if (!items) + return NS_ERROR_FAILURE; + + guint nitems = g_list_length(items); + if (nitems != 1) + return NS_ERROR_FAILURE; + + PangoItem *item = (PangoItem *)items->data; + PangoFcFont *fcfont = PANGO_FC_FONT(item->analysis.font); + if (!fcfont) + return NS_ERROR_FAILURE; + + // Get our font face + FT_Face face; + TT_OS2 *os2; + XftFont *xftFont = pango_xft_font_get_font(PANGO_FONT(fcfont)); + if (!xftFont) + return NS_ERROR_NOT_AVAILABLE; + + face = XftLockFace(xftFont); + os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2); + + // mEmHeight (size in pixels of EM height) + int size; + if (FcPatternGetInteger(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) != + FcResultMatch) { + size = 12; + } + mEmHeight = PR_MAX(1, nscoord(size * f)); + + // mMaxAscent + mMaxAscent = nscoord(xftFont->ascent * f); + + // mMaxDescent + mMaxDescent = nscoord(xftFont->descent * f); + + nscoord lineHeight = mMaxAscent + mMaxDescent; + + // mLeading (needs ascent and descent and EM height) + if (lineHeight > mEmHeight) + mLeading = lineHeight - mEmHeight; + else + mLeading = 0; + + // mMaxHeight (needs ascent and descent) + mMaxHeight = lineHeight; + + // mEmAscent (needs maxascent, EM height, ascent and descent) + mEmAscent = nscoord(mMaxAscent * mEmHeight / lineHeight); + + // mEmDescent (needs EM height and EM ascent + mEmDescent = mEmHeight - mEmAscent; + + // mMaxAdvance + mMaxAdvance = nscoord(xftFont->max_advance_width * f); + + // mSpaceWidth (width of a space) + nscoord tmpWidth; + GetWidth(" ", 1, tmpWidth, NULL); + mSpaceWidth = tmpWidth; + + // mAveCharWidth (width of an 'average' char) + // XftTextExtents16(GDK_DISPLAY(), xftFont, &xUnichar, 1, &extents); + //rawWidth = extents.width; + //mAveCharWidth = NSToCoordRound(rawWidth * f); + GetWidth("x", 1, tmpWidth, NULL); + mAveCharWidth = tmpWidth; + + // mXHeight (height of an 'x' character) + PRUnichar xUnichar('x'); + XGlyphInfo extents; + if (FcCharSetHasChar(xftFont->charset, xUnichar)) { + XftTextExtents16(GDK_DISPLAY(), xftFont, &xUnichar, 1, &extents); + mXHeight = extents.height; + } + else { + // 56% of ascent, best guess for non-true type or asian fonts + mXHeight = nscoord(((float)mMaxAscent) * 0.56); + } + mXHeight = nscoord(mXHeight * f); + + // mUnderlineOffset (offset for underlines) + val = CONVERT_DESIGN_UNITS_TO_PIXELS(face->underline_position, + face->size->metrics.y_scale); + if (val) { + mUnderlineOffset = NSToIntRound(val * f); + } + else { + mUnderlineOffset = + -NSToIntRound(PR_MAX(1, floor(0.1 * xftFont->height + 0.5)) * f); + } + + // mUnderlineSize (thickness of an underline) + val = CONVERT_DESIGN_UNITS_TO_PIXELS(face->underline_thickness, + face->size->metrics.y_scale); + if (val) { + mUnderlineSize = nscoord(PR_MAX(f, NSToIntRound(val * f))); + } + else { + mUnderlineSize = + NSToIntRound(PR_MAX(1, floor(0.05 * xftFont->height + 0.5)) * f); + } + + // mSuperscriptOffset + if (os2 && os2->ySuperscriptYOffset) { + val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySuperscriptYOffset, + face->size->metrics.y_scale); + mSuperscriptOffset = nscoord(PR_MAX(f, NSToIntRound(val * f))); + } + else { + mSuperscriptOffset = mXHeight; + } + + // mSubscriptOffset + if (os2 && os2->ySubscriptYOffset) { + val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySubscriptYOffset, + face->size->metrics.y_scale); + // some fonts have the incorrect sign. + val = (val < 0) ? -val : val; + mSubscriptOffset = nscoord(PR_MAX(f, NSToIntRound(val * f))); + } + else { + mSubscriptOffset = mXHeight; + } + + // mStrikeoutOffset + mStrikeoutOffset = NSToCoordRound(mXHeight / 2.0); + + // mStrikeoutSize + mStrikeoutSize = mUnderlineSize; + + XftUnlockFace(xftFont); + + /* + printf("%i\n", mXHeight); + printf("%i\n", mSuperscriptOffset); + printf("%i\n", mSubscriptOffset); + printf("%i\n", mStrikeoutOffset); + printf("%i\n", mStrikeoutSize); + printf("%i\n", mUnderlineOffset); + printf("%i\n", mUnderlineSize); + printf("%i\n", mMaxHeight); + printf("%i\n", mLeading); + printf("%i\n", mEmHeight); + printf("%i\n", mEmAscent); + printf("%i\n", mEmDescent); + printf("%i\n", mMaxAscent); + printf("%i\n", mMaxDescent); + printf("%i\n", mMaxAdvance); + printf("%i\n", mSpaceWidth); + printf("%i\n", mAveCharWidth); + */ + + return NS_OK; +} + +NS_IMETHODIMP +nsFontMetricsPango::Destroy() +{ + mDeviceContext = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +nsFontMetricsPango::GetFont(const nsFont *&aFont) +{ + aFont = mFont; + return NS_OK; +} + +NS_IMETHODIMP +nsFontMetricsPango::GetLangGroup(nsIAtom** aLangGroup) +{ + *aLangGroup = mLangGroup; + NS_IF_ADDREF(*aLangGroup); + + return NS_OK; +} + +NS_IMETHODIMP +nsFontMetricsPango::GetFontHandle(nsFontHandle &aHandle) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +// nsIFontMetricsPango impl + +nsresult +nsFontMetricsPango::GetWidth(const char* aString, PRUint32 aLength, + nscoord& aWidth, + nsRenderingContextGTK *aContext) +{ + PangoLayout *layout = pango_layout_new(mPangoContext); + + pango_layout_set_text(layout, aString, aLength); + + int width, height; + + pango_layout_get_size(layout, &width, &height); + + width /= PANGO_SCALE; + + g_object_unref(layout); + + float f; + f = mDeviceContext->DevUnitsToAppUnits(); + aWidth = NSToCoordRound(width * f); + + // printf("GetWidth (char *) %d\n", aWidth); + + return NS_OK; +} + +nsresult +nsFontMetricsPango::GetWidth(const PRUnichar* aString, PRUint32 aLength, + nscoord& aWidth, PRInt32 *aFontID, + nsRenderingContextGTK *aContext) +{ + nsresult rv = NS_OK; + PangoLayout *layout = pango_layout_new(mPangoContext); + + gchar *text = g_utf16_to_utf8(aString, aLength, + NULL, NULL, NULL); + + if (!text) { + aWidth = 0; +#ifdef DEBUG + NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow"); + DUMP_PRUNICHAR(aString, aLength) +#endif + rv = NS_ERROR_FAILURE; + goto loser; + } + + gint width, height; + + pango_layout_set_text(layout, text, strlen(text)); + pango_layout_get_size(layout, &width, &height); + + width /= PANGO_SCALE; + + float f; + f = mDeviceContext->DevUnitsToAppUnits(); + aWidth = NSToCoordRound(width * f); + + // printf("GetWidth %d\n", aWidth); + + loser: + g_free(text); + g_object_unref(layout); + + return rv; +} + + +nsresult +nsFontMetricsPango::GetTextDimensions(const PRUnichar* aString, + PRUint32 aLength, + nsTextDimensions& aDimensions, + PRInt32* aFontID, + nsRenderingContextGTK *aContext) +{ + nsresult rv = NS_OK; + + PangoLayout *layout = pango_layout_new(mPangoContext); + + gchar *text = g_utf16_to_utf8(aString, aLength, + NULL, NULL, NULL); + + if (!text) { +#ifdef DEBUG + NS_WARNING("nsFontMetricsPango::GetTextDimensions invalid unicode to follow"); + DUMP_PRUNICHAR(aString, aLength) +#endif + aDimensions.width = 0; + aDimensions.ascent = 0; + aDimensions.descent = 0; + + rv = NS_ERROR_FAILURE; + goto loser; + } + + + pango_layout_set_text(layout, text, strlen(text)); + + // Get the logical extents + PangoLayoutLine *line; + if (pango_layout_get_line_count(layout) != 1) { + printf("Warning: more than one line!\n"); + } + line = pango_layout_get_line(layout, 0); + + PangoRectangle rect; + pango_layout_line_get_extents(line, NULL, &rect); + + float P2T; + P2T = mDeviceContext->DevUnitsToAppUnits(); + + aDimensions.width = NSToCoordRound(rect.width / PANGO_SCALE * P2T); + aDimensions.ascent = NSToCoordRound(PANGO_ASCENT(rect) / PANGO_SCALE * P2T); + aDimensions.descent = NSToCoordRound(PANGO_DESCENT(rect) / PANGO_SCALE * P2T); + + // printf("GetTextDimensions %d %d %d\n", aDimensions.width, + //aDimensions.ascent, aDimensions.descent); + + loser: + g_free(text); + g_object_unref(layout); + + return rv; +} + +nsresult +nsFontMetricsPango::GetTextDimensions(const char* aString, + PRInt32 aLength, + PRInt32 aAvailWidth, + PRInt32* aBreaks, + PRInt32 aNumBreaks, + nsTextDimensions& aDimensions, + PRInt32& aNumCharsFit, + nsTextDimensions& aLastWordDimensions, + PRInt32* aFontID, + nsRenderingContextGTK *aContext) +{ + + return GetTextDimensionsInternal(aString, aLength, aAvailWidth, aBreaks, + aNumBreaks, aDimensions, aNumCharsFit, + aLastWordDimensions, aContext); + +} + +nsresult +nsFontMetricsPango::GetTextDimensions(const PRUnichar* aString, + PRInt32 aLength, + PRInt32 aAvailWidth, + PRInt32* aBreaks, + PRInt32 aNumBreaks, + nsTextDimensions& aDimensions, + PRInt32& aNumCharsFit, + nsTextDimensions& aLastWordDimensions, + PRInt32* aFontID, + nsRenderingContextGTK *aContext) +{ + nsresult rv = NS_OK; + PRInt32 curBreak = 0; + gchar *curChar; + + PRInt32 *utf8Breaks = new PRInt32[aNumBreaks]; + + gchar *text = g_utf16_to_utf8(aString, (PRInt32)aLength, + NULL, NULL, NULL); + + curChar = text; + + if (!text) { +#ifdef DEBUG + NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow"); + DUMP_PRUNICHAR(aString, (PRUint32)aLength) +#endif + rv = NS_ERROR_FAILURE; + goto loser; + } + + // Covert the utf16 break offsets to utf8 break offsets + for (PRInt32 curOffset=0; curOffset < aLength; + curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) { + if (aBreaks[curBreak] == curOffset) { + utf8Breaks[curBreak] = curChar - text; + curBreak++; + } + + if (IS_HIGH_SURROGATE(aString[curOffset])) + curOffset++; + } + + // Always catch the last break + utf8Breaks[curBreak] = curChar - text; + +#if 0 + if (strlen(text) != aLength) { + printf("Different lengths for utf16 %d and utf8 %d\n", aLength, strlen(text)); + DUMP_PRUNICHAR(aString, aLength) + DUMP_PRUNICHAR(text, strlen(text)) + for (PRInt32 i = 0; i < aNumBreaks; ++i) { + printf(" break %d utf16 %d utf8 %d\n", i, aBreaks[i], utf8Breaks[i]); + } + } +#endif + + // We'll use curBreak to indicate which of the breaks end up being + // used for the break point for this line. + curBreak = 0; + rv = GetTextDimensionsInternal(text, strlen(text), aAvailWidth, utf8Breaks, + aNumBreaks, aDimensions, aNumCharsFit, + aLastWordDimensions, aContext); + + // Figure out which of the breaks we ended up using to convert + // back to utf16 - start from the end. + for (PRInt32 i = aNumBreaks - 1; i >= 0; --i) { + if (utf8Breaks[i] == aNumCharsFit) { + // if (aNumCharsFit != aBreaks[i]) + // printf("Fixing utf8 -> utf16 %d -> %d\n", aNumCharsFit, aBreaks[i]); + aNumCharsFit = aBreaks[i]; + break; + } + } + + loser: + if (text) + g_free(text); + + delete[] utf8Breaks; + + return rv; +} + +nsresult +nsFontMetricsPango::DrawString(const char *aString, PRUint32 aLength, + nscoord aX, nscoord aY, + const nscoord* aSpacing, + nsRenderingContextGTK *aContext, + nsDrawingSurfaceGTK *aSurface) +{ + PangoLayout *layout = pango_layout_new(mPangoContext); + + pango_layout_set_text(layout, aString, aLength); + + int x = aX; + int y = aY; + + aContext->GetTranMatrix()->TransformCoord(&x, &y); + + PangoLayoutLine *line; + if (pango_layout_get_line_count(layout) != 1) { + printf("Warning: more than one line!\n"); + } + line = pango_layout_get_line(layout, 0); + + aContext->UpdateGC(); + GdkGC *gc = aContext->GetGC(); + + if (aSpacing && *aSpacing) { + DrawStringSlowly(aString, NULL, aLength, aSurface->GetDrawable(), + gc, x, y, line, aSpacing); + } + else { + gdk_draw_layout_line(aSurface->GetDrawable(), gc, + x, y, + line); + } + + g_object_unref(gc); + g_object_unref(layout); + + // printf("DrawString (char *)\n"); + + return NS_OK; +} + +nsresult +nsFontMetricsPango::DrawString(const PRUnichar* aString, PRUint32 aLength, + nscoord aX, nscoord aY, + PRInt32 aFontID, + const nscoord* aSpacing, + nsRenderingContextGTK *aContext, + nsDrawingSurfaceGTK *aSurface) +{ + nsresult rv = NS_OK; + int x = aX; + int y = aY; + + aContext->UpdateGC(); + GdkGC *gc = aContext->GetGC(); + + PangoLayout *layout = pango_layout_new(mPangoContext); + + gchar *text = g_utf16_to_utf8(aString, aLength, + NULL, NULL, NULL); + + if (!text) { +#ifdef DEBUG + NS_WARNING("nsFontMetricsPango::DrawString invalid unicode to follow"); + DUMP_PRUNICHAR(aString, aLength) +#endif + rv = NS_ERROR_FAILURE; + goto loser; + } + + pango_layout_set_text(layout, text, strlen(text)); + + aContext->GetTranMatrix()->TransformCoord(&x, &y); + + PangoLayoutLine *line; + if (pango_layout_get_line_count(layout) != 1) { + printf("Warning: more than one line!\n"); + } + line = pango_layout_get_line(layout, 0); + + if (aSpacing && *aSpacing) { + DrawStringSlowly(text, aString, aLength, aSurface->GetDrawable(), + gc, x, y, line, aSpacing); + } + else { + gdk_draw_layout_line(aSurface->GetDrawable(), gc, + x, y, + line); + } + + loser: + + g_free(text); + g_object_unref(gc); + g_object_unref(layout); + + // printf("DrawString\n"); + + return rv; +} + +#ifdef MOZ_MATHML +nsresult +nsFontMetricsPango::GetBoundingMetrics(const char *aString, PRUint32 aLength, + nsBoundingMetrics &aBoundingMetrics, + nsRenderingContextGTK *aContext) +{ + printf("GetBoundingMetrics (char *)\n"); + return NS_ERROR_FAILURE; +} + +nsresult +nsFontMetricsPango::GetBoundingMetrics(const PRUnichar *aString, + PRUint32 aLength, + nsBoundingMetrics &aBoundingMetrics, + PRInt32 *aFontID, + nsRenderingContextGTK *aContext) +{ + nsresult rv = NS_OK; + PangoLayout *layout = pango_layout_new(mPangoContext); + + gchar *text = g_utf16_to_utf8(aString, aLength, + NULL, NULL, NULL); + + if (!text) { +#ifdef DEBUG + NS_WARNING("nsFontMetricsPango::GetBoundingMetrics invalid unicode to follow"); + DUMP_PRUNICHAR(aString, aLength) +#endif + aBoundingMetrics.leftBearing = 0; + aBoundingMetrics.rightBearing = 0; + aBoundingMetrics.width = 0; + aBoundingMetrics.ascent = 0; + aBoundingMetrics.descent = 0; + + rv = NS_ERROR_FAILURE; + goto loser; + } + + pango_layout_set_text(layout, text, strlen(text)); + + // Get the logical extents + PangoLayoutLine *line; + if (pango_layout_get_line_count(layout) != 1) { + printf("Warning: more than one line!\n"); + } + line = pango_layout_get_line(layout, 0); + + // Get the ink extents + PangoRectangle rect; + pango_layout_line_get_extents(line, NULL, &rect); + + float P2T; + P2T = mDeviceContext->DevUnitsToAppUnits(); + + aBoundingMetrics.leftBearing = + NSToCoordRound(rect.x / PANGO_SCALE * P2T); + aBoundingMetrics.rightBearing = + NSToCoordRound(rect.width / PANGO_SCALE * P2T); + aBoundingMetrics.width = NSToCoordRound((rect.x + rect.width) / PANGO_SCALE * P2T); + aBoundingMetrics.ascent = NSToCoordRound(rect.y / PANGO_SCALE * P2T); + aBoundingMetrics.descent = NSToCoordRound(rect.height / PANGO_SCALE * P2T); + + loser: + g_free(text); + g_object_unref(layout); + + return rv; +} + +#endif /* MOZ_MATHML */ + +GdkFont* +nsFontMetricsPango::GetCurrentGDKFont(void) +{ + return nsnull; +} + +nsresult +nsFontMetricsPango::SetRightToLeftText(PRBool aIsRTL) +{ + if (aIsRTL) { + if (!mRTLPangoContext) { + mRTLPangoContext = pango_xft_get_context(GDK_DISPLAY(), 0); + pango_context_set_base_dir(mRTLPangoContext, PANGO_DIRECTION_RTL); + + gdk_pango_context_set_colormap(mRTLPangoContext, gdk_rgb_get_cmap()); + pango_context_set_language(mRTLPangoContext, GetPangoLanguage(mLangGroup)); + pango_context_set_font_description(mRTLPangoContext, mPangoFontDesc); + } + mPangoContext = mRTLPangoContext; + } + else { + mPangoContext = mLTRPangoContext; + } + + mIsRTL = aIsRTL; + return NS_OK; +} + +/* static */ +PRUint32 +nsFontMetricsPango::GetHints(void) +{ + return (NS_RENDERING_HINT_BIDI_REORDERING | + NS_RENDERING_HINT_ARABIC_SHAPING | + NS_RENDERING_HINT_FAST_MEASURE); +} + +/* static */ +nsresult +nsFontMetricsPango::FamilyExists(nsIDeviceContext *aDevice, + const nsString &aName) +{ + if (!IsASCIIFontName(aName)) + return NS_ERROR_FAILURE; + + NS_ConvertUCS2toUTF8 name(aName); + + nsresult rv = NS_ERROR_FAILURE; + PangoContext *context = pango_xft_get_context(GDK_DISPLAY(), 0); + PangoFontFamily **familyList; + int n; + + pango_context_list_families(context, &familyList, &n); + + for (int i=0; i < n; i++) { + const char *tmpname = pango_font_family_get_name(familyList[i]); + if (!Compare(nsDependentCString(tmpname), name, + nsCaseInsensitiveCStringComparator())) { + rv = NS_OK; + break; + } + } + + g_free(familyList); + g_object_unref(context); + + return rv; +} + +// Private Methods + +nsresult +nsFontMetricsPango::RealizeFont(void) +{ + nsCString familyList; + // Create and fill out the font description. + mPangoFontDesc = pango_font_description_new(); + + // Add CSS names - walk the list of fonts, adding the generic as + // the last font + for (int i=0; i < mFontList.Count(); ++i) { + // if this was a generic name, break out of the loop since we + // don't want to add it to the pattern yet + if (mFontIsGeneric[i]) + break;; + + nsCString *familyName = mFontList.CStringAt(i); + familyList.Append(familyName->get()); + familyList.Append(','); + } + + // If there's a generic add a pref for the generic if there's one + // set. + if (mGenericFont && !mFont->systemFont) { + nsCString name; + name += "font.name."; + name += mGenericFont->get(); + name += "."; + + nsString langGroup; + mLangGroup->ToString(langGroup); + + name.AppendWithConversion(langGroup); + + nsCOMPtr pref; + pref = do_GetService(NS_PREF_CONTRACTID); + if (pref) { + nsresult rv; + nsXPIDLCString value; + rv = pref->GetCharPref(name.get(), getter_Copies(value)); + + // we ignore prefs that have three hypens since they are X + // style prefs. + if (FFRECountHyphens(value) < 3) { + nsCString tmpstr; + tmpstr.Append(value); + + familyList.Append(tmpstr); + familyList.Append(','); + } + } + } + + // Add the generic if there is one. + if (mGenericFont && !mFont->systemFont) { + familyList.Append(mGenericFont->get()); + familyList.Append(','); + } + + // Set the family + pango_font_description_set_family(mPangoFontDesc, + familyList.get()); + + // Set the point size + pango_font_description_set_size(mPangoFontDesc, + (gint)(mPointSize * PANGO_SCALE)); + + // Set the style + pango_font_description_set_style(mPangoFontDesc, + CalculateStyle(mFont->style)); + + // Set the weight + pango_font_description_set_weight(mPangoFontDesc, + CalculateWeight(mFont->weight)); + + // Now that we have the font description set up, create the + // context. + mLTRPangoContext = pango_xft_get_context(GDK_DISPLAY(), 0); + mPangoContext = mLTRPangoContext; + + // Set the color map so we can draw later. + gdk_pango_context_set_colormap(mPangoContext, gdk_rgb_get_cmap()); + + // Set the pango language now that we have a context + pango_context_set_language(mPangoContext, GetPangoLanguage(mLangGroup)); + + // And attach the font description to this context + pango_context_set_font_description(mPangoContext, mPangoFontDesc); + + return NS_OK; +} + +/* static */ +PRBool +nsFontMetricsPango::EnumFontCallback(const nsString &aFamily, + PRBool aIsGeneric, void *aData) +{ + // make sure it's an ascii name, if not then return and continue + // enumerating + if (!IsASCIIFontName(aFamily)) + return PR_TRUE; + + nsCAutoString name; + name.AssignWithConversion(aFamily.get()); + ToLowerCase(name); + nsFontMetricsPango *metrics = (nsFontMetricsPango *)aData; + metrics->mFontList.AppendCString(name); + metrics->mFontIsGeneric.AppendElement((void *)aIsGeneric); + if (aIsGeneric) { + metrics->mGenericFont = + metrics->mFontList.CStringAt(metrics->mFontList.Count() - 1); + return PR_FALSE; // stop processing + } + + return PR_TRUE; // keep processing +} + +/* + * This is only used when there's per-character spacing happening. + * Well, really it can be either line or character spacing but it's + * just turtles all the way down! + */ + +void +nsFontMetricsPango::DrawStringSlowly(const gchar *aText, + const PRUnichar *aOrigString, + PRUint32 aLength, + GdkDrawable *aDrawable, + GdkGC *aGC, gint aX, gint aY, + PangoLayoutLine *aLine, + const nscoord *aSpacing) +{ + float app2dev; + app2dev = mDeviceContext->AppUnitsToDevUnits(); + gint offset = 0; + + /* + * We walk the list of glyphs returned in each layout run, + * matching up the glyphs with the characters in the source text. + * We use the aSpacing argument to figure out where to place those + * glyphs. It's important to note that since the string we're + * working with is in UTF-8 while the spacing argument assumes + * that offset will be part of the UTF-16 string. Logical + * attributes in pango are in byte offsets in the UTF-8 string, so + * we need to store the offsets based on the UTF-8 string. + */ + nscoord *utf8spacing = new nscoord[strlen(aText)]; + + if (aOrigString) { + const gchar *curChar = aText; + bzero(utf8spacing, sizeof(nscoord) * strlen(aText)); + + // Covert the utf16 spacing offsets to utf8 spacing offsets + for (PRUint32 curOffset=0; curOffset < aLength; + curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) { + utf8spacing[curChar - aText] = aSpacing[curOffset]; + + if (IS_HIGH_SURROGATE(aOrigString[curOffset])) + curOffset++; + } + } + else { + memcpy(utf8spacing, aSpacing, (sizeof(nscoord *) * aLength)); + } + + gint curRun = 0; + + for (GSList *tmpList = aLine->runs; tmpList && tmpList->data; + tmpList = tmpList->next, curRun++) { + PangoLayoutRun *layoutRun = (PangoLayoutRun *)tmpList->data; + gint tmpOffset = 0; + + /* printf(" Rendering run %d: \"%s\"\n", curRun, + &aText[layoutRun->item->offset]); */ + + for (gint i=0; i < layoutRun->glyphs->num_glyphs; i++) { + /* printf("glyph %d offset %d orig width %d new width %d\n", i, + * layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset, + * layoutRun->glyphs->glyphs[i].geometry.width, + * (gint)(utf8spacing[layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset] * app2dev * PANGO_SCALE)); + */ + gint thisOffset = (gint)(utf8spacing[layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset] + * app2dev * PANGO_SCALE); + layoutRun->glyphs->glyphs[i].geometry.width = thisOffset; + tmpOffset += thisOffset; + } + + /* printf(" rendering at X coord %d\n", aX + offset); */ + + gdk_draw_glyphs(aDrawable, aGC, layoutRun->item->analysis.font, + aX + (gint)(offset / PANGO_SCALE), aY, layoutRun->glyphs); + + offset += tmpOffset; + } + + delete[] utf8spacing; +} + +nsresult +nsFontMetricsPango::GetTextDimensionsInternal(const gchar* aString, + PRInt32 aLength, + PRInt32 aAvailWidth, + PRInt32* aBreaks, + PRInt32 aNumBreaks, + nsTextDimensions& aDimensions, + PRInt32& aNumCharsFit, + nsTextDimensions& aLastWordDimensions, + nsRenderingContextGTK *aContext) +{ + NS_PRECONDITION(aBreaks[aNumBreaks - 1] == aLength, "invalid break array"); + + // If we need to back up this state represents the last place + // we could break. We can use this to avoid remeasuring text + PRInt32 prevBreakState_BreakIndex = -1; // not known + // (hasn't been computed) + nscoord prevBreakState_Width = 0; // accumulated width to this point + + // Initialize OUT parameters + GetMaxAscent(aLastWordDimensions.ascent); + GetMaxDescent(aLastWordDimensions.descent); + aLastWordDimensions.width = -1; + aNumCharsFit = 0; + + // Iterate each character in the string and determine which font to use + nscoord width = 0; + PRInt32 start = 0; + nscoord aveCharWidth; + GetAveCharWidth(aveCharWidth); + + while (start < aLength) { + // Estimate how many characters will fit. Do that by + // diving the available space by the average character + // width. Make sure the estimated number of characters is + // at least 1 + PRInt32 estimatedNumChars = 0; + + if (aveCharWidth > 0) + estimatedNumChars = (aAvailWidth - width) / aveCharWidth; + + if (estimatedNumChars < 1) + estimatedNumChars = 1; + + // Find the nearest break offset + PRInt32 estimatedBreakOffset = start + estimatedNumChars; + PRInt32 breakIndex; + nscoord numChars; + + // Find the nearest place to break that is less than or equal to + // the estimated break offset + if (aLength <= estimatedBreakOffset) { + // All the characters should fit + numChars = aLength - start; + breakIndex = aNumBreaks - 1; + } + else { + breakIndex = prevBreakState_BreakIndex; + while (((breakIndex + 1) < aNumBreaks) && + (aBreaks[breakIndex + 1] <= estimatedBreakOffset)) { + ++breakIndex; + } + + if (breakIndex == prevBreakState_BreakIndex) { + ++breakIndex; // make sure we advanced past the + // previous break index + } + + numChars = aBreaks[breakIndex] - start; + } + + // Measure the text + nscoord twWidth = 0; + if ((1 == numChars) && (aString[start] == ' ')) + GetSpaceWidth(twWidth); + else if (numChars > 0) + GetWidth(&aString[start], numChars, twWidth, aContext); + + // See if the text fits + PRBool textFits = (twWidth + width) <= aAvailWidth; + + // If the text fits then update the width and the number of + // characters that fit + if (textFits) { + aNumCharsFit += numChars; + width += twWidth; + start += numChars; + + // This is a good spot to back up to if we need to so remember + // this state + prevBreakState_BreakIndex = breakIndex; + prevBreakState_Width = width; + } + else { + // See if we can just back up to the previous saved + // state and not have to measure any text + if (prevBreakState_BreakIndex > 0) { + // If the previous break index is just before the + // current break index then we can use it + if (prevBreakState_BreakIndex == (breakIndex - 1)) { + aNumCharsFit = aBreaks[prevBreakState_BreakIndex]; + width = prevBreakState_Width; + break; + } + } + + // We can't just revert to the previous break state + if (0 == breakIndex) { + // There's no place to back up to, so even though + // the text doesn't fit return it anyway + aNumCharsFit += numChars; + width += twWidth; + break; + } + + // Repeatedly back up until we get to where the text + // fits or we're all the way back to the first word + width += twWidth; + while ((breakIndex >= 1) && (width > aAvailWidth)) { + twWidth = 0; + start = aBreaks[breakIndex - 1]; + numChars = aBreaks[breakIndex] - start; + + if ((1 == numChars) && (aString[start] == ' ')) + GetSpaceWidth(twWidth); + else if (numChars > 0) + GetWidth(&aString[start], numChars, twWidth, + aContext); + width -= twWidth; + aNumCharsFit = start; + breakIndex--; + } + break; + } + } + + aDimensions.width = width; + GetMaxAscent(aDimensions.ascent); + GetMaxDescent(aDimensions.descent); + + /* printf("aDimensions %d %d %d aLastWordDimensions %d %d %d aNumCharsFit %d\n", + aDimensions.width, aDimensions.ascent, aDimensions.descent, + aLastWordDimensions.width, aLastWordDimensions.ascent, aLastWordDimensions.descent, + aNumCharsFit); */ + + return NS_OK; +} + +/* static */ +PRBool +IsASCIIFontName(const nsString& aName) +{ + PRUint32 len = aName.Length(); + const PRUnichar* str = aName.get(); + for (PRUint32 i = 0; i < len; i++) { + /* + * X font names are printable ASCII, ignore others (for now) + */ + if ((str[i] < 0x20) || (str[i] > 0x7E)) { + return PR_FALSE; + } + } + + return PR_TRUE; +} + +/* static */ +int +FFRECountHyphens (nsACString &aFFREName) +{ + int h = 0; + PRInt32 hyphen = 0; + while ((hyphen = aFFREName.FindChar('-', hyphen)) >= 0) { + ++h; + ++hyphen; + } + return h; +} + +/* static */ +PangoLanguage * +GetPangoLanguage(nsIAtom *aLangGroup) +{ + // Find the FC lang group for this lang group + nsCAutoString cname; + aLangGroup->ToUTF8String(cname); + + // see if the lang group needs to be translated from mozilla's + // internal mapping into fontconfig's + const struct MozPangoLangGroup *langGroup; + langGroup = FindPangoLangGroup(cname); + + // if there's no lang group, just use the lang group as it was + // passed to us + // + // we're casting away the const here for the strings - should be + // safe. + if (!langGroup) + return pango_language_from_string(cname.get()); + else if (langGroup->PangoLang) + return pango_language_from_string(langGroup->PangoLang); + + return pango_language_from_string("en"); +} + +/* static */ +const MozPangoLangGroup* +FindPangoLangGroup (nsACString &aLangGroup) +{ + for (unsigned int i=0; i < NUM_PANGO_LANG_GROUPS; ++i) { + if (aLangGroup.Equals(MozPangoLangGroups[i].mozLangGroup, + nsCaseInsensitiveCStringComparator())) { + return &MozPangoLangGroups[i]; + } + } + + return nsnull; +} + +/* static */ +void +FreeGlobals(void) +{ +} + +/* static */ +PangoStyle +CalculateStyle(PRUint8 aStyle) +{ + switch(aStyle) { + case NS_FONT_STYLE_ITALIC: + return PANGO_STYLE_OBLIQUE; + break; + case NS_FONT_STYLE_OBLIQUE: + return PANGO_STYLE_OBLIQUE; + break; + } + + return PANGO_STYLE_NORMAL; +} + +/* static */ +PangoWeight +CalculateWeight (PRUint16 aWeight) +{ + /* + * weights come in two parts crammed into one + * integer -- the "base" weight is weight / 100, + * the rest of the value is the "offset" from that + * weight -- the number of steps to move to adjust + * the weight in the list of supported font weights, + * this value can be negative or positive. + */ + PRInt32 baseWeight = (aWeight + 50) / 100; + PRInt32 offset = aWeight - baseWeight * 100; + + /* clip weights to range 0 to 9 */ + if (baseWeight < 0) + baseWeight = 0; + if (baseWeight > 9) + baseWeight = 9; + + /* Map from weight value to fcWeights index */ + static int fcWeightLookup[10] = { + 0, 0, 0, 0, 1, 1, 2, 3, 3, 4, + }; + + PRInt32 fcWeight = fcWeightLookup[baseWeight]; + + /* + * adjust by the offset value, make sure we stay inside the + * fcWeights table + */ + fcWeight += offset; + + if (fcWeight < 0) + fcWeight = 0; + if (fcWeight > 4) + fcWeight = 4; + + /* Map to final PANGO_WEIGHT value */ + static int fcWeights[5] = { + 349, + 499, + 649, + 749, + 999 + }; + + return (PangoWeight)fcWeights[fcWeight]; +} + +/* static */ +nsresult +EnumFontsPango(nsIAtom* aLangGroup, const char* aGeneric, + PRUint32* aCount, PRUnichar*** aResult) +{ + FcPattern *pat = NULL; + FcObjectSet *os = NULL; + FcFontSet *fs = NULL; + nsresult rv = NS_ERROR_FAILURE; + + PRUnichar **array = NULL; + PRUint32 narray = 0; + PRInt32 serif = 0, sansSerif = 0, monospace = 0, nGenerics; + + *aCount = 0; + *aResult = nsnull; + + pat = FcPatternCreate(); + if (!pat) + goto end; + + os = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, 0); + if (!os) + goto end; + + // take the pattern and add the lang group to it + if (aLangGroup) + AddLangGroup(pat, aLangGroup); + + // get the font list + fs = FcFontList(0, pat, os); + + if (!fs) + goto end; + + if (!fs->nfont) { + rv = NS_OK; + goto end; + } + + // Fontconfig supports 3 generic fonts, "serif", "sans-serif", and + // "monospace", slightly different from CSS's 5. + if (!aGeneric) + serif = sansSerif = monospace = 1; + else if (!strcmp(aGeneric, "serif")) + serif = 1; + else if (!strcmp(aGeneric, "sans-serif")) + sansSerif = 1; + else if (!strcmp(aGeneric, "monospace")) + monospace = 1; + else if (!strcmp(aGeneric, "cursive") || !strcmp(aGeneric, "fantasy")) + serif = sansSerif = 1; + else + NS_NOTREACHED("unexpected generic family"); + nGenerics = serif + sansSerif + monospace; + + array = NS_STATIC_CAST(PRUnichar **, + nsMemory::Alloc((fs->nfont + nGenerics) * sizeof(PRUnichar *))); + if (!array) + goto end; + + if (serif) { + PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("serif")); + if (!name) + goto end; + array[narray++] = name; + } + + if (sansSerif) { + PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("sans-serif")); + if (!name) + goto end; + array[narray++] = name; + } + + if (monospace) { + PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("monospace")); + if (!name) + goto end; + array[narray++] = name; + } + + for (int i=0; i < fs->nfont; ++i) { + char *family; + PRUnichar *name; + + // if there's no family, just move to the next iteration + if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0, + (FcChar8 **) &family) != FcResultMatch) { + continue; + } + + name = NS_STATIC_CAST(PRUnichar *, + nsMemory::Alloc ((strlen (family) + 1) + * sizeof (PRUnichar))); + + if (!name) + goto end; + + PRUnichar *r = name; + for (char *f = family; *f; ++f) + *r++ = *f; + *r = '\0'; + + array[narray++] = name; + } + + NS_QuickSort(array + nGenerics, narray - nGenerics, sizeof (PRUnichar*), + CompareFontNames, nsnull); + + *aCount = narray; + if (narray) + *aResult = array; + else + nsMemory::Free(array); + + rv = NS_OK; + + end: + if (NS_FAILED(rv) && array) { + while (narray) + nsMemory::Free (array[--narray]); + nsMemory::Free (array); + } + if (pat) + FcPatternDestroy(pat); + if (os) + FcObjectSetDestroy(os); + if (fs) + FcFontSetDestroy(fs); + + return rv; +} + +/* static */ +int +CompareFontNames (const void* aArg1, const void* aArg2, void* aClosure) +{ + const PRUnichar* str1 = *((const PRUnichar**) aArg1); + const PRUnichar* str2 = *((const PRUnichar**) aArg2); + + return nsCRT::strcmp(str1, str2); +} + + +// nsFontEnumeratorPango class + +nsFontEnumeratorPango::nsFontEnumeratorPango() +{ +} + +NS_IMPL_ISUPPORTS1(nsFontEnumeratorPango, nsIFontEnumerator) + +NS_IMETHODIMP +nsFontEnumeratorPango::EnumerateAllFonts(PRUint32 *aCount, + PRUnichar ***aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + *aResult = nsnull; + NS_ENSURE_ARG_POINTER(aCount); + *aCount = 0; + + return EnumFontsPango(nsnull, nsnull, aCount, aResult); +} + +NS_IMETHODIMP +nsFontEnumeratorPango::EnumerateFonts(const char *aLangGroup, + const char *aGeneric, + PRUint32 *aCount, + PRUnichar ***aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + *aResult = nsnull; + NS_ENSURE_ARG_POINTER(aCount); + *aCount = 0; + + // aLangGroup=null or "" means any (i.e., don't care) + // aGeneric=null or "" means any (i.e, don't care) + nsCOMPtr langGroup; + if (aLangGroup && *aLangGroup) + langGroup = do_GetAtom(aLangGroup); + const char* generic = nsnull; + if (aGeneric && *aGeneric) + generic = aGeneric; + + return EnumFontsPango(langGroup, generic, aCount, aResult); +} + +NS_IMETHODIMP +nsFontEnumeratorPango::HaveFontFor(const char *aLangGroup, + PRBool *aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + *aResult = PR_FALSE; + NS_ENSURE_ARG_POINTER(aLangGroup); + + *aResult = PR_TRUE; // always return true for now. + // Finish me - ftang + return NS_OK; +} + +NS_IMETHODIMP +nsFontEnumeratorPango::GetDefaultFont(const char *aLangGroup, + const char *aGeneric, + PRUnichar **aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + *aResult = nsnull; + + // Have a look at nsFontEnumeratorXft::GetDefaultFont for some + // possible code for this function. + + return NS_OK; +} + +NS_IMETHODIMP +nsFontEnumeratorPango::UpdateFontList(PRBool *_retval) +{ + *_retval = PR_FALSE; // always return false for now + return NS_OK; +} --- mozilla/gfx/src/gtk/nsRenderingContextGTK.h.foo 2003-02-24 21:38:34.000000000 -0500 +++ mozilla/gfx/src/gtk/nsRenderingContextGTK.h 2004-10-18 22:49:40.000000000 -0400 @@ -194,6 +194,8 @@ const nsRect &aDestBounds, PRUint32 aCopyFlags); NS_IMETHOD RetrieveCurrentNativeGraphicData(PRUint32 * ngd); + NS_IMETHOD SetRightToLeftText(PRBool aIsRTL); + NS_IMETHOD DrawImage(imgIContainer *aImage, const nsRect * aSrcRect, const nsPoint * aDestPoint); NS_IMETHOD DrawScaledImage(imgIContainer *aImage, const nsRect * aSrcRect, const nsRect * aDestRect); --- /dev/null 2004-02-18 10:26:44.000000000 -0500 +++ mozilla/gfx/src/gtk/nsFontMetricsPango.h 2004-10-18 22:49:40.000000000 -0400 @@ -0,0 +1,278 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:expandtab:shiftwidth=4:tabstop=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.org code. + * + * The Initial Developer of the Original Code Christopher Blizzard + * . Portions created by the Initial Developer + * are Copyright (C) 2002 the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 "nsIFontMetrics.h" +#include "nsIFontEnumerator.h" +#include "nsCRT.h" +#include "nsIAtom.h" +#include "nsString.h" +#include "nsVoidArray.h" +#include "nsIFontMetricsGTK.h" + +#include + +class nsFontMetricsPango : public nsIFontMetricsGTK +{ +public: + nsFontMetricsPango(); + virtual ~nsFontMetricsPango(); + + NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIFontMetrics + NS_IMETHOD Init (const nsFont& aFont, nsIAtom* aLangGroup, + nsIDeviceContext *aContext); + NS_IMETHOD Destroy(); + NS_IMETHOD GetFont (const nsFont *&aFont); + NS_IMETHOD GetLangGroup (nsIAtom** aLangGroup); + NS_IMETHOD GetFontHandle (nsFontHandle &aHandle); + + NS_IMETHOD GetXHeight (nscoord& aResult) + { aResult = mXHeight; return NS_OK; }; + + NS_IMETHOD GetSuperscriptOffset (nscoord& aResult) + { aResult = mSuperscriptOffset; + return NS_OK; }; + + NS_IMETHOD GetSubscriptOffset (nscoord& aResult) + { aResult = mSubscriptOffset; + return NS_OK; }; + + NS_IMETHOD GetStrikeout (nscoord& aOffset, nscoord& aSize) + { aOffset = mStrikeoutOffset; + aSize = mStrikeoutSize; + return NS_OK; }; + + NS_IMETHOD GetUnderline (nscoord& aOffset, nscoord& aSize) + { aOffset = mUnderlineOffset; + aSize = mUnderlineSize; + return NS_OK; }; + + NS_IMETHOD GetHeight (nscoord &aHeight) + { aHeight = mMaxHeight; + return NS_OK; }; + + NS_IMETHOD GetNormalLineHeight (nscoord &aHeight) + { aHeight = mEmHeight + mLeading; + return NS_OK; }; + + NS_IMETHOD GetLeading (nscoord &aLeading) + { aLeading = mLeading; + return NS_OK; }; + + NS_IMETHOD GetEmHeight (nscoord &aHeight) + { aHeight = mEmHeight; + return NS_OK; }; + + NS_IMETHOD GetEmAscent (nscoord &aAscent) + { aAscent = mEmAscent; + return NS_OK; }; + + NS_IMETHOD GetEmDescent (nscoord &aDescent) + { aDescent = mEmDescent; + return NS_OK; }; + + NS_IMETHOD GetMaxHeight (nscoord &aHeight) + { aHeight = mMaxHeight; + return NS_OK; }; + + NS_IMETHOD GetMaxAscent (nscoord &aAscent) + { aAscent = mMaxAscent; + return NS_OK; }; + + NS_IMETHOD GetMaxDescent (nscoord &aDescent) + { aDescent = mMaxDescent; + return NS_OK; }; + + NS_IMETHOD GetMaxAdvance (nscoord &aAdvance) + { aAdvance = mMaxAdvance; + return NS_OK; }; + + NS_IMETHOD GetSpaceWidth (nscoord &aSpaceCharWidth) + { aSpaceCharWidth = mSpaceWidth; + return NS_OK; }; + + NS_IMETHOD GetAveCharWidth (nscoord &aAveCharWidth) + { aAveCharWidth = mAveCharWidth; + return NS_OK; }; + + // nsIFontMetricsGTK (calls from the font rendering layer) + virtual nsresult GetWidth(const char* aString, PRUint32 aLength, + nscoord& aWidth, + nsRenderingContextGTK *aContext); + virtual nsresult GetWidth(const PRUnichar* aString, PRUint32 aLength, + nscoord& aWidth, PRInt32 *aFontID, + nsRenderingContextGTK *aContext); + + virtual nsresult GetTextDimensions(const PRUnichar* aString, + PRUint32 aLength, + nsTextDimensions& aDimensions, + PRInt32* aFontID, + nsRenderingContextGTK *aContext); + virtual nsresult GetTextDimensions(const char* aString, + PRInt32 aLength, + PRInt32 aAvailWidth, + PRInt32* aBreaks, + PRInt32 aNumBreaks, + nsTextDimensions& aDimensions, + PRInt32& aNumCharsFit, + nsTextDimensions& aLastWordDimensions, + PRInt32* aFontID, + nsRenderingContextGTK *aContext); + virtual nsresult GetTextDimensions(const PRUnichar* aString, + PRInt32 aLength, + PRInt32 aAvailWidth, + PRInt32* aBreaks, + PRInt32 aNumBreaks, + nsTextDimensions& aDimensions, + PRInt32& aNumCharsFit, + nsTextDimensions& aLastWordDimensions, + PRInt32* aFontID, + nsRenderingContextGTK *aContext); + + virtual nsresult DrawString(const char *aString, PRUint32 aLength, + nscoord aX, nscoord aY, + const nscoord* aSpacing, + nsRenderingContextGTK *aContext, + nsDrawingSurfaceGTK *aSurface); + virtual nsresult DrawString(const PRUnichar* aString, PRUint32 aLength, + nscoord aX, nscoord aY, + PRInt32 aFontID, + const nscoord* aSpacing, + nsRenderingContextGTK *aContext, + nsDrawingSurfaceGTK *aSurface); + +#ifdef MOZ_MATHML + virtual nsresult GetBoundingMetrics(const char *aString, PRUint32 aLength, + nsBoundingMetrics &aBoundingMetrics, + nsRenderingContextGTK *aContext); + virtual nsresult GetBoundingMetrics(const PRUnichar *aString, + PRUint32 aLength, + nsBoundingMetrics &aBoundingMetrics, + PRInt32 *aFontID, + nsRenderingContextGTK *aContext); +#endif /* MOZ_MATHML */ + + virtual GdkFont* GetCurrentGDKFont(void); + + virtual nsresult SetRightToLeftText(PRBool aIsRTL); + + // get hints for the font + static PRUint32 GetHints (void); + + // drawing surface methods + static nsresult FamilyExists (nsIDeviceContext *aDevice, + const nsString &aName); + +private: + + // generic font metrics class bits + nsCStringArray mFontList; + nsAutoVoidArray mFontIsGeneric; + + nsIDeviceContext *mDeviceContext; + nsCOMPtr mLangGroup; + nsCString *mGenericFont; + nsFont *mFont; + float mPointSize; + + nsCAutoString mDefaultFont; + + // Pango-related items + PangoFontDescription *mPangoFontDesc; + PangoContext *mPangoContext; + PangoContext *mLTRPangoContext; + PangoContext *mRTLPangoContext; + PangoAttrList *mPangoAttrList; + PRBool mIsRTL; + + // Cached font metrics + nscoord mXHeight; + nscoord mSuperscriptOffset; + nscoord mSubscriptOffset; + nscoord mStrikeoutOffset; + nscoord mStrikeoutSize; + nscoord mUnderlineOffset; + nscoord mUnderlineSize; + nscoord mMaxHeight; + nscoord mLeading; + nscoord mEmHeight; + nscoord mEmAscent; + nscoord mEmDescent; + nscoord mMaxAscent; + nscoord mMaxDescent; + nscoord mMaxAdvance; + nscoord mSpaceWidth; + nscoord mAveCharWidth; + + // Private methods + nsresult RealizeFont(void); + nsresult CacheFontMetrics(void); + + static PRBool EnumFontCallback(const nsString &aFamily, + PRBool aIsGeneric, void *aData); + + void DrawStringSlowly(const gchar *aText, + const PRUnichar *aOrigString, + PRUint32 aLength, + GdkDrawable *aDrawable, + GdkGC *aGC, gint aX, gint aY, + PangoLayoutLine *aLine, + const nscoord *aSpacing); + + nsresult GetTextDimensionsInternal(const gchar* aString, + PRInt32 aLength, + PRInt32 aAvailWidth, + PRInt32* aBreaks, + PRInt32 aNumBreaks, + nsTextDimensions& aDimensions, + PRInt32& aNumCharsFit, + nsTextDimensions& aLastWordDimensions, + nsRenderingContextGTK *aContext); +}; + +class nsFontEnumeratorPango : public nsIFontEnumerator +{ +public: + nsFontEnumeratorPango(); + NS_DECL_ISUPPORTS + NS_DECL_NSIFONTENUMERATOR +}; --- mozilla/gfx/src/gtk/nsFontMetricsUtils.h.foo 2002-10-11 22:03:32.000000000 -0400 +++ mozilla/gfx/src/gtk/nsFontMetricsUtils.h 2004-10-18 22:49:40.000000000 -0400 @@ -42,9 +42,12 @@ extern PRUint32 NS_FontMetricsGetHints (void); extern nsresult NS_FontMetricsFamilyExists(nsIDeviceContext *aDevice, const nsString &aName); - #ifdef MOZ_ENABLE_XFT extern PRBool NS_IsXftEnabled(void); #endif +#ifdef MOZ_ENABLE_PANGO +extern PRBool NS_IsPangoEnabled(void); +#endif + #endif /* __nsFontMetricsUtils_h */ --- mozilla/gfx/src/gtk/nsIFontMetricsGTK.h.foo 2002-10-11 23:00:17.000000000 -0400 +++ mozilla/gfx/src/gtk/nsIFontMetricsGTK.h 2004-10-18 22:49:40.000000000 -0400 @@ -121,6 +121,9 @@ // particular handle. virtual GdkFont* GetCurrentGDKFont(void) = 0; + // Set the direction of the text rendering + virtual nsresult SetRightToLeftText(PRBool aIsRTL) = 0; + }; #endif /* __nsIFontMetricsGTK_h */ --- mozilla/gfx/src/gtk/nsRenderingContextGTK.cpp.foo 2004-02-12 11:52:22.000000000 -0500 +++ mozilla/gfx/src/gtk/nsRenderingContextGTK.cpp 2004-10-18 22:49:40.000000000 -0400 @@ -524,6 +524,9 @@ values.foreground.pixel = gdk_rgb_xpixel_from_rgb(NS_TO_GDK_RGB(mCurrentColor)); + values.foreground.red = (NS_GET_R(mCurrentColor) << 8) | NS_GET_R(mCurrentColor); + values.foreground.green = (NS_GET_G(mCurrentColor) << 8) | NS_GET_G(mCurrentColor); + values.foreground.blue = (NS_GET_B(mCurrentColor) << 8) | NS_GET_B(mCurrentColor); valuesMask = GDK_GC_FOREGROUND; #ifdef MOZ_ENABLE_COREXFONTS @@ -1438,6 +1441,11 @@ #endif /* MOZ_MATHML */ +NS_IMETHODIMP nsRenderingContextGTK::SetRightToLeftText(PRBool aIsRTL) +{ + return mFontMetrics->SetRightToLeftText(aIsRTL); +} + NS_IMETHODIMP nsRenderingContextGTK::DrawImage(imgIContainer *aImage, const nsRect * aSrcRect, const nsPoint * aDestPoint) { UpdateGC(); --- mozilla/gfx/src/gtk/nsGCCache.cpp.foo 2002-02-02 22:47:15.000000000 -0500 +++ mozilla/gfx/src/gtk/nsGCCache.cpp 2004-10-18 22:49:40.000000000 -0400 @@ -232,98 +232,42 @@ // We have old GC, reuse it and check what // we have to change - XGCValues xvalues; - unsigned long xvalues_mask=0; + GdkGCValues xvalues; + int xvalues_mask = 0; if (entry->clipRegion) { // set it to none here and then set the clip region with // gdk_gc_set_clip_region in GetGC() xvalues.clip_mask = None; - xvalues_mask |= GCClipMask; + xvalues_mask |= GDK_GC_CLIP_MASK; gdk_region_destroy(entry->clipRegion); entry->clipRegion = NULL; } if (entry->gcv.foreground.pixel != gcv->foreground.pixel) { - xvalues.foreground = gcv->foreground.pixel; - xvalues_mask |= GCForeground; + xvalues.foreground.pixel = gcv->foreground.pixel; + xvalues_mask |= GDK_GC_FOREGROUND; } if (entry->gcv.function != gcv->function) { - switch (gcv->function) { - case GDK_COPY: - xvalues.function = GXcopy; - break; - case GDK_INVERT: - xvalues.function = GXinvert; - break; - case GDK_XOR: - xvalues.function = GXxor; - break; - case GDK_CLEAR: - xvalues.function = GXclear; - break; - case GDK_AND: - xvalues.function = GXand; - break; - case GDK_AND_REVERSE: - xvalues.function = GXandReverse; - break; - case GDK_AND_INVERT: - xvalues.function = GXandInverted; - break; - case GDK_NOOP: - xvalues.function = GXnoop; - break; - case GDK_OR: - xvalues.function = GXor; - break; - case GDK_EQUIV: - xvalues.function = GXequiv; - break; - case GDK_OR_REVERSE: - xvalues.function = GXorReverse; - break; - case GDK_COPY_INVERT: - xvalues.function = GXcopyInverted; - break; - case GDK_OR_INVERT: - xvalues.function = GXorInverted; - break; - case GDK_NAND: - xvalues.function = GXnand; - break; - case GDK_SET: - xvalues.function = GXset; - break; - } - xvalues_mask |= GCFunction; + xvalues.function = gcv->function; + xvalues_mask |= GDK_GC_FUNCTION; } if(entry->gcv.font != gcv->font && flags & GDK_GC_FONT) { - xvalues.font = ((XFontStruct *)GDK_FONT_XFONT(gcv->font))->fid; - xvalues_mask |= GCFont; + xvalues.font = gcv->font; + xvalues_mask |= GDK_GC_FONT; } if (entry->gcv.line_style != gcv->line_style) { - switch (gcv->line_style) { - case GDK_LINE_SOLID: - xvalues.line_style = LineSolid; - break; - case GDK_LINE_ON_OFF_DASH: - xvalues.line_style = LineOnOffDash; - break; - case GDK_LINE_DOUBLE_DASH: - xvalues.line_style = LineDoubleDash; - break; - } - xvalues_mask |= GCLineStyle; + xvalues.line_style = gcv->line_style; + xvalues_mask |= GDK_GC_LINE_STYLE; } if (xvalues_mask != 0) { - XChangeGC(GDK_GC_XDISPLAY(entry->gc), GDK_GC_XGC(entry->gc), - xvalues_mask, &xvalues); + gdk_gc_set_values(entry->gc, &xvalues, (GdkGCValuesMask)xvalues_mask); } + entry->flags = flags; entry->gcv = *gcv; } --- mozilla/gfx/src/gtk/nsFontMetricsGTK.cpp.foo 2004-03-09 09:14:54.000000000 -0500 +++ mozilla/gfx/src/gtk/nsFontMetricsGTK.cpp 2004-10-18 22:49:40.000000000 -0400 @@ -4600,6 +4600,12 @@ return mCurrentFont->GetGDKFont(); } +nsresult +nsFontMetricsGTK::SetRightToLeftText(PRBool aIsRTL) +{ + return NS_OK; +} + PR_BEGIN_EXTERN_C static int CompareSizes(const void* aArg1, const void* aArg2, void *data) --- mozilla/gfx/src/gtk/nsFontMetricsXft.h.foo 2004-02-23 16:38:52.000000000 -0500 +++ mozilla/gfx/src/gtk/nsFontMetricsXft.h 2004-10-18 22:49:40.000000000 -0400 @@ -202,6 +202,8 @@ virtual GdkFont* GetCurrentGDKFont(void); + virtual nsresult SetRightToLeftText(PRBool aIsRTL); + // get hints for the font static PRUint32 GetHints (void); --- mozilla/gfx/src/gtk/nsFontMetricsGTK.h.foo 2004-02-04 20:57:03.000000000 -0500 +++ mozilla/gfx/src/gtk/nsFontMetricsGTK.h 2004-10-18 22:49:40.000000000 -0400 @@ -344,6 +344,8 @@ virtual GdkFont* GetCurrentGDKFont(void); + virtual nsresult SetRightToLeftText(PRBool aIsRTL); + static nsresult FamilyExists(nsIDeviceContext *aDevice, const nsString& aName); static PRUint32 GetHints(void); --- mozilla/configure.in.foo 2004-05-25 22:25:16.000000000 -0400 +++ mozilla/configure.in 2004-10-18 22:49:40.000000000 -0400 @@ -3429,6 +3429,34 @@ AC_SUBST(MOZ_XFT_LIBS) dnl ======================================================== +dnl = pango font rendering +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(pango, +[ --enable-pango Enable Pango font rendering support], + MOZ_ENABLE_PANGO=1, + MOZ_ENABLE_PANGO=) + +if test "$MOZ_ENABLE_PANGO" +then + AC_DEFINE(MOZ_ENABLE_PANGO) + PKG_CHECK_MODULES(MOZ_PANGO, pango >= 1.5.0) + + dnl Make sure that the pango version is _actually_ new enough + _SAVE_CFLAGS=$CFLAGS + _SAVE_LDFLAGS=$LDFLAGS + CFLAGS="$MOZ_PANGO_CFLAGS $CFLAGS" + LDFLAGS="$MOZ_PANGO_LIBS $LDFLAGS" + AC_CHECK_LIB(pangoft2-1.0, pango_fc_font_map_add_decoder_find_func,, + AC_MSG_ERROR([Your Pango is too old. Sorry.])) + CFLAGS=$_SAVE_CFLAGS + LDFLAGS=$_SAVE_LDFLAGS + + AC_SUBST(MOZ_ENABLE_PANGO) + AC_SUBST(MOZ_PANGO_CFLAGS) + AC_SUBST(MOZ_PANGO_LIBS) +fi + +dnl ======================================================== dnl = disabling x11 core support, enabled by default dnl ======================================================== MOZ_ENABLE_COREXFONTS=${MOZ_ENABLE_COREXFONTS-1}