]> git.pld-linux.org Git - packages/firefox.git/blob - mozilla-firefox-pango-printing.patch
- updated to 3.5rc3
[packages/firefox.git] / mozilla-firefox-pango-printing.patch
1 Patch for Firefox 1.5.0.7 to add support for printing via Pango.
2 This also implements printing MathML via Pango, and prints bitmap
3 fonts too.
4
5 Authors:
6         Behdad Esfahbod
7         Chris Blizzard
8         Akira TAGOH
9
10 Index: gfx/src/freetype/nsFreeType.cpp
11 ===================================================================
12 RCS file: /cvsroot/mozilla/gfx/src/freetype/nsFreeType.cpp,v
13 retrieving revision 1.28
14 diff -u -p -d -r1.28 nsFreeType.cpp
15 --- gfx/src/freetype/nsFreeType.cpp     13 Jul 2005 18:21:10 -0000      1.28
16 +++ gfx/src/freetype/nsFreeType.cpp     23 Oct 2006 17:37:09 -0000
17 @@ -123,6 +123,8 @@ FtFuncList nsFreeType2::FtFuncs [] = {
18  // #endif
19    {"FT_Get_First_Char",       NS_FT2_OFFSET(nsFT_Get_First_Char),       PR_FALSE},
20    {"FT_Get_Next_Char",        NS_FT2_OFFSET(nsFT_Get_Next_Char),        PR_FALSE},
21 +  {"FT_Has_PS_Glyph_Names",   NS_FT2_OFFSET(nsFT_Has_PS_Glyph_Names),   PR_FALSE},
22 +  {"FT_Get_Glyph_Name",       NS_FT2_OFFSET(nsFT_Get_Glyph_Name),       PR_TRUE},
23    {nsnull,                    0, 0}
24  };
25  
26 @@ -388,6 +390,22 @@ nsFreeType2::GetNextChar(FT_Face face, F
27  } 
28  
29  NS_IMETHODIMP
30 +nsFreeType2::HasPSGlyphNames(FT_Face face, FT_Int *result)
31 +{
32 +  // call the FreeType2 function via the function pointer
33 +  *result = nsFT_Has_PS_Glyph_Names(face);
34 +  return NS_OK;
35 +}
36 +
37 +NS_IMETHODIMP
38 +nsFreeType2::GetGlyphName(FT_Face face, FT_UInt glyph_index, FT_Pointer buffer, FT_UInt buffer_max)
39 +{
40 +  // call the FreeType2 function via the function pointer
41 +  FT_Error error = nsFT_Get_Glyph_Name(face, glyph_index, buffer, buffer_max);
42 +  return error ? NS_ERROR_FAILURE : NS_OK;
43 +}
44 +
45 +NS_IMETHODIMP
46  nsFreeType2::SupportsExtFunc(PRBool *res)
47  { 
48    *res = gHasExtFunc;
49 Index: gfx/src/freetype/nsFreeType.h
50 ===================================================================
51 RCS file: /cvsroot/mozilla/gfx/src/freetype/nsFreeType.h,v
52 retrieving revision 1.18
53 diff -u -p -d -r1.18 nsFreeType.h
54 --- gfx/src/freetype/nsFreeType.h       1 May 2005 17:36:19 -0000       1.18
55 +++ gfx/src/freetype/nsFreeType.h       23 Oct 2006 17:37:09 -0000
56 @@ -52,6 +52,7 @@
57  #include FT_CACHE_H
58  #include FT_CACHE_IMAGE_H
59  #include FT_TRUETYPE_TABLES_H
60 +#include FT_TYPE1_TABLES_H
61  #include "nsIFreeType2.h"
62  
63  typedef struct FT_FaceRec_*  FT_Face;
64 @@ -138,6 +139,8 @@ typedef FT_Error (*FT_Glyph_To_Bitmap_t)
65  
66  typedef FT_ULong (*FT_Get_First_Char_t)(FT_Face, FT_UInt*);
67  typedef FT_ULong (*FT_Get_Next_Char_t)(FT_Face, FT_ULong, FT_UInt*);
68 +typedef FT_Int   (*FT_Has_PS_Glyph_Names_t)(FT_Face);
69 +typedef FT_Error (*FT_Get_Glyph_Name_t)(FT_Face, FT_UInt, FT_Pointer, FT_UInt);
70  
71  class nsFreeTypeFace;
72  
73 @@ -193,11 +196,13 @@ protected:
74  // #endif
75    FT_Get_First_Char_t       nsFT_Get_First_Char;
76    FT_Get_Next_Char_t        nsFT_Get_Next_Char;
77 +  FT_Has_PS_Glyph_Names_t   nsFT_Has_PS_Glyph_Names;
78 +  FT_Get_Glyph_Name_t       nsFT_Get_Glyph_Name;
79  
80    // this array needs to be big enough to hold all the function pointers
81    // plus one extra for the null at the end
82  // #ifdef MOZ_SVG
83 -  static FtFuncList FtFuncs[24];
84 +  static FtFuncList FtFuncs[28];
85  // #else
86  //  static FtFuncList FtFuncs[20];
87  // #endif
88 Index: gfx/src/ps/Makefile.in
89 ===================================================================
90 RCS file: /cvsroot/mozilla/gfx/src/ps/Makefile.in,v
91 retrieving revision 1.57.8.1
92 diff -d -u -p -r1.57.8.1 Makefile.in
93 --- gfx/src/ps/Makefile.in      17 Jun 2006 15:16:14 -0000      1.57.8.1
94 +++ gfx/src/ps/Makefile.in      24 Oct 2006 18:36:45 -0000
95 @@ -98,6 +98,15 @@ EXTRA_DSO_LDOPTS = \
96                 $(MOZ_UNICHARUTIL_LIBS) \
97                 $(NULL)
98  
99 +ifdef MOZ_ENABLE_PANGO
100 +CPPSRCS                += \
101 +               nsFontMetricsPSPango.cpp \
102 +               mozilla-ps-decoder.cpp
103 +EXTRA_DSO_LDOPTS += $(MOZ_PANGO_LIBS)
104 +CXXFLAGS       += $(MOZ_PANGO_CFLAGS)
105 +CFLAGS         += $(MOZ_PANGO_CFLAGS)
106 +endif
107 +
108  ifdef MOZ_ENABLE_XFT
109  EXTRA_DSO_LDOPTS += \
110                 $(MOZ_XFT_LIBS) \
111 @@ -105,7 +114,7 @@ EXTRA_DSO_LDOPTS += \
112                 $(NULL)
113  endif
114  
115 -ifneq (,$(MOZ_ENABLE_FREETYPE2)$(MOZ_ENABLE_XFT))
116 +ifneq (,$(MOZ_ENABLE_FREETYPE2)$(MOZ_ENABLE_XFT)$(MOZ_ENABLE_PANGO))
117  CPPSRCS                += \
118                 nsType1.cpp \
119                 $(NULL)
120 Index: gfx/src/ps/mozilla-ps-decoder.cpp
121 ===================================================================
122 RCS file: gfx/src/ps/mozilla-ps-decoder.cpp
123 diff -N gfx/src/ps/mozilla-ps-decoder.cpp
124 --- /dev/null   1 Jan 1970 00:00:00 -0000
125 +++ gfx/src/ps/mozilla-ps-decoder.cpp   23 Oct 2006 17:37:10 -0000
126 @@ -0,0 +1,376 @@
127 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
128 +/* vim:expandtab:shiftwidth=4:tabstop=4:
129 + */
130 +/* ***** BEGIN LICENSE BLOCK *****
131 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
132 + *
133 + * The contents of this file are subject to the Mozilla Public License Version
134 + * 1.1 (the "License"); you may not use this file except in compliance with
135 + * the License. You may obtain a copy of the License at
136 + * http://www.mozilla.org/MPL/
137 + *
138 + * Software distributed under the License is distributed on an "AS IS" basis,
139 + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
140 + * for the specific language governing rights and limitations under the
141 + * License.
142 + *
143 + * The Original Code is mozilla.org code.
144 + *
145 + * The Initial Developer of the Original Code is Christopher Blizzard
146 + * <blizzard@mozilla.org>.  Portions created by the Initial Developer
147 + * are Copyright (C) 2004 the Initial Developer. All Rights Reserved.
148 + *
149 + * Contributor(s):
150 + *
151 + * Alternatively, the contents of this file may be used under the terms of
152 + * either the GNU General Public License Version 2 or later (the "GPL"), or
153 + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
154 + * in which case the provisions of the GPL or the LGPL are applicable instead
155 + * of those above. If you wish to allow use of your version of this file only
156 + * under the terms of either the GPL or the LGPL, and not to allow others to
157 + * use your version of this file under the terms of the MPL, indicate your
158 + * decision by deleting the provisions above and replace them with the notice
159 + * and other provisions required by the GPL or the LGPL. If you do not delete
160 + * the provisions above, a recipient may use your version of this file under
161 + * the terms of any one of the MPL, the GPL or the LGPL.
162 + *
163 + * ***** END LICENSE BLOCK ***** */
164 +
165 +#define PANGO_ENABLE_BACKEND
166 +#define PANGO_ENABLE_ENGINE
167 +
168 +#include "mozilla-ps-decoder.h"
169 +#include <pango/pangofc-fontmap.h>
170 +#include <pango/pangofc-font.h>
171 +
172 +#include "nsString.h"
173 +#include "nsIPersistentProperties2.h"
174 +#include "nsNetUtil.h"
175 +#include "nsReadableUtils.h"
176 +#include "nsICharsetConverterManager.h"
177 +#include "nsICharRepresentable.h"
178 +#include "nsCompressedCharMap.h"
179 +
180 +#undef DEBUG_CUSTOM_ENCODER
181 +
182 +G_DEFINE_TYPE (MozillaPSDecoder, mozilla_ps_decoder, PANGO_TYPE_FC_DECODER)
183 +
184 +MozillaPSDecoder *mozilla_ps_decoder_new      (void);
185 +
186 +static FcCharSet  *mozilla_ps_decoder_get_charset (PangoFcDecoder *decoder,
187 +                                                PangoFcFont    *fcfont);
188 +static PangoGlyph  mozilla_ps_decoder_get_glyph   (PangoFcDecoder *decoder,
189 +                                                PangoFcFont    *fcfont,
190 +                                                guint32         wc);
191 +
192 +static PangoFcDecoder *mozilla_find_ps_decoder    (FcPattern *pattern,
193 +                                                gpointer   user_data);
194 +
195 +typedef struct _MozillaPSDecoderPrivate MozillaPSDecoderPrivate;
196 +
197 +#define MOZILLA_PS_DECODER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MOZILLA_TYPE_DECODER, MozillaPSDecoderPrivate))
198 +
199 +struct _MozillaPSDecoderPrivate {
200 +    char *family;
201 +    char *encoder;
202 +    char *cmap;
203 +    gboolean is_wide;
204 +    FcCharSet *charset;
205 +    nsCOMPtr<nsIUnicodeEncoder> uEncoder;
206 +};
207 +
208 +static nsICharsetConverterManager *gCharsetManager = NULL;
209 +
210 +static NS_DEFINE_CID(kCharsetConverterManagerCID,
211 +                     NS_ICHARSETCONVERTERMANAGER_CID);
212 +
213 +// Hash tables that hold the custom encodings and custom cmaps used in
214 +// various fonts.
215 +static GHashTable *encoder_hash = NULL;
216 +static GHashTable *cmap_hash = NULL;
217 +static GHashTable *wide_hash = NULL;
218 +
219 +void
220 +mozilla_ps_decoder_init (MozillaPSDecoder *decoder)
221 +{
222 +}
223 +
224 +void
225 +mozilla_ps_decoder_class_init (MozillaPSDecoderClass *klass)
226 +{
227 +    GObjectClass *object_class = G_OBJECT_CLASS(klass);
228 +    PangoFcDecoderClass *parent_class = PANGO_FC_DECODER_CLASS (klass);
229 +
230 +    /*   object_class->finalize = test_finalize; */
231 +
232 +    parent_class->get_charset = mozilla_ps_decoder_get_charset;
233 +    parent_class->get_glyph = mozilla_ps_decoder_get_glyph;
234 +
235 +    g_type_class_add_private (object_class, sizeof (MozillaPSDecoderPrivate));
236 +}
237 +
238 +MozillaPSDecoder *
239 +mozilla_ps_decoder_new(void)
240 +{
241 +    return (MozillaPSDecoder *)g_object_new(MOZILLA_TYPE_DECODER, NULL);
242 +}
243 +
244 +#ifdef DEBUG_CUSTOM_ENCODER
245 +void
246 +dump_hash(char *key, char *val, void *arg)
247 +{
248 +    printf("%s -> %s\n", key, val);
249 +}
250 +#endif
251 +
252 +/**
253 + * mozilla_ps_decoders_init:
254 + *
255 + * #mozilla_ps_decoders_init:
256 + *
257 + * This initializes all of the application-specific custom decoders
258 + * that Mozilla uses.  This should only be called once during the
259 + * lifetime of the application.
260 + *
261 + * Return value: zero on success, not zero on failure.
262 + *
263 + **/
264 +
265 +int
266 +mozilla_ps_decoders_init(PangoFontMap *fontmap)
267 +{
268 +    static PRBool initialized = PR_FALSE;
269 +    if (initialized)
270 +        return 0;
271 +
272 +    if (!PANGO_IS_FC_FONT_MAP (fontmap))
273 +        return -1;
274 +
275 +    encoder_hash = g_hash_table_new(g_str_hash, g_str_equal);
276 +    cmap_hash = g_hash_table_new(g_str_hash, g_str_equal);
277 +    wide_hash = g_hash_table_new(g_str_hash, g_str_equal);
278 +
279 +    PRBool dumb = PR_FALSE;
280 +    nsCOMPtr<nsIPersistentProperties> props;
281 +    nsCOMPtr<nsISimpleEnumerator> encodeEnum;
282 +
283 +    NS_LoadPersistentPropertiesFromURISpec(getter_AddRefs(props),
284 +        NS_LITERAL_CSTRING("resource://gre/res/fonts/pangoFontEncoding.properties"));
285 +
286 +    if (!props)
287 +        goto loser;
288 +
289 +    // Enumerate the properties in this file and figure out all of the
290 +    // fonts for which we have custom encodings.
291 +    props->Enumerate(getter_AddRefs(encodeEnum));
292 +    if (!encodeEnum)
293 +        goto loser;
294 +
295 +    while (encodeEnum->HasMoreElements(&dumb), dumb) {
296 +        nsCOMPtr<nsIPropertyElement> prop;
297 +        encodeEnum->GetNext(getter_AddRefs(prop));
298 +        if (!prop)
299 +            goto loser;
300 +
301 +        nsCAutoString name;
302 +        prop->GetKey(name);
303 +        nsAutoString value;
304 +        prop->GetValue(value);
305 +
306 +        if (!StringBeginsWith(name, NS_LITERAL_CSTRING("encoding."))) {
307 +            printf("string doesn't begin with encoding?\n");
308 +            continue;
309 +        }
310 +
311 +        name = Substring(name, 9);
312 +
313 +        if (StringEndsWith(name, NS_LITERAL_CSTRING(".ttf"))) {
314 +            name = Substring(name, 0, name.Length() - 4);
315 +
316 +            // Strip off a .wide if it's there.
317 +            if (StringEndsWith(value, NS_LITERAL_STRING(".wide"))) {
318 +                g_hash_table_insert(wide_hash, g_strdup(name.get()),
319 +                                    g_strdup("wide"));
320 +                value = Substring(value, 0, name.Length() - 5);
321 +            }
322 +
323 +            g_hash_table_insert(encoder_hash,
324 +                                g_strdup(name.get()),
325 +                                g_strdup(NS_ConvertUTF16toUTF8(value).get()));
326 +        }
327 +        else if (StringEndsWith(name, NS_LITERAL_CSTRING(".ftcmap"))) {
328 +            name = Substring(name, 0, name.Length() - 7);
329 +            g_hash_table_insert(cmap_hash,
330 +                                g_strdup(name.get()),
331 +                                g_strdup(NS_ConvertUTF16toUTF8(value).get()));
332 +        }
333 +        else {
334 +            printf("unknown suffix used for mapping\n");
335 +        }
336 +    }
337 +
338 +    pango_fc_font_map_add_decoder_find_func(PANGO_FC_FONT_MAP(fontmap),
339 +                                            mozilla_find_ps_decoder,
340 +                                            NULL,
341 +                                            NULL);
342 +
343 +    initialized = PR_TRUE;
344 +
345 +#ifdef DEBUG_CUSTOM_ENCODER
346 +    printf("*** encoders\n");
347 +    g_hash_table_foreach(encoder_hash, (GHFunc)dump_hash, NULL);
348 +
349 +    printf("*** cmaps\n");
350 +    g_hash_table_foreach(cmap_hash, (GHFunc)dump_hash, NULL);
351 +#endif
352 +
353 +    return 0;
354 +
355 + loser:
356 +    return -1;
357 +}
358 +
359 +static FcCharSet *
360 +mozilla_ps_decoder_get_charset (PangoFcDecoder *decoder,
361 +                             PangoFcFont    *fcfont)
362 +{
363 +    MozillaPSDecoderPrivate *priv = MOZILLA_PS_DECODER_GET_PRIVATE(decoder);
364 +
365 +    if (priv->charset)
366 +        return priv->charset;
367 +
368 +    // First time this has been accessed.  Populate the charset.
369 +    priv->charset = FcCharSetCreate();
370 +
371 +    if (!gCharsetManager) {
372 +        CallGetService(kCharsetConverterManagerCID, &gCharsetManager);
373 +    }
374 +
375 +    nsCOMPtr<nsIUnicodeEncoder> encoder;
376 +    nsCOMPtr<nsICharRepresentable> represent;
377 +
378 +    if (!gCharsetManager)
379 +        goto end;
380 +
381 +    gCharsetManager->GetUnicodeEncoderRaw(priv->encoder, getter_AddRefs(encoder));
382 +    if (!encoder)
383 +        goto end;
384 +    
385 +    encoder->SetOutputErrorBehavior(encoder->kOnError_Replace, nsnull, '?');
386 +
387 +    priv->uEncoder = encoder;
388 +
389 +    represent = do_QueryInterface(encoder);
390 +    if (!represent)
391 +        goto end;
392 +
393 +    PRUint32 map[UCS2_MAP_LEN];
394 +    memset(map, 0, sizeof(map));
395 +
396 +    represent->FillInfo(map);
397 +
398 +    for (int i = 0; i < NUM_UNICODE_CHARS; i++) {
399 +        if (IS_REPRESENTABLE(map, i))
400 +            FcCharSetAddChar(priv->charset, i);
401 +    }
402 +
403 + end:
404 +    return priv->charset;
405 +}
406 +
407 +static PangoGlyph
408 +mozilla_ps_decoder_get_glyph   (PangoFcDecoder *decoder,
409 +                             PangoFcFont    *fcfont,
410 +                             guint32         wc)
411 +{
412 +    MozillaPSDecoderPrivate *priv = MOZILLA_PS_DECODER_GET_PRIVATE(decoder);
413 +
414 +    PangoGlyph retval = 0;
415 +    PRUnichar inchar = wc;
416 +    PRInt32 inlen = 1;
417 +    char outchar[2] = {0,0};
418 +    PRInt32 outlen = 2;
419 +
420 +    priv->uEncoder->Convert(&inchar, &inlen, outchar, &outlen);
421 +    if (outlen != 1) {
422 +        printf("Warning: mozilla_ps_decoder_get_glyph doesn't support more than one character conversions.\n");
423 +        return 0;
424 +    }
425 +
426 +    FT_Face face = pango_fc_font_lock_face(fcfont);
427 +
428 +#ifdef DEBUG_CUSTOM_ENCODER
429 +    char *filename;
430 +    FcPatternGetString(fcfont->font_pattern, FC_FILE, 0, (FcChar8 **)&filename);
431 +    printf("filename is %s\n", filename);
432 +#endif
433 +
434 +    // Make sure to set the right charmap before trying to get the
435 +    // glyph
436 +    if (priv->cmap) {
437 +        if (!strcmp(priv->cmap, "mac_roman")) {
438 +            FT_Select_Charmap(face, ft_encoding_apple_roman);
439 +        }
440 +        else if (!strcmp(priv->cmap, "unicode")) {
441 +            FT_Select_Charmap(face, ft_encoding_unicode);
442 +        }
443 +        else {
444 +            printf("Warning: Invalid charmap entry for family %s\n",
445 +                   priv->family);
446 +        }
447 +    }
448 +
449 +    // Standard 8 bit to glyph translation
450 +    if (!priv->is_wide) {
451 +        FcChar32 blah = PRUint8(outchar[0]);
452 +        retval = FT_Get_Char_Index(face, blah);
453 +#ifdef DEBUG_CUSTOM_ENCODER
454 +        printf("wc 0x%x outchar[0] 0x%x index 0x%x retval 0x%x face %p\n",
455 +               wc, outchar[0], blah, retval, (void *)face);
456 +#endif
457 +    }
458 +    else {
459 +        printf("Warning: We don't support .wide fonts!\n");
460 +        retval = 0;
461 +    }
462 +
463 +    pango_fc_font_unlock_face(fcfont);
464 +
465 +    return retval;
466 +}
467 +
468 +static PangoFcDecoder *
469 +mozilla_find_ps_decoder (FcPattern *pattern, gpointer user_data)
470 +{
471 +    // Compare the family name of the font that's been opened to see
472 +    // if we have a custom decoder.
473 +    const char *orig = NULL;
474 +    FcPatternGetString(pattern, FC_FAMILY, 0, (FcChar8 **)&orig);
475 +
476 +    nsCAutoString family;
477 +    family.Assign(orig);
478 +
479 +    family.StripWhitespace();
480 +    ToLowerCase(family);
481 +
482 +    char *encoder = (char *)g_hash_table_lookup(encoder_hash, family.get());
483 +    if (!encoder)
484 +        return NULL;
485 +
486 +    MozillaPSDecoder *decoder = mozilla_ps_decoder_new();
487 +
488 +    MozillaPSDecoderPrivate *priv = MOZILLA_PS_DECODER_GET_PRIVATE(decoder);
489 +
490 +    priv->family = g_strdup(family.get());
491 +    priv->encoder = g_strdup(encoder);
492 +
493 +    char *cmap = (char *)g_hash_table_lookup(cmap_hash, family.get());
494 +    if (cmap)
495 +        priv->cmap = g_strdup(cmap);
496 +
497 +    char *wide = (char *)g_hash_table_lookup(wide_hash, family.get());
498 +    if (wide)
499 +        priv->is_wide = TRUE;
500 +
501 +    return PANGO_FC_DECODER(decoder);
502 +}
503 Index: gfx/src/ps/mozilla-ps-decoder.h
504 ===================================================================
505 RCS file: gfx/src/ps/mozilla-ps-decoder.h
506 diff -N gfx/src/ps/mozilla-ps-decoder.h
507 --- /dev/null   1 Jan 1970 00:00:00 -0000
508 +++ gfx/src/ps/mozilla-ps-decoder.h     23 Oct 2006 17:37:10 -0000
509 @@ -0,0 +1,72 @@
510 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
511 +/* vim:expandtab:shiftwidth=4:tabstop=4:
512 + */
513 +/* ***** BEGIN LICENSE BLOCK *****
514 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
515 + *
516 + * The contents of this file are subject to the Mozilla Public License Version
517 + * 1.1 (the "License"); you may not use this file except in compliance with
518 + * the License. You may obtain a copy of the License at
519 + * http://www.mozilla.org/MPL/
520 + *
521 + * Software distributed under the License is distributed on an "AS IS" basis,
522 + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
523 + * for the specific language governing rights and limitations under the
524 + * License.
525 + *
526 + * The Original Code is mozilla.org code.
527 + *
528 + * The Initial Developer of the Original Code is Christopher Blizzard
529 + * <blizzard@mozilla.org>.  Portions created by the Initial Developer
530 + * are Copyright (C) 2004 the Initial Developer. All Rights Reserved.
531 + *
532 + * Contributor(s):
533 + *
534 + * Alternatively, the contents of this file may be used under the terms of
535 + * either the GNU General Public License Version 2 or later (the "GPL"), or
536 + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
537 + * in which case the provisions of the GPL or the LGPL are applicable instead
538 + * of those above. If you wish to allow use of your version of this file only
539 + * under the terms of either the GPL or the LGPL, and not to allow others to
540 + * use your version of this file under the terms of the MPL, indicate your
541 + * decision by deleting the provisions above and replace them with the notice
542 + * and other provisions required by the GPL or the LGPL. If you do not delete
543 + * the provisions above, a recipient may use your version of this file under
544 + * the terms of any one of the MPL, the GPL or the LGPL.
545 + *
546 + * ***** END LICENSE BLOCK ***** */
547 +
548 +#ifndef _MOZILLA_PS_DECODER_H
549 +#define _MOZILLA_PS_DECODER_H
550 +
551 +#include <pango/pangofc-decoder.h>
552 +
553 +G_BEGIN_DECLS
554 +
555 +#define MOZILLA_TYPE_DECODER (mozilla_ps_decoder_get_type())
556 +#define MOZILLA_PS_DECODER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOZILLA_TYPE_DECODER, MozillaPSDecoder))
557 +#define MOZILLA_IS_DECODER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOZILLA_TYPE_DECODER))
558 +
559 +typedef struct _MozillaPSDecoder      MozillaPSDecoder;
560 +typedef struct _MozillaPSDecoderClass MozillaPSDecoderClass;
561 +
562 +#define MOZILLA_PS_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOZILLA_TYPE_DECODER, MozillaPSDecoderClass))
563 +#define MOZILLA_IS_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOZILLA_TYPE_DECODER))
564 +#define MOZILLA_PS_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOZILLA_TYPE_DECODER, MozillaPSDecoderClass))
565 +
566 +struct _MozillaPSDecoder
567 +{
568 +  PangoFcDecoder parent_instance;
569 +};
570 +
571 +struct _MozillaPSDecoderClass
572 +{
573 +  PangoFcDecoderClass parent_class;
574 +};
575 +
576 +GType           mozilla_ps_decoder_get_type (void);
577 +int             mozilla_ps_decoders_init    (PangoFontMap *fontmap);
578 +
579 +G_END_DECLS
580 +
581 +#endif /*_MOZILLA_PS_DECODER_H */
582 Index: gfx/src/ps/nsDeviceContextPS.cpp
583 ===================================================================
584 RCS file: /cvsroot/mozilla/gfx/src/ps/nsDeviceContextPS.cpp,v
585 retrieving revision 1.73
586 diff -u -p -d -r1.73 nsDeviceContextPS.cpp
587 --- gfx/src/ps/nsDeviceContextPS.cpp    21 May 2005 15:33:08 -0000      1.73
588 +++ gfx/src/ps/nsDeviceContextPS.cpp    23 Oct 2006 17:37:10 -0000
589 @@ -58,12 +58,15 @@
590  #include "nsIPref.h"
591  #include "nsString.h"
592  #include "nsFontMetricsPS.h"
593 +#ifdef MOZ_ENABLE_PANGO
594 +#include "nsFontMetricsPSPango.h"
595 +#endif
596  #include "nsPostScriptObj.h"
597  #include "nspr.h"
598  #include "nsILanguageAtomService.h"
599  #include "nsPrintJobPS.h"
600  #include "nsPrintJobFactoryPS.h"
601 -#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
602 +#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
603  #include "nsType1.h"
604  #endif
605  
606 @@ -223,7 +226,7 @@ nsDeviceContextPS::InitDeviceContextPS(n
607   
608    nsresult rv;
609    nsCOMPtr<nsIPref> pref(do_GetService(NS_PREF_CONTRACTID, &rv));
610 -#ifdef MOZ_ENABLE_XFT
611 +#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
612    if (NS_SUCCEEDED(rv)) {
613        rv = pref->GetBoolPref("font.FreeType2.printing", &mFTPEnable);
614        if (NS_FAILED(rv))
615 @@ -469,7 +472,7 @@ NS_IMETHODIMP nsDeviceContextPS::EndDocu
616        NS_ASSERTION(submitFP, "No print job submission handle");
617  
618        // Start writing the print job to the job handler
619 -#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
620 +#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
621        mPSObj->write_prolog(submitFP, mFTPEnable);
622  #else 
623        mPSObj->write_prolog(submitFP);
624 @@ -550,15 +553,52 @@ public:
625    virtual nsresult CreateFontMetricsInstance(nsIFontMetrics** aResult);
626  };
627  
628 +#if defined(MOZ_ENABLE_PANGO)
629 +PRBool
630 +NS_IsPangoEnabled(void)
631 +{
632 +    static PRBool beenHere;
633 +    static PRBool pangoEnabled;
634 +
635 +    if (!beenHere) {
636 +        beenHere = PR_TRUE;
637 +
638 +        char *val = PR_GetEnv("MOZ_DISABLE_PANGO");
639 +        pangoEnabled = !(val);
640 +
641 +        if (pangoEnabled) {
642 +            nsCOMPtr<nsIPref> prefService = do_GetService(NS_PREF_CONTRACTID);
643 +            if (prefService)
644 +                prefService->SetDefaultCharPref("general.useragent.extra.pango",
645 +                                                "pango-text");
646 +        }
647 +    }
648 +
649 +    return pangoEnabled;
650 +}
651 +#endif
652  
653  nsresult nsFontCachePS::CreateFontMetricsInstance(nsIFontMetrics** aResult)
654  {
655    NS_PRECONDITION(aResult, "null out param");
656 -  nsIFontMetrics *fm = new nsFontMetricsPS();
657 -  if (!fm)
658 -    return NS_ERROR_OUT_OF_MEMORY;
659 -  NS_ADDREF(fm);
660 -  *aResult = fm;
661 +#ifdef MOZ_ENABLE_PANGO
662 +  if (NS_IsPangoEnabled())
663 +  {
664 +    nsIFontMetrics *fm = new nsFontMetricsPSPango();
665 +    if (!fm)
666 +      return NS_ERROR_OUT_OF_MEMORY;
667 +    NS_ADDREF(fm);
668 +    *aResult = fm;
669 +  }
670 +  else
671 +#endif
672 +  {
673 +    nsIFontMetrics *fm = new nsFontMetricsPS();
674 +    if (!fm)
675 +      return NS_ERROR_OUT_OF_MEMORY;
676 +    NS_ADDREF(fm);
677 +    *aResult = fm;
678 +  }
679    return NS_OK;
680  }
681  
682 Index: gfx/src/ps/nsFontMetricsPS.cpp
683 ===================================================================
684 RCS file: /cvsroot/mozilla/gfx/src/ps/nsFontMetricsPS.cpp,v
685 retrieving revision 1.57.16.2
686 diff -u -p -d -r1.57.16.2 nsFontMetricsPS.cpp
687 --- gfx/src/ps/nsFontMetricsPS.cpp      7 May 2006 02:01:25 -0000       1.57.16.2
688 +++ gfx/src/ps/nsFontMetricsPS.cpp      23 Oct 2006 17:37:11 -0000
689 @@ -461,6 +461,239 @@ nsFontMetricsPS :: GetStringWidth(const 
690    return NS_OK;
691  }
692  
693 +nsresult
694 +nsFontMetricsPS::DrawString(const char *aString, PRUint32 aLength,
695 +                               nscoord aX, nscoord aY,
696 +                               const nscoord* aSpacing,
697 +                               nsRenderingContextPS *aContext)
698 +{
699 +  nsPostScriptObj* psObj = aContext->GetPostScriptObj();
700 +  // When FT2 printing is enabled, we don't need to set langgroup
701 +#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
702 +  if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, GetDeviceContext())->mFTPEnable) {
703 +#endif
704 +    nsCOMPtr<nsIAtom> langGroup;
705 +    GetLangGroup(getter_AddRefs(langGroup));
706 +    psObj->setlanggroup(langGroup);
707 +#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
708 +  }
709 +#endif
710 +
711 +  if (aLength == 0)
712 +    return NS_OK;
713 +  nsFontPS* fontPS = nsFontPS::FindFont(aString[0], Font(), this);
714 +  NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
715 +  fontPS->SetupFont(aContext);
716 +
717 +  PRUint32 i, start = 0;
718 +  for (i=0; i<aLength; i++) {
719 +    nsFontPS* fontThisChar;
720 +    fontThisChar = nsFontPS::FindFont(aString[i], Font(), this);
721 +    NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE);
722 +    if (fontThisChar != fontPS) {
723 +      // draw text up to this point
724 +      aX += DrawString(aString+start, i-start, aX, aY, fontPS, 
725 +                       aSpacing?aSpacing+start:nsnull, aContext);
726 +      start = i;
727 +
728 +      // setup for following text
729 +      fontPS = fontThisChar;
730 +      fontPS->SetupFont(aContext);
731 +    }
732 +  }
733 +
734 +  // draw the last part
735 +  if (aLength-start)
736 +    DrawString(aString+start, aLength-start, aX, aY, fontPS, 
737 +               aSpacing?aSpacing+start:nsnull, aContext);
738 +
739 +  return NS_OK;
740 +}
741 +
742 +nsresult
743 +nsFontMetricsPS::DrawString(const PRUnichar* aString, PRUint32 aLength,
744 +                               nscoord aX, nscoord aY,
745 +                               PRInt32 aFontID,
746 +                               const nscoord* aSpacing,
747 +                               nsRenderingContextPS *aContext)
748 +{
749 +  nsPostScriptObj* psObj = aContext->GetPostScriptObj();
750 +#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
751 +  // When FT2 printing is enabled, we don't need to set langgroup
752 +  if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, GetDeviceContext())->mFTPEnable) {
753 +#endif
754 +    nsCOMPtr<nsIAtom> langGroup = nsnull;
755 +    GetLangGroup(getter_AddRefs(langGroup));
756 +    psObj->setlanggroup(langGroup);
757 +#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
758 +  }
759 +#endif
760 +
761 +  /* build up conversion table */
762 +  psObj->preshow(aString, aLength);
763 +
764 +  if (aLength == 0)
765 +    return NS_OK;
766 +  nsFontPS* fontPS = nsFontPS::FindFont(aString[0], Font(), this);
767 +  NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
768 +  fontPS->SetupFont(aContext);
769 +
770 +  PRUint32 i, start = 0;
771 +  for (i=0; i<aLength; i++) {
772 +    nsFontPS* fontThisChar;
773 +    fontThisChar = nsFontPS::FindFont(aString[i], Font(), this);
774 +    NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE);
775 +    if (fontThisChar != fontPS) {
776 +      // draw text up to this point
777 +      aX += DrawString(aString+start, i-start, aX, aY, fontPS, 
778 +                       aSpacing?aSpacing+start:nsnull, aContext);
779 +      start = i;
780 +
781 +      // setup for following text
782 +      fontPS = fontThisChar;
783 +      fontPS->SetupFont(aContext);
784 +    }
785 +  }
786 +
787 +  // draw the last part
788 +  if (aLength-start)
789 +    DrawString(aString+start, aLength-start, aX, aY, fontPS, 
790 +               aSpacing?aSpacing+start:nsnull, aContext);
791 +
792 +  return NS_OK;
793 +}
794 +
795 +PRInt32
796 +nsFontMetricsPS::DrawString(const char *aString, PRUint32 aLength,
797 +                        nscoord aX, nscoord aY, nsFontPS* aFontPS,
798 +                        const nscoord* aSpacing,
799 +                       nsRenderingContextPS *aContext)
800 +{
801 +  nscoord width = 0;
802 +  PRInt32 x = aX;
803 +  PRInt32 y = aY;
804 +
805 +  PRInt32 dxMem[500];
806 +  PRInt32* dx0 = 0;
807 +  if (aSpacing) {
808 +    dx0 = dxMem;
809 +    if (aLength > 500) {
810 +      dx0 = new PRInt32[aLength];
811 +      NS_ENSURE_TRUE(dx0, NS_ERROR_OUT_OF_MEMORY);
812 +    }
813 +    aContext->GetTranMatrix()->ScaleXCoords(aSpacing, aLength, dx0);
814 +  }
815 +
816 +  aContext->GetTranMatrix()->TransformCoord(&x, &y);
817 +  width = aFontPS->DrawString(aContext, x, y, aString, aLength);
818 +
819 +  if ((aSpacing) && (dx0 != dxMem)) {
820 +    delete [] dx0;
821 +  }
822 +
823 +  return width;
824 +}
825 +
826 +
827 +PRInt32
828 +nsFontMetricsPS::DrawString(const PRUnichar* aString, PRUint32 aLength,
829 +                                 nscoord &aX, nscoord &aY, nsFontPS* aFontPS,
830 +                                 const nscoord* aSpacing,
831 +                                nsRenderingContextPS *aContext)
832 +{
833 +  nscoord width = 0;
834 +  PRInt32 x = aX;
835 +  PRInt32 y = aY;
836 +
837 +  if (aSpacing) {
838 +    // Slow, but accurate rendering
839 +    const PRUnichar* end = aString + aLength;
840 +    while (aString < end){
841 +      x = aX;
842 +      y = aY;
843 +      aContext->GetTranMatrix()->TransformCoord(&x, &y);
844 +      aFontPS->DrawString(aContext, x, y, aString, 1);
845 +      aX += *aSpacing++;
846 +      aString++;
847 +    }
848 +    width = aX;
849 +  } else {
850 +    aContext->GetTranMatrix()->TransformCoord(&x, &y);
851 +    width = aFontPS->DrawString(aContext, x, y, aString, aLength);
852 +  }
853 +
854 +  return width;
855 +}
856 +
857 +NS_IMETHODIMP
858 +nsFontMetricsPS::GetTextDimensions(const char*       aString,
859 +                                        PRInt32           aLength,
860 +                                        PRInt32           aAvailWidth,
861 +                                        PRInt32*          aBreaks,
862 +                                        PRInt32           aNumBreaks,
863 +                                        nsTextDimensions& aDimensions,
864 +                                        PRInt32&          aNumCharsFit,
865 +                                        nsTextDimensions& aLastWordDimensions,
866 +                                        PRInt32*          aFontID)
867 +{
868 +  NS_NOTYETIMPLEMENTED("nsFontMetricsPS::GetTextDimensions");
869 +  return NS_ERROR_NOT_IMPLEMENTED;
870 +}
871 +
872 +NS_IMETHODIMP
873 +nsFontMetricsPS::GetTextDimensions(const PRUnichar*  aString,
874 +                                        PRInt32           aLength,
875 +                                        PRInt32           aAvailWidth,
876 +                                        PRInt32*          aBreaks,
877 +                                        PRInt32           aNumBreaks,
878 +                                        nsTextDimensions& aDimensions,
879 +                                        PRInt32&          aNumCharsFit,
880 +                                        nsTextDimensions& aLastWordDimensions,
881 +                                        PRInt32*          aFontID)
882 +{
883 +  NS_NOTYETIMPLEMENTED("nsFontMetricsPS::GetTextDimensions");
884 +  return NS_ERROR_NOT_IMPLEMENTED;
885 +}
886 +
887 +NS_IMETHODIMP
888 +nsFontMetricsPS :: GetTextDimensions(const char* aString, PRUint32 aLength,
889 +                                          nsTextDimensions& aDimensions)
890 +{
891 +  GetStringWidth(aString, aDimensions.width, aLength);
892 +  GetMaxAscent(aDimensions.ascent);
893 +  GetMaxDescent(aDimensions.descent);
894 +  return NS_OK;
895 +}
896 +
897 +NS_IMETHODIMP
898 +nsFontMetricsPS :: GetTextDimensions(const PRUnichar* aString, PRUint32 aLength,
899 +                                          nsTextDimensions& aDimensions, PRInt32* aFontID)
900 +{
901 +  GetStringWidth(aString, aDimensions.width, aLength);
902 +  //XXX temporary - bug 96609
903 +  GetMaxAscent(aDimensions.ascent);
904 +  GetMaxDescent(aDimensions.descent);
905 +  return NS_OK;
906 +}
907 +
908 +nsresult
909 +nsFontMetricsPS::GetBoundingMetrics(const char*        aString,
910 +                                     PRUint32           aLength,
911 +                                     nsBoundingMetrics& aBoundingMetrics)
912 +{
913 +  return NS_ERROR_NOT_IMPLEMENTED;
914 +}
915 +
916 +nsresult
917 +nsFontMetricsPS::GetBoundingMetrics(const PRUnichar*   aString,
918 +                                     PRUint32           aLength,
919 +                                     nsBoundingMetrics &aBoundingMetrics,
920 +                                     PRInt32 *aFontID)
921 +{
922 +  return NS_ERROR_NOT_IMPLEMENTED;
923 +}
924 +
925 +
926  nsFontPS*
927  nsFontPS::FindFont(char aChar, const nsFont& aFont, 
928                     nsFontMetricsPS* aFontMetrics)
929 @@ -1128,23 +1361,38 @@ nsFontPSXft::DrawString(nsRenderingConte
930    PRUint32 start = 0;
931    PRUint32 i;
932  
933 +  FT_Face face = getFTFace();
934 +  if (!face) {
935 +    NS_WARNING("Failed to get FT Face in nsFontPSXft::DrawString\n");
936 +    return 0;
937 +  }
938 +
939 +  nsValueArray glyphs(PR_UINT16_MAX);
940 +
941    // XXX : ignore surrogate pairs for now
942 -  nsString *subSet = mPSFontGenerator->GetSubset();
943    for (i = 0; i < aLength; ++i) {
944 -    currSubFont = mPSFontGenerator->AddToSubset(aString[i]);
945 +    PRUint32 glyph = FT_Get_Char_Index(face, aString[i]);
946 +    currSubFont = mPSFontGenerator->AddToGlyphSubset(glyph);
947 +
948 +    // Check if we need to render the current string
949      if (prevSubFont != currSubFont) {
950 -      if (prevSubFont != -1)
951 -        psObj->show(&aString[start], i - start, *subSet, prevSubFont);
952 +      if (prevSubFont != -1) {
953 +        psObj->show(&glyphs, mPSFontGenerator, prevSubFont);
954 +      }
955        NS_ASSERTION(!mFontNameBase.IsEmpty(),
956                    "font base name shouldn't be empty");
957        psObj->setfont(mFontNameBase, mHeight, currSubFont);
958        prevSubFont = currSubFont;
959        start = i;
960 +      glyphs.Clear();
961      }
962 +
963 +    glyphs.AppendValue(glyph);
964    }
965  
966 -  if (prevSubFont != -1)
967 -    psObj->show(&aString[start], i - start, *subSet, prevSubFont); 
968 +  if (prevSubFont != -1) {
969 +    psObj->show(&glyphs, mPSFontGenerator, prevSubFont);
970 +  }
971    
972    return GetWidth(aString, aLength);
973  }
974 @@ -2278,10 +2526,13 @@ nsFontPSFreeType::GetBoundingMetrics(con
975  // Implementation of nsPSFontGenerator
976  nsPSFontGenerator::nsPSFontGenerator()
977  {
978 +  mGlyphSubset = new nsValueArray(PR_UINT16_MAX, 40);
979  }
980  
981  nsPSFontGenerator::~nsPSFontGenerator()
982  {
983 +  if (mGlyphSubset)
984 +    delete mGlyphSubset;
985  }
986  
987  void nsPSFontGenerator::GeneratePSFont(FILE* aFile)
988 @@ -2289,24 +2540,29 @@ void nsPSFontGenerator::GeneratePSFont(F
989    NS_ERROR("should never call nsPSFontGenerator::GeneratePSFont");
990  }
991  
992 -// Add a Unicode character to mSubset which will be divided into 
993 -// multiple chunks (subfonts) of 255 (kSubFontSize) characters each. 
994 -// Each chunk will be converted to a Type 1 font. Return the index of 
995 -// a subfont (chunk) this character belongs to.
996 +// Add a glyph offset to mSubset which will be divided into multiple
997 +// chunks (subfonts) of 255 (kSubFontSize) glyphs each.  Each chunk
998 +// will then be converted into a Type 1 font.  Return the index of a
999 +// subfont (chunk) this glyph belongs to.
1000  PRInt32
1001 -nsPSFontGenerator::AddToSubset(PRUnichar aChar)
1002 +nsPSFontGenerator::AddToGlyphSubset(PRUint32 aGlyph)
1003  {
1004 -  PRInt32 index = mSubset.FindChar(aChar);
1005 -  if (index == kNotFound) {
1006 -    mSubset.Append(aChar);
1007 -    index = mSubset.Length() - 1;
1008 +  nsValueArrayIndex index = mGlyphSubset->IndexOf(aGlyph);
1009 +  if (index == NSVALUEARRAY_INVALID) {
1010 +    mGlyphSubset->AppendValue(aGlyph);
1011 +    index = mGlyphSubset->Count() - 1;
1012    }
1013 +
1014    return index / kSubFontSize;
1015  }
1016  
1017 -nsString *nsPSFontGenerator::GetSubset()
1018 +PRInt32
1019 +nsPSFontGenerator::InSubsetIndexOf(PRUint32 aGlyph)
1020  {
1021 -  return &mSubset;
1022 +  nsValueArrayIndex index = mGlyphSubset->IndexOf(aGlyph);
1023 +  if (index == NSVALUEARRAY_INVALID)
1024 +    return 0;
1025 +  return (index % kSubFontSize) + 1;
1026  }
1027  
1028  #ifdef MOZ_ENABLE_XFT
1029 @@ -2353,8 +2609,8 @@ void nsXftType1Generator::GeneratePSFont
1030    }
1031  
1032    int wmode = 0;
1033 -  if (!mSubset.IsEmpty())
1034 -    FT2SubsetToType1FontSet(face, mSubset, wmode, aFile);
1035 +  if (mGlyphSubset->Count())
1036 +    FT2SubsetToType1FontSet(face, mGlyphSubset, wmode, aFile);
1037  }
1038  
1039  #else
1040 @@ -2402,8 +2658,8 @@ void nsFT2Type1Generator::GeneratePSFont
1041      return;
1042   
1043    int wmode = 0;
1044 -  if (!mSubset.IsEmpty())
1045 -    FT2SubsetToType1FontSet(face, mSubset, wmode, aFile);
1046 +  if (mGlyphSubset->Count())
1047 +    FT2SubsetToType1FontSet(face, mGlyphSubset, wmode, aFile);
1048  }
1049  
1050  #endif //MOZ_ENABLE_FREETYPE2
1051 Index: gfx/src/ps/nsFontMetricsPS.h
1052 ===================================================================
1053 RCS file: /cvsroot/mozilla/gfx/src/ps/nsFontMetricsPS.h,v
1054 retrieving revision 1.31
1055 diff -u -p -d -r1.31 nsFontMetricsPS.h
1056 --- gfx/src/ps/nsFontMetricsPS.h        28 Jun 2005 18:29:10 -0000      1.31
1057 +++ gfx/src/ps/nsFontMetricsPS.h        23 Oct 2006 17:37:11 -0000
1058 @@ -66,6 +66,7 @@
1059  #endif
1060  #include "nsVoidArray.h"
1061  #include "nsHashtable.h"
1062 +#include "nsValueArray.h"
1063  
1064  class nsPSFontGenerator;
1065  class nsDeviceContextPS;
1066 @@ -108,6 +109,65 @@ public:
1067    NS_IMETHOD  GetFontHandle(nsFontHandle &aHandle);
1068    NS_IMETHOD  GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength);
1069    NS_IMETHOD  GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength);
1070 +
1071 +    NS_IMETHOD       GetTextDimensions(const char* aString,
1072 +                                       PRUint32 aLength,
1073 +                                       nsTextDimensions& aDimensions);
1074 +    NS_IMETHOD       GetTextDimensions(const PRUnichar* aString,
1075 +                                       PRUint32 aLength,
1076 +                                       nsTextDimensions& aDimensions, 
1077 +                                       PRInt32* aFontID);
1078 +    NS_IMETHOD       GetTextDimensions(const char*         aString,
1079 +                                       PRInt32             aLength,
1080 +                                       PRInt32             aAvailWidth,
1081 +                                       PRInt32*            aBreaks,
1082 +                                       PRInt32             aNumBreaks,
1083 +                                       nsTextDimensions&   aDimensions,
1084 +                                       PRInt32&            aNumCharsFit,
1085 +                                       nsTextDimensions&   aLastWordDimensions,
1086 +                                       PRInt32*            aFontID);
1087 +    NS_IMETHOD       GetTextDimensions(const PRUnichar*    aString,
1088 +                                       PRInt32             aLength,
1089 +                                       PRInt32             aAvailWidth,
1090 +                                       PRInt32*            aBreaks,
1091 +                                       PRInt32             aNumBreaks,
1092 +                                       nsTextDimensions&   aDimensions,
1093 +                                       PRInt32&            aNumCharsFit,
1094 +                                       nsTextDimensions&   aLastWordDimensions,
1095 +                                       PRInt32*            aFontID);
1096 +#ifdef MOZ_MATHML
1097 +    NS_IMETHOD       GetBoundingMetrics(const char *aString, PRUint32 aLength,
1098 +                                        nsBoundingMetrics &aBoundingMetrics);
1099 +    NS_IMETHOD       GetBoundingMetrics(const PRUnichar *aString,
1100 +                                        PRUint32 aLength,
1101 +                                        nsBoundingMetrics &aBoundingMetrics,
1102 +                                        PRInt32 *aFontID);
1103 +#endif /* MOZ_MATHML */
1104 +
1105 +  NS_IMETHOD DrawString(const char *aString, PRUint32 aLength,
1106 +                        nscoord aX, nscoord aY,
1107 +                        const nscoord* aSpacing,
1108 +                       nsRenderingContextPS *aContext);
1109 +  NS_IMETHOD DrawString(const PRUnichar *aString, PRUint32 aLength,
1110 +                        nscoord aX, nscoord aY,
1111 +                        PRInt32 aFontID,
1112 +                        const nscoord* aSpacing,
1113 +                       nsRenderingContextPS *aContext);
1114 +
1115 +protected:
1116 +  PRInt32 DrawString(const char *aString, PRUint32 aLength,
1117 +                        nscoord aX, nscoord aY, nsFontPS* aFontPS,
1118 +                        const nscoord* aSpacing,
1119 +                       nsRenderingContextPS *aContext);
1120 +  PRInt32 DrawString(const PRUnichar *aString, PRUint32 aLength,
1121 +                        nscoord &aX, nscoord &aY, nsFontPS* aFontPS,
1122 +                        const nscoord* aSpacing,
1123 +                       nsRenderingContextPS *aContext);
1124 +
1125 +public:
1126 +
1127 +  virtual PRUint32    GetHints     (void) { return 0; }
1128 +
1129    
1130    inline void SetXHeight(nscoord aXHeight) { mXHeight = aXHeight; };
1131    inline void SetSuperscriptOffset(nscoord aSuperscriptOffset) { mSuperscriptOffset = aSuperscriptOffset; };
1132 @@ -455,16 +515,14 @@ public:
1133    nsPSFontGenerator();
1134    virtual ~nsPSFontGenerator();
1135    virtual void  GeneratePSFont(FILE* aFile);
1136 -  PRInt32  AddToSubset(PRUnichar aChar);
1137 -  nsString *GetSubset();
1138 +  PRInt32  AddToGlyphSubset(PRUint32 aGlyph);
1139 +  PRInt32  InSubsetIndexOf(PRUint32 aGlyph);
1140  
1141    // 256 (PS type 1 encoding vector size) - 1 (1 is for mandatory /.notdef)
1142    const static PRUint16 kSubFontSize; 
1143  
1144  protected:
1145 -  // XXX To support non-BMP characters, we may have to use 
1146 -  // nsValueArray with PRUint32
1147 -  nsString mSubset;
1148 +  nsValueArray *mGlyphSubset;
1149  };
1150  
1151  
1152 Index: gfx/src/ps/nsFontMetricsPSPango.cpp
1153 ===================================================================
1154 RCS file: gfx/src/ps/nsFontMetricsPSPango.cpp
1155 diff -N gfx/src/ps/nsFontMetricsPSPango.cpp
1156 --- /dev/null   1 Jan 1970 00:00:00 -0000
1157 +++ gfx/src/ps/nsFontMetricsPSPango.cpp 23 Oct 2006 17:37:13 -0000
1158 @@ -0,0 +1,2107 @@
1159 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1160 +/* vim:expandtab:shiftwidth=4:tabstop=4:
1161 + */
1162 +/* ***** BEGIN LICENSE BLOCK *****
1163 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
1164 + *
1165 + * The contents of this file are subject to the Mozilla Public License Version
1166 + * 1.1 (the "License"); you may not use this file except in compliance with
1167 + * the License. You may obtain a copy of the License at
1168 + * http://www.mozilla.org/MPL/
1169 + *
1170 + * Software distributed under the License is distributed on an "AS IS" basis,
1171 + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1172 + * for the specific language governing rights and limitations under the
1173 + * License.
1174 + *
1175 + * The Original Code is mozilla.org code.
1176 + *
1177 + * The Initial Developer of the Original Code is Christopher Blizzard
1178 + * <blizzard@mozilla.org>.  Portions created by the Initial Developer
1179 + * are Copyright (C) 2004 the Initial Developer. All Rights Reserved.
1180 + *
1181 + * Contributor(s):
1182 + *   Christopher Blizzard <blizzard@mozilla.org>
1183 + *   Behdad Esfahbod <behdad@behdad.org>
1184 + *
1185 + * Alternatively, the contents of this file may be used under the terms of
1186 + * either the GNU General Public License Version 2 or later (the "GPL"), or
1187 + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
1188 + * in which case the provisions of the GPL or the LGPL are applicable instead
1189 + * of those above. If you wish to allow use of your version of this file only
1190 + * under the terms of either the GPL or the LGPL, and not to allow others to
1191 + * use your version of this file under the terms of the MPL, indicate your
1192 + * decision by deleting the provisions above and replace them with the notice
1193 + * and other provisions required by the GPL or the LGPL. If you do not delete
1194 + * the provisions above, a recipient may use your version of this file under
1195 + * the terms of any one of the MPL, the GPL or the LGPL.
1196 + *
1197 + * ***** END LICENSE BLOCK ***** */
1198 +
1199 +#include <strings.h>
1200 +#include "nsFont.h"
1201 +#include "nsIDeviceContext.h"
1202 +#include "nsICharsetConverterManager.h"
1203 +#include "nsIPref.h"
1204 +#include "nsServiceManagerUtils.h"
1205 +
1206 +#define PANGO_ENABLE_BACKEND
1207 +#define PANGO_ENABLE_ENGINE
1208 +
1209 +#include "nsFontMetricsPSPango.h"
1210 +#include "nsRenderingContextPS.h"
1211 +#include "nsDeviceContextPS.h"
1212 +#include "nsFontConfigUtils.h"
1213 +
1214 +#include "nsPrintfCString.h"
1215 +#include "nsUnicharUtils.h"
1216 +#include "nsQuickSort.h"
1217 +#include "nsFontConfigUtils.h"
1218 +
1219 +#include <fontconfig/fontconfig.h>
1220 +#include <pango/pangoft2.h>
1221 +#include <freetype/tttables.h>
1222 +#include "nsType1.h"
1223 +
1224 +#include "mozilla-ps-decoder.h"
1225 +
1226 +#define FORCE_PR_LOG
1227 +#include "prlog.h"
1228 +
1229 +// Globals
1230 +
1231 +static PRLogModuleInfo            *gPangoFontLog;
1232 +static int                         gNumInstances;
1233 +
1234 +
1235 +static void
1236 +default_substitute (FcPattern *pattern,
1237 +                    gpointer   data)
1238 +{
1239 +  FcPatternDel (pattern, FC_HINTING);
1240 +  FcPatternAddBool (pattern, FC_HINTING, 0);
1241 +}
1242 +
1243 +static PangoFontMap *
1244 +get_fontmap (void)
1245 +{
1246 +  static PangoFontMap               *fontmap = NULL;
1247 +
1248 +  if (!fontmap) {
1249 +    fontmap = pango_ft2_font_map_new ();
1250 +    pango_ft2_font_map_set_resolution ((PangoFT2FontMap *)fontmap, 72., 72.);
1251 +    pango_ft2_font_map_set_default_substitute ((PangoFT2FontMap *)fontmap, default_substitute, NULL, NULL);
1252 +  }
1253 +
1254 +  return fontmap;
1255 +}
1256 +
1257 +static PangoContext *
1258 +get_context (void)
1259 +{
1260 +  return pango_ft2_font_map_create_context ((PangoFT2FontMap *) get_fontmap ());
1261 +}
1262 +
1263 +// Defines
1264 +
1265 +// This is the scaling factor that we keep fonts limited to against
1266 +// the display size.  If a pixel size is requested that is more than
1267 +// this factor larger than the height of the display, it's clamped to
1268 +// that value instead of the requested size.
1269 +#define FONT_MAX_FONT_SCALE 2
1270 +
1271 +static NS_DEFINE_CID(kCharsetConverterManagerCID,
1272 +                     NS_ICHARSETCONVERTERMANAGER_CID);
1273 +
1274 +#ifdef DEBUG
1275 +#define DUMP_PRUNICHAR(ustr, ulen) for (PRUint32 llen=0;llen<ulen;llen++) \
1276 +                                      printf("0x%x ", ustr[llen]); \
1277 +                                   printf("\n");
1278 +#endif
1279 +
1280 +// rounding and truncation functions for a Freetype floating point number 
1281 +// (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer
1282 +// part and low 6 bits for the fractional part. 
1283 +#define MOZ_FT_ROUND(x) (((x) + 32) & ~63) // 63 = 2^6 - 1
1284 +#define MOZ_FT_TRUNC(x) ((x) >> 6)
1285 +#define CONVERT_DESIGN_UNITS_TO_PIXELS(v, s) \
1286 +        MOZ_FT_TRUNC(MOZ_FT_ROUND(FT_MulFix((v) , (s))))
1287 +
1288 +// Static function decls
1289 +
1290 +static PangoLanguage *GetPangoLanguage(nsIAtom *aLangGroup);
1291 +
1292 +static void   FreeGlobals    (void);
1293 +
1294 +static PangoStyle  CalculateStyle  (PRUint8 aStyle);
1295 +static PangoWeight CalculateWeight (PRUint16 aWeight);
1296 +
1297 +static nsresult    EnumFontsPango   (nsIAtom* aLangGroup, const char* aGeneric,
1298 +                                     PRUint32* aCount, PRUnichar*** aResult);
1299 +static int         CompareFontNames (const void* aArg1, const void* aArg2,
1300 +                                     void* aClosure);
1301 +
1302 +nsFontMetricsPSPango::nsFontMetricsPSPango()
1303 +{
1304 +    if (!gPangoFontLog)
1305 +        gPangoFontLog = PR_NewLogModule("PangoFont");
1306 +
1307 +    gNumInstances++;
1308 +
1309 +    mPangoFontDesc = nsnull;
1310 +    mPangoContext = nsnull;
1311 +    mLTRPangoContext = nsnull;
1312 +    mRTLPangoContext = nsnull;
1313 +    mPangoAttrList = nsnull;
1314 +    mIsRTL = PR_FALSE;
1315 +    mPangoSpaceWidth = 0;
1316 +
1317 +    static PRBool initialized = PR_FALSE;
1318 +    if (initialized)
1319 +        return;
1320 +
1321 +    // Initialized the custom decoders
1322 +    if (!mozilla_ps_decoders_init(get_fontmap ()))
1323 +        initialized = PR_TRUE;
1324 +}
1325 +
1326 +nsFontMetricsPSPango::~nsFontMetricsPSPango()
1327 +{
1328 +    if (mDeviceContext)
1329 +        mDeviceContext->FontMetricsDeleted(this);
1330 +
1331 +    if (mPangoFontDesc)
1332 +        pango_font_description_free(mPangoFontDesc);
1333 +
1334 +    if (mLTRPangoContext)
1335 +        g_object_unref(mLTRPangoContext);
1336 +
1337 +    if (mRTLPangoContext)
1338 +        g_object_unref(mRTLPangoContext);
1339 +
1340 +    if (mPangoAttrList)
1341 +        pango_attr_list_unref(mPangoAttrList);
1342 +
1343 +    // XXX clean up all the pango objects
1344 +
1345 +    if (--gNumInstances == 0)
1346 +        FreeGlobals();
1347 +}
1348 +
1349 +
1350 +NS_IMPL_ISUPPORTS1(nsFontMetricsPSPango, nsIFontMetrics)
1351 +
1352 +// nsIFontMetrics impl
1353 +
1354 +NS_IMETHODIMP
1355 +nsFontMetricsPSPango::Init(const nsFont& aFont, nsIAtom* aLangGroup,
1356 +                         nsIDeviceContext *aContext)
1357 +{
1358 +    mFont = aFont;
1359 +    mLangGroup = aLangGroup;
1360 +
1361 +    // Hang on to the device context
1362 +    mDeviceContext = aContext;
1363 +    
1364 +    mPointSize = NSTwipsToFloatPoints(mFont.size);
1365 +
1366 +    // enumerate over the font names passed in
1367 +    mFont.EnumerateFamilies(nsFontMetricsPSPango::EnumFontCallback, this);
1368 +
1369 +    nsCOMPtr<nsIPref> prefService;
1370 +    prefService = do_GetService(NS_PREF_CONTRACTID);
1371 +    if (!prefService)
1372 +        return NS_ERROR_FAILURE;
1373 +        
1374 +    nsXPIDLCString value;
1375 +    const char* langGroup;
1376 +    mLangGroup->GetUTF8String(&langGroup);
1377 +
1378 +    // Set up the default font name if it's not set
1379 +    if (!mGenericFont) {
1380 +        nsCAutoString name("font.default.");
1381 +        name.Append(langGroup);
1382 +        prefService->CopyCharPref(name.get(), getter_Copies(value));
1383 +
1384 +        if (value.get())
1385 +            mDefaultFont = value.get();
1386 +        else
1387 +            mDefaultFont = "serif";
1388 +        
1389 +        mGenericFont = &mDefaultFont;
1390 +    }
1391 +
1392 +    // set up the minimum sizes for fonts
1393 +    if (mLangGroup) {
1394 +        nsCAutoString name("font.min-size.");
1395 +
1396 +        if (mGenericFont->Equals("monospace"))
1397 +            name.Append("fixed");
1398 +        else
1399 +            name.Append("variable");
1400 +
1401 +        name.Append(char('.'));
1402 +        name.Append(langGroup);
1403 +
1404 +        PRInt32 minimumInt = 0;
1405 +        float minimum;
1406 +        nsresult res;
1407 +        res = prefService->GetIntPref(name.get(), &minimumInt);
1408 +        if (NS_FAILED(res))
1409 +            prefService->GetDefaultIntPref(name.get(), &minimumInt);
1410 +
1411 +        if (minimumInt < 0)
1412 +            minimumInt = 0;
1413 +
1414 +        minimum = minimumInt;
1415 +
1416 +        // The minimum size is specified in pixels, not in points.
1417 +        // Convert the size from pixels to points.
1418 +        minimum = NSTwipsToFloatPoints(NSFloatPixelsToTwips(minimum, mDeviceContext->DevUnitsToAppUnits()));
1419 +        if (mPointSize < minimum)
1420 +            mPointSize = minimum;
1421 +    }
1422 +
1423 +    // Make sure that the pixel size is at least greater than zero
1424 +    if (mPointSize < 1) {
1425 +#ifdef DEBUG
1426 +        printf("*** Warning: nsFontMetricsPSPango created with point size %f\n",
1427 +               mPointSize);
1428 +#endif
1429 +        mPointSize = 1;
1430 +    }
1431 +
1432 +    nsresult rv = RealizeFont();
1433 +    if (NS_FAILED(rv))
1434 +        return rv;
1435 +
1436 +    // Cache font metrics for the 'x' character
1437 +    return CacheFontMetrics();
1438 +}
1439 +
1440 +nsresult
1441 +nsFontMetricsPSPango::CacheFontMetrics(void)
1442 +{
1443 +    // Get our scale factor
1444 +    float f;
1445 +    float val;
1446 +    f = mDeviceContext->DevUnitsToAppUnits();
1447 +
1448 +    mPangoAttrList = pango_attr_list_new();
1449 +
1450 +    GList *items = pango_itemize(mPangoContext,
1451 +                                 "a", 0, 1, mPangoAttrList, NULL);
1452 +
1453 +    if (!items)
1454 +        return NS_ERROR_FAILURE;
1455 +
1456 +    guint nitems = g_list_length(items);
1457 +    if (nitems != 1)
1458 +        return NS_ERROR_FAILURE;
1459 +
1460 +    PangoItem *item = (PangoItem *)items->data;
1461 +    PangoFcFont  *fcfont = PANGO_FC_FONT(item->analysis.font);
1462 +    if (!fcfont)
1463 +        return NS_ERROR_FAILURE;
1464 +
1465 +    // Get our font face
1466 +    FT_Face face;
1467 +    face = pango_fc_font_lock_face(fcfont);
1468 +    if (!face)
1469 +       return NS_ERROR_NOT_AVAILABLE;
1470 +       
1471 +    TT_OS2 *os2;
1472 +    os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2);
1473 +
1474 +    // mEmHeight (size in pixels of EM height)
1475 +    int size;
1476 +    if (FcPatternGetInteger(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) !=
1477 +        FcResultMatch) {
1478 +        size = 12;
1479 +    }
1480 +    mEmHeight = PR_MAX(1, nscoord(size * f));
1481 +
1482 +    // mMaxAscent
1483 +    val = MOZ_FT_TRUNC(face->size->metrics.ascender);
1484 +    mMaxAscent = NSToIntRound(val * f);
1485 +
1486 +    // mMaxDescent
1487 +    val = -MOZ_FT_TRUNC(face->size->metrics.descender);
1488 +    mMaxDescent = NSToIntRound(val * f);
1489 +
1490 +    nscoord lineHeight = mMaxAscent + mMaxDescent;
1491 +
1492 +    // mLeading (needs ascent and descent and EM height) 
1493 +    if (lineHeight > mEmHeight)
1494 +        mLeading = lineHeight - mEmHeight;
1495 +    else
1496 +        mLeading = 0;
1497 +
1498 +    // mMaxHeight (needs ascent and descent)
1499 +    mMaxHeight = lineHeight;
1500 +
1501 +    // mEmAscent (needs maxascent, EM height, ascent and descent)
1502 +    mEmAscent = nscoord(mMaxAscent * mEmHeight / lineHeight);
1503 +
1504 +    // mEmDescent (needs EM height and EM ascent
1505 +    mEmDescent = mEmHeight - mEmAscent;
1506 +
1507 +    // mMaxAdvance
1508 +    val = MOZ_FT_TRUNC(face->size->metrics.max_advance);
1509 +    mMaxAdvance = NSToIntRound(val * f);
1510 +
1511 +    // mPangoSpaceWidth
1512 +    PangoLayout *layout = pango_layout_new(mPangoContext);
1513 +    pango_layout_set_text(layout, " ", 1);
1514 +    int pswidth, psheight;
1515 +    pango_layout_get_size(layout, &pswidth, &psheight);
1516 +    mPangoSpaceWidth = pswidth;
1517 +    g_object_unref(layout);
1518 +
1519 +    // mSpaceWidth (width of a space)
1520 +    nscoord tmpWidth;
1521 +    GetWidth(" ", 1, tmpWidth);
1522 +    mSpaceWidth = tmpWidth;
1523 +
1524 +    // mAveCharWidth (width of an 'average' char)
1525 +    //    XftTextExtents16(GDK_DISPLAY(), xftFont, &xUnichar, 1, &extents);
1526 +    //rawWidth = extents.width;
1527 +    //mAveCharWidth = NSToCoordRound(rawWidth * f);
1528 +    GetWidth("x", 1, tmpWidth);
1529 +    mAveCharWidth = tmpWidth;
1530 +
1531 +    // mXHeight (height of an 'x' character)
1532 +    if (pango_fc_font_has_char(fcfont, 'x')) {
1533 +        PangoRectangle rect;
1534 +        PangoGlyph glyph = pango_fc_font_get_glyph (fcfont, 'x');
1535 +        pango_font_get_glyph_extents (PANGO_FONT (fcfont), glyph, &rect, NULL);
1536 +        mXHeight = NSToIntRound(rect.height * f / PANGO_SCALE);
1537 +    }
1538 +    else {
1539 +        // 56% of ascent, best guess for non-true type or asian fonts
1540 +        mXHeight = nscoord(((float)mMaxAscent) * 0.56 * f);
1541 +    }
1542 +
1543 +    // mUnderlineOffset (offset for underlines)
1544 +    val = CONVERT_DESIGN_UNITS_TO_PIXELS(face->underline_position,
1545 +                                         face->size->metrics.y_scale);
1546 +    if (val) {
1547 +        mUnderlineOffset = NSToIntRound(val * f);
1548 +    }
1549 +    else {
1550 +        mUnderlineOffset =
1551 +            -NSToIntRound(PR_MAX(1, floor(0.1 *
1552 +                MOZ_FT_TRUNC(face->size->metrics.height) + 0.5)) * f);
1553 +    }
1554 +
1555 +    // mUnderlineSize (thickness of an underline)
1556 +    val = CONVERT_DESIGN_UNITS_TO_PIXELS(face->underline_thickness,
1557 +                                         face->size->metrics.y_scale);
1558 +    if (val) {
1559 +        mUnderlineSize = nscoord(PR_MAX(f, NSToIntRound(val * f)));
1560 +    }
1561 +    else {
1562 +        mUnderlineSize =
1563 +            NSToIntRound(PR_MAX(1,
1564 +               floor(0.05 * MOZ_FT_TRUNC(face->size->metrics.height) + 0.5)) * f);
1565 +    }
1566 +
1567 +    // mSuperscriptOffset
1568 +    if (os2 && os2->ySuperscriptYOffset) {
1569 +        val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySuperscriptYOffset,
1570 +                                             face->size->metrics.y_scale);
1571 +        mSuperscriptOffset = nscoord(PR_MAX(f, NSToIntRound(val * f)));
1572 +    }
1573 +    else {
1574 +        mSuperscriptOffset = mXHeight;
1575 +    }
1576 +
1577 +    // mSubscriptOffset
1578 +    if (os2 && os2->ySubscriptYOffset) {
1579 +        val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySubscriptYOffset,
1580 +                                             face->size->metrics.y_scale);
1581 +        // some fonts have the incorrect sign. 
1582 +        val = (val < 0) ? -val : val;
1583 +        mSubscriptOffset = nscoord(PR_MAX(f, NSToIntRound(val * f)));
1584 +    }
1585 +    else {
1586 +        mSubscriptOffset = mXHeight;
1587 +    }
1588 +
1589 +    // mStrikeoutOffset
1590 +    mStrikeoutOffset = NSToCoordRound(mXHeight / 2.0);
1591 +
1592 +    // mStrikeoutSize
1593 +    mStrikeoutSize = mUnderlineSize;
1594 +
1595 +    pango_fc_font_unlock_face(fcfont);
1596 +
1597 +    /*
1598 +    printf("%i\n", mXHeight);
1599 +    printf("%i\n", mSuperscriptOffset);
1600 +    printf("%i\n", mSubscriptOffset);
1601 +    printf("%i\n", mStrikeoutOffset);
1602 +    printf("%i\n", mStrikeoutSize);
1603 +    printf("%i\n", mUnderlineOffset);
1604 +    printf("%i\n", mUnderlineSize);
1605 +    printf("%i\n", mMaxHeight);
1606 +    printf("%i\n", mLeading);
1607 +    printf("%i\n", mEmHeight);
1608 +    printf("%i\n", mEmAscent);
1609 +    printf("%i\n", mEmDescent);
1610 +    printf("%i\n", mMaxAscent);
1611 +    printf("%i\n", mMaxDescent);
1612 +    printf("%i\n", mMaxAdvance);
1613 +    printf("%i\n", mSpaceWidth);
1614 +    printf("%i\n", mAveCharWidth);
1615 +    */
1616 +
1617 +    return NS_OK;
1618 +}
1619 +
1620 +NS_IMETHODIMP
1621 +nsFontMetricsPSPango::Destroy()
1622 +{
1623 +    mDeviceContext = nsnull;
1624 +    return NS_OK;
1625 +}
1626 +
1627 +NS_IMETHODIMP
1628 +nsFontMetricsPSPango::GetLangGroup(nsIAtom** aLangGroup)
1629 +{
1630 +    *aLangGroup = mLangGroup;
1631 +    NS_IF_ADDREF(*aLangGroup);
1632 +
1633 +    return NS_OK;
1634 +}
1635 +
1636 +NS_IMETHODIMP
1637 +nsFontMetricsPSPango::GetFontHandle(nsFontHandle &aHandle)
1638 +{
1639 +    return NS_ERROR_NOT_IMPLEMENTED;
1640 +}
1641 +
1642 +// nsIFontMetricsPango impl
1643 +NS_IMETHODIMP
1644 +nsFontMetricsPSPango::GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength)
1645 +{
1646 +    return GetWidth (String, (PRUint32) aLength, aWidth);
1647 +}
1648 +
1649 +NS_IMETHODIMP
1650 +nsFontMetricsPSPango::GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength)
1651 +{
1652 +    return GetWidth (aString, (PRUint32)aLength, aWidth);
1653 +}
1654 +
1655 +nsresult
1656 +nsFontMetricsPSPango::GetWidth(const char* aString, PRUint32 aLength,
1657 +                             nscoord& aWidth)
1658 +{
1659 +    PangoLayout *layout = pango_layout_new(mPangoContext);
1660 +
1661 +    pango_layout_set_text(layout, aString, aLength);
1662 +
1663 +    if (mPangoSpaceWidth)
1664 +        FixupSpaceWidths(layout, aString);
1665 +
1666 +    int width, height;
1667 +
1668 +    pango_layout_get_size(layout, &width, &height);
1669 +
1670 +    g_object_unref(layout);
1671 +
1672 +    float f;
1673 +    f = mDeviceContext->DevUnitsToAppUnits();
1674 +    aWidth = NSToCoordRound(width * f / PANGO_SCALE);
1675 +
1676 +    //    printf("GetWidth (char *) %d\n", aWidth);
1677 +
1678 +    return NS_OK;
1679 +}
1680 +
1681 +nsresult
1682 +nsFontMetricsPSPango::GetWidth(const PRUnichar* aString, PRUint32 aLength,
1683 +                             nscoord& aWidth)
1684 +{
1685 +    nsresult rv = NS_OK;
1686 +    PangoLayout *layout = pango_layout_new(mPangoContext);
1687 +
1688 +    gchar *text = g_utf16_to_utf8(aString, aLength,
1689 +                                  NULL, NULL, NULL);
1690 +
1691 +    if (!text) {
1692 +        aWidth = 0;
1693 +#ifdef DEBUG
1694 +        NS_WARNING("nsFontMetricsPSPango::GetWidth invalid unicode to follow");
1695 +        DUMP_PRUNICHAR(aString, aLength)
1696 +#endif
1697 +        rv = NS_ERROR_FAILURE;
1698 +        goto loser;
1699 +    }
1700 +
1701 +    gint width, height;
1702 +
1703 +    pango_layout_set_text(layout, text, strlen(text));
1704 +    FixupSpaceWidths(layout, text);
1705 +    pango_layout_get_size(layout, &width, &height);
1706 +
1707 +    float f;
1708 +    f = mDeviceContext->DevUnitsToAppUnits();
1709 +    aWidth = NSToCoordRound(width * f / PANGO_SCALE);
1710 +
1711 +    //    printf("GetWidth %d\n", aWidth);
1712 +
1713 + loser:
1714 +    g_free(text);
1715 +    g_object_unref(layout);
1716 +
1717 +    return rv;
1718 +}
1719 +
1720 +
1721 +nsresult
1722 +nsFontMetricsPSPango :: GetTextDimensions(const char* aString, PRUint32 aLength,
1723 +                                          nsTextDimensions& aDimensions)
1724 +{
1725 +    nsresult rv = NS_OK;
1726 +
1727 +    PangoLayout *layout = pango_layout_new(mPangoContext);
1728 +
1729 +    pango_layout_set_text(layout, aString, aLength);
1730 +    FixupSpaceWidths(layout,aString);
1731 +
1732 +    // Get the logical extents
1733 +    PangoLayoutLine *line;
1734 +    if (pango_layout_get_line_count(layout) != 1) {
1735 +        printf("Warning: more than one line!\n");
1736 +    }
1737 +    line = pango_layout_get_line(layout, 0);
1738 +
1739 +    PangoRectangle rect;
1740 +    pango_layout_line_get_extents(line, NULL, &rect);
1741 +
1742 +    float P2T;
1743 +    P2T = mDeviceContext->DevUnitsToAppUnits();
1744 +
1745 +    aDimensions.width = NSToCoordRound(rect.width * P2T / PANGO_SCALE);
1746 +    aDimensions.ascent = NSToCoordRound(PANGO_ASCENT(rect) * P2T / PANGO_SCALE);
1747 +    aDimensions.descent = NSToCoordRound(PANGO_DESCENT(rect) * P2T / PANGO_SCALE);
1748 +
1749 +    //    printf("GetTextDimensions %d %d %d\n", aDimensions.width,
1750 +    //aDimensions.ascent, aDimensions.descent);
1751 +
1752 + loser:
1753 +    g_object_unref(layout);
1754 +
1755 +    return rv;
1756 +}
1757 +
1758 +nsresult
1759 +nsFontMetricsPSPango::GetTextDimensions(const PRUnichar* aString,
1760 +                                      PRUint32 aLength,
1761 +                                      nsTextDimensions& aDimensions, 
1762 +                                      PRInt32* aFontID)
1763 +{
1764 +    nsresult rv = NS_OK;
1765 +
1766 +    PangoLayout *layout = pango_layout_new(mPangoContext);
1767 +
1768 +    gchar *text = g_utf16_to_utf8(aString, aLength,
1769 +                                  NULL, NULL, NULL);
1770 +
1771 +    if (!text) {
1772 +#ifdef DEBUG
1773 +        NS_WARNING("nsFontMetricsPSPango::GetTextDimensions invalid unicode to follow");
1774 +        DUMP_PRUNICHAR(aString, aLength)
1775 +#endif
1776 +        aDimensions.width = 0;
1777 +        aDimensions.ascent = 0;
1778 +        aDimensions.descent = 0;
1779 +
1780 +        rv = NS_ERROR_FAILURE;
1781 +        goto loser;
1782 +    }
1783 +        
1784 +
1785 +    pango_layout_set_text(layout, text, strlen(text));
1786 +    FixupSpaceWidths(layout, text);
1787 +
1788 +    // Get the logical extents
1789 +    PangoLayoutLine *line;
1790 +    if (pango_layout_get_line_count(layout) != 1) {
1791 +        printf("Warning: more than one line!\n");
1792 +    }
1793 +    line = pango_layout_get_line(layout, 0);
1794 +
1795 +    PangoRectangle rect;
1796 +    pango_layout_line_get_extents(line, NULL, &rect);
1797 +
1798 +    float P2T;
1799 +    P2T = mDeviceContext->DevUnitsToAppUnits();
1800 +
1801 +    aDimensions.width = NSToCoordRound(rect.width * P2T / PANGO_SCALE);
1802 +    aDimensions.ascent = NSToCoordRound(PANGO_ASCENT(rect) * P2T / PANGO_SCALE);
1803 +    aDimensions.descent = NSToCoordRound(PANGO_DESCENT(rect) * P2T / PANGO_SCALE);
1804 +
1805 +    //    printf("GetTextDimensions %d %d %d\n", aDimensions.width,
1806 +    //aDimensions.ascent, aDimensions.descent);
1807 +
1808 + loser:
1809 +    g_free(text);
1810 +    g_object_unref(layout);
1811 +
1812 +    return rv;
1813 +}
1814 +
1815 +nsresult
1816 +nsFontMetricsPSPango::GetTextDimensions(const char*         aString,
1817 +                                      PRInt32             aLength,
1818 +                                      PRInt32             aAvailWidth,
1819 +                                      PRInt32*            aBreaks,
1820 +                                      PRInt32             aNumBreaks,
1821 +                                      nsTextDimensions&   aDimensions,
1822 +                                      PRInt32&            aNumCharsFit,
1823 +                                      nsTextDimensions&   aLastWordDimensions,
1824 +                                      PRInt32*            aFontID)
1825 +{
1826 +
1827 +    return GetTextDimensionsInternal(aString, aLength, aAvailWidth, aBreaks,
1828 +                                     aNumBreaks, aDimensions, aNumCharsFit,
1829 +                                     aLastWordDimensions);
1830 +
1831 +}
1832 +
1833 +nsresult
1834 +nsFontMetricsPSPango::GetTextDimensions(const PRUnichar*    aString,
1835 +                                      PRInt32             aLength,
1836 +                                      PRInt32             aAvailWidth,
1837 +                                      PRInt32*            aBreaks,
1838 +                                      PRInt32             aNumBreaks,
1839 +                                      nsTextDimensions&   aDimensions,
1840 +                                      PRInt32&            aNumCharsFit,
1841 +                                      nsTextDimensions&   aLastWordDimensions,
1842 +                                      PRInt32*            aFontID)
1843 +{
1844 +    nsresult rv = NS_OK;
1845 +    PRInt32 curBreak = 0;
1846 +    gchar *curChar;
1847 +
1848 +    PRInt32 *utf8Breaks = new PRInt32[aNumBreaks];
1849 +
1850 +    gchar *text = g_utf16_to_utf8(aString, (PRInt32)aLength,
1851 +                                  NULL, NULL, NULL);
1852 +
1853 +    curChar = text;
1854 +
1855 +    if (!text) {
1856 +#ifdef DEBUG
1857 +        NS_WARNING("nsFontMetricsPSPango::GetWidth invalid unicode to follow");
1858 +        DUMP_PRUNICHAR(aString, (PRUint32)aLength)
1859 +#endif
1860 +        rv = NS_ERROR_FAILURE;
1861 +        goto loser;
1862 +    }
1863 +
1864 +    // Covert the utf16 break offsets to utf8 break offsets
1865 +    for (PRInt32 curOffset=0; curOffset < aLength;
1866 +         curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
1867 +        if (aBreaks[curBreak] == curOffset) {
1868 +            utf8Breaks[curBreak] = curChar - text;
1869 +            curBreak++;
1870 +        }
1871 +
1872 +        if (IS_HIGH_SURROGATE(aString[curOffset]))
1873 +            curOffset++;
1874 +    }
1875 +
1876 +    // Always catch the last break
1877 +    utf8Breaks[curBreak] = curChar - text;
1878 +
1879 +#if 0
1880 +    if (strlen(text) != aLength) {
1881 +        printf("Different lengths for utf16 %d and utf8 %d\n", aLength, strlen(text));
1882 +        DUMP_PRUNICHAR(aString, aLength)
1883 +        DUMP_PRUNICHAR(text, strlen(text))
1884 +        for (PRInt32 i = 0; i < aNumBreaks; ++i) {
1885 +            printf("  break %d utf16 %d utf8 %d\n", i, aBreaks[i], utf8Breaks[i]);
1886 +        }
1887 +    }
1888 +#endif
1889 +
1890 +    // We'll use curBreak to indicate which of the breaks end up being
1891 +    // used for the break point for this line.
1892 +    curBreak = 0;
1893 +    rv = GetTextDimensionsInternal(text, strlen(text), aAvailWidth, utf8Breaks,
1894 +                                   aNumBreaks, aDimensions, aNumCharsFit,
1895 +                                   aLastWordDimensions);
1896 +
1897 +    // Figure out which of the breaks we ended up using to convert
1898 +    // back to utf16 - start from the end.
1899 +    for (PRInt32 i = aNumBreaks - 1; i >= 0; --i) {
1900 +        if (utf8Breaks[i] == aNumCharsFit) {
1901 +            //      if (aNumCharsFit != aBreaks[i])
1902 +            //                printf("Fixing utf8 -> utf16 %d -> %d\n", aNumCharsFit, aBreaks[i]);
1903 +            aNumCharsFit = aBreaks[i];
1904 +            break;
1905 +        }
1906 +    }
1907 +
1908 + loser:
1909 +    if (text)
1910 +        g_free(text);
1911 +
1912 +    delete[] utf8Breaks;
1913 +
1914 +    return rv;
1915 +}
1916 +
1917 +typedef struct _nsPSPangoRenderer        nsPSPangoRenderer;
1918 +typedef struct _nsPSPangoRendererClass   nsPSPangoRendererClass;
1919 +
1920 +struct _nsPSPangoRenderer
1921 +{
1922 +  PangoRenderer parent_instance;
1923 +  nsRenderingContextPS *psContext;
1924 +  nsFontMetricsPSPango *psPangoFontMetrics;
1925 +  float zoom;
1926 +};
1927 +
1928 +struct _nsPSPangoRendererClass
1929 +{
1930 +  PangoRendererClass parent_class;
1931 +};
1932 +
1933 +#define _PS_TYPE_PANGO_RENDERER            (_ps_pango_renderer_get_type())
1934 +#define _PS_PANGO_RENDERER(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRenderer))
1935 +#define _PS_IS_PANGO_RENDERER(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), _PS_TYPE_PANGO_RENDERER))
1936 +#define _PS_PANGO_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRendererClass))
1937 +#define _PS_IS_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), _PS_TYPE_PANGO_RENDERER))
1938 +#define _PS_PANGO_RENDERER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRendererClass))
1939 +
1940 +G_DEFINE_TYPE (_nsPSPangoRenderer, _ps_pango_renderer, PANGO_TYPE_RENDERER)
1941 +
1942 +static PangoRenderer *
1943 +get_renderer (void)
1944 +{
1945 +  static PangoRenderer               *renderer = NULL;
1946 +
1947 +  if (!renderer)
1948 +    renderer = (PangoRenderer *) g_object_new (_PS_TYPE_PANGO_RENDERER, NULL);
1949 +
1950 +  return renderer;
1951 +}
1952 +
1953 +static void
1954 +_ps_pango_renderer_draw_glyphs (PangoRenderer    *renderer,
1955 +                               PangoFont        *font,
1956 +                               PangoGlyphString *glyphs,
1957 +                               int               x,
1958 +                               int               y);
1959 +
1960 +static void
1961 +_ps_pango_renderer_class_init (nsPSPangoRendererClass *klass)
1962 +{
1963 +  PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
1964 +  
1965 +  renderer_class->draw_glyphs = _ps_pango_renderer_draw_glyphs;
1966 +}
1967 +
1968 +static void
1969 +_ps_pango_renderer_init (nsPSPangoRenderer *renderer)
1970 +{
1971 +}
1972 +
1973 +class nsPangoType1Generator : public nsPSFontGenerator {
1974 +public:
1975 +  nsPangoType1Generator();
1976 +  ~nsPangoType1Generator();
1977 +  nsresult Init(PangoFont *aFont);
1978 +  void  GeneratePSFont(FILE* aFile);
1979 +
1980 +protected:
1981 +  PangoFont *mFont;
1982 +};
1983 +
1984 +nsPangoType1Generator::nsPangoType1Generator()
1985 +{
1986 +}
1987 +
1988 +nsresult
1989 +nsPangoType1Generator::Init(PangoFont *aFont)
1990 +{
1991 +  NS_ENSURE_TRUE(aFont, NS_ERROR_FAILURE);
1992 +  mFont = aFont;
1993 +  g_object_ref (mFont);
1994 +  return NS_OK;
1995 +}
1996 +
1997 +nsPangoType1Generator::~nsPangoType1Generator()
1998 +{
1999 +  g_object_unref (mFont);
2000 +  mFont = nsnull;
2001 +}
2002 +
2003 +void nsPangoType1Generator::GeneratePSFont(FILE* aFile)
2004 +{
2005 +  FT_Face face = pango_fc_font_lock_face ((PangoFcFont *) mFont);
2006 +
2007 +  if (face == nsnull)
2008 +    return;
2009 +
2010 +  int wmode = 0;
2011 +  if (mGlyphSubset->Count())
2012 +    FT2SubsetToType1FontSet(face, mGlyphSubset, wmode, aFile);
2013 +
2014 +  pango_fc_font_unlock_face ((PangoFcFont *) mFont);
2015 +}
2016 +
2017 +typedef struct
2018 +{
2019 +  nsCString    *FontNameBase;
2020 +  nsCStringKey *key;
2021 +  int           font_size;
2022 +} PSPangoFontData;
2023 +
2024 +static void
2025 +ps_pango_font_data_destroy (PSPangoFontData *data)
2026 +{
2027 +  delete data->key;
2028 +  delete data->FontNameBase;
2029 +  g_free (data);
2030 +}
2031 +
2032 +static void
2033 +flattenName(nsCString& aString)
2034 +{
2035 +  nsCString::iterator start, end;
2036 +  aString.BeginWriting(start);
2037 +  aString.EndWriting(end);
2038 +  while(start != end) {
2039 +    if (*start == ' ')
2040 +      *start= '_';
2041 +    else if (*start == '(')
2042 +      *start = '_';
2043 +    else if (*start == ')')
2044 +      *start = '_';
2045 +    ++start;
2046 +  }
2047 +}
2048 +
2049 +static void
2050 +_ps_pango_renderer_draw_glyphs (PangoRenderer    *renderer,
2051 +                               PangoFont        *font,
2052 +                               PangoGlyphString *glyphs,
2053 +                               int               x,
2054 +                               int               y)
2055 +{
2056 +  if (!glyphs->num_glyphs)
2057 +    return;
2058 +
2059 +  static GQuark data_quark = 0;
2060 +  if (!data_quark)
2061 +    data_quark = g_quark_from_static_string ("ps-pango-font-data");
2062 +
2063 +  PSPangoFontData *data;
2064 +  if (!(data = (PSPangoFontData *) g_object_get_qdata (G_OBJECT (font), data_quark)))
2065 +    {
2066 +      data = g_new (PSPangoFontData, 1);
2067 +
2068 +      FT_Face face = pango_fc_font_lock_face ((PangoFcFont *) font);
2069 +      if (face == nsnull)
2070 +        return;
2071 +      int wmode = 0;
2072 +      data->FontNameBase = new nsCString ();
2073 +      if (NS_FAILED(FT2ToType1FontName(face, wmode, *data->FontNameBase))) {
2074 +        g_free (data);
2075 +        pango_fc_font_unlock_face ((PangoFcFont *) font);
2076 +        return;
2077 +      }
2078 +      pango_fc_font_unlock_face ((PangoFcFont *) font);
2079 +
2080 +      PangoFontDescription *desc = pango_font_describe (font);
2081 +      data->font_size = pango_font_description_get_size (desc);
2082 +      pango_font_description_free (desc);
2083 +
2084 +      data->key = new nsCStringKey (*data->FontNameBase);
2085 +
2086 +      g_object_set_qdata_full (G_OBJECT (font), data_quark, data, (GDestroyNotify) ps_pango_font_data_destroy);
2087 +    }
2088 +
2089 +  nsPSPangoRenderer *ps_renderer = (nsPSPangoRenderer *)renderer;
2090 +  nsRenderingContextPS *aContext = ps_renderer->psContext;
2091 +  nsFontMetricsPSPango *metrics = ps_renderer->psPangoFontMetrics;
2092 +  nsDeviceContextPS* dc = NS_REINTERPRET_CAST (nsDeviceContextPS*, metrics->GetDeviceContext());
2093 +  nsPostScriptObj* psObj = aContext->GetPostScriptObj();
2094 +  nsHashtable *psFGList = dc->GetPSFontGeneratorList();
2095 +  g_return_if_fail (psFGList);
2096 +  nsPSFontGenerator* psFontGen = (nsPSFontGenerator*) psFGList->Get(data->key);
2097 +  if (!psFontGen) {
2098 +    nsresult rv;
2099 +    psFontGen = new nsPangoType1Generator;
2100 +    g_return_if_fail (psFontGen);
2101 +    rv = ((nsPangoType1Generator*)psFontGen)->Init(font);
2102 +    if (NS_FAILED(rv)) {
2103 +      delete psFontGen;
2104 +      return;
2105 +    }
2106 +    psFGList->Put(data->key, (void *) psFontGen);
2107 +  }
2108 +  nscoord font_size = NSToCoordRound (ps_renderer->zoom * data->font_size / PANGO_SCALE);
2109 +
2110 +  g_return_if_fail (aContext);
2111 +  g_return_if_fail (psObj);
2112 +
2113 +  nscoord aX = NSToCoordRound(ps_renderer->zoom * x / PANGO_SCALE);
2114 +  nscoord aY = NSToCoordRound(ps_renderer->zoom * y / PANGO_SCALE);
2115 +  psObj->moveto(aX, aY);
2116 +
2117 +  PRInt32 currSubFont, prevSubFont = -1;
2118 +  PRUint32 i;
2119 +  PangoGlyphString gl;
2120 +
2121 +  gl.glyphs = glyphs->glyphs;
2122 +  gl.num_glyphs = 0;
2123 +  for (i = 0; i < glyphs->num_glyphs; ++i) {
2124 +    currSubFont = psFontGen->AddToGlyphSubset(glyphs->glyphs[i].glyph >= 0x00ffffff ? 0 : glyphs->glyphs[i].glyph);
2125 +    if (prevSubFont != currSubFont) {
2126 +      if (prevSubFont != -1)
2127 +        psObj->show(&gl, ps_renderer->zoom,  psFontGen, prevSubFont);
2128 +
2129 +
2130 +      psObj->setfont(*data->FontNameBase, (PRUint32) font_size, currSubFont);
2131 +      prevSubFont = currSubFont;
2132 +      gl.glyphs = glyphs->glyphs + i;
2133 +      gl.num_glyphs = 0;
2134 +    }
2135 +
2136 +    gl.num_glyphs++;
2137 +  }
2138 +
2139 +  if (prevSubFont != -1)
2140 +    psObj->show(&gl, ps_renderer->zoom, psFontGen, prevSubFont);
2141 +}
2142 +
2143 +static void
2144 +draw_layout_line (int x, int y, PangoLayoutLine *line, nsFontMetricsPSPango *aPSPangoFontMetrics, nsRenderingContextPS *aContext)
2145 +{
2146 +  PangoRenderer *renderer = get_renderer ();
2147 +  nsPSPangoRenderer *ps_renderer = (nsPSPangoRenderer *)renderer;
2148 +  ps_renderer->psContext = aContext;
2149 +  ps_renderer->psPangoFontMetrics = aPSPangoFontMetrics;
2150 +  nsDeviceContextPS* dc = NS_REINTERPRET_CAST (nsDeviceContextPS*, aPSPangoFontMetrics->GetDeviceContext());
2151 +  ps_renderer->zoom = dc->DevUnitsToAppUnits();
2152 +
2153 +  pango_renderer_draw_layout_line (renderer, line,
2154 +                                   NSToCoordRound (x * PANGO_SCALE / ps_renderer->zoom),
2155 +                                   NSToCoordRound (y * PANGO_SCALE / ps_renderer->zoom));
2156 +}
2157 +
2158 +nsresult
2159 +nsFontMetricsPSPango::DrawString(const char *aString, PRUint32 aLength,
2160 +                               nscoord aX, nscoord aY,
2161 +                               const nscoord* aSpacing,
2162 +                               nsRenderingContextPS *aContext)
2163 +{
2164 +    PangoLayout *layout = pango_layout_new(mPangoContext);
2165 +
2166 +    pango_layout_set_text(layout, aString, aLength);
2167 +    FixupSpaceWidths(layout, aString);
2168 +
2169 +    int x = aX;
2170 +    int y = aY;
2171 +
2172 +    aContext->GetTranMatrix()->TransformCoord(&x, &y);
2173 +
2174 +    PangoLayoutLine *line;
2175 +    if (pango_layout_get_line_count(layout) != 1) {
2176 +        printf("Warning: more than one line!\n");
2177 +    }
2178 +    line = pango_layout_get_line(layout, 0);
2179 +
2180 +    if (aSpacing && *aSpacing) {
2181 +        DrawStringSlowly(aString, NULL, aLength, x, y, line, aSpacing, aContext);
2182 +    }
2183 +    else {
2184 +       draw_layout_line (x, y, line, this, aContext);
2185 +    }
2186 +
2187 +    g_object_unref(layout);
2188 +
2189 +    return NS_OK;
2190 +}
2191 +
2192 +nsresult
2193 +nsFontMetricsPSPango::DrawString(const PRUnichar* aString, PRUint32 aLength,
2194 +                               nscoord aX, nscoord aY,
2195 +                               PRInt32 aFontID,
2196 +                               const nscoord* aSpacing,
2197 +                               nsRenderingContextPS *aContext)
2198 +{
2199 +    nsresult rv = NS_OK;
2200 +    int x = aX;
2201 +    int y = aY;
2202 +
2203 +    PangoLayout *layout = pango_layout_new(mPangoContext);
2204 +
2205 +    gchar *text = g_utf16_to_utf8(aString, aLength,
2206 +                                  NULL, NULL, NULL);
2207 +    if (!text) {
2208 +#ifdef DEBUG
2209 +        NS_WARNING("nsFontMetricsPSPango::DrawString invalid unicode to follow");
2210 +        DUMP_PRUNICHAR(aString, aLength)
2211 +#endif
2212 +        rv = NS_ERROR_FAILURE;
2213 +        goto loser;
2214 +    }
2215 +
2216 +    pango_layout_set_text(layout, text, strlen(text));
2217 +    FixupSpaceWidths(layout, text);
2218 +
2219 +    aContext->GetTranMatrix()->TransformCoord(&x, &y);
2220 +
2221 +    PangoLayoutLine *line;
2222 +    if (pango_layout_get_line_count(layout) != 1) {
2223 +        printf("Warning: more than one line!\n");
2224 +    }
2225 +    line = pango_layout_get_line(layout, 0);
2226 +
2227 +    if (aSpacing && *aSpacing) {
2228 +        DrawStringSlowly(text, aString, aLength, x, y, line, aSpacing, aContext);
2229 +    }
2230 +    else {
2231 +       draw_layout_line (x, y, line, this, aContext);
2232 +    }
2233 +
2234 + loser:
2235 +
2236 +    g_free(text);
2237 +    g_object_unref(layout);
2238 +
2239 +    return rv;
2240 +}
2241 +
2242 +#ifdef MOZ_MATHML
2243 +nsresult
2244 +nsFontMetricsPSPango::GetBoundingMetrics(const char *aString, PRUint32 aLength,
2245 +                                       nsBoundingMetrics &aBoundingMetrics)
2246 +{
2247 +    printf("GetBoundingMetrics (char *)\n");
2248 +    return NS_ERROR_FAILURE;
2249 +}
2250 +
2251 +nsresult
2252 +nsFontMetricsPSPango::GetBoundingMetrics(const PRUnichar *aString,
2253 +                                       PRUint32 aLength,
2254 +                                       nsBoundingMetrics &aBoundingMetrics,
2255 +                                       PRInt32 *aFontID)
2256 +{
2257 +    nsresult rv = NS_OK;
2258 +    PangoLayout *layout = pango_layout_new(mPangoContext);
2259 +
2260 +    gchar *text = g_utf16_to_utf8(aString, aLength,
2261 +                                  NULL, NULL, NULL);
2262 +
2263 +    if (!text) {
2264 +#ifdef DEBUG
2265 +        NS_WARNING("nsFontMetricsPSPango::GetBoundingMetrics invalid unicode to follow");
2266 +        DUMP_PRUNICHAR(aString, aLength)
2267 +#endif
2268 +        aBoundingMetrics.leftBearing = 0;
2269 +        aBoundingMetrics.rightBearing = 0;
2270 +        aBoundingMetrics.width = 0;
2271 +        aBoundingMetrics.ascent = 0;
2272 +        aBoundingMetrics.descent = 0;
2273 +
2274 +        rv = NS_ERROR_FAILURE;
2275 +        goto loser;
2276 +    }
2277 +
2278 +    pango_layout_set_text(layout, text, -1);
2279 +    FixupSpaceWidths(layout, text);
2280 +
2281 +    PangoLayoutLine *line;
2282 +    if (pango_layout_get_line_count(layout) != 1) {
2283 +        printf("Warning: more than one line!\n");
2284 +    }
2285 +    line = pango_layout_get_line(layout, 0);
2286 +
2287 +    // Get the ink and logical extents
2288 +    PangoRectangle ink, logical;
2289 +    pango_layout_line_get_extents(line, &ink, &logical);
2290 +
2291 +    float P2T;
2292 +    P2T = mDeviceContext->DevUnitsToAppUnits();
2293 +
2294 +    aBoundingMetrics.leftBearing  = NSToCoordRound(PANGO_LBEARING(ink) * P2T / PANGO_SCALE);
2295 +    aBoundingMetrics.rightBearing = NSToCoordRound(PANGO_RBEARING(ink) * P2T / PANGO_SCALE);
2296 +    aBoundingMetrics.ascent       = NSToCoordRound(PANGO_ASCENT(ink)   * P2T / PANGO_SCALE);
2297 +    aBoundingMetrics.descent      = NSToCoordRound(PANGO_DESCENT(ink)  * P2T / PANGO_SCALE);
2298 +    aBoundingMetrics.width        = NSToCoordRound(logical.width       * P2T / PANGO_SCALE);
2299 +
2300 + loser:
2301 +    g_free(text);
2302 +    g_object_unref(layout);
2303 +
2304 +    return rv;
2305 +}
2306 +
2307 +#endif /* MOZ_MATHML */
2308 +
2309 +nsresult
2310 +nsFontMetricsPSPango::SetRightToLeftText(PRBool aIsRTL)
2311 +{
2312 +    if (aIsRTL) {
2313 +        if (!mRTLPangoContext) {
2314 +            mRTLPangoContext = get_context();
2315 +            pango_context_set_base_dir(mRTLPangoContext, PANGO_DIRECTION_RTL);
2316 +
2317 +            pango_context_set_language(mRTLPangoContext, GetPangoLanguage(mLangGroup));
2318 +            pango_context_set_font_description(mRTLPangoContext, mPangoFontDesc);
2319 +        }
2320 +        mPangoContext = mRTLPangoContext;
2321 +    }
2322 +    else {
2323 +        mPangoContext = mLTRPangoContext;
2324 +    }
2325 +
2326 +    mIsRTL = aIsRTL;
2327 +    return NS_OK;
2328 +}
2329 +
2330 +nsresult
2331 +nsFontMetricsPSPango::GetClusterInfo(const PRUnichar *aText,
2332 +                                   PRUint32 aLength,
2333 +                                   PRUint8 *aClusterStarts)
2334 +{
2335 +    nsresult rv = NS_OK;
2336 +    PangoLogAttr *attrs = NULL;
2337 +    gint n_attrs = 0;
2338 +    PangoLayout *layout = pango_layout_new(mPangoContext);
2339 +    
2340 +    // Convert the incoming UTF-16 to UTF-8
2341 +    gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
2342 +
2343 +    if (!text) {
2344 +#ifdef DEBUG
2345 +        NS_WARNING("nsFontMetricsPSPango::GetWidth invalid unicode to follow");
2346 +        DUMP_PRUNICHAR(aText, aLength)
2347 +#endif
2348 +        rv = NS_ERROR_FAILURE;
2349 +        goto loser;
2350 +    }
2351 +
2352 +    // Set up the pango layout
2353 +    pango_layout_set_text(layout, text, strlen(text));
2354 +    FixupSpaceWidths(layout, text);
2355 +
2356 +    // Convert back to UTF-16 while filling in the cluster info
2357 +    // structure.
2358 +    pango_layout_get_log_attrs(layout, &attrs, &n_attrs);
2359 +
2360 +    for (PRUint32 pos = 0; pos < aLength; pos++) {
2361 +        if (IS_HIGH_SURROGATE(aText[pos])) {
2362 +            aClusterStarts[pos] = 1;
2363 +            pos++;
2364 +        }
2365 +        else {
2366 +            aClusterStarts[pos] = attrs[pos].is_cursor_position;
2367 +        }
2368 +    }
2369 +
2370 + loser:
2371 +    if (attrs)
2372 +        g_free(attrs);
2373 +    if (text)
2374 +        g_free(text);
2375 +    if (layout)
2376 +        g_object_unref(layout);
2377 +
2378 +    return rv;
2379 +}
2380 +
2381 +PRInt32
2382 +nsFontMetricsPSPango::GetPosition(const PRUnichar *aText, PRUint32 aLength,
2383 +                                nsPoint aPt)
2384 +{
2385 +    int trailing = 0;
2386 +    int inx = 0;
2387 +    const gchar *curChar;
2388 +    PRInt32 retval = 0;
2389 +
2390 +    float f = mDeviceContext->AppUnitsToDevUnits();
2391 +    
2392 +    PangoLayout *layout = pango_layout_new(mPangoContext);
2393 +    PRUint32 localX = (PRUint32)(aPt.x * PANGO_SCALE * f);
2394 +    PRUint32 localY = (PRUint32)(aPt.y * PANGO_SCALE * f);
2395 +
2396 +    // Convert the incoming UTF-16 to UTF-8
2397 +    gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
2398 +
2399 +    if (!text) {
2400 +#ifdef DEBUG
2401 +        NS_WARNING("nsFontMetricsPSPango::GetWidth invalid unicode to follow");
2402 +        DUMP_PRUNICHAR(aText, aLength)
2403 +#endif
2404 +        retval = -1;
2405 +        goto loser;
2406 +    }
2407 +
2408 +    // Set up the pango layout
2409 +    pango_layout_set_text(layout, text, strlen(text));
2410 +    FixupSpaceWidths(layout, text);
2411 +    
2412 +    pango_layout_xy_to_index(layout, localX, localY,
2413 +                             &inx, &trailing);
2414 +
2415 +    // Convert the index back to the utf-16 index
2416 +    curChar = text;
2417 +
2418 +    for (PRUint32 curOffset=0; curOffset < aLength;
2419 +         curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
2420 +
2421 +        // Check for a match before checking for a surrogate pair
2422 +        if (curChar - text == inx) {
2423 +            retval = curOffset;
2424 +            break;
2425 +        }
2426 +
2427 +        if (IS_HIGH_SURROGATE(aText[curOffset]))
2428 +            curOffset++;
2429 +    }
2430 +
2431 +    // If there was a trailing result, advance the index pointer the
2432 +    // number of characters equal to the trailing result.
2433 +    while (trailing) {
2434 +        retval++;
2435 +        // Yes, this can make aInx > length to indicate the end of the
2436 +        // string.
2437 +        if (retval < (PRInt32)aLength && IS_HIGH_SURROGATE(aText[retval]))
2438 +            retval++;
2439 +        trailing--;
2440 +    }
2441 +
2442 + loser:
2443 +    if (text)
2444 +        g_free(text);
2445 +    if (layout)
2446 +        g_object_unref(layout);
2447 +
2448 +    return retval;
2449 +}
2450 +
2451 +nsresult
2452 +nsFontMetricsPSPango::GetRangeWidth(const PRUnichar *aText,
2453 +                                  PRUint32 aLength,
2454 +                                  PRUint32 aStart,
2455 +                                  PRUint32 aEnd,
2456 +                                  PRUint32 &aWidth)
2457 +{
2458 +    nsresult rv = NS_OK;
2459 +    PRUint32 utf8Start = 0;
2460 +    PRUint32 utf8End = 0;
2461 +
2462 +    aWidth = 0;
2463 +
2464 +    // Convert the incoming UTF-16 to UTF-8
2465 +    gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
2466 +    gchar *curChar = text;
2467 +
2468 +    if (!text) {
2469 +#ifdef DEBUG
2470 +        NS_WARNING("nsFontMetricsPSPango::GetWidth invalid unicode to follow");
2471 +        DUMP_PRUNICHAR(aText, aLength)
2472 +#endif
2473 +        rv = NS_ERROR_FAILURE;
2474 +        goto loser;
2475 +    }
2476 +
2477 +    // Convert the utf16 offsets into utf8 offsets
2478 +    for (PRUint32 curOffset = 0; curOffset < aLength;
2479 +         curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
2480 +
2481 +        if (curOffset == aStart)
2482 +            utf8Start = curChar - text;
2483 +
2484 +        if (curOffset == aEnd)
2485 +            utf8End = curChar - text;
2486 +        
2487 +        if (IS_HIGH_SURROGATE(aText[curOffset]))
2488 +            curOffset++;
2489 +    }
2490 +
2491 +    // Special case where the end index is the same as the length
2492 +    if (aLength == aEnd)
2493 +        utf8End = strlen(text);
2494 +
2495 +    rv = GetRangeWidth(text, strlen(text), utf8Start, utf8End, aWidth);
2496 +
2497 + loser:
2498 +    if (text)
2499 +        g_free(text);
2500 +
2501 +    return rv;
2502 +}
2503 +
2504 +nsresult
2505 +nsFontMetricsPSPango::GetRangeWidth(const char *aText,
2506 +                                  PRUint32 aLength,
2507 +                                  PRUint32 aStart,
2508 +                                  PRUint32 aEnd,
2509 +                                  PRUint32 &aWidth)
2510 +{
2511 +    nsresult rv = NS_OK;
2512 +    int *ranges = NULL;
2513 +    int n_ranges = 0;
2514 +    float f;
2515 +
2516 +    aWidth = 0;
2517 +
2518 +    PangoLayout *layout = pango_layout_new(mPangoContext);
2519 +
2520 +    if (!aText) {
2521 +        rv = NS_ERROR_FAILURE;
2522 +        goto loser;
2523 +    }
2524 +
2525 +    pango_layout_set_text(layout, aText, aLength);
2526 +    FixupSpaceWidths(layout, aText);
2527 +
2528 +    PangoLayoutLine *line;
2529 +    if (pango_layout_get_line_count(layout) != 1) {
2530 +        printf("Warning: more than one line!\n");
2531 +    }
2532 +    line = pango_layout_get_line(layout, 0);
2533 +
2534 +    pango_layout_line_get_x_ranges(line, aStart, aEnd, &ranges, &n_ranges);
2535 +
2536 +    aWidth = (ranges[((n_ranges - 1) * 2) + 1] - ranges[0]);
2537 +
2538 +    f = mDeviceContext-> DevUnitsToAppUnits();
2539 +    aWidth = nscoord(aWidth * f / PANGO_SCALE);
2540 +
2541 + loser:
2542 +    if (ranges)
2543 +        g_free(ranges);
2544 +    if (layout)
2545 +        g_object_unref(layout);
2546 +
2547 +    return rv;
2548 +}
2549 +
2550 +PRUint32
2551 +nsFontMetricsPSPango::GetHints(void)
2552 +{
2553 +    return (NS_RENDERING_HINT_BIDI_REORDERING |
2554 +            NS_RENDERING_HINT_ARABIC_SHAPING | 
2555 +            NS_RENDERING_HINT_FAST_MEASURE |
2556 +            NS_RENDERING_HINT_REORDER_SPACED_TEXT |
2557 +            NS_RENDERING_HINT_TEXT_CLUSTERS);
2558 +}
2559 +
2560 +/* static */
2561 +nsresult
2562 +nsFontMetricsPSPango::FamilyExists(nsIDeviceContext *aDevice,
2563 +                                 const nsString &aName)
2564 +{
2565 +    // fontconfig family name is always in UTF-8
2566 +    NS_ConvertUTF16toUTF8 name(aName);
2567 +
2568 +    nsresult rv = NS_ERROR_FAILURE;
2569 +    PangoContext *context = get_context();
2570 +    PangoFontFamily **familyList;
2571 +    int n;
2572 +
2573 +    pango_context_list_families(context, &familyList, &n);
2574 +
2575 +    for (int i=0; i < n; i++) {
2576 +        const char *tmpname = pango_font_family_get_name(familyList[i]);
2577 +        if (!Compare(nsDependentCString(tmpname), name,
2578 +                     nsCaseInsensitiveCStringComparator())) {
2579 +            rv = NS_OK;
2580 +            break;
2581 +        }
2582 +    }
2583 +
2584 +    g_free(familyList);
2585 +    g_object_unref(context);
2586 +
2587 +    return rv;
2588 +}
2589 +
2590 +// Private Methods
2591 +
2592 +nsresult
2593 +nsFontMetricsPSPango::RealizeFont(void)
2594 +{
2595 +    nsCString familyList;
2596 +    // Create and fill out the font description.
2597 +    mPangoFontDesc = pango_font_description_new();
2598 +
2599 +    // Add CSS names - walk the list of fonts, adding the generic as
2600 +    // the last font
2601 +    for (int i=0; i < mFontList.Count(); ++i) {
2602 +        // if this was a generic name, break out of the loop since we
2603 +        // don't want to add it to the pattern yet
2604 +        if (mFontIsGeneric[i])
2605 +            break;;
2606 +
2607 +        nsCString *familyName = mFontList.CStringAt(i);
2608 +        familyList.Append(familyName->get());
2609 +        familyList.Append(',');
2610 +    }
2611 +
2612 +    // If there's a generic add a pref for the generic if there's one
2613 +    // set.
2614 +    if (mGenericFont && !mFont.systemFont) {
2615 +        nsCString name;
2616 +        name += "font.name.";
2617 +        name += mGenericFont->get();
2618 +        name += ".";
2619 +
2620 +        nsString langGroup;
2621 +        mLangGroup->ToString(langGroup);
2622 +
2623 +        name.AppendWithConversion(langGroup);
2624 +
2625 +        nsCOMPtr<nsIPref> pref;
2626 +        pref = do_GetService(NS_PREF_CONTRACTID);
2627 +        if (pref) {
2628 +            nsresult rv;
2629 +            nsXPIDLCString value;
2630 +            rv = pref->GetCharPref(name.get(), getter_Copies(value));
2631 +
2632 +            // we ignore prefs that have three hypens since they are X
2633 +            // style prefs.
2634 +            if (NS_FFRECountHyphens(value) < 3) {
2635 +                nsCString tmpstr;
2636 +                tmpstr.Append(value);
2637 +
2638 +                familyList.Append(tmpstr);
2639 +                familyList.Append(',');
2640 +            }
2641 +        }
2642 +    }
2643 +
2644 +    // Add the generic if there is one.
2645 +    if (mGenericFont && !mFont.systemFont) {
2646 +        familyList.Append(mGenericFont->get());
2647 +        familyList.Append(',');
2648 +    }
2649 +
2650 +    // Set the family
2651 +    pango_font_description_set_family(mPangoFontDesc,
2652 +                                      familyList.get());
2653 +
2654 +    // Set the point size
2655 +    pango_font_description_set_size(mPangoFontDesc,
2656 +                                    (gint)(mPointSize * PANGO_SCALE));
2657 +
2658 +    // Set the style
2659 +    pango_font_description_set_style(mPangoFontDesc,
2660 +                                     CalculateStyle(mFont.style));
2661 +
2662 +    // Set the weight
2663 +    pango_font_description_set_weight(mPangoFontDesc,
2664 +                                      CalculateWeight(mFont.weight));
2665 +
2666 +    // Now that we have the font description set up, create the
2667 +    // context.
2668 +    mLTRPangoContext = get_context();
2669 +    mPangoContext = mLTRPangoContext;
2670 +
2671 +    // Make sure to set the base direction to LTR - if layout needs to
2672 +    // render RTL text it will use ::SetRightToLeftText()
2673 +    pango_context_set_base_dir(mPangoContext, PANGO_DIRECTION_LTR);
2674 +
2675 +    // Set the pango language now that we have a context
2676 +    pango_context_set_language(mPangoContext, GetPangoLanguage(mLangGroup));
2677 +
2678 +    // And attach the font description to this context
2679 +    pango_context_set_font_description(mPangoContext, mPangoFontDesc);
2680 +
2681 +    return NS_OK;
2682 +}
2683 +
2684 +/* static */
2685 +PRBool
2686 +nsFontMetricsPSPango::EnumFontCallback(const nsString &aFamily,
2687 +                                     PRBool aIsGeneric, void *aData)
2688 +{
2689 +    NS_ConvertUTF16toUTF8 name(aFamily);
2690 +
2691 +    // The newest fontconfig does the full Unicode case folding so that 
2692 +    // we're being lazy here by calling |ToLowerCase| after converting
2693 +    // to UTF-8  assuming that in virtually all cases, we just have to
2694 +    // fold [A-Z].  (bug 223653). 
2695 +    ToLowerCase(name);
2696 +    nsFontMetricsPSPango *metrics = (nsFontMetricsPSPango *)aData;
2697 +    metrics->mFontList.AppendCString(name);
2698 +    metrics->mFontIsGeneric.AppendElement((void *)aIsGeneric);
2699 +    if (aIsGeneric) {
2700 +        metrics->mGenericFont = 
2701 +            metrics->mFontList.CStringAt(metrics->mFontList.Count() - 1);
2702 +        return PR_FALSE; // stop processing
2703 +    }
2704 +
2705 +    return PR_TRUE; // keep processing
2706 +}
2707 +
2708 +/*
2709 + * This is only used when there's per-character spacing happening.
2710 + * Well, really it can be either line or character spacing but it's
2711 + * just turtles all the way down!
2712 + */
2713 +
2714 +void
2715 +nsFontMetricsPSPango::DrawStringSlowly(const gchar *aText,
2716 +                                     const PRUnichar *aOrigString,
2717 +                                     PRUint32 aLength,
2718 +                                     gint aX, gint aY,
2719 +                                     PangoLayoutLine *aLine,
2720 +                                     const nscoord *aSpacing,
2721 +                                     nsRenderingContextPS *aContext)
2722 +{
2723 +    float app2dev;
2724 +    app2dev = mDeviceContext->AppUnitsToDevUnits();
2725 +    gint offset = 0;
2726 +
2727 +    /*
2728 +     * We walk the list of glyphs returned in each layout run,
2729 +     * matching up the glyphs with the characters in the source text.
2730 +     * We use the aSpacing argument to figure out where to place those
2731 +     * glyphs.  It's important to note that since the string we're
2732 +     * working with is in UTF-8 while the spacing argument assumes
2733 +     * that offset will be part of the UTF-16 string.  Logical
2734 +     * attributes in pango are in byte offsets in the UTF-8 string, so
2735 +     * we need to store the offsets based on the UTF-8 string.
2736 +     */
2737 +    nscoord *utf8spacing = new nscoord[strlen(aText)];
2738 +
2739 +    if (aOrigString) {
2740 +        const gchar *curChar = aText;
2741 +        bzero(utf8spacing, sizeof(nscoord) * strlen(aText));
2742 +
2743 +        // Covert the utf16 spacing offsets to utf8 spacing offsets
2744 +        for (PRUint32 curOffset=0; curOffset < aLength;
2745 +             curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
2746 +            utf8spacing[curChar - aText] = aSpacing[curOffset];
2747 +
2748 +            if (IS_HIGH_SURROGATE(aOrigString[curOffset]))
2749 +                curOffset++;
2750 +        }
2751 +    }
2752 +    else {
2753 +        memcpy(utf8spacing, aSpacing, (sizeof(nscoord *) * aLength));
2754 +    }
2755 +
2756 +    gint curRun = 0;
2757 +
2758 +    for (GSList *tmpList = aLine->runs; tmpList && tmpList->data;
2759 +         tmpList = tmpList->next, curRun++) {
2760 +        PangoLayoutRun *layoutRun = (PangoLayoutRun *)tmpList->data;
2761 +        gint tmpOffset = 0;
2762 +
2763 +        /*        printf("    Rendering run %d: \"%s\"\n", curRun,
2764 +                  &aText[layoutRun->item->offset]); */
2765 +
2766 +        for (gint i=0; i < layoutRun->glyphs->num_glyphs; i++) {
2767 +            /* printf("glyph %d offset %d orig width %d new width %d\n", i,
2768 +             *        layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset,
2769 +             *        layoutRun->glyphs->glyphs[i].geometry.width,
2770 +             *       (gint)(utf8spacing[layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset] * app2dev * PANGO_SCALE));
2771 +             */
2772 +            gint thisOffset = (gint)(utf8spacing[layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset]
2773 +                                     * app2dev * PANGO_SCALE);
2774 +            layoutRun->glyphs->glyphs[i].geometry.width = thisOffset;
2775 +            tmpOffset += thisOffset;
2776 +        }
2777 +
2778 +        /*        printf("    rendering at X coord %d\n", aX + offset); */
2779 +        offset += tmpOffset;
2780 +    }
2781 +
2782 +    draw_layout_line (aX, aY, aLine, this, aContext);
2783 +
2784 +    delete[] utf8spacing;
2785 +}
2786 +
2787 +nsresult
2788 +nsFontMetricsPSPango::GetTextDimensionsInternal(const gchar*        aString,
2789 +                                              PRInt32             aLength,
2790 +                                              PRInt32             aAvailWidth,
2791 +                                              PRInt32*            aBreaks,
2792 +                                              PRInt32             aNumBreaks,
2793 +                                              nsTextDimensions&   aDimensions,
2794 +                                              PRInt32&            aNumCharsFit,
2795 +                                              nsTextDimensions&   aLastWordDimensions)
2796 +{
2797 +    NS_PRECONDITION(aBreaks[aNumBreaks - 1] == aLength, "invalid break array");
2798 +
2799 +    // If we need to back up this state represents the last place
2800 +    // we could break. We can use this to avoid remeasuring text
2801 +    PRInt32 prevBreakState_BreakIndex = -1; // not known
2802 +                                            // (hasn't been computed)
2803 +    nscoord prevBreakState_Width = 0; // accumulated width to this point
2804 +
2805 +    // Initialize OUT parameters
2806 +    GetMaxAscent(aLastWordDimensions.ascent);
2807 +    GetMaxDescent(aLastWordDimensions.descent);
2808 +    aLastWordDimensions.width = -1;
2809 +    aNumCharsFit = 0;
2810 +
2811 +    // Iterate each character in the string and determine which font to use
2812 +    nscoord width = 0;
2813 +    PRInt32 start = 0;
2814 +    nscoord aveCharWidth;
2815 +    GetAveCharWidth(aveCharWidth);
2816 +
2817 +    while (start < aLength) {
2818 +        // Estimate how many characters will fit. Do that by
2819 +        // diving the available space by the average character
2820 +        // width. Make sure the estimated number of characters is
2821 +        // at least 1
2822 +        PRInt32 estimatedNumChars = 0;
2823 +
2824 +        if (aveCharWidth > 0)
2825 +            estimatedNumChars = (aAvailWidth - width) / aveCharWidth;
2826 +
2827 +        if (estimatedNumChars < 1)
2828 +            estimatedNumChars = 1;
2829 +
2830 +        // Find the nearest break offset
2831 +        PRInt32 estimatedBreakOffset = start + estimatedNumChars;
2832 +        PRInt32 breakIndex;
2833 +        nscoord numChars;
2834 +
2835 +        // Find the nearest place to break that is less than or equal to
2836 +        // the estimated break offset
2837 +        if (aLength <= estimatedBreakOffset) {
2838 +            // All the characters should fit
2839 +            numChars = aLength - start;
2840 +            breakIndex = aNumBreaks - 1;
2841 +        } 
2842 +        else {
2843 +            breakIndex = prevBreakState_BreakIndex;
2844 +            while (((breakIndex + 1) < aNumBreaks) &&
2845 +                   (aBreaks[breakIndex + 1] <= estimatedBreakOffset)) {
2846 +                ++breakIndex;
2847 +            }
2848 +
2849 +            if (breakIndex == prevBreakState_BreakIndex) {
2850 +                ++breakIndex; // make sure we advanced past the
2851 +                // previous break index
2852 +            }
2853 +
2854 +            numChars = aBreaks[breakIndex] - start;
2855 +        }
2856 +
2857 +        // Measure the text
2858 +        nscoord twWidth = 0;
2859 +        if ((1 == numChars) && (aString[start] == ' '))
2860 +            GetSpaceWidth(twWidth);
2861 +        else if (numChars > 0)
2862 +            GetWidth(&aString[start], numChars, twWidth);
2863 +
2864 +        // See if the text fits
2865 +        PRBool  textFits = (twWidth + width) <= aAvailWidth;
2866 +
2867 +        // If the text fits then update the width and the number of
2868 +        // characters that fit
2869 +        if (textFits) {
2870 +            aNumCharsFit += numChars;
2871 +            width += twWidth;
2872 +            start += numChars;
2873 +
2874 +            // This is a good spot to back up to if we need to so remember
2875 +            // this state
2876 +            prevBreakState_BreakIndex = breakIndex;
2877 +            prevBreakState_Width = width;
2878 +        }
2879 +        else {
2880 +            // See if we can just back up to the previous saved
2881 +            // state and not have to measure any text
2882 +            if (prevBreakState_BreakIndex > 0) {
2883 +                // If the previous break index is just before the
2884 +                // current break index then we can use it
2885 +                if (prevBreakState_BreakIndex == (breakIndex - 1)) {
2886 +                    aNumCharsFit = aBreaks[prevBreakState_BreakIndex];
2887 +                    width = prevBreakState_Width;
2888 +                    break;
2889 +                }
2890 +            }
2891 +
2892 +            // We can't just revert to the previous break state
2893 +            if (0 == breakIndex) {
2894 +                // There's no place to back up to, so even though
2895 +                // the text doesn't fit return it anyway
2896 +                aNumCharsFit += numChars;
2897 +                width += twWidth;
2898 +                break;
2899 +            }
2900 +
2901 +            // Repeatedly back up until we get to where the text
2902 +            // fits or we're all the way back to the first word
2903 +            width += twWidth;
2904 +            while ((breakIndex >= 1) && (width > aAvailWidth)) {
2905 +                twWidth = 0;
2906 +                start = aBreaks[breakIndex - 1];
2907 +                numChars = aBreaks[breakIndex] - start;
2908 +
2909 +                if ((1 == numChars) && (aString[start] == ' '))
2910 +                    GetSpaceWidth(twWidth);
2911 +                else if (numChars > 0)
2912 +                    GetWidth(&aString[start], numChars, twWidth);
2913 +                width -= twWidth;
2914 +                aNumCharsFit = start;
2915 +                breakIndex--;
2916 +            }
2917 +            break;
2918 +        }
2919 +    }
2920 +
2921 +    aDimensions.width = width;
2922 +    GetMaxAscent(aDimensions.ascent);
2923 +    GetMaxDescent(aDimensions.descent);
2924 +
2925 +    /*    printf("aDimensions %d %d %d aLastWordDimensions %d %d %d aNumCharsFit %d\n",
2926 +           aDimensions.width, aDimensions.ascent, aDimensions.descent,
2927 +           aLastWordDimensions.width, aLastWordDimensions.ascent, aLastWordDimensions.descent,
2928 +           aNumCharsFit); */
2929 +
2930 +    return NS_OK;
2931 +}
2932 +
2933 +void
2934 +nsFontMetricsPSPango::FixupSpaceWidths (PangoLayout *aLayout,
2935 +                                      const char *aString)
2936 +{
2937 +    PangoLayoutLine *line = pango_layout_get_line(aLayout, 0);
2938 +
2939 +    gint curRun = 0;
2940 +
2941 +    for (GSList *tmpList = line->runs; tmpList && tmpList->data;
2942 +         tmpList = tmpList->next, curRun++) {
2943 +        PangoLayoutRun *layoutRun = (PangoLayoutRun *)tmpList->data;
2944 +
2945 +        for (gint i=0; i < layoutRun->glyphs->num_glyphs; i++) {
2946 +            gint thisOffset = (gint)layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset;
2947 +            if (aString[thisOffset] == ' ')
2948 +                layoutRun->glyphs->glyphs[i].geometry.width = mPangoSpaceWidth;
2949 +        }
2950 +    }
2951 +}
2952 +
2953 +/* static */
2954 +PangoLanguage *
2955 +GetPangoLanguage(nsIAtom *aLangGroup)
2956 +{
2957 +    // Find the FC lang group for this lang group
2958 +    nsCAutoString cname;
2959 +    aLangGroup->ToUTF8String(cname);
2960 +
2961 +    // see if the lang group needs to be translated from mozilla's
2962 +    // internal mapping into fontconfig's
2963 +    const MozGtkLangGroup *langGroup;
2964 +    langGroup = NS_FindFCLangGroup(cname);
2965 +
2966 +    // if there's no lang group, just use the lang group as it was
2967 +    // passed to us
2968 +    //
2969 +    // we're casting away the const here for the strings - should be
2970 +    // safe.
2971 +    if (!langGroup)
2972 +        return pango_language_from_string(cname.get());
2973 +    else if (langGroup->Lang) 
2974 +        return pango_language_from_string((char *) langGroup->Lang);
2975 +
2976 +    return pango_language_from_string("en");
2977 +}
2978 +
2979 +/* static */
2980 +void
2981 +FreeGlobals(void)
2982 +{
2983 +}
2984 +
2985 +/* static */
2986 +PangoStyle
2987 +CalculateStyle(PRUint8 aStyle)
2988 +{
2989 +    switch(aStyle) {
2990 +    case NS_FONT_STYLE_ITALIC:
2991 +        return PANGO_STYLE_OBLIQUE;
2992 +        break;
2993 +    case NS_FONT_STYLE_OBLIQUE:
2994 +        return PANGO_STYLE_OBLIQUE;
2995 +        break;
2996 +    }
2997 +
2998 +    return PANGO_STYLE_NORMAL;
2999 +}
3000 +
3001 +/* static */
3002 +PangoWeight
3003 +CalculateWeight (PRUint16 aWeight)
3004 +{
3005 +    /*
3006 +     * weights come in two parts crammed into one
3007 +     * integer -- the "base" weight is weight / 100,
3008 +     * the rest of the value is the "offset" from that
3009 +     * weight -- the number of steps to move to adjust
3010 +     * the weight in the list of supported font weights,
3011 +     * this value can be negative or positive.
3012 +     */
3013 +    PRInt32 baseWeight = (aWeight + 50) / 100;
3014 +    PRInt32 offset = aWeight - baseWeight * 100;
3015 +
3016 +    /* clip weights to range 0 to 9 */
3017 +    if (baseWeight < 0)
3018 +        baseWeight = 0;
3019 +    if (baseWeight > 9)
3020 +        baseWeight = 9;
3021 +
3022 +    /* Map from weight value to fcWeights index */
3023 +    static int fcWeightLookup[10] = {
3024 +        0, 0, 0, 0, 1, 1, 2, 3, 3, 4,
3025 +    };
3026 +
3027 +    PRInt32 fcWeight = fcWeightLookup[baseWeight];
3028 +
3029 +    /*
3030 +     * adjust by the offset value, make sure we stay inside the 
3031 +     * fcWeights table
3032 +     */
3033 +    fcWeight += offset;
3034 +
3035 +    if (fcWeight < 0)
3036 +        fcWeight = 0;
3037 +    if (fcWeight > 4)
3038 +        fcWeight = 4;
3039 +
3040 +    /* Map to final PANGO_WEIGHT value */
3041 +    static int fcWeights[5] = {
3042 +        349,
3043 +        499,
3044 +        649,
3045 +        749,
3046 +        999
3047 +    };
3048 +
3049 +    return (PangoWeight)fcWeights[fcWeight];
3050 +}
3051 +
3052 +/* static */
3053 +nsresult
3054 +EnumFontsPango(nsIAtom* aLangGroup, const char* aGeneric,
3055 +               PRUint32* aCount, PRUnichar*** aResult)
3056 +{
3057 +    FcPattern   *pat = NULL;
3058 +    FcObjectSet *os  = NULL;
3059 +    FcFontSet   *fs  = NULL;
3060 +    nsresult     rv  = NS_ERROR_FAILURE;
3061 +
3062 +    PRUnichar **array = NULL;
3063 +    PRUint32    narray = 0;
3064 +    PRInt32     serif = 0, sansSerif = 0, monospace = 0, nGenerics;
3065 +
3066 +    *aCount = 0;
3067 +    *aResult = nsnull;
3068 +
3069 +    pat = FcPatternCreate();
3070 +    if (!pat)
3071 +        goto end;
3072 +
3073 +    os = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, NULL);
3074 +    if (!os)
3075 +        goto end;
3076 +
3077 +    // take the pattern and add the lang group to it
3078 +    if (aLangGroup)
3079 +        NS_AddLangGroup(pat, aLangGroup);
3080 +
3081 +    // get the font list
3082 +    fs = FcFontList(0, pat, os);
3083 +
3084 +    if (!fs)
3085 +        goto end;
3086 +
3087 +    if (!fs->nfont) {
3088 +        rv = NS_OK;
3089 +        goto end;
3090 +    }
3091 +
3092 +    // Fontconfig supports 3 generic fonts, "serif", "sans-serif", and
3093 +    // "monospace", slightly different from CSS's 5.
3094 +    if (!aGeneric)
3095 +        serif = sansSerif = monospace = 1;
3096 +    else if (!strcmp(aGeneric, "serif"))
3097 +        serif = 1;
3098 +    else if (!strcmp(aGeneric, "sans-serif"))
3099 +        sansSerif = 1;
3100 +    else if (!strcmp(aGeneric, "monospace"))
3101 +        monospace = 1;
3102 +    else if (!strcmp(aGeneric, "cursive") || !strcmp(aGeneric, "fantasy"))
3103 +        serif = sansSerif =  1;
3104 +    else
3105 +        NS_NOTREACHED("unexpected generic family");
3106 +    nGenerics = serif + sansSerif + monospace;
3107 +
3108 +    array = NS_STATIC_CAST(PRUnichar **,
3109 +               nsMemory::Alloc((fs->nfont + nGenerics) * sizeof(PRUnichar *)));
3110 +    if (!array)
3111 +        goto end;
3112 +
3113 +    if (serif) {
3114 +        PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("serif"));
3115 +        if (!name)
3116 +            goto end;
3117 +        array[narray++] = name;
3118 +    }
3119 +
3120 +    if (sansSerif) {
3121 +        PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("sans-serif"));
3122 +        if (!name)
3123 +            goto end;
3124 +        array[narray++] = name;
3125 +    }
3126 +
3127 +    if (monospace) {
3128 +        PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("monospace"));
3129 +        if (!name)
3130 +            goto end;
3131 +        array[narray++] = name;
3132 +    }
3133 +
3134 +    for (int i=0; i < fs->nfont; ++i) {
3135 +        char *family;
3136 +
3137 +        // if there's no family, just move to the next iteration
3138 +        if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
3139 +                                (FcChar8 **) &family) != FcResultMatch) {
3140 +            continue;
3141 +        }
3142 +
3143 +        // fontconfig always returns family names in UTF-8
3144 +        PRUnichar* name =  UTF8ToNewUnicode(nsDependentCString(family));
3145 +
3146 +        if (!name)
3147 +            goto end;
3148 +
3149 +        array[narray++] = name;
3150 +    }
3151 +
3152 +    NS_QuickSort(array + nGenerics, narray - nGenerics, sizeof (PRUnichar*),
3153 +                 CompareFontNames, nsnull);
3154 +
3155 +    *aCount = narray;
3156 +    if (narray)
3157 +        *aResult = array;
3158 +    else
3159 +        nsMemory::Free(array);
3160 +
3161 +    rv = NS_OK;
3162 +
3163 + end:
3164 +    if (NS_FAILED(rv) && array) {
3165 +        while (narray)
3166 +            nsMemory::Free (array[--narray]);
3167 +        nsMemory::Free (array);
3168 +    }
3169 +    if (pat)
3170 +        FcPatternDestroy(pat);
3171 +    if (os)
3172 +        FcObjectSetDestroy(os);
3173 +    if (fs)
3174 +        FcFontSetDestroy(fs);
3175 +
3176 +    return rv;
3177 +}
3178 +
3179 +/* static */
3180 +int
3181 +CompareFontNames (const void* aArg1, const void* aArg2, void* aClosure)
3182 +{
3183 +    const PRUnichar* str1 = *((const PRUnichar**) aArg1);
3184 +    const PRUnichar* str2 = *((const PRUnichar**) aArg2);
3185 +
3186 +    return nsCRT::strcmp(str1, str2);
3187 +}
3188 +
3189 +
3190 +// nsFontEnumeratorPango class
3191 +
3192 +nsFontEnumeratorPango::nsFontEnumeratorPango()
3193 +{
3194 +}
3195 +
3196 +NS_IMPL_ISUPPORTS1(nsFontEnumeratorPango, nsIFontEnumerator)
3197 +
3198 +NS_IMETHODIMP
3199 +nsFontEnumeratorPango::EnumerateAllFonts(PRUint32 *aCount,
3200 +                                         PRUnichar ***aResult)
3201 +{
3202 +    NS_ENSURE_ARG_POINTER(aResult);
3203 +    *aResult = nsnull;
3204 +    NS_ENSURE_ARG_POINTER(aCount);
3205 +    *aCount = 0;
3206 +
3207 +    return EnumFontsPango(nsnull, nsnull, aCount, aResult);
3208 +}
3209 +
3210 +NS_IMETHODIMP
3211 +nsFontEnumeratorPango::EnumerateFonts(const char *aLangGroup,
3212 +                                      const char *aGeneric,
3213 +                                      PRUint32 *aCount,
3214 +                                      PRUnichar ***aResult)
3215 +{
3216 +    NS_ENSURE_ARG_POINTER(aResult);
3217 +    *aResult = nsnull;
3218 +    NS_ENSURE_ARG_POINTER(aCount);
3219 +    *aCount = 0;
3220 +
3221 +    // aLangGroup=null or ""  means any (i.e., don't care)
3222 +    // aGeneric=null or ""  means any (i.e, don't care)
3223 +    nsCOMPtr<nsIAtom> langGroup;
3224 +    if (aLangGroup && *aLangGroup)
3225 +        langGroup = do_GetAtom(aLangGroup);
3226 +    const char* generic = nsnull;
3227 +    if (aGeneric && *aGeneric)
3228 +        generic = aGeneric;
3229 +
3230 +    return EnumFontsPango(langGroup, generic, aCount, aResult);
3231 +}
3232 +
3233 +NS_IMETHODIMP
3234 +nsFontEnumeratorPango::HaveFontFor(const char *aLangGroup,
3235 +                                   PRBool *aResult)
3236 +{
3237 +    NS_ENSURE_ARG_POINTER(aResult);
3238 +    *aResult = PR_FALSE;
3239 +    NS_ENSURE_ARG_POINTER(aLangGroup);
3240 +
3241 +    *aResult = PR_TRUE; // always return true for now.
3242 +    // Finish me - ftang
3243 +    return NS_OK;
3244 +}
3245 +
3246 +NS_IMETHODIMP
3247 +nsFontEnumeratorPango::GetDefaultFont(const char *aLangGroup,
3248 +                                      const char *aGeneric,
3249 +                                      PRUnichar **aResult)
3250 +{
3251 +    NS_ENSURE_ARG_POINTER(aResult);
3252 +    *aResult = nsnull;
3253 +
3254 +    // Have a look at nsFontEnumeratorXft::GetDefaultFont for some
3255 +    // possible code for this function.
3256 +
3257 +    return NS_OK;
3258 +}
3259 +
3260 +NS_IMETHODIMP
3261 +nsFontEnumeratorPango::UpdateFontList(PRBool *_retval)
3262 +{
3263 +    *_retval = PR_FALSE; // always return false for now
3264 +    return NS_OK;
3265 +}
3266 Index: gfx/src/ps/nsFontMetricsPSPango.h
3267 ===================================================================
3268 RCS file: gfx/src/ps/nsFontMetricsPSPango.h
3269 diff -N gfx/src/ps/nsFontMetricsPSPango.h
3270 --- /dev/null   1 Jan 1970 00:00:00 -0000
3271 +++ gfx/src/ps/nsFontMetricsPSPango.h   23 Oct 2006 17:37:13 -0000
3272 @@ -0,0 +1,305 @@
3273 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3274 +/* vim:expandtab:shiftwidth=4:tabstop=4:
3275 + */
3276 +/* ***** BEGIN LICENSE BLOCK *****
3277 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3278 + *
3279 + * The contents of this file are subject to the Mozilla Public License Version
3280 + * 1.1 (the "License"); you may not use this file except in compliance with
3281 + * the License. You may obtain a copy of the License at
3282 + * http://www.mozilla.org/MPL/
3283 + *
3284 + * Software distributed under the License is distributed on an "AS IS" basis,
3285 + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
3286 + * for the specific language governing rights and limitations under the
3287 + * License.
3288 + *
3289 + * The Original Code is mozilla.org code.
3290 + *
3291 + * The Initial Developer of the Original Code is
3292 + * Christopher Blizzard <blizzard@mozilla.org>.  
3293 + * Portions created by the Initial Developer are Copyright (C) 2002
3294 + * the Initial Developer. All Rights Reserved.
3295 + *
3296 + * Contributor(s):
3297 + *
3298 + * Alternatively, the contents of this file may be used under the terms of
3299 + * either the GNU General Public License Version 2 or later (the "GPL"), or
3300 + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
3301 + * in which case the provisions of the GPL or the LGPL are applicable instead
3302 + * of those above. If you wish to allow use of your version of this file only
3303 + * under the terms of either the GPL or the LGPL, and not to allow others to
3304 + * use your version of this file under the terms of the MPL, indicate your
3305 + * decision by deleting the provisions above and replace them with the notice
3306 + * and other provisions required by the GPL or the LGPL. If you do not delete
3307 + * the provisions above, a recipient may use your version of this file under
3308 + * the terms of any one of the MPL, the GPL or the LGPL.
3309 + *
3310 + * ***** END LICENSE BLOCK ***** */
3311 +
3312 +#ifndef nsFontMetricsPSPango_h__
3313 +#define nsFontMetricsPSPango_h__
3314 +
3315 +#include "nsIFontMetrics.h"
3316 +#include "nsIFontEnumerator.h"
3317 +#include "nsCRT.h"
3318 +#include "nsIAtom.h"
3319 +#include "nsString.h"
3320 +#include "nsVoidArray.h"
3321 +#include "nsFontMetricsPS.h"
3322 +
3323 +#include <pango/pango.h>
3324 +
3325 +class nsRenderingContextPS;
3326 +class nsIDrawingSurface;
3327 +
3328 +class nsFontMetricsPSPango : public nsFontMetricsPS
3329 +{
3330 +public:
3331 +    nsFontMetricsPSPango();
3332 +    virtual ~nsFontMetricsPSPango();
3333 +
3334 +    NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
3335 +
3336 +    // nsISupports
3337 +    NS_DECL_ISUPPORTS
3338 +
3339 +    // nsIFontMetrics
3340 +    NS_IMETHOD  Init                 (const nsFont& aFont, nsIAtom* aLangGroup,
3341 +                                      nsIDeviceContext *aContext);
3342 +    NS_IMETHOD  Destroy();
3343 +    NS_IMETHOD  GetLangGroup         (nsIAtom** aLangGroup);
3344 +    NS_IMETHOD  GetFontHandle        (nsFontHandle &aHandle);
3345 +
3346 +    NS_IMETHOD  GetXHeight           (nscoord& aResult)
3347 +                                     { aResult = mXHeight; return NS_OK; };
3348 +
3349 +    NS_IMETHOD GetSuperscriptOffset  (nscoord& aResult)
3350 +                                     { aResult = mSuperscriptOffset;
3351 +                                       return NS_OK; };
3352 +
3353 +    NS_IMETHOD GetSubscriptOffset    (nscoord& aResult)
3354 +                                     { aResult = mSubscriptOffset;
3355 +                                       return NS_OK; };
3356 +                              
3357 +    NS_IMETHOD GetStrikeout          (nscoord& aOffset, nscoord& aSize)
3358 +                                     { aOffset = mStrikeoutOffset;
3359 +                                       aSize = mStrikeoutSize; 
3360 +                                       return NS_OK; };
3361 +
3362 +    NS_IMETHOD GetUnderline          (nscoord& aOffset, nscoord& aSize)
3363 +                                     { aOffset = mUnderlineOffset;
3364 +                                       aSize = mUnderlineSize; 
3365 +                                       return NS_OK; };
3366 +
3367 +    NS_IMETHOD GetHeight             (nscoord &aHeight)
3368 +                                     { aHeight = mMaxHeight; 
3369 +                                       return NS_OK; };
3370 +
3371 +    NS_IMETHOD GetNormalLineHeight   (nscoord &aHeight)
3372 +                                     { aHeight = mEmHeight + mLeading;
3373 +                                       return NS_OK; };
3374 +
3375 +    NS_IMETHOD GetLeading            (nscoord &aLeading)
3376 +                                     { aLeading = mLeading; 
3377 +                                       return NS_OK; };
3378 +
3379 +    NS_IMETHOD GetEmHeight           (nscoord &aHeight)
3380 +                                     { aHeight = mEmHeight; 
3381 +                                       return NS_OK; };
3382 +
3383 +    NS_IMETHOD GetEmAscent           (nscoord &aAscent)
3384 +                                     { aAscent = mEmAscent;
3385 +                                       return NS_OK; };
3386 +
3387 +    NS_IMETHOD GetEmDescent          (nscoord &aDescent)
3388 +                                     { aDescent = mEmDescent;
3389 +                                       return NS_OK; };
3390 +
3391 +    NS_IMETHOD GetMaxHeight          (nscoord &aHeight)
3392 +                                     { aHeight = mMaxHeight;
3393 +                                       return NS_OK; };
3394 +
3395 +    NS_IMETHOD GetMaxAscent          (nscoord &aAscent)
3396 +                                     { aAscent = mMaxAscent;
3397 +                                       return NS_OK; };
3398 +
3399 +    NS_IMETHOD GetMaxDescent         (nscoord &aDescent)
3400 +                                     { aDescent = mMaxDescent;
3401 +                                       return NS_OK; };
3402 +
3403 +    NS_IMETHOD GetMaxAdvance         (nscoord &aAdvance)
3404 +                                     { aAdvance = mMaxAdvance;
3405 +                                       return NS_OK; };
3406 +
3407 +    NS_IMETHOD GetSpaceWidth         (nscoord &aSpaceCharWidth)
3408 +                                     { aSpaceCharWidth = mSpaceWidth;
3409 +                                       return NS_OK; };
3410 +
3411 +    NS_IMETHOD GetAveCharWidth       (nscoord &aAveCharWidth)
3412 +                                     { aAveCharWidth = mAveCharWidth;
3413 +                                       return NS_OK; };
3414 +
3415 +    // nsIFontMetricsPS (calls from the font rendering layer)
3416 +    NS_IMETHOD  GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength);
3417 +    NS_IMETHOD  GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength);
3418 +
3419 +    NS_IMETHOD       GetWidth(const char* aString, PRUint32 aLength,
3420 +                              nscoord& aWidth);
3421 +    NS_IMETHOD       GetWidth(const PRUnichar* aString, PRUint32 aLength,
3422 +                              nscoord& aWidth);
3423 +
3424 +    NS_IMETHOD       GetTextDimensions(const char* aString,
3425 +                                       PRUint32 aLength,
3426 +                                       nsTextDimensions& aDimensions);
3427 +    NS_IMETHOD       GetTextDimensions(const PRUnichar* aString,
3428 +                                       PRUint32 aLength,
3429 +                                       nsTextDimensions& aDimensions, 
3430 +                                       PRInt32* aFontID);
3431 +    NS_IMETHOD       GetTextDimensions(const char*         aString,
3432 +                                       PRInt32             aLength,
3433 +                                       PRInt32             aAvailWidth,
3434 +                                       PRInt32*            aBreaks,
3435 +                                       PRInt32             aNumBreaks,
3436 +                                       nsTextDimensions&   aDimensions,
3437 +                                       PRInt32&            aNumCharsFit,
3438 +                                       nsTextDimensions&   aLastWordDimensions,
3439 +                                       PRInt32*            aFontID);
3440 +    NS_IMETHOD       GetTextDimensions(const PRUnichar*    aString,
3441 +                                       PRInt32             aLength,
3442 +                                       PRInt32             aAvailWidth,
3443 +                                       PRInt32*            aBreaks,
3444 +                                       PRInt32             aNumBreaks,
3445 +                                       nsTextDimensions&   aDimensions,
3446 +                                       PRInt32&            aNumCharsFit,
3447 +                                       nsTextDimensions&   aLastWordDimensions,
3448 +                                       PRInt32*            aFontID);
3449 +
3450 +    NS_IMETHOD       DrawString(const char *aString, PRUint32 aLength,
3451 +                                nscoord aX, nscoord aY,
3452 +                                const nscoord* aSpacing,
3453 +                                nsRenderingContextPS *aContext);
3454 +    NS_IMETHOD       DrawString(const PRUnichar* aString, PRUint32 aLength,
3455 +                                nscoord aX, nscoord aY,
3456 +                                PRInt32 aFontID,
3457 +                                const nscoord* aSpacing,
3458 +                                nsRenderingContextPS *aContext);
3459 +
3460 +#ifdef MOZ_MATHML
3461 +    NS_IMETHOD       GetBoundingMetrics(const char *aString, PRUint32 aLength,
3462 +                                        nsBoundingMetrics &aBoundingMetrics);
3463 +    NS_IMETHOD       GetBoundingMetrics(const PRUnichar *aString,
3464 +                                        PRUint32 aLength,
3465 +                                        nsBoundingMetrics &aBoundingMetrics,
3466 +                                        PRInt32 *aFontID);
3467 +#endif /* MOZ_MATHML */
3468 +
3469 +    NS_IMETHOD       SetRightToLeftText(PRBool aIsRTL);
3470 +
3471 +    NS_IMETHOD       GetClusterInfo(const PRUnichar *aText,
3472 +                                    PRUint32 aLength,
3473 +                                    PRUint8 *aClusterStarts);
3474 +
3475 +    virtual PRInt32 GetPosition(const PRUnichar *aText,
3476 +                                PRUint32 aLength,
3477 +                                nsPoint aPt);
3478 +
3479 +    NS_IMETHOD       GetRangeWidth(const PRUnichar *aText,
3480 +                                   PRUint32 aLength,
3481 +                                   PRUint32 aStart,
3482 +                                   PRUint32 aEnd,
3483 +                                   PRUint32 &aWidth);
3484 +
3485 +    NS_IMETHOD       GetRangeWidth(const char *aText,
3486 +                                   PRUint32 aLength,
3487 +                                   PRUint32 aStart,
3488 +                                   PRUint32 aEnd,
3489 +                                   PRUint32 &aWidth);
3490 +
3491 +    // get hints for the font
3492 +    virtual PRUint32    GetHints     (void);
3493 +
3494 +    // drawing surface methods
3495 +    static nsresult FamilyExists    (nsIDeviceContext *aDevice,
3496 +                                     const nsString &aName);
3497 +
3498 +    inline nsIDeviceContext *GetDeviceContext() { return mDeviceContext; }
3499 +
3500 +private:
3501 +
3502 +    // generic font metrics class bits
3503 +    nsCStringArray       mFontList;
3504 +    nsAutoVoidArray      mFontIsGeneric;
3505 +
3506 +    nsIDeviceContext    *mDeviceContext;
3507 +    nsCOMPtr<nsIAtom>    mLangGroup;
3508 +    nsCString           *mGenericFont;
3509 +    float                mPointSize;
3510 +
3511 +    nsCAutoString        mDefaultFont;
3512 +
3513 +    // Pango-related items
3514 +    PangoFontDescription *mPangoFontDesc;
3515 +    PangoContext         *mPangoContext;
3516 +    PangoContext         *mLTRPangoContext;
3517 +    PangoContext         *mRTLPangoContext;
3518 +    PangoAttrList        *mPangoAttrList;
3519 +    PRBool                mIsRTL;
3520 +
3521 +    // Cached font metrics
3522 +    nscoord                  mXHeight;
3523 +    nscoord                  mSuperscriptOffset;
3524 +    nscoord                  mSubscriptOffset;
3525 +    nscoord                  mStrikeoutOffset;
3526 +    nscoord                  mStrikeoutSize;
3527 +    nscoord                  mUnderlineOffset;
3528 +    nscoord                  mUnderlineSize;
3529 +    nscoord                  mMaxHeight;
3530 +    nscoord                  mLeading;
3531 +    nscoord                  mEmHeight;
3532 +    nscoord                  mEmAscent;
3533 +    nscoord                  mEmDescent;
3534 +    nscoord                  mMaxAscent;
3535 +    nscoord                  mMaxDescent;
3536 +    nscoord                  mMaxAdvance;
3537 +    nscoord                  mSpaceWidth;
3538 +    nscoord                  mPangoSpaceWidth;
3539 +    nscoord                  mAveCharWidth;
3540 +
3541 +    // Private methods
3542 +    nsresult RealizeFont(void);
3543 +    nsresult CacheFontMetrics(void);
3544 +
3545 +    static PRBool EnumFontCallback(const nsString &aFamily,
3546 +                                   PRBool aIsGeneric, void *aData);
3547 +
3548 +    void     DrawStringSlowly(const gchar *aText,
3549 +                              const PRUnichar *aOrigString,
3550 +                              PRUint32 aLength,
3551 +                              gint aX, gint aY,
3552 +                              PangoLayoutLine *aLine,
3553 +                              const nscoord *aSpacing,
3554 +                              nsRenderingContextPS *aContext);
3555 +
3556 +    nsresult GetTextDimensionsInternal(const gchar*        aString,
3557 +                                       PRInt32             aLength,
3558 +                                       PRInt32             aAvailWidth,
3559 +                                       PRInt32*            aBreaks,
3560 +                                       PRInt32             aNumBreaks,
3561 +                                       nsTextDimensions&   aDimensions,
3562 +                                       PRInt32&            aNumCharsFit,
3563 +                                       nsTextDimensions&   aLastWordDimensions);
3564 +
3565 +    void FixupSpaceWidths (PangoLayout *aLayout, const char *aString);
3566 +};
3567 +
3568 +class nsFontEnumeratorPango : public nsIFontEnumerator
3569 +{
3570 +public:
3571 +    nsFontEnumeratorPango();
3572 +    NS_DECL_ISUPPORTS
3573 +    NS_DECL_NSIFONTENUMERATOR
3574 +};
3575 +
3576 +#endif
3577 +
3578 Index: gfx/src/ps/nsPostScriptObj.cpp
3579 ===================================================================
3580 RCS file: /cvsroot/mozilla/gfx/src/ps/nsPostScriptObj.cpp,v
3581 retrieving revision 1.124
3582 diff -u -p -d -r1.124 nsPostScriptObj.cpp
3583 --- gfx/src/ps/nsPostScriptObj.cpp      26 Jul 2005 15:54:18 -0000      1.124
3584 +++ gfx/src/ps/nsPostScriptObj.cpp      23 Oct 2006 17:37:29 -0000
3585 @@ -2061,31 +2061,74 @@ nsPostScriptObj::show(const PRUnichar* t
3586  
3587  #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
3588  void 
3589 -nsPostScriptObj::show(const PRUnichar* aTxt, int aLen,
3590 -                      const nsAFlatString& aCharList, PRUint16 aSubFontIdx)
3591 +/*nsPostScriptObj::show(const PRUnichar* aTxt, int aLen,
3592 +  const nsAFlatString& aCharList, PRUint16 aSubFontIdx) */
3593 +nsPostScriptObj::show(const nsValueArray *aGlyphs, nsPSFontGenerator *aSubset,
3594 +                      PRUint16 aSubFontIdx)
3595  {
3596 -  int i;
3597 +  PRUint32 i;
3598    fputc('<', mScriptFP);
3599  
3600 -  const PRUint16 subFontSize = nsPSFontGenerator::kSubFontSize;
3601 +  for (i = 0; i < aGlyphs->Count(); i++) {
3602 +    PRUint32 glyph = aGlyphs->ValueAt(i);
3603 +    fprintf(mScriptFP, "%02x", aSubset->InSubsetIndexOf(glyph));
3604 +  }
3605  
3606 -  // the character repertoire of a subfont (255 characters max)
3607 -  const nsAString& repertoire = 
3608 -        Substring(aCharList, aSubFontIdx * subFontSize,
3609 -                  PR_MIN(subFontSize, 
3610 -                  aCharList.Length() - aSubFontIdx * subFontSize));
3611 +  fputs("> show\n", mScriptFP);
3612 +}
3613 +#endif
3614  
3615 -  for (i = 0; i < aLen; i++) {
3616 -    // XXX This is a little inefficient, but printing is not perf. critical. 
3617 -    NS_ASSERTION(repertoire.FindChar(aTxt[i]) != kNotFound,
3618 -        "character is not covered by this subfont");
3619 -      
3620 -    // Type 1 encoding vector has 256 slots, but the 0-th slot is 
3621 -    // reserved for /.notdef so that we use the 1st through 255th slots
3622 -    // for actual characters (hence '+ 1')
3623 -    fprintf(mScriptFP, "%02x", repertoire.FindChar(aTxt[i]) + 1); 
3624 +#ifdef MOZ_ENABLE_PANGO
3625 +void
3626 +nsPostScriptObj::show(const PangoGlyphString *glyphs, float zoom, 
3627 +                      nsPSFontGenerator *aSubset, PRUint16 aSubFontIdx)
3628 +{
3629 +  PRUint32 i;
3630 +  int horiz = 1;
3631 +
3632 +  if (glyphs->glyphs[0].geometry.x_offset || glyphs->glyphs[0].geometry.y_offset)
3633 +    rmoveto (NSToCoordRound (zoom * glyphs->glyphs[0].geometry.x_offset / PANGO_SCALE),
3634 +             NSToCoordRound (zoom * glyphs->glyphs[0].geometry.y_offset / PANGO_SCALE));
3635 +
3636 +  fputc('<', mScriptFP);
3637 +
3638 +  for (i = 0; i < glyphs->num_glyphs; i++) {
3639 +    PRUint32 glyph = glyphs->glyphs[i].glyph;
3640 +    fprintf(mScriptFP, "%02x", aSubset->InSubsetIndexOf(glyph));
3641 +    if (glyphs->glyphs[i].geometry.y_offset)
3642 +      horiz = 0;
3643 +  }
3644 +
3645 +  if (horiz) {
3646 +    fputs(">\n[", mScriptFP);
3647 +    for (i = 1; i < glyphs->num_glyphs; i++) {
3648 +      fprintf(mScriptFP, "%d ",
3649 +              NSToCoordRound (zoom * (+ glyphs->glyphs[i  ].geometry.x_offset
3650 +                                      + glyphs->glyphs[i-1].geometry.width
3651 +                                      - glyphs->glyphs[i-1].geometry.x_offset) / PANGO_SCALE));
3652 +    }
3653 +    fprintf(mScriptFP, "%d",
3654 +              NSToCoordRound (zoom * (+ glyphs->glyphs[i-1].geometry.width
3655 +                                      - glyphs->glyphs[i-1].geometry.x_offset
3656 +                                      - glyphs->glyphs[  0].geometry.x_offset) / PANGO_SCALE));
3657 +    fputs("] xshow\n", mScriptFP);
3658 +  } else {
3659 +    fputs(">\n[", mScriptFP);
3660 +    for (i = 1; i < glyphs->num_glyphs; i++) {
3661 +      fprintf(mScriptFP, "%d %d ",
3662 +              NSToCoordRound (zoom * (+ glyphs->glyphs[i  ].geometry.x_offset
3663 +                                      + glyphs->glyphs[i-1].geometry.width
3664 +                                      - glyphs->glyphs[i-1].geometry.x_offset) / PANGO_SCALE),
3665 +              NSToCoordRound (zoom * (+ glyphs->glyphs[i  ].geometry.y_offset
3666 +                                      - glyphs->glyphs[i-1].geometry.y_offset) / PANGO_SCALE));
3667 +    }
3668 +    fprintf(mScriptFP, "%d %d",
3669 +              NSToCoordRound (zoom * (+ glyphs->glyphs[i-1].geometry.width
3670 +                                      - glyphs->glyphs[i-1].geometry.x_offset
3671 +                                      - glyphs->glyphs[  0].geometry.x_offset) / PANGO_SCALE),
3672 +              NSToCoordRound (zoom * (- glyphs->glyphs[i-1].geometry.y_offset) / PANGO_SCALE));
3673 +    fputs("] xyshow\n", mScriptFP);
3674    }
3675 -  fputs("> show\n", mScriptFP);
3676  }
3677  #endif
3678  
3679 @@ -2101,6 +2144,16 @@ nsPostScriptObj::moveto(nscoord x, nscoo
3680  
3681  /** ---------------------------------------------------
3682   *  See documentation in nsPostScriptObj.h
3683 + *     @update 10/20/06 behdad
3684 + */
3685 +void 
3686 +nsPostScriptObj::rmoveto(nscoord x, nscoord y)
3687 +{
3688 +  fprintf(mScriptFP, "%d %d rmoveto\n", x, y);
3689 +}
3690 +
3691 +/** ---------------------------------------------------
3692 + *  See documentation in nsPostScriptObj.h
3693   *     @update 2/1/99 dwc
3694   */
3695  void 
3696 Index: gfx/src/ps/nsPostScriptObj.h
3697 ===================================================================
3698 RCS file: /cvsroot/mozilla/gfx/src/ps/nsPostScriptObj.h,v
3699 retrieving revision 1.47
3700 diff -u -p -d -r1.47 nsPostScriptObj.h
3701 --- gfx/src/ps/nsPostScriptObj.h        8 May 2005 15:01:20 -0000       1.47
3702 +++ gfx/src/ps/nsPostScriptObj.h        23 Oct 2006 17:37:30 -0000
3703 @@ -57,9 +57,15 @@
3704  #include "nsIPersistentProperties2.h"
3705  #include "nsTempfilePS.h"
3706  #include "nsEPSObjectPS.h"
3707 +#ifdef MOZ_ENABLE_PANGO
3708 +#include <pango/pango.h>
3709 +#endif
3710 +
3711  
3712 +class nsPSFontGenerator;
3713  class nsIImage;
3714  class nsIAtom;
3715 +class nsValueArray;
3716  #endif
3717  
3718  #include <stdio.h>
3719 @@ -217,6 +223,14 @@ public:
3720     */
3721    void moveto(nscoord aX, nscoord aY);
3722    /** ---------------------------------------------------
3723 +   *  Move relative to the current point
3724 +   *   @update 10/20/2006 behdad
3725 +   *   @param  aX   X coordinate
3726 +   *           aY   Y coordinate
3727 +   *    @return VOID
3728 +   */
3729 +  void rmoveto(nscoord aX, nscoord aY);
3730 +  /** ---------------------------------------------------
3731     *  Add a line to the current path, from the current point
3732     *  to the specified point.
3733     *   @update 9/30/2003
3734 @@ -346,12 +360,24 @@ public:
3735     */
3736    void show(const PRUnichar* aText, int aLen, const char *aAlign, int aType);
3737    /** ---------------------------------------------------
3738 -   *  This version takes a PRUnichar string, a font subset string
3739 -   *  for freetype printing and a subfont index
3740 +   *  This version of show takes an array of glyphs, subfont and subfont index
3741 +   *  to render and is used for freetype and xft printing.
3742     *   @update 2/15/2005 jshin@mailaps.org
3743 +   *    @update 6/7/2005 blizzard@mozilla.org
3744     */
3745 -  void show(const PRUnichar* aText, int aLen, const nsAFlatString& aCharList,
3746 +  void show(const nsValueArray *aGlyphs, nsPSFontGenerator *aSubset,
3747              PRUint16 aSubFontIdx);
3748 +  /*void show(const PRUnichar* aText, int aLen, const nsAFlatString& aCharList,
3749 +    PRUint16 aSubFontIdx); */
3750 +#ifdef MOZ_ENABLE_PANGO
3751 +  /** ---------------------------------------------------
3752 +   *  This version of show takes a pango glyph string, subfont and subfont index
3753 +   *  to render and is used for pango printing.
3754 +   *   @update 10/20/2006 behdad@behdad.org
3755 +   */
3756 +  void show(const PangoGlyphString *glyphs, float zoom,
3757 +            nsPSFontGenerator *aSubset, PRUint16 aSubFontIdx);
3758 +#endif
3759    /** ---------------------------------------------------
3760     *  set the clipping path to the current path using the winding rule
3761     *   @update 2/1/99 dwc
3762 Index: gfx/src/ps/nsRenderingContextPS.cpp
3763 ===================================================================
3764 RCS file: /cvsroot/mozilla/gfx/src/ps/nsRenderingContextPS.cpp,v
3765 retrieving revision 1.83
3766 diff -u -p -d -r1.83 nsRenderingContextPS.cpp
3767 --- gfx/src/ps/nsRenderingContextPS.cpp 4 Mar 2005 07:39:27 -0000       1.83
3768 +++ gfx/src/ps/nsRenderingContextPS.cpp 23 Oct 2006 17:37:31 -0000
3769 @@ -251,6 +251,8 @@ nsRenderingContextPS :: GetDrawingSurfac
3770  NS_IMETHODIMP
3771  nsRenderingContextPS :: GetHints(PRUint32& aResult)
3772  {
3773 +  nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
3774 +  aResult = metrics->GetHints ();
3775    return NS_OK;
3776  }
3777  
3778 @@ -1006,8 +1008,11 @@ nsRenderingContextPS::GetTextDimensions(
3779                                          nsTextDimensions& aLastWordDimensions,
3780                                          PRInt32*          aFontID)
3781  {
3782 -  NS_NOTYETIMPLEMENTED("nsRenderingContextPS::GetTextDimensions");
3783 -  return NS_ERROR_NOT_IMPLEMENTED;
3784 +  NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER);
3785 +  nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
3786 +  NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
3787 +  return metrics->GetTextDimensions (aString, aLength, aAvailWidth, aBreaks, aNumBreaks,
3788 +                                    aDimensions, aNumCharsFit, aLastWordDimensions, aFontID);
3789  }
3790  
3791  NS_IMETHODIMP
3792 @@ -1021,43 +1026,31 @@ nsRenderingContextPS::GetTextDimensions(
3793                                          nsTextDimensions& aLastWordDimensions,
3794                                          PRInt32*          aFontID)
3795  {
3796 -  NS_NOTYETIMPLEMENTED("nsRenderingContextPS::GetTextDimensions");
3797 -  return NS_ERROR_NOT_IMPLEMENTED;
3798 +  NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER);
3799 +  nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
3800 +  NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
3801 +  return metrics->GetTextDimensions (aString, aLength, aAvailWidth, aBreaks, aNumBreaks,
3802 +                                    aDimensions, aNumCharsFit, aLastWordDimensions, aFontID);
3803  }
3804  
3805  NS_IMETHODIMP
3806  nsRenderingContextPS :: GetTextDimensions(const char* aString, PRUint32 aLength,
3807                                            nsTextDimensions& aDimensions)
3808  {
3809 -  nsresult rv = NS_ERROR_FAILURE;
3810 -
3811 -  if (mFontMetrics) {
3812 -    nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
3813 -    metrics->GetStringWidth(aString, aDimensions.width, aLength);
3814 -    metrics->GetMaxAscent(aDimensions.ascent);
3815 -    metrics->GetMaxDescent(aDimensions.descent);
3816 -    rv = NS_OK;
3817 -  }
3818 -  
3819 -  return rv;
3820 +  NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER);
3821 +  nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
3822 +  NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
3823 +  return metrics->GetTextDimensions (aString, aLength, aDimensions);
3824  }
3825  
3826  NS_IMETHODIMP
3827  nsRenderingContextPS :: GetTextDimensions(const PRUnichar* aString, PRUint32 aLength,
3828                                            nsTextDimensions& aDimensions, PRInt32* aFontID)
3829  {
3830 -  nsresult rv = NS_ERROR_FAILURE;
3831 -
3832 -  if (mFontMetrics) {
3833 -    nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
3834 -    metrics->GetStringWidth(aString, aDimensions.width, aLength);
3835 -     //XXX temporary - bug 96609
3836 -    metrics->GetMaxAscent(aDimensions.ascent);
3837 -    metrics->GetMaxDescent(aDimensions.descent);
3838 -    rv = NS_OK;
3839 -  }
3840 -
3841 -  return rv;
3842 +  NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER);
3843 +  nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
3844 +  NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
3845 +  return metrics->GetTextDimensions (aString, aLength, aDimensions, aFontID);
3846  }
3847  
3848  /** ---------------------------------------------------
3849 @@ -1073,47 +1066,7 @@ nsRenderingContextPS :: DrawString(const
3850  
3851    nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
3852    NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
3853 -
3854 -  // When FT2 printing is enabled, we don't need to set langgroup
3855 -#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
3856 -  if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, mContext.get())->mFTPEnable) {
3857 -#endif
3858 -    nsCOMPtr<nsIAtom> langGroup;
3859 -    mFontMetrics->GetLangGroup(getter_AddRefs(langGroup));
3860 -    mPSObj->setlanggroup(langGroup);
3861 -#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
3862 -  }
3863 -#endif
3864 -
3865 -  if (aLength == 0)
3866 -    return NS_OK;
3867 -  nsFontPS* fontPS = nsFontPS::FindFont(aString[0], metrics->Font(), metrics);
3868 -  NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
3869 -  fontPS->SetupFont(this);
3870 -
3871 -  PRUint32 i, start = 0;
3872 -  for (i=0; i<aLength; i++) {
3873 -    nsFontPS* fontThisChar;
3874 -    fontThisChar = nsFontPS::FindFont(aString[i], metrics->Font(), metrics);
3875 -    NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE);
3876 -    if (fontThisChar != fontPS) {
3877 -      // draw text up to this point
3878 -      aX += DrawString(aString+start, i-start, aX, aY, fontPS, 
3879 -                       aSpacing?aSpacing+start:nsnull);
3880 -      start = i;
3881 -
3882 -      // setup for following text
3883 -      fontPS = fontThisChar;
3884 -      fontPS->SetupFont(this);
3885 -    }
3886 -  }
3887 -
3888 -  // draw the last part
3889 -  if (aLength-start)
3890 -    DrawString(aString+start, aLength-start, aX, aY, fontPS, 
3891 -               aSpacing?aSpacing+start:nsnull);
3892 -
3893 -  return NS_OK;
3894 +  return metrics->DrawString (aString, aLength, aX, aY, aSpacing, this);
3895  }
3896  
3897  /** ---------------------------------------------------
3898 @@ -1129,110 +1082,7 @@ nsRenderingContextPS :: DrawString(const
3899    
3900    nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
3901    NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
3902 -
3903 -#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
3904 -  // When FT2 printing is enabled, we don't need to set langgroup
3905 -  if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, mContext.get())->mFTPEnable) {
3906 -#endif
3907 -    nsCOMPtr<nsIAtom> langGroup = nsnull;
3908 -    mFontMetrics->GetLangGroup(getter_AddRefs(langGroup));
3909 -    mPSObj->setlanggroup(langGroup);
3910 -#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
3911 -  }
3912 -#endif
3913 -
3914 -  /* build up conversion table */
3915 -  mPSObj->preshow(aString, aLength);
3916 -
3917 -  if (aLength == 0)
3918 -    return NS_OK;
3919 -  nsFontPS* fontPS = nsFontPS::FindFont(aString[0], metrics->Font(), metrics);
3920 -  NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
3921 -  fontPS->SetupFont(this);
3922 -
3923 -  PRUint32 i, start = 0;
3924 -  for (i=0; i<aLength; i++) {
3925 -    nsFontPS* fontThisChar;
3926 -    fontThisChar = nsFontPS::FindFont(aString[i], metrics->Font(), metrics);
3927 -    NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE);
3928 -    if (fontThisChar != fontPS) {
3929 -      // draw text up to this point
3930 -      aX += DrawString(aString+start, i-start, aX, aY, fontPS, 
3931 -                       aSpacing?aSpacing+start:nsnull);
3932 -      start = i;
3933 -
3934 -      // setup for following text
3935 -      fontPS = fontThisChar;
3936 -      fontPS->SetupFont(this);
3937 -    }
3938 -  }
3939 -
3940 -  // draw the last part
3941 -  if (aLength-start)
3942 -    DrawString(aString+start, aLength-start, aX, aY, fontPS, 
3943 -               aSpacing?aSpacing+start:nsnull);
3944 -
3945 -  return NS_OK;
3946 -}
3947 -
3948 -PRInt32 
3949 -nsRenderingContextPS::DrawString(const char *aString, PRUint32 aLength,
3950 -                                 nscoord &aX, nscoord &aY, nsFontPS* aFontPS,
3951 -                                 const nscoord* aSpacing)
3952 -{
3953 -  nscoord width = 0;
3954 -  PRInt32 x = aX;
3955 -  PRInt32 y = aY;
3956 -
3957 -  PRInt32 dxMem[500];
3958 -  PRInt32* dx0 = 0;
3959 -  if (aSpacing) {
3960 -    dx0 = dxMem;
3961 -    if (aLength > 500) {
3962 -      dx0 = new PRInt32[aLength];
3963 -      NS_ENSURE_TRUE(dx0, NS_ERROR_OUT_OF_MEMORY);
3964 -    }
3965 -    mTranMatrix->ScaleXCoords(aSpacing, aLength, dx0);
3966 -  }
3967 -
3968 -  mTranMatrix->TransformCoord(&x, &y);
3969 -  width = aFontPS->DrawString(this, x, y, aString, aLength);
3970 -
3971 -  if ((aSpacing) && (dx0 != dxMem)) {
3972 -    delete [] dx0;
3973 -  }
3974 -
3975 -  return width;
3976 -}
3977 -
3978 -
3979 -PRInt32 
3980 -nsRenderingContextPS::DrawString(const PRUnichar *aString, PRUint32 aLength,
3981 -                                 nscoord aX, nscoord aY, nsFontPS* aFontPS,
3982 -                                 const nscoord* aSpacing)
3983 -{
3984 -  nscoord width = 0;
3985 -  PRInt32 x = aX;
3986 -  PRInt32 y = aY;
3987 -
3988 -  if (aSpacing) {
3989 -    // Slow, but accurate rendering
3990 -    const PRUnichar* end = aString + aLength;
3991 -    while (aString < end){
3992 -      x = aX;
3993 -      y = aY;
3994 -      mTranMatrix->TransformCoord(&x, &y);
3995 -      aFontPS->DrawString(this, x, y, aString, 1);
3996 -      aX += *aSpacing++;
3997 -      aString++;
3998 -    }
3999 -    width = aX;
4000 -  } else {
4001 -    mTranMatrix->TransformCoord(&x, &y);
4002 -    width = aFontPS->DrawString(this, x, y, aString, aLength);
4003 -  }
4004 -
4005 -  return width;
4006 +  return metrics->DrawString (aString, aLength, aX, aY, aFontID, aSpacing, this);
4007  }
4008  
4009  /** ---------------------------------------------------
4010 @@ -1346,8 +1196,10 @@ nsRenderingContextPS::GetBoundingMetrics
4011                                           PRUint32           aLength,
4012                                           nsBoundingMetrics& aBoundingMetrics)
4013  {
4014 -  // Fill me up 
4015 -  return NS_ERROR_NOT_IMPLEMENTED;
4016 +  NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER);
4017 +  nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
4018 +  NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
4019 +  return metrics->GetBoundingMetrics (aString, aLength, aBoundingMetrics);
4020  }
4021  
4022    /**
4023 @@ -1359,8 +1211,10 @@ nsRenderingContextPS::GetBoundingMetrics
4024                                           nsBoundingMetrics& aBoundingMetrics,
4025                                           PRInt32*           aFontID)
4026  {
4027 -  // Fill me up 
4028 -  return NS_ERROR_NOT_IMPLEMENTED;
4029 +  NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER);
4030 +  nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
4031 +  NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
4032 +  return metrics->GetBoundingMetrics (aString, aLength, aBoundingMetrics, aFontID);
4033  }
4034  #endif /* MOZ_MATHML */
4035  
4036 Index: gfx/src/ps/nsRenderingContextPS.h
4037 ===================================================================
4038 RCS file: /cvsroot/mozilla/gfx/src/ps/nsRenderingContextPS.h,v
4039 retrieving revision 1.49
4040 diff -u -p -d -r1.49 nsRenderingContextPS.h
4041 --- gfx/src/ps/nsRenderingContextPS.h   20 Sep 2004 06:46:16 -0000      1.49
4042 +++ gfx/src/ps/nsRenderingContextPS.h   23 Oct 2006 17:37:35 -0000
4043 @@ -154,6 +154,10 @@ public:
4044    NS_IMETHOD GetWidth(const PRUnichar* aString, PRUint32 aLength,
4045                        nscoord& aWidth, PRInt32 *aFontID);
4046  
4047 +  nsTransform2D *GetTranMatrix() {
4048 +    return mTranMatrix;
4049 +  }
4050 +
4051    NS_IMETHOD DrawString(const char *aString, PRUint32 aLength,
4052                          nscoord aX, nscoord aY,
4053                          const nscoord* aSpacing);
4054 @@ -164,13 +168,6 @@ public:
4055    NS_IMETHOD DrawString(const nsString& aString, nscoord aX, nscoord aY,
4056                          PRInt32 aFontID,
4057                          const nscoord* aSpacing);
4058 -protected:
4059 -  PRInt32 DrawString(const PRUnichar *aString, PRUint32 aLength,
4060 -                        nscoord aX, nscoord aY, nsFontPS* aFontPS,
4061 -                        const nscoord* aSpacing);
4062 -  PRInt32 DrawString(const char *aString, PRUint32 aLength,
4063 -                        nscoord &aX, nscoord &aY, nsFontPS* aFontPS,
4064 -                        const nscoord* aSpacing);
4065  public:
4066  
4067    NS_IMETHOD GetTextDimensions(const char* aString, PRUint32 aLength,
4068 Index: gfx/src/ps/nsType1.cpp
4069 ===================================================================
4070 RCS file: /cvsroot/mozilla/gfx/src/ps/nsType1.cpp,v
4071 retrieving revision 1.5.8.1
4072 diff -u -p -d -r1.5.8.1 nsType1.cpp
4073 --- gfx/src/ps/nsType1.cpp      19 Oct 2005 08:16:22 -0000      1.5.8.1
4074 +++ gfx/src/ps/nsType1.cpp      23 Oct 2006 17:37:39 -0000
4075 @@ -73,8 +73,13 @@
4076  #include "nsIFreeType2.h"
4077  #include "nsServiceManagerUtils.h"
4078  #endif
4079 +#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
4080 +#include FT_TYPE1_TABLES_H
4081 +#endif
4082  #include "nsPrintfCString.h"
4083  #include "nsAutoBuffer.h"
4084 +#include "nsValueArray.h"
4085 +#include "nsVoidArray.h"
4086  
4087  #define HEXASCII_LINE_LEN 64
4088  
4089 @@ -113,7 +118,7 @@ static void encryptAndHexOut(FILE *aFile
4090                               const char *aBuf, PRInt32 aLen = -1);
4091  static void charStringOut(FILE* aFile, PRUint32* aPos, PRUint16* aKey,
4092                            const char *aStr, PRUint32 aLen, 
4093 -                          PRUnichar aId);
4094 +                          const char *aGlyphName);
4095  static void flattenName(nsCString& aString);
4096  
4097  /* thunk a short name for this function */
4098 @@ -202,19 +207,30 @@ Type1EncryptString(unsigned char *aInBuf
4099      aOutBuf[i] = Type1Encrypt(aInBuf[i], &key);
4100  }
4101  
4102 +static FT_UShort
4103 +get_upm (FT_Face face)
4104 +{
4105 +  FT_UShort upm = face->units_per_EM;
4106 +
4107 +  if (!upm)
4108 +    upm = 1000; // bitmap font or something
4109 +
4110 +  return upm;
4111 +}
4112 +
4113  static PRBool
4114  sideWidthAndBearing(const FT_Vector *aEndPt, FT2PT1_info *aFti)
4115  {
4116    int aw = 0;
4117    int ah = 0;
4118 -  FT_UShort upm = aFti->face->units_per_EM;
4119 +  FT_UShort upm = get_upm (aFti->face);
4120    FT_GlyphSlot slot;
4121    FT_Glyph glyph;
4122    FT_BBox bbox;
4123  
4124    slot = aFti->face->glyph;
4125  
4126 -#ifdef MOZ_ENABLE_XFT
4127 +#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
4128    FT_Error error = FT_Get_Glyph(slot, &glyph);
4129    if (error) {
4130      NS_ERROR("sideWidthAndBearing failed to get glyph");
4131 @@ -256,7 +272,7 @@ static int
4132  moveto(nsFT_CONST FT_Vector *aEndPt, void *aClosure)
4133  {
4134    FT2PT1_info *fti = (FT2PT1_info *)aClosure;
4135 -  FT_UShort upm = fti->face->units_per_EM;
4136 +  FT_UShort upm = get_upm (fti->face);
4137    PRBool rslt;
4138  
4139    if (fti->elm_cnt == 0) {
4140 @@ -293,7 +309,7 @@ static int
4141  lineto(nsFT_CONST FT_Vector *aEndPt, void *aClosure)
4142  {
4143    FT2PT1_info *fti = (FT2PT1_info *)aClosure;
4144 -  FT_UShort upm = fti->face->units_per_EM;
4145 +  FT_UShort upm = get_upm (fti->face);
4146  
4147    if (toCS(upm, aEndPt->x) == fti->cur_x) {
4148      fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->y) - (int)fti->cur_y);
4149 @@ -320,7 +336,7 @@ conicto(nsFT_CONST FT_Vector *aControlPt
4150          void *aClosure)
4151  {
4152    FT2PT1_info *ftinfo = (FT2PT1_info *)aClosure;
4153 -  FT_UShort upm = ftinfo->face->units_per_EM;
4154 +  FT_UShort upm = get_upm (ftinfo->face);
4155    double ctl_x, ctl_y;
4156    double cur_x, cur_y, x3, y3;
4157    FT_Vector aControlPt1, aControlPt2;
4158 @@ -353,7 +369,7 @@ cubicto(nsFT_CONST FT_Vector *aControlPt
4159          nsFT_CONST FT_Vector *aEndPt, void *aClosure)
4160  {
4161    FT2PT1_info *ftinfo = (FT2PT1_info *)aClosure;
4162 -  FT_UShort upm = ftinfo->face->units_per_EM;
4163 +  FT_UShort upm = get_upm (ftinfo->face);
4164    double cur_x, cur_y, x1, y1, x2, y2, x3, y3;
4165  
4166    cur_x = ftinfo->cur_x;
4167 @@ -408,8 +424,55 @@ static FT_Outline_Funcs ft_outline_funcs
4168    0
4169  };
4170  
4171 +
4172 +static int
4173 +trace_bitmap_glyph (FT_GlyphSlot slot, FT2PT1_info *fti)
4174 +{
4175 +  unsigned char *row, *byte_ptr, byte;
4176 +  int rows, cols;
4177 +  int x, y, bit_mask;
4178 +  int upm, x_off, y_off, x_mult, y_mult;
4179 +
4180 +  upm = get_upm (slot->face);
4181 +  x_off = slot->bitmap_left;
4182 +  y_off = slot->bitmap_top;
4183 +  x_mult = upm / slot->face->size->metrics.x_ppem;
4184 +  y_mult = upm / slot->face->size->metrics.y_ppem;
4185 +
4186 +  switch (slot->bitmap.pixel_mode) {
4187 +  case FT_PIXEL_MODE_MONO:
4188 +
4189 +    for (y = 0, row = slot->bitmap.buffer, rows = slot->bitmap.rows; rows; row += slot->bitmap.pitch, rows--, y++) {
4190 +       for (x = 0, byte_ptr = row, cols = (slot->bitmap.width + 7) / 8; cols; byte_ptr++, cols--) {
4191 +           byte = *byte_ptr;
4192 +           for (bit_mask = 128; bit_mask && x < slot->bitmap.width; bit_mask >>= 1, x++) {
4193 +               if (byte & bit_mask) {
4194 +                   FT_Vector p;
4195 +                   p.x = x_mult * (x_off + x);
4196 +                   p.y = y_mult * (y_off - y);
4197 +                   moveto(&p, (void *) fti);
4198 +                   p.x += x_mult;
4199 +                   lineto(&p, (void *) fti);
4200 +                   p.y += y_mult;
4201 +                   lineto(&p, (void *) fti);
4202 +                   p.x -= x_mult;
4203 +                   lineto(&p, (void *) fti);
4204 +               }
4205 +           }
4206 +       }
4207 +    }
4208 +    break;
4209 +
4210 +  default:
4211 +    return 1;
4212 +  }
4213 +
4214 +  return 0;
4215 +}
4216 +
4217 +
4218  FT_Error
4219 -#ifdef MOZ_ENABLE_XFT
4220 +#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
4221  FT2GlyphToType1CharString(FT_Face aFace, PRUint32 aGlyphID,
4222                            int aWmode, int aLenIV, unsigned char *aBuf)
4223  #else
4224 @@ -423,7 +486,7 @@ FT2GlyphToType1CharString(nsIFreeType2 *
4225    unsigned char *start = aBuf;
4226    FT2PT1_info fti;
4227  
4228 -#ifdef MOZ_ENABLE_XFT
4229 +#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
4230    FT_Error error = FT_Load_Glyph(aFace, aGlyphID, flags);
4231    if (error) {
4232      NS_ERROR("failed to load aGlyphID");
4233 @@ -438,11 +501,6 @@ FT2GlyphToType1CharString(nsIFreeType2 *
4234  #endif
4235    slot = aFace->glyph;
4236  
4237 -  if (slot->format != ft_glyph_format_outline) {
4238 -    NS_ERROR("aGlyphID is not an outline glyph");
4239 -    return 1;
4240 -  }
4241 -
4242  #ifdef MOZ_ENABLE_FREETYPE2
4243    fti.ft2     = aFt2;
4244  #endif
4245 @@ -456,18 +514,27 @@ FT2GlyphToType1CharString(nsIFreeType2 *
4246    for (j=0; j< aLenIV; j++) {
4247      fti.len += ecsi(&fti.buf, 0);
4248    }
4249 -#ifdef MOZ_ENABLE_XFT
4250 -  if (FT_Outline_Decompose(&slot->outline, &ft_outline_funcs, &fti))  {
4251 -    NS_ERROR("error decomposing aGlyphID");
4252 -    return 1;
4253 -  }
4254 +
4255 +  if (slot->format == ft_glyph_format_outline) {
4256 +#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
4257 +    if (FT_Outline_Decompose(&slot->outline, &ft_outline_funcs, &fti))  {
4258 +      NS_ERROR("error decomposing aGlyphID");
4259 +      return 1;
4260 +    }
4261  #else
4262 -  rv = aFt2->OutlineDecompose(&slot->outline, &ft_outline_funcs, &fti);
4263 -  if (NS_FAILED(rv)) {
4264 -    NS_ERROR("error decomposing aGlyphID");
4265 -    return 1;
4266 -  }
4267 +    rv = aFt2->OutlineDecompose(&slot->outline, &ft_outline_funcs, &fti);
4268 +    if (NS_FAILED(rv)) {
4269 +      NS_ERROR("error decomposing aGlyphID");
4270 +    }
4271  #endif
4272 +  } else if (slot->format == ft_glyph_format_bitmap) {
4273 +    /* ok, it's a bitmap glyph.  trace it! */
4274 +    if (trace_bitmap_glyph (slot, &fti)) {
4275 +      NS_ERROR("error tracing bitmap glyph");
4276 +    }
4277 +  } else {
4278 +      NS_ERROR("aGlyphID has unhandled format");
4279 +  }
4280  
4281    if (fti.elm_cnt) {
4282      fti.len += csc(&fti.buf, T1_CLOSEPATH);
4283 @@ -491,28 +558,52 @@ FT2GlyphToType1CharString(nsIFreeType2 *
4284  }
4285  
4286  static PRBool
4287 -#ifdef MOZ_ENABLE_XFT
4288 +#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
4289  outputType1SubFont(FT_Face aFace,
4290  #else
4291  outputType1SubFont(nsIFreeType2 *aFt2, FT_Face aFace,
4292  #endif
4293 -                 const nsAString &aCharIDs, const char *aFontName,
4294 -                 int aWmode, int aLenIV, FILE *aFile);
4295 +                   nsValueArray *aGlyphs,
4296 +                   PRUint32 aOffset, PRUint32 aLen,
4297 +                   const char *aFontName,
4298 +                   int aWmode, int aLenIV, FILE *aFile);
4299  
4300  nsresult
4301  FT2ToType1FontName(FT_Face aFace, int aWmode, nsCString& aFontName)
4302  {
4303 +  // only hash the first 10 000 bytes of the font
4304 +  int size = aFace->stream->size;
4305 +  size = size > 10000 ? 10000 : size;
4306 +
4307 +  unsigned char *data;
4308 +  if (aFace->stream->read) {
4309 +    data = (unsigned char *) malloc (size);
4310 +    aFace->stream->read (aFace->stream, 0, data, size);
4311 +  } else {
4312 +    data = aFace->stream->base;
4313 +  }
4314 +
4315 +  unsigned int data_hash = 0;
4316 +  int i;
4317 +  for (i = 0; i < size; i++)
4318 +    data_hash = (data_hash << 5) - data_hash + data[size];
4319 +
4320 +  if (aFace->stream->read)
4321 +    free (data);
4322 +
4323    aFontName = aFace->family_name;
4324    aFontName.AppendLiteral(".");
4325    aFontName += aFace->style_name;
4326 -  aFontName += nsPrintfCString(".%ld.%d", aFace->face_index, aWmode ? 1 : 0);
4327 +  aFontName += nsPrintfCString(".%ld.%d.%lx.%x", aFace->face_index, aWmode ? 1 : 0,
4328 +                               (long) aFace->stream->size, data_hash);
4329    flattenName(aFontName);
4330 +
4331    return NS_OK;
4332  }
4333  
4334  // output a subsetted truetype font converted to multiple type 1 fonts
4335  PRBool
4336 -FT2SubsetToType1FontSet(FT_Face aFace, const nsString& aSubset,
4337 +FT2SubsetToType1FontSet(FT_Face aFace, nsValueArray *aGlyphSubset,
4338                          int aWmode,  FILE *aFile)
4339  {
4340  #ifdef MOZ_ENABLE_FREETYPE2
4341 @@ -527,32 +618,35 @@ FT2SubsetToType1FontSet(FT_Face aFace, c
4342    nsCAutoString fontNameBase;
4343    FT2ToType1FontName(aFace, aWmode, fontNameBase);
4344    PRUint32 i = 0;
4345 -  for (; i <= aSubset.Length() / 255 ; i++) {
4346 +  for (; i <= aGlyphSubset->Count() / 255 ; i++) {
4347      nsCAutoString fontName(fontNameBase);
4348      fontName.AppendLiteral(".Set");
4349      fontName.AppendInt(i);
4350 -#ifdef MOZ_ENABLE_XFT
4351 +#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
4352      outputType1SubFont(aFace,
4353  #else
4354      outputType1SubFont(ft2, aFace, 
4355  #endif
4356 -      Substring(aSubset, i * 255, PR_MIN(255, aSubset.Length() - i * 255)),
4357 -      fontName.get(), aWmode, 4, aFile);
4358 +                       aGlyphSubset,
4359 +                       (i * 255), PR_MIN(255, aGlyphSubset->Count() - i * 255),
4360 +                       fontName.get(), aWmode, 4, aFile);
4361    }
4362    return PR_TRUE;
4363  }
4364  
4365  // output a type 1 font (with 255 characters or fewer) 
4366  static PRBool
4367 -#ifdef MOZ_ENABLE_XFT
4368 +#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
4369  outputType1SubFont(FT_Face aFace,
4370  #else
4371  outputType1SubFont(nsIFreeType2 *aFt2, FT_Face aFace,
4372  #endif
4373 -                 const nsAString& aCharIDs, const char *aFontName,
4374 -                 int aWmode, int aLenIV, FILE *aFile)
4375 +                   nsValueArray *aGlyphs,
4376 +                   PRUint32 aOffset, PRUint32 aLen,
4377 +                   const char *aFontName,
4378 +                   int aWmode, int aLenIV, FILE *aFile)
4379  {
4380 -  FT_UShort upm = aFace->units_per_EM;
4381 +  FT_UShort upm = get_upm (aFace);
4382  
4383    fprintf(aFile, "%%%%BeginResource: font %s\n"
4384                   "%%!PS-AdobeFont-1.0-3.0 %s 1.0\n"
4385 @@ -573,9 +667,13 @@ outputType1SubFont(nsIFreeType2 *aFt2, F
4386                   toCS(upm, aFace->bbox.xMax),
4387                   toCS(upm, aFace->bbox.yMax));
4388  
4389 -  nsString charIDstr(aCharIDs);
4390 -  PRUint32 len = aCharIDs.Length();
4391 -  
4392 +  nsValueArray glyphs(PR_UINT16_MAX);
4393 +  nsCStringArray glyphnames(PR_UINT16_MAX);
4394 +  glyphs = *aGlyphs;
4395 +
4396 +  PRUint32 len = aLen;
4397 +  PRUint32 i;
4398 +
4399    if (len < 10) { 
4400      // Add a small set of characters to the subset of the user
4401      // defined font to produce to make sure the font ends up
4402 @@ -584,25 +682,47 @@ outputType1SubFont(nsIFreeType2 *aFt2, F
4403      // XXX : need to check if this is true of type 1 fonts as well.
4404      // I suspect it's only the case of CID-keyed fonts (type 9) we used to
4405      // generate. 
4406 -    charIDstr.AppendLiteral("1234567890"); 
4407 +    for (i = 1; i <= 10; i++) {
4408 +      glyphs.AppendValue(i);
4409 +    }
4410      len += 10;
4411    }
4412    
4413 -  const PRUnichar *charIDs = charIDstr.get();
4414 -
4415 -  PRUint32 i;
4416 +  FT_Int has_glyph_name;
4417 +#if defined (MOZ_ENABLE_XFT) || defined (MOZ_ENABLE_PANGO)
4418 +  has_glyph_name = FT_Has_PS_Glyph_Names(aFace);
4419 +#else
4420 +  has_glyph_name = aFt2->hasPSGlyphNames(aFace);
4421 +#endif
4422  
4423    // construct an Encoding vector : the 0th element
4424    // is /.notdef
4425 -  fputs("/Encoding [\n/.notdef\n", aFile); 
4426 -  for (i = 0; i < len; ++i) {
4427 -      fprintf(aFile, "/uni%04X", charIDs[i]); 
4428 -      if (i % 8 == 7) fputc('\n', aFile);
4429 +  fputs("/Encoding [\n/.notdef", aFile); 
4430 +  for (i = aOffset; i < aOffset + aLen; ++i) {
4431 +      nsCString name;
4432 +      char buffer[256];
4433 +
4434 +      if (glyphs.ValueAt(i) == 0) {
4435 +        name = "/.notdef";
4436 +      } else if (!has_glyph_name ||
4437 +#if defined (MOZ_ENABLE_XFT) || defined (MOZ_ENABLE_PANGO)
4438 +                 FT_Get_Glyph_Name(aFace, glyphs.ValueAt(i), buffer, 255) != FT_Err_Ok
4439 +#else
4440 +                 NS_FAILED(aFt2->getGlyphName(aFace, glyphs.ValueAt(i), buffer, 255))
4441 +#endif
4442 +      ) {
4443 +        name = nsPrintfCString(256, "/idx%04X", glyphs.ValueAt(i));
4444 +      } else {
4445 +        name = nsPrintfCString(256, "/%s", buffer);
4446 +      }
4447 +      glyphnames.AppendCString(name);
4448 +      fprintf(aFile, name.get());
4449 +      if ((i-aOffset) % 8 == 6) fputc('\n', aFile);
4450    }
4451  
4452 -  for (i = len; i < 255; ++i) {
4453 +  for (i = PR_MAX (0, 255 - int(aLen)); i; --i) {
4454        fputs("/.notdef", aFile);
4455 -      if (i % 8 == 7) fputc('\n', aFile);
4456 +      if (i % 8 == 1) fputc('\n', aFile);
4457    }
4458    fputs("] def\n", aFile); 
4459  
4460 @@ -630,23 +750,21 @@ outputType1SubFont(nsIFreeType2 *aFt2, F
4461    // get the maximum charstring length without actually filling up the buffer
4462    PRInt32 charStringLen;
4463    PRInt32 maxCharStringLen =
4464 -#ifdef MOZ_ENABLE_XFT
4465 +#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
4466      FT2GlyphToType1CharString(aFace, 0, aWmode, aLenIV, nsnull);
4467  #else
4468      FT2GlyphToType1CharString(aFt2, aFace, 0, aWmode, aLenIV, nsnull);
4469  #endif
4470  
4471 -  PRUint32 glyphID;
4472 -
4473 -  for (i = 0; i < len; i++) {
4474 -#ifdef MOZ_ENABLE_XFT
4475 -    glyphID = FT_Get_Char_Index(aFace, charIDs[i]);
4476 +  for (i = aOffset; i < aOffset + aLen; i++) {
4477 +#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
4478      charStringLen =
4479 -      FT2GlyphToType1CharString(aFace, glyphID, aWmode, aLenIV, nsnull);
4480 +      FT2GlyphToType1CharString(aFace, glyphs.ValueAt(i), aWmode, aLenIV,
4481 +                                nsnull);
4482  #else
4483 -    aFt2->GetCharIndex(aFace, charIDs[i], &glyphID);
4484      charStringLen =
4485 -      FT2GlyphToType1CharString(aFt2, aFace, glyphID, aWmode, aLenIV, nsnull);
4486 +      FT2GlyphToType1CharString(aFt2, aFace, glyphs.ValueAt(i), aWmode, aLenIV,
4487 +                                nsnull);
4488  #endif
4489  
4490      if (charStringLen > maxCharStringLen)
4491 @@ -666,7 +784,7 @@ outputType1SubFont(nsIFreeType2 *aFt2, F
4492                                     len + 1).get()); 
4493  
4494    // output the notdef glyph
4495 -#ifdef MOZ_ENABLE_XFT
4496 +#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
4497    charStringLen = FT2GlyphToType1CharString(aFace, 0, aWmode, aLenIV,
4498                                              charString.get());
4499  #else
4500 @@ -676,22 +794,20 @@ outputType1SubFont(nsIFreeType2 *aFt2, F
4501  
4502    // enclose charString with  "/.notdef RD .....  ND" 
4503    charStringOut(aFile, &pos, &key, NS_REINTERPRET_CAST(const char*, charString.get()),
4504 -                charStringLen, 0); 
4505 +                charStringLen, "/.notdef");
4506  
4507  
4508    // output the charstrings for each glyph in this sub font
4509 -  for (i = 0; i < len; i++) {
4510 -#ifdef MOZ_ENABLE_XFT
4511 -    glyphID = FT_Get_Char_Index(aFace, charIDs[i]);
4512 -    charStringLen = FT2GlyphToType1CharString(aFace, glyphID, aWmode,
4513 +  for (i = aOffset; i < aOffset + aLen; i++) {
4514 +#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
4515 +    charStringLen = FT2GlyphToType1CharString(aFace, glyphs.ValueAt(i), aWmode,
4516                                                aLenIV, charString.get());
4517  #else
4518 -    aFt2->GetCharIndex(aFace, charIDs[i], &glyphID);
4519 -    charStringLen = FT2GlyphToType1CharString(aFt2, aFace, glyphID, aWmode,
4520 -                                              aLenIV, charString.get());
4521 +    charStringLen = FT2GlyphToType1CharString(aFt2, aFace, glyphs.ValueAt(i),
4522 +                                              aWmode, aLenIV, charString.get());
4523  #endif
4524      charStringOut(aFile, &pos, &key, NS_REINTERPRET_CAST(const char*, charString.get()),
4525 -                  charStringLen, charIDs[i]);
4526 +                  charStringLen, glyphnames.CStringAt(i - aOffset)->get());
4527    }
4528  
4529    // wrap up the encrypted part of the font definition
4530 @@ -753,15 +869,12 @@ void encryptAndHexOut(FILE *aFile, PRUin
4531  
4532  /* static */ 
4533  void charStringOut(FILE* aFile,  PRUint32* aPos, PRUint16* aKey, 
4534 -                   const char *aStr, PRUint32 aLen, PRUnichar aId)
4535 +                   const char *aStr, PRUint32 aLen, const char *aGlyphName)
4536  {
4537      // use a local buffer instead of nsPrintfCString to avoid alloc.
4538      char buf[30];
4539      int oLen;
4540 -    if (aId == 0)
4541 -      oLen = PR_snprintf(buf, 30, "/.notdef %d RD ", aLen); 
4542 -    else 
4543 -      oLen = PR_snprintf(buf, 30, "/uni%04X %d RD ", aId, aLen); 
4544 +    oLen = PR_snprintf(buf, 30, "%s %d RD ", aGlyphName, aLen);
4545  
4546      if (oLen >= 30) {
4547        NS_WARNING("buffer size exceeded. charstring will be truncated");
4548 Index: gfx/src/ps/nsType1.h
4549 ===================================================================
4550 RCS file: /cvsroot/mozilla/gfx/src/ps/nsType1.h,v
4551 retrieving revision 1.5
4552 diff -u -p -d -r1.5 nsType1.h
4553 --- gfx/src/ps/nsType1.h        4 Mar 2005 07:39:27 -0000       1.5
4554 +++ gfx/src/ps/nsType1.h        23 Oct 2006 17:37:39 -0000
4555 @@ -122,8 +122,9 @@ FT_Error FT2GlyphToType1CharString(nsIFr
4556  
4557  class nsString;
4558  class nsCString;
4559 +class nsValueArray;
4560  
4561 -PRBool FT2SubsetToType1FontSet(FT_Face aFace, const nsString& aSubset,
4562 +PRBool FT2SubsetToType1FontSet(FT_Face aFace, nsValueArray *aGlyphSubset,
4563                                 int aWmode,  FILE *aFile);
4564  nsresult FT2ToType1FontName(FT_Face aFace, int aWmode,
4565                              nsCString& aFontName);
4566 Index: config/system-headers
4567 ===================================================================
4568 --- config/system-headers       2006-10-26 12:21:39.000000000 -0400
4569 +++ config/system-headers       2006-10-26 12:23:29.000000000 -0400
4570 @@ -199,6 +199,7 @@
4571  freetype/ftoutln.h
4572  freetype/ttnameid.h
4573  freetype/tttables.h
4574 +freetype/t1tables.h
4575  fribidi/fribidi.h
4576  FSp_fopen.h
4577  fstream.h
4578 @@ -501,6 +503,7 @@
4579  pango/pangofc-fontmap.h
4580  pango/pango-fontmap.h
4581  pango/pango.h
4582 +pango/pangoft2.h
4583  pango/pangoxft.h
4584  pango/pangox.h
4585  pango-types.h
4586
This page took 0.520921 seconds and 3 git commands to generate.