Back to index

lightning-sunbird  0.9+nobinonly
mozilla-decoder.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* vim:expandtab:shiftwidth=4:tabstop=4:
00003  */
00004 /* ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is mozilla.org code.
00018  *
00019  * The Initial Developer of the Original Code is Christopher Blizzard
00020  * <blizzard@mozilla.org>.  Portions created by the Initial Developer
00021  * are Copyright (C) 2004 the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #define PANGO_ENABLE_BACKEND
00040 #define PANGO_ENABLE_ENGINE
00041 
00042 #include "mozilla-decoder.h"
00043 #include <pango/pangofc-fontmap.h>
00044 #include <pango/pangofc-font.h>
00045 #include <gdk/gdkpango.h>
00046 
00047 #include "nsString.h"
00048 #include "nsIPersistentProperties2.h"
00049 #include "nsNetUtil.h"
00050 #include "nsReadableUtils.h"
00051 #include "nsICharsetConverterManager.h"
00052 #include "nsICharRepresentable.h"
00053 #include "nsCompressedCharMap.h"
00054 
00055 #undef DEBUG_CUSTOM_ENCODER
00056 
00057 G_DEFINE_TYPE (MozillaDecoder, mozilla_decoder, PANGO_TYPE_FC_DECODER)
00058 
00059 MozillaDecoder *mozilla_decoder_new      (void);
00060 
00061 static FcCharSet  *mozilla_decoder_get_charset (PangoFcDecoder *decoder,
00062                                                 PangoFcFont    *fcfont);
00063 static PangoGlyph  mozilla_decoder_get_glyph   (PangoFcDecoder *decoder,
00064                                                 PangoFcFont    *fcfont,
00065                                                 guint32         wc);
00066 
00067 static PangoFcDecoder *mozilla_find_decoder    (FcPattern *pattern,
00068                                                 gpointer   user_data);
00069 
00070 typedef struct _MozillaDecoderPrivate MozillaDecoderPrivate;
00071 
00072 #define MOZILLA_DECODER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MOZILLA_TYPE_DECODER, MozillaDecoderPrivate))
00073 
00074 struct _MozillaDecoderPrivate {
00075     char *family;
00076     char *encoder;
00077     char *cmap;
00078     gboolean is_wide;
00079     FcCharSet *charset;
00080     nsCOMPtr<nsIUnicodeEncoder> uEncoder;
00081 };
00082 
00083 static nsICharsetConverterManager *gCharsetManager = NULL;
00084 
00085 static NS_DEFINE_CID(kCharsetConverterManagerCID,
00086                      NS_ICHARSETCONVERTERMANAGER_CID);
00087 
00088 // Hash tables that hold the custom encodings and custom cmaps used in
00089 // various fonts.
00090 GHashTable *encoder_hash = NULL;
00091 GHashTable *cmap_hash = NULL;
00092 GHashTable *wide_hash = NULL;
00093 
00094 void
00095 mozilla_decoder_init (MozillaDecoder *decoder)
00096 {
00097 }
00098 
00099 void
00100 mozilla_decoder_class_init (MozillaDecoderClass *klass)
00101 {
00102     GObjectClass *object_class = G_OBJECT_CLASS(klass);
00103     PangoFcDecoderClass *parent_class = PANGO_FC_DECODER_CLASS (klass);
00104 
00105     /*   object_class->finalize = test_finalize; */
00106 
00107     parent_class->get_charset = mozilla_decoder_get_charset;
00108     parent_class->get_glyph = mozilla_decoder_get_glyph;
00109 
00110     g_type_class_add_private (object_class, sizeof (MozillaDecoderPrivate));
00111 }
00112 
00113 MozillaDecoder *
00114 mozilla_decoder_new(void)
00115 {
00116     return (MozillaDecoder *)g_object_new(MOZILLA_TYPE_DECODER, NULL);
00117 }
00118 
00119 #ifdef DEBUG_CUSTOM_ENCODER
00120 void
00121 dump_hash(char *key, char *val, void *arg)
00122 {
00123     printf("%s -> %s\n", key, val);
00124 }
00125 #endif
00126 
00140 int
00141 mozilla_decoders_init(void)
00142 {
00143     static PRBool initialized = PR_FALSE;
00144     if (initialized)
00145         return 0;
00146 
00147     PangoContext* context = gdk_pango_context_get ();
00148     PangoFontMap* fontmap = pango_context_get_font_map (context);
00149     g_object_unref (context);
00150     
00151     if (!PANGO_IS_FC_FONT_MAP (fontmap))
00152         return -1;
00153 
00154     encoder_hash = g_hash_table_new(g_str_hash, g_str_equal);
00155     cmap_hash = g_hash_table_new(g_str_hash, g_str_equal);
00156     wide_hash = g_hash_table_new(g_str_hash, g_str_equal);
00157 
00158     PRBool dumb = PR_FALSE;
00159     nsCOMPtr<nsIPersistentProperties> props;
00160     nsCOMPtr<nsISimpleEnumerator> encodeEnum;
00161 
00162     NS_LoadPersistentPropertiesFromURISpec(getter_AddRefs(props),
00163         NS_LITERAL_CSTRING("resource://gre/res/fonts/pangoFontEncoding.properties"));
00164 
00165     if (!props)
00166         goto loser;
00167 
00168     // Enumerate the properties in this file and figure out all of the
00169     // fonts for which we have custom encodings.
00170     props->Enumerate(getter_AddRefs(encodeEnum));
00171     if (!encodeEnum)
00172         goto loser;
00173 
00174     while (encodeEnum->HasMoreElements(&dumb), dumb) {
00175         nsCOMPtr<nsIPropertyElement> prop;
00176         encodeEnum->GetNext(getter_AddRefs(prop));
00177         if (!prop)
00178             goto loser;
00179 
00180         nsCAutoString name;
00181         prop->GetKey(name);
00182         nsAutoString value;
00183         prop->GetValue(value);
00184 
00185         if (!StringBeginsWith(name, NS_LITERAL_CSTRING("encoding."))) {
00186             printf("string doesn't begin with encoding?\n");
00187             continue;
00188         }
00189 
00190         name = Substring(name, 9);
00191 
00192         if (StringEndsWith(name, NS_LITERAL_CSTRING(".ttf"))) {
00193             name = Substring(name, 0, name.Length() - 4);
00194 
00195             // Strip off a .wide if it's there.
00196             if (StringEndsWith(value, NS_LITERAL_STRING(".wide"))) {
00197                 g_hash_table_insert(wide_hash, g_strdup(name.get()),
00198                                     g_strdup("wide"));
00199                 value = Substring(value, 0, name.Length() - 5);
00200             }
00201 
00202             g_hash_table_insert(encoder_hash,
00203                                 g_strdup(name.get()),
00204                                 g_strdup(NS_ConvertUTF16toUTF8(value).get()));
00205         }
00206         else if (StringEndsWith(name, NS_LITERAL_CSTRING(".ftcmap"))) {
00207             name = Substring(name, 0, name.Length() - 7);
00208             g_hash_table_insert(cmap_hash,
00209                                 g_strdup(name.get()),
00210                                 g_strdup(NS_ConvertUTF16toUTF8(value).get()));
00211         }
00212         else {
00213             printf("unknown suffix used for mapping\n");
00214         }
00215     }
00216 
00217     pango_fc_font_map_add_decoder_find_func(PANGO_FC_FONT_MAP(fontmap),
00218                                             mozilla_find_decoder,
00219                                             NULL,
00220                                             NULL);
00221 
00222     initialized = PR_TRUE;
00223 
00224 #ifdef DEBUG_CUSTOM_ENCODER
00225     printf("*** encoders\n");
00226     g_hash_table_foreach(encoder_hash, (GHFunc)dump_hash, NULL);
00227 
00228     printf("*** cmaps\n");
00229     g_hash_table_foreach(cmap_hash, (GHFunc)dump_hash, NULL);
00230 #endif
00231 
00232     return 0;
00233 
00234  loser:
00235     return -1;
00236 }
00237 
00238 FcCharSet *
00239 mozilla_decoder_get_charset (PangoFcDecoder *decoder,
00240                              PangoFcFont    *fcfont)
00241 {
00242     MozillaDecoderPrivate *priv = MOZILLA_DECODER_GET_PRIVATE(decoder);
00243 
00244     if (priv->charset)
00245         return priv->charset;
00246 
00247     // First time this has been accessed.  Populate the charset.
00248     priv->charset = FcCharSetCreate();
00249 
00250     if (!gCharsetManager) {
00251         CallGetService(kCharsetConverterManagerCID, &gCharsetManager);
00252     }
00253 
00254     nsCOMPtr<nsIUnicodeEncoder> encoder;
00255     nsCOMPtr<nsICharRepresentable> represent;
00256 
00257     if (!gCharsetManager)
00258         goto end;
00259 
00260     gCharsetManager->GetUnicodeEncoderRaw(priv->encoder, getter_AddRefs(encoder));
00261     if (!encoder)
00262         goto end;
00263     
00264     encoder->SetOutputErrorBehavior(encoder->kOnError_Replace, nsnull, '?');
00265 
00266     priv->uEncoder = encoder;
00267 
00268     represent = do_QueryInterface(encoder);
00269     if (!represent)
00270         goto end;
00271 
00272     PRUint32 map[UCS2_MAP_LEN];
00273     memset(map, 0, sizeof(map));
00274 
00275     represent->FillInfo(map);
00276 
00277     for (int i = 0; i < NUM_UNICODE_CHARS; i++) {
00278         if (IS_REPRESENTABLE(map, i))
00279             FcCharSetAddChar(priv->charset, i);
00280     }
00281 
00282  end:
00283     return priv->charset;
00284 }
00285 
00286 PangoGlyph
00287 mozilla_decoder_get_glyph   (PangoFcDecoder *decoder,
00288                              PangoFcFont    *fcfont,
00289                              guint32         wc)
00290 {
00291     MozillaDecoderPrivate *priv = MOZILLA_DECODER_GET_PRIVATE(decoder);
00292 
00293     PangoGlyph retval = 0;
00294     PRUnichar inchar = wc;
00295     PRInt32 inlen = 1;
00296     char outchar[2] = {0,0};
00297     PRInt32 outlen = 2;
00298 
00299     priv->uEncoder->Convert(&inchar, &inlen, outchar, &outlen);
00300     if (outlen != 1) {
00301         printf("Warning: mozilla_decoder_get_glyph doesn't support more than one character conversions.\n");
00302         return 0;
00303     }
00304 
00305     FT_Face face = pango_fc_font_lock_face(fcfont);
00306 
00307 #ifdef DEBUG_CUSTOM_ENCODER
00308     char *filename;
00309     FcPatternGetString(fcfont->font_pattern, FC_FILE, 0, (FcChar8 **)&filename);
00310     printf("filename is %s\n", filename);
00311 #endif
00312 
00313     // Make sure to set the right charmap before trying to get the
00314     // glyph
00315     if (priv->cmap) {
00316         if (!strcmp(priv->cmap, "mac_roman")) {
00317             FT_Select_Charmap(face, ft_encoding_apple_roman);
00318         }
00319         else if (!strcmp(priv->cmap, "unicode")) {
00320             FT_Select_Charmap(face, ft_encoding_unicode);
00321         }
00322         else {
00323             printf("Warning: Invalid charmap entry for family %s\n",
00324                    priv->family);
00325         }
00326     }
00327 
00328     // Standard 8 bit to glyph translation
00329     if (!priv->is_wide) {
00330         FcChar32 blah = PRUint8(outchar[0]);
00331         retval = FT_Get_Char_Index(face, blah);
00332 #ifdef DEBUG_CUSTOM_ENCODER
00333         printf("wc 0x%x outchar[0] 0x%x index 0x%x retval 0x%x face %p\n",
00334                wc, outchar[0], blah, retval, (void *)face);
00335 #endif
00336     }
00337     else {
00338         printf("Warning: We don't support .wide fonts!\n");
00339         retval = 0;
00340     }
00341 
00342     pango_fc_font_unlock_face(fcfont);
00343 
00344     return retval;
00345 }
00346 
00347 PangoFcDecoder *
00348 mozilla_find_decoder (FcPattern *pattern, gpointer user_data)
00349 {
00350     // Compare the family name of the font that's been opened to see
00351     // if we have a custom decoder.
00352     const char *orig = NULL;
00353     FcPatternGetString(pattern, FC_FAMILY, 0, (FcChar8 **)&orig);
00354 
00355     nsCAutoString family;
00356     family.Assign(orig);
00357 
00358     family.StripWhitespace();
00359     ToLowerCase(family);
00360 
00361     char *encoder = (char *)g_hash_table_lookup(encoder_hash, family.get());
00362     if (!encoder)
00363         return NULL;
00364 
00365     MozillaDecoder *decoder = mozilla_decoder_new();
00366 
00367     MozillaDecoderPrivate *priv = MOZILLA_DECODER_GET_PRIVATE(decoder);
00368 
00369     priv->family = g_strdup(family.get());
00370     priv->encoder = g_strdup(encoder);
00371 
00372     char *cmap = (char *)g_hash_table_lookup(cmap_hash, family.get());
00373     if (cmap)
00374         priv->cmap = g_strdup(cmap);
00375 
00376     char *wide = (char *)g_hash_table_lookup(wide_hash, family.get());
00377     if (wide)
00378         priv->is_wide = TRUE;
00379 
00380     return PANGO_FC_DECODER(decoder);
00381 }