diff options
Diffstat (limited to 'firefox-2.0-pango-printing.patch')
-rw-r--r-- | firefox-2.0-pango-printing.patch | 4576 |
1 files changed, 4576 insertions, 0 deletions
diff --git a/firefox-2.0-pango-printing.patch b/firefox-2.0-pango-printing.patch new file mode 100644 index 0000000..794ced9 --- /dev/null +++ b/firefox-2.0-pango-printing.patch @@ -0,0 +1,4576 @@ +Patch for Firefox 1.5.0.7 to add support for printing via Pango. +This also implements printing MathML via Pango, and prints bitmap +fonts too. + +Authors: + Behdad Esfahbod + Chris Blizzard + Akira TAGOH + +Index: gfx/src/freetype/nsFreeType.cpp +=================================================================== +RCS file: /cvsroot/mozilla/gfx/src/freetype/nsFreeType.cpp,v +retrieving revision 1.28 +diff -u -p -d -r1.28 nsFreeType.cpp +--- gfx/src/freetype/nsFreeType.cpp 13 Jul 2005 18:21:10 -0000 1.28 ++++ gfx/src/freetype/nsFreeType.cpp 23 Oct 2006 17:37:09 -0000 +@@ -123,6 +123,8 @@ FtFuncList nsFreeType2::FtFuncs [] = { + // #endif + {"FT_Get_First_Char", NS_FT2_OFFSET(nsFT_Get_First_Char), PR_FALSE}, + {"FT_Get_Next_Char", NS_FT2_OFFSET(nsFT_Get_Next_Char), PR_FALSE}, ++ {"FT_Has_PS_Glyph_Names", NS_FT2_OFFSET(nsFT_Has_PS_Glyph_Names), PR_FALSE}, ++ {"FT_Get_Glyph_Name", NS_FT2_OFFSET(nsFT_Get_Glyph_Name), PR_TRUE}, + {nsnull, 0, 0} + }; + +@@ -388,6 +390,22 @@ nsFreeType2::GetNextChar(FT_Face face, F + } + + NS_IMETHODIMP ++nsFreeType2::HasPSGlyphNames(FT_Face face, FT_Int *result) ++{ ++ // call the FreeType2 function via the function pointer ++ *result = nsFT_Has_PS_Glyph_Names(face); ++ return NS_OK; ++} ++ ++NS_IMETHODIMP ++nsFreeType2::GetGlyphName(FT_Face face, FT_UInt glyph_index, FT_Pointer buffer, FT_UInt buffer_max) ++{ ++ // call the FreeType2 function via the function pointer ++ FT_Error error = nsFT_Get_Glyph_Name(face, glyph_index, buffer, buffer_max); ++ return error ? NS_ERROR_FAILURE : NS_OK; ++} ++ ++NS_IMETHODIMP + nsFreeType2::SupportsExtFunc(PRBool *res) + { + *res = gHasExtFunc; +Index: gfx/src/freetype/nsFreeType.h +=================================================================== +RCS file: /cvsroot/mozilla/gfx/src/freetype/nsFreeType.h,v +retrieving revision 1.18 +diff -u -p -d -r1.18 nsFreeType.h +--- gfx/src/freetype/nsFreeType.h 1 May 2005 17:36:19 -0000 1.18 ++++ gfx/src/freetype/nsFreeType.h 23 Oct 2006 17:37:09 -0000 +@@ -52,6 +52,7 @@ + #include FT_CACHE_H + #include FT_CACHE_IMAGE_H + #include FT_TRUETYPE_TABLES_H ++#include FT_TYPE1_TABLES_H + #include "nsIFreeType2.h" + + typedef struct FT_FaceRec_* FT_Face; +@@ -138,6 +139,8 @@ typedef FT_Error (*FT_Glyph_To_Bitmap_t) + + typedef FT_ULong (*FT_Get_First_Char_t)(FT_Face, FT_UInt*); + typedef FT_ULong (*FT_Get_Next_Char_t)(FT_Face, FT_ULong, FT_UInt*); ++typedef FT_Int (*FT_Has_PS_Glyph_Names_t)(FT_Face); ++typedef FT_Error (*FT_Get_Glyph_Name_t)(FT_Face, FT_UInt, FT_Pointer, FT_UInt); + + class nsFreeTypeFace; + +@@ -193,11 +196,13 @@ protected: + // #endif + FT_Get_First_Char_t nsFT_Get_First_Char; + FT_Get_Next_Char_t nsFT_Get_Next_Char; ++ FT_Has_PS_Glyph_Names_t nsFT_Has_PS_Glyph_Names; ++ FT_Get_Glyph_Name_t nsFT_Get_Glyph_Name; + + // this array needs to be big enough to hold all the function pointers + // plus one extra for the null at the end + // #ifdef MOZ_SVG +- static FtFuncList FtFuncs[24]; ++ static FtFuncList FtFuncs[28]; + // #else + // static FtFuncList FtFuncs[20]; + // #endif +Index: gfx/src/ps/Makefile.in +=================================================================== +RCS file: /cvsroot/mozilla/gfx/src/ps/Makefile.in,v +retrieving revision 1.57.8.1 +diff -d -u -p -r1.57.8.1 Makefile.in +--- gfx/src/ps/Makefile.in 17 Jun 2006 15:16:14 -0000 1.57.8.1 ++++ gfx/src/ps/Makefile.in 24 Oct 2006 18:36:45 -0000 +@@ -98,6 +98,15 @@ EXTRA_DSO_LDOPTS = \ + $(MOZ_UNICHARUTIL_LIBS) \ + $(NULL) + ++ifdef MOZ_ENABLE_PANGO ++CPPSRCS += \ ++ nsFontMetricsPSPango.cpp \ ++ mozilla-ps-decoder.cpp ++EXTRA_DSO_LDOPTS += $(MOZ_PANGO_LIBS) ++CXXFLAGS += $(MOZ_PANGO_CFLAGS) ++CFLAGS += $(MOZ_PANGO_CFLAGS) ++endif ++ + ifdef MOZ_ENABLE_XFT + EXTRA_DSO_LDOPTS += \ + $(MOZ_XFT_LIBS) \ +@@ -105,7 +114,7 @@ EXTRA_DSO_LDOPTS += \ + $(NULL) + endif + +-ifneq (,$(MOZ_ENABLE_FREETYPE2)$(MOZ_ENABLE_XFT)) ++ifneq (,$(MOZ_ENABLE_FREETYPE2)$(MOZ_ENABLE_XFT)$(MOZ_ENABLE_PANGO)) + CPPSRCS += \ + nsType1.cpp \ + $(NULL) +Index: gfx/src/ps/mozilla-ps-decoder.cpp +=================================================================== +RCS file: gfx/src/ps/mozilla-ps-decoder.cpp +diff -N gfx/src/ps/mozilla-ps-decoder.cpp +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ gfx/src/ps/mozilla-ps-decoder.cpp 23 Oct 2006 17:37:10 -0000 +@@ -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 ++ * <blizzard@mozilla.org>. 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-ps-decoder.h" ++#include <pango/pangofc-fontmap.h> ++#include <pango/pangofc-font.h> ++ ++#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 (MozillaPSDecoder, mozilla_ps_decoder, PANGO_TYPE_FC_DECODER) ++ ++MozillaPSDecoder *mozilla_ps_decoder_new (void); ++ ++static FcCharSet *mozilla_ps_decoder_get_charset (PangoFcDecoder *decoder, ++ PangoFcFont *fcfont); ++static PangoGlyph mozilla_ps_decoder_get_glyph (PangoFcDecoder *decoder, ++ PangoFcFont *fcfont, ++ guint32 wc); ++ ++static PangoFcDecoder *mozilla_find_ps_decoder (FcPattern *pattern, ++ gpointer user_data); ++ ++typedef struct _MozillaPSDecoderPrivate MozillaPSDecoderPrivate; ++ ++#define MOZILLA_PS_DECODER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MOZILLA_TYPE_DECODER, MozillaPSDecoderPrivate)) ++ ++struct _MozillaPSDecoderPrivate { ++ char *family; ++ char *encoder; ++ char *cmap; ++ gboolean is_wide; ++ FcCharSet *charset; ++ nsCOMPtr<nsIUnicodeEncoder> 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. ++static GHashTable *encoder_hash = NULL; ++static GHashTable *cmap_hash = NULL; ++static GHashTable *wide_hash = NULL; ++ ++void ++mozilla_ps_decoder_init (MozillaPSDecoder *decoder) ++{ ++} ++ ++void ++mozilla_ps_decoder_class_init (MozillaPSDecoderClass *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_ps_decoder_get_charset; ++ parent_class->get_glyph = mozilla_ps_decoder_get_glyph; ++ ++ g_type_class_add_private (object_class, sizeof (MozillaPSDecoderPrivate)); ++} ++ ++MozillaPSDecoder * ++mozilla_ps_decoder_new(void) ++{ ++ return (MozillaPSDecoder *)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_ps_decoders_init: ++ * ++ * #mozilla_ps_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_ps_decoders_init(PangoFontMap *fontmap) ++{ ++ static PRBool initialized = PR_FALSE; ++ if (initialized) ++ return 0; ++ ++ if (!PANGO_IS_FC_FONT_MAP (fontmap)) ++ return -1; ++ ++ 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<nsIPersistentProperties> props; ++ nsCOMPtr<nsISimpleEnumerator> 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<nsIPropertyElement> 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(fontmap), ++ mozilla_find_ps_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; ++} ++ ++static FcCharSet * ++mozilla_ps_decoder_get_charset (PangoFcDecoder *decoder, ++ PangoFcFont *fcfont) ++{ ++ MozillaPSDecoderPrivate *priv = MOZILLA_PS_DECODER_GET_PRIVATE(decoder); ++ ++ if (priv->charset) ++ return priv->charset; ++ ++ // First time this has been accessed. Populate the charset. ++ priv->charset = FcCharSetCreate(); ++ ++ if (!gCharsetManager) { ++ CallGetService(kCharsetConverterManagerCID, &gCharsetManager); ++ } ++ ++ nsCOMPtr<nsIUnicodeEncoder> encoder; ++ nsCOMPtr<nsICharRepresentable> 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; ++} ++ ++static PangoGlyph ++mozilla_ps_decoder_get_glyph (PangoFcDecoder *decoder, ++ PangoFcFont *fcfont, ++ guint32 wc) ++{ ++ MozillaPSDecoderPrivate *priv = MOZILLA_PS_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_ps_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; ++} ++ ++static PangoFcDecoder * ++mozilla_find_ps_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; ++ ++ MozillaPSDecoder *decoder = mozilla_ps_decoder_new(); ++ ++ MozillaPSDecoderPrivate *priv = MOZILLA_PS_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); ++} +Index: gfx/src/ps/mozilla-ps-decoder.h +=================================================================== +RCS file: gfx/src/ps/mozilla-ps-decoder.h +diff -N gfx/src/ps/mozilla-ps-decoder.h +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ gfx/src/ps/mozilla-ps-decoder.h 23 Oct 2006 17:37:10 -0000 +@@ -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 ++ * <blizzard@mozilla.org>. 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_PS_DECODER_H ++#define _MOZILLA_PS_DECODER_H ++ ++#include <pango/pangofc-decoder.h> ++ ++G_BEGIN_DECLS ++ ++#define MOZILLA_TYPE_DECODER (mozilla_ps_decoder_get_type()) ++#define MOZILLA_PS_DECODER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOZILLA_TYPE_DECODER, MozillaPSDecoder)) ++#define MOZILLA_IS_DECODER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOZILLA_TYPE_DECODER)) ++ ++typedef struct _MozillaPSDecoder MozillaPSDecoder; ++typedef struct _MozillaPSDecoderClass MozillaPSDecoderClass; ++ ++#define MOZILLA_PS_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOZILLA_TYPE_DECODER, MozillaPSDecoderClass)) ++#define MOZILLA_IS_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOZILLA_TYPE_DECODER)) ++#define MOZILLA_PS_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOZILLA_TYPE_DECODER, MozillaPSDecoderClass)) ++ ++struct _MozillaPSDecoder ++{ ++ PangoFcDecoder parent_instance; ++}; ++ ++struct _MozillaPSDecoderClass ++{ ++ PangoFcDecoderClass parent_class; ++}; ++ ++GType mozilla_ps_decoder_get_type (void); ++int mozilla_ps_decoders_init (PangoFontMap *fontmap); ++ ++G_END_DECLS ++ ++#endif /*_MOZILLA_PS_DECODER_H */ +Index: gfx/src/ps/nsDeviceContextPS.cpp +=================================================================== +RCS file: /cvsroot/mozilla/gfx/src/ps/nsDeviceContextPS.cpp,v +retrieving revision 1.73 +diff -u -p -d -r1.73 nsDeviceContextPS.cpp +--- gfx/src/ps/nsDeviceContextPS.cpp 21 May 2005 15:33:08 -0000 1.73 ++++ gfx/src/ps/nsDeviceContextPS.cpp 23 Oct 2006 17:37:10 -0000 +@@ -58,12 +58,15 @@ + #include "nsIPref.h" + #include "nsString.h" + #include "nsFontMetricsPS.h" ++#ifdef MOZ_ENABLE_PANGO ++#include "nsFontMetricsPSPango.h" ++#endif + #include "nsPostScriptObj.h" + #include "nspr.h" + #include "nsILanguageAtomService.h" + #include "nsPrintJobPS.h" + #include "nsPrintJobFactoryPS.h" +-#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) ++#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) + #include "nsType1.h" + #endif + +@@ -223,7 +226,7 @@ nsDeviceContextPS::InitDeviceContextPS(n + + nsresult rv; + nsCOMPtr<nsIPref> pref(do_GetService(NS_PREF_CONTRACTID, &rv)); +-#ifdef MOZ_ENABLE_XFT ++#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) + if (NS_SUCCEEDED(rv)) { + rv = pref->GetBoolPref("font.FreeType2.printing", &mFTPEnable); + if (NS_FAILED(rv)) +@@ -469,7 +472,7 @@ NS_IMETHODIMP nsDeviceContextPS::EndDocu + NS_ASSERTION(submitFP, "No print job submission handle"); + + // Start writing the print job to the job handler +-#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) ++#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) + mPSObj->write_prolog(submitFP, mFTPEnable); + #else + mPSObj->write_prolog(submitFP); +@@ -550,15 +553,52 @@ public: + virtual nsresult CreateFontMetricsInstance(nsIFontMetrics** aResult); + }; + ++#if defined(MOZ_ENABLE_PANGO) ++PRBool ++NS_IsPangoEnabled(void) ++{ ++ static PRBool beenHere; ++ static PRBool pangoEnabled; ++ ++ if (!beenHere) { ++ beenHere = PR_TRUE; ++ ++ char *val = PR_GetEnv("MOZ_DISABLE_PANGO"); ++ pangoEnabled = !(val); ++ ++ if (pangoEnabled) { ++ nsCOMPtr<nsIPref> prefService = do_GetService(NS_PREF_CONTRACTID); ++ if (prefService) ++ prefService->SetDefaultCharPref("general.useragent.extra.pango", ++ "pango-text"); ++ } ++ } ++ ++ return pangoEnabled; ++} ++#endif + + nsresult nsFontCachePS::CreateFontMetricsInstance(nsIFontMetrics** aResult) + { + NS_PRECONDITION(aResult, "null out param"); +- nsIFontMetrics *fm = new nsFontMetricsPS(); +- if (!fm) +- return NS_ERROR_OUT_OF_MEMORY; +- NS_ADDREF(fm); +- *aResult = fm; ++#ifdef MOZ_ENABLE_PANGO ++ if (NS_IsPangoEnabled()) ++ { ++ nsIFontMetrics *fm = new nsFontMetricsPSPango(); ++ if (!fm) ++ return NS_ERROR_OUT_OF_MEMORY; ++ NS_ADDREF(fm); ++ *aResult = fm; ++ } ++ else ++#endif ++ { ++ nsIFontMetrics *fm = new nsFontMetricsPS(); ++ if (!fm) ++ return NS_ERROR_OUT_OF_MEMORY; ++ NS_ADDREF(fm); ++ *aResult = fm; ++ } + return NS_OK; + } + +Index: gfx/src/ps/nsFontMetricsPS.cpp +=================================================================== +RCS file: /cvsroot/mozilla/gfx/src/ps/nsFontMetricsPS.cpp,v +retrieving revision 1.57.16.2 +diff -u -p -d -r1.57.16.2 nsFontMetricsPS.cpp +--- gfx/src/ps/nsFontMetricsPS.cpp 7 May 2006 02:01:25 -0000 1.57.16.2 ++++ gfx/src/ps/nsFontMetricsPS.cpp 23 Oct 2006 17:37:11 -0000 +@@ -461,6 +461,239 @@ nsFontMetricsPS :: GetStringWidth(const + return NS_OK; + } + ++nsresult ++nsFontMetricsPS::DrawString(const char *aString, PRUint32 aLength, ++ nscoord aX, nscoord aY, ++ const nscoord* aSpacing, ++ nsRenderingContextPS *aContext) ++{ ++ nsPostScriptObj* psObj = aContext->GetPostScriptObj(); ++ // When FT2 printing is enabled, we don't need to set langgroup ++#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) ++ if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, GetDeviceContext())->mFTPEnable) { ++#endif ++ nsCOMPtr<nsIAtom> langGroup; ++ GetLangGroup(getter_AddRefs(langGroup)); ++ psObj->setlanggroup(langGroup); ++#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) ++ } ++#endif ++ ++ if (aLength == 0) ++ return NS_OK; ++ nsFontPS* fontPS = nsFontPS::FindFont(aString[0], Font(), this); ++ NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE); ++ fontPS->SetupFont(aContext); ++ ++ PRUint32 i, start = 0; ++ for (i=0; i<aLength; i++) { ++ nsFontPS* fontThisChar; ++ fontThisChar = nsFontPS::FindFont(aString[i], Font(), this); ++ NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE); ++ if (fontThisChar != fontPS) { ++ // draw text up to this point ++ aX += DrawString(aString+start, i-start, aX, aY, fontPS, ++ aSpacing?aSpacing+start:nsnull, aContext); ++ start = i; ++ ++ // setup for following text ++ fontPS = fontThisChar; ++ fontPS->SetupFont(aContext); ++ } ++ } ++ ++ // draw the last part ++ if (aLength-start) ++ DrawString(aString+start, aLength-start, aX, aY, fontPS, ++ aSpacing?aSpacing+start:nsnull, aContext); ++ ++ return NS_OK; ++} ++ ++nsresult ++nsFontMetricsPS::DrawString(const PRUnichar* aString, PRUint32 aLength, ++ nscoord aX, nscoord aY, ++ PRInt32 aFontID, ++ const nscoord* aSpacing, ++ nsRenderingContextPS *aContext) ++{ ++ nsPostScriptObj* psObj = aContext->GetPostScriptObj(); ++#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) ++ // When FT2 printing is enabled, we don't need to set langgroup ++ if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, GetDeviceContext())->mFTPEnable) { ++#endif ++ nsCOMPtr<nsIAtom> langGroup = nsnull; ++ GetLangGroup(getter_AddRefs(langGroup)); ++ psObj->setlanggroup(langGroup); ++#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) ++ } ++#endif ++ ++ /* build up conversion table */ ++ psObj->preshow(aString, aLength); ++ ++ if (aLength == 0) ++ return NS_OK; ++ nsFontPS* fontPS = nsFontPS::FindFont(aString[0], Font(), this); ++ NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE); ++ fontPS->SetupFont(aContext); ++ ++ PRUint32 i, start = 0; ++ for (i=0; i<aLength; i++) { ++ nsFontPS* fontThisChar; ++ fontThisChar = nsFontPS::FindFont(aString[i], Font(), this); ++ NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE); ++ if (fontThisChar != fontPS) { ++ // draw text up to this point ++ aX += DrawString(aString+start, i-start, aX, aY, fontPS, ++ aSpacing?aSpacing+start:nsnull, aContext); ++ start = i; ++ ++ // setup for following text ++ fontPS = fontThisChar; ++ fontPS->SetupFont(aContext); ++ } ++ } ++ ++ // draw the last part ++ if (aLength-start) ++ DrawString(aString+start, aLength-start, aX, aY, fontPS, ++ aSpacing?aSpacing+start:nsnull, aContext); ++ ++ return NS_OK; ++} ++ ++PRInt32 ++nsFontMetricsPS::DrawString(const char *aString, PRUint32 aLength, ++ nscoord aX, nscoord aY, nsFontPS* aFontPS, ++ const nscoord* aSpacing, ++ nsRenderingContextPS *aContext) ++{ ++ nscoord width = 0; ++ PRInt32 x = aX; ++ PRInt32 y = aY; ++ ++ PRInt32 dxMem[500]; ++ PRInt32* dx0 = 0; ++ if (aSpacing) { ++ dx0 = dxMem; ++ if (aLength > 500) { ++ dx0 = new PRInt32[aLength]; ++ NS_ENSURE_TRUE(dx0, NS_ERROR_OUT_OF_MEMORY); ++ } ++ aContext->GetTranMatrix()->ScaleXCoords(aSpacing, aLength, dx0); ++ } ++ ++ aContext->GetTranMatrix()->TransformCoord(&x, &y); ++ width = aFontPS->DrawString(aContext, x, y, aString, aLength); ++ ++ if ((aSpacing) && (dx0 != dxMem)) { ++ delete [] dx0; ++ } ++ ++ return width; ++} ++ ++ ++PRInt32 ++nsFontMetricsPS::DrawString(const PRUnichar* aString, PRUint32 aLength, ++ nscoord &aX, nscoord &aY, nsFontPS* aFontPS, ++ const nscoord* aSpacing, ++ nsRenderingContextPS *aContext) ++{ ++ nscoord width = 0; ++ PRInt32 x = aX; ++ PRInt32 y = aY; ++ ++ if (aSpacing) { ++ // Slow, but accurate rendering ++ const PRUnichar* end = aString + aLength; ++ while (aString < end){ ++ x = aX; ++ y = aY; ++ aContext->GetTranMatrix()->TransformCoord(&x, &y); ++ aFontPS->DrawString(aContext, x, y, aString, 1); ++ aX += *aSpacing++; ++ aString++; ++ } ++ width = aX; ++ } else { ++ aContext->GetTranMatrix()->TransformCoord(&x, &y); ++ width = aFontPS->DrawString(aContext, x, y, aString, aLength); ++ } ++ ++ return width; ++} ++ ++NS_IMETHODIMP ++nsFontMetricsPS::GetTextDimensions(const char* aString, ++ PRInt32 aLength, ++ PRInt32 aAvailWidth, ++ PRInt32* aBreaks, ++ PRInt32 aNumBreaks, ++ nsTextDimensions& aDimensions, ++ PRInt32& aNumCharsFit, ++ nsTextDimensions& aLastWordDimensions, ++ PRInt32* aFontID) ++{ ++ NS_NOTYETIMPLEMENTED("nsFontMetricsPS::GetTextDimensions"); ++ return NS_ERROR_NOT_IMPLEMENTED; ++} ++ ++NS_IMETHODIMP ++nsFontMetricsPS::GetTextDimensions(const PRUnichar* aString, ++ PRInt32 aLength, ++ PRInt32 aAvailWidth, ++ PRInt32* aBreaks, ++ PRInt32 aNumBreaks, ++ nsTextDimensions& aDimensions, ++ PRInt32& aNumCharsFit, ++ nsTextDimensions& aLastWordDimensions, ++ PRInt32* aFontID) ++{ ++ NS_NOTYETIMPLEMENTED("nsFontMetricsPS::GetTextDimensions"); ++ return NS_ERROR_NOT_IMPLEMENTED; ++} ++ ++NS_IMETHODIMP ++nsFontMetricsPS :: GetTextDimensions(const char* aString, PRUint32 aLength, ++ nsTextDimensions& aDimensions) ++{ ++ GetStringWidth(aString, aDimensions.width, aLength); ++ GetMaxAscent(aDimensions.ascent); ++ GetMaxDescent(aDimensions.descent); ++ return NS_OK; ++} ++ ++NS_IMETHODIMP ++nsFontMetricsPS :: GetTextDimensions(const PRUnichar* aString, PRUint32 aLength, ++ nsTextDimensions& aDimensions, PRInt32* aFontID) ++{ ++ GetStringWidth(aString, aDimensions.width, aLength); ++ //XXX temporary - bug 96609 ++ GetMaxAscent(aDimensions.ascent); ++ GetMaxDescent(aDimensions.descent); ++ return NS_OK; ++} ++ ++nsresult ++nsFontMetricsPS::GetBoundingMetrics(const char* aString, ++ PRUint32 aLength, ++ nsBoundingMetrics& aBoundingMetrics) ++{ ++ return NS_ERROR_NOT_IMPLEMENTED; ++} ++ ++nsresult ++nsFontMetricsPS::GetBoundingMetrics(const PRUnichar* aString, ++ PRUint32 aLength, ++ nsBoundingMetrics &aBoundingMetrics, ++ PRInt32 *aFontID) ++{ ++ return NS_ERROR_NOT_IMPLEMENTED; ++} ++ ++ + nsFontPS* + nsFontPS::FindFont(char aChar, const nsFont& aFont, + nsFontMetricsPS* aFontMetrics) +@@ -1128,23 +1361,38 @@ nsFontPSXft::DrawString(nsRenderingConte + PRUint32 start = 0; + PRUint32 i; + ++ FT_Face face = getFTFace(); ++ if (!face) { ++ NS_WARNING("Failed to get FT Face in nsFontPSXft::DrawString\n"); ++ return 0; ++ } ++ ++ nsValueArray glyphs(PR_UINT16_MAX); ++ + // XXX : ignore surrogate pairs for now +- nsString *subSet = mPSFontGenerator->GetSubset(); + for (i = 0; i < aLength; ++i) { +- currSubFont = mPSFontGenerator->AddToSubset(aString[i]); ++ PRUint32 glyph = FT_Get_Char_Index(face, aString[i]); ++ currSubFont = mPSFontGenerator->AddToGlyphSubset(glyph); ++ ++ // Check if we need to render the current string + if (prevSubFont != currSubFont) { +- if (prevSubFont != -1) +- psObj->show(&aString[start], i - start, *subSet, prevSubFont); ++ if (prevSubFont != -1) { ++ psObj->show(&glyphs, mPSFontGenerator, prevSubFont); ++ } + NS_ASSERTION(!mFontNameBase.IsEmpty(), + "font base name shouldn't be empty"); + psObj->setfont(mFontNameBase, mHeight, currSubFont); + prevSubFont = currSubFont; + start = i; ++ glyphs.Clear(); + } ++ ++ glyphs.AppendValue(glyph); + } + +- if (prevSubFont != -1) +- psObj->show(&aString[start], i - start, *subSet, prevSubFont); ++ if (prevSubFont != -1) { ++ psObj->show(&glyphs, mPSFontGenerator, prevSubFont); ++ } + + return GetWidth(aString, aLength); + } +@@ -2278,10 +2526,13 @@ nsFontPSFreeType::GetBoundingMetrics(con + // Implementation of nsPSFontGenerator + nsPSFontGenerator::nsPSFontGenerator() + { ++ mGlyphSubset = new nsValueArray(PR_UINT16_MAX, 40); + } + + nsPSFontGenerator::~nsPSFontGenerator() + { ++ if (mGlyphSubset) ++ delete mGlyphSubset; + } + + void nsPSFontGenerator::GeneratePSFont(FILE* aFile) +@@ -2289,24 +2540,29 @@ void nsPSFontGenerator::GeneratePSFont(F + NS_ERROR("should never call nsPSFontGenerator::GeneratePSFont"); + } + +-// Add a Unicode character to mSubset which will be divided into +-// multiple chunks (subfonts) of 255 (kSubFontSize) characters each. +-// Each chunk will be converted to a Type 1 font. Return the index of +-// a subfont (chunk) this character belongs to. ++// Add a glyph offset to mSubset which will be divided into multiple ++// chunks (subfonts) of 255 (kSubFontSize) glyphs each. Each chunk ++// will then be converted into a Type 1 font. Return the index of a ++// subfont (chunk) this glyph belongs to. + PRInt32 +-nsPSFontGenerator::AddToSubset(PRUnichar aChar) ++nsPSFontGenerator::AddToGlyphSubset(PRUint32 aGlyph) + { +- PRInt32 index = mSubset.FindChar(aChar); +- if (index == kNotFound) { +- mSubset.Append(aChar); +- index = mSubset.Length() - 1; ++ nsValueArrayIndex index = mGlyphSubset->IndexOf(aGlyph); ++ if (index == NSVALUEARRAY_INVALID) { ++ mGlyphSubset->AppendValue(aGlyph); ++ index = mGlyphSubset->Count() - 1; + } ++ + return index / kSubFontSize; + } + +-nsString *nsPSFontGenerator::GetSubset() ++PRInt32 ++nsPSFontGenerator::InSubsetIndexOf(PRUint32 aGlyph) + { +- return &mSubset; ++ nsValueArrayIndex index = mGlyphSubset->IndexOf(aGlyph); ++ if (index == NSVALUEARRAY_INVALID) ++ return 0; ++ return (index % kSubFontSize) + 1; + } + + #ifdef MOZ_ENABLE_XFT +@@ -2332,8 +2588,8 @@ nsXftType1Generator::Init(nsXftEntry* aE + + nsXftType1Generator::~nsXftType1Generator() + { +- if (mEntry->mFace) +- FT_Done_Face(mEntry->mFace); ++ if (mEntry->mFace) ++ FT_Done_Face(mEntry->mFace); + + if (FT_Done_FreeType(mFreeTypeLibrary)) + return; +@@ -2353,8 +2609,8 @@ void nsXftType1Generator::GeneratePSFont + } + + int wmode = 0; +- if (!mSubset.IsEmpty()) +- FT2SubsetToType1FontSet(face, mSubset, wmode, aFile); ++ if (mGlyphSubset->Count()) ++ FT2SubsetToType1FontSet(face, mGlyphSubset, wmode, aFile); + } + + #else +@@ -2402,8 +2658,8 @@ void nsFT2Type1Generator::GeneratePSFont + return; + + int wmode = 0; +- if (!mSubset.IsEmpty()) +- FT2SubsetToType1FontSet(face, mSubset, wmode, aFile); ++ if (mGlyphSubset->Count()) ++ FT2SubsetToType1FontSet(face, mGlyphSubset, wmode, aFile); + } + + #endif //MOZ_ENABLE_FREETYPE2 +Index: gfx/src/ps/nsFontMetricsPS.h +=================================================================== +RCS file: /cvsroot/mozilla/gfx/src/ps/nsFontMetricsPS.h,v +retrieving revision 1.31 +diff -u -p -d -r1.31 nsFontMetricsPS.h +--- gfx/src/ps/nsFontMetricsPS.h 28 Jun 2005 18:29:10 -0000 1.31 ++++ gfx/src/ps/nsFontMetricsPS.h 23 Oct 2006 17:37:11 -0000 +@@ -66,6 +66,7 @@ + #endif + #include "nsVoidArray.h" + #include "nsHashtable.h" ++#include "nsValueArray.h" + + class nsPSFontGenerator; + class nsDeviceContextPS; +@@ -108,6 +109,65 @@ public: + NS_IMETHOD GetFontHandle(nsFontHandle &aHandle); + NS_IMETHOD GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength); + NS_IMETHOD GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength); ++ ++ NS_IMETHOD GetTextDimensions(const char* aString, ++ PRUint32 aLength, ++ nsTextDimensions& aDimensions); ++ NS_IMETHOD GetTextDimensions(const PRUnichar* aString, ++ PRUint32 aLength, ++ nsTextDimensions& aDimensions, ++ PRInt32* aFontID); ++ NS_IMETHOD GetTextDimensions(const char* aString, ++ PRInt32 aLength, ++ PRInt32 aAvailWidth, ++ PRInt32* aBreaks, ++ PRInt32 aNumBreaks, ++ nsTextDimensions& aDimensions, ++ PRInt32& aNumCharsFit, ++ nsTextDimensions& aLastWordDimensions, ++ PRInt32* aFontID); ++ NS_IMETHOD GetTextDimensions(const PRUnichar* aString, ++ PRInt32 aLength, ++ PRInt32 aAvailWidth, ++ PRInt32* aBreaks, ++ PRInt32 aNumBreaks, ++ nsTextDimensions& aDimensions, ++ PRInt32& aNumCharsFit, ++ nsTextDimensions& aLastWordDimensions, ++ PRInt32* aFontID); ++#ifdef MOZ_MATHML ++ NS_IMETHOD GetBoundingMetrics(const char *aString, PRUint32 aLength, ++ nsBoundingMetrics &aBoundingMetrics); ++ NS_IMETHOD GetBoundingMetrics(const PRUnichar *aString, ++ PRUint32 aLength, ++ nsBoundingMetrics &aBoundingMetrics, ++ PRInt32 *aFontID); ++#endif /* MOZ_MATHML */ ++ ++ NS_IMETHOD DrawString(const char *aString, PRUint32 aLength, ++ nscoord aX, nscoord aY, ++ const nscoord* aSpacing, ++ nsRenderingContextPS *aContext); ++ NS_IMETHOD DrawString(const PRUnichar *aString, PRUint32 aLength, ++ nscoord aX, nscoord aY, ++ PRInt32 aFontID, ++ const nscoord* aSpacing, ++ nsRenderingContextPS *aContext); ++ ++protected: ++ PRInt32 DrawString(const char *aString, PRUint32 aLength, ++ nscoord aX, nscoord aY, nsFontPS* aFontPS, ++ const nscoord* aSpacing, ++ nsRenderingContextPS *aContext); ++ PRInt32 DrawString(const PRUnichar *aString, PRUint32 aLength, ++ nscoord &aX, nscoord &aY, nsFontPS* aFontPS, ++ const nscoord* aSpacing, ++ nsRenderingContextPS *aContext); ++ ++public: ++ ++ virtual PRUint32 GetHints (void) { return 0; } ++ + + inline void SetXHeight(nscoord aXHeight) { mXHeight = aXHeight; }; + inline void SetSuperscriptOffset(nscoord aSuperscriptOffset) { mSuperscriptOffset = aSuperscriptOffset; }; +@@ -455,16 +515,14 @@ public: + nsPSFontGenerator(); + virtual ~nsPSFontGenerator(); + virtual void GeneratePSFont(FILE* aFile); +- PRInt32 AddToSubset(PRUnichar aChar); +- nsString *GetSubset(); ++ PRInt32 AddToGlyphSubset(PRUint32 aGlyph); ++ PRInt32 InSubsetIndexOf(PRUint32 aGlyph); + + // 256 (PS type 1 encoding vector size) - 1 (1 is for mandatory /.notdef) + const static PRUint16 kSubFontSize; + + protected: +- // XXX To support non-BMP characters, we may have to use +- // nsValueArray with PRUint32 +- nsString mSubset; ++ nsValueArray *mGlyphSubset; + }; + + +Index: gfx/src/ps/nsFontMetricsPSPango.cpp +=================================================================== +RCS file: gfx/src/ps/nsFontMetricsPSPango.cpp +diff -N gfx/src/ps/nsFontMetricsPSPango.cpp +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ gfx/src/ps/nsFontMetricsPSPango.cpp 23 Oct 2006 17:37:13 -0000 +@@ -0,0 +1,2107 @@ ++/* -*- 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 ++ * <blizzard@mozilla.org>. Portions created by the Initial Developer ++ * are Copyright (C) 2004 the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * Christopher Blizzard <blizzard@mozilla.org> ++ * Behdad Esfahbod <behdad@behdad.org> ++ * ++ * 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 <strings.h> ++#include "nsFont.h" ++#include "nsIDeviceContext.h" ++#include "nsICharsetConverterManager.h" ++#include "nsIPref.h" ++#include "nsServiceManagerUtils.h" ++ ++#define PANGO_ENABLE_BACKEND ++#define PANGO_ENABLE_ENGINE ++ ++#include "nsFontMetricsPSPango.h" ++#include "nsRenderingContextPS.h" ++#include "nsDeviceContextPS.h" ++#include "nsFontConfigUtils.h" ++ ++#include "nsPrintfCString.h" ++#include "nsUnicharUtils.h" ++#include "nsQuickSort.h" ++#include "nsFontConfigUtils.h" ++ ++#include <fontconfig/fontconfig.h> ++#include <pango/pangoft2.h> ++#include <freetype/tttables.h> ++#include "nsType1.h" ++ ++#include "mozilla-ps-decoder.h" ++ ++#define FORCE_PR_LOG ++#include "prlog.h" ++ ++// Globals ++ ++static PRLogModuleInfo *gPangoFontLog; ++static int gNumInstances; ++ ++ ++static void ++default_substitute (FcPattern *pattern, ++ gpointer data) ++{ ++ FcPatternDel (pattern, FC_HINTING); ++ FcPatternAddBool (pattern, FC_HINTING, 0); ++} ++ ++static PangoFontMap * ++get_fontmap (void) ++{ ++ static PangoFontMap *fontmap = NULL; ++ ++ if (!fontmap) { ++ fontmap = pango_ft2_font_map_new (); ++ pango_ft2_font_map_set_resolution ((PangoFT2FontMap *)fontmap, 72., 72.); ++ pango_ft2_font_map_set_default_substitute ((PangoFT2FontMap *)fontmap, default_substitute, NULL, NULL); ++ } ++ ++ return fontmap; ++} ++ ++static PangoContext * ++get_context (void) ++{ ++ return pango_ft2_font_map_create_context ((PangoFT2FontMap *) get_fontmap ()); ++} ++ ++// 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); ++ ++#ifdef DEBUG ++#define DUMP_PRUNICHAR(ustr, ulen) for (PRUint32 llen=0;llen<ulen;llen++) \ ++ printf("0x%x ", ustr[llen]); \ ++ printf("\n"); ++#endif ++ ++// rounding and truncation functions for a Freetype floating point number ++// (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer ++// part and low 6 bits for the fractional part. ++#define MOZ_FT_ROUND(x) (((x) + 32) & ~63) // 63 = 2^6 - 1 ++#define MOZ_FT_TRUNC(x) ((x) >> 6) ++#define CONVERT_DESIGN_UNITS_TO_PIXELS(v, s) \ ++ MOZ_FT_TRUNC(MOZ_FT_ROUND(FT_MulFix((v) , (s)))) ++ ++// Static function decls ++ ++static PangoLanguage *GetPangoLanguage(nsIAtom *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); ++ ++nsFontMetricsPSPango::nsFontMetricsPSPango() ++{ ++ if (!gPangoFontLog) ++ gPangoFontLog = PR_NewLogModule("PangoFont"); ++ ++ gNumInstances++; ++ ++ mPangoFontDesc = nsnull; ++ mPangoContext = nsnull; ++ mLTRPangoContext = nsnull; ++ mRTLPangoContext = nsnull; ++ mPangoAttrList = nsnull; ++ mIsRTL = PR_FALSE; ++ mPangoSpaceWidth = 0; ++ ++ static PRBool initialized = PR_FALSE; ++ if (initialized) ++ return; ++ ++ // Initialized the custom decoders ++ if (!mozilla_ps_decoders_init(get_fontmap ())) ++ initialized = PR_TRUE; ++} ++ ++nsFontMetricsPSPango::~nsFontMetricsPSPango() ++{ ++ 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(nsFontMetricsPSPango, nsIFontMetrics) ++ ++// nsIFontMetrics impl ++ ++NS_IMETHODIMP ++nsFontMetricsPSPango::Init(const nsFont& aFont, nsIAtom* aLangGroup, ++ nsIDeviceContext *aContext) ++{ ++ mFont = aFont; ++ mLangGroup = aLangGroup; ++ ++ // Hang on to the device context ++ mDeviceContext = aContext; ++ ++ mPointSize = NSTwipsToFloatPoints(mFont.size); ++ ++ // enumerate over the font names passed in ++ mFont.EnumerateFamilies(nsFontMetricsPSPango::EnumFontCallback, this); ++ ++ nsCOMPtr<nsIPref> prefService; ++ prefService = do_GetService(NS_PREF_CONTRACTID); ++ if (!prefService) ++ return NS_ERROR_FAILURE; ++ ++ nsXPIDLCString value; ++ const char* langGroup; ++ mLangGroup->GetUTF8String(&langGroup); ++ ++ // Set up the default font name if it's not set ++ if (!mGenericFont) { ++ nsCAutoString name("font.default."); ++ name.Append(langGroup); ++ prefService->CopyCharPref(name.get(), 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('.')); ++ 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: nsFontMetricsPSPango 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 ++nsFontMetricsPSPango::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; ++ face = pango_fc_font_lock_face(fcfont); ++ if (!face) ++ return NS_ERROR_NOT_AVAILABLE; ++ ++ TT_OS2 *os2; ++ 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 ++ val = MOZ_FT_TRUNC(face->size->metrics.ascender); ++ mMaxAscent = NSToIntRound(val * f); ++ ++ // mMaxDescent ++ val = -MOZ_FT_TRUNC(face->size->metrics.descender); ++ mMaxDescent = NSToIntRound(val * 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 ++ val = MOZ_FT_TRUNC(face->size->metrics.max_advance); ++ mMaxAdvance = NSToIntRound(val * f); ++ ++ // mPangoSpaceWidth ++ PangoLayout *layout = pango_layout_new(mPangoContext); ++ pango_layout_set_text(layout, " ", 1); ++ int pswidth, psheight; ++ pango_layout_get_size(layout, &pswidth, &psheight); ++ mPangoSpaceWidth = pswidth; ++ g_object_unref(layout); ++ ++ // mSpaceWidth (width of a space) ++ nscoord tmpWidth; ++ GetWidth(" ", 1, tmpWidth); ++ 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); ++ mAveCharWidth = tmpWidth; ++ ++ // mXHeight (height of an 'x' character) ++ if (pango_fc_font_has_char(fcfont, 'x')) { ++ PangoRectangle rect; ++ PangoGlyph glyph = pango_fc_font_get_glyph (fcfont, 'x'); ++ pango_font_get_glyph_extents (PANGO_FONT (fcfont), glyph, &rect, NULL); ++ mXHeight = NSToIntRound(rect.height * f / PANGO_SCALE); ++ } ++ else { ++ // 56% of ascent, best guess for non-true type or asian fonts ++ mXHeight = nscoord(((float)mMaxAscent) * 0.56 * 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 * ++ MOZ_FT_TRUNC(face->size->metrics.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 * MOZ_FT_TRUNC(face->size->metrics.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; ++ ++ pango_fc_font_unlock_face(fcfont); ++ ++ /* ++ 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 ++nsFontMetricsPSPango::Destroy() ++{ ++ mDeviceContext = nsnull; ++ return NS_OK; ++} ++ ++NS_IMETHODIMP ++nsFontMetricsPSPango::GetLangGroup(nsIAtom** aLangGroup) ++{ ++ *aLangGroup = mLangGroup; ++ NS_IF_ADDREF(*aLangGroup); ++ ++ return NS_OK; ++} ++ ++NS_IMETHODIMP ++nsFontMetricsPSPango::GetFontHandle(nsFontHandle &aHandle) ++{ ++ return NS_ERROR_NOT_IMPLEMENTED; ++} ++ ++// nsIFontMetricsPango impl ++NS_IMETHODIMP ++nsFontMetricsPSPango::GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength) ++{ ++ return GetWidth (String, (PRUint32) aLength, aWidth); ++} ++ ++NS_IMETHODIMP ++nsFontMetricsPSPango::GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength) ++{ ++ return GetWidth (aString, (PRUint32)aLength, aWidth); ++} ++ ++nsresult ++nsFontMetricsPSPango::GetWidth(const char* aString, PRUint32 aLength, ++ nscoord& aWidth) ++{ ++ PangoLayout *layout = pango_layout_new(mPangoContext); ++ ++ pango_layout_set_text(layout, aString, aLength); ++ ++ if (mPangoSpaceWidth) ++ FixupSpaceWidths(layout, aString); ++ ++ int width, height; ++ ++ pango_layout_get_size(layout, &width, &height); ++ ++ g_object_unref(layout); ++ ++ float f; ++ f = mDeviceContext->DevUnitsToAppUnits(); ++ aWidth = NSToCoordRound(width * f / PANGO_SCALE); ++ ++ // printf("GetWidth (char *) %d\n", aWidth); ++ ++ return NS_OK; ++} ++ ++nsresult ++nsFontMetricsPSPango::GetWidth(const PRUnichar* aString, PRUint32 aLength, ++ nscoord& aWidth) ++{ ++ 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("nsFontMetricsPSPango::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)); ++ FixupSpaceWidths(layout, text); ++ pango_layout_get_size(layout, &width, &height); ++ ++ float f; ++ f = mDeviceContext->DevUnitsToAppUnits(); ++ aWidth = NSToCoordRound(width * f / PANGO_SCALE); ++ ++ // printf("GetWidth %d\n", aWidth); ++ ++ loser: ++ g_free(text); ++ g_object_unref(layout); ++ ++ return rv; ++} ++ ++ ++nsresult ++nsFontMetricsPSPango :: GetTextDimensions(const char* aString, PRUint32 aLength, ++ nsTextDimensions& aDimensions) ++{ ++ nsresult rv = NS_OK; ++ ++ PangoLayout *layout = pango_layout_new(mPangoContext); ++ ++ pango_layout_set_text(layout, aString, aLength); ++ FixupSpaceWidths(layout,aString); ++ ++ // 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 * P2T / PANGO_SCALE); ++ aDimensions.ascent = NSToCoordRound(PANGO_ASCENT(rect) * P2T / PANGO_SCALE); ++ aDimensions.descent = NSToCoordRound(PANGO_DESCENT(rect) * P2T / PANGO_SCALE); ++ ++ // printf("GetTextDimensions %d %d %d\n", aDimensions.width, ++ //aDimensions.ascent, aDimensions.descent); ++ ++ loser: ++ g_object_unref(layout); ++ ++ return rv; ++} ++ ++nsresult ++nsFontMetricsPSPango::GetTextDimensions(const PRUnichar* aString, ++ PRUint32 aLength, ++ nsTextDimensions& aDimensions, ++ PRInt32* aFontID) ++{ ++ 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("nsFontMetricsPSPango::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)); ++ FixupSpaceWidths(layout, 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 * P2T / PANGO_SCALE); ++ aDimensions.ascent = NSToCoordRound(PANGO_ASCENT(rect) * P2T / PANGO_SCALE); ++ aDimensions.descent = NSToCoordRound(PANGO_DESCENT(rect) * P2T / PANGO_SCALE); ++ ++ // printf("GetTextDimensions %d %d %d\n", aDimensions.width, ++ //aDimensions.ascent, aDimensions.descent); ++ ++ loser: ++ g_free(text); ++ g_object_unref(layout); ++ ++ return rv; ++} ++ ++nsresult ++nsFontMetricsPSPango::GetTextDimensions(const char* aString, ++ PRInt32 aLength, ++ PRInt32 aAvailWidth, ++ PRInt32* aBreaks, ++ PRInt32 aNumBreaks, ++ nsTextDimensions& aDimensions, ++ PRInt32& aNumCharsFit, ++ nsTextDimensions& aLastWordDimensions, ++ PRInt32* aFontID) ++{ ++ ++ return GetTextDimensionsInternal(aString, aLength, aAvailWidth, aBreaks, ++ aNumBreaks, aDimensions, aNumCharsFit, ++ aLastWordDimensions); ++ ++} ++ ++nsresult ++nsFontMetricsPSPango::GetTextDimensions(const PRUnichar* aString, ++ PRInt32 aLength, ++ PRInt32 aAvailWidth, ++ PRInt32* aBreaks, ++ PRInt32 aNumBreaks, ++ nsTextDimensions& aDimensions, ++ PRInt32& aNumCharsFit, ++ nsTextDimensions& aLastWordDimensions, ++ PRInt32* aFontID) ++{ ++ 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("nsFontMetricsPSPango::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); ++ ++ // 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; ++} ++ ++typedef struct _nsPSPangoRenderer nsPSPangoRenderer; ++typedef struct _nsPSPangoRendererClass nsPSPangoRendererClass; ++ ++struct _nsPSPangoRenderer ++{ ++ PangoRenderer parent_instance; ++ nsRenderingContextPS *psContext; ++ nsFontMetricsPSPango *psPangoFontMetrics; ++ float zoom; ++}; ++ ++struct _nsPSPangoRendererClass ++{ ++ PangoRendererClass parent_class; ++}; ++ ++#define _PS_TYPE_PANGO_RENDERER (_ps_pango_renderer_get_type()) ++#define _PS_PANGO_RENDERER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRenderer)) ++#define _PS_IS_PANGO_RENDERER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), _PS_TYPE_PANGO_RENDERER)) ++#define _PS_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRendererClass)) ++#define _PS_IS_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), _PS_TYPE_PANGO_RENDERER)) ++#define _PS_PANGO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRendererClass)) ++ ++G_DEFINE_TYPE (_nsPSPangoRenderer, _ps_pango_renderer, PANGO_TYPE_RENDERER) ++ ++static PangoRenderer * ++get_renderer (void) ++{ ++ static PangoRenderer *renderer = NULL; ++ ++ if (!renderer) ++ renderer = (PangoRenderer *) g_object_new (_PS_TYPE_PANGO_RENDERER, NULL); ++ ++ return renderer; ++} ++ ++static void ++_ps_pango_renderer_draw_glyphs (PangoRenderer *renderer, ++ PangoFont *font, ++ PangoGlyphString *glyphs, ++ int x, ++ int y); ++ ++static void ++_ps_pango_renderer_class_init (nsPSPangoRendererClass *klass) ++{ ++ PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass); ++ ++ renderer_class->draw_glyphs = _ps_pango_renderer_draw_glyphs; ++} ++ ++static void ++_ps_pango_renderer_init (nsPSPangoRenderer *renderer) ++{ ++} ++ ++class nsPangoType1Generator : public nsPSFontGenerator { ++public: ++ nsPangoType1Generator(); ++ ~nsPangoType1Generator(); ++ nsresult Init(PangoFont *aFont); ++ void GeneratePSFont(FILE* aFile); ++ ++protected: ++ PangoFont *mFont; ++}; ++ ++nsPangoType1Generator::nsPangoType1Generator() ++{ ++} ++ ++nsresult ++nsPangoType1Generator::Init(PangoFont *aFont) ++{ ++ NS_ENSURE_TRUE(aFont, NS_ERROR_FAILURE); ++ mFont = aFont; ++ g_object_ref (mFont); ++ return NS_OK; ++} ++ ++nsPangoType1Generator::~nsPangoType1Generator() ++{ ++ g_object_unref (mFont); ++ mFont = nsnull; ++} ++ ++void nsPangoType1Generator::GeneratePSFont(FILE* aFile) ++{ ++ FT_Face face = pango_fc_font_lock_face ((PangoFcFont *) mFont); ++ ++ if (face == nsnull) ++ return; ++ ++ int wmode = 0; ++ if (mGlyphSubset->Count()) ++ FT2SubsetToType1FontSet(face, mGlyphSubset, wmode, aFile); ++ ++ pango_fc_font_unlock_face ((PangoFcFont *) mFont); ++} ++ ++typedef struct ++{ ++ nsCString *FontNameBase; ++ nsCStringKey *key; ++ int font_size; ++} PSPangoFontData; ++ ++static void ++ps_pango_font_data_destroy (PSPangoFontData *data) ++{ ++ delete data->key; ++ delete data->FontNameBase; ++ g_free (data); ++} ++ ++static void ++flattenName(nsCString& aString) ++{ ++ nsCString::iterator start, end; ++ aString.BeginWriting(start); ++ aString.EndWriting(end); ++ while(start != end) { ++ if (*start == ' ') ++ *start= '_'; ++ else if (*start == '(') ++ *start = '_'; ++ else if (*start == ')') ++ *start = '_'; ++ ++start; ++ } ++} ++ ++static void ++_ps_pango_renderer_draw_glyphs (PangoRenderer *renderer, ++ PangoFont *font, ++ PangoGlyphString *glyphs, ++ int x, ++ int y) ++{ ++ if (!glyphs->num_glyphs) ++ return; ++ ++ static GQuark data_quark = 0; ++ if (!data_quark) ++ data_quark = g_quark_from_static_string ("ps-pango-font-data"); ++ ++ PSPangoFontData *data; ++ if (!(data = (PSPangoFontData *) g_object_get_qdata (G_OBJECT (font), data_quark))) ++ { ++ data = g_new (PSPangoFontData, 1); ++ ++ FT_Face face = pango_fc_font_lock_face ((PangoFcFont *) font); ++ if (face == nsnull) ++ return; ++ int wmode = 0; ++ data->FontNameBase = new nsCString (); ++ if (NS_FAILED(FT2ToType1FontName(face, wmode, *data->FontNameBase))) { ++ g_free (data); ++ pango_fc_font_unlock_face ((PangoFcFont *) font); ++ return; ++ } ++ pango_fc_font_unlock_face ((PangoFcFont *) font); ++ ++ PangoFontDescription *desc = pango_font_describe (font); ++ data->font_size = pango_font_description_get_size (desc); ++ pango_font_description_free (desc); ++ ++ data->key = new nsCStringKey (*data->FontNameBase); ++ ++ g_object_set_qdata_full (G_OBJECT (font), data_quark, data, (GDestroyNotify) ps_pango_font_data_destroy); ++ } ++ ++ nsPSPangoRenderer *ps_renderer = (nsPSPangoRenderer *)renderer; ++ nsRenderingContextPS *aContext = ps_renderer->psContext; ++ nsFontMetricsPSPango *metrics = ps_renderer->psPangoFontMetrics; ++ nsDeviceContextPS* dc = NS_REINTERPRET_CAST (nsDeviceContextPS*, metrics->GetDeviceContext()); ++ nsPostScriptObj* psObj = aContext->GetPostScriptObj(); ++ nsHashtable *psFGList = dc->GetPSFontGeneratorList(); ++ g_return_if_fail (psFGList); ++ nsPSFontGenerator* psFontGen = (nsPSFontGenerator*) psFGList->Get(data->key); ++ if (!psFontGen) { ++ nsresult rv; ++ psFontGen = new nsPangoType1Generator; ++ g_return_if_fail (psFontGen); ++ rv = ((nsPangoType1Generator*)psFontGen)->Init(font); ++ if (NS_FAILED(rv)) { ++ delete psFontGen; ++ return; ++ } ++ psFGList->Put(data->key, (void *) psFontGen); ++ } ++ nscoord font_size = NSToCoordRound (ps_renderer->zoom * data->font_size / PANGO_SCALE); ++ ++ g_return_if_fail (aContext); ++ g_return_if_fail (psObj); ++ ++ nscoord aX = NSToCoordRound(ps_renderer->zoom * x / PANGO_SCALE); ++ nscoord aY = NSToCoordRound(ps_renderer->zoom * y / PANGO_SCALE); ++ psObj->moveto(aX, aY); ++ ++ PRInt32 currSubFont, prevSubFont = -1; ++ PRUint32 i; ++ PangoGlyphString gl; ++ ++ gl.glyphs = glyphs->glyphs; ++ gl.num_glyphs = 0; ++ for (i = 0; i < glyphs->num_glyphs; ++i) { ++ currSubFont = psFontGen->AddToGlyphSubset(glyphs->glyphs[i].glyph >= 0x00ffffff ? 0 : glyphs->glyphs[i].glyph); ++ if (prevSubFont != currSubFont) { ++ if (prevSubFont != -1) ++ psObj->show(&gl, ps_renderer->zoom, psFontGen, prevSubFont); ++ ++ ++ psObj->setfont(*data->FontNameBase, (PRUint32) font_size, currSubFont); ++ prevSubFont = currSubFont; ++ gl.glyphs = glyphs->glyphs + i; ++ gl.num_glyphs = 0; ++ } ++ ++ gl.num_glyphs++; ++ } ++ ++ if (prevSubFont != -1) ++ psObj->show(&gl, ps_renderer->zoom, psFontGen, prevSubFont); ++} ++ ++static void ++draw_layout_line (int x, int y, PangoLayoutLine *line, nsFontMetricsPSPango *aPSPangoFontMetrics, nsRenderingContextPS *aContext) ++{ ++ PangoRenderer *renderer = get_renderer (); ++ nsPSPangoRenderer *ps_renderer = (nsPSPangoRenderer *)renderer; ++ ps_renderer->psContext = aContext; ++ ps_renderer->psPangoFontMetrics = aPSPangoFontMetrics; ++ nsDeviceContextPS* dc = NS_REINTERPRET_CAST (nsDeviceContextPS*, aPSPangoFontMetrics->GetDeviceContext()); ++ ps_renderer->zoom = dc->DevUnitsToAppUnits(); ++ ++ pango_renderer_draw_layout_line (renderer, line, ++ NSToCoordRound (x * PANGO_SCALE / ps_renderer->zoom), ++ NSToCoordRound (y * PANGO_SCALE / ps_renderer->zoom)); ++} ++ ++nsresult ++nsFontMetricsPSPango::DrawString(const char *aString, PRUint32 aLength, ++ nscoord aX, nscoord aY, ++ const nscoord* aSpacing, ++ nsRenderingContextPS *aContext) ++{ ++ PangoLayout *layout = pango_layout_new(mPangoContext); ++ ++ pango_layout_set_text(layout, aString, aLength); ++ FixupSpaceWidths(layout, aString); ++ ++ 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); ++ ++ if (aSpacing && *aSpacing) { ++ DrawStringSlowly(aString, NULL, aLength, x, y, line, aSpacing, aContext); ++ } ++ else { ++ draw_layout_line (x, y, line, this, aContext); ++ } ++ ++ g_object_unref(layout); ++ ++ return NS_OK; ++} ++ ++nsresult ++nsFontMetricsPSPango::DrawString(const PRUnichar* aString, PRUint32 aLength, ++ nscoord aX, nscoord aY, ++ PRInt32 aFontID, ++ const nscoord* aSpacing, ++ nsRenderingContextPS *aContext) ++{ ++ nsresult rv = NS_OK; ++ int x = aX; ++ int y = aY; ++ ++ PangoLayout *layout = pango_layout_new(mPangoContext); ++ ++ gchar *text = g_utf16_to_utf8(aString, aLength, ++ NULL, NULL, NULL); ++ if (!text) { ++#ifdef DEBUG ++ NS_WARNING("nsFontMetricsPSPango::DrawString invalid unicode to follow"); ++ DUMP_PRUNICHAR(aString, aLength) ++#endif ++ rv = NS_ERROR_FAILURE; ++ goto loser; ++ } ++ ++ pango_layout_set_text(layout, text, strlen(text)); ++ FixupSpaceWidths(layout, 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, x, y, line, aSpacing, aContext); ++ } ++ else { ++ draw_layout_line (x, y, line, this, aContext); ++ } ++ ++ loser: ++ ++ g_free(text); ++ g_object_unref(layout); ++ ++ return rv; ++} ++ ++#ifdef MOZ_MATHML ++nsresult ++nsFontMetricsPSPango::GetBoundingMetrics(const char *aString, PRUint32 aLength, ++ nsBoundingMetrics &aBoundingMetrics) ++{ ++ printf("GetBoundingMetrics (char *)\n"); ++ return NS_ERROR_FAILURE; ++} ++ ++nsresult ++nsFontMetricsPSPango::GetBoundingMetrics(const PRUnichar *aString, ++ PRUint32 aLength, ++ nsBoundingMetrics &aBoundingMetrics, ++ PRInt32 *aFontID) ++{ ++ 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("nsFontMetricsPSPango::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, -1); ++ FixupSpaceWidths(layout, text); ++ ++ 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 and logical extents ++ PangoRectangle ink, logical; ++ pango_layout_line_get_extents(line, &ink, &logical); ++ ++ float P2T; ++ P2T = mDeviceContext->DevUnitsToAppUnits(); ++ ++ aBoundingMetrics.leftBearing = NSToCoordRound(PANGO_LBEARING(ink) * P2T / PANGO_SCALE); ++ aBoundingMetrics.rightBearing = NSToCoordRound(PANGO_RBEARING(ink) * P2T / PANGO_SCALE); ++ aBoundingMetrics.ascent = NSToCoordRound(PANGO_ASCENT(ink) * P2T / PANGO_SCALE); ++ aBoundingMetrics.descent = NSToCoordRound(PANGO_DESCENT(ink) * P2T / PANGO_SCALE); ++ aBoundingMetrics.width = NSToCoordRound(logical.width * P2T / PANGO_SCALE); ++ ++ loser: ++ g_free(text); ++ g_object_unref(layout); ++ ++ return rv; ++} ++ ++#endif /* MOZ_MATHML */ ++ ++nsresult ++nsFontMetricsPSPango::SetRightToLeftText(PRBool aIsRTL) ++{ ++ if (aIsRTL) { ++ if (!mRTLPangoContext) { ++ mRTLPangoContext = get_context(); ++ pango_context_set_base_dir(mRTLPangoContext, PANGO_DIRECTION_RTL); ++ ++ pango_context_set_language(mRTLPangoContext, GetPangoLanguage(mLangGroup)); ++ pango_context_set_font_description(mRTLPangoContext, mPangoFontDesc); ++ } ++ mPangoContext = mRTLPangoContext; ++ } ++ else { ++ mPangoContext = mLTRPangoContext; ++ } ++ ++ mIsRTL = aIsRTL; ++ return NS_OK; ++} ++ ++nsresult ++nsFontMetricsPSPango::GetClusterInfo(const PRUnichar *aText, ++ PRUint32 aLength, ++ PRUint8 *aClusterStarts) ++{ ++ nsresult rv = NS_OK; ++ PangoLogAttr *attrs = NULL; ++ gint n_attrs = 0; ++ PangoLayout *layout = pango_layout_new(mPangoContext); ++ ++ // Convert the incoming UTF-16 to UTF-8 ++ gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL); ++ ++ if (!text) { ++#ifdef DEBUG ++ NS_WARNING("nsFontMetricsPSPango::GetWidth invalid unicode to follow"); ++ DUMP_PRUNICHAR(aText, aLength) ++#endif ++ rv = NS_ERROR_FAILURE; ++ goto loser; ++ } ++ ++ // Set up the pango layout ++ pango_layout_set_text(layout, text, strlen(text)); ++ FixupSpaceWidths(layout, text); ++ ++ // Convert back to UTF-16 while filling in the cluster info ++ // structure. ++ pango_layout_get_log_attrs(layout, &attrs, &n_attrs); ++ ++ for (PRUint32 pos = 0; pos < aLength; pos++) { ++ if (IS_HIGH_SURROGATE(aText[pos])) { ++ aClusterStarts[pos] = 1; ++ pos++; ++ } ++ else { ++ aClusterStarts[pos] = attrs[pos].is_cursor_position; ++ } ++ } ++ ++ loser: ++ if (attrs) ++ g_free(attrs); ++ if (text) ++ g_free(text); ++ if (layout) ++ g_object_unref(layout); ++ ++ return rv; ++} ++ ++PRInt32 ++nsFontMetricsPSPango::GetPosition(const PRUnichar *aText, PRUint32 aLength, ++ nsPoint aPt) ++{ ++ int trailing = 0; ++ int inx = 0; ++ const gchar *curChar; ++ PRInt32 retval = 0; ++ ++ float f = mDeviceContext->AppUnitsToDevUnits(); ++ ++ PangoLayout *layout = pango_layout_new(mPangoContext); ++ PRUint32 localX = (PRUint32)(aPt.x * PANGO_SCALE * f); ++ PRUint32 localY = (PRUint32)(aPt.y * PANGO_SCALE * f); ++ ++ // Convert the incoming UTF-16 to UTF-8 ++ gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL); ++ ++ if (!text) { ++#ifdef DEBUG ++ NS_WARNING("nsFontMetricsPSPango::GetWidth invalid unicode to follow"); ++ DUMP_PRUNICHAR(aText, aLength) ++#endif ++ retval = -1; ++ goto loser; ++ } ++ ++ // Set up the pango layout ++ pango_layout_set_text(layout, text, strlen(text)); ++ FixupSpaceWidths(layout, text); ++ ++ pango_layout_xy_to_index(layout, localX, localY, ++ &inx, &trailing); ++ ++ // Convert the index back to the utf-16 index ++ curChar = text; ++ ++ for (PRUint32 curOffset=0; curOffset < aLength; ++ curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) { ++ ++ // Check for a match before checking for a surrogate pair ++ if (curChar - text == inx) { ++ retval = curOffset; ++ break; ++ } ++ ++ if (IS_HIGH_SURROGATE(aText[curOffset])) ++ curOffset++; ++ } ++ ++ // If there was a trailing result, advance the index pointer the ++ // number of characters equal to the trailing result. ++ while (trailing) { ++ retval++; ++ // Yes, this can make aInx > length to indicate the end of the ++ // string. ++ if (retval < (PRInt32)aLength && IS_HIGH_SURROGATE(aText[retval])) ++ retval++; ++ trailing--; ++ } ++ ++ loser: ++ if (text) ++ g_free(text); ++ if (layout) ++ g_object_unref(layout); ++ ++ return retval; ++} ++ ++nsresult ++nsFontMetricsPSPango::GetRangeWidth(const PRUnichar *aText, ++ PRUint32 aLength, ++ PRUint32 aStart, ++ PRUint32 aEnd, ++ PRUint32 &aWidth) ++{ ++ nsresult rv = NS_OK; ++ PRUint32 utf8Start = 0; ++ PRUint32 utf8End = 0; ++ ++ aWidth = 0; ++ ++ // Convert the incoming UTF-16 to UTF-8 ++ gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL); ++ gchar *curChar = text; ++ ++ if (!text) { ++#ifdef DEBUG ++ NS_WARNING("nsFontMetricsPSPango::GetWidth invalid unicode to follow"); ++ DUMP_PRUNICHAR(aText, aLength) ++#endif ++ rv = NS_ERROR_FAILURE; ++ goto loser; ++ } ++ ++ // Convert the utf16 offsets into utf8 offsets ++ for (PRUint32 curOffset = 0; curOffset < aLength; ++ curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) { ++ ++ if (curOffset == aStart) ++ utf8Start = curChar - text; ++ ++ if (curOffset == aEnd) ++ utf8End = curChar - text; ++ ++ if (IS_HIGH_SURROGATE(aText[curOffset])) ++ curOffset++; ++ } ++ ++ // Special case where the end index is the same as the length ++ if (aLength == aEnd) ++ utf8End = strlen(text); ++ ++ rv = GetRangeWidth(text, strlen(text), utf8Start, utf8End, aWidth); ++ ++ loser: ++ if (text) ++ g_free(text); ++ ++ return rv; ++} ++ ++nsresult ++nsFontMetricsPSPango::GetRangeWidth(const char *aText, ++ PRUint32 aLength, ++ PRUint32 aStart, ++ PRUint32 aEnd, ++ PRUint32 &aWidth) ++{ ++ nsresult rv = NS_OK; ++ int *ranges = NULL; ++ int n_ranges = 0; ++ float f; ++ ++ aWidth = 0; ++ ++ PangoLayout *layout = pango_layout_new(mPangoContext); ++ ++ if (!aText) { ++ rv = NS_ERROR_FAILURE; ++ goto loser; ++ } ++ ++ pango_layout_set_text(layout, aText, aLength); ++ FixupSpaceWidths(layout, aText); ++ ++ PangoLayoutLine *line; ++ if (pango_layout_get_line_count(layout) != 1) { ++ printf("Warning: more than one line!\n"); ++ } ++ line = pango_layout_get_line(layout, 0); ++ ++ pango_layout_line_get_x_ranges(line, aStart, aEnd, &ranges, &n_ranges); ++ ++ aWidth = (ranges[((n_ranges - 1) * 2) + 1] - ranges[0]); ++ ++ f = mDeviceContext-> DevUnitsToAppUnits(); ++ aWidth = nscoord(aWidth * f / PANGO_SCALE); ++ ++ loser: ++ if (ranges) ++ g_free(ranges); ++ if (layout) ++ g_object_unref(layout); ++ ++ return rv; ++} ++ ++PRUint32 ++nsFontMetricsPSPango::GetHints(void) ++{ ++ return (NS_RENDERING_HINT_BIDI_REORDERING | ++ NS_RENDERING_HINT_ARABIC_SHAPING | ++ NS_RENDERING_HINT_FAST_MEASURE | ++ NS_RENDERING_HINT_REORDER_SPACED_TEXT | ++ NS_RENDERING_HINT_TEXT_CLUSTERS); ++} ++ ++/* static */ ++nsresult ++nsFontMetricsPSPango::FamilyExists(nsIDeviceContext *aDevice, ++ const nsString &aName) ++{ ++ // fontconfig family name is always in UTF-8 ++ NS_ConvertUTF16toUTF8 name(aName); ++ ++ nsresult rv = NS_ERROR_FAILURE; ++ PangoContext *context = get_context(); ++ 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 ++nsFontMetricsPSPango::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<nsIPref> 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 (NS_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 = get_context(); ++ mPangoContext = mLTRPangoContext; ++ ++ // Make sure to set the base direction to LTR - if layout needs to ++ // render RTL text it will use ::SetRightToLeftText() ++ pango_context_set_base_dir(mPangoContext, PANGO_DIRECTION_LTR); ++ ++ // 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 ++nsFontMetricsPSPango::EnumFontCallback(const nsString &aFamily, ++ PRBool aIsGeneric, void *aData) ++{ ++ NS_ConvertUTF16toUTF8 name(aFamily); ++ ++ // The newest fontconfig does the full Unicode case folding so that ++ // we're being lazy here by calling |ToLowerCase| after converting ++ // to UTF-8 assuming that in virtually all cases, we just have to ++ // fold [A-Z]. (bug 223653). ++ ToLowerCase(name); ++ nsFontMetricsPSPango *metrics = (nsFontMetricsPSPango *)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 ++nsFontMetricsPSPango::DrawStringSlowly(const gchar *aText, ++ const PRUnichar *aOrigString, ++ PRUint32 aLength, ++ gint aX, gint aY, ++ PangoLayoutLine *aLine, ++ const nscoord *aSpacing, ++ nsRenderingContextPS *aContext) ++{ ++ 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); */ ++ offset += tmpOffset; ++ } ++ ++ draw_layout_line (aX, aY, aLine, this, aContext); ++ ++ delete[] utf8spacing; ++} ++ ++nsresult ++nsFontMetricsPSPango::GetTextDimensionsInternal(const gchar* aString, ++ PRInt32 aLength, ++ PRInt32 aAvailWidth, ++ PRInt32* aBreaks, ++ PRInt32 aNumBreaks, ++ nsTextDimensions& aDimensions, ++ PRInt32& aNumCharsFit, ++ nsTextDimensions& aLastWordDimensions) ++{ ++ 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); ++ ++ // 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); ++ 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; ++} ++ ++void ++nsFontMetricsPSPango::FixupSpaceWidths (PangoLayout *aLayout, ++ const char *aString) ++{ ++ PangoLayoutLine *line = pango_layout_get_line(aLayout, 0); ++ ++ gint curRun = 0; ++ ++ for (GSList *tmpList = line->runs; tmpList && tmpList->data; ++ tmpList = tmpList->next, curRun++) { ++ PangoLayoutRun *layoutRun = (PangoLayoutRun *)tmpList->data; ++ ++ for (gint i=0; i < layoutRun->glyphs->num_glyphs; i++) { ++ gint thisOffset = (gint)layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset; ++ if (aString[thisOffset] == ' ') ++ layoutRun->glyphs->glyphs[i].geometry.width = mPangoSpaceWidth; ++ } ++ } ++} ++ ++/* 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 MozGtkLangGroup *langGroup; ++ langGroup = NS_FindFCLangGroup(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->Lang) ++ return pango_language_from_string((char *) langGroup->Lang); ++ ++ return pango_language_from_string("en"); ++} ++ ++/* 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, NULL); ++ if (!os) ++ goto end; ++ ++ // take the pattern and add the lang group to it ++ if (aLangGroup) ++ NS_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; ++ ++ // if there's no family, just move to the next iteration ++ if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0, ++ (FcChar8 **) &family) != FcResultMatch) { ++ continue; ++ } ++ ++ // fontconfig always returns family names in UTF-8 ++ PRUnichar* name = UTF8ToNewUnicode(nsDependentCString(family)); ++ ++ if (!name) ++ goto end; ++ ++ 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<nsIAtom> 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; ++} +Index: gfx/src/ps/nsFontMetricsPSPango.h +=================================================================== +RCS file: gfx/src/ps/nsFontMetricsPSPango.h +diff -N gfx/src/ps/nsFontMetricsPSPango.h +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ gfx/src/ps/nsFontMetricsPSPango.h 23 Oct 2006 17:37:13 -0000 +@@ -0,0 +1,305 @@ ++/* -*- 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 <blizzard@mozilla.org>. ++ * 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 ***** */ ++ ++#ifndef nsFontMetricsPSPango_h__ ++#define nsFontMetricsPSPango_h__ ++ ++#include "nsIFontMetrics.h" ++#include "nsIFontEnumerator.h" ++#include "nsCRT.h" ++#include "nsIAtom.h" ++#include "nsString.h" ++#include "nsVoidArray.h" ++#include "nsFontMetricsPS.h" ++ ++#include <pango/pango.h> ++ ++class nsRenderingContextPS; ++class nsIDrawingSurface; ++ ++class nsFontMetricsPSPango : public nsFontMetricsPS ++{ ++public: ++ nsFontMetricsPSPango(); ++ virtual ~nsFontMetricsPSPango(); ++ ++ 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 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; }; ++ ++ // nsIFontMetricsPS (calls from the font rendering layer) ++ NS_IMETHOD GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength); ++ NS_IMETHOD GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength); ++ ++ NS_IMETHOD GetWidth(const char* aString, PRUint32 aLength, ++ nscoord& aWidth); ++ NS_IMETHOD GetWidth(const PRUnichar* aString, PRUint32 aLength, ++ nscoord& aWidth); ++ ++ NS_IMETHOD GetTextDimensions(const char* aString, ++ PRUint32 aLength, ++ nsTextDimensions& aDimensions); ++ NS_IMETHOD GetTextDimensions(const PRUnichar* aString, ++ PRUint32 aLength, ++ nsTextDimensions& aDimensions, ++ PRInt32* aFontID); ++ NS_IMETHOD GetTextDimensions(const char* aString, ++ PRInt32 aLength, ++ PRInt32 aAvailWidth, ++ PRInt32* aBreaks, ++ PRInt32 aNumBreaks, ++ nsTextDimensions& aDimensions, ++ PRInt32& aNumCharsFit, ++ nsTextDimensions& aLastWordDimensions, ++ PRInt32* aFontID); ++ NS_IMETHOD GetTextDimensions(const PRUnichar* aString, ++ PRInt32 aLength, ++ PRInt32 aAvailWidth, ++ PRInt32* aBreaks, ++ PRInt32 aNumBreaks, ++ nsTextDimensions& aDimensions, ++ PRInt32& aNumCharsFit, ++ nsTextDimensions& aLastWordDimensions, ++ PRInt32* aFontID); ++ ++ NS_IMETHOD DrawString(const char *aString, PRUint32 aLength, ++ nscoord aX, nscoord aY, ++ const nscoord* aSpacing, ++ nsRenderingContextPS *aContext); ++ NS_IMETHOD DrawString(const PRUnichar* aString, PRUint32 aLength, ++ nscoord aX, nscoord aY, ++ PRInt32 aFontID, ++ const nscoord* aSpacing, ++ nsRenderingContextPS *aContext); ++ ++#ifdef MOZ_MATHML ++ NS_IMETHOD GetBoundingMetrics(const char *aString, PRUint32 aLength, ++ nsBoundingMetrics &aBoundingMetrics); ++ NS_IMETHOD GetBoundingMetrics(const PRUnichar *aString, ++ PRUint32 aLength, ++ nsBoundingMetrics &aBoundingMetrics, ++ PRInt32 *aFontID); ++#endif /* MOZ_MATHML */ ++ ++ NS_IMETHOD SetRightToLeftText(PRBool aIsRTL); ++ ++ NS_IMETHOD GetClusterInfo(const PRUnichar *aText, ++ PRUint32 aLength, ++ PRUint8 *aClusterStarts); ++ ++ virtual PRInt32 GetPosition(const PRUnichar *aText, ++ PRUint32 aLength, ++ nsPoint aPt); ++ ++ NS_IMETHOD GetRangeWidth(const PRUnichar *aText, ++ PRUint32 aLength, ++ PRUint32 aStart, ++ PRUint32 aEnd, ++ PRUint32 &aWidth); ++ ++ NS_IMETHOD GetRangeWidth(const char *aText, ++ PRUint32 aLength, ++ PRUint32 aStart, ++ PRUint32 aEnd, ++ PRUint32 &aWidth); ++ ++ // get hints for the font ++ virtual PRUint32 GetHints (void); ++ ++ // drawing surface methods ++ static nsresult FamilyExists (nsIDeviceContext *aDevice, ++ const nsString &aName); ++ ++ inline nsIDeviceContext *GetDeviceContext() { return mDeviceContext; } ++ ++private: ++ ++ // generic font metrics class bits ++ nsCStringArray mFontList; ++ nsAutoVoidArray mFontIsGeneric; ++ ++ nsIDeviceContext *mDeviceContext; ++ nsCOMPtr<nsIAtom> mLangGroup; ++ nsCString *mGenericFont; ++ 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 mPangoSpaceWidth; ++ 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, ++ gint aX, gint aY, ++ PangoLayoutLine *aLine, ++ const nscoord *aSpacing, ++ nsRenderingContextPS *aContext); ++ ++ nsresult GetTextDimensionsInternal(const gchar* aString, ++ PRInt32 aLength, ++ PRInt32 aAvailWidth, ++ PRInt32* aBreaks, ++ PRInt32 aNumBreaks, ++ nsTextDimensions& aDimensions, ++ PRInt32& aNumCharsFit, ++ nsTextDimensions& aLastWordDimensions); ++ ++ void FixupSpaceWidths (PangoLayout *aLayout, const char *aString); ++}; ++ ++class nsFontEnumeratorPango : public nsIFontEnumerator ++{ ++public: ++ nsFontEnumeratorPango(); ++ NS_DECL_ISUPPORTS ++ NS_DECL_NSIFONTENUMERATOR ++}; ++ ++#endif ++ +Index: gfx/src/ps/nsPostScriptObj.cpp +=================================================================== +RCS file: /cvsroot/mozilla/gfx/src/ps/nsPostScriptObj.cpp,v +retrieving revision 1.124 +diff -u -p -d -r1.124 nsPostScriptObj.cpp +--- gfx/src/ps/nsPostScriptObj.cpp 26 Jul 2005 15:54:18 -0000 1.124 ++++ gfx/src/ps/nsPostScriptObj.cpp 23 Oct 2006 17:37:29 -0000 +@@ -2061,31 +2061,74 @@ nsPostScriptObj::show(const PRUnichar* t + + #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) + void +-nsPostScriptObj::show(const PRUnichar* aTxt, int aLen, +- const nsAFlatString& aCharList, PRUint16 aSubFontIdx) ++/*nsPostScriptObj::show(const PRUnichar* aTxt, int aLen, ++ const nsAFlatString& aCharList, PRUint16 aSubFontIdx) */ ++nsPostScriptObj::show(const nsValueArray *aGlyphs, nsPSFontGenerator *aSubset, ++ PRUint16 aSubFontIdx) + { +- int i; ++ PRUint32 i; + fputc('<', mScriptFP); + +- const PRUint16 subFontSize = nsPSFontGenerator::kSubFontSize; ++ for (i = 0; i < aGlyphs->Count(); i++) { ++ PRUint32 glyph = aGlyphs->ValueAt(i); ++ fprintf(mScriptFP, "%02x", aSubset->InSubsetIndexOf(glyph)); ++ } + +- // the character repertoire of a subfont (255 characters max) +- const nsAString& repertoire = +- Substring(aCharList, aSubFontIdx * subFontSize, +- PR_MIN(subFontSize, +- aCharList.Length() - aSubFontIdx * subFontSize)); ++ fputs("> show\n", mScriptFP); ++} ++#endif + +- for (i = 0; i < aLen; i++) { +- // XXX This is a little inefficient, but printing is not perf. critical. +- NS_ASSERTION(repertoire.FindChar(aTxt[i]) != kNotFound, +- "character is not covered by this subfont"); +- +- // Type 1 encoding vector has 256 slots, but the 0-th slot is +- // reserved for /.notdef so that we use the 1st through 255th slots +- // for actual characters (hence '+ 1') +- fprintf(mScriptFP, "%02x", repertoire.FindChar(aTxt[i]) + 1); ++#ifdef MOZ_ENABLE_PANGO ++void ++nsPostScriptObj::show(const PangoGlyphString *glyphs, float zoom, ++ nsPSFontGenerator *aSubset, PRUint16 aSubFontIdx) ++{ ++ PRUint32 i; ++ int horiz = 1; ++ ++ if (glyphs->glyphs[0].geometry.x_offset || glyphs->glyphs[0].geometry.y_offset) ++ rmoveto (NSToCoordRound (zoom * glyphs->glyphs[0].geometry.x_offset / PANGO_SCALE), ++ NSToCoordRound (zoom * glyphs->glyphs[0].geometry.y_offset / PANGO_SCALE)); ++ ++ fputc('<', mScriptFP); ++ ++ for (i = 0; i < glyphs->num_glyphs; i++) { ++ PRUint32 glyph = glyphs->glyphs[i].glyph; ++ fprintf(mScriptFP, "%02x", aSubset->InSubsetIndexOf(glyph)); ++ if (glyphs->glyphs[i].geometry.y_offset) ++ horiz = 0; ++ } ++ ++ if (horiz) { ++ fputs(">\n[", mScriptFP); ++ for (i = 1; i < glyphs->num_glyphs; i++) { ++ fprintf(mScriptFP, "%d ", ++ NSToCoordRound (zoom * (+ glyphs->glyphs[i ].geometry.x_offset ++ + glyphs->glyphs[i-1].geometry.width ++ - glyphs->glyphs[i-1].geometry.x_offset) / PANGO_SCALE)); ++ } ++ fprintf(mScriptFP, "%d", ++ NSToCoordRound (zoom * (+ glyphs->glyphs[i-1].geometry.width ++ - glyphs->glyphs[i-1].geometry.x_offset ++ - glyphs->glyphs[ 0].geometry.x_offset) / PANGO_SCALE)); ++ fputs("] xshow\n", mScriptFP); ++ } else { ++ fputs(">\n[", mScriptFP); ++ for (i = 1; i < glyphs->num_glyphs; i++) { ++ fprintf(mScriptFP, "%d %d ", ++ NSToCoordRound (zoom * (+ glyphs->glyphs[i ].geometry.x_offset ++ + glyphs->glyphs[i-1].geometry.width ++ - glyphs->glyphs[i-1].geometry.x_offset) / PANGO_SCALE), ++ NSToCoordRound (zoom * (+ glyphs->glyphs[i ].geometry.y_offset ++ - glyphs->glyphs[i-1].geometry.y_offset) / PANGO_SCALE)); ++ } ++ fprintf(mScriptFP, "%d %d", ++ NSToCoordRound (zoom * (+ glyphs->glyphs[i-1].geometry.width ++ - glyphs->glyphs[i-1].geometry.x_offset ++ - glyphs->glyphs[ 0].geometry.x_offset) / PANGO_SCALE), ++ NSToCoordRound (zoom * (- glyphs->glyphs[i-1].geometry.y_offset) / PANGO_SCALE)); ++ fputs("] xyshow\n", mScriptFP); + } +- fputs("> show\n", mScriptFP); + } + #endif + +@@ -2101,6 +2144,16 @@ nsPostScriptObj::moveto(nscoord x, nscoo + + /** --------------------------------------------------- + * See documentation in nsPostScriptObj.h ++ * @update 10/20/06 behdad ++ */ ++void ++nsPostScriptObj::rmoveto(nscoord x, nscoord y) ++{ ++ fprintf(mScriptFP, "%d %d rmoveto\n", x, y); ++} ++ ++/** --------------------------------------------------- ++ * See documentation in nsPostScriptObj.h + * @update 2/1/99 dwc + */ + void +Index: gfx/src/ps/nsPostScriptObj.h +=================================================================== +RCS file: /cvsroot/mozilla/gfx/src/ps/nsPostScriptObj.h,v +retrieving revision 1.47 +diff -u -p -d -r1.47 nsPostScriptObj.h +--- gfx/src/ps/nsPostScriptObj.h 8 May 2005 15:01:20 -0000 1.47 ++++ gfx/src/ps/nsPostScriptObj.h 23 Oct 2006 17:37:30 -0000 +@@ -57,9 +57,15 @@ + #include "nsIPersistentProperties2.h" + #include "nsTempfilePS.h" + #include "nsEPSObjectPS.h" ++#ifdef MOZ_ENABLE_PANGO ++#include <pango/pango.h> ++#endif ++ + ++class nsPSFontGenerator; + class nsIImage; + class nsIAtom; ++class nsValueArray; + #endif + + #include <stdio.h> +@@ -217,6 +223,14 @@ public: + */ + void moveto(nscoord aX, nscoord aY); + /** --------------------------------------------------- ++ * Move relative to the current point ++ * @update 10/20/2006 behdad ++ * @param aX X coordinate ++ * aY Y coordinate ++ * @return VOID ++ */ ++ void rmoveto(nscoord aX, nscoord aY); ++ /** --------------------------------------------------- + * Add a line to the current path, from the current point + * to the specified point. + * @update 9/30/2003 +@@ -346,12 +360,24 @@ public: + */ + void show(const PRUnichar* aText, int aLen, const char *aAlign, int aType); + /** --------------------------------------------------- +- * This version takes a PRUnichar string, a font subset string +- * for freetype printing and a subfont index ++ * This version of show takes an array of glyphs, subfont and subfont index ++ * to render and is used for freetype and xft printing. + * @update 2/15/2005 jshin@mailaps.org ++ * @update 6/7/2005 blizzard@mozilla.org + */ +- void show(const PRUnichar* aText, int aLen, const nsAFlatString& aCharList, ++ void show(const nsValueArray *aGlyphs, nsPSFontGenerator *aSubset, + PRUint16 aSubFontIdx); ++ /*void show(const PRUnichar* aText, int aLen, const nsAFlatString& aCharList, ++ PRUint16 aSubFontIdx); */ ++#ifdef MOZ_ENABLE_PANGO ++ /** --------------------------------------------------- ++ * This version of show takes a pango glyph string, subfont and subfont index ++ * to render and is used for pango printing. ++ * @update 10/20/2006 behdad@behdad.org ++ */ ++ void show(const PangoGlyphString *glyphs, float zoom, ++ nsPSFontGenerator *aSubset, PRUint16 aSubFontIdx); ++#endif + /** --------------------------------------------------- + * set the clipping path to the current path using the winding rule + * @update 2/1/99 dwc +Index: gfx/src/ps/nsRenderingContextPS.cpp +=================================================================== +RCS file: /cvsroot/mozilla/gfx/src/ps/nsRenderingContextPS.cpp,v +retrieving revision 1.83 +diff -u -p -d -r1.83 nsRenderingContextPS.cpp +--- gfx/src/ps/nsRenderingContextPS.cpp 4 Mar 2005 07:39:27 -0000 1.83 ++++ gfx/src/ps/nsRenderingContextPS.cpp 23 Oct 2006 17:37:31 -0000 +@@ -251,6 +251,8 @@ nsRenderingContextPS :: GetDrawingSurfac + NS_IMETHODIMP + nsRenderingContextPS :: GetHints(PRUint32& aResult) + { ++ nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get()); ++ aResult = metrics->GetHints (); + return NS_OK; + } + +@@ -1006,8 +1008,11 @@ nsRenderingContextPS::GetTextDimensions( + nsTextDimensions& aLastWordDimensions, + PRInt32* aFontID) + { +- NS_NOTYETIMPLEMENTED("nsRenderingContextPS::GetTextDimensions"); +- return NS_ERROR_NOT_IMPLEMENTED; ++ NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER); ++ nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get()); ++ NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE); ++ return metrics->GetTextDimensions (aString, aLength, aAvailWidth, aBreaks, aNumBreaks, ++ aDimensions, aNumCharsFit, aLastWordDimensions, aFontID); + } + + NS_IMETHODIMP +@@ -1021,43 +1026,31 @@ nsRenderingContextPS::GetTextDimensions( + nsTextDimensions& aLastWordDimensions, + PRInt32* aFontID) + { +- NS_NOTYETIMPLEMENTED("nsRenderingContextPS::GetTextDimensions"); +- return NS_ERROR_NOT_IMPLEMENTED; ++ NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER); ++ nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get()); ++ NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE); ++ return metrics->GetTextDimensions (aString, aLength, aAvailWidth, aBreaks, aNumBreaks, ++ aDimensions, aNumCharsFit, aLastWordDimensions, aFontID); + } + + NS_IMETHODIMP + nsRenderingContextPS :: GetTextDimensions(const char* aString, PRUint32 aLength, + nsTextDimensions& aDimensions) + { +- nsresult rv = NS_ERROR_FAILURE; +- +- if (mFontMetrics) { +- nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get()); +- metrics->GetStringWidth(aString, aDimensions.width, aLength); +- metrics->GetMaxAscent(aDimensions.ascent); +- metrics->GetMaxDescent(aDimensions.descent); +- rv = NS_OK; +- } +- +- return rv; ++ NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER); ++ nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get()); ++ NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE); ++ return metrics->GetTextDimensions (aString, aLength, aDimensions); + } + + NS_IMETHODIMP + nsRenderingContextPS :: GetTextDimensions(const PRUnichar* aString, PRUint32 aLength, + nsTextDimensions& aDimensions, PRInt32* aFontID) + { +- nsresult rv = NS_ERROR_FAILURE; +- +- if (mFontMetrics) { +- nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get()); +- metrics->GetStringWidth(aString, aDimensions.width, aLength); +- //XXX temporary - bug 96609 +- metrics->GetMaxAscent(aDimensions.ascent); +- metrics->GetMaxDescent(aDimensions.descent); +- rv = NS_OK; +- } +- +- return rv; ++ NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER); ++ nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get()); ++ NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE); ++ return metrics->GetTextDimensions (aString, aLength, aDimensions, aFontID); + } + + /** --------------------------------------------------- +@@ -1073,47 +1066,7 @@ nsRenderingContextPS :: DrawString(const + + nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get()); + NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE); +- +- // When FT2 printing is enabled, we don't need to set langgroup +-#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) +- if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, mContext.get())->mFTPEnable) { +-#endif +- nsCOMPtr<nsIAtom> langGroup; +- mFontMetrics->GetLangGroup(getter_AddRefs(langGroup)); +- mPSObj->setlanggroup(langGroup); +-#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) +- } +-#endif +- +- if (aLength == 0) +- return NS_OK; +- nsFontPS* fontPS = nsFontPS::FindFont(aString[0], metrics->Font(), metrics); +- NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE); +- fontPS->SetupFont(this); +- +- PRUint32 i, start = 0; +- for (i=0; i<aLength; i++) { +- nsFontPS* fontThisChar; +- fontThisChar = nsFontPS::FindFont(aString[i], metrics->Font(), metrics); +- NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE); +- if (fontThisChar != fontPS) { +- // draw text up to this point +- aX += DrawString(aString+start, i-start, aX, aY, fontPS, +- aSpacing?aSpacing+start:nsnull); +- start = i; +- +- // setup for following text +- fontPS = fontThisChar; +- fontPS->SetupFont(this); +- } +- } +- +- // draw the last part +- if (aLength-start) +- DrawString(aString+start, aLength-start, aX, aY, fontPS, +- aSpacing?aSpacing+start:nsnull); +- +- return NS_OK; ++ return metrics->DrawString (aString, aLength, aX, aY, aSpacing, this); + } + + /** --------------------------------------------------- +@@ -1129,110 +1082,7 @@ nsRenderingContextPS :: DrawString(const + + nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get()); + NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE); +- +-#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) +- // When FT2 printing is enabled, we don't need to set langgroup +- if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, mContext.get())->mFTPEnable) { +-#endif +- nsCOMPtr<nsIAtom> langGroup = nsnull; +- mFontMetrics->GetLangGroup(getter_AddRefs(langGroup)); +- mPSObj->setlanggroup(langGroup); +-#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) +- } +-#endif +- +- /* build up conversion table */ +- mPSObj->preshow(aString, aLength); +- +- if (aLength == 0) +- return NS_OK; +- nsFontPS* fontPS = nsFontPS::FindFont(aString[0], metrics->Font(), metrics); +- NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE); +- fontPS->SetupFont(this); +- +- PRUint32 i, start = 0; +- for (i=0; i<aLength; i++) { +- nsFontPS* fontThisChar; +- fontThisChar = nsFontPS::FindFont(aString[i], metrics->Font(), metrics); +- NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE); +- if (fontThisChar != fontPS) { +- // draw text up to this point +- aX += DrawString(aString+start, i-start, aX, aY, fontPS, +- aSpacing?aSpacing+start:nsnull); +- start = i; +- +- // setup for following text +- fontPS = fontThisChar; +- fontPS->SetupFont(this); +- } +- } +- +- // draw the last part +- if (aLength-start) +- DrawString(aString+start, aLength-start, aX, aY, fontPS, +- aSpacing?aSpacing+start:nsnull); +- +- return NS_OK; +-} +- +-PRInt32 +-nsRenderingContextPS::DrawString(const char *aString, PRUint32 aLength, +- nscoord &aX, nscoord &aY, nsFontPS* aFontPS, +- const nscoord* aSpacing) +-{ +- nscoord width = 0; +- PRInt32 x = aX; +- PRInt32 y = aY; +- +- PRInt32 dxMem[500]; +- PRInt32* dx0 = 0; +- if (aSpacing) { +- dx0 = dxMem; +- if (aLength > 500) { +- dx0 = new PRInt32[aLength]; +- NS_ENSURE_TRUE(dx0, NS_ERROR_OUT_OF_MEMORY); +- } +- mTranMatrix->ScaleXCoords(aSpacing, aLength, dx0); +- } +- +- mTranMatrix->TransformCoord(&x, &y); +- width = aFontPS->DrawString(this, x, y, aString, aLength); +- +- if ((aSpacing) && (dx0 != dxMem)) { +- delete [] dx0; +- } +- +- return width; +-} +- +- +-PRInt32 +-nsRenderingContextPS::DrawString(const PRUnichar *aString, PRUint32 aLength, +- nscoord aX, nscoord aY, nsFontPS* aFontPS, +- const nscoord* aSpacing) +-{ +- nscoord width = 0; +- PRInt32 x = aX; +- PRInt32 y = aY; +- +- if (aSpacing) { +- // Slow, but accurate rendering +- const PRUnichar* end = aString + aLength; +- while (aString < end){ +- x = aX; +- y = aY; +- mTranMatrix->TransformCoord(&x, &y); +- aFontPS->DrawString(this, x, y, aString, 1); +- aX += *aSpacing++; +- aString++; +- } +- width = aX; +- } else { +- mTranMatrix->TransformCoord(&x, &y); +- width = aFontPS->DrawString(this, x, y, aString, aLength); +- } +- +- return width; ++ return metrics->DrawString (aString, aLength, aX, aY, aFontID, aSpacing, this); + } + + /** --------------------------------------------------- +@@ -1346,8 +1196,10 @@ nsRenderingContextPS::GetBoundingMetrics + PRUint32 aLength, + nsBoundingMetrics& aBoundingMetrics) + { +- // Fill me up +- return NS_ERROR_NOT_IMPLEMENTED; ++ NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER); ++ nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get()); ++ NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE); ++ return metrics->GetBoundingMetrics (aString, aLength, aBoundingMetrics); + } + + /** +@@ -1359,8 +1211,10 @@ nsRenderingContextPS::GetBoundingMetrics + nsBoundingMetrics& aBoundingMetrics, + PRInt32* aFontID) + { +- // Fill me up +- return NS_ERROR_NOT_IMPLEMENTED; ++ NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER); ++ nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get()); ++ NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE); ++ return metrics->GetBoundingMetrics (aString, aLength, aBoundingMetrics, aFontID); + } + #endif /* MOZ_MATHML */ + +Index: gfx/src/ps/nsRenderingContextPS.h +=================================================================== +RCS file: /cvsroot/mozilla/gfx/src/ps/nsRenderingContextPS.h,v +retrieving revision 1.49 +diff -u -p -d -r1.49 nsRenderingContextPS.h +--- gfx/src/ps/nsRenderingContextPS.h 20 Sep 2004 06:46:16 -0000 1.49 ++++ gfx/src/ps/nsRenderingContextPS.h 23 Oct 2006 17:37:35 -0000 +@@ -154,6 +154,10 @@ public: + NS_IMETHOD GetWidth(const PRUnichar* aString, PRUint32 aLength, + nscoord& aWidth, PRInt32 *aFontID); + ++ nsTransform2D *GetTranMatrix() { ++ return mTranMatrix; ++ } ++ + NS_IMETHOD DrawString(const char *aString, PRUint32 aLength, + nscoord aX, nscoord aY, + const nscoord* aSpacing); +@@ -164,13 +168,6 @@ public: + NS_IMETHOD DrawString(const nsString& aString, nscoord aX, nscoord aY, + PRInt32 aFontID, + const nscoord* aSpacing); +-protected: +- PRInt32 DrawString(const PRUnichar *aString, PRUint32 aLength, +- nscoord aX, nscoord aY, nsFontPS* aFontPS, +- const nscoord* aSpacing); +- PRInt32 DrawString(const char *aString, PRUint32 aLength, +- nscoord &aX, nscoord &aY, nsFontPS* aFontPS, +- const nscoord* aSpacing); + public: + + NS_IMETHOD GetTextDimensions(const char* aString, PRUint32 aLength, +Index: gfx/src/ps/nsType1.cpp +=================================================================== +RCS file: /cvsroot/mozilla/gfx/src/ps/nsType1.cpp,v +retrieving revision 1.5.8.1 +diff -u -p -d -r1.5.8.1 nsType1.cpp +--- gfx/src/ps/nsType1.cpp 19 Oct 2005 08:16:22 -0000 1.5.8.1 ++++ gfx/src/ps/nsType1.cpp 23 Oct 2006 17:37:39 -0000 +@@ -73,8 +73,13 @@ + #include "nsIFreeType2.h" + #include "nsServiceManagerUtils.h" + #endif ++#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) ++#include FT_TYPE1_TABLES_H ++#endif + #include "nsPrintfCString.h" + #include "nsAutoBuffer.h" ++#include "nsValueArray.h" ++#include "nsVoidArray.h" + + #define HEXASCII_LINE_LEN 64 + +@@ -113,7 +118,7 @@ static void encryptAndHexOut(FILE *aFile + const char *aBuf, PRInt32 aLen = -1); + static void charStringOut(FILE* aFile, PRUint32* aPos, PRUint16* aKey, + const char *aStr, PRUint32 aLen, +- PRUnichar aId); ++ const char *aGlyphName); + static void flattenName(nsCString& aString); + + /* thunk a short name for this function */ +@@ -202,19 +207,30 @@ Type1EncryptString(unsigned char *aInBuf + aOutBuf[i] = Type1Encrypt(aInBuf[i], &key); + } + ++static FT_UShort ++get_upm (FT_Face face) ++{ ++ FT_UShort upm = face->units_per_EM; ++ ++ if (!upm) ++ upm = 1000; // bitmap font or something ++ ++ return upm; ++} ++ + static PRBool + sideWidthAndBearing(const FT_Vector *aEndPt, FT2PT1_info *aFti) + { + int aw = 0; + int ah = 0; +- FT_UShort upm = aFti->face->units_per_EM; ++ FT_UShort upm = get_upm (aFti->face); + FT_GlyphSlot slot; + FT_Glyph glyph; + FT_BBox bbox; + + slot = aFti->face->glyph; + +-#ifdef MOZ_ENABLE_XFT ++#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) + FT_Error error = FT_Get_Glyph(slot, &glyph); + if (error) { + NS_ERROR("sideWidthAndBearing failed to get glyph"); +@@ -256,7 +272,7 @@ static int + moveto(nsFT_CONST FT_Vector *aEndPt, void *aClosure) + { + FT2PT1_info *fti = (FT2PT1_info *)aClosure; +- FT_UShort upm = fti->face->units_per_EM; ++ FT_UShort upm = get_upm (fti->face); + PRBool rslt; + + if (fti->elm_cnt == 0) { +@@ -293,7 +309,7 @@ static int + lineto(nsFT_CONST FT_Vector *aEndPt, void *aClosure) + { + FT2PT1_info *fti = (FT2PT1_info *)aClosure; +- FT_UShort upm = fti->face->units_per_EM; ++ FT_UShort upm = get_upm (fti->face); + + if (toCS(upm, aEndPt->x) == fti->cur_x) { + fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->y) - (int)fti->cur_y); +@@ -320,7 +336,7 @@ conicto(nsFT_CONST FT_Vector *aControlPt + void *aClosure) + { + FT2PT1_info *ftinfo = (FT2PT1_info *)aClosure; +- FT_UShort upm = ftinfo->face->units_per_EM; ++ FT_UShort upm = get_upm (ftinfo->face); + double ctl_x, ctl_y; + double cur_x, cur_y, x3, y3; + FT_Vector aControlPt1, aControlPt2; +@@ -353,7 +369,7 @@ cubicto(nsFT_CONST FT_Vector *aControlPt + nsFT_CONST FT_Vector *aEndPt, void *aClosure) + { + FT2PT1_info *ftinfo = (FT2PT1_info *)aClosure; +- FT_UShort upm = ftinfo->face->units_per_EM; ++ FT_UShort upm = get_upm (ftinfo->face); + double cur_x, cur_y, x1, y1, x2, y2, x3, y3; + + cur_x = ftinfo->cur_x; +@@ -408,8 +424,55 @@ static FT_Outline_Funcs ft_outline_funcs + 0 + }; + ++ ++static int ++trace_bitmap_glyph (FT_GlyphSlot slot, FT2PT1_info *fti) ++{ ++ unsigned char *row, *byte_ptr, byte; ++ int rows, cols; ++ int x, y, bit_mask; ++ int upm, x_off, y_off, x_mult, y_mult; ++ ++ upm = get_upm (slot->face); ++ x_off = slot->bitmap_left; ++ y_off = slot->bitmap_top; ++ x_mult = upm / slot->face->size->metrics.x_ppem; ++ y_mult = upm / slot->face->size->metrics.y_ppem; ++ ++ switch (slot->bitmap.pixel_mode) { ++ case FT_PIXEL_MODE_MONO: ++ ++ for (y = 0, row = slot->bitmap.buffer, rows = slot->bitmap.rows; rows; row += slot->bitmap.pitch, rows--, y++) { ++ for (x = 0, byte_ptr = row, cols = (slot->bitmap.width + 7) / 8; cols; byte_ptr++, cols--) { ++ byte = *byte_ptr; ++ for (bit_mask = 128; bit_mask && x < slot->bitmap.width; bit_mask >>= 1, x++) { ++ if (byte & bit_mask) { ++ FT_Vector p; ++ p.x = x_mult * (x_off + x); ++ p.y = y_mult * (y_off - y); ++ moveto(&p, (void *) fti); ++ p.x += x_mult; ++ lineto(&p, (void *) fti); ++ p.y += y_mult; ++ lineto(&p, (void *) fti); ++ p.x -= x_mult; ++ lineto(&p, (void *) fti); ++ } ++ } ++ } ++ } ++ break; ++ ++ default: ++ return 1; ++ } ++ ++ return 0; ++} ++ ++ + FT_Error +-#ifdef MOZ_ENABLE_XFT ++#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) + FT2GlyphToType1CharString(FT_Face aFace, PRUint32 aGlyphID, + int aWmode, int aLenIV, unsigned char *aBuf) + #else +@@ -423,7 +486,7 @@ FT2GlyphToType1CharString(nsIFreeType2 * + unsigned char *start = aBuf; + FT2PT1_info fti; + +-#ifdef MOZ_ENABLE_XFT ++#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) + FT_Error error = FT_Load_Glyph(aFace, aGlyphID, flags); + if (error) { + NS_ERROR("failed to load aGlyphID"); +@@ -438,11 +501,6 @@ FT2GlyphToType1CharString(nsIFreeType2 * + #endif + slot = aFace->glyph; + +- if (slot->format != ft_glyph_format_outline) { +- NS_ERROR("aGlyphID is not an outline glyph"); +- return 1; +- } +- + #ifdef MOZ_ENABLE_FREETYPE2 + fti.ft2 = aFt2; + #endif +@@ -456,18 +514,27 @@ FT2GlyphToType1CharString(nsIFreeType2 * + for (j=0; j< aLenIV; j++) { + fti.len += ecsi(&fti.buf, 0); + } +-#ifdef MOZ_ENABLE_XFT +- if (FT_Outline_Decompose(&slot->outline, &ft_outline_funcs, &fti)) { +- NS_ERROR("error decomposing aGlyphID"); +- return 1; +- } ++ ++ if (slot->format == ft_glyph_format_outline) { ++#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) ++ if (FT_Outline_Decompose(&slot->outline, &ft_outline_funcs, &fti)) { ++ NS_ERROR("error decomposing aGlyphID"); ++ return 1; ++ } + #else +- rv = aFt2->OutlineDecompose(&slot->outline, &ft_outline_funcs, &fti); +- if (NS_FAILED(rv)) { +- NS_ERROR("error decomposing aGlyphID"); +- return 1; +- } ++ rv = aFt2->OutlineDecompose(&slot->outline, &ft_outline_funcs, &fti); ++ if (NS_FAILED(rv)) { ++ NS_ERROR("error decomposing aGlyphID"); ++ } + #endif ++ } else if (slot->format == ft_glyph_format_bitmap) { ++ /* ok, it's a bitmap glyph. trace it! */ ++ if (trace_bitmap_glyph (slot, &fti)) { ++ NS_ERROR("error tracing bitmap glyph"); ++ } ++ } else { ++ NS_ERROR("aGlyphID has unhandled format"); ++ } + + if (fti.elm_cnt) { + fti.len += csc(&fti.buf, T1_CLOSEPATH); +@@ -491,28 +558,52 @@ FT2GlyphToType1CharString(nsIFreeType2 * + } + + static PRBool +-#ifdef MOZ_ENABLE_XFT ++#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) + outputType1SubFont(FT_Face aFace, + #else + outputType1SubFont(nsIFreeType2 *aFt2, FT_Face aFace, + #endif +- const nsAString &aCharIDs, const char *aFontName, +- int aWmode, int aLenIV, FILE *aFile); ++ nsValueArray *aGlyphs, ++ PRUint32 aOffset, PRUint32 aLen, ++ const char *aFontName, ++ int aWmode, int aLenIV, FILE *aFile); + + nsresult + FT2ToType1FontName(FT_Face aFace, int aWmode, nsCString& aFontName) + { ++ // only hash the first 10 000 bytes of the font ++ int size = aFace->stream->size; ++ size = size > 10000 ? 10000 : size; ++ ++ unsigned char *data; ++ if (aFace->stream->read) { ++ data = (unsigned char *) malloc (size); ++ aFace->stream->read (aFace->stream, 0, data, size); ++ } else { ++ data = aFace->stream->base; ++ } ++ ++ unsigned int data_hash = 0; ++ int i; ++ for (i = 0; i < size; i++) ++ data_hash = (data_hash << 5) - data_hash + data[size]; ++ ++ if (aFace->stream->read) ++ free (data); ++ + aFontName = aFace->family_name; + aFontName.AppendLiteral("."); + aFontName += aFace->style_name; +- aFontName += nsPrintfCString(".%ld.%d", aFace->face_index, aWmode ? 1 : 0); ++ aFontName += nsPrintfCString(".%ld.%d.%lx.%x", aFace->face_index, aWmode ? 1 : 0, ++ (long) aFace->stream->size, data_hash); + flattenName(aFontName); ++ + return NS_OK; + } + + // output a subsetted truetype font converted to multiple type 1 fonts + PRBool +-FT2SubsetToType1FontSet(FT_Face aFace, const nsString& aSubset, ++FT2SubsetToType1FontSet(FT_Face aFace, nsValueArray *aGlyphSubset, + int aWmode, FILE *aFile) + { + #ifdef MOZ_ENABLE_FREETYPE2 +@@ -527,32 +618,35 @@ FT2SubsetToType1FontSet(FT_Face aFace, c + nsCAutoString fontNameBase; + FT2ToType1FontName(aFace, aWmode, fontNameBase); + PRUint32 i = 0; +- for (; i <= aSubset.Length() / 255 ; i++) { ++ for (; i <= aGlyphSubset->Count() / 255 ; i++) { + nsCAutoString fontName(fontNameBase); + fontName.AppendLiteral(".Set"); + fontName.AppendInt(i); +-#ifdef MOZ_ENABLE_XFT ++#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) + outputType1SubFont(aFace, + #else + outputType1SubFont(ft2, aFace, + #endif +- Substring(aSubset, i * 255, PR_MIN(255, aSubset.Length() - i * 255)), +- fontName.get(), aWmode, 4, aFile); ++ aGlyphSubset, ++ (i * 255), PR_MIN(255, aGlyphSubset->Count() - i * 255), ++ fontName.get(), aWmode, 4, aFile); + } + return PR_TRUE; + } + + // output a type 1 font (with 255 characters or fewer) + static PRBool +-#ifdef MOZ_ENABLE_XFT ++#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) + outputType1SubFont(FT_Face aFace, + #else + outputType1SubFont(nsIFreeType2 *aFt2, FT_Face aFace, + #endif +- const nsAString& aCharIDs, const char *aFontName, +- int aWmode, int aLenIV, FILE *aFile) ++ nsValueArray *aGlyphs, ++ PRUint32 aOffset, PRUint32 aLen, ++ const char *aFontName, ++ int aWmode, int aLenIV, FILE *aFile) + { +- FT_UShort upm = aFace->units_per_EM; ++ FT_UShort upm = get_upm (aFace); + + fprintf(aFile, "%%%%BeginResource: font %s\n" + "%%!PS-AdobeFont-1.0-3.0 %s 1.0\n" +@@ -573,9 +667,13 @@ outputType1SubFont(nsIFreeType2 *aFt2, F + toCS(upm, aFace->bbox.xMax), + toCS(upm, aFace->bbox.yMax)); + +- nsString charIDstr(aCharIDs); +- PRUint32 len = aCharIDs.Length(); +- ++ nsValueArray glyphs(PR_UINT16_MAX); ++ nsCStringArray glyphnames(PR_UINT16_MAX); ++ glyphs = *aGlyphs; ++ ++ PRUint32 len = aLen; ++ PRUint32 i; ++ + if (len < 10) { + // Add a small set of characters to the subset of the user + // defined font to produce to make sure the font ends up +@@ -584,25 +682,47 @@ outputType1SubFont(nsIFreeType2 *aFt2, F + // XXX : need to check if this is true of type 1 fonts as well. + // I suspect it's only the case of CID-keyed fonts (type 9) we used to + // generate. +- charIDstr.AppendLiteral("1234567890"); ++ for (i = 1; i <= 10; i++) { ++ glyphs.AppendValue(i); ++ } + len += 10; + } + +- const PRUnichar *charIDs = charIDstr.get(); +- +- PRUint32 i; ++ FT_Int has_glyph_name; ++#if defined (MOZ_ENABLE_XFT) || defined (MOZ_ENABLE_PANGO) ++ has_glyph_name = FT_Has_PS_Glyph_Names(aFace); ++#else ++ has_glyph_name = aFt2->hasPSGlyphNames(aFace); ++#endif + + // construct an Encoding vector : the 0th element + // is /.notdef +- fputs("/Encoding [\n/.notdef\n", aFile); +- for (i = 0; i < len; ++i) { +- fprintf(aFile, "/uni%04X", charIDs[i]); +- if (i % 8 == 7) fputc('\n', aFile); ++ fputs("/Encoding [\n/.notdef", aFile); ++ for (i = aOffset; i < aOffset + aLen; ++i) { ++ nsCString name; ++ char buffer[256]; ++ ++ if (glyphs.ValueAt(i) == 0) { ++ name = "/.notdef"; ++ } else if (!has_glyph_name || ++#if defined (MOZ_ENABLE_XFT) || defined (MOZ_ENABLE_PANGO) ++ FT_Get_Glyph_Name(aFace, glyphs.ValueAt(i), buffer, 255) != FT_Err_Ok ++#else ++ NS_FAILED(aFt2->getGlyphName(aFace, glyphs.ValueAt(i), buffer, 255)) ++#endif ++ ) { ++ name = nsPrintfCString(256, "/idx%04X", glyphs.ValueAt(i)); ++ } else { ++ name = nsPrintfCString(256, "/%s", buffer); ++ } ++ glyphnames.AppendCString(name); ++ fprintf(aFile, name.get()); ++ if ((i-aOffset) % 8 == 6) fputc('\n', aFile); + } + +- for (i = len; i < 255; ++i) { ++ for (i = PR_MAX (0, 255 - int(aLen)); i; --i) { + fputs("/.notdef", aFile); +- if (i % 8 == 7) fputc('\n', aFile); ++ if (i % 8 == 1) fputc('\n', aFile); + } + fputs("] def\n", aFile); + +@@ -630,23 +750,21 @@ outputType1SubFont(nsIFreeType2 *aFt2, F + // get the maximum charstring length without actually filling up the buffer + PRInt32 charStringLen; + PRInt32 maxCharStringLen = +-#ifdef MOZ_ENABLE_XFT ++#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) + FT2GlyphToType1CharString(aFace, 0, aWmode, aLenIV, nsnull); + #else + FT2GlyphToType1CharString(aFt2, aFace, 0, aWmode, aLenIV, nsnull); + #endif + +- PRUint32 glyphID; +- +- for (i = 0; i < len; i++) { +-#ifdef MOZ_ENABLE_XFT +- glyphID = FT_Get_Char_Index(aFace, charIDs[i]); ++ for (i = aOffset; i < aOffset + aLen; i++) { ++#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) + charStringLen = +- FT2GlyphToType1CharString(aFace, glyphID, aWmode, aLenIV, nsnull); ++ FT2GlyphToType1CharString(aFace, glyphs.ValueAt(i), aWmode, aLenIV, ++ nsnull); + #else +- aFt2->GetCharIndex(aFace, charIDs[i], &glyphID); + charStringLen = +- FT2GlyphToType1CharString(aFt2, aFace, glyphID, aWmode, aLenIV, nsnull); ++ FT2GlyphToType1CharString(aFt2, aFace, glyphs.ValueAt(i), aWmode, aLenIV, ++ nsnull); + #endif + + if (charStringLen > maxCharStringLen) +@@ -666,7 +784,7 @@ outputType1SubFont(nsIFreeType2 *aFt2, F + len + 1).get()); + + // output the notdef glyph +-#ifdef MOZ_ENABLE_XFT ++#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) + charStringLen = FT2GlyphToType1CharString(aFace, 0, aWmode, aLenIV, + charString.get()); + #else +@@ -676,22 +794,20 @@ outputType1SubFont(nsIFreeType2 *aFt2, F + + // enclose charString with "/.notdef RD ..... ND" + charStringOut(aFile, &pos, &key, NS_REINTERPRET_CAST(const char*, charString.get()), +- charStringLen, 0); ++ charStringLen, "/.notdef"); + + + // output the charstrings for each glyph in this sub font +- for (i = 0; i < len; i++) { +-#ifdef MOZ_ENABLE_XFT +- glyphID = FT_Get_Char_Index(aFace, charIDs[i]); +- charStringLen = FT2GlyphToType1CharString(aFace, glyphID, aWmode, ++ for (i = aOffset; i < aOffset + aLen; i++) { ++#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO) ++ charStringLen = FT2GlyphToType1CharString(aFace, glyphs.ValueAt(i), aWmode, + aLenIV, charString.get()); + #else +- aFt2->GetCharIndex(aFace, charIDs[i], &glyphID); +- charStringLen = FT2GlyphToType1CharString(aFt2, aFace, glyphID, aWmode, +- aLenIV, charString.get()); ++ charStringLen = FT2GlyphToType1CharString(aFt2, aFace, glyphs.ValueAt(i), ++ aWmode, aLenIV, charString.get()); + #endif + charStringOut(aFile, &pos, &key, NS_REINTERPRET_CAST(const char*, charString.get()), +- charStringLen, charIDs[i]); ++ charStringLen, glyphnames.CStringAt(i - aOffset)->get()); + } + + // wrap up the encrypted part of the font definition +@@ -753,15 +869,12 @@ void encryptAndHexOut(FILE *aFile, PRUin + + /* static */ + void charStringOut(FILE* aFile, PRUint32* aPos, PRUint16* aKey, +- const char *aStr, PRUint32 aLen, PRUnichar aId) ++ const char *aStr, PRUint32 aLen, const char *aGlyphName) + { + // use a local buffer instead of nsPrintfCString to avoid alloc. + char buf[30]; + int oLen; +- if (aId == 0) +- oLen = PR_snprintf(buf, 30, "/.notdef %d RD ", aLen); +- else +- oLen = PR_snprintf(buf, 30, "/uni%04X %d RD ", aId, aLen); ++ oLen = PR_snprintf(buf, 30, "%s %d RD ", aGlyphName, aLen); + + if (oLen >= 30) { + NS_WARNING("buffer size exceeded. charstring will be truncated"); +Index: gfx/src/ps/nsType1.h +=================================================================== +RCS file: /cvsroot/mozilla/gfx/src/ps/nsType1.h,v +retrieving revision 1.5 +diff -u -p -d -r1.5 nsType1.h +--- gfx/src/ps/nsType1.h 4 Mar 2005 07:39:27 -0000 1.5 ++++ gfx/src/ps/nsType1.h 23 Oct 2006 17:37:39 -0000 +@@ -122,8 +122,9 @@ FT_Error FT2GlyphToType1CharString(nsIFr + + class nsString; + class nsCString; ++class nsValueArray; + +-PRBool FT2SubsetToType1FontSet(FT_Face aFace, const nsString& aSubset, ++PRBool FT2SubsetToType1FontSet(FT_Face aFace, nsValueArray *aGlyphSubset, + int aWmode, FILE *aFile); + nsresult FT2ToType1FontName(FT_Face aFace, int aWmode, + nsCString& aFontName); |