diff --git a/mozilla-1.7.3-pango-render.patch b/mozilla-1.7.3-pango-render.patch new file mode 100644 index 0000000..71f91b5 --- /dev/null +++ b/mozilla-1.7.3-pango-render.patch @@ -0,0 +1,3090 @@ +--- mozilla/config/autoconf.mk.in.foo 2004-03-20 21:31:17.000000000 -0500 ++++ mozilla/config/autoconf.mk.in 2004-10-13 11:17:00.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-13 11:17:00.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); +--- mozilla/gfx/src/gtk/mozilla-decoder.h.foo 2004-10-13 11:17:00.000000000 -0400 ++++ mozilla/gfx/src/gtk/mozilla-decoder.h 2004-10-13 11:17:00.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 */ +--- mozilla/gfx/src/gtk/mozilla-decoder.cpp.foo 2004-10-13 11:17:00.000000000 -0400 ++++ mozilla/gfx/src/gtk/mozilla-decoder.cpp 2004-10-13 11:17:00.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-13 11:17:00.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-13 11:17:00.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-13 11:17:00.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 + +@@ -225,3 +231,4 @@ + $(INSTALL) $^ . + endif + ++MOZ_OPTIMIZE_FLAGS=-g +--- mozilla/gfx/src/gtk/pangoFontEncoding.properties.foo 2004-10-13 11:17:00.000000000 -0400 ++++ mozilla/gfx/src/gtk/pangoFontEncoding.properties 2004-10-13 11:17:00.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-13 11:17:36.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_DISABLE_PANGO"); ++ if (val) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++#endif +--- mozilla/gfx/src/gtk/nsFontMetricsPango.cpp.foo 2004-10-13 11:17:00.000000000 -0400 ++++ mozilla/gfx/src/gtk/nsFontMetricsPango.cpp 2004-10-13 11:17:00.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-13 11:17:00.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); + +--- mozilla/gfx/src/gtk/nsFontMetricsPango.h.foo 2004-10-13 11:17:00.000000000 -0400 ++++ mozilla/gfx/src/gtk/nsFontMetricsPango.h 2004-10-13 11:17:00.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-13 11:17:00.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-13 11:17:00.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-13 11:17:00.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-13 11:17:00.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-13 11:17:00.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-13 11:17:00.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-13 11:17:00.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-13 11:17:00.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} diff --git a/thunderbird-mozconfig b/thunderbird-mozconfig index 55086f0..01460e9 100644 --- a/thunderbird-mozconfig +++ b/thunderbird-mozconfig @@ -25,3 +25,4 @@ ac_add_options --disable-tests # fedora has permission to use the official Mozilla.org branding ac_add_options --enable-official-branding +ac_add_options --enable-pango diff --git a/thunderbird.spec b/thunderbird.spec index cf38cb6..acb1ddb 100644 --- a/thunderbird.spec +++ b/thunderbird.spec @@ -8,7 +8,7 @@ ExclusiveArch: i386 x86_64 ia64 ppc Summary: Mozilla Thunderbird mail/newsgroup client Name: thunderbird Version: 0.8.0 -Release: 6 +Release: 7 Epoch: 0 URL: http://www.mozilla.org/projects/thunderbird/ License: MPL @@ -43,6 +43,9 @@ Patch103: thunderbird-0.8.0-imap-race.patch Patch104: thunderbird-0.8.0-xremote-program-name.patch Patch105: thunderbird-0.8.0-xremote-crash.patch Patch106: thunderbird-0.8.0-access-64bit-crash.patch +Patch107: mozilla-1.7.3-pango-render.patch + + BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -52,6 +55,7 @@ BuildRequires: XFree86-devel BuildRequires: libIDL-devel BuildRequires: tcsh BuildRequires: freetype-devel +BuildRequires: autoconf213 Prereq: desktop-file-utils >= %{desktop_file_utils_version} Obsoletes: MozillaThunderbird Provides: MozillaThunderbird = %{epoch}:%{version} @@ -88,10 +92,13 @@ cp -f %{SOURCE5} . %patch104 -p0 -b .xremote-programname %patch105 -p0 -b .xremote-crash %patch106 -p0 -b .access-64bit-crash +%patch107 -p1 -b .pango #=============================================================================== %build +autoconf-2.13 + export RPM_OPT_FLAGS=$(echo $RPM_OPT_FLAGS | sed 's/-O2/-Os/') export CFLAGS="$RPM_OPT_FLAGS" export CXXFLAGS="$CFLAGS" @@ -155,6 +162,9 @@ rm -rf %{buildroot}/%{tbdir}/chrome/{classic,comm,embed-sample,en-{mac,win},help #=============================================================================== %changelog +* Thu Oct 14 2004 Christopher Blizzard 0.8.0-7 +- Use pango for rendering + * Tue Oct 12 2004 Christopher Aillon 0.8.0-6 - Fix for 64 bit crash at startup (b.m.o #256603)