thunderbird/firefox-2.0-pango-ligatures.patch
2007-07-31 13:06:27 +00:00

1933 lines
65 KiB
Diff

--- mozilla.back/gfx/src/gtk/nsFontMetricsPango.cpp.orig 2007-06-28 14:44:31.000000000 +0200
+++ mozilla.back/gfx/src/gtk/nsFontMetricsPango.cpp 2007-06-28 15:48:04.000000000 +0200
@@ -21,6 +21,8 @@
* 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
@@ -36,6 +38,10 @@
*
* ***** END LICENSE BLOCK ***** */
+#define PANGO_ENABLE_BACKEND
+
+#include "nsFontMetricsPango.h"
+
#include <strings.h>
#include "nsFont.h"
#include "nsIDeviceContext.h"
@@ -43,27 +49,37 @@
#include "nsIPref.h"
#include "nsServiceManagerUtils.h"
-#define PANGO_ENABLE_BACKEND
-#define PANGO_ENABLE_ENGINE
-
-#include "nsFontMetricsPango.h"
-#include "nsRenderingContextGTK.h"
-#include "nsDeviceContextGTK.h"
#include "nsFontConfigUtils.h"
#include "nsUnicharUtils.h"
#include "nsQuickSort.h"
#include "nsFontConfigUtils.h"
+#include "mozilla-decoder.h"
+
+#define FORCE_PR_LOG
+#include "prlog.h"
+
#include <fontconfig/fontconfig.h>
+#include <freetype/tttables.h>
+
+#include <pango/pango.h>
+#include <pango/pangofc-font.h>
+
+#ifdef PSPANGO
+#include <pango/pangoft2.h>
+#include "nsRenderingContextPS.h"
+#include "nsDeviceContextPS.h"
+#include "nsType1.h"
+#else
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
-#include <freetype/tttables.h>
+#include "nsRenderingContextGTK.h"
+#include "nsDeviceContextGTK.h"
+#endif
+
-#include "mozilla-decoder.h"
-#define FORCE_PR_LOG
-#include "prlog.h"
// Globals
@@ -108,6 +124,49 @@ static nsresult EnumFontsPango (nsI
PRUint32* aCount, PRUnichar*** aResult);
static int CompareFontNames (const void* aArg1, const void* aArg2,
void* aClosure);
+static void utf16_to_utf8 (const PRUnichar* aString, PRUint32 aLength,
+ char *&text, gint &text_len);
+
+#ifdef PSPANGO
+static void
+default_substitute (FcPattern *pattern,
+ gpointer data)
+{
+ FcPatternDel (pattern, FC_HINTING);
+ FcPatternAddBool (pattern, FC_HINTING, 0);
+}
+#endif
+
+static PangoFontMap *
+get_fontmap (void)
+{
+ static PangoFontMap *fontmap = NULL;
+
+ if (!fontmap) {
+#ifdef PSPANGO
+ 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);
+#else
+ PangoContext* context = gdk_pango_context_get ();
+ fontmap = pango_context_get_font_map (context);
+ g_object_unref (context);
+#endif
+ }
+
+ return fontmap;
+}
+
+static PangoContext *
+get_context (void)
+{
+#ifdef PSPANGO
+ return pango_ft2_font_map_create_context ((PangoFT2FontMap *) get_fontmap ());
+#else
+ return gdk_pango_context_get();
+#endif
+}
+
nsFontMetricsPango::nsFontMetricsPango()
{
@@ -169,14 +228,20 @@ nsFontMetricsPango::Init(const nsFont& a
mLangGroup = aLangGroup;
// Hang on to the device context
+#ifdef PSPANGO
+ mDeviceContext = (nsDeviceContextPS *)aContext;
+#else
mDeviceContext = aContext;
+#endif
mPointSize = NSTwipsToFloatPoints(mFont.size);
+#ifndef PSPANGO
// Make sure to clamp the pixel size to something reasonable so we
// don't make the X server blow up.
nscoord screenPixels = gdk_screen_height();
mPointSize = PR_MIN(screenPixels * FONT_MAX_FONT_SCALE, mPointSize);
+#endif
// enumerate over the font names passed in
mFont.EnumerateFamilies(nsFontMetricsPango::EnumFontCallback, this);
@@ -329,7 +394,7 @@ nsFontMetricsPango::CacheFontMetrics(voi
// mPangoSpaceWidth
PangoLayout *layout = pango_layout_new(mPangoContext);
- pango_layout_set_text(layout, " ", 1);
+ pango_layout_set_text(layout, " ", -1);
int pswidth, psheight;
pango_layout_get_size(layout, &pswidth, &psheight);
mPangoSpaceWidth = pswidth;
@@ -337,14 +402,14 @@ nsFontMetricsPango::CacheFontMetrics(voi
// mSpaceWidth (width of a space)
nscoord tmpWidth;
- GetWidth(" ", 1, tmpWidth, NULL);
+ GetWidth(" ", 1, tmpWidth CONTEXT_ARG_NULL);
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, NULL);
+ GetWidth("x", 1, tmpWidth CONTEXT_ARG_NULL);
mAveCharWidth = tmpWidth;
// mXHeight (height of an 'x' character)
@@ -460,130 +525,96 @@ nsFontMetricsPango::GetFontHandle(nsFont
// nsIFontMetricsPango impl
-nsresult
-nsFontMetricsPango::GetWidth(const char* aString, PRUint32 aLength,
- nscoord& aWidth,
- nsRenderingContextGTK *aContext)
+#ifdef PSPANGO
+NS_IMETHODIMP
+nsFontMetricsPSPango::GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength)
{
- PangoLayout *layout = pango_layout_new(mPangoContext);
-
- pango_layout_set_text(layout, aString, aLength);
+ return GetWidth (String, (PRUint32) aLength, aWidth CONTEXT_ARG_NULL);
+}
- if (mPangoSpaceWidth)
- FixupSpaceWidths(layout, aString);
+NS_IMETHODIMP
+nsFontMetricsPSPango::GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength)
+{
+ return GetWidth (aString, (PRUint32)aLength, aWidth, NULL CONTEXT_ARG_NULL);
+}
+#endif
+nsresult
+nsFontMetricsPango::GetWidth(const char* aString, PRUint32 aLength,
+ nscoord& aWidth
+ CONTEXT_ARG_DEF)
+{
int width, height;
-
+ PangoLayout *layout = GetLayout(aString, aLength);
pango_layout_get_size(layout, &width, &height);
-
g_object_unref(layout);
- float f;
- f = mDeviceContext->DevUnitsToAppUnits();
+ float f = mDeviceContext->DevUnitsToAppUnits();
aWidth = NSToCoordRound(width * f / PANGO_SCALE);
- // printf("GetWidth (char *) %d\n", aWidth);
-
return NS_OK;
}
nsresult
nsFontMetricsPango::GetWidth(const PRUnichar* aString, PRUint32 aLength,
- nscoord& aWidth, PRInt32 *aFontID,
- nsRenderingContextGTK *aContext)
+ nscoord& aWidth, PRInt32 *aFontID
+ CONTEXT_ARG_DEF)
{
- 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("nsFontMetricsPango::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);
+ PangoLayout *layout = GetLayout(aString, aLength);
pango_layout_get_size(layout, &width, &height);
+ g_object_unref(layout);
- float f;
- f = mDeviceContext->DevUnitsToAppUnits();
+ float f = mDeviceContext->DevUnitsToAppUnits();
aWidth = NSToCoordRound(width * f / PANGO_SCALE);
- // printf("GetWidth %d\n", aWidth);
-
- loser:
- g_free(text);
- g_object_unref(layout);
-
- return rv;
+ return NS_OK;
}
nsresult
-nsFontMetricsPango::GetTextDimensions(const PRUnichar* aString,
+nsFontMetricsPango::GetTextDimensions(const char* aString,
PRUint32 aLength,
- nsTextDimensions& aDimensions,
- PRInt32* aFontID,
- nsRenderingContextGTK *aContext)
+ nsTextDimensions& aDimensions
+ CONTEXT_ARG_DEF)
{
- nsresult rv = NS_OK;
-
- PangoLayout *layout = pango_layout_new(mPangoContext);
+ PangoLayout *layout = GetLayout(aString, aLength);
+ PangoLayoutLine *line = pango_layout_get_line(layout, 0);
- gchar *text = g_utf16_to_utf8(aString, aLength,
- NULL, NULL, NULL);
-
- if (!text) {
-#ifdef DEBUG
- NS_WARNING("nsFontMetricsPango::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;
- }
-
+ PangoRectangle logical;
+ pango_layout_line_get_extents(line, NULL, &logical);
+ g_object_unref(layout);
- pango_layout_set_text(layout, text, strlen(text));
- FixupSpaceWidths(layout, text);
+ float P2T = mDeviceContext->DevUnitsToAppUnits();
- // 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);
+ aDimensions.ascent = NSToCoordRound(PANGO_ASCENT(logical) * P2T / PANGO_SCALE);
+ aDimensions.descent = NSToCoordRound(PANGO_DESCENT(logical) * P2T / PANGO_SCALE);
+ aDimensions.width = NSToCoordRound(logical.width * P2T / PANGO_SCALE);
- PangoRectangle rect;
- pango_layout_line_get_extents(line, NULL, &rect);
+ return NS_OK;
+}
- float P2T;
- P2T = mDeviceContext->DevUnitsToAppUnits();
+nsresult
+nsFontMetricsPango::GetTextDimensions(const PRUnichar* aString,
+ PRUint32 aLength,
+ nsTextDimensions& aDimensions,
+ PRInt32* aFontID
+ CONTEXT_ARG_DEF)
+{
+ PangoLayout *layout = GetLayout(aString, aLength);
+ PangoLayoutLine *line = pango_layout_get_line(layout, 0);
- 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);
+ PangoRectangle logical;
+ pango_layout_line_get_extents(line, NULL, &logical);
+ g_object_unref(layout);
- // printf("GetTextDimensions %d %d %d\n", aDimensions.width,
- //aDimensions.ascent, aDimensions.descent);
+ float P2T = mDeviceContext->DevUnitsToAppUnits();
- loser:
- g_free(text);
- g_object_unref(layout);
+ aDimensions.ascent = NSToCoordRound(PANGO_ASCENT(logical) * P2T / PANGO_SCALE);
+ aDimensions.descent = NSToCoordRound(PANGO_DESCENT(logical) * P2T / PANGO_SCALE);
+ aDimensions.width = NSToCoordRound(logical.width * P2T / PANGO_SCALE);
- return rv;
+ return NS_OK;
}
nsresult
@@ -595,13 +626,13 @@ nsFontMetricsPango::GetTextDimensions(co
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
- PRInt32* aFontID,
- nsRenderingContextGTK *aContext)
+ PRInt32* aFontID
+ CONTEXT_ARG_DEF)
{
return GetTextDimensionsInternal(aString, aLength, aAvailWidth, aBreaks,
aNumBreaks, aDimensions, aNumCharsFit,
- aLastWordDimensions, aContext);
+ aLastWordDimensions CONTEXT_ARG_PASS);
}
@@ -614,8 +645,8 @@ nsFontMetricsPango::GetTextDimensions(co
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
- PRInt32* aFontID,
- nsRenderingContextGTK *aContext)
+ PRInt32* aFontID
+ CONTEXT_ARG_DEF)
{
nsresult rv = NS_OK;
PRInt32 curBreak = 0;
@@ -623,23 +654,15 @@ nsFontMetricsPango::GetTextDimensions(co
PRInt32 *utf8Breaks = new PRInt32[aNumBreaks];
- gchar *text = g_utf16_to_utf8(aString, (PRInt32)aLength,
- NULL, NULL, NULL);
+ gchar* text;
+ gint text_len;
+ utf16_to_utf8 (aString, aLength, text, text_len);
curChar = text;
- if (!text) {
-#ifdef DEBUG
- NS_WARNING("nsFontMetricsPango::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)) {
+ curOffset++, curChar = g_utf8_next_char(curChar)) {
if (aBreaks[curBreak] == curOffset) {
utf8Breaks[curBreak] = curChar - text;
curBreak++;
@@ -653,10 +676,10 @@ nsFontMetricsPango::GetTextDimensions(co
utf8Breaks[curBreak] = curChar - text;
#if 0
- if (strlen(text) != aLength) {
- printf("Different lengths for utf16 %d and utf8 %d\n", aLength, strlen(text));
+ if (text_len != aLength) {
+ printf("Different lengths for utf16 %d and utf8 %d\n", aLength, text_len);
DUMP_PRUNICHAR(aString, aLength)
- DUMP_PRUNICHAR(text, strlen(text))
+ DUMP_PRUNICHAR(text, text_len)
for (PRInt32 i = 0; i < aNumBreaks; ++i) {
printf(" break %d utf16 %d utf8 %d\n", i, aBreaks[i], utf8Breaks[i]);
}
@@ -666,9 +689,9 @@ nsFontMetricsPango::GetTextDimensions(co
// 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,
+ rv = GetTextDimensionsInternal(text, text_len, aAvailWidth, utf8Breaks,
aNumBreaks, aDimensions, aNumCharsFit,
- aLastWordDimensions, aContext);
+ aLastWordDimensions CONTEXT_ARG_PASS);
// Figure out which of the breaks we ended up using to convert
// back to utf16 - start from the end.
@@ -681,200 +704,365 @@ nsFontMetricsPango::GetTextDimensions(co
}
}
- loser:
- if (text)
- g_free(text);
+ g_free(text);
delete[] utf8Breaks;
return rv;
}
-nsresult
-nsFontMetricsPango::DrawString(const char *aString, PRUint32 aLength,
- nscoord aX, nscoord aY,
- const nscoord* aSpacing,
- nsRenderingContextGTK *aContext,
- nsDrawingSurfaceGTK *aSurface)
+#ifdef PSPANGO
+
+typedef struct _nsPSPangoRenderer nsPSPangoRenderer;
+typedef struct _nsPSPangoRendererClass nsPSPangoRendererClass;
+
+struct _nsPSPangoRenderer
{
- PangoLayout *layout = pango_layout_new(mPangoContext);
+ PangoRenderer parent_instance;
+ nsRenderingContextPS *psContext;
+ nsFontMetricsPSPango *psPangoFontMetrics;
+ float zoom;
+};
- pango_layout_set_text(layout, aString, aLength);
- FixupSpaceWidths(layout, aString);
+struct _nsPSPangoRendererClass
+{
+ PangoRendererClass parent_class;
+};
- int x = aX;
- int y = aY;
+#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))
- aContext->GetTranMatrix()->TransformCoord(&x, &y);
+G_DEFINE_TYPE (_nsPSPangoRenderer, _ps_pango_renderer, PANGO_TYPE_RENDERER)
- PangoLayoutLine *line;
- if (pango_layout_get_line_count(layout) != 1) {
- printf("Warning: more than one line!\n");
- }
- line = pango_layout_get_line(layout, 0);
+static PangoRenderer *
+get_renderer (void)
+{
+ static PangoRenderer *renderer = NULL;
- aContext->UpdateGC();
- GdkGC *gc = aContext->GetGC();
+ if (!renderer)
+ renderer = (PangoRenderer *) g_object_new (_PS_TYPE_PANGO_RENDERER, NULL);
- if (aSpacing && *aSpacing) {
- DrawStringSlowly(aString, NULL, aLength, aSurface->GetDrawable(),
- gc, x, y, line, aSpacing);
- }
- else {
- gdk_draw_layout_line(aSurface->GetDrawable(), gc,
- x, y,
- line);
- }
+ return renderer;
+}
- g_object_unref(gc);
- g_object_unref(layout);
+static void
+_ps_pango_renderer_draw_glyphs (PangoRenderer *renderer,
+ PangoFont *font,
+ PangoGlyphString *glyphs,
+ int x,
+ int y);
- // printf("DrawString (char *)\n");
+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;
+}
- return NS_OK;
+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
-nsFontMetricsPango::DrawString(const PRUnichar* aString, PRUint32 aLength,
- nscoord aX, nscoord aY,
- PRInt32 aFontID,
- const nscoord* aSpacing,
- nsRenderingContextGTK *aContext,
- nsDrawingSurfaceGTK *aSurface)
+nsPangoType1Generator::Init(PangoFont *aFont)
+ {
+ NS_ENSURE_TRUE(aFont, NS_ERROR_FAILURE);
+ mFont = aFont;
+ g_object_ref (mFont);
+ return NS_OK;
+}
+
+nsPangoType1Generator::~nsPangoType1Generator()
{
- nsresult rv = NS_OK;
- int x = aX;
- int y = aY;
+ g_object_unref (mFont);
+ mFont = nsnull;
+}
- aContext->UpdateGC();
- GdkGC *gc = aContext->GetGC();
+void nsPangoType1Generator::GeneratePSFont(FILE* aFile)
+{
+ FT_Face face = pango_fc_font_lock_face ((PangoFcFont *) mFont);
- PangoLayout *layout = pango_layout_new(mPangoContext);
+ if (face == nsnull)
+ return;
- gchar *text = g_utf16_to_utf8(aString, aLength,
- NULL, NULL, NULL);
+ int wmode = 0;
+ if (mGlyphSubset->Count())
+ FT2SubsetToType1FontSet(face, mGlyphSubset, wmode, aFile);
- if (!text) {
-#ifdef DEBUG
- NS_WARNING("nsFontMetricsPango::DrawString invalid unicode to follow");
- DUMP_PRUNICHAR(aString, aLength)
-#endif
- rv = NS_ERROR_FAILURE;
- goto loser;
- }
+ pango_fc_font_unlock_face ((PangoFcFont *) mFont);
+}
- pango_layout_set_text(layout, text, strlen(text));
- FixupSpaceWidths(layout, text);
+typedef struct
+{
+ nsCString *FontNameBase;
+ nsCStringKey *key;
+ int font_size;
+} PSPangoFontData;
- aContext->GetTranMatrix()->TransformCoord(&x, &y);
+static void
+ps_pango_font_data_destroy (PSPangoFontData *data)
+{
+ delete data->key;
+ delete data->FontNameBase;
+ g_free (data);
+}
- PangoLayoutLine *line;
- if (pango_layout_get_line_count(layout) != 1) {
- printf("Warning: more than one line!\n");
- }
- line = pango_layout_get_line(layout, 0);
+static void
+_ps_pango_renderer_draw_glyphs (PangoRenderer *renderer,
+ PangoFont *font,
+ PangoGlyphString *glyphs,
+ int x,
+ int y)
+{
+ if (!glyphs->num_glyphs)
+ return;
- if (aSpacing && *aSpacing) {
- DrawStringSlowly(text, aString, aLength, aSurface->GetDrawable(),
- gc, x, y, line, aSpacing);
- }
- else {
- gdk_draw_layout_line(aSurface->GetDrawable(), gc,
- x, y,
- line);
- }
+ static GQuark data_quark = 0;
+ if (!data_quark)
+ data_quark = g_quark_from_static_string ("ps-pango-font-data");
- loser:
+ PSPangoFontData *data;
+ if (!(data = (PSPangoFontData *) g_object_get_qdata (G_OBJECT (font), data_quark)))
+ {
+ data = g_new (PSPangoFontData, 1);
- g_free(text);
- g_object_unref(gc);
- g_object_unref(layout);
+ 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);
- // printf("DrawString\n");
+ 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;
+ currSubFont = prevSubFont;
+ for (i = 0; i < glyphs->num_glyphs; ++i) {
+ PangoGlyph glyph = glyphs->glyphs[i].glyph;
+
+ if (glyph != PANGO_GLYPH_EMPTY)
+ currSubFont = psFontGen->AddToGlyphSubset(glyph > 0x0fffffff ? 0 : 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;
+ }
- return rv;
+ gl.num_glyphs++;
+ }
+
+ if (prevSubFont != -1)
+ psObj->show(&gl, ps_renderer->zoom, psFontGen, prevSubFont);
}
+#endif
+
+static void
+draw_layout_line (int x, int y,
+ PangoLayoutLine *line,
+ nsFontMetricsPango *fm
+ CONTEXT_AND_SURFACE_ARG_DEF)
+{
+#ifdef PSPANGO
+ PangoRenderer *renderer = get_renderer ();
+ nsPSPangoRenderer *ps_renderer = (nsPSPangoRenderer *)renderer;
+ ps_renderer->psContext = aContext;
+ ps_renderer->psPangoFontMetrics = fm;
+ nsDeviceContextPS* dc = NS_REINTERPRET_CAST (nsDeviceContextPS*, fm->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));
+#else
+ aContext->UpdateGC();
+ GdkGC *gc = aContext->GetGC();
+ gdk_draw_layout_line(aSurface->GetDrawable(), gc, x, y, line);
+ g_object_unref(gc);
+#endif
+}
+
-#ifdef MOZ_MATHML
nsresult
-nsFontMetricsPango::GetBoundingMetrics(const char *aString, PRUint32 aLength,
- nsBoundingMetrics &aBoundingMetrics,
- nsRenderingContextGTK *aContext)
+nsFontMetricsPango::DrawString(const char *aString, PRUint32 aLength,
+ nscoord aX, nscoord aY,
+ const nscoord* aSpacing
+ CONTEXT_AND_SURFACE_ARG_DEF)
{
- printf("GetBoundingMetrics (char *)\n");
- return NS_ERROR_FAILURE;
+ int x = aX;
+ int y = aY;
+
+ aContext->GetTranMatrix()->TransformCoord(&x, &y);
+
+ PangoLayout *layout = GetLayout(aString, aLength);
+ PangoLayoutLine *line = pango_layout_get_line(layout, 0);
+
+ ApplySpacing(aString, aLength, line, aSpacing);
+ draw_layout_line(x, y, line, this CONTEXT_AND_SURFACE_ARG_PASS);
+
+ g_object_unref(layout);
+
+ return NS_OK;
}
nsresult
-nsFontMetricsPango::GetBoundingMetrics(const PRUnichar *aString,
- PRUint32 aLength,
- nsBoundingMetrics &aBoundingMetrics,
- PRInt32 *aFontID,
- nsRenderingContextGTK *aContext)
+nsFontMetricsPango::DrawString(const PRUnichar* aString, PRUint32 aLength,
+ nscoord aX, nscoord aY,
+ PRInt32 aFontID,
+ const nscoord* aSpacing
+ CONTEXT_AND_SURFACE_ARG_DEF)
{
- nsresult rv = NS_OK;
- PangoLayout *layout = pango_layout_new(mPangoContext);
+ int x = aX;
+ int y = aY;
- gchar *text = g_utf16_to_utf8(aString, aLength,
- NULL, NULL, NULL);
+ aContext->GetTranMatrix()->TransformCoord(&x, &y);
- if (!text) {
-#ifdef DEBUG
- NS_WARNING("nsFontMetricsPango::GetBoundingMetrics invalid unicode to follow");
- DUMP_PRUNICHAR(aString, aLength)
-#endif
- aBoundingMetrics.Clear();
+ PangoLayout *layout = GetLayout(aString, aLength);
+ PangoLayoutLine *line = pango_layout_get_line(layout, 0);
- rv = NS_ERROR_FAILURE;
- goto loser;
- }
+ ApplySpacing(aString, aLength, line, aSpacing);
+ draw_layout_line(x, y, line, this CONTEXT_AND_SURFACE_ARG_PASS);
- pango_layout_set_text(layout, text, -1);
- FixupSpaceWidths(layout, text);
+ g_object_unref(layout);
+
+ return NS_OK;
+}
- PangoLayoutLine *line;
- if (pango_layout_get_line_count(layout) != 1) {
- printf("Warning: more than one line!\n");
- }
- line = pango_layout_get_line(layout, 0);
+
+#ifdef MOZ_MATHML
+void
+nsFontMetricsPango::GetBoundingMetricsInternal(PangoLayout *aLayout,
+ nsBoundingMetrics &aBoundingMetrics
+ CONTEXT_ARG_DEF)
+{
+ PangoLayoutLine *line = pango_layout_get_line(aLayout, 0);
// Get the ink and logical extents
PangoRectangle ink, logical;
pango_layout_line_get_extents(line, &ink, &logical);
- float P2T;
- P2T = mDeviceContext->DevUnitsToAppUnits();
+ float 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);
+nsresult
+nsFontMetricsPango::GetBoundingMetrics(const char *aString, PRUint32 aLength,
+ nsBoundingMetrics &aBoundingMetrics
+ CONTEXT_ARG_DEF)
+{
+ PangoLayout *layout = GetLayout(aString, aLength);
+ GetBoundingMetricsInternal (layout, aBoundingMetrics CONTEXT_ARG_PASS);
g_object_unref(layout);
- return rv;
+ return NS_OK;
+}
+
+nsresult
+nsFontMetricsPango::GetBoundingMetrics(const PRUnichar *aString,
+ PRUint32 aLength,
+ nsBoundingMetrics &aBoundingMetrics,
+ PRInt32 *aFontID
+ CONTEXT_ARG_DEF)
+{
+ PangoLayout *layout = GetLayout(aString, aLength);
+ GetBoundingMetricsInternal (layout, aBoundingMetrics CONTEXT_ARG_PASS);
+ g_object_unref(layout);
+
+ return NS_OK;
}
#endif /* MOZ_MATHML */
+#ifndef PSPANGO
GdkFont*
nsFontMetricsPango::GetCurrentGDKFont(void)
{
return nsnull;
}
+#endif
nsresult
nsFontMetricsPango::SetRightToLeftText(PRBool aIsRTL)
{
if (aIsRTL) {
if (!mRTLPangoContext) {
- mRTLPangoContext = gdk_pango_context_get();
+ mRTLPangoContext = get_context();
pango_context_set_base_dir(mRTLPangoContext, PANGO_DIRECTION_RTL);
-
- gdk_pango_context_set_colormap(mRTLPangoContext, gdk_rgb_get_cmap());
pango_context_set_language(mRTLPangoContext, GetPangoLanguage(mLangGroup));
pango_context_set_font_description(mRTLPangoContext, mPangoFontDesc);
}
@@ -899,34 +1087,18 @@ nsFontMetricsPango::GetClusterInfo(const
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("nsFontMetricsPango::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);
+ PangoLayout *layout = GetLayout(aText, aLength);
+ pango_layout_get_log_attrs(layout, &attrs, &n_attrs);
+ g_object_unref(layout);
// 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;
+ aClusterStarts[pos] = 1;//FIXME: shouldn't this be zero?! --be
pos++;
}
else {
@@ -934,56 +1106,34 @@ nsFontMetricsPango::GetClusterInfo(const
}
}
- loser:
- if (attrs)
- g_free(attrs);
- if (text)
- g_free(text);
- if (layout)
- g_object_unref(layout);
+ g_free(attrs);
- return rv;
+ return NS_OK;
}
PRInt32
-nsFontMetricsPango::GetPosition(const PRUnichar *aText, PRUint32 aLength,
- nsPoint aPt)
+nsFontMetricsPango::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("nsFontMetricsPango::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);
+ PangoLayout *layout = GetLayout(aText, aLength);
pango_layout_xy_to_index(layout, localX, localY,
&inx, &trailing);
// Convert the index back to the utf-16 index
- curChar = text;
+ const gchar *text = pango_layout_get_text (layout);
+ const gchar *curChar = text;
for (PRUint32 curOffset=0; curOffset < aLength;
- curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
+ curOffset++, curChar = g_utf8_next_char(curChar)) {
// Check for a match before checking for a surrogate pair
if (curChar - text == inx) {
@@ -1006,13 +1156,9 @@ nsFontMetricsPango::GetPosition(const PR
trailing--;
}
- loser:
- if (text)
- g_free(text);
- if (layout)
- g_object_unref(layout);
+ g_object_unref(layout);
- return retval;
+ return retval;
}
nsresult
@@ -1022,28 +1168,21 @@ nsFontMetricsPango::GetRangeWidth(const
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("nsFontMetricsPango::GetWidth invalid unicode to follow");
- DUMP_PRUNICHAR(aText, aLength)
-#endif
- rv = NS_ERROR_FAILURE;
- goto loser;
- }
+ gchar* text;
+ gint text_len;
+ utf16_to_utf8 (aText, aLength, text, text_len);
+ gchar *curChar = text;
// Convert the utf16 offsets into utf8 offsets
for (PRUint32 curOffset = 0; curOffset < aLength;
- curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
+ curOffset++, curChar = g_utf8_next_char(curChar)) {
if (curOffset == aStart)
utf8Start = curChar - text;
@@ -1057,15 +1196,13 @@ nsFontMetricsPango::GetRangeWidth(const
// Special case where the end index is the same as the length
if (aLength == aEnd)
- utf8End = strlen(text);
+ utf8End = text_len;
- rv = GetRangeWidth(text, strlen(text), utf8Start, utf8End, aWidth);
+ GetRangeWidth(text, text_len, utf8Start, utf8End, aWidth);
- loser:
- if (text)
- g_free(text);
+ g_free(text);
- return rv;
+ return NS_OK;
}
nsresult
@@ -1075,43 +1212,26 @@ nsFontMetricsPango::GetRangeWidth(const
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);
+ PangoLayout *layout = GetLayout(aText, aLength);
+ PangoLayoutLine *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);
+ aWidth = NSToCoordRound(aWidth * f / PANGO_SCALE);
- loser:
- if (ranges)
- g_free(ranges);
- if (layout)
- g_object_unref(layout);
+ g_free(ranges);
+ g_object_unref(layout);
- return rv;
+ return NS_OK;
}
/* static */
@@ -1134,7 +1254,7 @@ nsFontMetricsPango::FamilyExists(nsIDevi
NS_ConvertUTF16toUTF8 name(aName);
nsresult rv = NS_ERROR_FAILURE;
- PangoContext *context = gdk_pango_context_get();
+ PangoContext *context = get_context();
PangoFontFamily **familyList;
int n;
@@ -1233,16 +1353,13 @@ nsFontMetricsPango::RealizeFont(void)
// Now that we have the font description set up, create the
// context.
- mLTRPangoContext = gdk_pango_context_get();
+ 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 color map so we can draw later.
- gdk_pango_context_set_colormap(mPangoContext, gdk_rgb_get_cmap());
-
// Set the pango language now that we have a context
pango_context_set_language(mPangoContext, GetPangoLanguage(mLangGroup));
@@ -1280,79 +1397,268 @@ nsFontMetricsPango::EnumFontCallback(con
* 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!
+ *
+ * To do it correctly (ligatures, etc) we need machinery that is private
+ * in Pango. IMPORT IT:
+ */
+
+#define _PangoGlyphItemIter _nsFontMetricsPangoGlyphItemIter
+#define PangoGlyphItemIter nsFontMetricsPangoGlyphItemIter
+
+#define LTR(glyph_item) (((glyph_item)->item->analysis.level % 2) == 0)
+
+/* Structure holding state when we're iterating over a GlyphItem.
+ * start_index/cluster_end (and range_start/range_end in
+ * apply_attrs()) are offsets into the text, so note the difference
+ * of glyph_item->item->offset between them and clusters in the
+ * log_clusters[] array.
*/
+typedef struct _PangoGlyphItemIter PangoGlyphItemIter;
+
+struct _PangoGlyphItemIter
+{
+ PangoGlyphItem *glyph_item;
+ const gchar *text;
+
+ int start_glyph;
+ int start_index;
+ int start_char;
+
+ int end_glyph;
+ int end_index;
+ int end_char;
+};
+
+/**
+ * _pango_glyph_item_iter_next_cluster:
+ * @iter: a #PangoGlyphItemIter
+ *
+ * Advances the iterator to the next cluster in the glyph item.
+ *
+ * Return value: %TRUE if the iterator was advanced, %FALSE if we were already on the
+ * last cluster.
+ **/
+static gboolean
+_pango_glyph_item_iter_next_cluster (PangoGlyphItemIter *iter)
+{
+ int glyph_index = iter->end_glyph;
+ PangoGlyphString *glyphs = iter->glyph_item->glyphs;
+ PangoItem *item = iter->glyph_item->item;
+
+ if (LTR (iter->glyph_item))
+ {
+ if (glyph_index == glyphs->num_glyphs)
+ return FALSE;
+ }
+ else
+ {
+ if (glyph_index < 0)
+ return FALSE;
+ }
+
+ iter->start_glyph = iter->end_glyph;
+ iter->start_index = iter->end_index;
+ iter->start_char = iter->end_char;
+
+ if (LTR (iter->glyph_item))
+ {
+ while (TRUE)
+ {
+ glyph_index++;
+
+ if (glyph_index == glyphs->num_glyphs)
+ {
+ iter->end_index = item->offset + item->length;
+ iter->end_char = item->num_chars;
+ break;
+ }
+
+ if (item->offset + glyphs->log_clusters[glyph_index] != iter->start_index)
+ {
+ iter->end_index = item->offset + glyphs->log_clusters[glyph_index];
+ iter->end_char += g_utf8_strlen (iter->text + iter->start_index,
+ iter->end_index - iter->start_index);
+ break;
+ }
+ }
+ }
+ else /* RTL */
+ {
+ while (TRUE)
+ {
+ glyph_index--;
+
+ if (glyph_index < 0)
+ {
+ iter->end_index = item->offset + item->length;
+ iter->end_char = item->num_chars;
+ break;
+ }
+
+ if (item->offset + glyphs->log_clusters[glyph_index] != iter->start_index)
+ {
+ iter->end_index = item->offset + glyphs->log_clusters[glyph_index];
+ iter->end_char += g_utf8_strlen (iter->text + iter->start_index,
+ iter->end_index - iter->start_index);
+ break;
+ }
+ }
+ }
+
+ iter->end_glyph = glyph_index;
+ return TRUE;
+}
+
+/**
+ * _pango_glyph_item_iter_init_start:
+ * @iter: pointer to a #PangoGlyphItemIter structure
+ * @glyph_item: the glyph item that the iter points into
+ * @text: text corresponding to the glyph item
+ *
+ * Initializes a #PangoGlyphItemIter structure to point to the
+ * first cluster in a glyph item.
+ *
+ * Return value: %FALSE if there are no clusters in the glyph item;
+ * in this case, the state of the iter is undefined.
+ **/
+static gboolean
+_pango_glyph_item_iter_init_start (PangoGlyphItemIter *iter,
+ PangoGlyphItem *glyph_item,
+ const char *text)
+{
+ iter->glyph_item = glyph_item;
+ iter->text = text;
+
+ if (LTR (glyph_item))
+ iter->end_glyph = 0;
+ else
+ iter->end_glyph = glyph_item->glyphs->num_glyphs - 1;
+
+ iter->end_index = glyph_item->item->offset;
+ iter->end_char = 0;
+
+ /* Advance onto the first cluster of the glyph item */
+ return _pango_glyph_item_iter_next_cluster (iter);
+}
+
void
-nsFontMetricsPango::DrawStringSlowly(const gchar *aText,
- const PRUnichar *aOrigString,
- PRUint32 aLength,
- GdkDrawable *aDrawable,
- GdkGC *aGC, gint aX, gint aY,
- PangoLayoutLine *aLine,
- const nscoord *aSpacing)
-{
- float app2dev;
- app2dev = mDeviceContext->AppUnitsToDevUnits();
- gint offset = 0;
+nsFontMetricsPango::ApplySpacing(const gchar *aText,
+ PRUint32 aLength,
+ PangoLayoutLine *aLine,
+ const nscoord *aSpacing)
+{
+ if (!(aSpacing && *aSpacing))
+ return;
+
+ float app2dev = mDeviceContext->AppUnitsToDevUnits();
/*
* 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.
+ * glyphs.
*/
- nscoord *utf8spacing = new nscoord[strlen(aText)];
+ for (GSList *tmpList = aLine->runs; tmpList && tmpList->data;
+ tmpList = tmpList->next) {
+ PangoGlyphItem *glyph_item = (PangoGlyphItem *)tmpList->data;
+ PangoGlyphItemIter iter;
+ gboolean have_cluster;
+ PangoGlyphInfo *glyphs = glyph_item->glyphs->glyphs;
+ int residualWidth = 0;
+
+ for (have_cluster = _pango_glyph_item_iter_init_start (&iter, glyph_item, aText);
+ have_cluster;
+ have_cluster = _pango_glyph_item_iter_next_cluster (&iter))
+ {
+ int clusterOldWidth = 0;
+ int clusterNewWidth = 0;
+ int dir = iter.start_glyph < iter.end_glyph ? +1 : -1;
+ gboolean has_zero_width = FALSE;
+
+ for (const char *p = iter.text + iter.start_index;
+ p < iter.text + iter.end_index;
+ p = g_utf8_next_char (p))
+ clusterNewWidth += aSpacing[p - iter.text];
+
+ clusterNewWidth = (gint)(clusterNewWidth * app2dev * PANGO_SCALE);
+
+ for (gint i = iter.start_glyph; i != iter.end_glyph; i += dir) {
+ if (!glyphs[i].geometry.width)
+ has_zero_width = TRUE;
+ clusterOldWidth += glyphs[i].geometry.width;
+ }
+
+ /* if a zero-width glyph exists, don't touch the glyph widths.
+ * required for combining marks. ff thinks they have a width.
+ * instead, we charge the difference to the next space glyph. */
+ if (has_zero_width) {
+ residualWidth += clusterNewWidth - clusterOldWidth;
+ continue;
+ }
- 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 a space glyph is found, charge it whatever residual we
+ * have accumulated so far. */
+ if (iter.end_index - iter.start_index == 1 &&
+ *(iter.text + iter.start_index) == ' ') {
+ clusterNewWidth += residualWidth;
+ residualWidth = 0;
+ }
+
+#ifndef PSPANGO
+ /* do some hinting for display */
+
+ if (clusterOldWidth % PANGO_SCALE == 0 && clusterNewWidth % PANGO_SCALE != 0) {
+ int tmp = clusterNewWidth;
+ clusterNewWidth = PANGO_PIXELS (clusterNewWidth) * PANGO_SCALE;
+ residualWidth += tmp - clusterNewWidth;
+ }
+#endif
- if (IS_HIGH_SURROGATE(aOrigString[curOffset]))
- curOffset++;
+ /* find the first non-zero-width glyph and adjust its width */
+ for (gint i = iter.start_glyph; i != iter.end_glyph; i += dir)
+ if (glyphs[i].geometry.width) {
+ glyphs[i].geometry.width += clusterNewWidth - clusterOldWidth;
+ break;
+ }
}
}
- else {
- memcpy(utf8spacing, aSpacing, (sizeof(nscoord *) * aLength));
- }
+}
- gint curRun = 0;
+void
+nsFontMetricsPango::ApplySpacing(const PRUnichar *aText,
+ PRUint32 aLength,
+ PangoLayoutLine *aLine,
+ const nscoord *aSpacing)
+{
+ if (!(aSpacing && *aSpacing))
+ return;
- for (GSList *tmpList = aLine->runs; tmpList && tmpList->data;
- tmpList = tmpList->next, curRun++) {
- PangoLayoutRun *layoutRun = (PangoLayoutRun *)tmpList->data;
- gint tmpOffset = 0;
+ const char *utf8Text = pango_layout_get_text (aLine->layout);
+ int utf8Text_len = aLine->start_index + aLine->length;
- /* printf(" Rendering run %d: \"%s\"\n", curRun,
- &aText[layoutRun->item->offset]); */
+ /* 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 = g_new0 (nscoord, utf8Text_len);
- 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;
- }
+ const gchar *curChar = utf8Text + aLine->start_index;
- /* printf(" rendering at X coord %d\n", aX + offset); */
- offset += tmpOffset;
+ // Covert the utf16 spacing offsets to utf8 spacing offsets
+ for (PRUint32 curOffset=0; curOffset < aLength;
+ curOffset++, curChar = g_utf8_next_char(curChar)) {
+ utf8spacing[curChar - utf8Text] = aSpacing[curOffset];
+
+ if (IS_HIGH_SURROGATE(aText[curOffset]))
+ curOffset++;
}
- gdk_draw_layout_line(aDrawable, aGC, aX, aY, aLine);
+ ApplySpacing (utf8Text, utf8Text_len, aLine, utf8spacing);
- delete[] utf8spacing;
+ g_free (utf8spacing);
}
nsresult
@@ -1363,8 +1669,8 @@ nsFontMetricsPango::GetTextDimensionsInt
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
- nsTextDimensions& aLastWordDimensions,
- nsRenderingContextGTK *aContext)
+ nsTextDimensions& aLastWordDimensions
+ CONTEXT_ARG_DEF)
{
NS_PRECONDITION(aBreaks[aNumBreaks - 1] == aLength, "invalid break array");
@@ -1410,7 +1716,7 @@ nsFontMetricsPango::GetTextDimensionsInt
// All the characters should fit
numChars = aLength - start;
breakIndex = aNumBreaks - 1;
- }
+ }
else {
breakIndex = prevBreakState_BreakIndex;
while (((breakIndex + 1) < aNumBreaks) &&
@@ -1431,7 +1737,7 @@ nsFontMetricsPango::GetTextDimensionsInt
if ((1 == numChars) && (aString[start] == ' '))
GetSpaceWidth(twWidth);
else if (numChars > 0)
- GetWidth(&aString[start], numChars, twWidth, aContext);
+ GetWidth(&aString[start], numChars, twWidth CONTEXT_ARG_PASS);
// See if the text fits
PRBool textFits = (twWidth + width) <= aAvailWidth;
@@ -1481,8 +1787,7 @@ nsFontMetricsPango::GetTextDimensionsInt
if ((1 == numChars) && (aString[start] == ' '))
GetSpaceWidth(twWidth);
else if (numChars > 0)
- GetWidth(&aString[start], numChars, twWidth,
- aContext);
+ GetWidth(&aString[start], numChars, twWidth CONTEXT_ARG_PASS);
width -= twWidth;
aNumCharsFit = start;
breakIndex--;
@@ -1504,9 +1809,16 @@ nsFontMetricsPango::GetTextDimensionsInt
}
void
-nsFontMetricsPango::FixupSpaceWidths (PangoLayout *aLayout,
- const char *aString)
+nsFontMetricsPango::FixupSpaceWidths (PangoLayout *aLayout)
{
+ if (!mPangoSpaceWidth)
+ return;
+
+ const char *aString = pango_layout_get_text (aLayout);
+
+ if (pango_layout_get_line_count(aLayout) != 1) {
+ printf("Warning: more than one line!\n");
+ }
PangoLayoutLine *line = pango_layout_get_line(aLayout, 0);
gint curRun = 0;
@@ -1523,6 +1835,107 @@ nsFontMetricsPango::FixupSpaceWidths (Pa
}
}
+PangoLayout*
+nsFontMetricsPango::GetLayout (const PRUnichar* aText,
+ PRUint32 aLength)
+{
+ gchar* text;
+ gint length;
+ utf16_to_utf8 (aText, aLength, text, length);
+
+ PangoLayout *layout = pango_layout_new(mPangoContext);
+ pango_layout_set_text (layout, text, length);
+ FixupSpaceWidths (layout);
+
+ g_free ((gpointer) text);
+
+ return layout;
+}
+
+PangoLayout*
+nsFontMetricsPango::GetLayout (const gchar* aText,
+ PRInt32 aLength)
+{
+ gboolean has_nul = FALSE;
+ int i;
+
+ for (i = 0; i < aLength; i++)
+ if (!aText[i]) {
+ has_nul = TRUE;
+ break;
+ }
+
+ if (has_nul) {
+ /* Pango doesn't correctly handle nuls. We convert them to 0xff. */
+
+ char *p = (char *) g_memdup (aText, aLength);
+
+ /* don't need to reset i */
+ for (; i < aLength; i++)
+ if (!p[i])
+ p[i] = (char) 0xff;
+
+ aText = p;
+ }
+
+ PangoLayout *layout = pango_layout_new(mPangoContext);
+ pango_layout_set_text (layout, aText, aLength);
+ FixupSpaceWidths (layout);
+
+ if (has_nul)
+ g_free ((gpointer) aText);
+
+ return layout;
+}
+
+static void
+utf16_to_utf8 (const PRUnichar* aText, PRUint32 aLength, char *&text, gint &length)
+{
+ gboolean need_copy = FALSE;
+ int i;
+
+ for (i = 0; i < aLength; i++) {
+ if (!aText[i] || IS_LOW_SURROGATE (aText[i]))
+ need_copy = TRUE;
+ else if (IS_HIGH_SURROGATE (aText[i])) {
+ if (i < aLength - 1 && IS_LOW_SURROGATE (aText[i+1]))
+ i++;
+ else
+ need_copy = TRUE;
+ }
+ }
+
+ if (need_copy) {
+
+ /* Pango doesn't correctly handle nuls. We convert them to 0xff. */
+ /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */
+
+ PRUnichar *p = (PRUnichar *) g_memdup (aText, aLength * sizeof (aText[0]));
+
+ /* don't need to reset i */
+ for (i = 0; i < aLength; i++) {
+ if (!p[i] || IS_LOW_SURROGATE (p[i]))
+ p[i] = 0xFFFD;
+ else if (IS_HIGH_SURROGATE (p[i])) {
+ if (i < aLength - 1 && IS_LOW_SURROGATE (aText[i+1]))
+ i++;
+ else
+ p[i] = 0xFFFD;
+ }
+ }
+
+ aText = p;
+ }
+
+ glong items_written;
+ text = g_utf16_to_utf8 (aText, aLength, NULL, &items_written, NULL);
+ length = items_written;
+
+ if (need_copy)
+ g_free ((gpointer) aText);
+
+}
+
/* static */
PangoLanguage *
GetPangoLanguage(nsIAtom *aLangGroup)
--- mozilla.back/gfx/src/gtk/nsFontMetricsPango.h.orig 2006-06-30 01:18:34.000000000 +0200
+++ mozilla.back/gfx/src/gtk/nsFontMetricsPango.h 2007-06-28 15:16:39.000000000 +0200
@@ -37,17 +37,53 @@
*
* ***** END LICENSE BLOCK ***** */
+
#include "nsIFontMetrics.h"
#include "nsIFontEnumerator.h"
#include "nsCRT.h"
#include "nsIAtom.h"
#include "nsString.h"
#include "nsVoidArray.h"
+
+#ifdef PSPANGO
+#include "nsFontMetricsPS.h"
+#else
#include "nsIFontMetricsGTK.h"
+#endif
#include <pango/pango.h>
-class nsFontMetricsPango : public nsIFontMetricsGTK
+#ifdef PSPANGO
+
+#define CONTEXT_ARG_DEF
+#define CONTEXT_ARG_PASS
+#define CONTEXT_ARG_NULL
+#define CONTEXT_AND_SURFACE_ARG_DEF , nsRenderingContextPS *aContext
+#define CONTEXT_AND_SURFACE_ARG_PASS , aContext
+
+#else
+
+#define CONTEXT_ARG_DEF , nsRenderingContextGTK *aContext
+#define CONTEXT_ARG_PASS , aContext
+#define CONTEXT_ARG_NULL , NULL
+#define CONTEXT_AND_SURFACE_ARG_DEF , nsRenderingContextGTK *aContext, nsDrawingSurfaceGTK *aSurface
+#define CONTEXT_AND_SURFACE_ARG_PASS , aContext, aSurface
+
+#endif
+
+
+#ifdef PSPANGO
+
+#define nsFontMetricsPango nsFontMetricsPSPango
+#define PSPANGO_PARENT_CLASS nsFontMetricsPS
+
+#else
+
+#define PSPANGO_PARENT_CLASS nsIFontMetricsGTK
+
+#endif
+
+class nsFontMetricsPango : public PSPANGO_PARENT_CLASS
{
public:
nsFontMetricsPango();
@@ -136,20 +172,30 @@ public:
PRInt32 GetMaxStringLength() { return mMaxStringLength; }
- // nsIFontMetricsGTK (calls from the font rendering layer)
- virtual nsresult GetWidth(const char* aString, PRUint32 aLength,
- nscoord& aWidth,
- nsRenderingContextGTK *aContext);
- virtual nsresult GetWidth(const PRUnichar* aString, PRUint32 aLength,
- nscoord& aWidth, PRInt32 *aFontID,
- nsRenderingContextGTK *aContext);
+ // nsIFontMetrics (calls from the font rendering layer)
- virtual nsresult GetTextDimensions(const PRUnichar* aString,
+#ifdef PSPANGO
+ NS_IMETHOD GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength);
+ NS_IMETHOD GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength);
+#endif
+
+ NS_METHOD GetWidth(const char* aString, PRUint32 aLength,
+ nscoord& aWidth
+ CONTEXT_ARG_DEF);
+ NS_METHOD GetWidth(const PRUnichar* aString, PRUint32 aLength,
+ nscoord& aWidth, PRInt32 *aFontID
+ CONTEXT_ARG_DEF);
+
+ NS_METHOD GetTextDimensions(const char* aString,
+ PRUint32 aLength,
+ nsTextDimensions& aDimensions
+ CONTEXT_ARG_DEF);
+ NS_METHOD GetTextDimensions(const PRUnichar* aString,
PRUint32 aLength,
nsTextDimensions& aDimensions,
- PRInt32* aFontID,
- nsRenderingContextGTK *aContext);
- virtual nsresult GetTextDimensions(const char* aString,
+ PRInt32* aFontID
+ CONTEXT_ARG_DEF);
+ NS_METHOD GetTextDimensions(const char* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
@@ -157,9 +203,9 @@ public:
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
- PRInt32* aFontID,
- nsRenderingContextGTK *aContext);
- virtual nsresult GetTextDimensions(const PRUnichar* aString,
+ PRInt32* aFontID
+ CONTEXT_ARG_DEF);
+ NS_METHOD GetTextDimensions(const PRUnichar* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
@@ -167,38 +213,37 @@ public:
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
- PRInt32* aFontID,
- nsRenderingContextGTK *aContext);
+ PRInt32* aFontID
+ CONTEXT_ARG_DEF);
- virtual nsresult DrawString(const char *aString, PRUint32 aLength,
+ NS_METHOD DrawString(const char *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
- const nscoord* aSpacing,
- nsRenderingContextGTK *aContext,
- nsDrawingSurfaceGTK *aSurface);
- virtual nsresult DrawString(const PRUnichar* aString, PRUint32 aLength,
+ const nscoord* aSpacing
+ CONTEXT_AND_SURFACE_ARG_DEF);
+
+ NS_METHOD DrawString(const PRUnichar* aString, PRUint32 aLength,
nscoord aX, nscoord aY,
PRInt32 aFontID,
- const nscoord* aSpacing,
- nsRenderingContextGTK *aContext,
- nsDrawingSurfaceGTK *aSurface);
+ const nscoord* aSpacing
+ CONTEXT_AND_SURFACE_ARG_DEF);
#ifdef MOZ_MATHML
- virtual nsresult GetBoundingMetrics(const char *aString, PRUint32 aLength,
- nsBoundingMetrics &aBoundingMetrics,
- nsRenderingContextGTK *aContext);
- virtual nsresult GetBoundingMetrics(const PRUnichar *aString,
+ NS_METHOD GetBoundingMetrics(const char *aString, PRUint32 aLength,
+ nsBoundingMetrics &aBoundingMetrics
+ CONTEXT_ARG_DEF);
+ NS_METHOD GetBoundingMetrics(const PRUnichar *aString,
PRUint32 aLength,
nsBoundingMetrics &aBoundingMetrics,
- PRInt32 *aFontID,
- nsRenderingContextGTK *aContext);
+ PRInt32 *aFontID
+ CONTEXT_ARG_DEF);
#endif /* MOZ_MATHML */
-
+#ifndef PSPANGO
virtual GdkFont* GetCurrentGDKFont(void);
-
- virtual nsresult SetRightToLeftText(PRBool aIsRTL);
+#endif
virtual PRBool GetRightToLeftText();
-
- virtual nsresult GetClusterInfo(const PRUnichar *aText,
+ NS_METHOD SetRightToLeftText(PRBool aIsRTL);
+
+ NS_METHOD GetClusterInfo(const PRUnichar *aText,
PRUint32 aLength,
PRUint8 *aClusterStarts);
@@ -206,32 +251,35 @@ public:
PRUint32 aLength,
nsPoint aPt);
- virtual nsresult GetRangeWidth(const PRUnichar *aText,
+ NS_METHOD GetRangeWidth(const PRUnichar *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth);
- virtual nsresult GetRangeWidth(const char *aText,
+ NS_METHOD GetRangeWidth(const char *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth);
// get hints for the font
- static PRUint32 GetHints (void);
+#ifndef PSPANGO
+ static
+#endif
+ PRUint32 GetHints (void);
// drawing surface methods
static nsresult FamilyExists (nsIDeviceContext *aDevice,
const nsString &aName);
+
private:
// generic font metrics class bits
nsCStringArray mFontList;
nsAutoVoidArray mFontIsGeneric;
- nsIDeviceContext *mDeviceContext;
nsCOMPtr<nsIAtom> mLangGroup;
nsCString *mGenericFont;
float mPointSize;
@@ -246,6 +294,9 @@ private:
PangoAttrList *mPangoAttrList;
PRBool mIsRTL;
+#ifndef PSPANGO
+ nsIDeviceContext *mDeviceContext;
+
// Cached font metrics
nscoord mXHeight;
nscoord mSuperscriptOffset;
@@ -263,6 +314,7 @@ private:
nscoord mMaxDescent;
nscoord mMaxAdvance;
nscoord mSpaceWidth;
+#endif
nscoord mPangoSpaceWidth;
nscoord mAveCharWidth;
PRInt32 mMaxStringLength;
@@ -274,13 +326,14 @@ private:
static PRBool EnumFontCallback(const nsString &aFamily,
PRBool aIsGeneric, void *aData);
- void DrawStringSlowly(const gchar *aText,
- const PRUnichar *aOrigString,
- PRUint32 aLength,
- GdkDrawable *aDrawable,
- GdkGC *aGC, gint aX, gint aY,
- PangoLayoutLine *aLine,
- const nscoord *aSpacing);
+ void ApplySpacing(const gchar *aText,
+ PRUint32 aLength,
+ PangoLayoutLine *aLine,
+ const nscoord *aSpacing);
+ void ApplySpacing(const PRUnichar *aText,
+ PRUint32 aLength,
+ PangoLayoutLine *aLine,
+ const nscoord *aSpacing);
nsresult GetTextDimensionsInternal(const gchar* aString,
PRInt32 aLength,
@@ -289,10 +342,20 @@ private:
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
- nsTextDimensions& aLastWordDimensions,
- nsRenderingContextGTK *aContext);
+ nsTextDimensions& aLastWordDimensions
+ CONTEXT_ARG_DEF);
+#ifdef MOZ_MATHML
+ void GetBoundingMetricsInternal(PangoLayout *aLayout,
+ nsBoundingMetrics &aBoundingMetrics
+ CONTEXT_ARG_DEF);
+#endif /* MOZ_MATHML */
+
+ void FixupSpaceWidths (PangoLayout *aLayout);
- void FixupSpaceWidths (PangoLayout *aLayout, const char *aString);
+ PangoLayout* GetLayout (const PRUnichar* aText,
+ PRUint32 aLength);
+ PangoLayout* GetLayout (const gchar* aText,
+ PRInt32 aLength);
};
class nsFontEnumeratorPango : public nsIFontEnumerator