Bug 458861. Validate TrueType headers before activating downloaded font. r=roc, sr...
[wine-gecko.git] / gfx / src / thebes / mozilla-decoder.cpp
blob609595f14855cca59183028bae308f8a8a44dc4c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:expandtab:shiftwidth=4:tabstop=4:
3 */
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
15 * License.
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.
23 * Contributor(s):
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>
46 #include <gdk/gdkx.h>
48 #include "nsString.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,
63 PangoFcFont *fcfont);
64 static PangoGlyph mozilla_decoder_get_glyph (PangoFcDecoder *decoder,
65 PangoFcFont *fcfont,
66 guint32 wc);
68 static PangoFcDecoder *mozilla_find_decoder (FcPattern *pattern,
69 gpointer user_data);
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 {
76 char *family;
77 char *encoder;
78 char *cmap;
79 gboolean is_wide;
80 FcCharSet *charset;
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
90 // various fonts.
91 GHashTable *encoder_hash = NULL;
92 GHashTable *cmap_hash = NULL;
93 GHashTable *wide_hash = NULL;
95 void
96 mozilla_decoder_init (MozillaDecoder *decoder)
100 void
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));
114 MozillaDecoder *
115 mozilla_decoder_new(void)
117 return (MozillaDecoder *)g_object_new(MOZILLA_TYPE_DECODER, NULL);
120 #ifdef DEBUG_CUSTOM_ENCODER
121 void
122 dump_hash(char *key, char *val, void *arg)
124 printf("%s -> %s\n", key, val);
126 #endif
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;
145 if (initialized)
146 return 0;
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"));
159 if (!props)
160 goto loser;
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));
165 if (!encodeEnum)
166 goto loser;
168 while (encodeEnum->HasMoreElements(&dumb), dumb) {
169 nsCOMPtr<nsIPropertyElement> prop;
170 encodeEnum->GetNext(getter_AddRefs(prop));
171 if (!prop)
172 goto loser;
174 nsCAutoString name;
175 prop->GetKey(name);
176 nsAutoString value;
177 prop->GetValue(value);
179 if (!StringBeginsWith(name, NS_LITERAL_CSTRING("encoding."))) {
180 printf("string doesn't begin with encoding?\n");
181 continue;
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()),
192 g_strdup("wide"));
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()));
206 else {
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,
213 NULL,
214 NULL);
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);
224 #endif
226 return 0;
228 loser:
229 return -1;
232 FcCharSet *
233 mozilla_decoder_get_charset (PangoFcDecoder *decoder,
234 PangoFcFont *fcfont)
236 MozillaDecoderPrivate *priv = MOZILLA_DECODER_GET_PRIVATE(decoder);
238 if (priv->charset)
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)
252 goto end;
254 gCharsetManager->GetUnicodeEncoderRaw(priv->encoder, getter_AddRefs(encoder));
255 if (!encoder)
256 goto end;
258 encoder->SetOutputErrorBehavior(encoder->kOnError_Replace, nsnull, '?');
260 priv->uEncoder = encoder;
262 represent = do_QueryInterface(encoder);
263 if (!represent)
264 goto end;
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);
276 end:
277 return priv->charset;
280 PangoGlyph
281 mozilla_decoder_get_glyph (PangoFcDecoder *decoder,
282 PangoFcFont *fcfont,
283 guint32 wc)
285 MozillaDecoderPrivate *priv = MOZILLA_DECODER_GET_PRIVATE(decoder);
287 PangoGlyph retval = 0;
288 PRUnichar inchar = wc;
289 PRInt32 inlen = 1;
290 char outchar[2] = {0,0};
291 PRInt32 outlen = 2;
293 priv->uEncoder->Convert(&inchar, &inlen, outchar, &outlen);
294 if (outlen != 1) {
295 printf("Warning: mozilla_decoder_get_glyph doesn't support more than one character conversions.\n");
296 return 0;
299 FT_Face face = pango_fc_font_lock_face(fcfont);
301 #ifdef DEBUG_CUSTOM_ENCODER
302 char *filename;
303 FcPatternGetString(fcfont->font_pattern, FC_FILE, 0, (FcChar8 **)&filename);
304 printf("filename is %s\n", filename);
305 #endif
307 // Make sure to set the right charmap before trying to get the
308 // glyph
309 if (priv->cmap) {
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);
316 else {
317 printf("Warning: Invalid charmap entry for family %s\n",
318 priv->family);
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);
329 #endif
331 else {
332 printf("Warning: We don't support .wide fonts!\n");
333 retval = 0;
336 pango_fc_font_unlock_face(fcfont);
338 return retval;
341 PangoFcDecoder *
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;
350 family.Assign(orig);
352 family.StripWhitespace();
353 ToLowerCase(family);
355 char *encoder = (char *)g_hash_table_lookup(encoder_hash, family.get());
356 if (!encoder)
357 return NULL;
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());
367 if (cmap)
368 priv->cmap = g_strdup(cmap);
370 char *wide = (char *)g_hash_table_lookup(wide_hash, family.get());
371 if (wide)
372 priv->is_wide = TRUE;
374 return PANGO_FC_DECODER(decoder);