/* Font backend for the Microsoft W32 Uniscribe API.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Emacs.
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
-#ifdef USE_FONT_BACKEND
#include <config.h>
/* Override API version - Uniscribe is only available as standard since
#include "dispextern.h"
#include "character.h"
#include "charset.h"
+#include "composite.h"
#include "fontset.h"
#include "font.h"
#include "w32font.h"
uniscribe_list (frame, font_spec)
Lisp_Object frame, font_spec;
{
- return w32font_list_internal (frame, font_spec, 1);
+ Lisp_Object fonts = w32font_list_internal (frame, font_spec, 1);
+ font_add_log ("uniscribe-list", font_spec, fonts);
+ return fonts;
}
static Lisp_Object
uniscribe_match (frame, font_spec)
Lisp_Object frame, font_spec;
{
- return w32font_match_internal (frame, font_spec, 1);
+ Lisp_Object entity = w32font_match_internal (frame, font_spec, 1);
+ font_add_log ("uniscribe-match", font_spec, entity);
+ return entity;
}
static Lisp_Object
return list;
}
-static struct font *
+static Lisp_Object
uniscribe_open (f, font_entity, pixel_size)
FRAME_PTR f;
Lisp_Object font_entity;
int pixel_size;
{
+ Lisp_Object font_object
+ = font_make_object (VECSIZE (struct uniscribe_font_info),
+ font_entity, pixel_size);
struct uniscribe_font_info *uniscribe_font
- = xmalloc (sizeof (struct uniscribe_font_info));
+ = (struct uniscribe_font_info *) XFONT_OBJECT (font_object);
- if (uniscribe_font == NULL)
- return NULL;
+ ASET (font_object, FONT_TYPE_INDEX, Quniscribe);
- if (!w32font_open_internal (f, font_entity, pixel_size,
- (struct w32font_info *) uniscribe_font))
+ if (!w32font_open_internal (f, font_entity, pixel_size, font_object))
{
- xfree (uniscribe_font);
- return NULL;
+ return Qnil;
}
/* Initialize the cache for this font. */
uniscribe_font->cache = NULL;
+
+ /* Uniscribe backend uses glyph indices. */
+ uniscribe_font->w32_font.glyph_idx = ETO_GLYPH_INDEX;
+
/* Mark the format as opentype */
- uniscribe_font->w32_font.font.format = Qopentype;
+ uniscribe_font->w32_font.font.props[FONT_FORMAT_INDEX] = Qopentype;
uniscribe_font->w32_font.font.driver = &uniscribe_font_driver;
- return (struct font *) uniscribe_font;
+ return font_object;
}
static void
= (struct uniscribe_font_info *) font;
if (uniscribe_font->cache)
- ScriptFreeCache (&uniscribe_font->cache);
+ ScriptFreeCache (&(uniscribe_font->cache));
w32font_close (f, font);
}
f = XFRAME (selected_frame);
context = get_frame_dc (f);
- old_font = SelectObject (context,
- ((W32FontStruct *) (font->font.font))->hfont);
+ old_font = SelectObject (context, FONT_HANDLE(font));
features = otf_features (context, "GSUB");
XSETCAR (capability, features);
wchar_t *chars;
WORD *glyphs, *clusters;
SCRIPT_ITEM *items;
- SCRIPT_CONTROL control;
SCRIPT_VISATTR *attributes;
int *advances;
GOFFSET *offsets;
ABC overall_metrics;
- MAT2 transform;
- HDC context;
- HFONT old_font;
HRESULT result;
- struct frame * f;
+ struct frame * f = NULL;
+ HDC context = NULL;
+ HFONT old_font = NULL;
CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
uniscribe_font = (struct uniscribe_font_info *) font;
/* Get the chars from lgstring in a form we can use with uniscribe. */
- max_glyphs = nchars = LGSTRING_LENGTH (lgstring);
+ max_glyphs = nchars = LGSTRING_GLYPH_LEN (lgstring);
done_glyphs = 0;
chars = (wchar_t *) alloca (nchars * sizeof (wchar_t));
for (i = 0; i < nchars; i++)
can be treated together. First try a single run. */
max_items = 2;
items = (SCRIPT_ITEM *) xmalloc (sizeof (SCRIPT_ITEM) * max_items + 1);
- bzero (&control, sizeof (control));
- while ((result = ScriptItemize (chars, nchars, max_items, &control, NULL,
+ while ((result = ScriptItemize (chars, nchars, max_items, NULL, NULL,
items, &nitems)) == E_OUTOFMEMORY)
{
/* If that wasn't enough, keep trying with one more run. */
sizeof (SCRIPT_ITEM) * max_items + 1);
}
- /* 0 = success in Microsoft's backwards world. */
- if (result)
+ if (FAILED (result))
{
xfree (items);
return Qnil;
/* TODO: When we get BIDI support, we need to call ScriptLayout here.
Requires that we know the surrounding context. */
- f = XFRAME (selected_frame);
- context = get_frame_dc (f);
- old_font = SelectObject (context,
- ((W32FontStruct *) (font->font.font))->hfont);
-
glyphs = alloca (max_glyphs * sizeof (WORD));
clusters = alloca (nchars * sizeof (WORD));
attributes = alloca (max_glyphs * sizeof (SCRIPT_VISATTR));
advances = alloca (max_glyphs * sizeof (int));
offsets = alloca (max_glyphs * sizeof (GOFFSET));
- bzero (&transform, sizeof (transform));
- transform.eM11.value = 1;
- transform.eM22.value = 1;
for (i = 0; i < nitems; i++)
{
int nglyphs, nchars_in_run, rtl = items[i].a.fRTL ? -1 : 1;
nchars_in_run = items[i+1].iCharPos - items[i].iCharPos;
+ /* Context may be NULL here, in which case the cache should be
+ used without needing to select the font. */
result = ScriptShape (context, &(uniscribe_font->cache),
chars + items[i].iCharPos, nchars_in_run,
max_glyphs - done_glyphs, &(items[i].a),
glyphs, clusters, attributes, &nglyphs);
+
+ if (result == E_PENDING && !context)
+ {
+ /* This assumes the selected frame is on the same display as the
+ one we are drawing. It would be better for the frame to be
+ passed in. */
+ f = XFRAME (selected_frame);
+ context = get_frame_dc (f);
+ old_font = SelectObject (context, FONT_HANDLE(font));
+
+ result = ScriptShape (context, &(uniscribe_font->cache),
+ chars + items[i].iCharPos, nchars_in_run,
+ max_glyphs - done_glyphs, &(items[i].a),
+ glyphs, clusters, attributes, &nglyphs);
+ }
+
if (result == E_OUTOFMEMORY)
{
/* Need a bigger lgstring. */
lgstring = Qnil;
break;
}
- else if (result) /* Failure. */
+ else if (FAILED (result))
{
/* Can't shape this run - return results so far if any. */
break;
result = ScriptPlace (context, &(uniscribe_font->cache),
glyphs, nglyphs, attributes, &(items[i].a),
advances, offsets, &overall_metrics);
- if (result == 0) /* Success. */
+ if (result == E_PENDING && !context)
+ {
+ /* Cache not complete... */
+ f = XFRAME (selected_frame);
+ context = get_frame_dc (f);
+ old_font = SelectObject (context, FONT_HANDLE(font));
+
+ result = ScriptPlace (context, &(uniscribe_font->cache),
+ glyphs, nglyphs, attributes, &(items[i].a),
+ advances, offsets, &overall_metrics);
+ }
+ if (SUCCEEDED (result))
{
int j, nclusters, from, to;
int lglyph_index = j + done_glyphs;
Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, lglyph_index);
ABC char_metric;
+ unsigned gl;
if (NILP (lglyph))
{
lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
LGSTRING_SET_GLYPH (lgstring, lglyph_index, lglyph);
}
- LGLYPH_SET_CODE (lglyph, glyphs[j]);
+ /* Copy to a 32-bit data type to shut up the
+ compiler warning in LGLYPH_SET_CODE about
+ comparison being always false. */
+ gl = glyphs[j];
+ LGLYPH_SET_CODE (lglyph, gl);
/* Detect clusters, for linking codes back to characters. */
if (attributes[j].fClusterStart)
result = ScriptGetGlyphABCWidth (context,
&(uniscribe_font->cache),
glyphs[j], &char_metric);
+ if (result == E_PENDING && !context)
+ {
+ /* Cache incomplete... */
+ f = XFRAME (selected_frame);
+ context = get_frame_dc (f);
+ old_font = SelectObject (context, FONT_HANDLE(font));
+ result = ScriptGetGlyphABCWidth (context,
+ &(uniscribe_font->cache),
+ glyphs[j], &char_metric);
+ }
- if (result == 0) /* Success. */
+ if (SUCCEEDED (result))
{
LGLYPH_SET_LBEARING (lglyph, char_metric.abcA);
LGLYPH_SET_RBEARING (lglyph, (char_metric.abcA
}
else
LGLYPH_SET_ADJUSTMENT (lglyph, Qnil);
- } }
+ }
+ }
}
done_glyphs += nglyphs;
}
xfree (items);
- SelectObject (context, old_font);
- release_frame_dc (f, context);
+
+ if (context)
+ {
+ SelectObject (context, old_font);
+ release_frame_dc (f, context);
+ }
if (NILP (lgstring))
return Qnil;
struct font *font;
int c;
{
- wchar_t chars[1];
- WORD indices[1];
- HDC context;
- struct frame *f;
- HFONT old_font;
- DWORD retval;
-
- /* TODO: surrogates. */
- if (c > 0xFFFF)
- return FONT_INVALID_CODE;
-
- chars[0] = (wchar_t) c;
+ HDC context = NULL;
+ struct frame *f = NULL;
+ HFONT old_font = NULL;
+ unsigned code = FONT_INVALID_CODE;
+ wchar_t ch[2];
+ int len;
+ SCRIPT_ITEM* items;
+ int nitems;
+ struct uniscribe_font_info *uniscribe_font
+ = (struct uniscribe_font_info *)font;
- /* Use selected frame until API is updated to pass the frame. */
- f = XFRAME (selected_frame);
- context = get_frame_dc (f);
- old_font = SelectObject (context,
- ((W32FontStruct *)(font->font.font))->hfont);
+ if (c < 0x10000)
+ {
+ ch[0] = (wchar_t) c;
+ len = 1;
+ }
+ else
+ {
+ DWORD surrogate = c - 0x10000;
- retval = GetGlyphIndicesW (context, chars, 1, indices,
- GGI_MARK_NONEXISTING_GLYPHS);
+ /* High surrogate: U+D800 - U+DBFF. */
+ ch[0] = 0xD800 + ((surrogate >> 10) & 0x03FF);
+ /* Low surrogate: U+DC00 - U+DFFF. */
+ ch[1] = 0xDC00 + (surrogate & 0x03FF);
+ len = 2;
+ }
- SelectObject (context, old_font);
- release_frame_dc (f, context);
+ /* Non BMP characters must be handled by the uniscribe shaping
+ engine as GDI functions (except blindly displaying lines of
+ unicode text) and the promising looking ScriptGetCMap do not
+ convert surrogate pairs to glyph indexes correctly. */
+ {
+ items = (SCRIPT_ITEM *) alloca (sizeof (SCRIPT_ITEM) * 2 + 1);
+ if (SUCCEEDED (ScriptItemize (ch, len, 2, NULL, NULL, items, &nitems)))
+ {
+ HRESULT result;
+ /* Surrogates seem to need 2 here, even though only one glyph is
+ returned. Indic characters can also produce 2 or more glyphs for
+ a single code point, but they need to use uniscribe_shape
+ above for correct display. */
+ WORD glyphs[2], clusters[2];
+ SCRIPT_VISATTR attrs[2];
+ int nglyphs;
+
+ result = ScriptShape (context, &(uniscribe_font->cache),
+ ch, len, 2, &(items[0].a),
+ glyphs, clusters, attrs, &nglyphs);
+
+ if (result == E_PENDING)
+ {
+ /* Use selected frame until API is updated to pass
+ the frame. */
+ f = XFRAME (selected_frame);
+ context = get_frame_dc (f);
+ old_font = SelectObject (context, FONT_HANDLE(font));
+ result = ScriptShape (context, &(uniscribe_font->cache),
+ ch, len, 2, &(items[0].a),
+ glyphs, clusters, attrs, &nglyphs);
+ }
+
+ if (SUCCEEDED (result) && nglyphs == 1)
+ {
+ /* Some fonts return .notdef glyphs instead of failing.
+ (Truetype spec reserves glyph code 0 for .notdef) */
+ if (glyphs[0])
+ code = glyphs[0];
+ }
+ else if (SUCCEEDED (result) || result == E_OUTOFMEMORY)
+ {
+ /* This character produces zero or more than one glyph
+ when shaped. But we still need the return from here
+ to be valid for the shaping engine to be invoked
+ later. */
+ result = ScriptGetCMap (context, &(uniscribe_font->cache),
+ ch, len, 0, glyphs);
+ if (SUCCEEDED (result) && glyphs[0])
+ code = glyphs[0];
+ }
+ }
+ }
+ if (context)
+ {
+ SelectObject (context, old_font);
+ release_frame_dc (f, context);
+ }
- if (retval == 1)
- return indices[0] == 0xFFFF ? FONT_INVALID_CODE : indices[0];
- else
- return FONT_INVALID_CODE;
+ return code;
}
/*
&& font_type != TRUETYPE_FONTTYPE)
return 1;
- family = intern_downcase (logical_font->elfLogFont.lfFaceName,
- strlen (logical_font->elfLogFont.lfFaceName));
+ /* Skip fonts that have no unicode coverage. */
+ if (!physical_font->ntmFontSig.fsUsb[3]
+ && !physical_font->ntmFontSig.fsUsb[2]
+ && !physical_font->ntmFontSig.fsUsb[1]
+ && !(physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff))
+ return 1;
+
+ family = intern_font_name (logical_font->elfLogFont.lfFaceName);
if (! memq_no_quit (family, *list))
*list = Fcons (family, *list);
OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table);
break;
}
+#if 0 /* Causes false positives. */
/* If there is a DFLT script defined in the font, use it
if the specified script is not found. */
else if (script_id == default_script)
OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table);
+#endif
}
/* If no specific or default script table was found, then this font
does not support the script. */
struct font_driver uniscribe_font_driver =
{
0, /* Quniscribe */
+ 0, /* case insensitive */
w32font_get_cache,
uniscribe_list,
uniscribe_match,
register_font_driver (&uniscribe_font_driver, NULL);
}
-#endif /* USE_FONT_BACKEND */
-
/* arch-tag: 9530f0e1-7471-47dd-a780-94330af87ea0
(do not change this comment) */