diff --git a/firefox-2.0-pango-ligatures.patch b/firefox-2.0-pango-ligatures.patch new file mode 100644 index 0000000..c259488 --- /dev/null +++ b/firefox-2.0-pango-ligatures.patch @@ -0,0 +1,1932 @@ +--- 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 ++ * Behdad Esfahbod + * + * 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 + #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 ++#include ++ ++#include ++#include ++ ++#ifdef PSPANGO ++#include ++#include "nsRenderingContextPS.h" ++#include "nsDeviceContextPS.h" ++#include "nsType1.h" ++#else + #include + #include +-#include ++#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 + +-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 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 diff --git a/thunderbird.spec b/thunderbird.spec index e8bdbef..5444cf2 100644 --- a/thunderbird.spec +++ b/thunderbird.spec @@ -8,7 +8,7 @@ Summary: Mozilla Thunderbird mail/newsgroup client Name: thunderbird Version: 2.0.0.0 -Release: 1%{?dist} +Release: 2%{?dist} URL: http://www.mozilla.org/projects/thunderbird/ License: MPL Group: Applications/Internet @@ -55,6 +55,7 @@ Patch85: firefox-1.5-pango-cursor-position-more.patch Patch86: firefox-1.5-pango-justified-range.patch Patch87: firefox-1.5-pango-underline.patch Patch88: firefox-1.5-xft-rangewidth.patch +Patch89: firefox-2.0-pango-ligatures.patch # Other Patch102: firefox-1.5-theme-change.patch @@ -127,6 +128,7 @@ Mozilla Thunderbird is a standalone mail and newsgroup client. %patch86 -p1 -b .pango-justified-range %patch87 -p1 -b .pango-underline %patch88 -p1 -b .nopangoxft2 +%patch89 -p1 -b .ligatures pushd gfx/src/ps # This sort of sucks, but it works for now. ln -s ../gtk/nsFontMetricsPango.h . @@ -309,6 +311,9 @@ update-desktop-database %{_datadir}/applications #=============================================================================== %changelog +* Tue Jul 31 2007 Martin Stransky 2.0.0.0-2 +- added pango ligature fix + * Thu Apr 19 2007 Christopher Aillon 2.0.0.0-1 - Update to 2.0.0.0 Final