# HG changeset patch # User YAMAMOTO Mitsuharu # Date 1135239430 0 # Node ID 330ac31a0c823aad2071402f4677bb8a96e47aef # Parent caacdc1a999e0db21005c6f7fcbda36a283ec6e5 (mac_per_char_metric): Add prototype. (x_per_char_metric) [USE_CG_TEXT_DRAWING]: Remove prototype. (mac_query_char_extents): New function. (x_per_char_metric): Use it. (XLoadQueryFont): Likewise. Consolidate min/max_bounds calculations. [USE_CG_TEXT_DRAWING] (mac_draw_string_cg): Use mac_per_char_metric instead of x_per_char_metric. (mac_text_extents_16): New function. (mac_compute_glyph_string_overhangs): Use it. (mac_unload_font): Free member `bounds' in struct MacFontStruct. diff -r caacdc1a999e -r 330ac31a0c82 src/macterm.c --- a/src/macterm.c Thu Dec 22 08:17:01 2005 +0000 +++ b/src/macterm.c Thu Dec 22 08:17:10 2005 +0000 @@ -259,7 +259,7 @@ unsigned long *)); static int is_emacs_window P_ ((WindowPtr)); - +static XCharStruct *mac_per_char_metric P_ ((XFontStruct *, XChar2b *, int)); static void XSetFont P_ ((Display *, GC, XFontStruct *)); /* Defined in macmenu.h. */ @@ -868,9 +868,159 @@ } +/* Mac replacement for XQueryTextExtents, but takes a character. If + STYLE is NULL, measurement is done by QuickDraw Text routines for + the font of the current graphics port. If CG_GLYPH is not NULL, + *CG_GLYPH is set to the glyph ID or 0 if it cannot be obtained. */ + +static OSErr +mac_query_char_extents (style, c, + font_ascent_return, font_descent_return, + overall_return, cg_glyph) +#if USE_ATSUI + ATSUStyle style; +#else + void *style; +#endif + int c; + int *font_ascent_return, *font_descent_return; + XCharStruct *overall_return; #if USE_CG_TEXT_DRAWING -static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *)); - + CGGlyph *cg_glyph; +#else + void *cg_glyph; +#endif +{ + OSErr err = noErr; + int width; + Rect char_bounds; + +#if USE_ATSUI + if (style) + { + ATSUTextLayout text_layout; + UniChar ch = c; + + err = atsu_get_text_layout_with_text_ptr (&ch, 1, style, &text_layout); + if (err == noErr) + { + ATSTrapezoid glyph_bounds; + + err = ATSUGetGlyphBounds (text_layout, 0, 0, + kATSUFromTextBeginning, kATSUToTextEnd, +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 + kATSUseFractionalOrigins, +#else + kATSUseDeviceOrigins, +#endif + 1, &glyph_bounds, NULL); + if (err == noErr) + { + xassert (glyph_bounds.lowerRight.x - glyph_bounds.lowerLeft.x + == glyph_bounds.upperRight.x - glyph_bounds.upperLeft.x); + + width = Fix2Long (glyph_bounds.upperRight.x + - glyph_bounds.upperLeft.x); + if (font_ascent_return) + *font_ascent_return = -Fix2Long (glyph_bounds.upperLeft.y); + if (font_descent_return) + *font_descent_return = Fix2Long (glyph_bounds.lowerLeft.y); + } + } + if (err == noErr && overall_return) + { + err = ATSUMeasureTextImage (text_layout, + kATSUFromTextBeginning, kATSUToTextEnd, + 0, 0, &char_bounds); + if (err == noErr) + STORE_XCHARSTRUCT (*overall_return, width, char_bounds); +#if USE_CG_TEXT_DRAWING + if (err == noErr && cg_glyph) + { + OSErr err1; + ATSUGlyphInfoArray glyph_info_array; + ByteCount count = sizeof (ATSUGlyphInfoArray); + + err1 = ATSUMatchFontsToText (text_layout, kATSUFromTextBeginning, + kATSUToTextEnd, NULL, NULL, NULL); + if (err1 == noErr) + err1 = ATSUGetGlyphInfo (text_layout, kATSUFromTextBeginning, + kATSUToTextEnd, &count, + &glyph_info_array); + if (err1 == noErr) + { + xassert (glyph_info_array.glyphs[0].glyphID); + *cg_glyph = glyph_info_array.glyphs[0].glyphID; + } + else + *cg_glyph = 0; + } +#endif + } + } + else +#endif + { + if (font_ascent_return || font_descent_return) + { + FontInfo font_info; + + GetFontInfo (&font_info); + if (font_ascent_return) + *font_ascent_return = font_info.ascent; + if (font_descent_return) + *font_descent_return = font_info.descent; + } + if (overall_return) + { + char ch = c; + + width = CharWidth (ch); + QDTextBounds (1, &ch, &char_bounds); + STORE_XCHARSTRUCT (*overall_return, width, char_bounds); + } + } + + return err; +} + + +/* Mac replacement for XTextExtents16. Only sets horizontal metrics. */ + +static int +mac_text_extents_16 (font_struct, string, nchars, overall_return) + XFontStruct *font_struct; + XChar2b *string; + int nchars; + XCharStruct *overall_return; +{ + int i; + short width = 0, lbearing = 0, rbearing = 0; + XCharStruct *pcm; + + for (i = 0; i < nchars; i++) + { + pcm = mac_per_char_metric (font_struct, string, 0); + if (pcm == NULL) + width += FONT_WIDTH (font_struct); + else + { + lbearing = min (lbearing, width + pcm->lbearing); + rbearing = max (rbearing, width + pcm->rbearing); + width += pcm->width; + } + string++; + } + + overall_return->lbearing = lbearing; + overall_return->rbearing = rbearing; + overall_return->width = width; + + /* What's the meaning of the return value of XTextExtents16? */ +} + + +#if USE_CG_TEXT_DRAWING static int cg_text_anti_aliasing_threshold = 8; static void @@ -910,7 +1060,9 @@ advances = xmalloc (sizeof (CGSize) * nchars); for (i = 0; i < nchars; i++) { - advances[i].width = x_per_char_metric (GC_FONT (gc), buf)->width; + XCharStruct *pcm = mac_per_char_metric (GC_FONT (gc), buf, 0); + + advances[i].width = pcm->width; advances[i].height = 0; glyphs[i] = GC_FONT (gc)->cg_glyphs[buf->byte2]; buf++; @@ -1724,63 +1876,32 @@ #if USE_ATSUI if (font->mac_style) { - if (char2b->byte1 >= font->min_byte1 - && char2b->byte1 <= font->max_byte1 - && char2b->byte2 >= font->min_char_or_byte2 - && char2b->byte2 <= font->max_char_or_byte2) + XCharStructRow **row = font->bounds.rows + char2b->byte1; + + if (*row == NULL) { - pcm = (font->per_char - + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1) - * (char2b->byte1 - font->min_byte1)) - + (char2b->byte2 - font->min_char_or_byte2)); + *row = xmalloc (sizeof (XCharStructRow)); + if (*row) + bzero (*row, sizeof (XCharStructRow)); } - - if (pcm && !pcm->valid_p) + if (*row) { - OSErr err; - ATSUTextLayout text_layout; - UniChar c; - int char_width; - ATSTrapezoid glyph_bounds; - Rect char_bounds; - - c = (char2b->byte1 << 8) + char2b->byte2; - BLOCK_INPUT; - err = atsu_get_text_layout_with_text_ptr (&c, 1, - font->mac_style, - &text_layout); - if (err == noErr) - err = ATSUMeasureTextImage (text_layout, - kATSUFromTextBeginning, kATSUToTextEnd, - 0, 0, &char_bounds); - - if (err == noErr) - err = ATSUGetGlyphBounds (text_layout, 0, 0, - kATSUFromTextBeginning, kATSUToTextEnd, -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 - kATSUseFractionalOrigins, -#else - kATSUseDeviceOrigins, -#endif - 1, &glyph_bounds, NULL); - UNBLOCK_INPUT; - if (err != noErr) - pcm = NULL; - else + pcm = (*row)->per_char + char2b->byte2; + if (!XCHARSTRUCTROW_CHAR_VALID_P (*row, char2b->byte2)) { - xassert (glyph_bounds.lowerRight.x - glyph_bounds.lowerLeft.x - == glyph_bounds.upperRight.x - glyph_bounds.upperLeft.x); - - char_width = Fix2Long (glyph_bounds.upperRight.x - - glyph_bounds.upperLeft.x); - STORE_XCHARSTRUCT (*pcm, char_width, char_bounds); + BLOCK_INPUT; + mac_query_char_extents (font->mac_style, + (char2b->byte1 << 8) + char2b->byte2, + NULL, NULL, pcm, NULL); + UNBLOCK_INPUT; + XCHARSTRUCTROW_SET_CHAR_VALID (*row, char2b->byte2); } } } else { #endif - if (font->per_char != NULL) + if (font->bounds.per_char != NULL) { if (font->min_byte1 == 0 && font->max_byte1 == 0) { @@ -1793,7 +1914,8 @@ if (char2b->byte1 == 0 && char2b->byte2 >= font->min_char_or_byte2 && char2b->byte2 <= font->max_char_or_byte2) - pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2; + pcm = font->bounds.per_char + + (char2b->byte2 - font->min_char_or_byte2); } else { @@ -1815,7 +1937,7 @@ && char2b->byte2 >= font->min_char_or_byte2 && char2b->byte2 <= font->max_char_or_byte2) { - pcm = (font->per_char + pcm = (font->bounds.per_char + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1) * (char2b->byte1 - font->min_byte1)) + (char2b->byte2 - font->min_char_or_byte2)); @@ -2157,67 +2279,32 @@ { if (s->cmp == NULL && s->first_glyph->type == CHAR_GLYPH) - { - Rect r; - MacFontStruct *font = s->font; - + if (!s->two_byte_p #if USE_ATSUI - if (font->mac_style) - { - OSErr err; - ATSUTextLayout text_layout; - UniChar *buf; - int i; - - SetRect (&r, 0, 0, 0, 0); - buf = xmalloc (sizeof (UniChar) * s->nchars); - if (buf) - { - for (i = 0; i < s->nchars; i++) - buf[i] = (s->char2b[i].byte1 << 8) + s->char2b[i].byte2; - - err = atsu_get_text_layout_with_text_ptr (buf, s->nchars, - font->mac_style, - &text_layout); - if (err == noErr) - err = ATSUMeasureTextImage (text_layout, - kATSUFromTextBeginning, - kATSUToTextEnd, - 0, 0, &r); - xfree (buf); - } - } - else - { -#endif - TextFont (font->mac_fontnum); - TextSize (font->mac_fontsize); - TextFace (font->mac_fontface); - - if (s->two_byte_p) + || s->font->mac_style +#endif + ) + { + XCharStruct cs; + + mac_text_extents_16 (s->font, s->char2b, s->nchars, &cs); + s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0; + s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0; + } + else + { + Rect r; + MacFontStruct *font = s->font; + + TextFont (font->mac_fontnum); + TextSize (font->mac_fontsize); + TextFace (font->mac_fontface); + QDTextBounds (s->nchars * 2, (char *)s->char2b, &r); - else - { - int i; - char *buf = xmalloc (s->nchars); - - if (buf == NULL) - SetRect (&r, 0, 0, 0, 0); - else - { - for (i = 0; i < s->nchars; ++i) - buf[i] = s->char2b[i].byte2; - QDTextBounds (s->nchars, buf, &r); - xfree (buf); - } - } -#if USE_ATSUI - } -#endif - - s->right_overhang = r.right > s->width ? r.right - s->width : 0; - s->left_overhang = r.left < 0 ? -r.left : 0; - } + + s->right_overhang = r.right > s->width ? r.right - s->width : 0; + s->left_overhang = r.left < 0 ? -r.left : 0; + } } @@ -7375,7 +7462,7 @@ static MacFontStruct * XLoadQueryFont (Display *dpy, char *fontname) { - int i, size, char_width; + int size; char *name; Str255 family; Str31 charset; @@ -7392,6 +7479,7 @@ short scriptcode; #endif MacFontStruct *font; + XCharStruct *space_bounds = NULL, *pcm; if (is_fully_specified_xlfd (fontname)) name = fontname; @@ -7488,19 +7576,27 @@ if (font->mac_style) { OSErr err; - ATSUTextLayout text_layout; - UniChar c = 0x20; - Rect char_bounds, min_bounds, max_bounds; - int min_width, max_width; - ATSTrapezoid glyph_bounds; - - font->per_char = xmalloc (sizeof (XCharStruct) * 0x10000); - if (font->per_char == NULL) + UniChar c; + + font->min_byte1 = 0; + font->max_byte1 = 0xff; + font->min_char_or_byte2 = 0; + font->max_char_or_byte2 = 0xff; + + font->bounds.rows = xmalloc (sizeof (XCharStructRow *) * 0x100); + if (font->bounds.rows == NULL) { mac_unload_font (&one_mac_display_info, font); return NULL; } - bzero (font->per_char, sizeof (XCharStruct) * 0x10000); + bzero (font->bounds.rows, sizeof (XCharStructRow *) * 0x100); + font->bounds.rows[0] = xmalloc (sizeof (XCharStructRow)); + if (font->bounds.rows[0] == NULL) + { + mac_unload_font (&one_mac_display_info, font); + return NULL; + } + bzero (font->bounds.rows[0], sizeof (XCharStructRow)); #if USE_CG_TEXT_DRAWING { @@ -7525,108 +7621,58 @@ if (font->cg_glyphs) bzero (font->cg_glyphs, sizeof (CGGlyph) * 0x100); #endif - - err = atsu_get_text_layout_with_text_ptr (&c, 1, - font->mac_style, - &text_layout); + space_bounds = font->bounds.rows[0]->per_char + 0x20; + err = mac_query_char_extents (font->mac_style, 0x20, + &font->ascent, &font->descent, + space_bounds, +#if USE_CG_TEXT_DRAWING + (font->cg_glyphs ? font->cg_glyphs + 0x20 + : NULL) +#else + NULL +#endif + ); if (err != noErr) { mac_unload_font (&one_mac_display_info, font); return NULL; } - - for (c = 0x20; c <= 0xff; c++) + XCHARSTRUCTROW_SET_CHAR_VALID (font->bounds.rows[0], 0x20); + + pcm = font->bounds.rows[0]->per_char; + for (c = 0x21; c <= 0xff; c++) { if (c == 0xad) /* Soft hyphen is not supported in ATSUI. */ continue; else if (c == 0x7f) { - STORE_XCHARSTRUCT (font->min_bounds, min_width, min_bounds); - STORE_XCHARSTRUCT (font->max_bounds, max_width, max_bounds); c = 0x9f; continue; } - err = ATSUClearLayoutCache (text_layout, kATSUFromTextBeginning); - if (err == noErr) - err = ATSUMeasureTextImage (text_layout, - kATSUFromTextBeginning, kATSUToTextEnd, - 0, 0, &char_bounds); - if (err == noErr) - err = ATSUGetGlyphBounds (text_layout, 0, 0, - kATSUFromTextBeginning, kATSUToTextEnd, -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 - kATSUseFractionalOrigins, + mac_query_char_extents (font->mac_style, c, NULL, NULL, pcm + c, +#if USE_CG_TEXT_DRAWING + (font->cg_glyphs ? font->cg_glyphs + c + : NULL) #else - kATSUseDeviceOrigins, -#endif - 1, &glyph_bounds, NULL); - if (err == noErr) + NULL +#endif + ); + XCHARSTRUCTROW_SET_CHAR_VALID (font->bounds.rows[0], c); + +#if USE_CG_TEXT_DRAWING + if (font->cg_glyphs && font->cg_glyphs[c] == 0) { - xassert (glyph_bounds.lowerRight.x - glyph_bounds.lowerLeft.x - == glyph_bounds.upperRight.x - glyph_bounds.upperLeft.x); - - char_width = Fix2Long (glyph_bounds.upperRight.x - - glyph_bounds.upperLeft.x); - STORE_XCHARSTRUCT (font->per_char[c], - char_width, char_bounds); - if (c == 0x20) - { - min_width = max_width = char_width; - min_bounds = max_bounds = char_bounds; - font->ascent = -Fix2Long (glyph_bounds.upperLeft.y); - font->descent = Fix2Long (glyph_bounds.lowerLeft.y); - } - else - { - if (char_width > 0) - { - min_width = min (min_width, char_width); - max_width = max (max_width, char_width); - } - if (!EmptyRect (&char_bounds)) - { - SetRect (&min_bounds, - max (min_bounds.left, char_bounds.left), - max (min_bounds.top, char_bounds.top), - min (min_bounds.right, char_bounds.right), - min (min_bounds.bottom, char_bounds.bottom)); - UnionRect (&max_bounds, &char_bounds, &max_bounds); - } - } - } -#if USE_CG_TEXT_DRAWING - if (err == noErr && char_width > 0 && font->cg_font) - { - ATSUGlyphInfoArray glyph_info_array; - ByteCount count = sizeof (ATSUGlyphInfoArray); - - err = ATSUMatchFontsToText (text_layout, kATSUFromTextBeginning, - kATSUToTextEnd, NULL, NULL, NULL); - if (err == noErr) - err = ATSUGetGlyphInfo (text_layout, kATSUFromTextBeginning, - kATSUToTextEnd, &count, - &glyph_info_array); - if (err == noErr) - font->cg_glyphs[c] = glyph_info_array.glyphs[0].glyphID; - else - { - /* Don't use CG text drawing if font substitution - occurs in ASCII or Latin-1 characters. */ - CGFontRelease (font->cg_font); - font->cg_font = NULL; - xfree (font->cg_glyphs); - font->cg_glyphs = NULL; - } + /* Don't use CG text drawing if font substitution occurs in + ASCII or Latin-1 characters. */ + CGFontRelease (font->cg_font); + font->cg_font = NULL; + xfree (font->cg_glyphs); + font->cg_glyphs = NULL; } #endif } - - font->min_byte1 = 0; - font->max_byte1 = 0xff; - font->min_char_or_byte2 = 0; - font->max_char_or_byte2 = 0xff; } else #endif @@ -7665,6 +7711,8 @@ if (is_two_byte_font) { + int char_width; + font->min_byte1 = 0xa1; font->max_byte1 = 0xfe; font->min_char_or_byte2 = 0xa1; @@ -7693,21 +7741,8 @@ char_width = StringWidth("\p\xa1\xa1"); break; } - } - else - { - font->min_byte1 = font->max_byte1 = 0; - font->min_char_or_byte2 = 0x20; - font->max_char_or_byte2 = 0xff; - - /* Do this instead of use the_fontinfo.widMax, which - incorrectly returns 15 for 12-point Monaco! */ - char_width = CharWidth ('m'); - } - - if (is_two_byte_font) - { - font->per_char = NULL; + + font->bounds.per_char = NULL; if (fontface & italic) font->max_bounds.rbearing = char_width + 1; @@ -7722,54 +7757,28 @@ } else { - int c, min_width, max_width; - Rect char_bounds, min_bounds, max_bounds; - char ch; - - font->per_char = xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1)); - bzero (font->per_char, sizeof (XCharStruct) * (0xff - 0x20 + 1)); - - min_width = max_width = char_width; - SetRect (&min_bounds, -32767, -32767, 32767, 32767); - SetRect (&max_bounds, 0, 0, 0, 0); - for (c = 0x20; c <= 0xff; c++) + int c; + + font->min_byte1 = font->max_byte1 = 0; + font->min_char_or_byte2 = 0x20; + font->max_char_or_byte2 = 0xff; + + font->bounds.per_char = + xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1)); + if (font->bounds.per_char == NULL) { - if (c == 0x7f) - { - STORE_XCHARSTRUCT (font->min_bounds, min_width, min_bounds); - STORE_XCHARSTRUCT (font->max_bounds, max_width, max_bounds); - continue; - } - - ch = c; - char_width = CharWidth (ch); - QDTextBounds (1, &ch, &char_bounds); - STORE_XCHARSTRUCT (font->per_char[c - 0x20], - char_width, char_bounds); - /* Some Japanese fonts (in SJIS encoding) return 0 as - the character width of 0x7f. */ - if (char_width > 0) - { - min_width = min (min_width, char_width); - max_width = max (max_width, char_width); - } - if (!EmptyRect (&char_bounds)) - { - SetRect (&min_bounds, - max (min_bounds.left, char_bounds.left), - max (min_bounds.top, char_bounds.top), - min (min_bounds.right, char_bounds.right), - min (min_bounds.bottom, char_bounds.bottom)); - UnionRect (&max_bounds, &char_bounds, &max_bounds); - } + mac_unload_font (&one_mac_display_info, font); + return NULL; } - if (min_width == max_width - && max_bounds.left >= 0 && max_bounds.right <= max_width) - { - /* Fixed width and no overhangs. */ - xfree (font->per_char); - font->per_char = NULL; - } + bzero (font->bounds.per_char, + sizeof (XCharStruct) * (0xff - 0x20 + 1)); + + space_bounds = font->bounds.per_char; + mac_query_char_extents (NULL, 0x20, &font->ascent, &font->descent, + space_bounds, NULL); + + for (c = 0x21, pcm = space_bounds + 1; c <= 0xff; c++, pcm++) + mac_query_char_extents (NULL, c, NULL, NULL, pcm, NULL); } /* Restore previous font number, size and face. */ @@ -7778,6 +7787,46 @@ TextFace (old_fontface); } + if (space_bounds) + { + int c; + + font->min_bounds = font->max_bounds = *space_bounds; + for (c = 0x21, pcm = space_bounds + 1; c <= 0x7f; c++, pcm++) + if (pcm->width > 0) + { + font->min_bounds.lbearing = min (font->min_bounds.lbearing, + pcm->lbearing); + font->min_bounds.rbearing = min (font->min_bounds.rbearing, + pcm->rbearing); + font->min_bounds.width = min (font->min_bounds.width, + pcm->width); + font->min_bounds.ascent = min (font->min_bounds.ascent, + pcm->ascent); + + font->max_bounds.lbearing = max (font->max_bounds.lbearing, + pcm->lbearing); + font->max_bounds.rbearing = max (font->max_bounds.rbearing, + pcm->rbearing); + font->max_bounds.width = max (font->max_bounds.width, + pcm->width); + font->max_bounds.ascent = max (font->max_bounds.ascent, + pcm->ascent); + } + if ( +#if USE_ATSUI + font->mac_style == NULL && +#endif + font->max_bounds.width == font->min_bounds.width + && font->min_bounds.lbearing >= 0 + && font->max_bounds.rbearing <= font->max_bounds.width) + { + /* Fixed width and no overhangs. */ + xfree (font->bounds.per_char); + font->bounds.per_char = NULL; + } + } + #if !defined (MAC_OS8) || USE_ATSUI /* AppKit and WebKit do some adjustment to the heights of Courier, Helvetica, and Times. This only works on the environments where @@ -7797,18 +7846,27 @@ XFontStruct *font; { xfree (font->full_name); - if (font->per_char) - xfree (font->per_char); #if USE_ATSUI if (font->mac_style) - ATSUDisposeStyle (font->mac_style); + { + int i; + + for (i = font->min_byte1; i <= font->max_byte1; i++) + if (font->bounds.rows[i]) + xfree (font->bounds.rows[i]); + xfree (font->bounds.rows); + ATSUDisposeStyle (font->mac_style); + } + else +#endif + if (font->bounds.per_char) + xfree (font->bounds.per_char); #if USE_CG_TEXT_DRAWING if (font->cg_font) CGFontRelease (font->cg_font); if (font->cg_glyphs) xfree (font->cg_glyphs); #endif -#endif xfree (font); }