summaryrefslogtreecommitdiff
path: root/firefox-2.0-pango-printing.patch
diff options
context:
space:
mode:
Diffstat (limited to 'firefox-2.0-pango-printing.patch')
-rw-r--r--firefox-2.0-pango-printing.patch4576
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);
bgstack15