4587 lines
151 KiB
Diff
4587 lines
151 KiB
Diff
Patch for Firefox 1.5.0.7 to add support for printing via Pango.
|
|
This also implements printing MathML via Pango, and prints bitmap
|
|
fonts too.
|
|
|
|
Authors:
|
|
Behdad Esfahbod
|
|
Chris Blizzard
|
|
Akira TAGOH
|
|
|
|
Index: gfx/src/freetype/nsFreeType.cpp
|
|
===================================================================
|
|
RCS file: /cvsroot/mozilla/gfx/src/freetype/nsFreeType.cpp,v
|
|
retrieving revision 1.28
|
|
diff -u -p -d -r1.28 nsFreeType.cpp
|
|
--- gfx/src/freetype/nsFreeType.cpp 13 Jul 2005 18:21:10 -0000 1.28
|
|
+++ gfx/src/freetype/nsFreeType.cpp 23 Oct 2006 17:37:09 -0000
|
|
@@ -123,6 +123,8 @@ FtFuncList nsFreeType2::FtFuncs [] = {
|
|
// #endif
|
|
{"FT_Get_First_Char", NS_FT2_OFFSET(nsFT_Get_First_Char), PR_FALSE},
|
|
{"FT_Get_Next_Char", NS_FT2_OFFSET(nsFT_Get_Next_Char), PR_FALSE},
|
|
+ {"FT_Has_PS_Glyph_Names", NS_FT2_OFFSET(nsFT_Has_PS_Glyph_Names), PR_FALSE},
|
|
+ {"FT_Get_Glyph_Name", NS_FT2_OFFSET(nsFT_Get_Glyph_Name), PR_TRUE},
|
|
{nsnull, 0, 0}
|
|
};
|
|
|
|
@@ -388,6 +390,22 @@ nsFreeType2::GetNextChar(FT_Face face, F
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
+nsFreeType2::HasPSGlyphNames(FT_Face face, FT_Int *result)
|
|
+{
|
|
+ // call the FreeType2 function via the function pointer
|
|
+ *result = nsFT_Has_PS_Glyph_Names(face);
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFreeType2::GetGlyphName(FT_Face face, FT_UInt glyph_index, FT_Pointer buffer, FT_UInt buffer_max)
|
|
+{
|
|
+ // call the FreeType2 function via the function pointer
|
|
+ FT_Error error = nsFT_Get_Glyph_Name(face, glyph_index, buffer, buffer_max);
|
|
+ return error ? NS_ERROR_FAILURE : NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
nsFreeType2::SupportsExtFunc(PRBool *res)
|
|
{
|
|
*res = gHasExtFunc;
|
|
Index: gfx/src/freetype/nsFreeType.h
|
|
===================================================================
|
|
RCS file: /cvsroot/mozilla/gfx/src/freetype/nsFreeType.h,v
|
|
retrieving revision 1.18
|
|
diff -u -p -d -r1.18 nsFreeType.h
|
|
--- gfx/src/freetype/nsFreeType.h 1 May 2005 17:36:19 -0000 1.18
|
|
+++ gfx/src/freetype/nsFreeType.h 23 Oct 2006 17:37:09 -0000
|
|
@@ -52,6 +52,7 @@
|
|
#include FT_CACHE_H
|
|
#include FT_CACHE_IMAGE_H
|
|
#include FT_TRUETYPE_TABLES_H
|
|
+#include FT_TYPE1_TABLES_H
|
|
#include "nsIFreeType2.h"
|
|
|
|
typedef struct FT_FaceRec_* FT_Face;
|
|
@@ -138,6 +139,8 @@ typedef FT_Error (*FT_Glyph_To_Bitmap_t)
|
|
|
|
typedef FT_ULong (*FT_Get_First_Char_t)(FT_Face, FT_UInt*);
|
|
typedef FT_ULong (*FT_Get_Next_Char_t)(FT_Face, FT_ULong, FT_UInt*);
|
|
+typedef FT_Int (*FT_Has_PS_Glyph_Names_t)(FT_Face);
|
|
+typedef FT_Error (*FT_Get_Glyph_Name_t)(FT_Face, FT_UInt, FT_Pointer, FT_UInt);
|
|
|
|
class nsFreeTypeFace;
|
|
|
|
@@ -193,11 +196,13 @@ protected:
|
|
// #endif
|
|
FT_Get_First_Char_t nsFT_Get_First_Char;
|
|
FT_Get_Next_Char_t nsFT_Get_Next_Char;
|
|
+ FT_Has_PS_Glyph_Names_t nsFT_Has_PS_Glyph_Names;
|
|
+ FT_Get_Glyph_Name_t nsFT_Get_Glyph_Name;
|
|
|
|
// this array needs to be big enough to hold all the function pointers
|
|
// plus one extra for the null at the end
|
|
// #ifdef MOZ_SVG
|
|
- static FtFuncList FtFuncs[24];
|
|
+ static FtFuncList FtFuncs[28];
|
|
// #else
|
|
// static FtFuncList FtFuncs[20];
|
|
// #endif
|
|
Index: gfx/src/ps/Makefile.in
|
|
===================================================================
|
|
RCS file: /cvsroot/mozilla/gfx/src/ps/Makefile.in,v
|
|
retrieving revision 1.57.8.1
|
|
diff -d -u -p -r1.57.8.1 Makefile.in
|
|
--- gfx/src/ps/Makefile.in 17 Jun 2006 15:16:14 -0000 1.57.8.1
|
|
+++ gfx/src/ps/Makefile.in 24 Oct 2006 18:36:45 -0000
|
|
@@ -98,6 +98,15 @@ EXTRA_DSO_LDOPTS = \
|
|
$(MOZ_UNICHARUTIL_LIBS) \
|
|
$(NULL)
|
|
|
|
+ifdef MOZ_ENABLE_PANGO
|
|
+CPPSRCS += \
|
|
+ nsFontMetricsPSPango.cpp \
|
|
+ mozilla-ps-decoder.cpp
|
|
+EXTRA_DSO_LDOPTS += $(MOZ_PANGO_LIBS)
|
|
+CXXFLAGS += $(MOZ_PANGO_CFLAGS)
|
|
+CFLAGS += $(MOZ_PANGO_CFLAGS)
|
|
+endif
|
|
+
|
|
ifdef MOZ_ENABLE_XFT
|
|
EXTRA_DSO_LDOPTS += \
|
|
$(MOZ_XFT_LIBS) \
|
|
@@ -105,7 +114,7 @@ EXTRA_DSO_LDOPTS += \
|
|
$(NULL)
|
|
endif
|
|
|
|
-ifneq (,$(MOZ_ENABLE_FREETYPE2)$(MOZ_ENABLE_XFT))
|
|
+ifneq (,$(MOZ_ENABLE_FREETYPE2)$(MOZ_ENABLE_XFT)$(MOZ_ENABLE_PANGO))
|
|
CPPSRCS += \
|
|
nsType1.cpp \
|
|
$(NULL)
|
|
Index: gfx/src/ps/mozilla-ps-decoder.cpp
|
|
===================================================================
|
|
RCS file: gfx/src/ps/mozilla-ps-decoder.cpp
|
|
diff -N gfx/src/ps/mozilla-ps-decoder.cpp
|
|
--- /dev/null 1 Jan 1970 00:00:00 -0000
|
|
+++ gfx/src/ps/mozilla-ps-decoder.cpp 23 Oct 2006 17:37:10 -0000
|
|
@@ -0,0 +1,376 @@
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
+ */
|
|
+/* ***** BEGIN LICENSE BLOCK *****
|
|
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
+ *
|
|
+ * The contents of this file are subject to the Mozilla Public License Version
|
|
+ * 1.1 (the "License"); you may not use this file except in compliance with
|
|
+ * the License. You may obtain a copy of the License at
|
|
+ * http://www.mozilla.org/MPL/
|
|
+ *
|
|
+ * Software distributed under the License is distributed on an "AS IS" basis,
|
|
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
+ * for the specific language governing rights and limitations under the
|
|
+ * License.
|
|
+ *
|
|
+ * The Original Code is mozilla.org code.
|
|
+ *
|
|
+ * The Initial Developer of the Original Code is Christopher Blizzard
|
|
+ * <blizzard@mozilla.org>. Portions created by the Initial Developer
|
|
+ * are Copyright (C) 2004 the Initial Developer. All Rights Reserved.
|
|
+ *
|
|
+ * Contributor(s):
|
|
+ *
|
|
+ * Alternatively, the contents of this file may be used under the terms of
|
|
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
+ * in which case the provisions of the GPL or the LGPL are applicable instead
|
|
+ * of those above. If you wish to allow use of your version of this file only
|
|
+ * under the terms of either the GPL or the LGPL, and not to allow others to
|
|
+ * use your version of this file under the terms of the MPL, indicate your
|
|
+ * decision by deleting the provisions above and replace them with the notice
|
|
+ * and other provisions required by the GPL or the LGPL. If you do not delete
|
|
+ * the provisions above, a recipient may use your version of this file under
|
|
+ * the terms of any one of the MPL, the GPL or the LGPL.
|
|
+ *
|
|
+ * ***** END LICENSE BLOCK ***** */
|
|
+
|
|
+#define PANGO_ENABLE_BACKEND
|
|
+#define PANGO_ENABLE_ENGINE
|
|
+
|
|
+#include "mozilla-ps-decoder.h"
|
|
+#include <pango/pangofc-fontmap.h>
|
|
+#include <pango/pangofc-font.h>
|
|
+
|
|
+#include "nsString.h"
|
|
+#include "nsIPersistentProperties2.h"
|
|
+#include "nsNetUtil.h"
|
|
+#include "nsReadableUtils.h"
|
|
+#include "nsICharsetConverterManager.h"
|
|
+#include "nsICharRepresentable.h"
|
|
+#include "nsCompressedCharMap.h"
|
|
+
|
|
+#undef DEBUG_CUSTOM_ENCODER
|
|
+
|
|
+G_DEFINE_TYPE (MozillaPSDecoder, mozilla_ps_decoder, PANGO_TYPE_FC_DECODER)
|
|
+
|
|
+MozillaPSDecoder *mozilla_ps_decoder_new (void);
|
|
+
|
|
+static FcCharSet *mozilla_ps_decoder_get_charset (PangoFcDecoder *decoder,
|
|
+ PangoFcFont *fcfont);
|
|
+static PangoGlyph mozilla_ps_decoder_get_glyph (PangoFcDecoder *decoder,
|
|
+ PangoFcFont *fcfont,
|
|
+ guint32 wc);
|
|
+
|
|
+static PangoFcDecoder *mozilla_find_ps_decoder (FcPattern *pattern,
|
|
+ gpointer user_data);
|
|
+
|
|
+typedef struct _MozillaPSDecoderPrivate MozillaPSDecoderPrivate;
|
|
+
|
|
+#define MOZILLA_PS_DECODER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MOZILLA_TYPE_DECODER, MozillaPSDecoderPrivate))
|
|
+
|
|
+struct _MozillaPSDecoderPrivate {
|
|
+ char *family;
|
|
+ char *encoder;
|
|
+ char *cmap;
|
|
+ gboolean is_wide;
|
|
+ FcCharSet *charset;
|
|
+ nsCOMPtr<nsIUnicodeEncoder> uEncoder;
|
|
+};
|
|
+
|
|
+static nsICharsetConverterManager *gCharsetManager = NULL;
|
|
+
|
|
+static NS_DEFINE_CID(kCharsetConverterManagerCID,
|
|
+ NS_ICHARSETCONVERTERMANAGER_CID);
|
|
+
|
|
+// Hash tables that hold the custom encodings and custom cmaps used in
|
|
+// various fonts.
|
|
+static GHashTable *encoder_hash = NULL;
|
|
+static GHashTable *cmap_hash = NULL;
|
|
+static GHashTable *wide_hash = NULL;
|
|
+
|
|
+void
|
|
+mozilla_ps_decoder_init (MozillaPSDecoder *decoder)
|
|
+{
|
|
+}
|
|
+
|
|
+void
|
|
+mozilla_ps_decoder_class_init (MozillaPSDecoderClass *klass)
|
|
+{
|
|
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
|
+ PangoFcDecoderClass *parent_class = PANGO_FC_DECODER_CLASS (klass);
|
|
+
|
|
+ /* object_class->finalize = test_finalize; */
|
|
+
|
|
+ parent_class->get_charset = mozilla_ps_decoder_get_charset;
|
|
+ parent_class->get_glyph = mozilla_ps_decoder_get_glyph;
|
|
+
|
|
+ g_type_class_add_private (object_class, sizeof (MozillaPSDecoderPrivate));
|
|
+}
|
|
+
|
|
+MozillaPSDecoder *
|
|
+mozilla_ps_decoder_new(void)
|
|
+{
|
|
+ return (MozillaPSDecoder *)g_object_new(MOZILLA_TYPE_DECODER, NULL);
|
|
+}
|
|
+
|
|
+#ifdef DEBUG_CUSTOM_ENCODER
|
|
+void
|
|
+dump_hash(char *key, char *val, void *arg)
|
|
+{
|
|
+ printf("%s -> %s\n", key, val);
|
|
+}
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * mozilla_ps_decoders_init:
|
|
+ *
|
|
+ * #mozilla_ps_decoders_init:
|
|
+ *
|
|
+ * This initializes all of the application-specific custom decoders
|
|
+ * that Mozilla uses. This should only be called once during the
|
|
+ * lifetime of the application.
|
|
+ *
|
|
+ * Return value: zero on success, not zero on failure.
|
|
+ *
|
|
+ **/
|
|
+
|
|
+int
|
|
+mozilla_ps_decoders_init(PangoFontMap *fontmap)
|
|
+{
|
|
+ static PRBool initialized = PR_FALSE;
|
|
+ if (initialized)
|
|
+ return 0;
|
|
+
|
|
+ if (!PANGO_IS_FC_FONT_MAP (fontmap))
|
|
+ return -1;
|
|
+
|
|
+ encoder_hash = g_hash_table_new(g_str_hash, g_str_equal);
|
|
+ cmap_hash = g_hash_table_new(g_str_hash, g_str_equal);
|
|
+ wide_hash = g_hash_table_new(g_str_hash, g_str_equal);
|
|
+
|
|
+ PRBool dumb = PR_FALSE;
|
|
+ nsCOMPtr<nsIPersistentProperties> props;
|
|
+ nsCOMPtr<nsISimpleEnumerator> encodeEnum;
|
|
+
|
|
+ NS_LoadPersistentPropertiesFromURISpec(getter_AddRefs(props),
|
|
+ NS_LITERAL_CSTRING("resource://gre/res/fonts/pangoFontEncoding.properties"));
|
|
+
|
|
+ if (!props)
|
|
+ goto loser;
|
|
+
|
|
+ // Enumerate the properties in this file and figure out all of the
|
|
+ // fonts for which we have custom encodings.
|
|
+ props->Enumerate(getter_AddRefs(encodeEnum));
|
|
+ if (!encodeEnum)
|
|
+ goto loser;
|
|
+
|
|
+ while (encodeEnum->HasMoreElements(&dumb), dumb) {
|
|
+ nsCOMPtr<nsIPropertyElement> prop;
|
|
+ encodeEnum->GetNext(getter_AddRefs(prop));
|
|
+ if (!prop)
|
|
+ goto loser;
|
|
+
|
|
+ nsCAutoString name;
|
|
+ prop->GetKey(name);
|
|
+ nsAutoString value;
|
|
+ prop->GetValue(value);
|
|
+
|
|
+ if (!StringBeginsWith(name, NS_LITERAL_CSTRING("encoding."))) {
|
|
+ printf("string doesn't begin with encoding?\n");
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ name = Substring(name, 9);
|
|
+
|
|
+ if (StringEndsWith(name, NS_LITERAL_CSTRING(".ttf"))) {
|
|
+ name = Substring(name, 0, name.Length() - 4);
|
|
+
|
|
+ // Strip off a .wide if it's there.
|
|
+ if (StringEndsWith(value, NS_LITERAL_STRING(".wide"))) {
|
|
+ g_hash_table_insert(wide_hash, g_strdup(name.get()),
|
|
+ g_strdup("wide"));
|
|
+ value = Substring(value, 0, name.Length() - 5);
|
|
+ }
|
|
+
|
|
+ g_hash_table_insert(encoder_hash,
|
|
+ g_strdup(name.get()),
|
|
+ g_strdup(NS_ConvertUTF16toUTF8(value).get()));
|
|
+ }
|
|
+ else if (StringEndsWith(name, NS_LITERAL_CSTRING(".ftcmap"))) {
|
|
+ name = Substring(name, 0, name.Length() - 7);
|
|
+ g_hash_table_insert(cmap_hash,
|
|
+ g_strdup(name.get()),
|
|
+ g_strdup(NS_ConvertUTF16toUTF8(value).get()));
|
|
+ }
|
|
+ else {
|
|
+ printf("unknown suffix used for mapping\n");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ pango_fc_font_map_add_decoder_find_func(PANGO_FC_FONT_MAP(fontmap),
|
|
+ mozilla_find_ps_decoder,
|
|
+ NULL,
|
|
+ NULL);
|
|
+
|
|
+ initialized = PR_TRUE;
|
|
+
|
|
+#ifdef DEBUG_CUSTOM_ENCODER
|
|
+ printf("*** encoders\n");
|
|
+ g_hash_table_foreach(encoder_hash, (GHFunc)dump_hash, NULL);
|
|
+
|
|
+ printf("*** cmaps\n");
|
|
+ g_hash_table_foreach(cmap_hash, (GHFunc)dump_hash, NULL);
|
|
+#endif
|
|
+
|
|
+ return 0;
|
|
+
|
|
+ loser:
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static FcCharSet *
|
|
+mozilla_ps_decoder_get_charset (PangoFcDecoder *decoder,
|
|
+ PangoFcFont *fcfont)
|
|
+{
|
|
+ MozillaPSDecoderPrivate *priv = MOZILLA_PS_DECODER_GET_PRIVATE(decoder);
|
|
+
|
|
+ if (priv->charset)
|
|
+ return priv->charset;
|
|
+
|
|
+ // First time this has been accessed. Populate the charset.
|
|
+ priv->charset = FcCharSetCreate();
|
|
+
|
|
+ if (!gCharsetManager) {
|
|
+ CallGetService(kCharsetConverterManagerCID, &gCharsetManager);
|
|
+ }
|
|
+
|
|
+ nsCOMPtr<nsIUnicodeEncoder> encoder;
|
|
+ nsCOMPtr<nsICharRepresentable> represent;
|
|
+
|
|
+ if (!gCharsetManager)
|
|
+ goto end;
|
|
+
|
|
+ gCharsetManager->GetUnicodeEncoderRaw(priv->encoder, getter_AddRefs(encoder));
|
|
+ if (!encoder)
|
|
+ goto end;
|
|
+
|
|
+ encoder->SetOutputErrorBehavior(encoder->kOnError_Replace, nsnull, '?');
|
|
+
|
|
+ priv->uEncoder = encoder;
|
|
+
|
|
+ represent = do_QueryInterface(encoder);
|
|
+ if (!represent)
|
|
+ goto end;
|
|
+
|
|
+ PRUint32 map[UCS2_MAP_LEN];
|
|
+ memset(map, 0, sizeof(map));
|
|
+
|
|
+ represent->FillInfo(map);
|
|
+
|
|
+ for (int i = 0; i < NUM_UNICODE_CHARS; i++) {
|
|
+ if (IS_REPRESENTABLE(map, i))
|
|
+ FcCharSetAddChar(priv->charset, i);
|
|
+ }
|
|
+
|
|
+ end:
|
|
+ return priv->charset;
|
|
+}
|
|
+
|
|
+static PangoGlyph
|
|
+mozilla_ps_decoder_get_glyph (PangoFcDecoder *decoder,
|
|
+ PangoFcFont *fcfont,
|
|
+ guint32 wc)
|
|
+{
|
|
+ MozillaPSDecoderPrivate *priv = MOZILLA_PS_DECODER_GET_PRIVATE(decoder);
|
|
+
|
|
+ PangoGlyph retval = 0;
|
|
+ PRUnichar inchar = wc;
|
|
+ PRInt32 inlen = 1;
|
|
+ char outchar[2] = {0,0};
|
|
+ PRInt32 outlen = 2;
|
|
+
|
|
+ priv->uEncoder->Convert(&inchar, &inlen, outchar, &outlen);
|
|
+ if (outlen != 1) {
|
|
+ printf("Warning: mozilla_ps_decoder_get_glyph doesn't support more than one character conversions.\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ FT_Face face = pango_fc_font_lock_face(fcfont);
|
|
+
|
|
+#ifdef DEBUG_CUSTOM_ENCODER
|
|
+ char *filename;
|
|
+ FcPatternGetString(fcfont->font_pattern, FC_FILE, 0, (FcChar8 **)&filename);
|
|
+ printf("filename is %s\n", filename);
|
|
+#endif
|
|
+
|
|
+ // Make sure to set the right charmap before trying to get the
|
|
+ // glyph
|
|
+ if (priv->cmap) {
|
|
+ if (!strcmp(priv->cmap, "mac_roman")) {
|
|
+ FT_Select_Charmap(face, ft_encoding_apple_roman);
|
|
+ }
|
|
+ else if (!strcmp(priv->cmap, "unicode")) {
|
|
+ FT_Select_Charmap(face, ft_encoding_unicode);
|
|
+ }
|
|
+ else {
|
|
+ printf("Warning: Invalid charmap entry for family %s\n",
|
|
+ priv->family);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Standard 8 bit to glyph translation
|
|
+ if (!priv->is_wide) {
|
|
+ FcChar32 blah = PRUint8(outchar[0]);
|
|
+ retval = FT_Get_Char_Index(face, blah);
|
|
+#ifdef DEBUG_CUSTOM_ENCODER
|
|
+ printf("wc 0x%x outchar[0] 0x%x index 0x%x retval 0x%x face %p\n",
|
|
+ wc, outchar[0], blah, retval, (void *)face);
|
|
+#endif
|
|
+ }
|
|
+ else {
|
|
+ printf("Warning: We don't support .wide fonts!\n");
|
|
+ retval = 0;
|
|
+ }
|
|
+
|
|
+ pango_fc_font_unlock_face(fcfont);
|
|
+
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+static PangoFcDecoder *
|
|
+mozilla_find_ps_decoder (FcPattern *pattern, gpointer user_data)
|
|
+{
|
|
+ // Compare the family name of the font that's been opened to see
|
|
+ // if we have a custom decoder.
|
|
+ const char *orig = NULL;
|
|
+ FcPatternGetString(pattern, FC_FAMILY, 0, (FcChar8 **)&orig);
|
|
+
|
|
+ nsCAutoString family;
|
|
+ family.Assign(orig);
|
|
+
|
|
+ family.StripWhitespace();
|
|
+ ToLowerCase(family);
|
|
+
|
|
+ char *encoder = (char *)g_hash_table_lookup(encoder_hash, family.get());
|
|
+ if (!encoder)
|
|
+ return NULL;
|
|
+
|
|
+ MozillaPSDecoder *decoder = mozilla_ps_decoder_new();
|
|
+
|
|
+ MozillaPSDecoderPrivate *priv = MOZILLA_PS_DECODER_GET_PRIVATE(decoder);
|
|
+
|
|
+ priv->family = g_strdup(family.get());
|
|
+ priv->encoder = g_strdup(encoder);
|
|
+
|
|
+ char *cmap = (char *)g_hash_table_lookup(cmap_hash, family.get());
|
|
+ if (cmap)
|
|
+ priv->cmap = g_strdup(cmap);
|
|
+
|
|
+ char *wide = (char *)g_hash_table_lookup(wide_hash, family.get());
|
|
+ if (wide)
|
|
+ priv->is_wide = TRUE;
|
|
+
|
|
+ return PANGO_FC_DECODER(decoder);
|
|
+}
|
|
Index: gfx/src/ps/mozilla-ps-decoder.h
|
|
===================================================================
|
|
RCS file: gfx/src/ps/mozilla-ps-decoder.h
|
|
diff -N gfx/src/ps/mozilla-ps-decoder.h
|
|
--- /dev/null 1 Jan 1970 00:00:00 -0000
|
|
+++ gfx/src/ps/mozilla-ps-decoder.h 23 Oct 2006 17:37:10 -0000
|
|
@@ -0,0 +1,72 @@
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
+ */
|
|
+/* ***** BEGIN LICENSE BLOCK *****
|
|
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
+ *
|
|
+ * The contents of this file are subject to the Mozilla Public License Version
|
|
+ * 1.1 (the "License"); you may not use this file except in compliance with
|
|
+ * the License. You may obtain a copy of the License at
|
|
+ * http://www.mozilla.org/MPL/
|
|
+ *
|
|
+ * Software distributed under the License is distributed on an "AS IS" basis,
|
|
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
+ * for the specific language governing rights and limitations under the
|
|
+ * License.
|
|
+ *
|
|
+ * The Original Code is mozilla.org code.
|
|
+ *
|
|
+ * The Initial Developer of the Original Code is Christopher Blizzard
|
|
+ * <blizzard@mozilla.org>. Portions created by the Initial Developer
|
|
+ * are Copyright (C) 2004 the Initial Developer. All Rights Reserved.
|
|
+ *
|
|
+ * Contributor(s):
|
|
+ *
|
|
+ * Alternatively, the contents of this file may be used under the terms of
|
|
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
+ * in which case the provisions of the GPL or the LGPL are applicable instead
|
|
+ * of those above. If you wish to allow use of your version of this file only
|
|
+ * under the terms of either the GPL or the LGPL, and not to allow others to
|
|
+ * use your version of this file under the terms of the MPL, indicate your
|
|
+ * decision by deleting the provisions above and replace them with the notice
|
|
+ * and other provisions required by the GPL or the LGPL. If you do not delete
|
|
+ * the provisions above, a recipient may use your version of this file under
|
|
+ * the terms of any one of the MPL, the GPL or the LGPL.
|
|
+ *
|
|
+ * ***** END LICENSE BLOCK ***** */
|
|
+
|
|
+#ifndef _MOZILLA_PS_DECODER_H
|
|
+#define _MOZILLA_PS_DECODER_H
|
|
+
|
|
+#include <pango/pangofc-decoder.h>
|
|
+
|
|
+G_BEGIN_DECLS
|
|
+
|
|
+#define MOZILLA_TYPE_DECODER (mozilla_ps_decoder_get_type())
|
|
+#define MOZILLA_PS_DECODER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOZILLA_TYPE_DECODER, MozillaPSDecoder))
|
|
+#define MOZILLA_IS_DECODER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOZILLA_TYPE_DECODER))
|
|
+
|
|
+typedef struct _MozillaPSDecoder MozillaPSDecoder;
|
|
+typedef struct _MozillaPSDecoderClass MozillaPSDecoderClass;
|
|
+
|
|
+#define MOZILLA_PS_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOZILLA_TYPE_DECODER, MozillaPSDecoderClass))
|
|
+#define MOZILLA_IS_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOZILLA_TYPE_DECODER))
|
|
+#define MOZILLA_PS_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOZILLA_TYPE_DECODER, MozillaPSDecoderClass))
|
|
+
|
|
+struct _MozillaPSDecoder
|
|
+{
|
|
+ PangoFcDecoder parent_instance;
|
|
+};
|
|
+
|
|
+struct _MozillaPSDecoderClass
|
|
+{
|
|
+ PangoFcDecoderClass parent_class;
|
|
+};
|
|
+
|
|
+GType mozilla_ps_decoder_get_type (void);
|
|
+int mozilla_ps_decoders_init (PangoFontMap *fontmap);
|
|
+
|
|
+G_END_DECLS
|
|
+
|
|
+#endif /*_MOZILLA_PS_DECODER_H */
|
|
Index: gfx/src/ps/nsDeviceContextPS.cpp
|
|
===================================================================
|
|
RCS file: /cvsroot/mozilla/gfx/src/ps/nsDeviceContextPS.cpp,v
|
|
retrieving revision 1.73
|
|
diff -u -p -d -r1.73 nsDeviceContextPS.cpp
|
|
--- gfx/src/ps/nsDeviceContextPS.cpp 21 May 2005 15:33:08 -0000 1.73
|
|
+++ gfx/src/ps/nsDeviceContextPS.cpp 23 Oct 2006 17:37:10 -0000
|
|
@@ -58,12 +58,15 @@
|
|
#include "nsIPref.h"
|
|
#include "nsString.h"
|
|
#include "nsFontMetricsPS.h"
|
|
+#ifdef MOZ_ENABLE_PANGO
|
|
+#include "nsFontMetricsPSPango.h"
|
|
+#endif
|
|
#include "nsPostScriptObj.h"
|
|
#include "nspr.h"
|
|
#include "nsILanguageAtomService.h"
|
|
#include "nsPrintJobPS.h"
|
|
#include "nsPrintJobFactoryPS.h"
|
|
-#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
|
|
+#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
#include "nsType1.h"
|
|
#endif
|
|
|
|
@@ -223,7 +226,7 @@ nsDeviceContextPS::InitDeviceContextPS(n
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIPref> pref(do_GetService(NS_PREF_CONTRACTID, &rv));
|
|
-#ifdef MOZ_ENABLE_XFT
|
|
+#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
if (NS_SUCCEEDED(rv)) {
|
|
rv = pref->GetBoolPref("font.FreeType2.printing", &mFTPEnable);
|
|
if (NS_FAILED(rv))
|
|
@@ -469,7 +472,7 @@ NS_IMETHODIMP nsDeviceContextPS::EndDocu
|
|
NS_ASSERTION(submitFP, "No print job submission handle");
|
|
|
|
// Start writing the print job to the job handler
|
|
-#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
|
|
+#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
mPSObj->write_prolog(submitFP, mFTPEnable);
|
|
#else
|
|
mPSObj->write_prolog(submitFP);
|
|
@@ -550,15 +553,52 @@ public:
|
|
virtual nsresult CreateFontMetricsInstance(nsIFontMetrics** aResult);
|
|
};
|
|
|
|
+#if defined(MOZ_ENABLE_PANGO)
|
|
+PRBool
|
|
+NS_IsPangoEnabled(void)
|
|
+{
|
|
+ static PRBool beenHere;
|
|
+ static PRBool pangoEnabled;
|
|
+
|
|
+ if (!beenHere) {
|
|
+ beenHere = PR_TRUE;
|
|
+
|
|
+ char *val = PR_GetEnv("MOZ_DISABLE_PANGO");
|
|
+ pangoEnabled = !(val);
|
|
+
|
|
+ if (pangoEnabled) {
|
|
+ nsCOMPtr<nsIPref> prefService = do_GetService(NS_PREF_CONTRACTID);
|
|
+ if (prefService)
|
|
+ prefService->SetDefaultCharPref("general.useragent.extra.pango",
|
|
+ "pango-text");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return pangoEnabled;
|
|
+}
|
|
+#endif
|
|
|
|
nsresult nsFontCachePS::CreateFontMetricsInstance(nsIFontMetrics** aResult)
|
|
{
|
|
NS_PRECONDITION(aResult, "null out param");
|
|
- nsIFontMetrics *fm = new nsFontMetricsPS();
|
|
- if (!fm)
|
|
- return NS_ERROR_OUT_OF_MEMORY;
|
|
- NS_ADDREF(fm);
|
|
- *aResult = fm;
|
|
+#ifdef MOZ_ENABLE_PANGO
|
|
+ if (NS_IsPangoEnabled())
|
|
+ {
|
|
+ nsIFontMetrics *fm = new nsFontMetricsPSPango();
|
|
+ if (!fm)
|
|
+ return NS_ERROR_OUT_OF_MEMORY;
|
|
+ NS_ADDREF(fm);
|
|
+ *aResult = fm;
|
|
+ }
|
|
+ else
|
|
+#endif
|
|
+ {
|
|
+ nsIFontMetrics *fm = new nsFontMetricsPS();
|
|
+ if (!fm)
|
|
+ return NS_ERROR_OUT_OF_MEMORY;
|
|
+ NS_ADDREF(fm);
|
|
+ *aResult = fm;
|
|
+ }
|
|
return NS_OK;
|
|
}
|
|
|
|
Index: gfx/src/ps/nsFontMetricsPS.cpp
|
|
===================================================================
|
|
RCS file: /cvsroot/mozilla/gfx/src/ps/nsFontMetricsPS.cpp,v
|
|
retrieving revision 1.57.16.2
|
|
diff -u -p -d -r1.57.16.2 nsFontMetricsPS.cpp
|
|
--- gfx/src/ps/nsFontMetricsPS.cpp 7 May 2006 02:01:25 -0000 1.57.16.2
|
|
+++ gfx/src/ps/nsFontMetricsPS.cpp 23 Oct 2006 17:37:11 -0000
|
|
@@ -461,6 +461,239 @@ nsFontMetricsPS :: GetStringWidth(const
|
|
return NS_OK;
|
|
}
|
|
|
|
+nsresult
|
|
+nsFontMetricsPS::DrawString(const char *aString, PRUint32 aLength,
|
|
+ nscoord aX, nscoord aY,
|
|
+ const nscoord* aSpacing,
|
|
+ nsRenderingContextPS *aContext)
|
|
+{
|
|
+ nsPostScriptObj* psObj = aContext->GetPostScriptObj();
|
|
+ // When FT2 printing is enabled, we don't need to set langgroup
|
|
+#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
|
|
+ if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, GetDeviceContext())->mFTPEnable) {
|
|
+#endif
|
|
+ nsCOMPtr<nsIAtom> langGroup;
|
|
+ GetLangGroup(getter_AddRefs(langGroup));
|
|
+ psObj->setlanggroup(langGroup);
|
|
+#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ if (aLength == 0)
|
|
+ return NS_OK;
|
|
+ nsFontPS* fontPS = nsFontPS::FindFont(aString[0], Font(), this);
|
|
+ NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
|
|
+ fontPS->SetupFont(aContext);
|
|
+
|
|
+ PRUint32 i, start = 0;
|
|
+ for (i=0; i<aLength; i++) {
|
|
+ nsFontPS* fontThisChar;
|
|
+ fontThisChar = nsFontPS::FindFont(aString[i], Font(), this);
|
|
+ NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE);
|
|
+ if (fontThisChar != fontPS) {
|
|
+ // draw text up to this point
|
|
+ aX += DrawString(aString+start, i-start, aX, aY, fontPS,
|
|
+ aSpacing?aSpacing+start:nsnull, aContext);
|
|
+ start = i;
|
|
+
|
|
+ // setup for following text
|
|
+ fontPS = fontThisChar;
|
|
+ fontPS->SetupFont(aContext);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // draw the last part
|
|
+ if (aLength-start)
|
|
+ DrawString(aString+start, aLength-start, aX, aY, fontPS,
|
|
+ aSpacing?aSpacing+start:nsnull, aContext);
|
|
+
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPS::DrawString(const PRUnichar* aString, PRUint32 aLength,
|
|
+ nscoord aX, nscoord aY,
|
|
+ PRInt32 aFontID,
|
|
+ const nscoord* aSpacing,
|
|
+ nsRenderingContextPS *aContext)
|
|
+{
|
|
+ nsPostScriptObj* psObj = aContext->GetPostScriptObj();
|
|
+#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
|
|
+ // When FT2 printing is enabled, we don't need to set langgroup
|
|
+ if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, GetDeviceContext())->mFTPEnable) {
|
|
+#endif
|
|
+ nsCOMPtr<nsIAtom> langGroup = nsnull;
|
|
+ GetLangGroup(getter_AddRefs(langGroup));
|
|
+ psObj->setlanggroup(langGroup);
|
|
+#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ /* build up conversion table */
|
|
+ psObj->preshow(aString, aLength);
|
|
+
|
|
+ if (aLength == 0)
|
|
+ return NS_OK;
|
|
+ nsFontPS* fontPS = nsFontPS::FindFont(aString[0], Font(), this);
|
|
+ NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
|
|
+ fontPS->SetupFont(aContext);
|
|
+
|
|
+ PRUint32 i, start = 0;
|
|
+ for (i=0; i<aLength; i++) {
|
|
+ nsFontPS* fontThisChar;
|
|
+ fontThisChar = nsFontPS::FindFont(aString[i], Font(), this);
|
|
+ NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE);
|
|
+ if (fontThisChar != fontPS) {
|
|
+ // draw text up to this point
|
|
+ aX += DrawString(aString+start, i-start, aX, aY, fontPS,
|
|
+ aSpacing?aSpacing+start:nsnull, aContext);
|
|
+ start = i;
|
|
+
|
|
+ // setup for following text
|
|
+ fontPS = fontThisChar;
|
|
+ fontPS->SetupFont(aContext);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // draw the last part
|
|
+ if (aLength-start)
|
|
+ DrawString(aString+start, aLength-start, aX, aY, fontPS,
|
|
+ aSpacing?aSpacing+start:nsnull, aContext);
|
|
+
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+PRInt32
|
|
+nsFontMetricsPS::DrawString(const char *aString, PRUint32 aLength,
|
|
+ nscoord aX, nscoord aY, nsFontPS* aFontPS,
|
|
+ const nscoord* aSpacing,
|
|
+ nsRenderingContextPS *aContext)
|
|
+{
|
|
+ nscoord width = 0;
|
|
+ PRInt32 x = aX;
|
|
+ PRInt32 y = aY;
|
|
+
|
|
+ PRInt32 dxMem[500];
|
|
+ PRInt32* dx0 = 0;
|
|
+ if (aSpacing) {
|
|
+ dx0 = dxMem;
|
|
+ if (aLength > 500) {
|
|
+ dx0 = new PRInt32[aLength];
|
|
+ NS_ENSURE_TRUE(dx0, NS_ERROR_OUT_OF_MEMORY);
|
|
+ }
|
|
+ aContext->GetTranMatrix()->ScaleXCoords(aSpacing, aLength, dx0);
|
|
+ }
|
|
+
|
|
+ aContext->GetTranMatrix()->TransformCoord(&x, &y);
|
|
+ width = aFontPS->DrawString(aContext, x, y, aString, aLength);
|
|
+
|
|
+ if ((aSpacing) && (dx0 != dxMem)) {
|
|
+ delete [] dx0;
|
|
+ }
|
|
+
|
|
+ return width;
|
|
+}
|
|
+
|
|
+
|
|
+PRInt32
|
|
+nsFontMetricsPS::DrawString(const PRUnichar* aString, PRUint32 aLength,
|
|
+ nscoord &aX, nscoord &aY, nsFontPS* aFontPS,
|
|
+ const nscoord* aSpacing,
|
|
+ nsRenderingContextPS *aContext)
|
|
+{
|
|
+ nscoord width = 0;
|
|
+ PRInt32 x = aX;
|
|
+ PRInt32 y = aY;
|
|
+
|
|
+ if (aSpacing) {
|
|
+ // Slow, but accurate rendering
|
|
+ const PRUnichar* end = aString + aLength;
|
|
+ while (aString < end){
|
|
+ x = aX;
|
|
+ y = aY;
|
|
+ aContext->GetTranMatrix()->TransformCoord(&x, &y);
|
|
+ aFontPS->DrawString(aContext, x, y, aString, 1);
|
|
+ aX += *aSpacing++;
|
|
+ aString++;
|
|
+ }
|
|
+ width = aX;
|
|
+ } else {
|
|
+ aContext->GetTranMatrix()->TransformCoord(&x, &y);
|
|
+ width = aFontPS->DrawString(aContext, x, y, aString, aLength);
|
|
+ }
|
|
+
|
|
+ return width;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFontMetricsPS::GetTextDimensions(const char* aString,
|
|
+ PRInt32 aLength,
|
|
+ PRInt32 aAvailWidth,
|
|
+ PRInt32* aBreaks,
|
|
+ PRInt32 aNumBreaks,
|
|
+ nsTextDimensions& aDimensions,
|
|
+ PRInt32& aNumCharsFit,
|
|
+ nsTextDimensions& aLastWordDimensions,
|
|
+ PRInt32* aFontID)
|
|
+{
|
|
+ NS_NOTYETIMPLEMENTED("nsFontMetricsPS::GetTextDimensions");
|
|
+ return NS_ERROR_NOT_IMPLEMENTED;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFontMetricsPS::GetTextDimensions(const PRUnichar* aString,
|
|
+ PRInt32 aLength,
|
|
+ PRInt32 aAvailWidth,
|
|
+ PRInt32* aBreaks,
|
|
+ PRInt32 aNumBreaks,
|
|
+ nsTextDimensions& aDimensions,
|
|
+ PRInt32& aNumCharsFit,
|
|
+ nsTextDimensions& aLastWordDimensions,
|
|
+ PRInt32* aFontID)
|
|
+{
|
|
+ NS_NOTYETIMPLEMENTED("nsFontMetricsPS::GetTextDimensions");
|
|
+ return NS_ERROR_NOT_IMPLEMENTED;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFontMetricsPS :: GetTextDimensions(const char* aString, PRUint32 aLength,
|
|
+ nsTextDimensions& aDimensions)
|
|
+{
|
|
+ GetStringWidth(aString, aDimensions.width, aLength);
|
|
+ GetMaxAscent(aDimensions.ascent);
|
|
+ GetMaxDescent(aDimensions.descent);
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFontMetricsPS :: GetTextDimensions(const PRUnichar* aString, PRUint32 aLength,
|
|
+ nsTextDimensions& aDimensions, PRInt32* aFontID)
|
|
+{
|
|
+ GetStringWidth(aString, aDimensions.width, aLength);
|
|
+ //XXX temporary - bug 96609
|
|
+ GetMaxAscent(aDimensions.ascent);
|
|
+ GetMaxDescent(aDimensions.descent);
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPS::GetBoundingMetrics(const char* aString,
|
|
+ PRUint32 aLength,
|
|
+ nsBoundingMetrics& aBoundingMetrics)
|
|
+{
|
|
+ return NS_ERROR_NOT_IMPLEMENTED;
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPS::GetBoundingMetrics(const PRUnichar* aString,
|
|
+ PRUint32 aLength,
|
|
+ nsBoundingMetrics &aBoundingMetrics,
|
|
+ PRInt32 *aFontID)
|
|
+{
|
|
+ return NS_ERROR_NOT_IMPLEMENTED;
|
|
+}
|
|
+
|
|
+
|
|
nsFontPS*
|
|
nsFontPS::FindFont(char aChar, const nsFont& aFont,
|
|
nsFontMetricsPS* aFontMetrics)
|
|
@@ -1128,23 +1361,38 @@ nsFontPSXft::DrawString(nsRenderingConte
|
|
PRUint32 start = 0;
|
|
PRUint32 i;
|
|
|
|
+ FT_Face face = getFTFace();
|
|
+ if (!face) {
|
|
+ NS_WARNING("Failed to get FT Face in nsFontPSXft::DrawString\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ nsValueArray glyphs(PR_UINT16_MAX);
|
|
+
|
|
// XXX : ignore surrogate pairs for now
|
|
- nsString *subSet = mPSFontGenerator->GetSubset();
|
|
for (i = 0; i < aLength; ++i) {
|
|
- currSubFont = mPSFontGenerator->AddToSubset(aString[i]);
|
|
+ PRUint32 glyph = FT_Get_Char_Index(face, aString[i]);
|
|
+ currSubFont = mPSFontGenerator->AddToGlyphSubset(glyph);
|
|
+
|
|
+ // Check if we need to render the current string
|
|
if (prevSubFont != currSubFont) {
|
|
- if (prevSubFont != -1)
|
|
- psObj->show(&aString[start], i - start, *subSet, prevSubFont);
|
|
+ if (prevSubFont != -1) {
|
|
+ psObj->show(&glyphs, mPSFontGenerator, prevSubFont);
|
|
+ }
|
|
NS_ASSERTION(!mFontNameBase.IsEmpty(),
|
|
"font base name shouldn't be empty");
|
|
psObj->setfont(mFontNameBase, mHeight, currSubFont);
|
|
prevSubFont = currSubFont;
|
|
start = i;
|
|
+ glyphs.Clear();
|
|
}
|
|
+
|
|
+ glyphs.AppendValue(glyph);
|
|
}
|
|
|
|
- if (prevSubFont != -1)
|
|
- psObj->show(&aString[start], i - start, *subSet, prevSubFont);
|
|
+ if (prevSubFont != -1) {
|
|
+ psObj->show(&glyphs, mPSFontGenerator, prevSubFont);
|
|
+ }
|
|
|
|
return GetWidth(aString, aLength);
|
|
}
|
|
@@ -2278,10 +2526,13 @@ nsFontPSFreeType::GetBoundingMetrics(con
|
|
// Implementation of nsPSFontGenerator
|
|
nsPSFontGenerator::nsPSFontGenerator()
|
|
{
|
|
+ mGlyphSubset = new nsValueArray(PR_UINT16_MAX, 40);
|
|
}
|
|
|
|
nsPSFontGenerator::~nsPSFontGenerator()
|
|
{
|
|
+ if (mGlyphSubset)
|
|
+ delete mGlyphSubset;
|
|
}
|
|
|
|
void nsPSFontGenerator::GeneratePSFont(FILE* aFile)
|
|
@@ -2289,24 +2540,29 @@ void nsPSFontGenerator::GeneratePSFont(F
|
|
NS_ERROR("should never call nsPSFontGenerator::GeneratePSFont");
|
|
}
|
|
|
|
-// Add a Unicode character to mSubset which will be divided into
|
|
-// multiple chunks (subfonts) of 255 (kSubFontSize) characters each.
|
|
-// Each chunk will be converted to a Type 1 font. Return the index of
|
|
-// a subfont (chunk) this character belongs to.
|
|
+// Add a glyph offset to mSubset which will be divided into multiple
|
|
+// chunks (subfonts) of 255 (kSubFontSize) glyphs each. Each chunk
|
|
+// will then be converted into a Type 1 font. Return the index of a
|
|
+// subfont (chunk) this glyph belongs to.
|
|
PRInt32
|
|
-nsPSFontGenerator::AddToSubset(PRUnichar aChar)
|
|
+nsPSFontGenerator::AddToGlyphSubset(PRUint32 aGlyph)
|
|
{
|
|
- PRInt32 index = mSubset.FindChar(aChar);
|
|
- if (index == kNotFound) {
|
|
- mSubset.Append(aChar);
|
|
- index = mSubset.Length() - 1;
|
|
+ nsValueArrayIndex index = mGlyphSubset->IndexOf(aGlyph);
|
|
+ if (index == NSVALUEARRAY_INVALID) {
|
|
+ mGlyphSubset->AppendValue(aGlyph);
|
|
+ index = mGlyphSubset->Count() - 1;
|
|
}
|
|
+
|
|
return index / kSubFontSize;
|
|
}
|
|
|
|
-nsString *nsPSFontGenerator::GetSubset()
|
|
+PRInt32
|
|
+nsPSFontGenerator::InSubsetIndexOf(PRUint32 aGlyph)
|
|
{
|
|
- return &mSubset;
|
|
+ nsValueArrayIndex index = mGlyphSubset->IndexOf(aGlyph);
|
|
+ if (index == NSVALUEARRAY_INVALID)
|
|
+ return 0;
|
|
+ return (index % kSubFontSize) + 1;
|
|
}
|
|
|
|
#ifdef MOZ_ENABLE_XFT
|
|
@@ -2353,8 +2609,8 @@ void nsXftType1Generator::GeneratePSFont
|
|
}
|
|
|
|
int wmode = 0;
|
|
- if (!mSubset.IsEmpty())
|
|
- FT2SubsetToType1FontSet(face, mSubset, wmode, aFile);
|
|
+ if (mGlyphSubset->Count())
|
|
+ FT2SubsetToType1FontSet(face, mGlyphSubset, wmode, aFile);
|
|
}
|
|
|
|
#else
|
|
@@ -2402,8 +2658,8 @@ void nsFT2Type1Generator::GeneratePSFont
|
|
return;
|
|
|
|
int wmode = 0;
|
|
- if (!mSubset.IsEmpty())
|
|
- FT2SubsetToType1FontSet(face, mSubset, wmode, aFile);
|
|
+ if (mGlyphSubset->Count())
|
|
+ FT2SubsetToType1FontSet(face, mGlyphSubset, wmode, aFile);
|
|
}
|
|
|
|
#endif //MOZ_ENABLE_FREETYPE2
|
|
Index: gfx/src/ps/nsFontMetricsPS.h
|
|
===================================================================
|
|
RCS file: /cvsroot/mozilla/gfx/src/ps/nsFontMetricsPS.h,v
|
|
retrieving revision 1.31
|
|
diff -u -p -d -r1.31 nsFontMetricsPS.h
|
|
--- gfx/src/ps/nsFontMetricsPS.h 28 Jun 2005 18:29:10 -0000 1.31
|
|
+++ gfx/src/ps/nsFontMetricsPS.h 23 Oct 2006 17:37:11 -0000
|
|
@@ -66,6 +66,7 @@
|
|
#endif
|
|
#include "nsVoidArray.h"
|
|
#include "nsHashtable.h"
|
|
+#include "nsValueArray.h"
|
|
|
|
class nsPSFontGenerator;
|
|
class nsDeviceContextPS;
|
|
@@ -108,6 +109,65 @@ public:
|
|
NS_IMETHOD GetFontHandle(nsFontHandle &aHandle);
|
|
NS_IMETHOD GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength);
|
|
NS_IMETHOD GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength);
|
|
+
|
|
+ NS_IMETHOD GetTextDimensions(const char* aString,
|
|
+ PRUint32 aLength,
|
|
+ nsTextDimensions& aDimensions);
|
|
+ NS_IMETHOD GetTextDimensions(const PRUnichar* aString,
|
|
+ PRUint32 aLength,
|
|
+ nsTextDimensions& aDimensions,
|
|
+ PRInt32* aFontID);
|
|
+ NS_IMETHOD GetTextDimensions(const char* aString,
|
|
+ PRInt32 aLength,
|
|
+ PRInt32 aAvailWidth,
|
|
+ PRInt32* aBreaks,
|
|
+ PRInt32 aNumBreaks,
|
|
+ nsTextDimensions& aDimensions,
|
|
+ PRInt32& aNumCharsFit,
|
|
+ nsTextDimensions& aLastWordDimensions,
|
|
+ PRInt32* aFontID);
|
|
+ NS_IMETHOD GetTextDimensions(const PRUnichar* aString,
|
|
+ PRInt32 aLength,
|
|
+ PRInt32 aAvailWidth,
|
|
+ PRInt32* aBreaks,
|
|
+ PRInt32 aNumBreaks,
|
|
+ nsTextDimensions& aDimensions,
|
|
+ PRInt32& aNumCharsFit,
|
|
+ nsTextDimensions& aLastWordDimensions,
|
|
+ PRInt32* aFontID);
|
|
+#ifdef MOZ_MATHML
|
|
+ NS_IMETHOD GetBoundingMetrics(const char *aString, PRUint32 aLength,
|
|
+ nsBoundingMetrics &aBoundingMetrics);
|
|
+ NS_IMETHOD GetBoundingMetrics(const PRUnichar *aString,
|
|
+ PRUint32 aLength,
|
|
+ nsBoundingMetrics &aBoundingMetrics,
|
|
+ PRInt32 *aFontID);
|
|
+#endif /* MOZ_MATHML */
|
|
+
|
|
+ NS_IMETHOD DrawString(const char *aString, PRUint32 aLength,
|
|
+ nscoord aX, nscoord aY,
|
|
+ const nscoord* aSpacing,
|
|
+ nsRenderingContextPS *aContext);
|
|
+ NS_IMETHOD DrawString(const PRUnichar *aString, PRUint32 aLength,
|
|
+ nscoord aX, nscoord aY,
|
|
+ PRInt32 aFontID,
|
|
+ const nscoord* aSpacing,
|
|
+ nsRenderingContextPS *aContext);
|
|
+
|
|
+protected:
|
|
+ PRInt32 DrawString(const char *aString, PRUint32 aLength,
|
|
+ nscoord aX, nscoord aY, nsFontPS* aFontPS,
|
|
+ const nscoord* aSpacing,
|
|
+ nsRenderingContextPS *aContext);
|
|
+ PRInt32 DrawString(const PRUnichar *aString, PRUint32 aLength,
|
|
+ nscoord &aX, nscoord &aY, nsFontPS* aFontPS,
|
|
+ const nscoord* aSpacing,
|
|
+ nsRenderingContextPS *aContext);
|
|
+
|
|
+public:
|
|
+
|
|
+ virtual PRUint32 GetHints (void) { return 0; }
|
|
+
|
|
|
|
inline void SetXHeight(nscoord aXHeight) { mXHeight = aXHeight; };
|
|
inline void SetSuperscriptOffset(nscoord aSuperscriptOffset) { mSuperscriptOffset = aSuperscriptOffset; };
|
|
@@ -455,16 +515,14 @@ public:
|
|
nsPSFontGenerator();
|
|
virtual ~nsPSFontGenerator();
|
|
virtual void GeneratePSFont(FILE* aFile);
|
|
- PRInt32 AddToSubset(PRUnichar aChar);
|
|
- nsString *GetSubset();
|
|
+ PRInt32 AddToGlyphSubset(PRUint32 aGlyph);
|
|
+ PRInt32 InSubsetIndexOf(PRUint32 aGlyph);
|
|
|
|
// 256 (PS type 1 encoding vector size) - 1 (1 is for mandatory /.notdef)
|
|
const static PRUint16 kSubFontSize;
|
|
|
|
protected:
|
|
- // XXX To support non-BMP characters, we may have to use
|
|
- // nsValueArray with PRUint32
|
|
- nsString mSubset;
|
|
+ nsValueArray *mGlyphSubset;
|
|
};
|
|
|
|
|
|
Index: gfx/src/ps/nsFontMetricsPSPango.cpp
|
|
===================================================================
|
|
RCS file: gfx/src/ps/nsFontMetricsPSPango.cpp
|
|
diff -N gfx/src/ps/nsFontMetricsPSPango.cpp
|
|
--- /dev/null 1 Jan 1970 00:00:00 -0000
|
|
+++ gfx/src/ps/nsFontMetricsPSPango.cpp 23 Oct 2006 17:37:13 -0000
|
|
@@ -0,0 +1,2107 @@
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
+ */
|
|
+/* ***** BEGIN LICENSE BLOCK *****
|
|
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
+ *
|
|
+ * The contents of this file are subject to the Mozilla Public License Version
|
|
+ * 1.1 (the "License"); you may not use this file except in compliance with
|
|
+ * the License. You may obtain a copy of the License at
|
|
+ * http://www.mozilla.org/MPL/
|
|
+ *
|
|
+ * Software distributed under the License is distributed on an "AS IS" basis,
|
|
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
+ * for the specific language governing rights and limitations under the
|
|
+ * License.
|
|
+ *
|
|
+ * The Original Code is mozilla.org code.
|
|
+ *
|
|
+ * The Initial Developer of the Original Code is Christopher Blizzard
|
|
+ * <blizzard@mozilla.org>. Portions created by the Initial Developer
|
|
+ * are Copyright (C) 2004 the Initial Developer. All Rights Reserved.
|
|
+ *
|
|
+ * Contributor(s):
|
|
+ * Christopher Blizzard <blizzard@mozilla.org>
|
|
+ * Behdad Esfahbod <behdad@behdad.org>
|
|
+ *
|
|
+ * Alternatively, the contents of this file may be used under the terms of
|
|
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
+ * in which case the provisions of the GPL or the LGPL are applicable instead
|
|
+ * of those above. If you wish to allow use of your version of this file only
|
|
+ * under the terms of either the GPL or the LGPL, and not to allow others to
|
|
+ * use your version of this file under the terms of the MPL, indicate your
|
|
+ * decision by deleting the provisions above and replace them with the notice
|
|
+ * and other provisions required by the GPL or the LGPL. If you do not delete
|
|
+ * the provisions above, a recipient may use your version of this file under
|
|
+ * the terms of any one of the MPL, the GPL or the LGPL.
|
|
+ *
|
|
+ * ***** END LICENSE BLOCK ***** */
|
|
+
|
|
+#include <strings.h>
|
|
+#include "nsFont.h"
|
|
+#include "nsIDeviceContext.h"
|
|
+#include "nsICharsetConverterManager.h"
|
|
+#include "nsIPref.h"
|
|
+#include "nsServiceManagerUtils.h"
|
|
+
|
|
+#define PANGO_ENABLE_BACKEND
|
|
+#define PANGO_ENABLE_ENGINE
|
|
+
|
|
+#include "nsFontMetricsPSPango.h"
|
|
+#include "nsRenderingContextPS.h"
|
|
+#include "nsDeviceContextPS.h"
|
|
+#include "nsFontConfigUtils.h"
|
|
+
|
|
+#include "nsPrintfCString.h"
|
|
+#include "nsUnicharUtils.h"
|
|
+#include "nsQuickSort.h"
|
|
+#include "nsFontConfigUtils.h"
|
|
+
|
|
+#include <fontconfig/fontconfig.h>
|
|
+#include <pango/pangoft2.h>
|
|
+#include <freetype/tttables.h>
|
|
+#include "nsType1.h"
|
|
+
|
|
+#include "mozilla-ps-decoder.h"
|
|
+
|
|
+#define FORCE_PR_LOG
|
|
+#include "prlog.h"
|
|
+
|
|
+// Globals
|
|
+
|
|
+static PRLogModuleInfo *gPangoFontLog;
|
|
+static int gNumInstances;
|
|
+
|
|
+
|
|
+static void
|
|
+default_substitute (FcPattern *pattern,
|
|
+ gpointer data)
|
|
+{
|
|
+ FcPatternDel (pattern, FC_HINTING);
|
|
+ FcPatternAddBool (pattern, FC_HINTING, 0);
|
|
+}
|
|
+
|
|
+static PangoFontMap *
|
|
+get_fontmap (void)
|
|
+{
|
|
+ static PangoFontMap *fontmap = NULL;
|
|
+
|
|
+ if (!fontmap) {
|
|
+ fontmap = pango_ft2_font_map_new ();
|
|
+ pango_ft2_font_map_set_resolution ((PangoFT2FontMap *)fontmap, 72., 72.);
|
|
+ pango_ft2_font_map_set_default_substitute ((PangoFT2FontMap *)fontmap, default_substitute, NULL, NULL);
|
|
+ }
|
|
+
|
|
+ return fontmap;
|
|
+}
|
|
+
|
|
+static PangoContext *
|
|
+get_context (void)
|
|
+{
|
|
+ return pango_ft2_font_map_create_context ((PangoFT2FontMap *) get_fontmap ());
|
|
+}
|
|
+
|
|
+// Defines
|
|
+
|
|
+// This is the scaling factor that we keep fonts limited to against
|
|
+// the display size. If a pixel size is requested that is more than
|
|
+// this factor larger than the height of the display, it's clamped to
|
|
+// that value instead of the requested size.
|
|
+#define FONT_MAX_FONT_SCALE 2
|
|
+
|
|
+static NS_DEFINE_CID(kCharsetConverterManagerCID,
|
|
+ NS_ICHARSETCONVERTERMANAGER_CID);
|
|
+
|
|
+#ifdef DEBUG
|
|
+#define DUMP_PRUNICHAR(ustr, ulen) for (PRUint32 llen=0;llen<ulen;llen++) \
|
|
+ printf("0x%x ", ustr[llen]); \
|
|
+ printf("\n");
|
|
+#endif
|
|
+
|
|
+// rounding and truncation functions for a Freetype floating point number
|
|
+// (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer
|
|
+// part and low 6 bits for the fractional part.
|
|
+#define MOZ_FT_ROUND(x) (((x) + 32) & ~63) // 63 = 2^6 - 1
|
|
+#define MOZ_FT_TRUNC(x) ((x) >> 6)
|
|
+#define CONVERT_DESIGN_UNITS_TO_PIXELS(v, s) \
|
|
+ MOZ_FT_TRUNC(MOZ_FT_ROUND(FT_MulFix((v) , (s))))
|
|
+
|
|
+// Static function decls
|
|
+
|
|
+static PangoLanguage *GetPangoLanguage(nsIAtom *aLangGroup);
|
|
+
|
|
+static void FreeGlobals (void);
|
|
+
|
|
+static PangoStyle CalculateStyle (PRUint8 aStyle);
|
|
+static PangoWeight CalculateWeight (PRUint16 aWeight);
|
|
+
|
|
+static nsresult EnumFontsPango (nsIAtom* aLangGroup, const char* aGeneric,
|
|
+ PRUint32* aCount, PRUnichar*** aResult);
|
|
+static int CompareFontNames (const void* aArg1, const void* aArg2,
|
|
+ void* aClosure);
|
|
+
|
|
+nsFontMetricsPSPango::nsFontMetricsPSPango()
|
|
+{
|
|
+ if (!gPangoFontLog)
|
|
+ gPangoFontLog = PR_NewLogModule("PangoFont");
|
|
+
|
|
+ gNumInstances++;
|
|
+
|
|
+ mPangoFontDesc = nsnull;
|
|
+ mPangoContext = nsnull;
|
|
+ mLTRPangoContext = nsnull;
|
|
+ mRTLPangoContext = nsnull;
|
|
+ mPangoAttrList = nsnull;
|
|
+ mIsRTL = PR_FALSE;
|
|
+ mPangoSpaceWidth = 0;
|
|
+
|
|
+ static PRBool initialized = PR_FALSE;
|
|
+ if (initialized)
|
|
+ return;
|
|
+
|
|
+ // Initialized the custom decoders
|
|
+ if (!mozilla_ps_decoders_init(get_fontmap ()))
|
|
+ initialized = PR_TRUE;
|
|
+}
|
|
+
|
|
+nsFontMetricsPSPango::~nsFontMetricsPSPango()
|
|
+{
|
|
+ if (mDeviceContext)
|
|
+ mDeviceContext->FontMetricsDeleted(this);
|
|
+
|
|
+ if (mPangoFontDesc)
|
|
+ pango_font_description_free(mPangoFontDesc);
|
|
+
|
|
+ if (mLTRPangoContext)
|
|
+ g_object_unref(mLTRPangoContext);
|
|
+
|
|
+ if (mRTLPangoContext)
|
|
+ g_object_unref(mRTLPangoContext);
|
|
+
|
|
+ if (mPangoAttrList)
|
|
+ pango_attr_list_unref(mPangoAttrList);
|
|
+
|
|
+ // XXX clean up all the pango objects
|
|
+
|
|
+ if (--gNumInstances == 0)
|
|
+ FreeGlobals();
|
|
+}
|
|
+
|
|
+
|
|
+NS_IMPL_ISUPPORTS1(nsFontMetricsPSPango, nsIFontMetrics)
|
|
+
|
|
+// nsIFontMetrics impl
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFontMetricsPSPango::Init(const nsFont& aFont, nsIAtom* aLangGroup,
|
|
+ nsIDeviceContext *aContext)
|
|
+{
|
|
+ mFont = aFont;
|
|
+ mLangGroup = aLangGroup;
|
|
+
|
|
+ // Hang on to the device context
|
|
+ mDeviceContext = aContext;
|
|
+
|
|
+ mPointSize = NSTwipsToFloatPoints(mFont.size);
|
|
+
|
|
+ // enumerate over the font names passed in
|
|
+ mFont.EnumerateFamilies(nsFontMetricsPSPango::EnumFontCallback, this);
|
|
+
|
|
+ nsCOMPtr<nsIPref> prefService;
|
|
+ prefService = do_GetService(NS_PREF_CONTRACTID);
|
|
+ if (!prefService)
|
|
+ return NS_ERROR_FAILURE;
|
|
+
|
|
+ nsXPIDLCString value;
|
|
+ const char* langGroup;
|
|
+ mLangGroup->GetUTF8String(&langGroup);
|
|
+
|
|
+ // Set up the default font name if it's not set
|
|
+ if (!mGenericFont) {
|
|
+ nsCAutoString name("font.default.");
|
|
+ name.Append(langGroup);
|
|
+ prefService->CopyCharPref(name.get(), getter_Copies(value));
|
|
+
|
|
+ if (value.get())
|
|
+ mDefaultFont = value.get();
|
|
+ else
|
|
+ mDefaultFont = "serif";
|
|
+
|
|
+ mGenericFont = &mDefaultFont;
|
|
+ }
|
|
+
|
|
+ // set up the minimum sizes for fonts
|
|
+ if (mLangGroup) {
|
|
+ nsCAutoString name("font.min-size.");
|
|
+
|
|
+ if (mGenericFont->Equals("monospace"))
|
|
+ name.Append("fixed");
|
|
+ else
|
|
+ name.Append("variable");
|
|
+
|
|
+ name.Append(char('.'));
|
|
+ name.Append(langGroup);
|
|
+
|
|
+ PRInt32 minimumInt = 0;
|
|
+ float minimum;
|
|
+ nsresult res;
|
|
+ res = prefService->GetIntPref(name.get(), &minimumInt);
|
|
+ if (NS_FAILED(res))
|
|
+ prefService->GetDefaultIntPref(name.get(), &minimumInt);
|
|
+
|
|
+ if (minimumInt < 0)
|
|
+ minimumInt = 0;
|
|
+
|
|
+ minimum = minimumInt;
|
|
+
|
|
+ // The minimum size is specified in pixels, not in points.
|
|
+ // Convert the size from pixels to points.
|
|
+ minimum = NSTwipsToFloatPoints(NSFloatPixelsToTwips(minimum, mDeviceContext->DevUnitsToAppUnits()));
|
|
+ if (mPointSize < minimum)
|
|
+ mPointSize = minimum;
|
|
+ }
|
|
+
|
|
+ // Make sure that the pixel size is at least greater than zero
|
|
+ if (mPointSize < 1) {
|
|
+#ifdef DEBUG
|
|
+ printf("*** Warning: nsFontMetricsPSPango created with point size %f\n",
|
|
+ mPointSize);
|
|
+#endif
|
|
+ mPointSize = 1;
|
|
+ }
|
|
+
|
|
+ nsresult rv = RealizeFont();
|
|
+ if (NS_FAILED(rv))
|
|
+ return rv;
|
|
+
|
|
+ // Cache font metrics for the 'x' character
|
|
+ return CacheFontMetrics();
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::CacheFontMetrics(void)
|
|
+{
|
|
+ // Get our scale factor
|
|
+ float f;
|
|
+ float val;
|
|
+ f = mDeviceContext->DevUnitsToAppUnits();
|
|
+
|
|
+ mPangoAttrList = pango_attr_list_new();
|
|
+
|
|
+ GList *items = pango_itemize(mPangoContext,
|
|
+ "a", 0, 1, mPangoAttrList, NULL);
|
|
+
|
|
+ if (!items)
|
|
+ return NS_ERROR_FAILURE;
|
|
+
|
|
+ guint nitems = g_list_length(items);
|
|
+ if (nitems != 1)
|
|
+ return NS_ERROR_FAILURE;
|
|
+
|
|
+ PangoItem *item = (PangoItem *)items->data;
|
|
+ PangoFcFont *fcfont = PANGO_FC_FONT(item->analysis.font);
|
|
+ if (!fcfont)
|
|
+ return NS_ERROR_FAILURE;
|
|
+
|
|
+ // Get our font face
|
|
+ FT_Face face;
|
|
+ face = pango_fc_font_lock_face(fcfont);
|
|
+ if (!face)
|
|
+ return NS_ERROR_NOT_AVAILABLE;
|
|
+
|
|
+ TT_OS2 *os2;
|
|
+ os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2);
|
|
+
|
|
+ // mEmHeight (size in pixels of EM height)
|
|
+ int size;
|
|
+ if (FcPatternGetInteger(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) !=
|
|
+ FcResultMatch) {
|
|
+ size = 12;
|
|
+ }
|
|
+ mEmHeight = PR_MAX(1, nscoord(size * f));
|
|
+
|
|
+ // mMaxAscent
|
|
+ val = MOZ_FT_TRUNC(face->size->metrics.ascender);
|
|
+ mMaxAscent = NSToIntRound(val * f);
|
|
+
|
|
+ // mMaxDescent
|
|
+ val = -MOZ_FT_TRUNC(face->size->metrics.descender);
|
|
+ mMaxDescent = NSToIntRound(val * f);
|
|
+
|
|
+ nscoord lineHeight = mMaxAscent + mMaxDescent;
|
|
+
|
|
+ // mLeading (needs ascent and descent and EM height)
|
|
+ if (lineHeight > mEmHeight)
|
|
+ mLeading = lineHeight - mEmHeight;
|
|
+ else
|
|
+ mLeading = 0;
|
|
+
|
|
+ // mMaxHeight (needs ascent and descent)
|
|
+ mMaxHeight = lineHeight;
|
|
+
|
|
+ // mEmAscent (needs maxascent, EM height, ascent and descent)
|
|
+ mEmAscent = nscoord(mMaxAscent * mEmHeight / lineHeight);
|
|
+
|
|
+ // mEmDescent (needs EM height and EM ascent
|
|
+ mEmDescent = mEmHeight - mEmAscent;
|
|
+
|
|
+ // mMaxAdvance
|
|
+ val = MOZ_FT_TRUNC(face->size->metrics.max_advance);
|
|
+ mMaxAdvance = NSToIntRound(val * f);
|
|
+
|
|
+ // mPangoSpaceWidth
|
|
+ PangoLayout *layout = pango_layout_new(mPangoContext);
|
|
+ pango_layout_set_text(layout, " ", 1);
|
|
+ int pswidth, psheight;
|
|
+ pango_layout_get_size(layout, &pswidth, &psheight);
|
|
+ mPangoSpaceWidth = pswidth;
|
|
+ g_object_unref(layout);
|
|
+
|
|
+ // mSpaceWidth (width of a space)
|
|
+ nscoord tmpWidth;
|
|
+ GetWidth(" ", 1, tmpWidth);
|
|
+ mSpaceWidth = tmpWidth;
|
|
+
|
|
+ // mAveCharWidth (width of an 'average' char)
|
|
+ // XftTextExtents16(GDK_DISPLAY(), xftFont, &xUnichar, 1, &extents);
|
|
+ //rawWidth = extents.width;
|
|
+ //mAveCharWidth = NSToCoordRound(rawWidth * f);
|
|
+ GetWidth("x", 1, tmpWidth);
|
|
+ mAveCharWidth = tmpWidth;
|
|
+
|
|
+ // mXHeight (height of an 'x' character)
|
|
+ if (pango_fc_font_has_char(fcfont, 'x')) {
|
|
+ PangoRectangle rect;
|
|
+ PangoGlyph glyph = pango_fc_font_get_glyph (fcfont, 'x');
|
|
+ pango_font_get_glyph_extents (PANGO_FONT (fcfont), glyph, &rect, NULL);
|
|
+ mXHeight = NSToIntRound(rect.height * f / PANGO_SCALE);
|
|
+ }
|
|
+ else {
|
|
+ // 56% of ascent, best guess for non-true type or asian fonts
|
|
+ mXHeight = nscoord(((float)mMaxAscent) * 0.56 * f);
|
|
+ }
|
|
+
|
|
+ // mUnderlineOffset (offset for underlines)
|
|
+ val = CONVERT_DESIGN_UNITS_TO_PIXELS(face->underline_position,
|
|
+ face->size->metrics.y_scale);
|
|
+ if (val) {
|
|
+ mUnderlineOffset = NSToIntRound(val * f);
|
|
+ }
|
|
+ else {
|
|
+ mUnderlineOffset =
|
|
+ -NSToIntRound(PR_MAX(1, floor(0.1 *
|
|
+ MOZ_FT_TRUNC(face->size->metrics.height) + 0.5)) * f);
|
|
+ }
|
|
+
|
|
+ // mUnderlineSize (thickness of an underline)
|
|
+ val = CONVERT_DESIGN_UNITS_TO_PIXELS(face->underline_thickness,
|
|
+ face->size->metrics.y_scale);
|
|
+ if (val) {
|
|
+ mUnderlineSize = nscoord(PR_MAX(f, NSToIntRound(val * f)));
|
|
+ }
|
|
+ else {
|
|
+ mUnderlineSize =
|
|
+ NSToIntRound(PR_MAX(1,
|
|
+ floor(0.05 * MOZ_FT_TRUNC(face->size->metrics.height) + 0.5)) * f);
|
|
+ }
|
|
+
|
|
+ // mSuperscriptOffset
|
|
+ if (os2 && os2->ySuperscriptYOffset) {
|
|
+ val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySuperscriptYOffset,
|
|
+ face->size->metrics.y_scale);
|
|
+ mSuperscriptOffset = nscoord(PR_MAX(f, NSToIntRound(val * f)));
|
|
+ }
|
|
+ else {
|
|
+ mSuperscriptOffset = mXHeight;
|
|
+ }
|
|
+
|
|
+ // mSubscriptOffset
|
|
+ if (os2 && os2->ySubscriptYOffset) {
|
|
+ val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySubscriptYOffset,
|
|
+ face->size->metrics.y_scale);
|
|
+ // some fonts have the incorrect sign.
|
|
+ val = (val < 0) ? -val : val;
|
|
+ mSubscriptOffset = nscoord(PR_MAX(f, NSToIntRound(val * f)));
|
|
+ }
|
|
+ else {
|
|
+ mSubscriptOffset = mXHeight;
|
|
+ }
|
|
+
|
|
+ // mStrikeoutOffset
|
|
+ mStrikeoutOffset = NSToCoordRound(mXHeight / 2.0);
|
|
+
|
|
+ // mStrikeoutSize
|
|
+ mStrikeoutSize = mUnderlineSize;
|
|
+
|
|
+ pango_fc_font_unlock_face(fcfont);
|
|
+
|
|
+ /*
|
|
+ printf("%i\n", mXHeight);
|
|
+ printf("%i\n", mSuperscriptOffset);
|
|
+ printf("%i\n", mSubscriptOffset);
|
|
+ printf("%i\n", mStrikeoutOffset);
|
|
+ printf("%i\n", mStrikeoutSize);
|
|
+ printf("%i\n", mUnderlineOffset);
|
|
+ printf("%i\n", mUnderlineSize);
|
|
+ printf("%i\n", mMaxHeight);
|
|
+ printf("%i\n", mLeading);
|
|
+ printf("%i\n", mEmHeight);
|
|
+ printf("%i\n", mEmAscent);
|
|
+ printf("%i\n", mEmDescent);
|
|
+ printf("%i\n", mMaxAscent);
|
|
+ printf("%i\n", mMaxDescent);
|
|
+ printf("%i\n", mMaxAdvance);
|
|
+ printf("%i\n", mSpaceWidth);
|
|
+ printf("%i\n", mAveCharWidth);
|
|
+ */
|
|
+
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFontMetricsPSPango::Destroy()
|
|
+{
|
|
+ mDeviceContext = nsnull;
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFontMetricsPSPango::GetLangGroup(nsIAtom** aLangGroup)
|
|
+{
|
|
+ *aLangGroup = mLangGroup;
|
|
+ NS_IF_ADDREF(*aLangGroup);
|
|
+
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFontMetricsPSPango::GetFontHandle(nsFontHandle &aHandle)
|
|
+{
|
|
+ return NS_ERROR_NOT_IMPLEMENTED;
|
|
+}
|
|
+
|
|
+// nsIFontMetricsPango impl
|
|
+NS_IMETHODIMP
|
|
+nsFontMetricsPSPango::GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength)
|
|
+{
|
|
+ return GetWidth (String, (PRUint32) aLength, aWidth);
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFontMetricsPSPango::GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength)
|
|
+{
|
|
+ return GetWidth (aString, (PRUint32)aLength, aWidth);
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::GetWidth(const char* aString, PRUint32 aLength,
|
|
+ nscoord& aWidth)
|
|
+{
|
|
+ PangoLayout *layout = pango_layout_new(mPangoContext);
|
|
+
|
|
+ pango_layout_set_text(layout, aString, aLength);
|
|
+
|
|
+ if (mPangoSpaceWidth)
|
|
+ FixupSpaceWidths(layout, aString);
|
|
+
|
|
+ int width, height;
|
|
+
|
|
+ pango_layout_get_size(layout, &width, &height);
|
|
+
|
|
+ g_object_unref(layout);
|
|
+
|
|
+ float f;
|
|
+ f = mDeviceContext->DevUnitsToAppUnits();
|
|
+ aWidth = NSToCoordRound(width * f / PANGO_SCALE);
|
|
+
|
|
+ // printf("GetWidth (char *) %d\n", aWidth);
|
|
+
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::GetWidth(const PRUnichar* aString, PRUint32 aLength,
|
|
+ nscoord& aWidth)
|
|
+{
|
|
+ nsresult rv = NS_OK;
|
|
+ PangoLayout *layout = pango_layout_new(mPangoContext);
|
|
+
|
|
+ gchar *text = g_utf16_to_utf8(aString, aLength,
|
|
+ NULL, NULL, NULL);
|
|
+
|
|
+ if (!text) {
|
|
+ aWidth = 0;
|
|
+#ifdef DEBUG
|
|
+ NS_WARNING("nsFontMetricsPSPango::GetWidth invalid unicode to follow");
|
|
+ DUMP_PRUNICHAR(aString, aLength)
|
|
+#endif
|
|
+ rv = NS_ERROR_FAILURE;
|
|
+ goto loser;
|
|
+ }
|
|
+
|
|
+ gint width, height;
|
|
+
|
|
+ pango_layout_set_text(layout, text, strlen(text));
|
|
+ FixupSpaceWidths(layout, text);
|
|
+ pango_layout_get_size(layout, &width, &height);
|
|
+
|
|
+ float f;
|
|
+ f = mDeviceContext->DevUnitsToAppUnits();
|
|
+ aWidth = NSToCoordRound(width * f / PANGO_SCALE);
|
|
+
|
|
+ // printf("GetWidth %d\n", aWidth);
|
|
+
|
|
+ loser:
|
|
+ g_free(text);
|
|
+ g_object_unref(layout);
|
|
+
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango :: GetTextDimensions(const char* aString, PRUint32 aLength,
|
|
+ nsTextDimensions& aDimensions)
|
|
+{
|
|
+ nsresult rv = NS_OK;
|
|
+
|
|
+ PangoLayout *layout = pango_layout_new(mPangoContext);
|
|
+
|
|
+ pango_layout_set_text(layout, aString, aLength);
|
|
+ FixupSpaceWidths(layout,aString);
|
|
+
|
|
+ // Get the logical extents
|
|
+ PangoLayoutLine *line;
|
|
+ if (pango_layout_get_line_count(layout) != 1) {
|
|
+ printf("Warning: more than one line!\n");
|
|
+ }
|
|
+ line = pango_layout_get_line(layout, 0);
|
|
+
|
|
+ PangoRectangle rect;
|
|
+ pango_layout_line_get_extents(line, NULL, &rect);
|
|
+
|
|
+ float P2T;
|
|
+ P2T = mDeviceContext->DevUnitsToAppUnits();
|
|
+
|
|
+ aDimensions.width = NSToCoordRound(rect.width * P2T / PANGO_SCALE);
|
|
+ aDimensions.ascent = NSToCoordRound(PANGO_ASCENT(rect) * P2T / PANGO_SCALE);
|
|
+ aDimensions.descent = NSToCoordRound(PANGO_DESCENT(rect) * P2T / PANGO_SCALE);
|
|
+
|
|
+ // printf("GetTextDimensions %d %d %d\n", aDimensions.width,
|
|
+ //aDimensions.ascent, aDimensions.descent);
|
|
+
|
|
+ loser:
|
|
+ g_object_unref(layout);
|
|
+
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::GetTextDimensions(const PRUnichar* aString,
|
|
+ PRUint32 aLength,
|
|
+ nsTextDimensions& aDimensions,
|
|
+ PRInt32* aFontID)
|
|
+{
|
|
+ nsresult rv = NS_OK;
|
|
+
|
|
+ PangoLayout *layout = pango_layout_new(mPangoContext);
|
|
+
|
|
+ gchar *text = g_utf16_to_utf8(aString, aLength,
|
|
+ NULL, NULL, NULL);
|
|
+
|
|
+ if (!text) {
|
|
+#ifdef DEBUG
|
|
+ NS_WARNING("nsFontMetricsPSPango::GetTextDimensions invalid unicode to follow");
|
|
+ DUMP_PRUNICHAR(aString, aLength)
|
|
+#endif
|
|
+ aDimensions.width = 0;
|
|
+ aDimensions.ascent = 0;
|
|
+ aDimensions.descent = 0;
|
|
+
|
|
+ rv = NS_ERROR_FAILURE;
|
|
+ goto loser;
|
|
+ }
|
|
+
|
|
+
|
|
+ pango_layout_set_text(layout, text, strlen(text));
|
|
+ FixupSpaceWidths(layout, text);
|
|
+
|
|
+ // Get the logical extents
|
|
+ PangoLayoutLine *line;
|
|
+ if (pango_layout_get_line_count(layout) != 1) {
|
|
+ printf("Warning: more than one line!\n");
|
|
+ }
|
|
+ line = pango_layout_get_line(layout, 0);
|
|
+
|
|
+ PangoRectangle rect;
|
|
+ pango_layout_line_get_extents(line, NULL, &rect);
|
|
+
|
|
+ float P2T;
|
|
+ P2T = mDeviceContext->DevUnitsToAppUnits();
|
|
+
|
|
+ aDimensions.width = NSToCoordRound(rect.width * P2T / PANGO_SCALE);
|
|
+ aDimensions.ascent = NSToCoordRound(PANGO_ASCENT(rect) * P2T / PANGO_SCALE);
|
|
+ aDimensions.descent = NSToCoordRound(PANGO_DESCENT(rect) * P2T / PANGO_SCALE);
|
|
+
|
|
+ // printf("GetTextDimensions %d %d %d\n", aDimensions.width,
|
|
+ //aDimensions.ascent, aDimensions.descent);
|
|
+
|
|
+ loser:
|
|
+ g_free(text);
|
|
+ g_object_unref(layout);
|
|
+
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::GetTextDimensions(const char* aString,
|
|
+ PRInt32 aLength,
|
|
+ PRInt32 aAvailWidth,
|
|
+ PRInt32* aBreaks,
|
|
+ PRInt32 aNumBreaks,
|
|
+ nsTextDimensions& aDimensions,
|
|
+ PRInt32& aNumCharsFit,
|
|
+ nsTextDimensions& aLastWordDimensions,
|
|
+ PRInt32* aFontID)
|
|
+{
|
|
+
|
|
+ return GetTextDimensionsInternal(aString, aLength, aAvailWidth, aBreaks,
|
|
+ aNumBreaks, aDimensions, aNumCharsFit,
|
|
+ aLastWordDimensions);
|
|
+
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::GetTextDimensions(const PRUnichar* aString,
|
|
+ PRInt32 aLength,
|
|
+ PRInt32 aAvailWidth,
|
|
+ PRInt32* aBreaks,
|
|
+ PRInt32 aNumBreaks,
|
|
+ nsTextDimensions& aDimensions,
|
|
+ PRInt32& aNumCharsFit,
|
|
+ nsTextDimensions& aLastWordDimensions,
|
|
+ PRInt32* aFontID)
|
|
+{
|
|
+ nsresult rv = NS_OK;
|
|
+ PRInt32 curBreak = 0;
|
|
+ gchar *curChar;
|
|
+
|
|
+ PRInt32 *utf8Breaks = new PRInt32[aNumBreaks];
|
|
+
|
|
+ gchar *text = g_utf16_to_utf8(aString, (PRInt32)aLength,
|
|
+ NULL, NULL, NULL);
|
|
+
|
|
+ curChar = text;
|
|
+
|
|
+ if (!text) {
|
|
+#ifdef DEBUG
|
|
+ NS_WARNING("nsFontMetricsPSPango::GetWidth invalid unicode to follow");
|
|
+ DUMP_PRUNICHAR(aString, (PRUint32)aLength)
|
|
+#endif
|
|
+ rv = NS_ERROR_FAILURE;
|
|
+ goto loser;
|
|
+ }
|
|
+
|
|
+ // Covert the utf16 break offsets to utf8 break offsets
|
|
+ for (PRInt32 curOffset=0; curOffset < aLength;
|
|
+ curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
|
|
+ if (aBreaks[curBreak] == curOffset) {
|
|
+ utf8Breaks[curBreak] = curChar - text;
|
|
+ curBreak++;
|
|
+ }
|
|
+
|
|
+ if (IS_HIGH_SURROGATE(aString[curOffset]))
|
|
+ curOffset++;
|
|
+ }
|
|
+
|
|
+ // Always catch the last break
|
|
+ utf8Breaks[curBreak] = curChar - text;
|
|
+
|
|
+#if 0
|
|
+ if (strlen(text) != aLength) {
|
|
+ printf("Different lengths for utf16 %d and utf8 %d\n", aLength, strlen(text));
|
|
+ DUMP_PRUNICHAR(aString, aLength)
|
|
+ DUMP_PRUNICHAR(text, strlen(text))
|
|
+ for (PRInt32 i = 0; i < aNumBreaks; ++i) {
|
|
+ printf(" break %d utf16 %d utf8 %d\n", i, aBreaks[i], utf8Breaks[i]);
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ // We'll use curBreak to indicate which of the breaks end up being
|
|
+ // used for the break point for this line.
|
|
+ curBreak = 0;
|
|
+ rv = GetTextDimensionsInternal(text, strlen(text), aAvailWidth, utf8Breaks,
|
|
+ aNumBreaks, aDimensions, aNumCharsFit,
|
|
+ aLastWordDimensions);
|
|
+
|
|
+ // Figure out which of the breaks we ended up using to convert
|
|
+ // back to utf16 - start from the end.
|
|
+ for (PRInt32 i = aNumBreaks - 1; i >= 0; --i) {
|
|
+ if (utf8Breaks[i] == aNumCharsFit) {
|
|
+ // if (aNumCharsFit != aBreaks[i])
|
|
+ // printf("Fixing utf8 -> utf16 %d -> %d\n", aNumCharsFit, aBreaks[i]);
|
|
+ aNumCharsFit = aBreaks[i];
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ loser:
|
|
+ if (text)
|
|
+ g_free(text);
|
|
+
|
|
+ delete[] utf8Breaks;
|
|
+
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+typedef struct _nsPSPangoRenderer nsPSPangoRenderer;
|
|
+typedef struct _nsPSPangoRendererClass nsPSPangoRendererClass;
|
|
+
|
|
+struct _nsPSPangoRenderer
|
|
+{
|
|
+ PangoRenderer parent_instance;
|
|
+ nsRenderingContextPS *psContext;
|
|
+ nsFontMetricsPSPango *psPangoFontMetrics;
|
|
+ float zoom;
|
|
+};
|
|
+
|
|
+struct _nsPSPangoRendererClass
|
|
+{
|
|
+ PangoRendererClass parent_class;
|
|
+};
|
|
+
|
|
+#define _PS_TYPE_PANGO_RENDERER (_ps_pango_renderer_get_type())
|
|
+#define _PS_PANGO_RENDERER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRenderer))
|
|
+#define _PS_IS_PANGO_RENDERER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), _PS_TYPE_PANGO_RENDERER))
|
|
+#define _PS_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRendererClass))
|
|
+#define _PS_IS_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), _PS_TYPE_PANGO_RENDERER))
|
|
+#define _PS_PANGO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRendererClass))
|
|
+
|
|
+G_DEFINE_TYPE (_nsPSPangoRenderer, _ps_pango_renderer, PANGO_TYPE_RENDERER)
|
|
+
|
|
+static PangoRenderer *
|
|
+get_renderer (void)
|
|
+{
|
|
+ static PangoRenderer *renderer = NULL;
|
|
+
|
|
+ if (!renderer)
|
|
+ renderer = (PangoRenderer *) g_object_new (_PS_TYPE_PANGO_RENDERER, NULL);
|
|
+
|
|
+ return renderer;
|
|
+}
|
|
+
|
|
+static void
|
|
+_ps_pango_renderer_draw_glyphs (PangoRenderer *renderer,
|
|
+ PangoFont *font,
|
|
+ PangoGlyphString *glyphs,
|
|
+ int x,
|
|
+ int y);
|
|
+
|
|
+static void
|
|
+_ps_pango_renderer_class_init (nsPSPangoRendererClass *klass)
|
|
+{
|
|
+ PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
|
|
+
|
|
+ renderer_class->draw_glyphs = _ps_pango_renderer_draw_glyphs;
|
|
+}
|
|
+
|
|
+static void
|
|
+_ps_pango_renderer_init (nsPSPangoRenderer *renderer)
|
|
+{
|
|
+}
|
|
+
|
|
+class nsPangoType1Generator : public nsPSFontGenerator {
|
|
+public:
|
|
+ nsPangoType1Generator();
|
|
+ ~nsPangoType1Generator();
|
|
+ nsresult Init(PangoFont *aFont);
|
|
+ void GeneratePSFont(FILE* aFile);
|
|
+
|
|
+protected:
|
|
+ PangoFont *mFont;
|
|
+};
|
|
+
|
|
+nsPangoType1Generator::nsPangoType1Generator()
|
|
+{
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsPangoType1Generator::Init(PangoFont *aFont)
|
|
+{
|
|
+ NS_ENSURE_TRUE(aFont, NS_ERROR_FAILURE);
|
|
+ mFont = aFont;
|
|
+ g_object_ref (mFont);
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+nsPangoType1Generator::~nsPangoType1Generator()
|
|
+{
|
|
+ g_object_unref (mFont);
|
|
+ mFont = nsnull;
|
|
+}
|
|
+
|
|
+void nsPangoType1Generator::GeneratePSFont(FILE* aFile)
|
|
+{
|
|
+ FT_Face face = pango_fc_font_lock_face ((PangoFcFont *) mFont);
|
|
+
|
|
+ if (face == nsnull)
|
|
+ return;
|
|
+
|
|
+ int wmode = 0;
|
|
+ if (mGlyphSubset->Count())
|
|
+ FT2SubsetToType1FontSet(face, mGlyphSubset, wmode, aFile);
|
|
+
|
|
+ pango_fc_font_unlock_face ((PangoFcFont *) mFont);
|
|
+}
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ nsCString *FontNameBase;
|
|
+ nsCStringKey *key;
|
|
+ int font_size;
|
|
+} PSPangoFontData;
|
|
+
|
|
+static void
|
|
+ps_pango_font_data_destroy (PSPangoFontData *data)
|
|
+{
|
|
+ delete data->key;
|
|
+ delete data->FontNameBase;
|
|
+ g_free (data);
|
|
+}
|
|
+
|
|
+static void
|
|
+flattenName(nsCString& aString)
|
|
+{
|
|
+ nsCString::iterator start, end;
|
|
+ aString.BeginWriting(start);
|
|
+ aString.EndWriting(end);
|
|
+ while(start != end) {
|
|
+ if (*start == ' ')
|
|
+ *start= '_';
|
|
+ else if (*start == '(')
|
|
+ *start = '_';
|
|
+ else if (*start == ')')
|
|
+ *start = '_';
|
|
+ ++start;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+_ps_pango_renderer_draw_glyphs (PangoRenderer *renderer,
|
|
+ PangoFont *font,
|
|
+ PangoGlyphString *glyphs,
|
|
+ int x,
|
|
+ int y)
|
|
+{
|
|
+ if (!glyphs->num_glyphs)
|
|
+ return;
|
|
+
|
|
+ static GQuark data_quark = 0;
|
|
+ if (!data_quark)
|
|
+ data_quark = g_quark_from_static_string ("ps-pango-font-data");
|
|
+
|
|
+ PSPangoFontData *data;
|
|
+ if (!(data = (PSPangoFontData *) g_object_get_qdata (G_OBJECT (font), data_quark)))
|
|
+ {
|
|
+ data = g_new (PSPangoFontData, 1);
|
|
+
|
|
+ FT_Face face = pango_fc_font_lock_face ((PangoFcFont *) font);
|
|
+ if (face == nsnull)
|
|
+ return;
|
|
+ int wmode = 0;
|
|
+ data->FontNameBase = new nsCString ();
|
|
+ if (NS_FAILED(FT2ToType1FontName(face, wmode, *data->FontNameBase))) {
|
|
+ g_free (data);
|
|
+ pango_fc_font_unlock_face ((PangoFcFont *) font);
|
|
+ return;
|
|
+ }
|
|
+ pango_fc_font_unlock_face ((PangoFcFont *) font);
|
|
+
|
|
+ PangoFontDescription *desc = pango_font_describe (font);
|
|
+ data->font_size = pango_font_description_get_size (desc);
|
|
+ pango_font_description_free (desc);
|
|
+
|
|
+ data->key = new nsCStringKey (*data->FontNameBase);
|
|
+
|
|
+ g_object_set_qdata_full (G_OBJECT (font), data_quark, data, (GDestroyNotify) ps_pango_font_data_destroy);
|
|
+ }
|
|
+
|
|
+ nsPSPangoRenderer *ps_renderer = (nsPSPangoRenderer *)renderer;
|
|
+ nsRenderingContextPS *aContext = ps_renderer->psContext;
|
|
+ nsFontMetricsPSPango *metrics = ps_renderer->psPangoFontMetrics;
|
|
+ nsDeviceContextPS* dc = NS_REINTERPRET_CAST (nsDeviceContextPS*, metrics->GetDeviceContext());
|
|
+ nsPostScriptObj* psObj = aContext->GetPostScriptObj();
|
|
+ nsHashtable *psFGList = dc->GetPSFontGeneratorList();
|
|
+ g_return_if_fail (psFGList);
|
|
+ nsPSFontGenerator* psFontGen = (nsPSFontGenerator*) psFGList->Get(data->key);
|
|
+ if (!psFontGen) {
|
|
+ nsresult rv;
|
|
+ psFontGen = new nsPangoType1Generator;
|
|
+ g_return_if_fail (psFontGen);
|
|
+ rv = ((nsPangoType1Generator*)psFontGen)->Init(font);
|
|
+ if (NS_FAILED(rv)) {
|
|
+ delete psFontGen;
|
|
+ return;
|
|
+ }
|
|
+ psFGList->Put(data->key, (void *) psFontGen);
|
|
+ }
|
|
+ nscoord font_size = NSToCoordRound (ps_renderer->zoom * data->font_size / PANGO_SCALE);
|
|
+
|
|
+ g_return_if_fail (aContext);
|
|
+ g_return_if_fail (psObj);
|
|
+
|
|
+ nscoord aX = NSToCoordRound(ps_renderer->zoom * x / PANGO_SCALE);
|
|
+ nscoord aY = NSToCoordRound(ps_renderer->zoom * y / PANGO_SCALE);
|
|
+ psObj->moveto(aX, aY);
|
|
+
|
|
+ PRInt32 currSubFont, prevSubFont = -1;
|
|
+ PRUint32 i;
|
|
+ PangoGlyphString gl;
|
|
+
|
|
+ gl.glyphs = glyphs->glyphs;
|
|
+ gl.num_glyphs = 0;
|
|
+ for (i = 0; i < glyphs->num_glyphs; ++i) {
|
|
+ currSubFont = psFontGen->AddToGlyphSubset(glyphs->glyphs[i].glyph >= 0x00ffffff ? 0 : glyphs->glyphs[i].glyph);
|
|
+ if (prevSubFont != currSubFont) {
|
|
+ if (prevSubFont != -1)
|
|
+ psObj->show(&gl, ps_renderer->zoom, psFontGen, prevSubFont);
|
|
+
|
|
+
|
|
+ psObj->setfont(*data->FontNameBase, (PRUint32) font_size, currSubFont);
|
|
+ prevSubFont = currSubFont;
|
|
+ gl.glyphs = glyphs->glyphs + i;
|
|
+ gl.num_glyphs = 0;
|
|
+ }
|
|
+
|
|
+ gl.num_glyphs++;
|
|
+ }
|
|
+
|
|
+ if (prevSubFont != -1)
|
|
+ psObj->show(&gl, ps_renderer->zoom, psFontGen, prevSubFont);
|
|
+}
|
|
+
|
|
+static void
|
|
+draw_layout_line (int x, int y, PangoLayoutLine *line, nsFontMetricsPSPango *aPSPangoFontMetrics, nsRenderingContextPS *aContext)
|
|
+{
|
|
+ PangoRenderer *renderer = get_renderer ();
|
|
+ nsPSPangoRenderer *ps_renderer = (nsPSPangoRenderer *)renderer;
|
|
+ ps_renderer->psContext = aContext;
|
|
+ ps_renderer->psPangoFontMetrics = aPSPangoFontMetrics;
|
|
+ nsDeviceContextPS* dc = NS_REINTERPRET_CAST (nsDeviceContextPS*, aPSPangoFontMetrics->GetDeviceContext());
|
|
+ ps_renderer->zoom = dc->DevUnitsToAppUnits();
|
|
+
|
|
+ pango_renderer_draw_layout_line (renderer, line,
|
|
+ NSToCoordRound (x * PANGO_SCALE / ps_renderer->zoom),
|
|
+ NSToCoordRound (y * PANGO_SCALE / ps_renderer->zoom));
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::DrawString(const char *aString, PRUint32 aLength,
|
|
+ nscoord aX, nscoord aY,
|
|
+ const nscoord* aSpacing,
|
|
+ nsRenderingContextPS *aContext)
|
|
+{
|
|
+ PangoLayout *layout = pango_layout_new(mPangoContext);
|
|
+
|
|
+ pango_layout_set_text(layout, aString, aLength);
|
|
+ FixupSpaceWidths(layout, aString);
|
|
+
|
|
+ int x = aX;
|
|
+ int y = aY;
|
|
+
|
|
+ aContext->GetTranMatrix()->TransformCoord(&x, &y);
|
|
+
|
|
+ PangoLayoutLine *line;
|
|
+ if (pango_layout_get_line_count(layout) != 1) {
|
|
+ printf("Warning: more than one line!\n");
|
|
+ }
|
|
+ line = pango_layout_get_line(layout, 0);
|
|
+
|
|
+ if (aSpacing && *aSpacing) {
|
|
+ DrawStringSlowly(aString, NULL, aLength, x, y, line, aSpacing, aContext);
|
|
+ }
|
|
+ else {
|
|
+ draw_layout_line (x, y, line, this, aContext);
|
|
+ }
|
|
+
|
|
+ g_object_unref(layout);
|
|
+
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::DrawString(const PRUnichar* aString, PRUint32 aLength,
|
|
+ nscoord aX, nscoord aY,
|
|
+ PRInt32 aFontID,
|
|
+ const nscoord* aSpacing,
|
|
+ nsRenderingContextPS *aContext)
|
|
+{
|
|
+ nsresult rv = NS_OK;
|
|
+ int x = aX;
|
|
+ int y = aY;
|
|
+
|
|
+ PangoLayout *layout = pango_layout_new(mPangoContext);
|
|
+
|
|
+ gchar *text = g_utf16_to_utf8(aString, aLength,
|
|
+ NULL, NULL, NULL);
|
|
+ if (!text) {
|
|
+#ifdef DEBUG
|
|
+ NS_WARNING("nsFontMetricsPSPango::DrawString invalid unicode to follow");
|
|
+ DUMP_PRUNICHAR(aString, aLength)
|
|
+#endif
|
|
+ rv = NS_ERROR_FAILURE;
|
|
+ goto loser;
|
|
+ }
|
|
+
|
|
+ pango_layout_set_text(layout, text, strlen(text));
|
|
+ FixupSpaceWidths(layout, text);
|
|
+
|
|
+ aContext->GetTranMatrix()->TransformCoord(&x, &y);
|
|
+
|
|
+ PangoLayoutLine *line;
|
|
+ if (pango_layout_get_line_count(layout) != 1) {
|
|
+ printf("Warning: more than one line!\n");
|
|
+ }
|
|
+ line = pango_layout_get_line(layout, 0);
|
|
+
|
|
+ if (aSpacing && *aSpacing) {
|
|
+ DrawStringSlowly(text, aString, aLength, x, y, line, aSpacing, aContext);
|
|
+ }
|
|
+ else {
|
|
+ draw_layout_line (x, y, line, this, aContext);
|
|
+ }
|
|
+
|
|
+ loser:
|
|
+
|
|
+ g_free(text);
|
|
+ g_object_unref(layout);
|
|
+
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+#ifdef MOZ_MATHML
|
|
+nsresult
|
|
+nsFontMetricsPSPango::GetBoundingMetrics(const char *aString, PRUint32 aLength,
|
|
+ nsBoundingMetrics &aBoundingMetrics)
|
|
+{
|
|
+ printf("GetBoundingMetrics (char *)\n");
|
|
+ return NS_ERROR_FAILURE;
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::GetBoundingMetrics(const PRUnichar *aString,
|
|
+ PRUint32 aLength,
|
|
+ nsBoundingMetrics &aBoundingMetrics,
|
|
+ PRInt32 *aFontID)
|
|
+{
|
|
+ nsresult rv = NS_OK;
|
|
+ PangoLayout *layout = pango_layout_new(mPangoContext);
|
|
+
|
|
+ gchar *text = g_utf16_to_utf8(aString, aLength,
|
|
+ NULL, NULL, NULL);
|
|
+
|
|
+ if (!text) {
|
|
+#ifdef DEBUG
|
|
+ NS_WARNING("nsFontMetricsPSPango::GetBoundingMetrics invalid unicode to follow");
|
|
+ DUMP_PRUNICHAR(aString, aLength)
|
|
+#endif
|
|
+ aBoundingMetrics.leftBearing = 0;
|
|
+ aBoundingMetrics.rightBearing = 0;
|
|
+ aBoundingMetrics.width = 0;
|
|
+ aBoundingMetrics.ascent = 0;
|
|
+ aBoundingMetrics.descent = 0;
|
|
+
|
|
+ rv = NS_ERROR_FAILURE;
|
|
+ goto loser;
|
|
+ }
|
|
+
|
|
+ pango_layout_set_text(layout, text, -1);
|
|
+ FixupSpaceWidths(layout, text);
|
|
+
|
|
+ PangoLayoutLine *line;
|
|
+ if (pango_layout_get_line_count(layout) != 1) {
|
|
+ printf("Warning: more than one line!\n");
|
|
+ }
|
|
+ line = pango_layout_get_line(layout, 0);
|
|
+
|
|
+ // Get the ink and logical extents
|
|
+ PangoRectangle ink, logical;
|
|
+ pango_layout_line_get_extents(line, &ink, &logical);
|
|
+
|
|
+ float P2T;
|
|
+ P2T = mDeviceContext->DevUnitsToAppUnits();
|
|
+
|
|
+ aBoundingMetrics.leftBearing = NSToCoordRound(PANGO_LBEARING(ink) * P2T / PANGO_SCALE);
|
|
+ aBoundingMetrics.rightBearing = NSToCoordRound(PANGO_RBEARING(ink) * P2T / PANGO_SCALE);
|
|
+ aBoundingMetrics.ascent = NSToCoordRound(PANGO_ASCENT(ink) * P2T / PANGO_SCALE);
|
|
+ aBoundingMetrics.descent = NSToCoordRound(PANGO_DESCENT(ink) * P2T / PANGO_SCALE);
|
|
+ aBoundingMetrics.width = NSToCoordRound(logical.width * P2T / PANGO_SCALE);
|
|
+
|
|
+ loser:
|
|
+ g_free(text);
|
|
+ g_object_unref(layout);
|
|
+
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+#endif /* MOZ_MATHML */
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::SetRightToLeftText(PRBool aIsRTL)
|
|
+{
|
|
+ if (aIsRTL) {
|
|
+ if (!mRTLPangoContext) {
|
|
+ mRTLPangoContext = get_context();
|
|
+ pango_context_set_base_dir(mRTLPangoContext, PANGO_DIRECTION_RTL);
|
|
+
|
|
+ pango_context_set_language(mRTLPangoContext, GetPangoLanguage(mLangGroup));
|
|
+ pango_context_set_font_description(mRTLPangoContext, mPangoFontDesc);
|
|
+ }
|
|
+ mPangoContext = mRTLPangoContext;
|
|
+ }
|
|
+ else {
|
|
+ mPangoContext = mLTRPangoContext;
|
|
+ }
|
|
+
|
|
+ mIsRTL = aIsRTL;
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::GetClusterInfo(const PRUnichar *aText,
|
|
+ PRUint32 aLength,
|
|
+ PRUint8 *aClusterStarts)
|
|
+{
|
|
+ nsresult rv = NS_OK;
|
|
+ PangoLogAttr *attrs = NULL;
|
|
+ gint n_attrs = 0;
|
|
+ PangoLayout *layout = pango_layout_new(mPangoContext);
|
|
+
|
|
+ // Convert the incoming UTF-16 to UTF-8
|
|
+ gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
|
|
+
|
|
+ if (!text) {
|
|
+#ifdef DEBUG
|
|
+ NS_WARNING("nsFontMetricsPSPango::GetWidth invalid unicode to follow");
|
|
+ DUMP_PRUNICHAR(aText, aLength)
|
|
+#endif
|
|
+ rv = NS_ERROR_FAILURE;
|
|
+ goto loser;
|
|
+ }
|
|
+
|
|
+ // Set up the pango layout
|
|
+ pango_layout_set_text(layout, text, strlen(text));
|
|
+ FixupSpaceWidths(layout, text);
|
|
+
|
|
+ // Convert back to UTF-16 while filling in the cluster info
|
|
+ // structure.
|
|
+ pango_layout_get_log_attrs(layout, &attrs, &n_attrs);
|
|
+
|
|
+ for (PRUint32 pos = 0; pos < aLength; pos++) {
|
|
+ if (IS_HIGH_SURROGATE(aText[pos])) {
|
|
+ aClusterStarts[pos] = 1;
|
|
+ pos++;
|
|
+ }
|
|
+ else {
|
|
+ aClusterStarts[pos] = attrs[pos].is_cursor_position;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ loser:
|
|
+ if (attrs)
|
|
+ g_free(attrs);
|
|
+ if (text)
|
|
+ g_free(text);
|
|
+ if (layout)
|
|
+ g_object_unref(layout);
|
|
+
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+PRInt32
|
|
+nsFontMetricsPSPango::GetPosition(const PRUnichar *aText, PRUint32 aLength,
|
|
+ nsPoint aPt)
|
|
+{
|
|
+ int trailing = 0;
|
|
+ int inx = 0;
|
|
+ const gchar *curChar;
|
|
+ PRInt32 retval = 0;
|
|
+
|
|
+ float f = mDeviceContext->AppUnitsToDevUnits();
|
|
+
|
|
+ PangoLayout *layout = pango_layout_new(mPangoContext);
|
|
+ PRUint32 localX = (PRUint32)(aPt.x * PANGO_SCALE * f);
|
|
+ PRUint32 localY = (PRUint32)(aPt.y * PANGO_SCALE * f);
|
|
+
|
|
+ // Convert the incoming UTF-16 to UTF-8
|
|
+ gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
|
|
+
|
|
+ if (!text) {
|
|
+#ifdef DEBUG
|
|
+ NS_WARNING("nsFontMetricsPSPango::GetWidth invalid unicode to follow");
|
|
+ DUMP_PRUNICHAR(aText, aLength)
|
|
+#endif
|
|
+ retval = -1;
|
|
+ goto loser;
|
|
+ }
|
|
+
|
|
+ // Set up the pango layout
|
|
+ pango_layout_set_text(layout, text, strlen(text));
|
|
+ FixupSpaceWidths(layout, text);
|
|
+
|
|
+ pango_layout_xy_to_index(layout, localX, localY,
|
|
+ &inx, &trailing);
|
|
+
|
|
+ // Convert the index back to the utf-16 index
|
|
+ curChar = text;
|
|
+
|
|
+ for (PRUint32 curOffset=0; curOffset < aLength;
|
|
+ curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
|
|
+
|
|
+ // Check for a match before checking for a surrogate pair
|
|
+ if (curChar - text == inx) {
|
|
+ retval = curOffset;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (IS_HIGH_SURROGATE(aText[curOffset]))
|
|
+ curOffset++;
|
|
+ }
|
|
+
|
|
+ // If there was a trailing result, advance the index pointer the
|
|
+ // number of characters equal to the trailing result.
|
|
+ while (trailing) {
|
|
+ retval++;
|
|
+ // Yes, this can make aInx > length to indicate the end of the
|
|
+ // string.
|
|
+ if (retval < (PRInt32)aLength && IS_HIGH_SURROGATE(aText[retval]))
|
|
+ retval++;
|
|
+ trailing--;
|
|
+ }
|
|
+
|
|
+ loser:
|
|
+ if (text)
|
|
+ g_free(text);
|
|
+ if (layout)
|
|
+ g_object_unref(layout);
|
|
+
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::GetRangeWidth(const PRUnichar *aText,
|
|
+ PRUint32 aLength,
|
|
+ PRUint32 aStart,
|
|
+ PRUint32 aEnd,
|
|
+ PRUint32 &aWidth)
|
|
+{
|
|
+ nsresult rv = NS_OK;
|
|
+ PRUint32 utf8Start = 0;
|
|
+ PRUint32 utf8End = 0;
|
|
+
|
|
+ aWidth = 0;
|
|
+
|
|
+ // Convert the incoming UTF-16 to UTF-8
|
|
+ gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
|
|
+ gchar *curChar = text;
|
|
+
|
|
+ if (!text) {
|
|
+#ifdef DEBUG
|
|
+ NS_WARNING("nsFontMetricsPSPango::GetWidth invalid unicode to follow");
|
|
+ DUMP_PRUNICHAR(aText, aLength)
|
|
+#endif
|
|
+ rv = NS_ERROR_FAILURE;
|
|
+ goto loser;
|
|
+ }
|
|
+
|
|
+ // Convert the utf16 offsets into utf8 offsets
|
|
+ for (PRUint32 curOffset = 0; curOffset < aLength;
|
|
+ curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
|
|
+
|
|
+ if (curOffset == aStart)
|
|
+ utf8Start = curChar - text;
|
|
+
|
|
+ if (curOffset == aEnd)
|
|
+ utf8End = curChar - text;
|
|
+
|
|
+ if (IS_HIGH_SURROGATE(aText[curOffset]))
|
|
+ curOffset++;
|
|
+ }
|
|
+
|
|
+ // Special case where the end index is the same as the length
|
|
+ if (aLength == aEnd)
|
|
+ utf8End = strlen(text);
|
|
+
|
|
+ rv = GetRangeWidth(text, strlen(text), utf8Start, utf8End, aWidth);
|
|
+
|
|
+ loser:
|
|
+ if (text)
|
|
+ g_free(text);
|
|
+
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::GetRangeWidth(const char *aText,
|
|
+ PRUint32 aLength,
|
|
+ PRUint32 aStart,
|
|
+ PRUint32 aEnd,
|
|
+ PRUint32 &aWidth)
|
|
+{
|
|
+ nsresult rv = NS_OK;
|
|
+ int *ranges = NULL;
|
|
+ int n_ranges = 0;
|
|
+ float f;
|
|
+
|
|
+ aWidth = 0;
|
|
+
|
|
+ PangoLayout *layout = pango_layout_new(mPangoContext);
|
|
+
|
|
+ if (!aText) {
|
|
+ rv = NS_ERROR_FAILURE;
|
|
+ goto loser;
|
|
+ }
|
|
+
|
|
+ pango_layout_set_text(layout, aText, aLength);
|
|
+ FixupSpaceWidths(layout, aText);
|
|
+
|
|
+ PangoLayoutLine *line;
|
|
+ if (pango_layout_get_line_count(layout) != 1) {
|
|
+ printf("Warning: more than one line!\n");
|
|
+ }
|
|
+ line = pango_layout_get_line(layout, 0);
|
|
+
|
|
+ pango_layout_line_get_x_ranges(line, aStart, aEnd, &ranges, &n_ranges);
|
|
+
|
|
+ aWidth = (ranges[((n_ranges - 1) * 2) + 1] - ranges[0]);
|
|
+
|
|
+ f = mDeviceContext-> DevUnitsToAppUnits();
|
|
+ aWidth = nscoord(aWidth * f / PANGO_SCALE);
|
|
+
|
|
+ loser:
|
|
+ if (ranges)
|
|
+ g_free(ranges);
|
|
+ if (layout)
|
|
+ g_object_unref(layout);
|
|
+
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+PRUint32
|
|
+nsFontMetricsPSPango::GetHints(void)
|
|
+{
|
|
+ return (NS_RENDERING_HINT_BIDI_REORDERING |
|
|
+ NS_RENDERING_HINT_ARABIC_SHAPING |
|
|
+ NS_RENDERING_HINT_FAST_MEASURE |
|
|
+ NS_RENDERING_HINT_REORDER_SPACED_TEXT |
|
|
+ NS_RENDERING_HINT_TEXT_CLUSTERS);
|
|
+}
|
|
+
|
|
+/* static */
|
|
+nsresult
|
|
+nsFontMetricsPSPango::FamilyExists(nsIDeviceContext *aDevice,
|
|
+ const nsString &aName)
|
|
+{
|
|
+ // fontconfig family name is always in UTF-8
|
|
+ NS_ConvertUTF16toUTF8 name(aName);
|
|
+
|
|
+ nsresult rv = NS_ERROR_FAILURE;
|
|
+ PangoContext *context = get_context();
|
|
+ PangoFontFamily **familyList;
|
|
+ int n;
|
|
+
|
|
+ pango_context_list_families(context, &familyList, &n);
|
|
+
|
|
+ for (int i=0; i < n; i++) {
|
|
+ const char *tmpname = pango_font_family_get_name(familyList[i]);
|
|
+ if (!Compare(nsDependentCString(tmpname), name,
|
|
+ nsCaseInsensitiveCStringComparator())) {
|
|
+ rv = NS_OK;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ g_free(familyList);
|
|
+ g_object_unref(context);
|
|
+
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+// Private Methods
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::RealizeFont(void)
|
|
+{
|
|
+ nsCString familyList;
|
|
+ // Create and fill out the font description.
|
|
+ mPangoFontDesc = pango_font_description_new();
|
|
+
|
|
+ // Add CSS names - walk the list of fonts, adding the generic as
|
|
+ // the last font
|
|
+ for (int i=0; i < mFontList.Count(); ++i) {
|
|
+ // if this was a generic name, break out of the loop since we
|
|
+ // don't want to add it to the pattern yet
|
|
+ if (mFontIsGeneric[i])
|
|
+ break;;
|
|
+
|
|
+ nsCString *familyName = mFontList.CStringAt(i);
|
|
+ familyList.Append(familyName->get());
|
|
+ familyList.Append(',');
|
|
+ }
|
|
+
|
|
+ // If there's a generic add a pref for the generic if there's one
|
|
+ // set.
|
|
+ if (mGenericFont && !mFont.systemFont) {
|
|
+ nsCString name;
|
|
+ name += "font.name.";
|
|
+ name += mGenericFont->get();
|
|
+ name += ".";
|
|
+
|
|
+ nsString langGroup;
|
|
+ mLangGroup->ToString(langGroup);
|
|
+
|
|
+ name.AppendWithConversion(langGroup);
|
|
+
|
|
+ nsCOMPtr<nsIPref> pref;
|
|
+ pref = do_GetService(NS_PREF_CONTRACTID);
|
|
+ if (pref) {
|
|
+ nsresult rv;
|
|
+ nsXPIDLCString value;
|
|
+ rv = pref->GetCharPref(name.get(), getter_Copies(value));
|
|
+
|
|
+ // we ignore prefs that have three hypens since they are X
|
|
+ // style prefs.
|
|
+ if (NS_FFRECountHyphens(value) < 3) {
|
|
+ nsCString tmpstr;
|
|
+ tmpstr.Append(value);
|
|
+
|
|
+ familyList.Append(tmpstr);
|
|
+ familyList.Append(',');
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Add the generic if there is one.
|
|
+ if (mGenericFont && !mFont.systemFont) {
|
|
+ familyList.Append(mGenericFont->get());
|
|
+ familyList.Append(',');
|
|
+ }
|
|
+
|
|
+ // Set the family
|
|
+ pango_font_description_set_family(mPangoFontDesc,
|
|
+ familyList.get());
|
|
+
|
|
+ // Set the point size
|
|
+ pango_font_description_set_size(mPangoFontDesc,
|
|
+ (gint)(mPointSize * PANGO_SCALE));
|
|
+
|
|
+ // Set the style
|
|
+ pango_font_description_set_style(mPangoFontDesc,
|
|
+ CalculateStyle(mFont.style));
|
|
+
|
|
+ // Set the weight
|
|
+ pango_font_description_set_weight(mPangoFontDesc,
|
|
+ CalculateWeight(mFont.weight));
|
|
+
|
|
+ // Now that we have the font description set up, create the
|
|
+ // context.
|
|
+ mLTRPangoContext = get_context();
|
|
+ mPangoContext = mLTRPangoContext;
|
|
+
|
|
+ // Make sure to set the base direction to LTR - if layout needs to
|
|
+ // render RTL text it will use ::SetRightToLeftText()
|
|
+ pango_context_set_base_dir(mPangoContext, PANGO_DIRECTION_LTR);
|
|
+
|
|
+ // Set the pango language now that we have a context
|
|
+ pango_context_set_language(mPangoContext, GetPangoLanguage(mLangGroup));
|
|
+
|
|
+ // And attach the font description to this context
|
|
+ pango_context_set_font_description(mPangoContext, mPangoFontDesc);
|
|
+
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+/* static */
|
|
+PRBool
|
|
+nsFontMetricsPSPango::EnumFontCallback(const nsString &aFamily,
|
|
+ PRBool aIsGeneric, void *aData)
|
|
+{
|
|
+ NS_ConvertUTF16toUTF8 name(aFamily);
|
|
+
|
|
+ // The newest fontconfig does the full Unicode case folding so that
|
|
+ // we're being lazy here by calling |ToLowerCase| after converting
|
|
+ // to UTF-8 assuming that in virtually all cases, we just have to
|
|
+ // fold [A-Z]. (bug 223653).
|
|
+ ToLowerCase(name);
|
|
+ nsFontMetricsPSPango *metrics = (nsFontMetricsPSPango *)aData;
|
|
+ metrics->mFontList.AppendCString(name);
|
|
+ metrics->mFontIsGeneric.AppendElement((void *)aIsGeneric);
|
|
+ if (aIsGeneric) {
|
|
+ metrics->mGenericFont =
|
|
+ metrics->mFontList.CStringAt(metrics->mFontList.Count() - 1);
|
|
+ return PR_FALSE; // stop processing
|
|
+ }
|
|
+
|
|
+ return PR_TRUE; // keep processing
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This is only used when there's per-character spacing happening.
|
|
+ * Well, really it can be either line or character spacing but it's
|
|
+ * just turtles all the way down!
|
|
+ */
|
|
+
|
|
+void
|
|
+nsFontMetricsPSPango::DrawStringSlowly(const gchar *aText,
|
|
+ const PRUnichar *aOrigString,
|
|
+ PRUint32 aLength,
|
|
+ gint aX, gint aY,
|
|
+ PangoLayoutLine *aLine,
|
|
+ const nscoord *aSpacing,
|
|
+ nsRenderingContextPS *aContext)
|
|
+{
|
|
+ float app2dev;
|
|
+ app2dev = mDeviceContext->AppUnitsToDevUnits();
|
|
+ gint offset = 0;
|
|
+
|
|
+ /*
|
|
+ * We walk the list of glyphs returned in each layout run,
|
|
+ * matching up the glyphs with the characters in the source text.
|
|
+ * We use the aSpacing argument to figure out where to place those
|
|
+ * glyphs. It's important to note that since the string we're
|
|
+ * working with is in UTF-8 while the spacing argument assumes
|
|
+ * that offset will be part of the UTF-16 string. Logical
|
|
+ * attributes in pango are in byte offsets in the UTF-8 string, so
|
|
+ * we need to store the offsets based on the UTF-8 string.
|
|
+ */
|
|
+ nscoord *utf8spacing = new nscoord[strlen(aText)];
|
|
+
|
|
+ if (aOrigString) {
|
|
+ const gchar *curChar = aText;
|
|
+ bzero(utf8spacing, sizeof(nscoord) * strlen(aText));
|
|
+
|
|
+ // Covert the utf16 spacing offsets to utf8 spacing offsets
|
|
+ for (PRUint32 curOffset=0; curOffset < aLength;
|
|
+ curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
|
|
+ utf8spacing[curChar - aText] = aSpacing[curOffset];
|
|
+
|
|
+ if (IS_HIGH_SURROGATE(aOrigString[curOffset]))
|
|
+ curOffset++;
|
|
+ }
|
|
+ }
|
|
+ else {
|
|
+ memcpy(utf8spacing, aSpacing, (sizeof(nscoord *) * aLength));
|
|
+ }
|
|
+
|
|
+ gint curRun = 0;
|
|
+
|
|
+ for (GSList *tmpList = aLine->runs; tmpList && tmpList->data;
|
|
+ tmpList = tmpList->next, curRun++) {
|
|
+ PangoLayoutRun *layoutRun = (PangoLayoutRun *)tmpList->data;
|
|
+ gint tmpOffset = 0;
|
|
+
|
|
+ /* printf(" Rendering run %d: \"%s\"\n", curRun,
|
|
+ &aText[layoutRun->item->offset]); */
|
|
+
|
|
+ for (gint i=0; i < layoutRun->glyphs->num_glyphs; i++) {
|
|
+ /* printf("glyph %d offset %d orig width %d new width %d\n", i,
|
|
+ * layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset,
|
|
+ * layoutRun->glyphs->glyphs[i].geometry.width,
|
|
+ * (gint)(utf8spacing[layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset] * app2dev * PANGO_SCALE));
|
|
+ */
|
|
+ gint thisOffset = (gint)(utf8spacing[layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset]
|
|
+ * app2dev * PANGO_SCALE);
|
|
+ layoutRun->glyphs->glyphs[i].geometry.width = thisOffset;
|
|
+ tmpOffset += thisOffset;
|
|
+ }
|
|
+
|
|
+ /* printf(" rendering at X coord %d\n", aX + offset); */
|
|
+ offset += tmpOffset;
|
|
+ }
|
|
+
|
|
+ draw_layout_line (aX, aY, aLine, this, aContext);
|
|
+
|
|
+ delete[] utf8spacing;
|
|
+}
|
|
+
|
|
+nsresult
|
|
+nsFontMetricsPSPango::GetTextDimensionsInternal(const gchar* aString,
|
|
+ PRInt32 aLength,
|
|
+ PRInt32 aAvailWidth,
|
|
+ PRInt32* aBreaks,
|
|
+ PRInt32 aNumBreaks,
|
|
+ nsTextDimensions& aDimensions,
|
|
+ PRInt32& aNumCharsFit,
|
|
+ nsTextDimensions& aLastWordDimensions)
|
|
+{
|
|
+ NS_PRECONDITION(aBreaks[aNumBreaks - 1] == aLength, "invalid break array");
|
|
+
|
|
+ // If we need to back up this state represents the last place
|
|
+ // we could break. We can use this to avoid remeasuring text
|
|
+ PRInt32 prevBreakState_BreakIndex = -1; // not known
|
|
+ // (hasn't been computed)
|
|
+ nscoord prevBreakState_Width = 0; // accumulated width to this point
|
|
+
|
|
+ // Initialize OUT parameters
|
|
+ GetMaxAscent(aLastWordDimensions.ascent);
|
|
+ GetMaxDescent(aLastWordDimensions.descent);
|
|
+ aLastWordDimensions.width = -1;
|
|
+ aNumCharsFit = 0;
|
|
+
|
|
+ // Iterate each character in the string and determine which font to use
|
|
+ nscoord width = 0;
|
|
+ PRInt32 start = 0;
|
|
+ nscoord aveCharWidth;
|
|
+ GetAveCharWidth(aveCharWidth);
|
|
+
|
|
+ while (start < aLength) {
|
|
+ // Estimate how many characters will fit. Do that by
|
|
+ // diving the available space by the average character
|
|
+ // width. Make sure the estimated number of characters is
|
|
+ // at least 1
|
|
+ PRInt32 estimatedNumChars = 0;
|
|
+
|
|
+ if (aveCharWidth > 0)
|
|
+ estimatedNumChars = (aAvailWidth - width) / aveCharWidth;
|
|
+
|
|
+ if (estimatedNumChars < 1)
|
|
+ estimatedNumChars = 1;
|
|
+
|
|
+ // Find the nearest break offset
|
|
+ PRInt32 estimatedBreakOffset = start + estimatedNumChars;
|
|
+ PRInt32 breakIndex;
|
|
+ nscoord numChars;
|
|
+
|
|
+ // Find the nearest place to break that is less than or equal to
|
|
+ // the estimated break offset
|
|
+ if (aLength <= estimatedBreakOffset) {
|
|
+ // All the characters should fit
|
|
+ numChars = aLength - start;
|
|
+ breakIndex = aNumBreaks - 1;
|
|
+ }
|
|
+ else {
|
|
+ breakIndex = prevBreakState_BreakIndex;
|
|
+ while (((breakIndex + 1) < aNumBreaks) &&
|
|
+ (aBreaks[breakIndex + 1] <= estimatedBreakOffset)) {
|
|
+ ++breakIndex;
|
|
+ }
|
|
+
|
|
+ if (breakIndex == prevBreakState_BreakIndex) {
|
|
+ ++breakIndex; // make sure we advanced past the
|
|
+ // previous break index
|
|
+ }
|
|
+
|
|
+ numChars = aBreaks[breakIndex] - start;
|
|
+ }
|
|
+
|
|
+ // Measure the text
|
|
+ nscoord twWidth = 0;
|
|
+ if ((1 == numChars) && (aString[start] == ' '))
|
|
+ GetSpaceWidth(twWidth);
|
|
+ else if (numChars > 0)
|
|
+ GetWidth(&aString[start], numChars, twWidth);
|
|
+
|
|
+ // See if the text fits
|
|
+ PRBool textFits = (twWidth + width) <= aAvailWidth;
|
|
+
|
|
+ // If the text fits then update the width and the number of
|
|
+ // characters that fit
|
|
+ if (textFits) {
|
|
+ aNumCharsFit += numChars;
|
|
+ width += twWidth;
|
|
+ start += numChars;
|
|
+
|
|
+ // This is a good spot to back up to if we need to so remember
|
|
+ // this state
|
|
+ prevBreakState_BreakIndex = breakIndex;
|
|
+ prevBreakState_Width = width;
|
|
+ }
|
|
+ else {
|
|
+ // See if we can just back up to the previous saved
|
|
+ // state and not have to measure any text
|
|
+ if (prevBreakState_BreakIndex > 0) {
|
|
+ // If the previous break index is just before the
|
|
+ // current break index then we can use it
|
|
+ if (prevBreakState_BreakIndex == (breakIndex - 1)) {
|
|
+ aNumCharsFit = aBreaks[prevBreakState_BreakIndex];
|
|
+ width = prevBreakState_Width;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // We can't just revert to the previous break state
|
|
+ if (0 == breakIndex) {
|
|
+ // There's no place to back up to, so even though
|
|
+ // the text doesn't fit return it anyway
|
|
+ aNumCharsFit += numChars;
|
|
+ width += twWidth;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ // Repeatedly back up until we get to where the text
|
|
+ // fits or we're all the way back to the first word
|
|
+ width += twWidth;
|
|
+ while ((breakIndex >= 1) && (width > aAvailWidth)) {
|
|
+ twWidth = 0;
|
|
+ start = aBreaks[breakIndex - 1];
|
|
+ numChars = aBreaks[breakIndex] - start;
|
|
+
|
|
+ if ((1 == numChars) && (aString[start] == ' '))
|
|
+ GetSpaceWidth(twWidth);
|
|
+ else if (numChars > 0)
|
|
+ GetWidth(&aString[start], numChars, twWidth);
|
|
+ width -= twWidth;
|
|
+ aNumCharsFit = start;
|
|
+ breakIndex--;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ aDimensions.width = width;
|
|
+ GetMaxAscent(aDimensions.ascent);
|
|
+ GetMaxDescent(aDimensions.descent);
|
|
+
|
|
+ /* printf("aDimensions %d %d %d aLastWordDimensions %d %d %d aNumCharsFit %d\n",
|
|
+ aDimensions.width, aDimensions.ascent, aDimensions.descent,
|
|
+ aLastWordDimensions.width, aLastWordDimensions.ascent, aLastWordDimensions.descent,
|
|
+ aNumCharsFit); */
|
|
+
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+void
|
|
+nsFontMetricsPSPango::FixupSpaceWidths (PangoLayout *aLayout,
|
|
+ const char *aString)
|
|
+{
|
|
+ PangoLayoutLine *line = pango_layout_get_line(aLayout, 0);
|
|
+
|
|
+ gint curRun = 0;
|
|
+
|
|
+ for (GSList *tmpList = line->runs; tmpList && tmpList->data;
|
|
+ tmpList = tmpList->next, curRun++) {
|
|
+ PangoLayoutRun *layoutRun = (PangoLayoutRun *)tmpList->data;
|
|
+
|
|
+ for (gint i=0; i < layoutRun->glyphs->num_glyphs; i++) {
|
|
+ gint thisOffset = (gint)layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset;
|
|
+ if (aString[thisOffset] == ' ')
|
|
+ layoutRun->glyphs->glyphs[i].geometry.width = mPangoSpaceWidth;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/* static */
|
|
+PangoLanguage *
|
|
+GetPangoLanguage(nsIAtom *aLangGroup)
|
|
+{
|
|
+ // Find the FC lang group for this lang group
|
|
+ nsCAutoString cname;
|
|
+ aLangGroup->ToUTF8String(cname);
|
|
+
|
|
+ // see if the lang group needs to be translated from mozilla's
|
|
+ // internal mapping into fontconfig's
|
|
+ const MozGtkLangGroup *langGroup;
|
|
+ langGroup = NS_FindFCLangGroup(cname);
|
|
+
|
|
+ // if there's no lang group, just use the lang group as it was
|
|
+ // passed to us
|
|
+ //
|
|
+ // we're casting away the const here for the strings - should be
|
|
+ // safe.
|
|
+ if (!langGroup)
|
|
+ return pango_language_from_string(cname.get());
|
|
+ else if (langGroup->Lang)
|
|
+ return pango_language_from_string((char *) langGroup->Lang);
|
|
+
|
|
+ return pango_language_from_string("en");
|
|
+}
|
|
+
|
|
+/* static */
|
|
+void
|
|
+FreeGlobals(void)
|
|
+{
|
|
+}
|
|
+
|
|
+/* static */
|
|
+PangoStyle
|
|
+CalculateStyle(PRUint8 aStyle)
|
|
+{
|
|
+ switch(aStyle) {
|
|
+ case NS_FONT_STYLE_ITALIC:
|
|
+ return PANGO_STYLE_OBLIQUE;
|
|
+ break;
|
|
+ case NS_FONT_STYLE_OBLIQUE:
|
|
+ return PANGO_STYLE_OBLIQUE;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return PANGO_STYLE_NORMAL;
|
|
+}
|
|
+
|
|
+/* static */
|
|
+PangoWeight
|
|
+CalculateWeight (PRUint16 aWeight)
|
|
+{
|
|
+ /*
|
|
+ * weights come in two parts crammed into one
|
|
+ * integer -- the "base" weight is weight / 100,
|
|
+ * the rest of the value is the "offset" from that
|
|
+ * weight -- the number of steps to move to adjust
|
|
+ * the weight in the list of supported font weights,
|
|
+ * this value can be negative or positive.
|
|
+ */
|
|
+ PRInt32 baseWeight = (aWeight + 50) / 100;
|
|
+ PRInt32 offset = aWeight - baseWeight * 100;
|
|
+
|
|
+ /* clip weights to range 0 to 9 */
|
|
+ if (baseWeight < 0)
|
|
+ baseWeight = 0;
|
|
+ if (baseWeight > 9)
|
|
+ baseWeight = 9;
|
|
+
|
|
+ /* Map from weight value to fcWeights index */
|
|
+ static int fcWeightLookup[10] = {
|
|
+ 0, 0, 0, 0, 1, 1, 2, 3, 3, 4,
|
|
+ };
|
|
+
|
|
+ PRInt32 fcWeight = fcWeightLookup[baseWeight];
|
|
+
|
|
+ /*
|
|
+ * adjust by the offset value, make sure we stay inside the
|
|
+ * fcWeights table
|
|
+ */
|
|
+ fcWeight += offset;
|
|
+
|
|
+ if (fcWeight < 0)
|
|
+ fcWeight = 0;
|
|
+ if (fcWeight > 4)
|
|
+ fcWeight = 4;
|
|
+
|
|
+ /* Map to final PANGO_WEIGHT value */
|
|
+ static int fcWeights[5] = {
|
|
+ 349,
|
|
+ 499,
|
|
+ 649,
|
|
+ 749,
|
|
+ 999
|
|
+ };
|
|
+
|
|
+ return (PangoWeight)fcWeights[fcWeight];
|
|
+}
|
|
+
|
|
+/* static */
|
|
+nsresult
|
|
+EnumFontsPango(nsIAtom* aLangGroup, const char* aGeneric,
|
|
+ PRUint32* aCount, PRUnichar*** aResult)
|
|
+{
|
|
+ FcPattern *pat = NULL;
|
|
+ FcObjectSet *os = NULL;
|
|
+ FcFontSet *fs = NULL;
|
|
+ nsresult rv = NS_ERROR_FAILURE;
|
|
+
|
|
+ PRUnichar **array = NULL;
|
|
+ PRUint32 narray = 0;
|
|
+ PRInt32 serif = 0, sansSerif = 0, monospace = 0, nGenerics;
|
|
+
|
|
+ *aCount = 0;
|
|
+ *aResult = nsnull;
|
|
+
|
|
+ pat = FcPatternCreate();
|
|
+ if (!pat)
|
|
+ goto end;
|
|
+
|
|
+ os = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, NULL);
|
|
+ if (!os)
|
|
+ goto end;
|
|
+
|
|
+ // take the pattern and add the lang group to it
|
|
+ if (aLangGroup)
|
|
+ NS_AddLangGroup(pat, aLangGroup);
|
|
+
|
|
+ // get the font list
|
|
+ fs = FcFontList(0, pat, os);
|
|
+
|
|
+ if (!fs)
|
|
+ goto end;
|
|
+
|
|
+ if (!fs->nfont) {
|
|
+ rv = NS_OK;
|
|
+ goto end;
|
|
+ }
|
|
+
|
|
+ // Fontconfig supports 3 generic fonts, "serif", "sans-serif", and
|
|
+ // "monospace", slightly different from CSS's 5.
|
|
+ if (!aGeneric)
|
|
+ serif = sansSerif = monospace = 1;
|
|
+ else if (!strcmp(aGeneric, "serif"))
|
|
+ serif = 1;
|
|
+ else if (!strcmp(aGeneric, "sans-serif"))
|
|
+ sansSerif = 1;
|
|
+ else if (!strcmp(aGeneric, "monospace"))
|
|
+ monospace = 1;
|
|
+ else if (!strcmp(aGeneric, "cursive") || !strcmp(aGeneric, "fantasy"))
|
|
+ serif = sansSerif = 1;
|
|
+ else
|
|
+ NS_NOTREACHED("unexpected generic family");
|
|
+ nGenerics = serif + sansSerif + monospace;
|
|
+
|
|
+ array = NS_STATIC_CAST(PRUnichar **,
|
|
+ nsMemory::Alloc((fs->nfont + nGenerics) * sizeof(PRUnichar *)));
|
|
+ if (!array)
|
|
+ goto end;
|
|
+
|
|
+ if (serif) {
|
|
+ PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("serif"));
|
|
+ if (!name)
|
|
+ goto end;
|
|
+ array[narray++] = name;
|
|
+ }
|
|
+
|
|
+ if (sansSerif) {
|
|
+ PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("sans-serif"));
|
|
+ if (!name)
|
|
+ goto end;
|
|
+ array[narray++] = name;
|
|
+ }
|
|
+
|
|
+ if (monospace) {
|
|
+ PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("monospace"));
|
|
+ if (!name)
|
|
+ goto end;
|
|
+ array[narray++] = name;
|
|
+ }
|
|
+
|
|
+ for (int i=0; i < fs->nfont; ++i) {
|
|
+ char *family;
|
|
+
|
|
+ // if there's no family, just move to the next iteration
|
|
+ if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
|
|
+ (FcChar8 **) &family) != FcResultMatch) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ // fontconfig always returns family names in UTF-8
|
|
+ PRUnichar* name = UTF8ToNewUnicode(nsDependentCString(family));
|
|
+
|
|
+ if (!name)
|
|
+ goto end;
|
|
+
|
|
+ array[narray++] = name;
|
|
+ }
|
|
+
|
|
+ NS_QuickSort(array + nGenerics, narray - nGenerics, sizeof (PRUnichar*),
|
|
+ CompareFontNames, nsnull);
|
|
+
|
|
+ *aCount = narray;
|
|
+ if (narray)
|
|
+ *aResult = array;
|
|
+ else
|
|
+ nsMemory::Free(array);
|
|
+
|
|
+ rv = NS_OK;
|
|
+
|
|
+ end:
|
|
+ if (NS_FAILED(rv) && array) {
|
|
+ while (narray)
|
|
+ nsMemory::Free (array[--narray]);
|
|
+ nsMemory::Free (array);
|
|
+ }
|
|
+ if (pat)
|
|
+ FcPatternDestroy(pat);
|
|
+ if (os)
|
|
+ FcObjectSetDestroy(os);
|
|
+ if (fs)
|
|
+ FcFontSetDestroy(fs);
|
|
+
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+/* static */
|
|
+int
|
|
+CompareFontNames (const void* aArg1, const void* aArg2, void* aClosure)
|
|
+{
|
|
+ const PRUnichar* str1 = *((const PRUnichar**) aArg1);
|
|
+ const PRUnichar* str2 = *((const PRUnichar**) aArg2);
|
|
+
|
|
+ return nsCRT::strcmp(str1, str2);
|
|
+}
|
|
+
|
|
+
|
|
+// nsFontEnumeratorPango class
|
|
+
|
|
+nsFontEnumeratorPango::nsFontEnumeratorPango()
|
|
+{
|
|
+}
|
|
+
|
|
+NS_IMPL_ISUPPORTS1(nsFontEnumeratorPango, nsIFontEnumerator)
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFontEnumeratorPango::EnumerateAllFonts(PRUint32 *aCount,
|
|
+ PRUnichar ***aResult)
|
|
+{
|
|
+ NS_ENSURE_ARG_POINTER(aResult);
|
|
+ *aResult = nsnull;
|
|
+ NS_ENSURE_ARG_POINTER(aCount);
|
|
+ *aCount = 0;
|
|
+
|
|
+ return EnumFontsPango(nsnull, nsnull, aCount, aResult);
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFontEnumeratorPango::EnumerateFonts(const char *aLangGroup,
|
|
+ const char *aGeneric,
|
|
+ PRUint32 *aCount,
|
|
+ PRUnichar ***aResult)
|
|
+{
|
|
+ NS_ENSURE_ARG_POINTER(aResult);
|
|
+ *aResult = nsnull;
|
|
+ NS_ENSURE_ARG_POINTER(aCount);
|
|
+ *aCount = 0;
|
|
+
|
|
+ // aLangGroup=null or "" means any (i.e., don't care)
|
|
+ // aGeneric=null or "" means any (i.e, don't care)
|
|
+ nsCOMPtr<nsIAtom> langGroup;
|
|
+ if (aLangGroup && *aLangGroup)
|
|
+ langGroup = do_GetAtom(aLangGroup);
|
|
+ const char* generic = nsnull;
|
|
+ if (aGeneric && *aGeneric)
|
|
+ generic = aGeneric;
|
|
+
|
|
+ return EnumFontsPango(langGroup, generic, aCount, aResult);
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFontEnumeratorPango::HaveFontFor(const char *aLangGroup,
|
|
+ PRBool *aResult)
|
|
+{
|
|
+ NS_ENSURE_ARG_POINTER(aResult);
|
|
+ *aResult = PR_FALSE;
|
|
+ NS_ENSURE_ARG_POINTER(aLangGroup);
|
|
+
|
|
+ *aResult = PR_TRUE; // always return true for now.
|
|
+ // Finish me - ftang
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFontEnumeratorPango::GetDefaultFont(const char *aLangGroup,
|
|
+ const char *aGeneric,
|
|
+ PRUnichar **aResult)
|
|
+{
|
|
+ NS_ENSURE_ARG_POINTER(aResult);
|
|
+ *aResult = nsnull;
|
|
+
|
|
+ // Have a look at nsFontEnumeratorXft::GetDefaultFont for some
|
|
+ // possible code for this function.
|
|
+
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsFontEnumeratorPango::UpdateFontList(PRBool *_retval)
|
|
+{
|
|
+ *_retval = PR_FALSE; // always return false for now
|
|
+ return NS_OK;
|
|
+}
|
|
Index: gfx/src/ps/nsFontMetricsPSPango.h
|
|
===================================================================
|
|
RCS file: gfx/src/ps/nsFontMetricsPSPango.h
|
|
diff -N gfx/src/ps/nsFontMetricsPSPango.h
|
|
--- /dev/null 1 Jan 1970 00:00:00 -0000
|
|
+++ gfx/src/ps/nsFontMetricsPSPango.h 23 Oct 2006 17:37:13 -0000
|
|
@@ -0,0 +1,305 @@
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
+ */
|
|
+/* ***** BEGIN LICENSE BLOCK *****
|
|
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
+ *
|
|
+ * The contents of this file are subject to the Mozilla Public License Version
|
|
+ * 1.1 (the "License"); you may not use this file except in compliance with
|
|
+ * the License. You may obtain a copy of the License at
|
|
+ * http://www.mozilla.org/MPL/
|
|
+ *
|
|
+ * Software distributed under the License is distributed on an "AS IS" basis,
|
|
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
+ * for the specific language governing rights and limitations under the
|
|
+ * License.
|
|
+ *
|
|
+ * The Original Code is mozilla.org code.
|
|
+ *
|
|
+ * The Initial Developer of the Original Code is
|
|
+ * Christopher Blizzard <blizzard@mozilla.org>.
|
|
+ * Portions created by the Initial Developer are Copyright (C) 2002
|
|
+ * the Initial Developer. All Rights Reserved.
|
|
+ *
|
|
+ * Contributor(s):
|
|
+ *
|
|
+ * Alternatively, the contents of this file may be used under the terms of
|
|
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
+ * in which case the provisions of the GPL or the LGPL are applicable instead
|
|
+ * of those above. If you wish to allow use of your version of this file only
|
|
+ * under the terms of either the GPL or the LGPL, and not to allow others to
|
|
+ * use your version of this file under the terms of the MPL, indicate your
|
|
+ * decision by deleting the provisions above and replace them with the notice
|
|
+ * and other provisions required by the GPL or the LGPL. If you do not delete
|
|
+ * the provisions above, a recipient may use your version of this file under
|
|
+ * the terms of any one of the MPL, the GPL or the LGPL.
|
|
+ *
|
|
+ * ***** END LICENSE BLOCK ***** */
|
|
+
|
|
+#ifndef nsFontMetricsPSPango_h__
|
|
+#define nsFontMetricsPSPango_h__
|
|
+
|
|
+#include "nsIFontMetrics.h"
|
|
+#include "nsIFontEnumerator.h"
|
|
+#include "nsCRT.h"
|
|
+#include "nsIAtom.h"
|
|
+#include "nsString.h"
|
|
+#include "nsVoidArray.h"
|
|
+#include "nsFontMetricsPS.h"
|
|
+
|
|
+#include <pango/pango.h>
|
|
+
|
|
+class nsRenderingContextPS;
|
|
+class nsIDrawingSurface;
|
|
+
|
|
+class nsFontMetricsPSPango : public nsFontMetricsPS
|
|
+{
|
|
+public:
|
|
+ nsFontMetricsPSPango();
|
|
+ virtual ~nsFontMetricsPSPango();
|
|
+
|
|
+ NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
|
|
+
|
|
+ // nsISupports
|
|
+ NS_DECL_ISUPPORTS
|
|
+
|
|
+ // nsIFontMetrics
|
|
+ NS_IMETHOD Init (const nsFont& aFont, nsIAtom* aLangGroup,
|
|
+ nsIDeviceContext *aContext);
|
|
+ NS_IMETHOD Destroy();
|
|
+ NS_IMETHOD GetLangGroup (nsIAtom** aLangGroup);
|
|
+ NS_IMETHOD GetFontHandle (nsFontHandle &aHandle);
|
|
+
|
|
+ NS_IMETHOD GetXHeight (nscoord& aResult)
|
|
+ { aResult = mXHeight; return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetSuperscriptOffset (nscoord& aResult)
|
|
+ { aResult = mSuperscriptOffset;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetSubscriptOffset (nscoord& aResult)
|
|
+ { aResult = mSubscriptOffset;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetStrikeout (nscoord& aOffset, nscoord& aSize)
|
|
+ { aOffset = mStrikeoutOffset;
|
|
+ aSize = mStrikeoutSize;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetUnderline (nscoord& aOffset, nscoord& aSize)
|
|
+ { aOffset = mUnderlineOffset;
|
|
+ aSize = mUnderlineSize;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetHeight (nscoord &aHeight)
|
|
+ { aHeight = mMaxHeight;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetNormalLineHeight (nscoord &aHeight)
|
|
+ { aHeight = mEmHeight + mLeading;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetLeading (nscoord &aLeading)
|
|
+ { aLeading = mLeading;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetEmHeight (nscoord &aHeight)
|
|
+ { aHeight = mEmHeight;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetEmAscent (nscoord &aAscent)
|
|
+ { aAscent = mEmAscent;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetEmDescent (nscoord &aDescent)
|
|
+ { aDescent = mEmDescent;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetMaxHeight (nscoord &aHeight)
|
|
+ { aHeight = mMaxHeight;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetMaxAscent (nscoord &aAscent)
|
|
+ { aAscent = mMaxAscent;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetMaxDescent (nscoord &aDescent)
|
|
+ { aDescent = mMaxDescent;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetMaxAdvance (nscoord &aAdvance)
|
|
+ { aAdvance = mMaxAdvance;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetSpaceWidth (nscoord &aSpaceCharWidth)
|
|
+ { aSpaceCharWidth = mSpaceWidth;
|
|
+ return NS_OK; };
|
|
+
|
|
+ NS_IMETHOD GetAveCharWidth (nscoord &aAveCharWidth)
|
|
+ { aAveCharWidth = mAveCharWidth;
|
|
+ return NS_OK; };
|
|
+
|
|
+ // nsIFontMetricsPS (calls from the font rendering layer)
|
|
+ NS_IMETHOD GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength);
|
|
+ NS_IMETHOD GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength);
|
|
+
|
|
+ NS_IMETHOD GetWidth(const char* aString, PRUint32 aLength,
|
|
+ nscoord& aWidth);
|
|
+ NS_IMETHOD GetWidth(const PRUnichar* aString, PRUint32 aLength,
|
|
+ nscoord& aWidth);
|
|
+
|
|
+ NS_IMETHOD GetTextDimensions(const char* aString,
|
|
+ PRUint32 aLength,
|
|
+ nsTextDimensions& aDimensions);
|
|
+ NS_IMETHOD GetTextDimensions(const PRUnichar* aString,
|
|
+ PRUint32 aLength,
|
|
+ nsTextDimensions& aDimensions,
|
|
+ PRInt32* aFontID);
|
|
+ NS_IMETHOD GetTextDimensions(const char* aString,
|
|
+ PRInt32 aLength,
|
|
+ PRInt32 aAvailWidth,
|
|
+ PRInt32* aBreaks,
|
|
+ PRInt32 aNumBreaks,
|
|
+ nsTextDimensions& aDimensions,
|
|
+ PRInt32& aNumCharsFit,
|
|
+ nsTextDimensions& aLastWordDimensions,
|
|
+ PRInt32* aFontID);
|
|
+ NS_IMETHOD GetTextDimensions(const PRUnichar* aString,
|
|
+ PRInt32 aLength,
|
|
+ PRInt32 aAvailWidth,
|
|
+ PRInt32* aBreaks,
|
|
+ PRInt32 aNumBreaks,
|
|
+ nsTextDimensions& aDimensions,
|
|
+ PRInt32& aNumCharsFit,
|
|
+ nsTextDimensions& aLastWordDimensions,
|
|
+ PRInt32* aFontID);
|
|
+
|
|
+ NS_IMETHOD DrawString(const char *aString, PRUint32 aLength,
|
|
+ nscoord aX, nscoord aY,
|
|
+ const nscoord* aSpacing,
|
|
+ nsRenderingContextPS *aContext);
|
|
+ NS_IMETHOD DrawString(const PRUnichar* aString, PRUint32 aLength,
|
|
+ nscoord aX, nscoord aY,
|
|
+ PRInt32 aFontID,
|
|
+ const nscoord* aSpacing,
|
|
+ nsRenderingContextPS *aContext);
|
|
+
|
|
+#ifdef MOZ_MATHML
|
|
+ NS_IMETHOD GetBoundingMetrics(const char *aString, PRUint32 aLength,
|
|
+ nsBoundingMetrics &aBoundingMetrics);
|
|
+ NS_IMETHOD GetBoundingMetrics(const PRUnichar *aString,
|
|
+ PRUint32 aLength,
|
|
+ nsBoundingMetrics &aBoundingMetrics,
|
|
+ PRInt32 *aFontID);
|
|
+#endif /* MOZ_MATHML */
|
|
+
|
|
+ NS_IMETHOD SetRightToLeftText(PRBool aIsRTL);
|
|
+
|
|
+ NS_IMETHOD GetClusterInfo(const PRUnichar *aText,
|
|
+ PRUint32 aLength,
|
|
+ PRUint8 *aClusterStarts);
|
|
+
|
|
+ virtual PRInt32 GetPosition(const PRUnichar *aText,
|
|
+ PRUint32 aLength,
|
|
+ nsPoint aPt);
|
|
+
|
|
+ NS_IMETHOD GetRangeWidth(const PRUnichar *aText,
|
|
+ PRUint32 aLength,
|
|
+ PRUint32 aStart,
|
|
+ PRUint32 aEnd,
|
|
+ PRUint32 &aWidth);
|
|
+
|
|
+ NS_IMETHOD GetRangeWidth(const char *aText,
|
|
+ PRUint32 aLength,
|
|
+ PRUint32 aStart,
|
|
+ PRUint32 aEnd,
|
|
+ PRUint32 &aWidth);
|
|
+
|
|
+ // get hints for the font
|
|
+ virtual PRUint32 GetHints (void);
|
|
+
|
|
+ // drawing surface methods
|
|
+ static nsresult FamilyExists (nsIDeviceContext *aDevice,
|
|
+ const nsString &aName);
|
|
+
|
|
+ inline nsIDeviceContext *GetDeviceContext() { return mDeviceContext; }
|
|
+
|
|
+private:
|
|
+
|
|
+ // generic font metrics class bits
|
|
+ nsCStringArray mFontList;
|
|
+ nsAutoVoidArray mFontIsGeneric;
|
|
+
|
|
+ nsIDeviceContext *mDeviceContext;
|
|
+ nsCOMPtr<nsIAtom> mLangGroup;
|
|
+ nsCString *mGenericFont;
|
|
+ float mPointSize;
|
|
+
|
|
+ nsCAutoString mDefaultFont;
|
|
+
|
|
+ // Pango-related items
|
|
+ PangoFontDescription *mPangoFontDesc;
|
|
+ PangoContext *mPangoContext;
|
|
+ PangoContext *mLTRPangoContext;
|
|
+ PangoContext *mRTLPangoContext;
|
|
+ PangoAttrList *mPangoAttrList;
|
|
+ PRBool mIsRTL;
|
|
+
|
|
+ // Cached font metrics
|
|
+ nscoord mXHeight;
|
|
+ nscoord mSuperscriptOffset;
|
|
+ nscoord mSubscriptOffset;
|
|
+ nscoord mStrikeoutOffset;
|
|
+ nscoord mStrikeoutSize;
|
|
+ nscoord mUnderlineOffset;
|
|
+ nscoord mUnderlineSize;
|
|
+ nscoord mMaxHeight;
|
|
+ nscoord mLeading;
|
|
+ nscoord mEmHeight;
|
|
+ nscoord mEmAscent;
|
|
+ nscoord mEmDescent;
|
|
+ nscoord mMaxAscent;
|
|
+ nscoord mMaxDescent;
|
|
+ nscoord mMaxAdvance;
|
|
+ nscoord mSpaceWidth;
|
|
+ nscoord mPangoSpaceWidth;
|
|
+ nscoord mAveCharWidth;
|
|
+
|
|
+ // Private methods
|
|
+ nsresult RealizeFont(void);
|
|
+ nsresult CacheFontMetrics(void);
|
|
+
|
|
+ static PRBool EnumFontCallback(const nsString &aFamily,
|
|
+ PRBool aIsGeneric, void *aData);
|
|
+
|
|
+ void DrawStringSlowly(const gchar *aText,
|
|
+ const PRUnichar *aOrigString,
|
|
+ PRUint32 aLength,
|
|
+ gint aX, gint aY,
|
|
+ PangoLayoutLine *aLine,
|
|
+ const nscoord *aSpacing,
|
|
+ nsRenderingContextPS *aContext);
|
|
+
|
|
+ nsresult GetTextDimensionsInternal(const gchar* aString,
|
|
+ PRInt32 aLength,
|
|
+ PRInt32 aAvailWidth,
|
|
+ PRInt32* aBreaks,
|
|
+ PRInt32 aNumBreaks,
|
|
+ nsTextDimensions& aDimensions,
|
|
+ PRInt32& aNumCharsFit,
|
|
+ nsTextDimensions& aLastWordDimensions);
|
|
+
|
|
+ void FixupSpaceWidths (PangoLayout *aLayout, const char *aString);
|
|
+};
|
|
+
|
|
+class nsFontEnumeratorPango : public nsIFontEnumerator
|
|
+{
|
|
+public:
|
|
+ nsFontEnumeratorPango();
|
|
+ NS_DECL_ISUPPORTS
|
|
+ NS_DECL_NSIFONTENUMERATOR
|
|
+};
|
|
+
|
|
+#endif
|
|
+
|
|
Index: gfx/src/ps/nsPostScriptObj.cpp
|
|
===================================================================
|
|
RCS file: /cvsroot/mozilla/gfx/src/ps/nsPostScriptObj.cpp,v
|
|
retrieving revision 1.124
|
|
diff -u -p -d -r1.124 nsPostScriptObj.cpp
|
|
--- gfx/src/ps/nsPostScriptObj.cpp 26 Jul 2005 15:54:18 -0000 1.124
|
|
+++ gfx/src/ps/nsPostScriptObj.cpp 23 Oct 2006 17:37:29 -0000
|
|
@@ -2061,31 +2061,74 @@ nsPostScriptObj::show(const PRUnichar* t
|
|
|
|
#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
|
|
void
|
|
-nsPostScriptObj::show(const PRUnichar* aTxt, int aLen,
|
|
- const nsAFlatString& aCharList, PRUint16 aSubFontIdx)
|
|
+/*nsPostScriptObj::show(const PRUnichar* aTxt, int aLen,
|
|
+ const nsAFlatString& aCharList, PRUint16 aSubFontIdx) */
|
|
+nsPostScriptObj::show(const nsValueArray *aGlyphs, nsPSFontGenerator *aSubset,
|
|
+ PRUint16 aSubFontIdx)
|
|
{
|
|
- int i;
|
|
+ PRUint32 i;
|
|
fputc('<', mScriptFP);
|
|
|
|
- const PRUint16 subFontSize = nsPSFontGenerator::kSubFontSize;
|
|
+ for (i = 0; i < aGlyphs->Count(); i++) {
|
|
+ PRUint32 glyph = aGlyphs->ValueAt(i);
|
|
+ fprintf(mScriptFP, "%02x", aSubset->InSubsetIndexOf(glyph));
|
|
+ }
|
|
|
|
- // the character repertoire of a subfont (255 characters max)
|
|
- const nsAString& repertoire =
|
|
- Substring(aCharList, aSubFontIdx * subFontSize,
|
|
- PR_MIN(subFontSize,
|
|
- aCharList.Length() - aSubFontIdx * subFontSize));
|
|
+ fputs("> show\n", mScriptFP);
|
|
+}
|
|
+#endif
|
|
|
|
- for (i = 0; i < aLen; i++) {
|
|
- // XXX This is a little inefficient, but printing is not perf. critical.
|
|
- NS_ASSERTION(repertoire.FindChar(aTxt[i]) != kNotFound,
|
|
- "character is not covered by this subfont");
|
|
-
|
|
- // Type 1 encoding vector has 256 slots, but the 0-th slot is
|
|
- // reserved for /.notdef so that we use the 1st through 255th slots
|
|
- // for actual characters (hence '+ 1')
|
|
- fprintf(mScriptFP, "%02x", repertoire.FindChar(aTxt[i]) + 1);
|
|
+#ifdef MOZ_ENABLE_PANGO
|
|
+void
|
|
+nsPostScriptObj::show(const PangoGlyphString *glyphs, float zoom,
|
|
+ nsPSFontGenerator *aSubset, PRUint16 aSubFontIdx)
|
|
+{
|
|
+ PRUint32 i;
|
|
+ int horiz = 1;
|
|
+
|
|
+ if (glyphs->glyphs[0].geometry.x_offset || glyphs->glyphs[0].geometry.y_offset)
|
|
+ rmoveto (NSToCoordRound (zoom * glyphs->glyphs[0].geometry.x_offset / PANGO_SCALE),
|
|
+ NSToCoordRound (zoom * glyphs->glyphs[0].geometry.y_offset / PANGO_SCALE));
|
|
+
|
|
+ fputc('<', mScriptFP);
|
|
+
|
|
+ for (i = 0; i < glyphs->num_glyphs; i++) {
|
|
+ PRUint32 glyph = glyphs->glyphs[i].glyph;
|
|
+ fprintf(mScriptFP, "%02x", aSubset->InSubsetIndexOf(glyph));
|
|
+ if (glyphs->glyphs[i].geometry.y_offset)
|
|
+ horiz = 0;
|
|
+ }
|
|
+
|
|
+ if (horiz) {
|
|
+ fputs(">\n[", mScriptFP);
|
|
+ for (i = 1; i < glyphs->num_glyphs; i++) {
|
|
+ fprintf(mScriptFP, "%d ",
|
|
+ NSToCoordRound (zoom * (+ glyphs->glyphs[i ].geometry.x_offset
|
|
+ + glyphs->glyphs[i-1].geometry.width
|
|
+ - glyphs->glyphs[i-1].geometry.x_offset) / PANGO_SCALE));
|
|
+ }
|
|
+ fprintf(mScriptFP, "%d",
|
|
+ NSToCoordRound (zoom * (+ glyphs->glyphs[i-1].geometry.width
|
|
+ - glyphs->glyphs[i-1].geometry.x_offset
|
|
+ - glyphs->glyphs[ 0].geometry.x_offset) / PANGO_SCALE));
|
|
+ fputs("] xshow\n", mScriptFP);
|
|
+ } else {
|
|
+ fputs(">\n[", mScriptFP);
|
|
+ for (i = 1; i < glyphs->num_glyphs; i++) {
|
|
+ fprintf(mScriptFP, "%d %d ",
|
|
+ NSToCoordRound (zoom * (+ glyphs->glyphs[i ].geometry.x_offset
|
|
+ + glyphs->glyphs[i-1].geometry.width
|
|
+ - glyphs->glyphs[i-1].geometry.x_offset) / PANGO_SCALE),
|
|
+ NSToCoordRound (zoom * (+ glyphs->glyphs[i ].geometry.y_offset
|
|
+ - glyphs->glyphs[i-1].geometry.y_offset) / PANGO_SCALE));
|
|
+ }
|
|
+ fprintf(mScriptFP, "%d %d",
|
|
+ NSToCoordRound (zoom * (+ glyphs->glyphs[i-1].geometry.width
|
|
+ - glyphs->glyphs[i-1].geometry.x_offset
|
|
+ - glyphs->glyphs[ 0].geometry.x_offset) / PANGO_SCALE),
|
|
+ NSToCoordRound (zoom * (- glyphs->glyphs[i-1].geometry.y_offset) / PANGO_SCALE));
|
|
+ fputs("] xyshow\n", mScriptFP);
|
|
}
|
|
- fputs("> show\n", mScriptFP);
|
|
}
|
|
#endif
|
|
|
|
@@ -2101,6 +2144,16 @@ nsPostScriptObj::moveto(nscoord x, nscoo
|
|
|
|
/** ---------------------------------------------------
|
|
* See documentation in nsPostScriptObj.h
|
|
+ * @update 10/20/06 behdad
|
|
+ */
|
|
+void
|
|
+nsPostScriptObj::rmoveto(nscoord x, nscoord y)
|
|
+{
|
|
+ fprintf(mScriptFP, "%d %d rmoveto\n", x, y);
|
|
+}
|
|
+
|
|
+/** ---------------------------------------------------
|
|
+ * See documentation in nsPostScriptObj.h
|
|
* @update 2/1/99 dwc
|
|
*/
|
|
void
|
|
Index: gfx/src/ps/nsPostScriptObj.h
|
|
===================================================================
|
|
RCS file: /cvsroot/mozilla/gfx/src/ps/nsPostScriptObj.h,v
|
|
retrieving revision 1.47
|
|
diff -u -p -d -r1.47 nsPostScriptObj.h
|
|
--- gfx/src/ps/nsPostScriptObj.h 8 May 2005 15:01:20 -0000 1.47
|
|
+++ gfx/src/ps/nsPostScriptObj.h 23 Oct 2006 17:37:30 -0000
|
|
@@ -57,9 +57,15 @@
|
|
#include "nsIPersistentProperties2.h"
|
|
#include "nsTempfilePS.h"
|
|
#include "nsEPSObjectPS.h"
|
|
+#ifdef MOZ_ENABLE_PANGO
|
|
+#include <pango/pango.h>
|
|
+#endif
|
|
+
|
|
|
|
+class nsPSFontGenerator;
|
|
class nsIImage;
|
|
class nsIAtom;
|
|
+class nsValueArray;
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
@@ -217,6 +223,14 @@ public:
|
|
*/
|
|
void moveto(nscoord aX, nscoord aY);
|
|
/** ---------------------------------------------------
|
|
+ * Move relative to the current point
|
|
+ * @update 10/20/2006 behdad
|
|
+ * @param aX X coordinate
|
|
+ * aY Y coordinate
|
|
+ * @return VOID
|
|
+ */
|
|
+ void rmoveto(nscoord aX, nscoord aY);
|
|
+ /** ---------------------------------------------------
|
|
* Add a line to the current path, from the current point
|
|
* to the specified point.
|
|
* @update 9/30/2003
|
|
@@ -346,12 +360,24 @@ public:
|
|
*/
|
|
void show(const PRUnichar* aText, int aLen, const char *aAlign, int aType);
|
|
/** ---------------------------------------------------
|
|
- * This version takes a PRUnichar string, a font subset string
|
|
- * for freetype printing and a subfont index
|
|
+ * This version of show takes an array of glyphs, subfont and subfont index
|
|
+ * to render and is used for freetype and xft printing.
|
|
* @update 2/15/2005 jshin@mailaps.org
|
|
+ * @update 6/7/2005 blizzard@mozilla.org
|
|
*/
|
|
- void show(const PRUnichar* aText, int aLen, const nsAFlatString& aCharList,
|
|
+ void show(const nsValueArray *aGlyphs, nsPSFontGenerator *aSubset,
|
|
PRUint16 aSubFontIdx);
|
|
+ /*void show(const PRUnichar* aText, int aLen, const nsAFlatString& aCharList,
|
|
+ PRUint16 aSubFontIdx); */
|
|
+#ifdef MOZ_ENABLE_PANGO
|
|
+ /** ---------------------------------------------------
|
|
+ * This version of show takes a pango glyph string, subfont and subfont index
|
|
+ * to render and is used for pango printing.
|
|
+ * @update 10/20/2006 behdad@behdad.org
|
|
+ */
|
|
+ void show(const PangoGlyphString *glyphs, float zoom,
|
|
+ nsPSFontGenerator *aSubset, PRUint16 aSubFontIdx);
|
|
+#endif
|
|
/** ---------------------------------------------------
|
|
* set the clipping path to the current path using the winding rule
|
|
* @update 2/1/99 dwc
|
|
Index: gfx/src/ps/nsRenderingContextPS.cpp
|
|
===================================================================
|
|
RCS file: /cvsroot/mozilla/gfx/src/ps/nsRenderingContextPS.cpp,v
|
|
retrieving revision 1.83
|
|
diff -u -p -d -r1.83 nsRenderingContextPS.cpp
|
|
--- gfx/src/ps/nsRenderingContextPS.cpp 4 Mar 2005 07:39:27 -0000 1.83
|
|
+++ gfx/src/ps/nsRenderingContextPS.cpp 23 Oct 2006 17:37:31 -0000
|
|
@@ -251,6 +251,8 @@ nsRenderingContextPS :: GetDrawingSurfac
|
|
NS_IMETHODIMP
|
|
nsRenderingContextPS :: GetHints(PRUint32& aResult)
|
|
{
|
|
+ nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
|
|
+ aResult = metrics->GetHints ();
|
|
return NS_OK;
|
|
}
|
|
|
|
@@ -1006,8 +1008,11 @@ nsRenderingContextPS::GetTextDimensions(
|
|
nsTextDimensions& aLastWordDimensions,
|
|
PRInt32* aFontID)
|
|
{
|
|
- NS_NOTYETIMPLEMENTED("nsRenderingContextPS::GetTextDimensions");
|
|
- return NS_ERROR_NOT_IMPLEMENTED;
|
|
+ NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER);
|
|
+ nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
|
|
+ NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
|
|
+ return metrics->GetTextDimensions (aString, aLength, aAvailWidth, aBreaks, aNumBreaks,
|
|
+ aDimensions, aNumCharsFit, aLastWordDimensions, aFontID);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
@@ -1021,43 +1026,31 @@ nsRenderingContextPS::GetTextDimensions(
|
|
nsTextDimensions& aLastWordDimensions,
|
|
PRInt32* aFontID)
|
|
{
|
|
- NS_NOTYETIMPLEMENTED("nsRenderingContextPS::GetTextDimensions");
|
|
- return NS_ERROR_NOT_IMPLEMENTED;
|
|
+ NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER);
|
|
+ nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
|
|
+ NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
|
|
+ return metrics->GetTextDimensions (aString, aLength, aAvailWidth, aBreaks, aNumBreaks,
|
|
+ aDimensions, aNumCharsFit, aLastWordDimensions, aFontID);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsRenderingContextPS :: GetTextDimensions(const char* aString, PRUint32 aLength,
|
|
nsTextDimensions& aDimensions)
|
|
{
|
|
- nsresult rv = NS_ERROR_FAILURE;
|
|
-
|
|
- if (mFontMetrics) {
|
|
- nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
|
|
- metrics->GetStringWidth(aString, aDimensions.width, aLength);
|
|
- metrics->GetMaxAscent(aDimensions.ascent);
|
|
- metrics->GetMaxDescent(aDimensions.descent);
|
|
- rv = NS_OK;
|
|
- }
|
|
-
|
|
- return rv;
|
|
+ NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER);
|
|
+ nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
|
|
+ NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
|
|
+ return metrics->GetTextDimensions (aString, aLength, aDimensions);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsRenderingContextPS :: GetTextDimensions(const PRUnichar* aString, PRUint32 aLength,
|
|
nsTextDimensions& aDimensions, PRInt32* aFontID)
|
|
{
|
|
- nsresult rv = NS_ERROR_FAILURE;
|
|
-
|
|
- if (mFontMetrics) {
|
|
- nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
|
|
- metrics->GetStringWidth(aString, aDimensions.width, aLength);
|
|
- //XXX temporary - bug 96609
|
|
- metrics->GetMaxAscent(aDimensions.ascent);
|
|
- metrics->GetMaxDescent(aDimensions.descent);
|
|
- rv = NS_OK;
|
|
- }
|
|
-
|
|
- return rv;
|
|
+ NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER);
|
|
+ nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
|
|
+ NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
|
|
+ return metrics->GetTextDimensions (aString, aLength, aDimensions, aFontID);
|
|
}
|
|
|
|
/** ---------------------------------------------------
|
|
@@ -1073,47 +1066,7 @@ nsRenderingContextPS :: DrawString(const
|
|
|
|
nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
|
|
NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
|
|
-
|
|
- // When FT2 printing is enabled, we don't need to set langgroup
|
|
-#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
|
|
- if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, mContext.get())->mFTPEnable) {
|
|
-#endif
|
|
- nsCOMPtr<nsIAtom> langGroup;
|
|
- mFontMetrics->GetLangGroup(getter_AddRefs(langGroup));
|
|
- mPSObj->setlanggroup(langGroup);
|
|
-#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
|
|
- }
|
|
-#endif
|
|
-
|
|
- if (aLength == 0)
|
|
- return NS_OK;
|
|
- nsFontPS* fontPS = nsFontPS::FindFont(aString[0], metrics->Font(), metrics);
|
|
- NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
|
|
- fontPS->SetupFont(this);
|
|
-
|
|
- PRUint32 i, start = 0;
|
|
- for (i=0; i<aLength; i++) {
|
|
- nsFontPS* fontThisChar;
|
|
- fontThisChar = nsFontPS::FindFont(aString[i], metrics->Font(), metrics);
|
|
- NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE);
|
|
- if (fontThisChar != fontPS) {
|
|
- // draw text up to this point
|
|
- aX += DrawString(aString+start, i-start, aX, aY, fontPS,
|
|
- aSpacing?aSpacing+start:nsnull);
|
|
- start = i;
|
|
-
|
|
- // setup for following text
|
|
- fontPS = fontThisChar;
|
|
- fontPS->SetupFont(this);
|
|
- }
|
|
- }
|
|
-
|
|
- // draw the last part
|
|
- if (aLength-start)
|
|
- DrawString(aString+start, aLength-start, aX, aY, fontPS,
|
|
- aSpacing?aSpacing+start:nsnull);
|
|
-
|
|
- return NS_OK;
|
|
+ return metrics->DrawString (aString, aLength, aX, aY, aSpacing, this);
|
|
}
|
|
|
|
/** ---------------------------------------------------
|
|
@@ -1129,110 +1082,7 @@ nsRenderingContextPS :: DrawString(const
|
|
|
|
nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
|
|
NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
|
|
-
|
|
-#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
|
|
- // When FT2 printing is enabled, we don't need to set langgroup
|
|
- if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, mContext.get())->mFTPEnable) {
|
|
-#endif
|
|
- nsCOMPtr<nsIAtom> langGroup = nsnull;
|
|
- mFontMetrics->GetLangGroup(getter_AddRefs(langGroup));
|
|
- mPSObj->setlanggroup(langGroup);
|
|
-#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
|
|
- }
|
|
-#endif
|
|
-
|
|
- /* build up conversion table */
|
|
- mPSObj->preshow(aString, aLength);
|
|
-
|
|
- if (aLength == 0)
|
|
- return NS_OK;
|
|
- nsFontPS* fontPS = nsFontPS::FindFont(aString[0], metrics->Font(), metrics);
|
|
- NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
|
|
- fontPS->SetupFont(this);
|
|
-
|
|
- PRUint32 i, start = 0;
|
|
- for (i=0; i<aLength; i++) {
|
|
- nsFontPS* fontThisChar;
|
|
- fontThisChar = nsFontPS::FindFont(aString[i], metrics->Font(), metrics);
|
|
- NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE);
|
|
- if (fontThisChar != fontPS) {
|
|
- // draw text up to this point
|
|
- aX += DrawString(aString+start, i-start, aX, aY, fontPS,
|
|
- aSpacing?aSpacing+start:nsnull);
|
|
- start = i;
|
|
-
|
|
- // setup for following text
|
|
- fontPS = fontThisChar;
|
|
- fontPS->SetupFont(this);
|
|
- }
|
|
- }
|
|
-
|
|
- // draw the last part
|
|
- if (aLength-start)
|
|
- DrawString(aString+start, aLength-start, aX, aY, fontPS,
|
|
- aSpacing?aSpacing+start:nsnull);
|
|
-
|
|
- return NS_OK;
|
|
-}
|
|
-
|
|
-PRInt32
|
|
-nsRenderingContextPS::DrawString(const char *aString, PRUint32 aLength,
|
|
- nscoord &aX, nscoord &aY, nsFontPS* aFontPS,
|
|
- const nscoord* aSpacing)
|
|
-{
|
|
- nscoord width = 0;
|
|
- PRInt32 x = aX;
|
|
- PRInt32 y = aY;
|
|
-
|
|
- PRInt32 dxMem[500];
|
|
- PRInt32* dx0 = 0;
|
|
- if (aSpacing) {
|
|
- dx0 = dxMem;
|
|
- if (aLength > 500) {
|
|
- dx0 = new PRInt32[aLength];
|
|
- NS_ENSURE_TRUE(dx0, NS_ERROR_OUT_OF_MEMORY);
|
|
- }
|
|
- mTranMatrix->ScaleXCoords(aSpacing, aLength, dx0);
|
|
- }
|
|
-
|
|
- mTranMatrix->TransformCoord(&x, &y);
|
|
- width = aFontPS->DrawString(this, x, y, aString, aLength);
|
|
-
|
|
- if ((aSpacing) && (dx0 != dxMem)) {
|
|
- delete [] dx0;
|
|
- }
|
|
-
|
|
- return width;
|
|
-}
|
|
-
|
|
-
|
|
-PRInt32
|
|
-nsRenderingContextPS::DrawString(const PRUnichar *aString, PRUint32 aLength,
|
|
- nscoord aX, nscoord aY, nsFontPS* aFontPS,
|
|
- const nscoord* aSpacing)
|
|
-{
|
|
- nscoord width = 0;
|
|
- PRInt32 x = aX;
|
|
- PRInt32 y = aY;
|
|
-
|
|
- if (aSpacing) {
|
|
- // Slow, but accurate rendering
|
|
- const PRUnichar* end = aString + aLength;
|
|
- while (aString < end){
|
|
- x = aX;
|
|
- y = aY;
|
|
- mTranMatrix->TransformCoord(&x, &y);
|
|
- aFontPS->DrawString(this, x, y, aString, 1);
|
|
- aX += *aSpacing++;
|
|
- aString++;
|
|
- }
|
|
- width = aX;
|
|
- } else {
|
|
- mTranMatrix->TransformCoord(&x, &y);
|
|
- width = aFontPS->DrawString(this, x, y, aString, aLength);
|
|
- }
|
|
-
|
|
- return width;
|
|
+ return metrics->DrawString (aString, aLength, aX, aY, aFontID, aSpacing, this);
|
|
}
|
|
|
|
/** ---------------------------------------------------
|
|
@@ -1346,8 +1196,10 @@ nsRenderingContextPS::GetBoundingMetrics
|
|
PRUint32 aLength,
|
|
nsBoundingMetrics& aBoundingMetrics)
|
|
{
|
|
- // Fill me up
|
|
- return NS_ERROR_NOT_IMPLEMENTED;
|
|
+ NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER);
|
|
+ nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
|
|
+ NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
|
|
+ return metrics->GetBoundingMetrics (aString, aLength, aBoundingMetrics);
|
|
}
|
|
|
|
/**
|
|
@@ -1359,8 +1211,10 @@ nsRenderingContextPS::GetBoundingMetrics
|
|
nsBoundingMetrics& aBoundingMetrics,
|
|
PRInt32* aFontID)
|
|
{
|
|
- // Fill me up
|
|
- return NS_ERROR_NOT_IMPLEMENTED;
|
|
+ NS_ENSURE_TRUE(mFontMetrics, NS_ERROR_NULL_POINTER);
|
|
+ nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
|
|
+ NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
|
|
+ return metrics->GetBoundingMetrics (aString, aLength, aBoundingMetrics, aFontID);
|
|
}
|
|
#endif /* MOZ_MATHML */
|
|
|
|
Index: gfx/src/ps/nsRenderingContextPS.h
|
|
===================================================================
|
|
RCS file: /cvsroot/mozilla/gfx/src/ps/nsRenderingContextPS.h,v
|
|
retrieving revision 1.49
|
|
diff -u -p -d -r1.49 nsRenderingContextPS.h
|
|
--- gfx/src/ps/nsRenderingContextPS.h 20 Sep 2004 06:46:16 -0000 1.49
|
|
+++ gfx/src/ps/nsRenderingContextPS.h 23 Oct 2006 17:37:35 -0000
|
|
@@ -154,6 +154,10 @@ public:
|
|
NS_IMETHOD GetWidth(const PRUnichar* aString, PRUint32 aLength,
|
|
nscoord& aWidth, PRInt32 *aFontID);
|
|
|
|
+ nsTransform2D *GetTranMatrix() {
|
|
+ return mTranMatrix;
|
|
+ }
|
|
+
|
|
NS_IMETHOD DrawString(const char *aString, PRUint32 aLength,
|
|
nscoord aX, nscoord aY,
|
|
const nscoord* aSpacing);
|
|
@@ -164,13 +168,6 @@ public:
|
|
NS_IMETHOD DrawString(const nsString& aString, nscoord aX, nscoord aY,
|
|
PRInt32 aFontID,
|
|
const nscoord* aSpacing);
|
|
-protected:
|
|
- PRInt32 DrawString(const PRUnichar *aString, PRUint32 aLength,
|
|
- nscoord aX, nscoord aY, nsFontPS* aFontPS,
|
|
- const nscoord* aSpacing);
|
|
- PRInt32 DrawString(const char *aString, PRUint32 aLength,
|
|
- nscoord &aX, nscoord &aY, nsFontPS* aFontPS,
|
|
- const nscoord* aSpacing);
|
|
public:
|
|
|
|
NS_IMETHOD GetTextDimensions(const char* aString, PRUint32 aLength,
|
|
Index: gfx/src/ps/nsType1.cpp
|
|
===================================================================
|
|
RCS file: /cvsroot/mozilla/gfx/src/ps/nsType1.cpp,v
|
|
retrieving revision 1.5.8.1
|
|
diff -u -p -d -r1.5.8.1 nsType1.cpp
|
|
--- gfx/src/ps/nsType1.cpp 19 Oct 2005 08:16:22 -0000 1.5.8.1
|
|
+++ gfx/src/ps/nsType1.cpp 23 Oct 2006 17:37:39 -0000
|
|
@@ -73,8 +73,13 @@
|
|
#include "nsIFreeType2.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#endif
|
|
+#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
+#include FT_TYPE1_TABLES_H
|
|
+#endif
|
|
#include "nsPrintfCString.h"
|
|
#include "nsAutoBuffer.h"
|
|
+#include "nsValueArray.h"
|
|
+#include "nsVoidArray.h"
|
|
|
|
#define HEXASCII_LINE_LEN 64
|
|
|
|
@@ -113,7 +118,7 @@ static void encryptAndHexOut(FILE *aFile
|
|
const char *aBuf, PRInt32 aLen = -1);
|
|
static void charStringOut(FILE* aFile, PRUint32* aPos, PRUint16* aKey,
|
|
const char *aStr, PRUint32 aLen,
|
|
- PRUnichar aId);
|
|
+ const char *aGlyphName);
|
|
static void flattenName(nsCString& aString);
|
|
|
|
/* thunk a short name for this function */
|
|
@@ -202,19 +207,30 @@ Type1EncryptString(unsigned char *aInBuf
|
|
aOutBuf[i] = Type1Encrypt(aInBuf[i], &key);
|
|
}
|
|
|
|
+static FT_UShort
|
|
+get_upm (FT_Face face)
|
|
+{
|
|
+ FT_UShort upm = face->units_per_EM;
|
|
+
|
|
+ if (!upm)
|
|
+ upm = 1000; // bitmap font or something
|
|
+
|
|
+ return upm;
|
|
+}
|
|
+
|
|
static PRBool
|
|
sideWidthAndBearing(const FT_Vector *aEndPt, FT2PT1_info *aFti)
|
|
{
|
|
int aw = 0;
|
|
int ah = 0;
|
|
- FT_UShort upm = aFti->face->units_per_EM;
|
|
+ FT_UShort upm = get_upm (aFti->face);
|
|
FT_GlyphSlot slot;
|
|
FT_Glyph glyph;
|
|
FT_BBox bbox;
|
|
|
|
slot = aFti->face->glyph;
|
|
|
|
-#ifdef MOZ_ENABLE_XFT
|
|
+#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
FT_Error error = FT_Get_Glyph(slot, &glyph);
|
|
if (error) {
|
|
NS_ERROR("sideWidthAndBearing failed to get glyph");
|
|
@@ -256,7 +272,7 @@ static int
|
|
moveto(nsFT_CONST FT_Vector *aEndPt, void *aClosure)
|
|
{
|
|
FT2PT1_info *fti = (FT2PT1_info *)aClosure;
|
|
- FT_UShort upm = fti->face->units_per_EM;
|
|
+ FT_UShort upm = get_upm (fti->face);
|
|
PRBool rslt;
|
|
|
|
if (fti->elm_cnt == 0) {
|
|
@@ -293,7 +309,7 @@ static int
|
|
lineto(nsFT_CONST FT_Vector *aEndPt, void *aClosure)
|
|
{
|
|
FT2PT1_info *fti = (FT2PT1_info *)aClosure;
|
|
- FT_UShort upm = fti->face->units_per_EM;
|
|
+ FT_UShort upm = get_upm (fti->face);
|
|
|
|
if (toCS(upm, aEndPt->x) == fti->cur_x) {
|
|
fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->y) - (int)fti->cur_y);
|
|
@@ -320,7 +336,7 @@ conicto(nsFT_CONST FT_Vector *aControlPt
|
|
void *aClosure)
|
|
{
|
|
FT2PT1_info *ftinfo = (FT2PT1_info *)aClosure;
|
|
- FT_UShort upm = ftinfo->face->units_per_EM;
|
|
+ FT_UShort upm = get_upm (ftinfo->face);
|
|
double ctl_x, ctl_y;
|
|
double cur_x, cur_y, x3, y3;
|
|
FT_Vector aControlPt1, aControlPt2;
|
|
@@ -353,7 +369,7 @@ cubicto(nsFT_CONST FT_Vector *aControlPt
|
|
nsFT_CONST FT_Vector *aEndPt, void *aClosure)
|
|
{
|
|
FT2PT1_info *ftinfo = (FT2PT1_info *)aClosure;
|
|
- FT_UShort upm = ftinfo->face->units_per_EM;
|
|
+ FT_UShort upm = get_upm (ftinfo->face);
|
|
double cur_x, cur_y, x1, y1, x2, y2, x3, y3;
|
|
|
|
cur_x = ftinfo->cur_x;
|
|
@@ -408,8 +424,55 @@ static FT_Outline_Funcs ft_outline_funcs
|
|
0
|
|
};
|
|
|
|
+
|
|
+static int
|
|
+trace_bitmap_glyph (FT_GlyphSlot slot, FT2PT1_info *fti)
|
|
+{
|
|
+ unsigned char *row, *byte_ptr, byte;
|
|
+ int rows, cols;
|
|
+ int x, y, bit_mask;
|
|
+ int upm, x_off, y_off, x_mult, y_mult;
|
|
+
|
|
+ upm = get_upm (slot->face);
|
|
+ x_off = slot->bitmap_left;
|
|
+ y_off = slot->bitmap_top;
|
|
+ x_mult = upm / slot->face->size->metrics.x_ppem;
|
|
+ y_mult = upm / slot->face->size->metrics.y_ppem;
|
|
+
|
|
+ switch (slot->bitmap.pixel_mode) {
|
|
+ case FT_PIXEL_MODE_MONO:
|
|
+
|
|
+ for (y = 0, row = slot->bitmap.buffer, rows = slot->bitmap.rows; rows; row += slot->bitmap.pitch, rows--, y++) {
|
|
+ for (x = 0, byte_ptr = row, cols = (slot->bitmap.width + 7) / 8; cols; byte_ptr++, cols--) {
|
|
+ byte = *byte_ptr;
|
|
+ for (bit_mask = 128; bit_mask && x < slot->bitmap.width; bit_mask >>= 1, x++) {
|
|
+ if (byte & bit_mask) {
|
|
+ FT_Vector p;
|
|
+ p.x = x_mult * (x_off + x);
|
|
+ p.y = y_mult * (y_off - y);
|
|
+ moveto(&p, (void *) fti);
|
|
+ p.x += x_mult;
|
|
+ lineto(&p, (void *) fti);
|
|
+ p.y += y_mult;
|
|
+ lineto(&p, (void *) fti);
|
|
+ p.x -= x_mult;
|
|
+ lineto(&p, (void *) fti);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
FT_Error
|
|
-#ifdef MOZ_ENABLE_XFT
|
|
+#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
FT2GlyphToType1CharString(FT_Face aFace, PRUint32 aGlyphID,
|
|
int aWmode, int aLenIV, unsigned char *aBuf)
|
|
#else
|
|
@@ -423,7 +486,7 @@ FT2GlyphToType1CharString(nsIFreeType2 *
|
|
unsigned char *start = aBuf;
|
|
FT2PT1_info fti;
|
|
|
|
-#ifdef MOZ_ENABLE_XFT
|
|
+#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
FT_Error error = FT_Load_Glyph(aFace, aGlyphID, flags);
|
|
if (error) {
|
|
NS_ERROR("failed to load aGlyphID");
|
|
@@ -438,11 +501,6 @@ FT2GlyphToType1CharString(nsIFreeType2 *
|
|
#endif
|
|
slot = aFace->glyph;
|
|
|
|
- if (slot->format != ft_glyph_format_outline) {
|
|
- NS_ERROR("aGlyphID is not an outline glyph");
|
|
- return 1;
|
|
- }
|
|
-
|
|
#ifdef MOZ_ENABLE_FREETYPE2
|
|
fti.ft2 = aFt2;
|
|
#endif
|
|
@@ -456,18 +514,27 @@ FT2GlyphToType1CharString(nsIFreeType2 *
|
|
for (j=0; j< aLenIV; j++) {
|
|
fti.len += ecsi(&fti.buf, 0);
|
|
}
|
|
-#ifdef MOZ_ENABLE_XFT
|
|
- if (FT_Outline_Decompose(&slot->outline, &ft_outline_funcs, &fti)) {
|
|
- NS_ERROR("error decomposing aGlyphID");
|
|
- return 1;
|
|
- }
|
|
+
|
|
+ if (slot->format == ft_glyph_format_outline) {
|
|
+#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
+ if (FT_Outline_Decompose(&slot->outline, &ft_outline_funcs, &fti)) {
|
|
+ NS_ERROR("error decomposing aGlyphID");
|
|
+ return 1;
|
|
+ }
|
|
#else
|
|
- rv = aFt2->OutlineDecompose(&slot->outline, &ft_outline_funcs, &fti);
|
|
- if (NS_FAILED(rv)) {
|
|
- NS_ERROR("error decomposing aGlyphID");
|
|
- return 1;
|
|
- }
|
|
+ rv = aFt2->OutlineDecompose(&slot->outline, &ft_outline_funcs, &fti);
|
|
+ if (NS_FAILED(rv)) {
|
|
+ NS_ERROR("error decomposing aGlyphID");
|
|
+ }
|
|
#endif
|
|
+ } else if (slot->format == ft_glyph_format_bitmap) {
|
|
+ /* ok, it's a bitmap glyph. trace it! */
|
|
+ if (trace_bitmap_glyph (slot, &fti)) {
|
|
+ NS_ERROR("error tracing bitmap glyph");
|
|
+ }
|
|
+ } else {
|
|
+ NS_ERROR("aGlyphID has unhandled format");
|
|
+ }
|
|
|
|
if (fti.elm_cnt) {
|
|
fti.len += csc(&fti.buf, T1_CLOSEPATH);
|
|
@@ -491,28 +558,52 @@ FT2GlyphToType1CharString(nsIFreeType2 *
|
|
}
|
|
|
|
static PRBool
|
|
-#ifdef MOZ_ENABLE_XFT
|
|
+#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
outputType1SubFont(FT_Face aFace,
|
|
#else
|
|
outputType1SubFont(nsIFreeType2 *aFt2, FT_Face aFace,
|
|
#endif
|
|
- const nsAString &aCharIDs, const char *aFontName,
|
|
- int aWmode, int aLenIV, FILE *aFile);
|
|
+ nsValueArray *aGlyphs,
|
|
+ PRUint32 aOffset, PRUint32 aLen,
|
|
+ const char *aFontName,
|
|
+ int aWmode, int aLenIV, FILE *aFile);
|
|
|
|
nsresult
|
|
FT2ToType1FontName(FT_Face aFace, int aWmode, nsCString& aFontName)
|
|
{
|
|
+ // only hash the first 10 000 bytes of the font
|
|
+ int size = aFace->stream->size;
|
|
+ size = size > 10000 ? 10000 : size;
|
|
+
|
|
+ unsigned char *data;
|
|
+ if (aFace->stream->read) {
|
|
+ data = (unsigned char *) malloc (size);
|
|
+ aFace->stream->read (aFace->stream, 0, data, size);
|
|
+ } else {
|
|
+ data = aFace->stream->base;
|
|
+ }
|
|
+
|
|
+ unsigned int data_hash = 0;
|
|
+ int i;
|
|
+ for (i = 0; i < size; i++)
|
|
+ data_hash = (data_hash << 5) - data_hash + data[size];
|
|
+
|
|
+ if (aFace->stream->read)
|
|
+ free (data);
|
|
+
|
|
aFontName = aFace->family_name;
|
|
aFontName.AppendLiteral(".");
|
|
aFontName += aFace->style_name;
|
|
- aFontName += nsPrintfCString(".%ld.%d", aFace->face_index, aWmode ? 1 : 0);
|
|
+ aFontName += nsPrintfCString(".%ld.%d.%lx.%x", aFace->face_index, aWmode ? 1 : 0,
|
|
+ (long) aFace->stream->size, data_hash);
|
|
flattenName(aFontName);
|
|
+
|
|
return NS_OK;
|
|
}
|
|
|
|
// output a subsetted truetype font converted to multiple type 1 fonts
|
|
PRBool
|
|
-FT2SubsetToType1FontSet(FT_Face aFace, const nsString& aSubset,
|
|
+FT2SubsetToType1FontSet(FT_Face aFace, nsValueArray *aGlyphSubset,
|
|
int aWmode, FILE *aFile)
|
|
{
|
|
#ifdef MOZ_ENABLE_FREETYPE2
|
|
@@ -527,32 +618,35 @@ FT2SubsetToType1FontSet(FT_Face aFace, c
|
|
nsCAutoString fontNameBase;
|
|
FT2ToType1FontName(aFace, aWmode, fontNameBase);
|
|
PRUint32 i = 0;
|
|
- for (; i <= aSubset.Length() / 255 ; i++) {
|
|
+ for (; i <= aGlyphSubset->Count() / 255 ; i++) {
|
|
nsCAutoString fontName(fontNameBase);
|
|
fontName.AppendLiteral(".Set");
|
|
fontName.AppendInt(i);
|
|
-#ifdef MOZ_ENABLE_XFT
|
|
+#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
outputType1SubFont(aFace,
|
|
#else
|
|
outputType1SubFont(ft2, aFace,
|
|
#endif
|
|
- Substring(aSubset, i * 255, PR_MIN(255, aSubset.Length() - i * 255)),
|
|
- fontName.get(), aWmode, 4, aFile);
|
|
+ aGlyphSubset,
|
|
+ (i * 255), PR_MIN(255, aGlyphSubset->Count() - i * 255),
|
|
+ fontName.get(), aWmode, 4, aFile);
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
// output a type 1 font (with 255 characters or fewer)
|
|
static PRBool
|
|
-#ifdef MOZ_ENABLE_XFT
|
|
+#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
outputType1SubFont(FT_Face aFace,
|
|
#else
|
|
outputType1SubFont(nsIFreeType2 *aFt2, FT_Face aFace,
|
|
#endif
|
|
- const nsAString& aCharIDs, const char *aFontName,
|
|
- int aWmode, int aLenIV, FILE *aFile)
|
|
+ nsValueArray *aGlyphs,
|
|
+ PRUint32 aOffset, PRUint32 aLen,
|
|
+ const char *aFontName,
|
|
+ int aWmode, int aLenIV, FILE *aFile)
|
|
{
|
|
- FT_UShort upm = aFace->units_per_EM;
|
|
+ FT_UShort upm = get_upm (aFace);
|
|
|
|
fprintf(aFile, "%%%%BeginResource: font %s\n"
|
|
"%%!PS-AdobeFont-1.0-3.0 %s 1.0\n"
|
|
@@ -573,9 +667,13 @@ outputType1SubFont(nsIFreeType2 *aFt2, F
|
|
toCS(upm, aFace->bbox.xMax),
|
|
toCS(upm, aFace->bbox.yMax));
|
|
|
|
- nsString charIDstr(aCharIDs);
|
|
- PRUint32 len = aCharIDs.Length();
|
|
-
|
|
+ nsValueArray glyphs(PR_UINT16_MAX);
|
|
+ nsCStringArray glyphnames(PR_UINT16_MAX);
|
|
+ glyphs = *aGlyphs;
|
|
+
|
|
+ PRUint32 len = aLen;
|
|
+ PRUint32 i;
|
|
+
|
|
if (len < 10) {
|
|
// Add a small set of characters to the subset of the user
|
|
// defined font to produce to make sure the font ends up
|
|
@@ -584,25 +682,47 @@ outputType1SubFont(nsIFreeType2 *aFt2, F
|
|
// XXX : need to check if this is true of type 1 fonts as well.
|
|
// I suspect it's only the case of CID-keyed fonts (type 9) we used to
|
|
// generate.
|
|
- charIDstr.AppendLiteral("1234567890");
|
|
+ for (i = 1; i <= 10; i++) {
|
|
+ glyphs.AppendValue(i);
|
|
+ }
|
|
len += 10;
|
|
}
|
|
|
|
- const PRUnichar *charIDs = charIDstr.get();
|
|
-
|
|
- PRUint32 i;
|
|
+ FT_Int has_glyph_name;
|
|
+#if defined (MOZ_ENABLE_XFT) || defined (MOZ_ENABLE_PANGO)
|
|
+ has_glyph_name = FT_Has_PS_Glyph_Names(aFace);
|
|
+#else
|
|
+ has_glyph_name = aFt2->hasPSGlyphNames(aFace);
|
|
+#endif
|
|
|
|
// construct an Encoding vector : the 0th element
|
|
// is /.notdef
|
|
- fputs("/Encoding [\n/.notdef\n", aFile);
|
|
- for (i = 0; i < len; ++i) {
|
|
- fprintf(aFile, "/uni%04X", charIDs[i]);
|
|
- if (i % 8 == 7) fputc('\n', aFile);
|
|
+ fputs("/Encoding [\n/.notdef", aFile);
|
|
+ for (i = aOffset; i < aOffset + aLen; ++i) {
|
|
+ nsCString name;
|
|
+ char buffer[256];
|
|
+
|
|
+ if (glyphs.ValueAt(i) == 0) {
|
|
+ name = "/.notdef";
|
|
+ } else if (!has_glyph_name ||
|
|
+#if defined (MOZ_ENABLE_XFT) || defined (MOZ_ENABLE_PANGO)
|
|
+ FT_Get_Glyph_Name(aFace, glyphs.ValueAt(i), buffer, 255) != FT_Err_Ok
|
|
+#else
|
|
+ NS_FAILED(aFt2->getGlyphName(aFace, glyphs.ValueAt(i), buffer, 255))
|
|
+#endif
|
|
+ ) {
|
|
+ name = nsPrintfCString(256, "/idx%04X", glyphs.ValueAt(i));
|
|
+ } else {
|
|
+ name = nsPrintfCString(256, "/%s", buffer);
|
|
+ }
|
|
+ glyphnames.AppendCString(name);
|
|
+ fprintf(aFile, name.get());
|
|
+ if ((i-aOffset) % 8 == 6) fputc('\n', aFile);
|
|
}
|
|
|
|
- for (i = len; i < 255; ++i) {
|
|
+ for (i = PR_MAX (0, 255 - int(aLen)); i; --i) {
|
|
fputs("/.notdef", aFile);
|
|
- if (i % 8 == 7) fputc('\n', aFile);
|
|
+ if (i % 8 == 1) fputc('\n', aFile);
|
|
}
|
|
fputs("] def\n", aFile);
|
|
|
|
@@ -630,23 +750,21 @@ outputType1SubFont(nsIFreeType2 *aFt2, F
|
|
// get the maximum charstring length without actually filling up the buffer
|
|
PRInt32 charStringLen;
|
|
PRInt32 maxCharStringLen =
|
|
-#ifdef MOZ_ENABLE_XFT
|
|
+#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
FT2GlyphToType1CharString(aFace, 0, aWmode, aLenIV, nsnull);
|
|
#else
|
|
FT2GlyphToType1CharString(aFt2, aFace, 0, aWmode, aLenIV, nsnull);
|
|
#endif
|
|
|
|
- PRUint32 glyphID;
|
|
-
|
|
- for (i = 0; i < len; i++) {
|
|
-#ifdef MOZ_ENABLE_XFT
|
|
- glyphID = FT_Get_Char_Index(aFace, charIDs[i]);
|
|
+ for (i = aOffset; i < aOffset + aLen; i++) {
|
|
+#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
charStringLen =
|
|
- FT2GlyphToType1CharString(aFace, glyphID, aWmode, aLenIV, nsnull);
|
|
+ FT2GlyphToType1CharString(aFace, glyphs.ValueAt(i), aWmode, aLenIV,
|
|
+ nsnull);
|
|
#else
|
|
- aFt2->GetCharIndex(aFace, charIDs[i], &glyphID);
|
|
charStringLen =
|
|
- FT2GlyphToType1CharString(aFt2, aFace, glyphID, aWmode, aLenIV, nsnull);
|
|
+ FT2GlyphToType1CharString(aFt2, aFace, glyphs.ValueAt(i), aWmode, aLenIV,
|
|
+ nsnull);
|
|
#endif
|
|
|
|
if (charStringLen > maxCharStringLen)
|
|
@@ -666,7 +784,7 @@ outputType1SubFont(nsIFreeType2 *aFt2, F
|
|
len + 1).get());
|
|
|
|
// output the notdef glyph
|
|
-#ifdef MOZ_ENABLE_XFT
|
|
+#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
charStringLen = FT2GlyphToType1CharString(aFace, 0, aWmode, aLenIV,
|
|
charString.get());
|
|
#else
|
|
@@ -676,22 +794,20 @@ outputType1SubFont(nsIFreeType2 *aFt2, F
|
|
|
|
// enclose charString with "/.notdef RD ..... ND"
|
|
charStringOut(aFile, &pos, &key, NS_REINTERPRET_CAST(const char*, charString.get()),
|
|
- charStringLen, 0);
|
|
+ charStringLen, "/.notdef");
|
|
|
|
|
|
// output the charstrings for each glyph in this sub font
|
|
- for (i = 0; i < len; i++) {
|
|
-#ifdef MOZ_ENABLE_XFT
|
|
- glyphID = FT_Get_Char_Index(aFace, charIDs[i]);
|
|
- charStringLen = FT2GlyphToType1CharString(aFace, glyphID, aWmode,
|
|
+ for (i = aOffset; i < aOffset + aLen; i++) {
|
|
+#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
|
|
+ charStringLen = FT2GlyphToType1CharString(aFace, glyphs.ValueAt(i), aWmode,
|
|
aLenIV, charString.get());
|
|
#else
|
|
- aFt2->GetCharIndex(aFace, charIDs[i], &glyphID);
|
|
- charStringLen = FT2GlyphToType1CharString(aFt2, aFace, glyphID, aWmode,
|
|
- aLenIV, charString.get());
|
|
+ charStringLen = FT2GlyphToType1CharString(aFt2, aFace, glyphs.ValueAt(i),
|
|
+ aWmode, aLenIV, charString.get());
|
|
#endif
|
|
charStringOut(aFile, &pos, &key, NS_REINTERPRET_CAST(const char*, charString.get()),
|
|
- charStringLen, charIDs[i]);
|
|
+ charStringLen, glyphnames.CStringAt(i - aOffset)->get());
|
|
}
|
|
|
|
// wrap up the encrypted part of the font definition
|
|
@@ -753,15 +869,12 @@ void encryptAndHexOut(FILE *aFile, PRUin
|
|
|
|
/* static */
|
|
void charStringOut(FILE* aFile, PRUint32* aPos, PRUint16* aKey,
|
|
- const char *aStr, PRUint32 aLen, PRUnichar aId)
|
|
+ const char *aStr, PRUint32 aLen, const char *aGlyphName)
|
|
{
|
|
// use a local buffer instead of nsPrintfCString to avoid alloc.
|
|
char buf[30];
|
|
int oLen;
|
|
- if (aId == 0)
|
|
- oLen = PR_snprintf(buf, 30, "/.notdef %d RD ", aLen);
|
|
- else
|
|
- oLen = PR_snprintf(buf, 30, "/uni%04X %d RD ", aId, aLen);
|
|
+ oLen = PR_snprintf(buf, 30, "%s %d RD ", aGlyphName, aLen);
|
|
|
|
if (oLen >= 30) {
|
|
NS_WARNING("buffer size exceeded. charstring will be truncated");
|
|
Index: gfx/src/ps/nsType1.h
|
|
===================================================================
|
|
RCS file: /cvsroot/mozilla/gfx/src/ps/nsType1.h,v
|
|
retrieving revision 1.5
|
|
diff -u -p -d -r1.5 nsType1.h
|
|
--- gfx/src/ps/nsType1.h 4 Mar 2005 07:39:27 -0000 1.5
|
|
+++ gfx/src/ps/nsType1.h 23 Oct 2006 17:37:39 -0000
|
|
@@ -122,8 +122,9 @@ FT_Error FT2GlyphToType1CharString(nsIFr
|
|
|
|
class nsString;
|
|
class nsCString;
|
|
+class nsValueArray;
|
|
|
|
-PRBool FT2SubsetToType1FontSet(FT_Face aFace, const nsString& aSubset,
|
|
+PRBool FT2SubsetToType1FontSet(FT_Face aFace, nsValueArray *aGlyphSubset,
|
|
int aWmode, FILE *aFile);
|
|
nsresult FT2ToType1FontName(FT_Face aFace, int aWmode,
|
|
nsCString& aFontName);
|
|
Index: config/system-headers
|
|
===================================================================
|
|
--- config/system-headers 2006-10-26 12:21:39.000000000 -0400
|
|
+++ config/system-headers 2006-10-26 12:23:29.000000000 -0400
|
|
@@ -199,6 +199,7 @@
|
|
freetype/ftoutln.h
|
|
freetype/ttnameid.h
|
|
freetype/tttables.h
|
|
+freetype/t1tables.h
|
|
fribidi/fribidi.h
|
|
FSp_fopen.h
|
|
fstream.h
|
|
@@ -501,6 +503,7 @@
|
|
pango/pangofc-fontmap.h
|
|
pango/pango-fontmap.h
|
|
pango/pango.h
|
|
+pango/pangoft2.h
|
|
pango/pangoxft.h
|
|
pango/pangox.h
|
|
pango-types.h
|
|
|