1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:expandtab:shiftwidth=4:tabstop=4:
4 /* ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is mozilla.org code.
19 * The Initial Developer of the Original Code is Christopher Blizzard
20 * <blizzard@mozilla.org>. Portions created by the Initial Developer
21 * are Copyright (C) 2004 the Initial Developer. All Rights Reserved.
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #define PANGO_ENABLE_BACKEND
40 #define PANGO_ENABLE_ENGINE
42 #include "mozilla-decoder.h"
43 #include <pango/pangoxft.h>
44 #include <pango/pangofc-fontmap.h>
45 #include <pango/pangofc-font.h>
49 #include "nsIPersistentProperties2.h"
50 #include "nsNetUtil.h"
51 #include "nsReadableUtils.h"
52 #include "nsICharsetConverterManager.h"
53 #include "nsICharRepresentable.h"
54 #include "nsCompressedCharMap.h"
56 #undef DEBUG_CUSTOM_ENCODER
58 G_DEFINE_TYPE (MozillaDecoder
, mozilla_decoder
, PANGO_TYPE_FC_DECODER
)
60 MozillaDecoder
*mozilla_decoder_new (void);
62 static FcCharSet
*mozilla_decoder_get_charset (PangoFcDecoder
*decoder
,
64 static PangoGlyph
mozilla_decoder_get_glyph (PangoFcDecoder
*decoder
,
68 static PangoFcDecoder
*mozilla_find_decoder (FcPattern
*pattern
,
71 typedef struct _MozillaDecoderPrivate MozillaDecoderPrivate
;
73 #define MOZILLA_DECODER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MOZILLA_TYPE_DECODER, MozillaDecoderPrivate))
75 struct _MozillaDecoderPrivate
{
81 nsCOMPtr
<nsIUnicodeEncoder
> uEncoder
;
84 static nsICharsetConverterManager
*gCharsetManager
= NULL
;
86 static NS_DEFINE_CID(kCharsetConverterManagerCID
,
87 NS_ICHARSETCONVERTERMANAGER_CID
);
89 // Hash tables that hold the custom encodings and custom cmaps used in
91 GHashTable
*encoder_hash
= NULL
;
92 GHashTable
*cmap_hash
= NULL
;
93 GHashTable
*wide_hash
= NULL
;
96 mozilla_decoder_init (MozillaDecoder
*decoder
)
101 mozilla_decoder_class_init (MozillaDecoderClass
*klass
)
103 GObjectClass
*object_class
= G_OBJECT_CLASS(klass
);
104 PangoFcDecoderClass
*parent_class
= PANGO_FC_DECODER_CLASS (klass
);
106 /* object_class->finalize = test_finalize; */
108 parent_class
->get_charset
= mozilla_decoder_get_charset
;
109 parent_class
->get_glyph
= mozilla_decoder_get_glyph
;
111 g_type_class_add_private (object_class
, sizeof (MozillaDecoderPrivate
));
115 mozilla_decoder_new(void)
117 return (MozillaDecoder
*)g_object_new(MOZILLA_TYPE_DECODER
, NULL
);
120 #ifdef DEBUG_CUSTOM_ENCODER
122 dump_hash(char *key
, char *val
, void *arg
)
124 printf("%s -> %s\n", key
, val
);
129 * mozilla_decoders_init:
131 * #mozilla_decoders_init:
133 * This initializes all of the application-specific custom decoders
134 * that Mozilla uses. This should only be called once during the
135 * lifetime of the application.
137 * Return value: zero on success, not zero on failure.
142 mozilla_decoders_init(void)
144 static PRBool initialized
= PR_FALSE
;
148 encoder_hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
149 cmap_hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
150 wide_hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
152 PRBool dumb
= PR_FALSE
;
153 nsCOMPtr
<nsIPersistentProperties
> props
;
154 nsCOMPtr
<nsISimpleEnumerator
> encodeEnum
;
156 NS_LoadPersistentPropertiesFromURISpec(getter_AddRefs(props
),
157 NS_LITERAL_CSTRING("resource://gre/res/fonts/pangoFontEncoding.properties"));
162 // Enumerate the properties in this file and figure out all of the
163 // fonts for which we have custom encodings.
164 props
->Enumerate(getter_AddRefs(encodeEnum
));
168 while (encodeEnum
->HasMoreElements(&dumb
), dumb
) {
169 nsCOMPtr
<nsIPropertyElement
> prop
;
170 encodeEnum
->GetNext(getter_AddRefs(prop
));
177 prop
->GetValue(value
);
179 if (!StringBeginsWith(name
, NS_LITERAL_CSTRING("encoding."))) {
180 printf("string doesn't begin with encoding?\n");
184 name
= Substring(name
, 9);
186 if (StringEndsWith(name
, NS_LITERAL_CSTRING(".ttf"))) {
187 name
= Substring(name
, 0, name
.Length() - 4);
189 // Strip off a .wide if it's there.
190 if (StringEndsWith(value
, NS_LITERAL_STRING(".wide"))) {
191 g_hash_table_insert(wide_hash
, g_strdup(name
.get()),
193 value
= Substring(value
, 0, name
.Length() - 5);
196 g_hash_table_insert(encoder_hash
,
197 g_strdup(name
.get()),
198 g_strdup(NS_ConvertUTF16toUTF8(value
).get()));
200 else if (StringEndsWith(name
, NS_LITERAL_CSTRING(".ftcmap"))) {
201 name
= Substring(name
, 0, name
.Length() - 7);
202 g_hash_table_insert(cmap_hash
,
203 g_strdup(name
.get()),
204 g_strdup(NS_ConvertUTF16toUTF8(value
).get()));
207 printf("unknown suffix used for mapping\n");
211 pango_fc_font_map_add_decoder_find_func(PANGO_FC_FONT_MAP(pango_xft_get_font_map(GDK_DISPLAY(),gdk_x11_get_default_screen())),
212 mozilla_find_decoder
,
216 initialized
= PR_TRUE
;
218 #ifdef DEBUG_CUSTOM_ENCODER
219 printf("*** encoders\n");
220 g_hash_table_foreach(encoder_hash
, (GHFunc
)dump_hash
, NULL
);
222 printf("*** cmaps\n");
223 g_hash_table_foreach(cmap_hash
, (GHFunc
)dump_hash
, NULL
);
233 mozilla_decoder_get_charset (PangoFcDecoder
*decoder
,
236 MozillaDecoderPrivate
*priv
= MOZILLA_DECODER_GET_PRIVATE(decoder
);
239 return priv
->charset
;
241 // First time this has been accessed. Populate the charset.
242 priv
->charset
= FcCharSetCreate();
244 if (!gCharsetManager
) {
245 CallGetService(kCharsetConverterManagerCID
, &gCharsetManager
);
248 nsCOMPtr
<nsIUnicodeEncoder
> encoder
;
249 nsCOMPtr
<nsICharRepresentable
> represent
;
251 if (!gCharsetManager
)
254 gCharsetManager
->GetUnicodeEncoderRaw(priv
->encoder
, getter_AddRefs(encoder
));
258 encoder
->SetOutputErrorBehavior(encoder
->kOnError_Replace
, nsnull
, '?');
260 priv
->uEncoder
= encoder
;
262 represent
= do_QueryInterface(encoder
);
266 PRUint32 map
[UCS2_MAP_LEN
];
267 memset(map
, 0, sizeof(map
));
269 represent
->FillInfo(map
);
271 for (int i
= 0; i
< NUM_UNICODE_CHARS
; i
++) {
272 if (IS_REPRESENTABLE(map
, i
))
273 FcCharSetAddChar(priv
->charset
, i
);
277 return priv
->charset
;
281 mozilla_decoder_get_glyph (PangoFcDecoder
*decoder
,
285 MozillaDecoderPrivate
*priv
= MOZILLA_DECODER_GET_PRIVATE(decoder
);
287 PangoGlyph retval
= 0;
288 PRUnichar inchar
= wc
;
290 char outchar
[2] = {0,0};
293 priv
->uEncoder
->Convert(&inchar
, &inlen
, outchar
, &outlen
);
295 printf("Warning: mozilla_decoder_get_glyph doesn't support more than one character conversions.\n");
299 FT_Face face
= pango_fc_font_lock_face(fcfont
);
301 #ifdef DEBUG_CUSTOM_ENCODER
303 FcPatternGetString(fcfont
->font_pattern
, FC_FILE
, 0, (FcChar8
**)&filename
);
304 printf("filename is %s\n", filename
);
307 // Make sure to set the right charmap before trying to get the
310 if (!strcmp(priv
->cmap
, "mac_roman")) {
311 FT_Select_Charmap(face
, ft_encoding_apple_roman
);
313 else if (!strcmp(priv
->cmap
, "unicode")) {
314 FT_Select_Charmap(face
, ft_encoding_unicode
);
317 printf("Warning: Invalid charmap entry for family %s\n",
322 // Standard 8 bit to glyph translation
323 if (!priv
->is_wide
) {
324 FcChar32 blah
= PRUint8(outchar
[0]);
325 retval
= FT_Get_Char_Index(face
, blah
);
326 #ifdef DEBUG_CUSTOM_ENCODER
327 printf("wc 0x%x outchar[0] 0x%x index 0x%x retval 0x%x face %p\n",
328 wc
, outchar
[0], blah
, retval
, (void *)face
);
332 printf("Warning: We don't support .wide fonts!\n");
336 pango_fc_font_unlock_face(fcfont
);
342 mozilla_find_decoder (FcPattern
*pattern
, gpointer user_data
)
344 // Compare the family name of the font that's been opened to see
345 // if we have a custom decoder.
346 const char *orig
= NULL
;
347 FcPatternGetString(pattern
, FC_FAMILY
, 0, (FcChar8
**)&orig
);
349 nsCAutoString family
;
352 family
.StripWhitespace();
355 char *encoder
= (char *)g_hash_table_lookup(encoder_hash
, family
.get());
359 MozillaDecoder
*decoder
= mozilla_decoder_new();
361 MozillaDecoderPrivate
*priv
= MOZILLA_DECODER_GET_PRIVATE(decoder
);
363 priv
->family
= g_strdup(family
.get());
364 priv
->encoder
= g_strdup(encoder
);
366 char *cmap
= (char *)g_hash_table_lookup(cmap_hash
, family
.get());
368 priv
->cmap
= g_strdup(cmap
);
370 char *wide
= (char *)g_hash_table_lookup(wide_hash
, family
.get());
372 priv
->is_wide
= TRUE
;
374 return PANGO_FC_DECODER(decoder
);