aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJason Rumney <[email protected]>2008-04-08 13:52:21 +0000
committerJason Rumney <[email protected]>2008-04-08 13:52:21 +0000
commit8f112d5210cf530f35c77172a4d44e12703be53a (patch)
treebf96336df00c4cd672cfbb8e78e960f146b37d1b /src
parent20e3d3f1cad9f6b6c69f04fb613a5d2ad2232566 (diff)
(Qja, Qko, Qzh): New symbols.
(syms_of_w32font): Initialise them. (font_matches_spec): Use them to filter by language. (recompute_cached_metrics): Remove function. (compute_metrics, clear_cached_metrics): New functions. (w32font_encode_char): Use them to manage metric cache. (w32font_text_extents): Cache metrics for all glyphs on demand. Delay converting glyph indices to WORD until needed. (w32font_open_internal): Initialize metric cache to empty. (registry_to_w32_charset): Charset should always be a symbol. (fill_in_logfont, list_all_matching_fonts): Family should always be a symbol.
Diffstat (limited to 'src')
-rw-r--r--src/w32font.c285
1 files changed, 168 insertions, 117 deletions
diff --git a/src/w32font.c b/src/w32font.c
index 866b86e228..6bd0376810 100644
--- a/src/w32font.c
+++ b/src/w32font.c
@@ -59,6 +59,9 @@ extern Lisp_Object QCantialias, QCotf, QClanguage; /* defined in font.c */
extern Lisp_Object Qnone; /* reuse from w32fns.c */
static Lisp_Object Qstandard, Qsubpixel, Qnatural;
+/* languages */
+static Lisp_Object Qja, Qko, Qzh;
+
/* scripts */
static Lisp_Object Qlatin, Qgreek, Qcoptic, Qcyrillic, Qarmenian, Qhebrew;
static Lisp_Object Qarabic, Qsyriac, Qnko, Qthaana, Qdevanagari, Qbengali;
@@ -82,18 +85,18 @@ static Lisp_Object Qphonetic;
/* Font spacing symbols - defined in font.c. */
extern Lisp_Object Qc, Qp, Qm;
-static void fill_in_logfont P_ ((FRAME_PTR f, LOGFONT *logfont,
- Lisp_Object font_spec));
+static void fill_in_logfont P_ ((FRAME_PTR, LOGFONT *, Lisp_Object));
-static BYTE w32_antialias_type P_ ((Lisp_Object type));
-static Lisp_Object lispy_antialias_type P_ ((BYTE type));
+static BYTE w32_antialias_type P_ ((Lisp_Object));
+static Lisp_Object lispy_antialias_type P_ ((BYTE));
-static Lisp_Object font_supported_scripts P_ ((FONTSIGNATURE * sig));
-static int w32font_full_name P_ ((LOGFONT * font, Lisp_Object font_obj,
- int pixel_size, char *name, int nbytes));
-static void recompute_cached_metrics P_ ((HDC dc, struct w32font_info * font));
+static Lisp_Object font_supported_scripts P_ ((FONTSIGNATURE *));
+static int w32font_full_name P_ ((LOGFONT *, Lisp_Object, int, char *, int));
+static void compute_metrics P_ ((HDC, struct w32font_info *, unsigned int,
+ struct w32_metric_cache *));
+static void clear_cached_metrics P_ ((struct w32font_info *));
-static Lisp_Object w32_registry P_ ((LONG w32_charset, DWORD font_type));
+static Lisp_Object w32_registry P_ ((LONG, DWORD));
/* EnumFontFamiliesEx callbacks. */
static int CALLBACK add_font_entity_to_list P_ ((ENUMLOGFONTEX *,
@@ -126,10 +129,10 @@ struct font_callback_data
/* Handles the problem that EnumFontFamiliesEx will not return all
style variations if the font name is not specified. */
-static void list_all_matching_fonts P_ ((struct font_callback_data *match));
+static void list_all_matching_fonts P_ ((struct font_callback_data *));
/* From old font code in w32fns.c */
-char * w32_to_x_charset P_ ((int charset, char * matching));
+char * w32_to_x_charset P_ ((int, char *));
static int
@@ -336,7 +339,8 @@ w32font_encode_char (font, c)
/* Mark this font as not supporting glyph indices. This can happen
on Windows9x, and maybe with non-Truetype fonts on NT etc. */
w32_font->glyph_idx = 0;
- recompute_cached_metrics (dc, w32_font);
+ /* Clear metrics cache. */
+ clear_cached_metrics (w32_font);
return c;
}
@@ -359,24 +363,13 @@ w32font_text_extents (font, code, nglyphs, metrics)
HDC dc = NULL;
struct frame * f;
int total_width = 0;
- WORD *wcode = alloca(nglyphs * sizeof (WORD));
+ WORD *wcode = NULL;
SIZE size;
- /* TODO: Frames can come and go, and their fonts outlive them. So we
- can't cache the frame in the font structure. Use selected_frame
- until the API is updated to pass in a frame. */
- f = XFRAME (selected_frame);
-
if (metrics)
{
- GLYPHMETRICS gm;
- MAT2 transform;
struct w32font_info *w32_font = (struct w32font_info *) font;
- /* Set transform to the identity matrix. */
- bzero (&transform, sizeof (transform));
- transform.eM11.value = 1;
- transform.eM22.value = 1;
metrics->width = 0;
metrics->ascent = font->ascent;
metrics->descent = font->descent;
@@ -384,65 +377,67 @@ w32font_text_extents (font, code, nglyphs, metrics)
for (i = 0; i < nglyphs; i++)
{
- if (*(code + i) < 128)
- {
- /* Use cached metrics for ASCII. */
- struct font_metrics *char_metric
- = &w32_font->ascii_metrics[*(code+i)];
-
- /* If we couldn't get metrics when caching, use fallback. */
- if (char_metric->width == 0)
- break;
-
- metrics->lbearing = min (metrics->lbearing,
- metrics->width + char_metric->lbearing);
- metrics->rbearing = max (metrics->rbearing,
- metrics->width + char_metric->rbearing);
- metrics->width += char_metric->width;
- }
- else
- {
- if (dc == NULL)
- {
+ struct w32_metric_cache *char_metric;
+ int block = *(code + i) / CACHE_BLOCKSIZE;
+ int pos_in_block = *(code + i) % CACHE_BLOCKSIZE;
+
+ if (block >= w32_font->n_cache_blocks)
+ {
+ if (!w32_font->cached_metrics)
+ w32_font->cached_metrics
+ = xmalloc ((block + 1)
+ * sizeof (struct w32_cached_metric *));
+ else
+ w32_font->cached_metrics
+ = xrealloc (w32_font->cached_metrics,
+ (block + 1)
+ * sizeof (struct w32_cached_metric *));
+ bzero (w32_font->cached_metrics + w32_font->n_cache_blocks,
+ ((block + 1 - w32_font->n_cache_blocks)
+ * sizeof (struct w32_cached_metric *)));
+ w32_font->n_cache_blocks = block + 1;
+ }
+
+ if (!w32_font->cached_metrics[block])
+ {
+ w32_font->cached_metrics[block]
+ = xmalloc (CACHE_BLOCKSIZE * sizeof (struct font_metrics));
+ bzero (w32_font->cached_metrics[block],
+ CACHE_BLOCKSIZE * sizeof (struct font_metrics));
+ }
+
+ char_metric = w32_font->cached_metrics[block] + pos_in_block;
+
+ if (char_metric->status == W32METRIC_NO_ATTEMPT)
+ {
+ if (dc == NULL)
+ {
+ /* TODO: Frames can come and go, and their fonts
+ outlive them. So we can't cache the frame in the
+ font structure. Use selected_frame until the API
+ is updated to pass in a frame. */
+ f = XFRAME (selected_frame);
+
dc = get_frame_dc (f);
old_font = SelectObject (dc, ((W32FontStruct *)
(font->font.font))->hfont);
- }
- if (GetGlyphOutlineW (dc, *(code + i),
- GGO_METRICS
- | w32_font->glyph_idx
- ? GGO_GLYPH_INDEX : 0,
- &gm, 0, NULL, &transform) != GDI_ERROR)
- {
- int new_val = metrics->width + gm.gmBlackBoxX
- + gm.gmptGlyphOrigin.x;
- metrics->rbearing = max (metrics->rbearing, new_val);
- new_val = metrics->width + gm.gmptGlyphOrigin.x;
- metrics->lbearing = min (metrics->lbearing, new_val);
- metrics->width += gm.gmCellIncX;
- }
- else
- {
- if (w32_font->glyph_idx)
- {
- /* Disable glyph indexing for this font, as we can't
- handle the metrics. Abort this run, our recovery
- strategies rely on having unicode code points here.
- This will cause a glitch in display, but in practice,
- any problems should be caught when initialising the
- metrics cache. */
- w32_font->glyph_idx = 0;
- recompute_cached_metrics (dc, w32_font);
- SelectObject (dc, old_font);
- release_frame_dc (f, dc);
- return 0;
- }
- /* Rely on an estimate based on the overall font metrics. */
- break;
- }
- }
- }
+ }
+ compute_metrics (dc, w32_font, *(code + i), char_metric);
+ }
+ if (char_metric->status == W32METRIC_SUCCESS)
+ {
+ metrics->lbearing = min (metrics->lbearing,
+ metrics->width + char_metric->lbearing);
+ metrics->rbearing = max (metrics->rbearing,
+ metrics->width + char_metric->rbearing);
+ metrics->width += char_metric->width;
+ }
+ else
+ /* If we couldn't get metrics for a char,
+ use alternative method. */
+ break;
+ }
/* If we got through everything, return. */
if (i == nglyphs)
{
@@ -460,19 +455,27 @@ w32font_text_extents (font, code, nglyphs, metrics)
/* For non-truetype fonts, GetGlyphOutlineW is not supported, so
fallback on other methods that will at least give some of the metric
information. */
- for (i = 0; i < nglyphs; i++)
- {
- if (code[i] < 0x10000)
- wcode[i] = code[i];
- else
- {
- /* TODO: Convert to surrogate, reallocating array if needed */
- wcode[i] = 0xffff;
- }
- }
-
+ if (!wcode) {
+ wcode = alloca (nglyphs * sizeof (WORD));
+ for (i = 0; i < nglyphs; i++)
+ {
+ if (code[i] < 0x10000)
+ wcode[i] = code[i];
+ else
+ {
+ /* TODO: Convert to surrogate, reallocating array if needed */
+ wcode[i] = 0xffff;
+ }
+ }
+ }
if (dc == NULL)
{
+ /* TODO: Frames can come and go, and their fonts outlive
+ them. So we can't cache the frame in the font structure. Use
+ selected_frame until the API is updated to pass in a
+ frame. */
+ f = XFRAME (selected_frame);
+
dc = get_frame_dc (f);
old_font = SelectObject (dc, ((W32FontStruct *)
(font->font.font))->hfont);
@@ -792,8 +795,8 @@ w32font_open_internal (f, font_entity, pixel_size, w32_font)
w32_font->glyph_idx = ETO_GLYPH_INDEX;
- /* Cache ASCII metrics. */
- recompute_cached_metrics (dc, w32_font);
+ w32_font->cached_metrics = NULL;
+ w32_font->n_cache_blocks = 0;
SelectObject (dc, old_font);
release_frame_dc (f, dc);
@@ -1226,6 +1229,36 @@ font_matches_spec (type, font, spec, backend, logfont)
return 0;
}
}
+ else if (EQ (key, QClanguage) && SYMBOLP (val))
+ {
+ /* Just handle the CJK languages here, as the language
+ parameter is used to select a font with appropriate
+ glyphs in the cjk unified ideographs block. Other fonts
+ support for a language can be solely determined by
+ its character coverage. */
+ if (EQ (val, Qja))
+ {
+ if (font->ntmTm.tmCharSet != SHIFTJIS_CHARSET)
+ return 0;
+ }
+ else if (EQ (val, Qko))
+ {
+ if (font->ntmTm.tmCharSet != HANGUL_CHARSET
+ && font->ntmTm.tmCharSet != JOHAB_CHARSET)
+ return 0;
+ }
+ else if (EQ (val, Qzh))
+ {
+ if (font->ntmTm.tmCharSet != GB2312_CHARSET
+ && font->ntmTm.tmCharSet != CHINESEBIG5_CHARSET)
+ return 0;
+ }
+ else
+ /* Any other language, we don't recognize it. Fontset
+ spec should have a fallback, as some backends do
+ not recognize language at all. */
+ return 0;
+ }
else if (EQ (key, QCotf) && CONSP (val))
{
/* OTF features only supported by the uniscribe backend. */
@@ -1345,8 +1378,6 @@ registry_to_w32_charset (charset)
return ANSI_CHARSET;
else if (SYMBOLP (charset))
return x_to_w32_charset (SDATA (SYMBOL_NAME (charset)));
- else if (STRINGP (charset))
- return x_to_w32_charset (SDATA (charset));
else
return DEFAULT_CHARSET;
}
@@ -1449,8 +1480,6 @@ fill_in_logfont (f, logfont, font_spec)
user input. */
else if (SYMBOLP (tmp))
strncpy (logfont->lfFaceName, SDATA (SYMBOL_NAME (tmp)), LF_FACESIZE);
- else if (STRINGP (tmp))
- strncpy (logfont->lfFaceName, SDATA (tmp), LF_FACESIZE);
}
tmp = AREF (font_spec, FONT_ADSTYLE_INDEX);
@@ -1550,10 +1579,10 @@ list_all_matching_fonts (match_data)
families = CDR (families);
if (NILP (family))
continue;
- else if (STRINGP (family))
- name = SDATA (family);
- else
+ else if (SYMBOLP (family))
name = SDATA (SYMBOL_NAME (family));
+ else
+ continue;
strncpy (match_data->pattern.lfFaceName, name, LF_FACESIZE);
match_data->pattern.lfFaceName[LF_FACESIZE - 1] = '\0';
@@ -1807,38 +1836,55 @@ w32font_full_name (font, font_obj, pixel_size, name, nbytes)
}
-static void
-recompute_cached_metrics (dc, w32_font)
+static void compute_metrics (dc, w32_font, code, metrics)
HDC dc;
struct w32font_info *w32_font;
+ unsigned int code;
+ struct w32_metric_cache *metrics;
{
GLYPHMETRICS gm;
MAT2 transform;
- unsigned int i;
+ unsigned int options = GGO_METRICS;
+
+ if (w32_font->glyph_idx)
+ options |= GGO_GLYPH_INDEX;
bzero (&transform, sizeof (transform));
transform.eM11.value = 1;
transform.eM22.value = 1;
-
- for (i = 0; i < 128; i++)
+
+ if (GetGlyphOutlineW (dc, code, options, &gm, 0, NULL, &transform)
+ != GDI_ERROR)
+ {
+ metrics->lbearing = gm.gmptGlyphOrigin.x;
+ metrics->rbearing = gm.gmptGlyphOrigin.x + gm.gmBlackBoxX;
+ metrics->width = gm.gmCellIncX;
+ metrics->status = W32METRIC_SUCCESS;
+ }
+ else
{
- struct font_metrics* char_metric = &w32_font->ascii_metrics[i];
- unsigned int options = GGO_METRICS;
if (w32_font->glyph_idx)
- options |= GGO_GLYPH_INDEX;
-
- if (GetGlyphOutlineW (dc, i, options, &gm, 0, NULL, &transform)
- != GDI_ERROR)
- {
- char_metric->lbearing = gm.gmptGlyphOrigin.x;
- char_metric->rbearing = gm.gmBlackBoxX + gm.gmptGlyphOrigin.x;
- char_metric->width = gm.gmCellIncX;
- }
- else
- char_metric->width = 0;
+ {
+ /* Can't use glyph indexes after all.
+ Avoid it in future, and clear any metrics that were based on
+ glyph indexes. */
+ w32_font->glyph_idx = 0;
+ clear_cached_metrics (w32_font);
+ }
+ metrics->status = W32METRIC_FAIL;
}
}
+static void
+clear_cached_metrics (w32_font)
+ struct w32font_info *w32_font;
+{
+ int i;
+ for (i = 0; i < w32_font->n_cache_blocks; i++)
+ bzero (w32_font->cached_metrics[i],
+ CACHE_BLOCKSIZE * sizeof (struct font_metrics));
+}
+
struct font_driver w32font_driver =
{
0, /* Qgdi */
@@ -1898,6 +1944,11 @@ syms_of_w32font ()
DEFSYM (Qsubpixel, "subpixel");
DEFSYM (Qnatural, "natural");
+ /* Languages */
+ DEFSYM (Qja, "ja");
+ DEFSYM (Qko, "ko");
+ DEFSYM (Qzh, "zh");
+
/* Scripts */
DEFSYM (Qlatin, "latin");
DEFSYM (Qgreek, "greek");