nw="$nw -Wsync-nand" # irrelevant here, and provokes ObjC warning
nw="$nw -Wunsafe-loop-optimizations" # OK to suppress unsafe optimizations
nw="$nw -Wbad-function-cast" # These casts are no worse than others.
+ nw="$nw -Wunknown-warning-option" # Let #pragma GCC ignore work properly
+ # even when the compiler in use doesn't
+ # support the option.
# Emacs doesn't care about shadowing; see
# <https://lists.gnu.org/r/emacs-diffs/2011-11/msg00265.html>.
# requires Emacs be built as a position independent executable.
ANDROID_CFLAGS="-fPIC -fvisibility=hidden"
+ # Graphics code in sfntfont-android.c benefits heavily from
+ # vectorization.
+ ANDROID_CFLAGS="$ANDROID_CFLAGS -ftree-vectorize"
+
# Link with libraries required for Android support.
ANDROID_LIBS="-landroid -llog -ljnigraphics"
# Link with the sfnt font library and sfntfont.o, along with
# sfntfont-android.o.
- ANDROID_OBJ="sfnt.o sfntfont.o sfntfont-android.o"
+ ANDROID_OBJ="$ANDROID_OBJ sfnt.o sfntfont.o sfntfont-android.o"
fi
fi
(setq startup--original-eln-load-path
(copy-sequence native-comp-eln-load-path))))
+(defvar android-fonts-enumerated nil
+ "Whether or not fonts have been enumerated already.
+On Android, Emacs uses this variable internally at startup.")
+
(defun normal-top-level ()
"Emacs calls this function when it first starts up.
It sets `command-line-processed', processes the command-line,
reads the initialization files, etc.
It is the default value of the variable `top-level'."
+ ;; Initialize the Android font driver late.
+ ;; This is done here because it needs the `mac-roman' coding system
+ ;; to be loaded.
+ (when (and (featurep 'android)
+ (fboundp 'android-enumerate-fonts)
+ (not android-fonts-enumerated))
+ (funcall 'android-enumerate-fonts)
+ (setq android-fonts-enumerated t))
+
;; Allow disabling automatic .elc->.eln processing.
(setq inhibit-automatic-native-compilation
(getenv "EMACS_INHIBIT_AUTOMATIC_NATIVE_COMPILATION"))
#include TERM_HEADER
#endif /* HAVE_WINDOW_SYSTEM */
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+#include "sfntfont.h"
+#endif
+
#ifdef HAVE_TREE_SITTER
#include "treesit.h"
#endif
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
/* The Android font driver needs the ability to associate extra
information with font entities. */
- if ((vector->header.size & PSEUDOVECTOR_SIZE_MASK)
- == FONT_ENTITY_MAX)
+ if (((vector->header.size & PSEUDOVECTOR_SIZE_MASK)
+ == FONT_ENTITY_MAX)
+ && PSEUDOVEC_STRUCT (vector, font_entity)->is_android)
android_finalize_font_entity (PSEUDOVEC_STRUCT (vector, font_entity));
#endif
}
#ifdef HAVE_ANDROID
mark_androidterm ();
+#ifndef ANDROID_STUBIFY
+ mark_sfntfont ();
+#endif
#endif
#ifdef HAVE_NS
{
jclass class;
jmethodID get_bitmap;
+ jmethodID damage_rect;
};
/* The asset manager being used. */
assert (drawable_class.c_name);
FIND_METHOD (get_bitmap, "getBitmap", "()Landroid/graphics/Bitmap;");
+ FIND_METHOD (damage_rect, "damageRect", "(Landroid/graphics/Rect;)V");
#undef FIND_METHOD
}
gc = xmalloc (sizeof *gc);
prev_max_handle = max_handle;
gc->gcontext = android_alloc_id ();
+ gc->foreground = 0;
+ gc->background = 0xffffff;
+ gc->clip_rects = NULL;
+
+ /* This means to not apply any clipping. */
+ gc->num_clip_rects = -1;
if (!gc->gcontext)
{
android_free_gc (struct android_gc *gc)
{
android_destroy_handle (gc->gcontext);
+
+ xfree (gc->clip_rects);
xfree (gc);
}
ANDROID_HANDLE_GCONTEXT);
if (mask & ANDROID_GC_FOREGROUND)
- (*android_java_env)->SetIntField (android_java_env,
- gcontext,
- emacs_gc_foreground,
- values->foreground);
+ {
+ (*android_java_env)->SetIntField (android_java_env,
+ gcontext,
+ emacs_gc_foreground,
+ values->foreground);
+ gc->foreground = values->foreground;
+ }
if (mask & ANDROID_GC_BACKGROUND)
- (*android_java_env)->SetIntField (android_java_env,
- gcontext,
- emacs_gc_background,
- values->background);
+ {
+ (*android_java_env)->SetIntField (android_java_env,
+ gcontext,
+ emacs_gc_background,
+ values->background);
+ gc->background = values->background;
+ }
if (mask & ANDROID_GC_FUNCTION)
(*android_java_env)->SetIntField (android_java_env,
gcontext,
emacs_gc_clip_rects,
NULL);
+
+ xfree (gc->clip_rects);
+ gc->clip_rects = NULL;
+ gc->num_clip_rects = -1;
}
if (mask & ANDROID_GC_STIPPLE)
(*android_java_env)->CallVoidMethod (android_java_env,
gcontext,
emacs_gc_mark_dirty);
+
+ /* Cache the clip rectangles on the C side for
+ sfntfont-android.c. */
+ if (gc->clip_rects)
+ xfree (gc->clip_rects);
+
+ /* If gc->num_clip_rects is 0, then no drawing will be performed at
+ all. */
+ gc->clip_rects = xmalloc (sizeof *gc->clip_rects
+ * n_clip_rects);
+ gc->num_clip_rects = n_clip_rects;
+ memcpy (gc->clip_rects, clip_rects,
+ n_clip_rects * sizeof *gc->clip_rects);
}
void
if (mask & ANDROID_GC_FOREGROUND)
/* GCs never have 32 bit colors, so we don't have to worry about
sign extension here. */
- values->foreground
- = (*android_java_env)->GetIntField (android_java_env,
- gcontext,
- emacs_gc_foreground);
+ values->foreground = gc->foreground;
if (mask & ANDROID_GC_BACKGROUND)
- values->background
- = (*android_java_env)->GetIntField (android_java_env,
- gcontext,
- emacs_gc_background);
+ values->background = gc->background;
if (mask & ANDROID_GC_FUNCTION)
values->function
unsigned char *data1, *data2;
int i, x;
- /* N.B. that supporting windows requires some more work to make
- EmacsDrawable.getBitmap thread safe. */
drawable = android_resolve_handle2 (handle, ANDROID_HANDLE_WINDOW,
ANDROID_HANDLE_PIXMAP);
\f
+/* Low level drawing primitives. */
+
+/* Lock the bitmap corresponding to the window WINDOW. Return the
+ bitmap data upon success, and store the bitmap object in
+ BITMAP_RETURN. Value is NULL upon failure.
+
+ The caller must take care to unlock the bitmap data afterwards. */
+
+unsigned char *
+android_lock_bitmap (android_window window,
+ AndroidBitmapInfo *bitmap_info,
+ jobject *bitmap_return)
+{
+ jobject drawable, bitmap;
+ void *data;
+
+ drawable = android_resolve_handle (window, ANDROID_HANDLE_WINDOW);
+
+ /* Look up the drawable and get the bitmap corresponding to it.
+ Then, lock the bitmap's bits. */
+ bitmap = (*android_java_env)->CallObjectMethod (android_java_env,
+ drawable,
+ drawable_class.get_bitmap);
+ if (!bitmap)
+ /* NULL is returned when the bitmap does not currently exist due
+ to ongoing reconfiguration on the main thread. */
+ return NULL;
+
+ memset (bitmap_info, 0, sizeof *bitmap_info);
+
+ /* Get the bitmap info. */
+ AndroidBitmap_getInfo (android_java_env, bitmap, bitmap_info);
+
+ if (!bitmap_info->stride)
+ {
+ ANDROID_DELETE_LOCAL_REF (bitmap);
+ return NULL;
+ }
+
+ /* Now lock the image data. */
+ data = NULL;
+ AndroidBitmap_lockPixels (android_java_env, bitmap, &data);
+
+ if (!data)
+ {
+ ANDROID_DELETE_LOCAL_REF (bitmap);
+ return NULL;
+ }
+
+ /* Give the bitmap to the caller. */
+ *bitmap_return = bitmap;
+
+ /* The bitmap data is now locked. */
+ return data;
+}
+
+/* Damage the window HANDLE by the given damage rectangle. */
+
+void
+android_damage_window (android_drawable handle,
+ struct android_rectangle *damage)
+{
+ jobject drawable, rect;
+
+ drawable = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
+
+ /* Now turn DAMAGE into a Java rectangle. */
+ rect = (*android_java_env)->NewObject (android_java_env,
+ android_rect_class,
+ android_rect_constructor,
+ (jint) damage->x,
+ (jint) damage->y,
+ (jint) (damage->x
+ + damage->width),
+ (jint) (damage->y
+ + damage->height));
+ if (!rect)
+ {
+ (*android_java_env)->ExceptionClear (android_java_env);
+ memory_full (0);
+ }
+
+ /* Post the damage to the drawable. */
+ (*android_java_env)->CallVoidMethod (android_java_env,
+ drawable,
+ drawable_class.damage_rect,
+ rect);
+ ANDROID_DELETE_LOCAL_REF (rect);
+}
+
+\f
+
#undef faccessat
/* Replace the system faccessat with one which understands AT_EACCESS.
#include <pwd.h>
#include <sys/stat.h>
+#include <android/bitmap.h>
+
#include "androidgui.h"
#endif
extern jobject android_resolve_handle (android_handle,
enum android_handle_type);
+extern unsigned char *android_lock_bitmap (android_window,
+ AndroidBitmapInfo *,
+ jobject *);
+extern void android_damage_window (android_window,
+ struct android_rectangle *);
#endif
if (! FONTP (font) && ! STRINGP (font))
{
const char *names[] = {
- /* This will find the normal font. The default font size on
- Android is 8. */
+ "Droid Sans Mono",
"monospace",
"DroidSansMono",
NULL
}
register_font_driver (&androidfont_driver, f);
+ register_font_driver (&android_sfntfont_driver, f);
image_cache_refcount = (FRAME_IMAGE_CACHE (f)
? FRAME_IMAGE_CACHE (f)->refcount
struct android_gc
{
+ /* Array of clip rectangles. */
+ struct android_rectangle *clip_rects;
+
+ /* Number of clip rectangles. When -1, it means clipping should not
+ be applied. */
+ int num_clip_rects;
+
/* The Java-side handle. */
android_gcontext gcontext;
+
+ /* Current foreground color. */
+ unsigned long foreground;
+
+ /* Current background color. */
+ unsigned long background;
};
enum android_swap_action
/* Defined in sfntfont-android.c. */
+extern const struct font_driver android_sfntfont_driver;
+
extern void init_sfntfont_android (void);
extern void syms_of_sfntfont_android (void);
#define NativeRectangle int
#endif
+#ifdef HAVE_WINDOW_SYSTEM
+
+/* ``box'' structure similar to that found in the X sample server,
+ meaning that X2 and Y2 are not actually the end of the box, but one
+ pixel past the end of the box, which makes checking for overlaps
+ less necessary. This is convenient to use in every GUI port. */
+
+struct gui_box
+{
+ /* Bounds of the box. */
+ int x1, y1;
+ int x2, y2;
+};
+
+#endif
+
/* Text cursor types. */
enum text_cursor_kinds
extern bool gui_intersect_rectangles (const Emacs_Rectangle *,
const Emacs_Rectangle *,
Emacs_Rectangle *);
+extern void gui_union_rectangles (const Emacs_Rectangle *,
+ const Emacs_Rectangle *,
+ Emacs_Rectangle *);
extern void gui_consider_frame_title (Lisp_Object);
#endif /* HAVE_WINDOW_SYSTEM */
init_haiku_select ();
#endif
-#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
- init_androidfont ();
- init_sfntfont ();
- init_sfntfont_android ();
-#endif
-
init_charset ();
/* This calls putenv and so must precede init_process_emacs. */
init_window ();
init_font ();
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+ init_androidfont ();
+ init_sfntfont ();
+ init_sfntfont_android ();
+#endif
+
if (!initialized)
{
char *file;
safe_run_hooks (Qafter_pdump_load_hook);
#endif
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY && 0
+ /* This comes very late in the startup process because it requires
+ most of lisp/international to be loaded. This approach doesn't
+ work because normal-top-level runs and creates the initial frame
+ before fonts are initialized. So this is done in
+ normal-top-level instead. */
+ Vtop_level = list3 (Qprogn, Vtop_level,
+ list1 (Qandroid_enumerate_fonts));
+#endif
+
/* Enter editor command loop. This never returns. */
set_initial_minibuffer_mode ();
Frecursive_edit ();
allocate_pseudovector (VECSIZE (struct font_entity),
FONT_ENTITY_MAX, FONT_ENTITY_MAX, PVEC_FONT));
XSETFONT (font_entity, entity);
+
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+ entity->is_android = false;
+#endif
+
return font_entity;
}
= ((struct font_entity *)
allocate_pseudovector (size, FONT_ENTITY_MAX, FONT_ENTITY_MAX,
PVEC_FONT));
+
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+ entity->is_android = true;
+#endif
+
XSETFONT (font_entity, entity);
return font_entity;
}
{
union vectorlike_header header;
Lisp_Object props[FONT_ENTITY_MAX];
+
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+ /* Whether or not this is an Android font entity. */
+ bool is_android;
+#endif
};
/* A value which may appear in the member `encoding' of struct font
print_c_string ("#<font-entity", printcharfun);
for (int i = 0; i < FONT_SPEC_MAX; i++)
{
- printchar (' ', printcharfun);
- if (i < FONT_WEIGHT_INDEX || i > FONT_WIDTH_INDEX)
- print_object (AREF (obj, i), printcharfun, escapeflag);
- else
- print_object (font_style_symbolic (obj, i, 0),
- printcharfun, escapeflag);
+ /* FONT_EXTRA_INDEX can contain private information in
+ font entities which isn't safe to print. */
+ if (i != FONT_EXTRA_INDEX || !FONT_ENTITY_P (obj))
+ {
+ printchar (' ', printcharfun);
+ if (i < FONT_WEIGHT_INDEX || i > FONT_WIDTH_INDEX)
+ print_object (AREF (obj, i), printcharfun, escapeflag);
+ else
+ print_object (font_style_symbolic (obj, i, 0),
+ printcharfun, escapeflag);
+ }
}
}
else
#include <string.h>
#include <unistd.h>
+#if defined __GNUC__ && !defined __clang__
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+#endif
+
#ifdef TEST
#include <time.h>
format0->format = header->format;
format0->length = header->length;
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstringop-overflow"
-
/* Read the rest. */
wanted_size = (sizeof *format0
- offsetof (struct sfnt_cmap_format_0,
language));
rc = read (fd, &format0->language, wanted_size);
-#pragma GCC diagnostic pop
-
if (rc < wanted_size)
{
xfree (format0);
format2->format = header->format;
format2->length = header->length;
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstringop-overflow"
-
/* Read the part before the variable length data. */
min_bytes -= offsetof (struct sfnt_cmap_format_2, language);
rc = read (fd, &format2->language, min_bytes);
return (struct sfnt_cmap_format_2 *) -1;
}
-#pragma GCC diagnostic pop
-
/* Check whether or not the data is of the correct size. */
if (min_bytes < nsub * sizeof *format2->subheaders)
{
format4->format = header->format;
format4->length = header->length;
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstringop-overflow"
-
/* Read the initial data. */
min_bytes -= offsetof (struct sfnt_cmap_format_4, language);
rc = read (fd, &format4->language, min_bytes);
for (i = 0; i < format4->glyph_index_size; ++i)
sfnt_swap16 (&format4->glyph_index_array[i]);
-#pragma GCC diagnostic pop
-
/* Done. Return the format 4 character map. */
return format4;
}
format6->format = header->format;
format6->length = header->length;
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstringop-overflow"
-
/* Read the fixed size data. */
min_size -= offsetof (struct sfnt_cmap_format_6, language);
rc = read (fd, &format6->language, min_size);
return (struct sfnt_cmap_format_6 *) -1;
}
-#pragma GCC diagnostic pop
-
/* Set the data pointer and swap everything. */
format6->glyph_index_array = (uint16_t *) (format6 + 1);
for (i = 0; i < format6->entry_count; ++i)
format8->reserved = header->length;
format8->length = length;
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstringop-overflow"
-
/* Read the fixed length data. */
min_size -= offsetof (struct sfnt_cmap_format_8, language);
rc = read (fd, &format8->language, min_size);
return (struct sfnt_cmap_format_8 *) -1;
}
-#pragma GCC diagnostic pop
-
/* Set the pointer to the variable length data. */
format8->groups
= (struct sfnt_cmap_format_8_or_12_group *) (format8 + 1);
format12->reserved = header->length;
format12->length = length;
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstringop-overflow"
-
/* Read the fixed length data. */
min_size -= offsetof (struct sfnt_cmap_format_12, language);
rc = read (fd, &format12->language, min_size);
return (struct sfnt_cmap_format_12 *) -1;
}
-#pragma GCC diagnostic pop
-
/* Swap what was read. */
sfnt_swap32 (&format12->language);
sfnt_swap32 (&format12->num_groups);
return ((int) *((uint16_t *) a)) - ((int) *((uint16_t *) b));
}
-/* Look up the glyph corresponding to CHARACTER in the format 4 cmap
- FORMAT4. Return 0 if no glyph was found. */
+/* Look up the glyph corresponding to CODE in the format 4 cmap
+ FORMAT4, using the table segment SEGMENT. Value is 0 if no glyph
+ was found. */
static sfnt_glyph
-sfnt_lookup_glyph_4 (sfnt_char character,
- struct sfnt_cmap_format_4 *format4)
+sfnt_lookup_glyph_4_1 (uint16_t code, uint16_t segment,
+ struct sfnt_cmap_format_4 *format4)
{
- uint16_t *segment_address, *index;
- uint16_t code, segment;
-
- if (character > 65535)
- return 0;
-
- code = character;
-
- /* Find the segment above CHARACTER. */
- segment_address = sfnt_bsearch_above (&code, format4->end_code,
- format4->seg_count_x2 / 2,
- sizeof code,
- sfnt_compare_uint16);
- segment = segment_address - format4->end_code;
-
- /* If the segment starts too late, return 0. */
- if (!segment_address || format4->start_code[segment] > character)
- return 0;
+ uint16_t *index;
if (format4->id_range_offset[segment])
{
return (format4->id_delta[segment] + code) % 65536;
}
+/* Look up the glyph corresponding to CHARACTER in the format 4 cmap
+ FORMAT4. Return 0 if no glyph was found. */
+
+static sfnt_glyph
+sfnt_lookup_glyph_4 (sfnt_char character,
+ struct sfnt_cmap_format_4 *format4)
+{
+ uint16_t *segment_address;
+ uint16_t code, segment;
+ sfnt_glyph glyph;
+
+ if (character > 65535)
+ return 0;
+
+ code = character;
+
+ /* Find the segment ending above or at CHARACTER. */
+ segment_address = sfnt_bsearch_above (&code, format4->end_code,
+ format4->seg_count_x2 / 2,
+ sizeof code,
+ sfnt_compare_uint16);
+ segment = segment_address - format4->end_code;
+
+ /* If the segment starts too late, return 0. */
+ if (!segment_address || format4->start_code[segment] > character)
+ return 0;
+
+ glyph = sfnt_lookup_glyph_4_1 (character, segment, format4);
+
+ if (glyph)
+ return glyph;
+
+ /* Droid Sans Mono has overlapping segments in its format 4 cmap
+ subtable where the first segment's end code is 32, while the
+ second segment's start code is also 32. The TrueType Reference
+ Manual says that mapping should begin by searching for the first
+ segment whose end code is greater than or equal to the character
+ being indexed, but that results in the first subtable being
+ found, which doesn't work, while the second table does. Try to
+ detect this situation and use the second table if possible. */
+
+ if (!glyph
+ /* The character being looked up is the current segment's end
+ code. */
+ && code == format4->end_code[segment]
+ /* There is an additional segment. */
+ && segment + 1 < format4->seg_count_x2 / 2
+ /* That segment's start code is the same as this segment's end
+ code. */
+ && format4->start_code[segment + 1] == format4->end_code[segment])
+ /* Try the second segment. */
+ return sfnt_lookup_glyph_4_1 (character, segment + 1, format4);
+
+ /* Fail. */
+ return 0;
+}
+
/* Look up the glyph corresponding to CHARACTER in the format 6 cmap
FORMAT6. Return 0 if no glyph was found. */
which must be in the correct encoding for the cmap table pointed to
by DATA. */
-static sfnt_glyph
+TEST_STATIC sfnt_glyph
sfnt_lookup_glyph (sfnt_char character,
struct sfnt_cmap_encoding_subtable_data *data)
{
/* Calculate the minimum size of the glyph data. This is the size
of the instruction length field followed by
- glyf->number_of_contours * sizeof (uint16_t). */
+ glyph->number_of_contours * sizeof (uint16_t). */
min_size = (glyph->number_of_contours * sizeof (uint16_t)
+ sizeof (uint16_t));
struct sfnt_loca_table_long *loca_long)
{
struct sfnt_glyph glyph, *memory;
- ptrdiff_t offset;
+ ptrdiff_t offset, next_offset;
+
+ /* Check the glyph code is within bounds. */
+ if (glyph_code > 65535)
+ return NULL;
if (loca_short)
{
- /* Check that the glyph is within bounds. */
- if (glyph_code > loca_short->num_offsets)
+ /* Check that the glyph is within bounds. glyph_code + 1 is the
+ entry in the table which defines the length of the glyph. */
+ if (glyph_code + 1 >= loca_short->num_offsets)
return NULL;
offset = loca_short->offsets[glyph_code] * 2;
+ next_offset = loca_short->offsets[glyph_code + 1] * 2;
}
else if (loca_long)
{
- if (glyph_code > loca_long->num_offsets)
+ if (glyph_code + 1 >= loca_long->num_offsets)
return NULL;
offset = loca_long->offsets[glyph_code];
+ next_offset = loca_long->offsets[glyph_code + 1];
}
else
abort ();
+ /* If offset - next_offset is 0, then the glyph is empty. Its
+ horizontal advance may still be provided by the hmtx table. */
+
+ if (offset == next_offset)
+ {
+ glyph.number_of_contours = 0;
+ glyph.xmin = 0;
+ glyph.ymin = 0;
+ glyph.xmax = 0;
+ glyph.ymax = 0;
+ glyph.simple = xmalloc (sizeof *glyph.simple);
+ glyph.compound = NULL;
+ memset (glyph.simple, 0, sizeof *glyph.simple);
+ memory = xmalloc (sizeof *memory);
+ *memory = glyph;
+ return memory;
+ }
+
/* Verify that GLYF is big enough to hold a glyph at OFFSET. */
if (glyf->size < offset + SFNT_ENDOF (struct sfnt_glyph,
ymax, sfnt_fword))
/* Free a glyph returned from sfnt_read_glyph. GLYPH may be NULL. */
-static void
+TEST_STATIC void
sfnt_free_glyph (struct sfnt_glyph *glyph)
{
if (!glyph)
static void
sfnt_transform_coordinates (struct sfnt_compound_glyph_component *component,
- sfnt_fixed *x, sfnt_fixed *y,
+ sfnt_fixed *restrict x, sfnt_fixed *restrict y,
size_t num_coordinates)
{
double m1, m2, m3;
sfnt_lerp_half (struct sfnt_point *control1, struct sfnt_point *control2,
struct sfnt_point *result)
{
- result->x = (control1->x + control2->x) / 2;
- result->y = (control1->y + control2->y) / 2;
+ result->x = control1->x + ((control2->x - control1->x) >> 1);
+ result->y = control1->y + ((control2->y - control1->y) >> 1);
}
/* Decompose GLYPH into its individual components. Call MOVE_TO to
sfnt_free_glyph_proc free_glyph,
void *dcontext)
{
- size_t here, last;
+ size_t here, start, last;
struct sfnt_point pen, control1, control2;
struct sfnt_compound_glyph_context context;
size_t n;
if (glyph->simple)
{
if (!glyph->number_of_contours)
- /* No contours. */
- return 1;
+ /* No contours. Nothing needs to be decomposed. */
+ return 0;
here = 0;
pen.y = glyph->simple->y_coordinates[here] << 16U;
move_to (pen, dcontext);
+ /* Record start so the contour can be closed. */
+ start = here;
+
/* If there is only one point in a contour, draw a one pixel
wide line. */
if (last == here)
curve_to (control1, pen, dcontext);
}
}
+
+ /* Now close the contour if there is more than one point
+ inside it. */
+ if (start != here - 1)
+ {
+ /* Restore here after the for loop increased it. */
+ here --;
+
+ if (glyph->simple->flags[start] & 01) /* On Curve */
+ {
+ pen.x = glyph->simple->x_coordinates[start] << 16U;
+ pen.y = glyph->simple->y_coordinates[start] << 16U;
+
+ /* See if the last point (in this case, `here') was
+ on the curve. If it wasn't, then curve from
+ there to here. */
+ if (!(glyph->simple->flags[here] & 01))
+ {
+ control1.x
+ = glyph->simple->x_coordinates[here] << 16U;
+ control1.y
+ = glyph->simple->y_coordinates[here] << 16U;
+ curve_to (control1, pen, dcontext);
+ }
+ else
+ /* Otherwise, this is an ordinary line from there
+ to here. */
+ line_to (pen, dcontext);
+ }
+
+ /* Restore here to where it was earlier. */
+ here++;
+ }
}
return 0;
if (!context.num_end_points)
/* No contours. */
- goto fail;
+ goto early;
here = 0;
pen.y = context.y_coordinates[here];
move_to (pen, dcontext);
+ /* Record start so the contour can be closed. */
+ start = here;
+
/* If there is only one point in a contour, draw a one pixel
wide line. */
if (last == here)
curve_to (control1, pen, dcontext);
}
}
+
+ /* Now close the contour if there is more than one point
+ inside it. */
+ if (start != here - 1)
+ {
+ /* Restore here after the for loop increased it. */
+ here --;
+
+ if (context.flags[start] & 01) /* On Curve */
+ {
+ pen.x = context.x_coordinates[start];
+ pen.y = context.y_coordinates[start];
+
+ /* See if the last point (in this case, `here') was
+ on the curve. If it wasn't, then curve from
+ there to here. */
+ if (!(context.flags[here] & 01))
+ {
+ control1.x = context.x_coordinates[here];
+ control1.y = context.y_coordinates[here];
+ curve_to (control1, pen, dcontext);
+ }
+ else
+ /* Otherwise, this is an ordinary line from there
+ to here. */
+ line_to (pen, dcontext);
+ }
+
+ /* Restore here to where it was earlier. */
+ here++;
+ }
}
+ early:
xfree (context.x_coordinates);
xfree (context.y_coordinates);
xfree (context.flags);
return 1;
}
+struct sfnt_build_glyph_outline_context
+{
+ /* The outline being built. */
+ struct sfnt_glyph_outline *outline;
+
+ /* The head table. */
+ struct sfnt_head_table *head;
+
+ /* The pixel size being used, and any extra flags to apply to the
+ outline at this point. */
+ int pixel_size;
+
+ /* Factor to multiply positions by to get the pixel width. */
+ sfnt_fixed factor;
+
+ /* The position of the pen in 16.16 fixed point format. */
+ sfnt_fixed x, y;
+};
+
/* Global state for sfnt_build_glyph_outline and related
functions. */
static struct sfnt_build_glyph_outline_context build_outline_context;
/* Extend outline bounding box. */
- if (outline->outline_used == 3)
+ if (outline->outline_used == 1)
{
/* These are the first points in the outline. */
outline->xmin = outline->xmax = x;
return outline;
}
-/* Set the pen size to the specified point and return. POINT will be
- scaled up to the pixel size. */
-
-static void
-sfnt_move_to_and_build (struct sfnt_point point, void *dcontext)
-{
- sfnt_fixed x, y;
-
- x = build_outline_context.factor * point.x;
- y = build_outline_context.factor * point.y;
-
- build_outline_context.outline = sfnt_build_append (0, x, y);
- build_outline_context.x = x;
- build_outline_context.y = y;
-}
-
-/* Record a line to the specified point and return. POINT will be
- scaled up to the pixel size. */
-
-static void
-sfnt_line_to_and_build (struct sfnt_point point, void *dcontext)
-{
- sfnt_fixed x, y;
-
- x = build_outline_context.factor * point.x;
- y = build_outline_context.factor * point.y;
-
- build_outline_context.outline
- = sfnt_build_append (SFNT_GLYPH_OUTLINE_LINETO,
- x, y);
- build_outline_context.x = x;
- build_outline_context.y = y;
-}
-
/* Multiply the two 16.16 fixed point numbers X and Y. Return the
result regardless of overflow. */
#endif
}
+/* Set the pen size to the specified point and return. POINT will be
+ scaled up to the pixel size. */
+
+static void
+sfnt_move_to_and_build (struct sfnt_point point, void *dcontext)
+{
+ sfnt_fixed x, y;
+
+ x = sfnt_mul_fixed (build_outline_context.factor, point.x);
+ y = sfnt_mul_fixed (build_outline_context.factor, point.y);
+
+ build_outline_context.outline = sfnt_build_append (0, x, y);
+ build_outline_context.x = x;
+ build_outline_context.y = y;
+}
+
+/* Record a line to the specified point and return. POINT will be
+ scaled up to the pixel size. */
+
+static void
+sfnt_line_to_and_build (struct sfnt_point point, void *dcontext)
+{
+ sfnt_fixed x, y;
+
+ x = sfnt_mul_fixed (build_outline_context.factor, point.x);
+ y = sfnt_mul_fixed (build_outline_context.factor, point.y);
+
+ build_outline_context.outline
+ = sfnt_build_append (SFNT_GLYPH_OUTLINE_LINETO,
+ x, y);
+ build_outline_context.x = x;
+ build_outline_context.y = y;
+}
+
/* Divide the two 16.16 fixed point numbers X and Y. Return the
result regardless of overflow. */
struct sfnt_point control1,
struct sfnt_point endpoint)
{
- struct sfnt_point ab;
+ struct sfnt_point ab, bc, abbc;
/* control0, control and endpoint make up the spline. Figure out
its distance from a line. */
}
else
{
- /* Split the spline between control0 and control1.
+ /* Calculate new control points.
Maybe apply a recursion limit here? */
sfnt_lerp_half (&control0, &control1, &ab);
+ sfnt_lerp_half (&control1, &endpoint, &bc);
+ sfnt_lerp_half (&ab, &bc, &abbc);
/* Keep splitting until a flat enough spline results. */
- sfnt_curve_to_and_build_1 (control0, ab, control1);
+ sfnt_curve_to_and_build_1 (control0, ab, abbc);
/* Then go on with the spline between control1 and endpoint. */
- sfnt_curve_to_and_build_1 (ab, control1, endpoint);
+ sfnt_curve_to_and_build_1 (abbc, bc, endpoint);
}
}
control0.x = build_outline_context.x;
control0.y = build_outline_context.y;
- control.x *= build_outline_context.factor;
- control.y *= build_outline_context.factor;
- endpoint.x *= build_outline_context.factor;
- endpoint.y *= build_outline_context.factor;
+ control.x = sfnt_mul_fixed (control.x,
+ build_outline_context.factor);
+ control.y = sfnt_mul_fixed (control.y,
+ build_outline_context.factor);
+ endpoint.x = sfnt_mul_fixed (endpoint.x,
+ build_outline_context.factor);
+ endpoint.y = sfnt_mul_fixed (endpoint.y,
+ build_outline_context.factor);
sfnt_curve_to_and_build_1 (control0, control, endpoint);
}
/* Non-reentrantly build the outline for the specified GLYPH at the
- given pixel size. Return the outline data upon success, or NULL
- upon failure.
+ given pixel size. Return the outline data with a refcount of 0
+ upon success, or NULL upon failure.
Call GET_GLYPH and FREE_GLYPH with the specified DCONTEXT to obtain
glyphs for compound glyph subcomponents.
outline = xmalloc (sizeof *outline + 40 * sizeof (*outline->outline));
outline->outline_size = 40;
outline->outline_used = 0;
+ outline->refcount = 0;
outline->outline
= (struct sfnt_glyph_outline_command *) (outline + 1);
It would be nice to get rid of this floating point arithmetic at
some point. */
build_outline_context.factor
- = (double) pixel_size / head->units_per_em;
+ = sfnt_div_fixed (pixel_size << 16,
+ head->units_per_em << 16);
/* Decompose the outline. */
rc = sfnt_decompose_glyph (glyph, sfnt_move_to_and_build,
& ~(SFNT_POLY_STEP - 1)) + SFNT_POLY_START);
}
+enum
+ {
+ SFNT_POLY_ALIGNMENT = 4,
+ };
+
/* Initialize the specified RASTER in preparation for displaying spans
- for OUTLINE. The caller must then set RASTER->cells to a zeroed
- array of size RASTER->width * RASTER->height. */
+ for OUTLINE, and set RASTER->refcount to 0. The caller must then
+ set RASTER->cells to a zeroed array of size RASTER->stride *
+ RASTER->height, aligned to RASTER. */
-static void
+TEST_STATIC void
sfnt_prepare_raster (struct sfnt_raster *raster,
struct sfnt_glyph_outline *outline)
{
= sfnt_ceil_fixed (outline->xmax - outline->xmin) >> 16;
raster->height
= sfnt_ceil_fixed (outline->ymax - outline->ymin) >> 16;
+ raster->refcount = 0;
+
+ /* Align the raster to a SFNT_POLY_ALIGNMENT byte boundary. */
+ raster->stride = ((raster->width
+ + (SFNT_POLY_ALIGNMENT - 1))
+ & ~(SFNT_POLY_ALIGNMENT - 1));
+
raster->offx
- = sfnt_floor_fixed (outline->xmin);
+ = sfnt_floor_fixed (outline->xmin) >> 16;
raster->offy
- = sfnt_floor_fixed (raster->height - outline->ymax);
+ = sfnt_floor_fixed (outline->ymin) >> 16;
}
typedef void (*sfnt_edge_proc) (struct sfnt_edge *, size_t,
typedef void (*sfnt_span_proc) (struct sfnt_edge *, sfnt_fixed, void *);
/* Move EDGE->x forward, assuming that the scanline has moved upwards
- by DY. */
+ by SFNT_POLY_STEP. */
static void
-sfnt_step_edge_by (struct sfnt_edge *edge, sfnt_fixed dy)
+sfnt_step_edge (struct sfnt_edge *edge)
{
/* Step edge. */
- edge->x += sfnt_mul_fixed (edge->step_x, dy);
+ edge->x += edge->step_x;
}
/* Build a list of edges for each contour in OUTLINE, applying
sfnt_edge_proc edge_proc, void *dcontext)
{
struct sfnt_edge *edges;
- size_t i, edge, start, next_vertex, y;
- sfnt_fixed dx, dy, bot;
+ size_t i, edge, next_vertex;
+ sfnt_fixed dx, dy, bot, step_x;
int inc_x;
- size_t top, bottom;
+ size_t top, bottom, y;
edges = alloca (outline->outline_used * sizeof *edges);
edge = 0;
- /* First outline currently being processed. */
- start = 0;
-
- for (i = 0; i < outline->outline_used; i++)
+ for (i = 0; i < outline->outline_used; ++i)
{
- if (!(outline->outline[i].flags & SFNT_GLYPH_OUTLINE_LINETO))
- /* Flush the edge. */
- start = i;
-
/* Set NEXT_VERTEX to the next point (vertex) in this contour.
- If i + 3 is the end of the contour, then the next point is
- its start, so wrap it around to there. */
+
+ If i is past the end of the contour, then don't build edges
+ for this point. */
next_vertex = i + 1;
+
if (next_vertex == outline->outline_used
|| !(outline->outline[next_vertex].flags
& SFNT_GLYPH_OUTLINE_LINETO))
- next_vertex = start;
+ continue;
/* Skip past horizontal vertices. */
if (outline->outline[next_vertex].y == outline->outline[i].y)
dy = abs (outline->outline[top].y
- outline->outline[bottom].y);
+#ifdef TEST
+ edges[edge].source_x = edges[edge].x;
+#endif
+
/* Compute the increment. This is which direction X moves in
for each increase in Y. */
/* Compute the step X. This is how much X changes for each
increase in Y. */
- edges[edge].step_x = inc_x * sfnt_div_fixed (dx, dy);
+ step_x = inc_x * sfnt_div_fixed (dx, dy);
/* Step to first grid point. */
y = sfnt_poly_grid_ceil (bot);
- sfnt_step_edge_by (&edges[edge], bot - y);
+
+ /* If rounding would make the edge not cover any area, skip this
+ edge. */
+ if (y > edges[edge].top)
+ continue;
+
+ edges[edge].x += sfnt_mul_fixed (step_x, bot - y);
edges[edge].bottom = y;
edges[edge].next = NULL;
+ /* Compute the step X scaled to the poly step. */
+ edges[edge].step_x
+ = sfnt_mul_fixed (step_x, SFNT_POLY_STEP);
+
edge++;
}
/* Step all edges. */
for (a = active; a; a = a->next)
- sfnt_step_edge_by (a, SFNT_POLY_STEP);
+ sfnt_step_edge (a);
/* Resort on X axis. */
for (prev = &active; (a = *prev) && (n = a->next);)
{
unsigned char *start;
unsigned char *coverage;
- sfnt_fixed left, right;
+ sfnt_fixed left, right, end;
unsigned short w, a;
int row, col;
right are now 16.2. */
left = sfnt_poly_grid_ceil (x0) >> (16 - SFNT_POLY_SHIFT);
right = sfnt_poly_grid_ceil (x1) >> (16 - SFNT_POLY_SHIFT);
- start = raster->cells + row * raster->width;
+#if 7 > __GNUC__
+ start = raster->cells + row * raster->stride;
+#else
+ start = __builtin_assume_aligned ((raster->cells
+ + row * raster->stride),
+ SFNT_POLY_ALIGNMENT);
+#endif
start += left >> SFNT_POLY_SHIFT;
/* Compute coverage for first pixel, then poly. */
map, unlike row which indexes the raster. */
col = 0;
- while (left < right && (left & SFNT_POLY_MASK))
+ /* Precompute this to allow for better optimizations. */
+ end = ((left + SFNT_POLY_SAMPLE - 1) & ~SFNT_POLY_MASK);
+
+ while (left < right && left < end)
left++, w += coverage[col++];
a = *start + w;
for (edge = start; edge; edge = edge->next)
{
- /* Skip out of bounds spans. This ought to go away. */
- if (!(y >= edge->bottom && y < edge->top))
- continue;
-
if (!winding)
x0 = edge->x;
else
sfnt_prepare_raster (&raster, outline);
/* Allocate the raster data. */
- data = xmalloc (sizeof *data + raster.width * raster.height);
+ data = xmalloc (sizeof *data + raster.stride * raster.height);
*data = raster;
data->cells = (unsigned char *) (data + 1);
- memset (data->cells, 0, raster.width * raster.height);
+ memset (data->cells, 0, raster.stride * raster.height);
/* Generate edges for the outline, polying each array of edges to
the raster. */
for (i = 0; i < num_edges; ++i)
{
- printf ("/* edge x, top, bot: %g, %g - %g. winding: %d */\n",
+ printf ("/* edge x, top, bot: %g, %g - %g. winding: %d */\n"
+ "/* edge step_x: %g, source_x: %g (%d) */\n",
sfnt_coerce_fixed (edges[i].x),
sfnt_coerce_fixed (edges[i].top),
sfnt_coerce_fixed (edges[i].bottom),
- edges[i].winding);
+ edges[i].winding,
+ sfnt_coerce_fixed (edges[i].step_x),
+ sfnt_coerce_fixed (edges[i].source_x),
+ edges[i].source_x);
#ifdef TEST_VERTEX
printf ("ctx.fillRect (%g, %g, 1, 1);\n",
sfnt_coerce_fixed (edges[i].x),
sfnt_coerce_fixed (sfnt_test_max
- edges[i].y));
+#else
+ printf ("ctx.fillRect (%g, %g, 1, 1);\n",
+ sfnt_coerce_fixed (edges[i].x),
+ sfnt_coerce_fixed (sfnt_test_max
+ - edges[i].bottom));
#endif
}
for (y = 0; y < raster->height; ++y)
{
for (x = 0; x < raster->width; ++x)
- printf ("%3d ", (int) raster->cells[y * raster->width + x]);
+ printf ("%3d ", (int) raster->cells[y * raster->stride + x]);
puts ("");
}
}
/* Time this important bit. */
clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start);
outline = sfnt_build_glyph_outline (glyph, head,
- 40,
+ 45,
sfnt_test_get_glyph,
sfnt_test_free_glyph,
&dcontext);
sfnt_build_outline_edges (outline, sfnt_test_edge,
NULL);
+ raster = NULL;
+
clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start);
- raster = sfnt_raster_glyph_outline (outline);
+
+ for (i = 0; i < 400; ++i)
+ {
+ xfree (raster);
+ raster = sfnt_raster_glyph_outline (outline);
+ }
+
clock_gettime (CLOCK_THREAD_CPUTIME_ID, &end);
sub2 = timespec_sub (end, start);
/* Print out the raster. */
sfnt_test_raster (raster);
+ printf ("raster offsets: %d, %d\n",
+ raster->offx, raster->offy);
xfree (raster);
if (hmtx && head)
{
- if (!sfnt_lookup_glyph_metrics (code, 40,
+ if (!sfnt_lookup_glyph_metrics (code, 36,
&metrics,
hmtx, hhea,
head, maxp))
printf ("time spent building edges: %lld sec %ld nsec\n",
(long long) sub1.tv_sec, sub1.tv_nsec);
printf ("time spent rasterizing: %lld sec %ld nsec\n",
- (long long) sub2.tv_sec, sub2.tv_nsec);
+ (long long) sub2.tv_sec / 400, sub2.tv_nsec / 400);
xfree (outline);
}
/* Rectangle defining bounds of the outline. Namely, the minimum
and maximum X and Y positions. */
sfnt_fixed xmin, ymin, xmax, ymax;
+
+ /* Reference count. Initially zero. */
+ short refcount;
};
enum sfnt_glyph_outline_flags
SFNT_GLYPH_OUTLINE_LINETO = (1 << 1),
};
-struct sfnt_build_glyph_outline_context
-{
- /* The outline being built. */
- struct sfnt_glyph_outline *outline;
-
- /* The head table. */
- struct sfnt_head_table *head;
-
- /* The pixel size being used, and any extra flags to apply to the
- outline at this point. */
- int pixel_size;
-
- /* Factor to multiply positions by to get the pixel width. */
- double factor;
-
- /* The position of the pen in 16.16 fixed point format. */
- sfnt_fixed x, y;
-};
-
\f
/* Glyph rasterization. */
struct sfnt_raster
{
+ /* Pointer to coverage data. */
+ unsigned char *cells;
+
/* Basic dimensions of the raster. */
unsigned short width, height;
/* Integer offset to apply to positions in the raster. */
- unsigned short offx, offy;
+ short offx, offy;
- /* Pointer to coverage data. */
- unsigned char *cells;
+ /* The raster stride. */
+ unsigned short stride;
+
+ /* Reference count. Initially zero. */
+ unsigned short refcount;
};
struct sfnt_edge
/* X position, top and bottom of edges. */
sfnt_fixed x, top, bottom;
- /* step_x is how many pixels to move for each increase in Y. */
+ /* step_x is how many pixels to move for each increase in Y by
+ SFNT_POLY_STEP. */
sfnt_fixed step_x;
+
+#ifdef TEST
+ /* Value of x before initial adjustment of bottom to match the
+ grid. */
+ sfnt_fixed source_x;
+#endif
};
\f
\f
+#define SFNT_CEIL_FIXED(fixed) \
+ (!((fixed) & 0177777) ? (fixed) \
+ : ((fixed) + 0200000) & 037777600000)
+
+\f
+
/* Function declarations. Keep these sorted by the order in which
they appear in sfnt.c. Keep each line no longer than 80
columns. */
int, struct sfnt_offset_subtable *, \
struct sfnt_cmap_encoding_subtable **, \
struct sfnt_cmap_encoding_subtable_data ***
-static struct sfnt_cmap_table *sfnt_read_cmap_table (PROTOTYPE);
+extern struct sfnt_cmap_table *sfnt_read_cmap_table (PROTOTYPE);
#undef PROTOTYPE
+extern sfnt_glyph sfnt_lookup_glyph (sfnt_char,
+ struct sfnt_cmap_encoding_subtable_data *);
+
#define PROTOTYPE int, struct sfnt_offset_subtable *
extern struct sfnt_head_table *sfnt_read_head_table (PROTOTYPE);
extern struct sfnt_hhea_table *sfnt_read_hhea_table (PROTOTYPE);
extern struct sfnt_glyph *sfnt_read_glyph (sfnt_glyph, struct sfnt_glyf_table *,
struct sfnt_loca_table_short *,
struct sfnt_loca_table_long *);
+extern void sfnt_free_glyph (struct sfnt_glyph *);
#define PROTOTYPE \
struct sfnt_glyph *, \
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <config.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <android/api-level.h>
#include "androidterm.h"
#include "sfntfont.h"
+#include "pdumper.h"
+#include "blockinput.h"
+#include "android.h"
+
+/* Array of directories to search for system fonts. */
+const char *system_font_directories[] =
+ {
+ "/system/fonts",
+ };
+
+/* The font cache. */
+static Lisp_Object font_cache;
+
+\f
+
+static unsigned int
+sfntfont_android_saturate32 (unsigned int a, unsigned int b)
+{
+ unsigned int c;
+
+ c = a + b;
+
+ if (c < a)
+ c = -1;
+
+ return c;
+}
+
+/* Scale each of the four packed bytes in P in the low 16 bits of P by
+ SCALE. Return the result.
+
+ SCALE is an integer between 0 and 256. */
+
+static unsigned int
+sfntfont_android_scale32 (unsigned int scale, unsigned int p)
+{
+ uint32_t ag, rb;
+ uint32_t scaled_ag, scaled_rb;
+
+ ag = (p & 0xFF00FF00) >> 8;
+ rb = (p & 0x00FF00FF);
+
+ scaled_ag = (scale * ag) & 0xFF00FF00;
+ scaled_rb = (scale * rb) >> 8 & 0x00FF00FF;
+
+ return scaled_ag | scaled_rb;
+}
+
+static unsigned int
+sfntfont_android_mul8x2 (unsigned int a8, unsigned int b32)
+{
+ unsigned int i;
+
+ b32 &= 0xff00ff;
+ i = a8 * b32 + 0x800080;
+
+ return (i + ((i >> 8) & 0xff00ff)) >> 8 & 0xff00ff;
+}
+
+/* Blend two pixels SRC and DST without utilizing any control flow.
+ SRC must be in premultiplied ARGB8888 format, and DST must be in
+ premultiplied ABGR8888 format. Value is in premultiplied ABGR8888
+ format. */
+
+static unsigned int
+sfntfont_android_blend (unsigned int src, unsigned int dst)
+{
+ unsigned int a, br_part, ag_part, src_rb, both;
+
+ a = (src >> 24);
+ br_part = sfntfont_android_mul8x2 (255 - a, dst);
+ ag_part = sfntfont_android_mul8x2 (255 - a, dst >> 8) << 8;
+
+ both = ag_part | br_part;
+
+ /* Swizzle src. */
+ src_rb = src & 0x00ff00ff;
+ src = src & ~0x00ff00ff;
+ src |= (src_rb >> 16 | src_rb << 16);
+
+ /* Saturating is unnecessary but helps find bugs. */
+ return sfntfont_android_saturate32 (both, src);
+}
+
+#define U255TO256(x) ((unsigned short) (x) + ((x) >> 7))
+
+/* Blend two pixels SRC and DST without utilizing any control flow.
+ Both SRC and DST are expected to be in premultiplied ARGB8888
+ format. Value is returned in premultiplied ARGB8888 format. */
+
+static unsigned int
+sfntfont_android_blendrgb (unsigned int src, unsigned int dst)
+{
+ unsigned int a, rb_part, ag_part, both;
+
+ a = (src >> 24);
+ rb_part = sfntfont_android_mul8x2 (255 - a, dst);
+ ag_part = sfntfont_android_mul8x2 (255 - a, dst >> 8) << 8;
+
+ both = ag_part | rb_part;
+
+ /* Saturating is unnecessary but helps find bugs. */
+ return sfntfont_android_saturate32 (both, src);
+}
+
+/* Composite the bitmap described by BUFFER, STRIDE and TEXT_RECTANGLE
+ onto the native-endian ABGR8888 bitmap described by DEST and
+ BITMAP_INFO. RECT is the subset of the bitmap to composite. */
+
+static void
+sfntfont_android_composite_bitmap (unsigned char *restrict buffer,
+ size_t stride,
+ unsigned char *restrict dest,
+ AndroidBitmapInfo *bitmap_info,
+ struct android_rectangle *text_rectangle,
+ struct android_rectangle *rect)
+{
+ unsigned int *src_row;
+ unsigned int *dst_row;
+ unsigned int i, src_y, x, src_x, max_x, dst_x;
+
+ if ((intptr_t) dest & 3 || bitmap_info->stride & 3)
+ /* This shouldn't be possible as Android is supposed to align the
+ bitmap to at least a 4 byte boundary. */
+ emacs_abort ();
+ else
+ {
+ for (i = 0; i < rect->height; ++i)
+ {
+ if (i + rect->y >= bitmap_info->height)
+ /* Done. */
+ return;
+
+ src_y = i + (rect->y - text_rectangle->y);
+
+ src_row = (unsigned int *) ((buffer + src_y * stride));
+ dst_row = (unsigned int *) (dest + ((i + rect->y)
+ * bitmap_info->stride));
+
+ /* Figure out where the loop below should end. */
+ max_x = min (rect->width, bitmap_info->width - rect->x);
+
+ /* Keep this loop simple! */
+ for (x = 0; x < max_x; ++x)
+ {
+ src_x = x + (rect->x - text_rectangle->x);
+ dst_x = x + rect->x;
+
+ dst_row[dst_x]
+ = sfntfont_android_blend (src_row[src_x],
+ dst_row[dst_x]);
+ }
+ }
+ }
+}
+
+/* Calculate the union containing both A and B, both boxes. Place the
+ result in RESULT. */
+
+static void
+sfntfont_android_union_boxes (struct gui_box a, struct gui_box b,
+ struct gui_box *result)
+{
+ result->x1 = min (a.x1, b.x1);
+ result->y1 = min (a.y1, b.y1);
+ result->x2 = max (a.x2, b.x2);
+ result->y2 = max (a.y2, b.y2);
+}
+
+/* Draw the specified glyph rasters from FROM to TO on behalf of S,
+ using S->gc. Fill the background if WITH_BACKGROUND is true.
+
+ See init_sfntfont_vendor and sfntfont_draw for more details. */
+
+static void
+sfntfont_android_put_glyphs (struct glyph_string *s, int from,
+ int to, int x, int y, bool with_background,
+ struct sfnt_raster **rasters,
+ int *x_coords)
+{
+ struct android_rectangle background, text_rectangle, rect;
+ struct gui_box text, character;
+ unsigned int *buffer, *row;
+ unsigned char *restrict raster_row;
+ size_t stride, i;
+ AndroidBitmapInfo bitmap_info;
+ unsigned char *bitmap_data;
+ jobject bitmap;
+ int left, top, temp_y;
+ unsigned int prod, raster_y;
+
+ if (!s->gc->num_clip_rects)
+ /* Clip region is empty. */
+ return;
+
+ if (from == to)
+ /* Nothing to draw. */
+ return;
+
+ USE_SAFE_ALLOCA;
+
+ prepare_face_for_display (s->f, s->face);
+
+ /* Build the scanline buffer. Figure out the bounds of the
+ background. */
+ memset (&background, 0, sizeof background);
+
+ if (with_background)
+ {
+ background.x = x;
+ background.y = y - FONT_BASE (s->font);
+ background.width = s->width;
+ background.height = FONT_HEIGHT (s->font);
+ }
+
+ /* Now figure out the bounds of the text. */
+
+ if (rasters[0])
+ {
+ text.x1 = x_coords[0] + rasters[0]->offx;
+ text.x2 = text.x1 + rasters[0]->width;
+ text.y1 = y - (rasters[0]->height + rasters[0]->offy);
+ text.y2 = y - rasters[0]->offy;
+ }
+ else
+ memset (&text, 0, sizeof text);
+
+ for (i = 1; i < to - from; ++i)
+ {
+ /* See if text has to be extended. */
+
+ if (!rasters[i])
+ continue;
+
+ character.x1 = x_coords[i] + rasters[i]->offx;
+ character.x2 = character.x1 + rasters[i]->width;
+ character.y1 = y - (rasters[i]->height + rasters[i]->offy);
+ character.y2 = y - rasters[i]->offy;
+
+ sfntfont_android_union_boxes (text, character, &text);
+ }
+
+ /* Union the background rect with the text rectangle. */
+ text_rectangle.x = text.x1;
+ text_rectangle.y = text.y1;
+ text_rectangle.width = text.x2 - text.x1;
+ text_rectangle.height = text.y2 - text.y1;
+ gui_union_rectangles (&background, &text_rectangle,
+ &text_rectangle);
+
+ /* Allocate enough to hold text_rectangle.height, aligned to 8
+ bytes. Then fill it with the background. */
+ stride = (text_rectangle.width * sizeof *buffer) + 7 & ~7;
+ SAFE_NALLOCA (buffer, text_rectangle.height, stride);
+ memset (buffer, 0, text_rectangle.height * stride);
+
+ if (with_background)
+ {
+ /* Fill the background. First, offset the background rectangle
+ to become relative from text_rectangle.x,
+ text_rectangle.y. */
+ background.x = background.x - text_rectangle.x;
+ background.y = background.y - text_rectangle.y;
+ eassert (background.x >= 0 && background.y >= 0);
+
+ for (temp_y = background.y; (temp_y
+ < (background.y
+ + background.height));
+ ++temp_y)
+ {
+ row = (unsigned int *) ((unsigned char *) buffer
+ + stride * temp_y);
+
+ for (x = background.x; x < background.x + background.width; ++x)
+ row[x] = s->gc->background | 0xff000000;
+ }
+ }
+
+ /* Draw all the rasters onto the buffer. */
+ for (i = 0; i < to - from; ++i)
+ {
+ if (!rasters[i])
+ continue;
+
+ /* Figure out the top and left of the raster relative to
+ text_rectangle. */
+ left = x_coords[i] + rasters[i]->offx - text_rectangle.x;
+
+ /* Note that negative offy represents the part of the text that
+ lies below the baseline. */
+ top = (y - (rasters[i]->height + rasters[i]->offy)
+ - text_rectangle.y);
+ eassert (left >= 0 && top >= 0);
+
+ /* Draw the raster onto the temporary bitmap using the
+ foreground color scaled by the alpha map. */
+
+ for (raster_y = 0; raster_y < rasters[i]->height; ++raster_y)
+ {
+ row = (unsigned int *) ((unsigned char *) buffer
+ + stride * (raster_y + top));
+ raster_row = &rasters[i]->cells[raster_y * rasters[i]->stride];
+
+ for (x = 0; x < rasters[i]->width; ++x)
+ {
+ prod
+ = sfntfont_android_scale32 (U255TO256 (raster_row[x]),
+ (s->gc->foreground
+ | 0xff000000));
+ row[left + x]
+ = sfntfont_android_blendrgb (prod, row[left + x]);
+ }
+ }
+ }
+
+ /* Lock the bitmap. It must be unlocked later. */
+ bitmap_data = android_lock_bitmap (FRAME_ANDROID_WINDOW (s->f),
+ &bitmap_info, &bitmap);
+
+ /* If locking the bitmap fails, just discard the data that was
+ allocated. */
+ if (!bitmap_data)
+ {
+ SAFE_FREE ();
+ return;
+ }
+
+ /* Loop over each clip rect in the GC. */
+ eassert (bitmap_info.format == ANDROID_BITMAP_FORMAT_RGBA_8888);
+
+ if (s->gc->num_clip_rects > 0)
+ {
+ for (i = 0; i < s->gc->num_clip_rects; ++i)
+ {
+ if (!gui_intersect_rectangles (&s->gc->clip_rects[i],
+ &text_rectangle, &rect))
+ /* Outside the clip region. */
+ continue;
+
+ /* Composite the intersection onto the buffer. */
+ sfntfont_android_composite_bitmap ((unsigned char *) buffer,
+ stride, bitmap_data,
+ &bitmap_info,
+ &text_rectangle, &rect);
+ }
+ }
+ else /* gc->num_clip_rects < 0 */
+ sfntfont_android_composite_bitmap ((unsigned char *) buffer,
+ stride, bitmap_data,
+ &bitmap_info,
+ &text_rectangle,
+ &text_rectangle);
+
+ /* Release the bitmap. */
+ AndroidBitmap_unlockPixels (android_java_env, bitmap);
+ ANDROID_DELETE_LOCAL_REF (bitmap);
+
+ /* Damage the window by the text rectangle. */
+ android_damage_window (FRAME_ANDROID_WINDOW (s->f),
+ &text_rectangle);
+
+ /* Release the temporary scanline buffer. */
+ SAFE_FREE ();
+}
+
+\f
+
+/* Font driver definition. */
+
+/* Return the font cache for this font driver. F is ignored. */
+
+static Lisp_Object
+sfntfont_android_get_cache (struct frame *f)
+{
+ return font_cache;
+}
+
+/* The Android sfntfont driver. */
+const struct font_driver android_sfntfont_driver =
+ {
+ .type = LISPSYM_INITIALLY (Qsfnt_android),
+ .case_sensitive = true,
+ .get_cache = sfntfont_android_get_cache,
+ .list = sfntfont_list,
+ .match = sfntfont_match,
+ .draw = sfntfont_draw,
+ .open_font = sfntfont_open,
+ .close_font = sfntfont_close,
+ .encode_char = sfntfont_encode_char,
+ .text_extents = sfntfont_text_extents,
+ .list_family = sfntfont_list_family,
+
+ /* TODO: list_family, shaping. */
+ };
+
+\f
+
+/* This is an ugly hack that should go away, but I can't think of
+ how. */
+
+DEFUN ("android-enumerate-fonts", Fandroid_enumerate_fonts,
+ Sandroid_enumerate_fonts, 0, 0, 0,
+ doc: /* Enumerate fonts present on the system.
+
+Signal an error if fonts have already been enumerated. This would
+normally have been done in C, but reading fonts require Lisp to be
+loaded before character sets are made available. */)
+ (void)
+{
+ DIR *dir;
+ int i;
+ struct dirent *dirent;
+ char name[PATH_MAX * 2];
+ static bool enumerated;
+
+ if (enumerated)
+ error ("Fonts have already been enumerated");
+ enumerated = true;
+
+ block_input ();
+
+ /* Scan through each of the system font directories. Enumerate each
+ font that looks like a TrueType font. */
+ for (i = 0; i < ARRAYELTS (system_font_directories); ++i)
+ {
+ dir = opendir (system_font_directories[i]);
+
+ if (!dir)
+ continue;
+
+ while ((dirent = readdir (dir)))
+ {
+ /* If it contains (not ends with!) with .ttf, then enumerate
+ it. */
+
+ if (strstr (dirent->d_name, ".ttf"))
+ {
+ sprintf (name, "%s/%s", system_font_directories[i],
+ dirent->d_name);
+ sfnt_enum_font (name);
+ }
+ }
+
+ closedir (dir);
+ }
+
+ unblock_input ();
+
+ return Qnil;
+}
+
+\f
+
+static void
+syms_of_sfntfont_android_for_pdumper (void)
+{
+ init_sfntfont_vendor (Qsfnt_android, &android_sfntfont_driver,
+ sfntfont_android_put_glyphs);
+ register_font_driver (&android_sfntfont_driver, NULL);
+}
void
init_sfntfont_android (void)
{
-
+ /* Make sure to pick the right Sans Serif font depending on what
+ version of Android the device is running. */
+ if (android_get_device_api_level () >= 15)
+ Vsfnt_default_family_alist
+ = list2 (Fcons (build_string ("Monospace"),
+ build_string ("Droid Sans Mono")),
+ Fcons (build_string ("Sans Serif"),
+ build_string ("Roboto")));
+ else
+ Vsfnt_default_family_alist
+ = list2 (Fcons (build_string ("Monospace"),
+ build_string ("Droid Sans Mono")),
+ Fcons (build_string ("Sans Serif"),
+ build_string ("Droid Sans")));
}
void
syms_of_sfntfont_android (void)
{
+ DEFSYM (Qsfnt_android, "sfnt-android");
+ DEFSYM (Qandroid_enumerate_fonts, "android-enumerate-fonts");
+ Fput (Qandroid, Qfont_driver_superseded_by, Qsfnt_android);
+
+ font_cache = list (Qnil);
+ staticpro (&font_cache);
+
+ defsubr (&Sandroid_enumerate_fonts);
+ pdumper_do_now_and_after_load (syms_of_sfntfont_android_for_pdumper);
}
#include <config.h>
+#include <fcntl.h>
+
#include "lisp.h"
-#include "sfnt.h"
+
+#include "blockinput.h"
+#include "charset.h"
#include "coding.h"
+#include "font.h"
+#include "frame.h"
+#include "math.h"
+#include "sfnt.h"
+#include "sfntfont.h"
+
+/* For FRAME_FONT. */
+#include TERM_HEADER
/* Generic font driver for sfnt-based fonts (currently TrueType, but
- it would be easy to add CFF support in the future.)
+ it would be easy to add CFF support in the future with a PostScript
+ renderer.)
This is not a complete font driver. Hooks must be supplied by the
platform implementer to draw glyphs. */
/* Style name of the font. */
Lisp_Object style;
+ /* Designer (foundry) of the font. */
+ Lisp_Object designer;
+
/* Numeric width, weight, slant and spacing. */
int width, weight, slant, spacing;
/* Path to the font file. */
char *path;
+
+ /* char table consisting of characters already known to be
+ present in the font. */
+ Lisp_Object char_cache;
+
+ /* Whether or not the character map can't be used by Emacs. */
+ bool cmap_invalid;
+
+ /* The header of the cmap being used. May be invalid, in which case
+ platform_id will be 500. */
+ struct sfnt_cmap_encoding_subtable subtable;
};
/* List of fonts. */
case SFNT_PLATFORM_MICROSOFT:
system = Qutf_16be;
- /* FIXME will someone look at the MS spec and see if this
- right. */
- if (platform_specific_id
- == SFNT_MICROSOFT_BIG_FIVE)
+ /* Not sure if this is right. */
+ if (platform_specific_id == SFNT_MICROSOFT_BIG_FIVE)
system = Qchinese_big5;
break;
+
+ default:
+ system = Qnil;
}
if (NILP (system))
return 1;
setup_coding_system (system, coding);
+ return 0;
}
/* Globals used to communicate inside the condition-case wrapper. */
static bool sfnt_font_signal;
static Lisp_Object
-sfnt_safe_encode_coding_object_1 (void)
+sfnt_safe_decode_coding_object_1 (void)
{
- encode_coding_object (sfnt_font_coding,
+ decode_coding_object (sfnt_font_coding,
sfnt_font_src_object,
sfnt_font_from,
sfnt_font_from_byte,
}
static Lisp_Object
-sfnt_safe_encode_coding_object_2 (void)
+sfnt_safe_decode_coding_object_2 (Lisp_Object error)
{
sfnt_font_signal = true;
return Qnil;
}
-/* Like encode_coding_object, but return 1 if a signal happens. Value
+/* Like decode_coding_object, but return 1 if a signal happens. Value
is otherwise 0. */
static int
-sfnt_safe_encode_coding_object (struct coding_system *coding,
+sfnt_safe_decode_coding_object (struct coding_system *coding,
Lisp_Object src_object,
ptrdiff_t from, ptrdiff_t from_byte,
ptrdiff_t to, ptrdiff_t to_byte,
sfnt_font_dst_object = dst_object;
sfnt_font_signal = false;
- internal_condition_case (sfnt_safe_encode_coding_object_1,
+ internal_condition_case (sfnt_safe_decode_coding_object_1,
Qt,
- sfnt_safe_encode_coding_object_2);
+ sfnt_safe_decode_coding_object_2);
return (int) sfnt_font_signal;
}
coding.common_flags &= ~CODING_ANNOTATION_MASK;
coding.source = data;
- if (sfnt_safe_encode_coding_object (&coding, Qnil, 0, 0,
- 0, 0, length, length,
- Qnil))
+ if (sfnt_safe_decode_coding_object (&coding, Qnil, 0, 0,
+ length, length, Qt))
return Qnil;
return coding.dst_object;
return (!NILP (*family) && !NILP (*style)) ? 0 : 1;
}
+/* Decode the foundry names from the name table NAME. Return the
+ foundry name, or nil upon failure. */
+
+static Lisp_Object
+sfnt_decode_foundry_name (struct sfnt_name_table *name)
+{
+ struct sfnt_name_record designer_rec;
+ unsigned char *designer_data;
+
+ designer_data = sfnt_find_name (name, SFNT_NAME_DESIGNER,
+ &designer_rec);
+
+ if (!designer_data)
+ return Qnil;
+
+ return sfnt_decode_font_string (designer_data,
+ designer_rec.platform_id,
+ designer_rec.platform_specific_id,
+ designer_rec.language_id,
+ designer_rec.length);
+}
+
struct sfnt_style_desc
{
/* The C string to match against. */
};
/* Array of style descriptions describing weight. */
-static struct sfnt_style_desc sfnt_weight_descriptions =
+static struct sfnt_style_desc sfnt_weight_descriptions[] =
{
{ "thin", 0, },
{ "extralight", 40, },
};
/* Array of style descriptions describing slant. */
-static struct sfnt_style_desc sfnt_slant_descriptions =
+static struct sfnt_style_desc sfnt_slant_descriptions[] =
{
- { "italic", 100, },
- { "oblique", 110, },
+ { "italic", 200, },
+ { "oblique", 210, },
};
/* Array of style descriptions describing width. */
-static struct sfnt_width_desc sfnt_width_descriptions =
+static struct sfnt_style_desc sfnt_width_descriptions[] =
{
{ "ultracondensed", 50, },
{ "extracondensed", 63, },
};
/* Figure out DESC->width, DESC->weight, DESC->slant and DESC->spacing
- based on the style name passed as STYLE. */
+ based on the style name passed as STYLE_NAME. */
static void
-sfnt_parse_style (Lisp_Object style, struct sfnt_font_desc *desc)
+sfnt_parse_style (Lisp_Object style_name, struct sfnt_font_desc *desc)
{
- char *style, single, *saveptr;
+ char *style, *single, *saveptr;
int i;
- /* Fill in default values. */
+ /* Fill in default values. slant seems to not be consistent with
+ Fontconfig. */
desc->weight = 80;
- desc->slant = 0;
+ desc->slant = 100;
desc->width = 100;
/* Split the style into spaces. As long as no weight, slant, or
width is encountered, look in the corresponding descriptions
array. GC must not happen inside this block. */
- style = SSDATA (Fdowncase (style));
+ style = SSDATA (Fdowncase (style_name));
saveptr = NULL;
while ((single = strtok_r (style, " ", &saveptr)))
}
}
- if (!desc->slant)
+ if (desc->slant == 100)
{
/* Slant hasn't been found yet. Scan through the slant
table. */
for (i = 0; i < ARRAYELTS (sfnt_slant_descriptions); ++i)
{
- if (!strcmp (sfnt_weight_descriptions[i].c_string,
+ if (!strcmp (sfnt_slant_descriptions[i].c_string,
single))
{
/* Slant found. Continue on reading the weight and
width. */
- desc->slant = sfnt_weight_descriptions[i].value;
+ desc->slant = sfnt_slant_descriptions[i].value;
goto next;
}
}
{
/* Width found. Continue on reading the slant and
weight. */
- desc->slant = sfnt_width_descriptions[i].value;
+ desc->width = sfnt_width_descriptions[i].value;
goto next;
}
}
next:
/* Break early if everything has been found. */
- if (desc->slant && desc->width != 100 && desc->weight != 80)
+ if (desc->slant != 100 && desc->width != 100 && desc->weight != 80)
break;
continue;
memcpy (desc->path, file, strlen (file) + 1);
/* Now open the font for reading. */
- fd = emacs_open (file, O_RDWR);
+ fd = emacs_open (file, O_RDONLY, 0);
+
+ if (fd == -1)
+ goto bail;
/* Read the table directory. */
subtables = sfnt_read_table_directory (fd);
/* Set the family. */
desc->family = family;
+ desc->designer = sfnt_decode_foundry_name (name);
+ desc->char_cache = Qnil;
+ desc->subtable.platform_id = 500;
/* Parse the style. */
sfnt_parse_style (style, desc);
xfree (subtables);
bail0:
emacs_close (fd);
+ bail:
+ xfree (desc);
return 1;
}
\f
-void
-syms_of_sfntfont (void)
+/* Font discovery and matching. */
+
+static struct charset *
+sfntfont_charset_for_name (Lisp_Object symbol)
{
- DEFSYM (Qutf_16be, "utf-16be");
- DEFSYM (Qmac_roman, "mac-roman");
+ ptrdiff_t idx;
+ int id;
+
+ idx = CHARSET_SYMBOL_HASH_INDEX (symbol);
+
+ if (idx == -1)
+ return NULL;
+
+ /* Vcharset_hash_table is not a real variable, so Lisp programs
+ can't clobber it. */
+ id = XFIXNUM (AREF (HASH_VALUE (XHASH_TABLE (Vcharset_hash_table),
+ idx),
+ charset_id));
+
+ return CHARSET_FROM_ID (id);
}
-void
-mark_sfntfont (void)
+/* Return the character set corresponding to a cmap subtable SUBTABLE.
+ Value is NULL if the subtable is not supported. */
+
+static struct charset *
+sfntfont_charset_for_cmap (struct sfnt_cmap_encoding_subtable subtable)
{
- struct sfnt_font_desc *desc;
+ switch (subtable.platform_id)
+ {
+ case SFNT_PLATFORM_UNICODE:
+ /* Reject variation selector and last resort tables. */
+ if ((subtable.platform_specific_id
+ == SFNT_UNICODE_VARIATION_SEQUENCES)
+ || (subtable.platform_specific_id
+ == SFNT_UNICODE_LAST_RESORT))
+ return NULL;
- /* Mark each font desc. */
- for (desc = system_fonts; ++desc; desc = desc->next)
+ /* 1.0, 1.1, ISO-10646-1993, and 2.0_BMP tables are all within
+ the BMP. */
+ if (subtable.platform_specific_id < SFNT_UNICODE_2_0)
+ return sfntfont_charset_for_name (Qunicode_bmp);
+
+ return sfntfont_charset_for_name (Qunicode);
+
+ case SFNT_PLATFORM_MACINTOSH:
+
+ switch (subtable.platform_specific_id)
+ {
+ case SFNT_MACINTOSH_ROMAN:
+ return sfntfont_charset_for_name (Qmac_roman);
+
+ default:
+ /* Some other Macintosh charset not supported by Emacs. */
+ return NULL;
+ }
+
+ case SFNT_PLATFORM_MICROSOFT:
+
+ /* Microsoft specific encodings. */
+
+ switch (subtable.platform_specific_id)
+ {
+ case SFNT_MICROSOFT_SYMBOL:
+ /* Symbols in the Unicode PUA are still Unicode. */
+ return sfntfont_charset_for_name (Qunicode);
+
+ case SFNT_MICROSOFT_UNICODE_BMP:
+ return sfntfont_charset_for_name (Qunicode_bmp);
+
+ case SFNT_MICROSOFT_SHIFT_JIS:
+ /* PCK aka japanese-jisx0208. */
+ return sfntfont_charset_for_name (Qjapanese_jisx0208);
+
+ case SFNT_MICROSOFT_PRC:
+ /* GBK, GB2312 or GB18030. */
+ return sfntfont_charset_for_name (Qgbk);
+
+ case SFNT_MICROSOFT_JOHAB:
+ /* KS C 5601-1992, aka korean-ksc5601. */
+ return sfntfont_charset_for_name (Qkorean_ksc5601);
+
+ case SFNT_MICROSOFT_UNICODE_UCS_4:
+ /* Unicode past the BMP. */
+ return sfntfont_charset_for_name (Qucs);
+ }
+
+ default:
+ return NULL;
+ }
+}
+
+/* Return the type of characters that the cmap subtable SUBTABLE maps
+ from. Value is:
+
+ 2 if SUBTABLE maps from Unicode characters, including those outside
+ the Unicode Basic Multilingual Plane (BMP).
+
+ 1 if SUBTABLE maps from Unicode characters within the BMP.
+
+ 0 if SUBTABLE maps from some other character set that Emacs knows
+ about.
+
+ 3 if SUBTABLE cannot be used by Emacs. */
+
+static int
+sfntfont_identify_cmap (struct sfnt_cmap_encoding_subtable subtable)
+{
+ switch (subtable.platform_id)
{
- mark_object (desc->family);
- mark_object (desc->style);
+ case SFNT_PLATFORM_UNICODE:
+
+ /* Reject variation selector and last resort tables. */
+ if ((subtable.platform_specific_id
+ == SFNT_UNICODE_VARIATION_SEQUENCES)
+ || (subtable.platform_specific_id
+ == SFNT_UNICODE_LAST_RESORT))
+ return 3;
+
+ /* 1.0, 1.1, ISO-10646-1993, and 2.0_BMP tables are all within
+ the BMP. */
+ if (subtable.platform_specific_id < SFNT_UNICODE_2_0)
+ return 1;
+
+ return 2;
+
+ case SFNT_PLATFORM_MACINTOSH:
+
+ switch (subtable.platform_specific_id)
+ {
+ case SFNT_MACINTOSH_ROMAN:
+ /* mac-roman */
+ return 0;
+
+ default:
+ /* Some other Macintosh charset not supported by Emacs. */
+ return 3;
+ }
+
+ case SFNT_PLATFORM_MICROSOFT:
+
+ /* Microsoft specific encodings. */
+
+ switch (subtable.platform_specific_id)
+ {
+ case SFNT_MICROSOFT_SYMBOL:
+ /* Symbols in the Unicode PUA are still Unicode. */
+ return 1;
+
+ case SFNT_MICROSOFT_UNICODE_BMP:
+ return 1;
+
+ case SFNT_MICROSOFT_SHIFT_JIS:
+ /* PCK aka japanese-jisx0208. */
+ return 0;
+
+ case SFNT_MICROSOFT_PRC:
+ /* GBK, GB2312 or GB18030. */
+ return 0;
+
+ case SFNT_MICROSOFT_JOHAB:
+ /* KS C 5601-1992, aka korean-ksc5601. */
+ return 0;
+
+ case SFNT_MICROSOFT_UNICODE_UCS_4:
+ /* Unicode past the BMP. */
+ return 2;
+ }
+
+ default:
+ return 3;
+ }
+}
+
+/* Pick the best character map in the cmap table CMAP. Use the
+ subtables in SUBTABLES and DATA. Return the subtable data and the
+ subtable in *SUBTABLE upon success, NULL otherwise. */
+
+static struct sfnt_cmap_encoding_subtable_data *
+sfntfont_select_cmap (struct sfnt_cmap_table *cmap,
+ struct sfnt_cmap_encoding_subtable *subtables,
+ struct sfnt_cmap_encoding_subtable_data **data,
+ struct sfnt_cmap_encoding_subtable *subtable)
+{
+ int i;
+
+ /* First look for a non-BMP Unicode cmap. */
+
+ for (i = 0; i < cmap->num_subtables; ++i)
+ {
+ if (data[i] && sfntfont_identify_cmap (subtables[i]) == 2)
+ {
+ *subtable = subtables[i];
+ return data[i];
+ }
+ }
+
+ /* Next, look for a BMP only Unicode cmap. */
+
+ for (i = 0; i < cmap->num_subtables; ++i)
+ {
+ if (data[i] && sfntfont_identify_cmap (subtables[i]) == 1)
+ {
+ *subtable = subtables[i];
+ return data[i];
+ }
+ }
+
+ /* Finally, use the first cmap that appears and can be
+ identified. */
+
+ for (i = 0; i < cmap->num_subtables; ++i)
+ {
+ if (data[i] && sfntfont_identify_cmap (subtables[i]) == 0)
+ {
+ *subtable = subtables[i];
+ return data[i];
+ }
+ }
+
+ /* There are no cmaps available to Emacs. */
+ return NULL;
+}
+
+/* Read the cmap from the font descriptor DESC, and place it in CMAP.
+ Keep *CMAP untouched if opening the cmap fails. Set SUBTABLE to
+ the cmap's header upon success. */
+
+static void
+sfntfont_read_cmap (struct sfnt_font_desc *desc,
+ struct sfnt_cmap_encoding_subtable_data **cmap,
+ struct sfnt_cmap_encoding_subtable *subtable)
+{
+ struct sfnt_offset_subtable *font;
+ struct sfnt_cmap_encoding_subtable *subtables;
+ struct sfnt_cmap_encoding_subtable_data **data;
+ struct sfnt_cmap_table *table;
+ int fd, i;
+
+ /* Pick a character map and place it in *CMAP. */
+ fd = emacs_open (desc->path, O_RDONLY, 0);
+
+ if (fd < 1)
+ return;
+
+ font = sfnt_read_table_directory (fd);
+
+ if (!font)
+ {
+ close (fd);
+ return;
+ }
+
+ table = sfnt_read_cmap_table (fd, font, &subtables,
+ &data);
+ xfree (font);
+
+ if (!table)
+ {
+ close (fd);
+ return;
+ }
+
+ /* Now pick the best character map. */
+
+ *cmap = sfntfont_select_cmap (table, subtables, data,
+ subtable);
+
+ /* Free the cmap data. */
+
+ for (i = 0; i < table->num_subtables; ++i)
+ {
+ if (data[i] != *cmap)
+ xfree (data[i]);
+ }
+
+ xfree (data);
+ xfree (subtables);
+ xfree (table);
+}
+
+/* Look up a character CHARACTER in the font description DESC. Cache
+ the results. Return true if the character exists, false otherwise.
+
+ If *CMAP is NULL, select a character map for the font and save it
+ there. Otherwise, use the character map in *CMAP. Save data
+ associated with the character map in *SUBTABLE. */
+
+static bool
+sfntfont_lookup_char (struct sfnt_font_desc *desc, Lisp_Object character,
+ struct sfnt_cmap_encoding_subtable_data **cmap,
+ struct sfnt_cmap_encoding_subtable *subtable)
+{
+ Lisp_Object cached;
+ sfnt_char font_character;
+ struct charset *charset;
+ bool present;
+
+ /* Return false for characters that don't fit in a char table. */
+ if (XFIXNUM (character) > INT_MAX || XFIXNUM (character) < 0)
+ return false;
+
+ if (!NILP (desc->char_cache))
+ {
+ cached = char_table_ref (desc->char_cache,
+ XFIXNUM (character));
+ if (!NILP (cached))
+ return (EQ (cached, Qlambda) ? false : true);
+ }
+
+ if (!*cmap && !desc->cmap_invalid)
+ sfntfont_read_cmap (desc, cmap, subtable);
+
+ /* Check that a cmap is now present. */
+ if (!*cmap)
+ {
+ /* Opening the cmap failed. Set desc->cmap_invalid to avoid
+ opening it again. */
+ desc->cmap_invalid = true;
+ return false;
+ }
+
+ /* Otherwise, encode the character. */
+
+ charset = sfntfont_charset_for_cmap (*subtable);
+ if (!charset)
+ /* Emacs missing charsets? */
+ return false;
+
+ font_character = ENCODE_CHAR (charset, XFIXNUM (character));
+
+ if (font_character == CHARSET_INVALID_CODE (charset))
+ return false;
+
+ /* Now return whether or not the glyph is present. */
+ present = sfnt_lookup_glyph (font_character, *cmap) != 0;
+
+ /* Cache the result. Store Qlambda when not present, Qt
+ otherwise. */
+
+ if (NILP (desc->char_cache))
+ desc->char_cache = Fmake_char_table (Qfont_lookup_cache,
+ Qnil);
+
+ Fset_char_table_range (desc->char_cache, character,
+ present ? Qt : Qlambda);
+ return present;
+}
+
+/* Return whether or not the font description DESC satisfactorily
+ matches the font specification FONT_SPEC. */
+
+static bool
+sfntfont_list_1 (struct sfnt_font_desc *desc, Lisp_Object spec)
+{
+ Lisp_Object tem, extra, tail;
+ struct sfnt_cmap_encoding_subtable_data *cmap;
+ size_t i;
+ struct sfnt_cmap_encoding_subtable subtable;
+
+ /* cmap and subtable are caches for sfntfont_lookup_char. */
+
+ /* Check that the family name in SPEC matches DESC->family if it is
+ specified. */
+
+ tem = AREF (spec, FONT_FAMILY_INDEX);
+
+ /* If TEM is a family listed in Vsfnt_default_family_alist,
+ then use that instead. */
+
+ if (SYMBOLP (tem) && CONSP (Vsfnt_default_family_alist))
+ {
+ tail = Vsfnt_default_family_alist;
+ FOR_EACH_TAIL_SAFE (tail)
+ {
+ if (!CONSP (XCAR (tail)))
+ continue;
+
+ if (STRINGP (XCAR (XCAR (tail)))
+ && STRINGP (XCDR (XCAR (tail)))
+ && Fstring_equal (SYMBOL_NAME (tem),
+ XCAR (XCAR (tail))))
+ {
+ /* Special family found. */
+ tem = Fintern (XCDR (XCAR (tail)), Qnil);
+ break;
+ }
+ }
+ }
+
+ if (!NILP (tem) && NILP (Fstring_equal (SYMBOL_NAME (tem),
+ desc->family)))
+ return false;
+
+ /* Check that no adstyle has been specified. That's a relic from
+ the Postscript era. */
+
+ tem = AREF (spec, FONT_ADSTYLE_INDEX);
+ if (!NILP (tem))
+ return false;
+
+ /* Check the style. */
+
+ if (FONT_WIDTH_NUMERIC (spec) != -1
+ && FONT_WIDTH_NUMERIC (spec) != desc->width)
+ return false;
+
+ if (FONT_WEIGHT_NUMERIC (spec) != -1
+ && FONT_WEIGHT_NUMERIC (spec) != desc->weight)
+ return false;
+
+ if (FONT_SLANT_NUMERIC (spec) != -1
+ && FONT_SLANT_NUMERIC (spec) != desc->slant)
+ return false;
+
+ /* Handle extras. */
+ extra = AREF (spec, FONT_EXTRA_INDEX);
+
+ if (NILP (extra))
+ return true;
+
+ tem = assq_no_quit (QCscript, extra);
+ cmap = NULL;
+
+ if (!NILP (tem))
+ {
+ /* If a script has been specified, look up its representative
+ characters and see if they are present in the font. This
+ requires reading the cmap. */
+ tem = assq_no_quit (XCDR (tem), Vscript_representative_chars);
+
+ if (CONSP (tem) && VECTORP (XCDR (tem)))
+ {
+ tem = XCDR (tem);
+
+ /* The vector contains characters, of which one must be
+ present in the font. */
+ for (i = 0; i < ASIZE (tem); ++i)
+ {
+ if (FIXNUMP (AREF (tem, i)))
+ {
+ if (!sfntfont_lookup_char (desc, AREF (tem, i),
+ &cmap, &subtable))
+ goto fail;
+
+ /* One character is enough to pass a font. Don't
+ look at too many. */
+ break;
+ }
+ }
+ }
+ else if (CONSP (tem) && CONSP (XCDR (tem)))
+ {
+ tem = XCDR (tem);
+
+ /* tem is a list of each characters, one of which must be
+ present in the font. */
+ FOR_EACH_TAIL_SAFE (tem)
+ {
+ if (FIXNUMP (XCAR (tem)))
+ {
+ if (!sfntfont_lookup_char (desc, XCAR (tem), &cmap,
+ &subtable))
+ goto fail;
+
+ /* One character is enough to pass a font. Don't
+ look at too many. */
+ break;
+ }
+ }
+ }
+ }
+
+ /* Set desc->subtable if cmap was specified. */
+ if (cmap)
+ desc->subtable = subtable;
+
+ xfree (cmap);
+ return true;
+
+ fail:
+ /* The cmap might've been read in and require deallocation. */
+ xfree (cmap);
+ return false;
+}
+
+/* Type of font entities and font objects created. */
+static Lisp_Object sfnt_vendor_name;
+
+/* Font driver used in font objects created. */
+static const struct font_driver *sfnt_font_driver;
+
+/* Return the font registry corresponding to the font descriptor DESC.
+ Under X, the font registry is an atom registered with the Open
+ Group uniquely identifying the organization which defines the
+ font's character set.
+
+ In practice, the registry overlaps with the character set itself.
+ So Emacs just uses the ``registry'' field to represent both
+ instead. */
+
+static Lisp_Object
+sfntfont_registry_for_desc (struct sfnt_font_desc *desc)
+{
+ struct sfnt_cmap_encoding_subtable_data *cmap;
+
+ cmap = NULL;
+
+ if (desc->cmap_invalid)
+ return Qnil;
+
+ if (desc->subtable.platform_id == 500)
+ {
+ /* Read in the cmap to determine the registry. */
+ sfntfont_read_cmap (desc, &cmap, &desc->subtable);
+
+ if (!cmap)
+ {
+ desc->cmap_invalid = true;
+ return Qnil;
+ }
+ }
+
+ xfree (cmap);
+
+ if (desc->subtable.platform_id != 500)
+ {
+ /* desc->subtable.platform_id is now set. CMAP is already free,
+ because it is not actually used. */
+
+ switch (desc->subtable.platform_id)
+ {
+ case SFNT_PLATFORM_UNICODE:
+ /* Reject variation selector and last resort tables. */
+ if ((desc->subtable.platform_specific_id
+ == SFNT_UNICODE_VARIATION_SEQUENCES)
+ || (desc->subtable.platform_specific_id
+ == SFNT_UNICODE_LAST_RESORT))
+ return Qnil;
+
+ return Qiso10646_1;
+
+ case SFNT_PLATFORM_MACINTOSH:
+
+ switch (desc->subtable.platform_specific_id)
+ {
+ case SFNT_MACINTOSH_ROMAN:
+ /* X calls mac-roman ``apple-roman''. */
+ return Qapple_roman;
+
+ default:
+ /* Some other Macintosh charset not supported by Emacs. */
+ return Qnil;
+ }
+
+ case SFNT_PLATFORM_MICROSOFT:
+
+ /* Microsoft specific encodings. */
+
+ switch (desc->subtable.platform_specific_id)
+ {
+ case SFNT_MICROSOFT_SYMBOL:
+ case SFNT_MICROSOFT_UNICODE_BMP:
+ /* Symbols in the Unicode PUA are still Unicode. */
+ return Qiso10646_1;
+
+ case SFNT_MICROSOFT_SHIFT_JIS:
+ return Qjisx0208_1983_0;
+
+ case SFNT_MICROSOFT_PRC:
+ return Qgbk;
+
+ case SFNT_MICROSOFT_JOHAB:
+ return Qksc5601_1987_0;
+
+ case SFNT_MICROSOFT_UNICODE_UCS_4:
+ return Qiso10646_1;
+ }
+
+ default:
+ return Qnil;
+ }
}
+
+ return Qnil;
+}
+
+/* Return a font-entity that represents the font descriptor (unopened
+ font) DESC. */
+
+static Lisp_Object
+sfntfont_desc_to_entity (struct sfnt_font_desc *desc)
+{
+ Lisp_Object entity;
+
+ entity = font_make_entity ();
+
+ ASET (entity, FONT_TYPE_INDEX, sfnt_vendor_name);
+
+ if (!NILP (desc->designer))
+ ASET (entity, FONT_FOUNDRY_INDEX,
+ Fintern (desc->designer, Qnil));
+
+ ASET (entity, FONT_FAMILY_INDEX, Fintern (desc->family, Qnil));
+ ASET (entity, FONT_ADSTYLE_INDEX, Qnil);
+ ASET (entity, FONT_REGISTRY_INDEX,
+ sfntfont_registry_for_desc (desc));
+
+ /* Size of 0 means the font is scalable. */
+ ASET (entity, FONT_SIZE_INDEX, make_fixnum (0));
+ ASET (entity, FONT_AVGWIDTH_INDEX, make_fixnum (0));
+ ASET (entity, FONT_SPACING_INDEX,
+ make_fixnum (desc->spacing));
+
+ FONT_SET_STYLE (entity, FONT_WIDTH_INDEX,
+ make_fixnum (desc->width));
+ FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
+ make_fixnum (desc->weight));
+ FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
+ make_fixnum (desc->slant));
+
+ ASET (entity, FONT_ADSTYLE_INDEX, Qnil);
+
+ /* Set FONT_EXTRA_INDEX to a pointer to the font description. Font
+ descriptions are never supposed to be freed. */
+ ASET (entity, FONT_EXTRA_INDEX,
+ list1 (Fcons (Qfont_entity, make_mint_ptr (desc))));
+
+ return entity;
+}
+
+/* Return a list of font-entities matching the specified
+ FONT_SPEC. */
+
+Lisp_Object
+sfntfont_list (struct frame *f, Lisp_Object font_spec)
+{
+ Lisp_Object matching, tem;
+ struct sfnt_font_desc *desc;
+
+ matching = Qnil;
+
+ block_input ();
+ /* Returning irrelevant results on receiving an OTF form will cause
+ fontset.c to loop over and over, making displaying some
+ characters very slow. */
+ tem = assq_no_quit (QCotf, AREF (font_spec, FONT_EXTRA_INDEX));
+ if (CONSP (tem) && !NILP (XCDR (tem)))
+ {
+ unblock_input ();
+ return Qnil;
+ }
+
+ /* Loop through known system fonts and add them one-by-one. */
+ for (desc = system_fonts; desc; desc = desc->next)
+ {
+ if (sfntfont_list_1 (desc, font_spec))
+ matching = Fcons (sfntfont_desc_to_entity (desc), matching);
+ }
+
+ unblock_input ();
+
+ return matching;
+}
+
+/* Return the first font-entity matching the specified FONT_SPEC. */
+
+Lisp_Object
+sfntfont_match (struct frame *f, Lisp_Object font_spec)
+{
+ Lisp_Object matches;
+
+ matches = sfntfont_list (f, font_spec);
+
+ if (!NILP (matches))
+ return XCAR (matches);
+
+ return Qnil;
+}
+
+\f
+
+enum
+ {
+ SFNT_OUTLINE_CACHE_SIZE = 128,
+ SFNT_RASTER_CACHE_SIZE = 100,
+ };
+
+/* Caching subsystem. Generating outlines from glyphs is expensive,
+ and so is rasterizing them, so two caches are maintained for both
+ glyph outlines and rasters. */
+
+struct sfnt_outline_cache
+{
+ /* Next and last cache buckets. */
+ struct sfnt_outline_cache *next, *last;
+
+ /* Pointer to outline. */
+ struct sfnt_glyph_outline *outline;
+
+ /* What glyph this caches. */
+ sfnt_glyph glyph;
+};
+
+struct sfnt_raster_cache
+{
+ /* Next and last cache buckets. */
+ struct sfnt_raster_cache *next, *last;
+
+ /* Pointer to raster. */
+ struct sfnt_raster *raster;
+
+ /* What glyph this caches. */
+ sfnt_glyph glyph;
+};
+
+struct sfntfont_get_glyph_outline_dcontext
+{
+ /* Long and short loca tables. */
+ struct sfnt_loca_table_long *loca_long;
+ struct sfnt_loca_table_short *loca_short;
+
+ /* glyf table. */
+ struct sfnt_glyf_table *glyf;
+};
+
+/* Return the glyph identified by GLYPH from the glyf and loca table
+ specified in DCONTEXT. Set *NEED_FREE to true. */
+
+static struct sfnt_glyph *
+sfntfont_get_glyph (sfnt_glyph glyph, void *dcontext,
+ bool *need_free)
+{
+ struct sfntfont_get_glyph_outline_dcontext *tables;
+
+ tables = dcontext;
+ *need_free = true;
+
+ return sfnt_read_glyph (glyph, tables->glyf,
+ tables->loca_short,
+ tables->loca_long);
+}
+
+/* Free the glyph identified by GLYPH. */
+
+static void
+sfntfont_free_glyph (struct sfnt_glyph *glyph, void *dcontext)
+{
+ sfnt_free_glyph (glyph);
+}
+
+/* Dereference the outline OUTLINE. Free it once refcount reaches
+ 0. */
+
+static void
+sfntfont_dereference_outline (struct sfnt_glyph_outline *outline)
+{
+ eassert (outline->refcount > 0);
+
+ if (--outline->refcount)
+ return;
+
+ xfree (outline);
+}
+
+/* Get the outline corresponding to the specified GLYPH_CODE in CACHE.
+ Use the pixel size PIXEL_SIZE, the glyf table GLYF, and the head
+ table HEAD. Keep *CACHE_SIZE updated with the number of elements
+ in the cache.
+
+ Use the offset information in the long or short loca tables
+ LOCA_LONG and LOCA_SHORT, whichever is set.
+
+ Return the outline with an incremented reference count and enter
+ the generated outline into CACHE upon success, possibly discarding
+ any older outlines, or NULL on failure. */
+
+static struct sfnt_glyph_outline *
+sfntfont_get_glyph_outline (sfnt_glyph glyph_code,
+ struct sfnt_outline_cache *cache,
+ int pixel_size, int *cache_size,
+ struct sfnt_glyf_table *glyf,
+ struct sfnt_head_table *head,
+ struct sfnt_loca_table_short *loca_short,
+ struct sfnt_loca_table_long *loca_long)
+{
+ struct sfnt_outline_cache *start;
+ struct sfnt_glyph_outline *outline;
+ struct sfnt_glyph *glyph;
+ struct sfntfont_get_glyph_outline_dcontext dcontext;
+
+ start = cache->next;
+
+ /* See if the outline is already cached. */
+ for (; start != cache; start = start->next)
+ {
+ if (start->glyph == glyph_code)
+ {
+ /* Move start to the start of the ring. Then increase
+ start->outline->refcount and return it. */
+
+ start->last->next = start->next;
+ start->next->last = start->last;
+
+ start->next = cache->next;
+ start->last = cache;
+ start->next->last = start;
+ start->last->next = start;
+ start->outline->refcount++;
+
+ return start->outline;
+ }
+ }
+
+ /* Not already cached. Get the glyph. */
+ glyph = sfnt_read_glyph (glyph_code, glyf,
+ loca_short, loca_long);
+
+ if (!glyph)
+ return NULL;
+
+ dcontext.loca_long = loca_long;
+ dcontext.loca_short = loca_short;
+ dcontext.glyf = glyf;
+
+ outline = sfnt_build_glyph_outline (glyph, head, pixel_size,
+ sfntfont_get_glyph,
+ sfntfont_free_glyph,
+ &dcontext);
+ xfree (glyph);
+
+ if (!outline)
+ return NULL;
+
+ start = xmalloc (sizeof *start);
+ start->glyph = glyph_code;
+ start->outline = outline;
+
+ /* One reference goes to the cache. The second reference goes to
+ the caller. */
+ outline->refcount = 2;
+
+ /* Link start onto the cache. */
+ start->next = cache->next;
+ start->last = cache;
+ start->next->last = start;
+ start->last->next = start;
+
+ /* Update the cache size. */
+ (*cache_size)++;
+
+ /* Figure out if the least recently used element has to be
+ evicted. */
+ if (*cache_size > SFNT_OUTLINE_CACHE_SIZE)
+ {
+ start = cache->last;
+ eassert (start != cache);
+
+ /* Free the least recently used entry in the cache. */
+ start->last->next = start->next;
+ start->next->last = start->last;
+ sfntfont_dereference_outline (start->outline);
+ xfree (start);
+
+ (*cache_size)--;
+ }
+
+ /* Return the cached outline. */
+ return outline;
+}
+
+/* Free the outline cache referred to by CACHE. Dereference each
+ outline contained therein. */
+
+static void
+sfntfont_free_outline_cache (struct sfnt_outline_cache *cache)
+{
+ struct sfnt_outline_cache *next, *last;
+
+ /* Handle partly initialized fonts. */
+ if (!cache->next)
+ return;
+
+ for (next = cache->next; next != cache;)
+ {
+ last = next;
+ next = next->next;
+
+ sfntfont_dereference_outline (last->outline);
+ xfree (last);
+ }
+}
+
+/* Dereference the raster RASTER. Free it once refcount reaches
+ 0. */
+
+static void
+sfntfont_dereference_raster (struct sfnt_raster *raster)
+{
+ eassert (raster->refcount > 0);
+
+ if (--raster->refcount)
+ return;
+
+ xfree (raster);
+}
+
+/* Get the raster corresponding to the specified GLYPH_CODE in CACHE.
+ Use the outline named OUTLINE. Keep *CACHE_SIZE updated with the
+ number of elements in the cache. */
+
+static struct sfnt_raster *
+sfntfont_get_glyph_raster (sfnt_glyph glyph_code,
+ struct sfnt_raster_cache *cache,
+ struct sfnt_glyph_outline *outline,
+ int *cache_size)
+{
+ struct sfnt_raster_cache *start;
+ struct sfnt_raster *raster;
+
+ /* See if the raster is already cached. */
+ start = cache->next;
+
+ for (; start != cache; start = start->next)
+ {
+ if (start->glyph == glyph_code)
+ {
+ /* Move start to the start of the ring. Them, increase
+ start->raster->refcount and return it. */
+
+ start->last->next = start->next;
+ start->next->last = start->last;
+
+ start->next = cache->next;
+ start->last = cache;
+ start->next->last = start;
+ start->last->next = start;
+ start->raster->refcount++;
+
+ return start->raster;
+ }
+ }
+
+ /* Not already cached. Raster the outline. */
+ raster = sfnt_raster_glyph_outline (outline);
+
+ if (!raster)
+ return NULL;
+
+ start = xmalloc (sizeof *start);
+ start->glyph = glyph_code;
+ start->raster = raster;
+
+ /* One reference goes to the cache. The second reference goes to
+ the caller. */
+ raster->refcount = 2;
+
+ /* Link start onto the cache. */
+ start->next = cache->next;
+ start->last = cache;
+ start->next->last = start;
+ start->last->next = start;
+
+ /* Update the cache size. */
+ (*cache_size)++;
+
+ /* Figure out if the least recently used element has to be
+ evicted. */
+ if (*cache_size > SFNT_OUTLINE_CACHE_SIZE)
+ {
+ start = cache->last;
+ eassert (start != cache);
+
+ /* Free the least recently used entry in the cache. */
+ start->last->next = start->next;
+ start->next->last = start->last;
+ sfntfont_dereference_raster (start->raster);
+ xfree (start);
+
+ (*cache_size)--;
+ }
+
+ /* Return the cached raster. */
+ return raster;
+}
+
+/* Free the raster cache referred to by CACHE. Dereference each
+ raster contained therein. */
+
+static void
+sfntfont_free_raster_cache (struct sfnt_raster_cache *cache)
+{
+ struct sfnt_raster_cache *next, *last;
+
+ /* Handle partly initialized fonts. */
+ if (!cache->next)
+ return;
+
+ for (next = cache->next; next != cache;)
+ {
+ last = next;
+ next = next->next;
+
+ sfntfont_dereference_raster (last->raster);
+ xfree (last);
+ }
+}
+
+\f
+
+/* Opening fonts. */
+
+struct sfnt_font_info
+{
+ /* Parent font structure. */
+ struct font font;
+
+ /* Various tables required to use the font. */
+ struct sfnt_cmap_table *cmap;
+ struct sfnt_hhea_table *hhea;
+ struct sfnt_maxp_table *maxp;
+ struct sfnt_head_table *head;
+ struct sfnt_hmtx_table *hmtx;
+ struct sfnt_glyf_table *glyf;
+ struct sfnt_loca_table_short *loca_short;
+ struct sfnt_loca_table_long *loca_long;
+
+ /* The selected character map. */
+ struct sfnt_cmap_encoding_subtable_data *cmap_data;
+
+ /* Data identifying that character map. */
+ struct sfnt_cmap_encoding_subtable cmap_subtable;
+
+ /* Outline cache. */
+ struct sfnt_outline_cache outline_cache;
+
+ /* Number of elements in the outline cache. */
+ int outline_cache_size;
+
+ /* Raster cache. */
+ struct sfnt_raster_cache raster_cache;
+
+ /* Number of elements in the raster cache. */
+ int raster_cache_size;
+};
+
+/* Look up the glyph corresponding to the character C in FONT. Return
+ 0 upon failure, and the glyph otherwise. */
+
+static sfnt_glyph
+sfntfont_lookup_glyph (struct sfnt_font_info *font_info, int c)
+{
+ struct charset *charset;
+ sfnt_char character;
+ sfnt_glyph glyph;
+
+ charset = CHARSET_FROM_ID (font_info->font.encoding_charset);
+
+ if (!charset)
+ return 0;
+
+ character = ENCODE_CHAR (charset, c);
+
+ if (character == CHARSET_INVALID_CODE (charset))
+ return 0;
+
+ /* Do the actual lookup with the encoded character. */
+ glyph = sfnt_lookup_glyph (character, font_info->cmap_data);
+
+ return glyph;
+}
+
+/* Probe and set FONT_INFO->font.average_width,
+ FONT_INFO->font.space_width, and FONT_INFO->font.min_width
+ according to the tables contained therein. */
+
+static void
+sfntfont_probe_widths (struct sfnt_font_info *font_info)
+{
+ int i, num_characters, total_width;
+ sfnt_glyph glyph;
+ struct sfnt_glyph_metrics metrics;
+
+ num_characters = 0;
+ total_width = 0;
+
+ /* First set some reasonable default values. */
+ font_info->font.average_width = font_info->font.pixel_size;
+ font_info->font.space_width = font_info->font.pixel_size;
+ font_info->font.min_width = 1;
+
+ /* Next, loop through the common ASCII characters. Tally up their
+ advance widths and set space_width if necessary. */
+ for (i = 0; i < 127; ++i)
+ {
+ glyph = sfntfont_lookup_glyph (font_info, i);
+
+ if (!glyph)
+ continue;
+
+ /* Now look up the metrics of this glyph. */
+ if (sfnt_lookup_glyph_metrics (glyph, font_info->font.pixel_size,
+ &metrics, font_info->hmtx,
+ font_info->hhea, font_info->head,
+ font_info->maxp))
+ continue;
+
+ /* Increase the number of characters. */
+ num_characters++;
+
+ /* Add the advance to total_width. */
+ total_width += metrics.advance >> 16;
+
+ /* Update min_width if it hasn't been set yet or is wider. */
+ if (font_info->font.min_width == 1
+ || font_info->font.min_width > metrics.advance >> 16)
+ font_info->font.min_width = metrics.advance >> 16;
+
+ /* If i is the space character, set the space width. Make sure
+ to round this up. */
+ if (i == 32)
+ font_info->font.space_width
+ = SFNT_CEIL_FIXED (metrics.advance) >> 16;
+ }
+
+ /* Now, if characters were found, set average_width. */
+ if (num_characters)
+ font_info->font.average_width = total_width / num_characters;
+}
+
+/* Open the font corresponding to the font-entity FONT_ENTITY. Return
+ nil upon failure, else the opened font-object. */
+
+Lisp_Object
+sfntfont_open (struct frame *f, Lisp_Object font_entity,
+ int pixel_size)
+{
+ struct sfnt_font_info *font_info;
+ struct font *font;
+ struct sfnt_font_desc *desc;
+ Lisp_Object font_object;
+ int fd, i;
+ struct sfnt_offset_subtable *subtable;
+ struct sfnt_cmap_encoding_subtable *subtables;
+ struct sfnt_cmap_encoding_subtable_data **data;
+ struct charset *charset;
+
+ if (XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)) != 0)
+ pixel_size = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX));
+ else if (pixel_size == 0)
+ {
+ /* This bit was copied from xfont.c. The values might need
+ adjustment. */
+
+ if (FRAME_FONT (f))
+ pixel_size = FRAME_FONT (f)->pixel_size;
+ else
+ pixel_size = 12;
+ }
+
+ /* Now find the font description corresponding to FONT_ENTITY. */
+
+ if (NILP (AREF (font_entity, FONT_EXTRA_INDEX)))
+ return Qnil;
+
+ desc = xmint_pointer (XCDR (XCAR (AREF (font_entity, FONT_EXTRA_INDEX))));
+
+ /* Build the font object. */
+ font_object = font_make_object (VECSIZE (struct sfnt_font_info),
+ font_entity, pixel_size);
+ font_info = (struct sfnt_font_info *) XFONT_OBJECT (font_object);
+
+ block_input ();
+
+ /* Initialize all the font driver specific data. */
+
+ font_info->cmap = NULL;
+ font_info->hhea = NULL;
+ font_info->maxp = NULL;
+ font_info->head = NULL;
+ font_info->glyf = NULL;
+ font_info->hmtx = NULL;
+ font_info->loca_short = NULL;
+ font_info->loca_long = NULL;
+ font_info->cmap_data = NULL;
+
+ font_info->outline_cache.next = &font_info->outline_cache;
+ font_info->outline_cache.last = &font_info->outline_cache;
+ font_info->outline_cache_size = 0;
+ font_info->raster_cache.next = &font_info->raster_cache;
+ font_info->raster_cache.last = &font_info->raster_cache;
+ font_info->raster_cache_size = 0;
+
+ /* Open the font. */
+ fd = emacs_open (desc->path, O_RDONLY, 0);
+
+ if (fd == -1)
+ goto bail;
+
+ /* Read the offset subtable. */
+ subtable = sfnt_read_table_directory (fd);
+
+ if (!subtable)
+ goto bail1;
+
+ /* Read required tables. This font backend is supposed to be used
+ mostly on devices with flash memory, so the order in which they
+ are read is insignificant. */
+
+ /* Select a character map table. */
+ font_info->cmap = sfnt_read_cmap_table (fd, subtable, &subtables,
+ &data);
+ if (!font_info->cmap)
+ goto bail2;
+
+ font_info->cmap_data
+ = sfntfont_select_cmap (font_info->cmap,
+ subtables, data,
+ &font_info->cmap_subtable);
+
+ for (i = 0; i < font_info->cmap->num_subtables; ++i)
+ {
+ if (data[i] != font_info->cmap_data)
+ xfree (data[i]);
+ }
+
+ xfree (subtables);
+ xfree (data);
+
+ if (!font_info->cmap_data)
+ goto bail3;
+
+ /* Read the hhea, maxp, glyf, and head tables. */
+ font_info->hhea = sfnt_read_hhea_table (fd, subtable);
+ font_info->maxp = sfnt_read_maxp_table (fd, subtable);
+ font_info->glyf = sfnt_read_glyf_table (fd, subtable);
+ font_info->head = sfnt_read_head_table (fd, subtable);
+
+ /* If any of those tables couldn't be read, bail. */
+ if (!font_info->hhea || !font_info->maxp || !font_info->glyf
+ || !font_info->head)
+ goto bail4;
+
+ /* Now figure out which kind of loca table must be read based on
+ head->index_to_loc_format. */
+ font_info->loca_short = NULL;
+ font_info->loca_long = NULL;
+
+ if (font_info->head->index_to_loc_format)
+ {
+ font_info->loca_long
+ = sfnt_read_loca_table_long (fd, subtable);
+
+ if (!font_info->loca_long)
+ goto bail4;
+ }
+ else
+ {
+ font_info->loca_short
+ = sfnt_read_loca_table_short (fd, subtable);
+
+ if (!font_info->loca_short)
+ goto bail4;
+ }
+
+ /* Read the horizontal metrics table. */
+ font_info->hmtx = sfnt_read_hmtx_table (fd, subtable,
+ font_info->hhea,
+ font_info->maxp);
+ if (!font_info->hmtx)
+ goto bail5;
+
+ /* Fill in font data. */
+ font = &font_info->font;
+ font->pixel_size = pixel_size;
+ font->driver = sfnt_font_driver;
+ font->encoding_charset = font->repertory_charset = -1;
+
+ /* Figure out which character set to use. */
+ charset = sfntfont_charset_for_cmap (font_info->cmap_subtable);
+
+ if (!charset)
+ goto bail6;
+
+ /* Set the character set IDs. */
+ font->encoding_charset = charset->id;
+ font->repertory_charset = charset->id;
+
+ /* Figure out the font ascent and descent. */
+ font->ascent
+ = ceil (font_info->hhea->ascent
+ * pixel_size * 1.0 / font_info->head->units_per_em);
+ font->descent
+ = -floor (font_info->hhea->descent
+ * pixel_size * 1.0 / font_info->head->units_per_em);
+ font->height = font->ascent + font->descent;
+
+ /* Set generic attributes such as type and style. */
+ ASET (font_object, FONT_TYPE_INDEX, sfnt_vendor_name);
+
+ if (!NILP (desc->designer))
+ ASET (font_object, FONT_FOUNDRY_INDEX,
+ Fintern (desc->designer, Qnil));
+
+ ASET (font_object, FONT_FAMILY_INDEX, Fintern (desc->family, Qnil));
+ ASET (font_object, FONT_ADSTYLE_INDEX, Qnil);
+ ASET (font_object, FONT_REGISTRY_INDEX,
+ sfntfont_registry_for_desc (desc));
+
+ /* Size of 0 means the font is scalable. */
+ ASET (font_object, FONT_SIZE_INDEX, make_fixnum (0));
+ ASET (font_object, FONT_AVGWIDTH_INDEX, make_fixnum (0));
+ ASET (font_object, FONT_SPACING_INDEX,
+ make_fixnum (desc->spacing));
+
+ FONT_SET_STYLE (font_object, FONT_WIDTH_INDEX,
+ make_fixnum (desc->width));
+ FONT_SET_STYLE (font_object, FONT_WEIGHT_INDEX,
+ make_fixnum (desc->weight));
+ FONT_SET_STYLE (font_object, FONT_SLANT_INDEX,
+ make_fixnum (desc->slant));
+
+ ASET (font_object, FONT_ADSTYLE_INDEX, Qnil);
+
+ /* Find out the minimum, maximum and average widths. */
+ sfntfont_probe_widths (font_info);
+
+ /* Clear various offsets. */
+ font_info->font.baseline_offset = 0;
+ font_info->font.relative_compose = 0;
+ font_info->font.default_ascent = 0;
+ font_info->font.vertical_centering = 0;
+ font_info->font.underline_position = -1;
+ font_info->font.underline_thickness = 0;
+
+ /* Calculate the xfld name. */
+ font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
+
+ /* All done. */
+ unblock_input ();
+ return font_object;
+
+ bail6:
+ xfree (font_info->hmtx);
+ font_info->hmtx = NULL;
+ bail5:
+ xfree (font_info->loca_long);
+ xfree (font_info->loca_short);
+ font_info->loca_long = NULL;
+ font_info->loca_short = NULL;
+ bail4:
+ xfree (font_info->hhea);
+ xfree (font_info->maxp);
+ xfree (font_info->glyf);
+ xfree (font_info->head);
+ font_info->hhea = NULL;
+ font_info->maxp = NULL;
+ font_info->glyf = NULL;
+ font_info->head = NULL;
+
+ /* This comes in bail4 due to a peculiarity of how the four tables
+ above are validated. */
+ xfree (font_info->cmap_data);
+ font_info->cmap_data = NULL;
+ bail3:
+ xfree (font_info->cmap);
+ font_info->cmap = NULL;
+ bail2:
+ xfree (subtable);
+ bail1:
+ close (fd);
+ bail:
+ unblock_input ();
+ return Qnil;
+}
+
+\f
+
+/* Metrics computation and other similar font backend functions. */
+
+/* Return the glyph code corresponding to C inside the font-object
+ FONT. Value is the glyph code upon success, else
+ FONT_INVALID_CODE. */
+
+unsigned int
+sfntfont_encode_char (struct font *font, int c)
+{
+ sfnt_glyph glyph;
+
+ /* Now look up the glyph. */
+ glyph = sfntfont_lookup_glyph ((struct sfnt_font_info *) font, c);
+
+ if (!glyph)
+ return FONT_INVALID_CODE;
+
+ return glyph;
+}
+
+/* Measure the single glyph GLYPH in the font FONT and return its
+ metrics in *PCM. Value is 0 upon success, 1 otherwise. */
+
+static int
+sfntfont_measure_pcm (struct sfnt_font_info *font, sfnt_glyph glyph,
+ struct font_metrics *pcm)
+{
+ struct sfnt_glyph_metrics metrics;
+ struct sfnt_glyph_outline *outline;
+
+ /* Get the glyph metrics first. */
+ if (sfnt_lookup_glyph_metrics (glyph, font->font.pixel_size,
+ &metrics, font->hmtx, font->hhea,
+ font->head, font->maxp))
+ return 1;
+
+ /* Now get the glyph outline, which is required to obtain the rsb,
+ ascent and descent. */
+ outline = sfntfont_get_glyph_outline (glyph, &font->outline_cache,
+ font->font.pixel_size,
+ &font->outline_cache_size,
+ font->glyf, font->head,
+ font->loca_short,
+ font->loca_long);
+
+ if (!outline)
+ return 1;
+
+ /* How to round lbearing and rbearing? */
+ pcm->lbearing = metrics.lbearing >> 16;
+ pcm->rbearing = outline->xmax >> 16;
+
+ /* Round the advance, ascent and descent upwards. */
+ pcm->width = SFNT_CEIL_FIXED (metrics.advance) >> 16;
+ pcm->ascent = SFNT_CEIL_FIXED (outline->ymax) >> 16;
+ pcm->descent = SFNT_CEIL_FIXED (-outline->ymin) >> 16;
+
+ sfntfont_dereference_outline (outline);
+ return 0;
+}
+
+/* Return the total text extents of NGLYPHS glyphs given as CODE in
+ the single font metrics array METRICS. */
+
+void
+sfntfont_text_extents (struct font *font, const unsigned int *code,
+ int nglyphs, struct font_metrics *metrics)
+{
+ int i, total_width;
+ struct font_metrics pcm;
+
+ total_width = 0;
+
+ /* Get the metrcs one by one, then sum them up. */
+ for (i = 0; i < nglyphs; ++i)
+ {
+ if (!sfntfont_measure_pcm ((struct sfnt_font_info *) font,
+ code[i], &pcm))
+ {
+ /* Add the per-char metric (PCM) to the metrics in
+ METRICS. */
+
+ if (total_width + pcm.lbearing < metrics->lbearing)
+ metrics->lbearing = total_width + pcm.lbearing;
+
+ if (total_width + pcm.rbearing > metrics->rbearing)
+ metrics->rbearing = total_width + pcm.rbearing;
+
+ if (pcm.ascent > metrics->ascent)
+ metrics->ascent = pcm.ascent;
+
+ if (pcm.descent > metrics->descent)
+ metrics->descent = pcm.descent;
+ }
+
+ total_width += pcm.width;
+ }
+
+ metrics->width = total_width;
+}
+
+/* Close the font FONT, discarding all tables inside it and
+ dereferencing all cached outlines and rasters. */
+
+void
+sfntfont_close (struct font *font)
+{
+ struct sfnt_font_info *info;
+
+ info = (struct sfnt_font_info *) font;
+ xfree (info->cmap);
+ xfree (info->hhea);
+ xfree (info->maxp);
+ xfree (info->head);
+ xfree (info->hmtx);
+ xfree (info->glyf);
+ xfree (info->loca_short);
+ xfree (info->loca_long);
+ xfree (info->cmap_data);
+
+ sfntfont_free_outline_cache (&info->outline_cache);
+ sfntfont_free_raster_cache (&info->raster_cache);
+}
+
+\f
+
+/* Glyph display. */
+
+/* Function called to actually draw rasters to the glass. */
+static sfntfont_put_glyph_proc sfnt_put_glyphs;
+
+/* Draw glyphs in S->char2b starting from FROM to TO, with the origin
+ at X and baseline at Y. Fill the background from X, Y +
+ FONT_DESCENT to X + S->background_width, Y - FONT_ASCENT with the
+ background color if necessary. Use the foreground and background
+ colors in S->gc. */
+
+int
+sfntfont_draw (struct glyph_string *s, int from, int to,
+ int x, int y, bool with_background)
+{
+ int length;
+ struct sfnt_raster **rasters;
+ int *x_coords, current_x, i;
+ struct sfnt_glyph_outline *outline;
+ struct font *font;
+ struct sfnt_font_info *info;
+ struct sfnt_glyph_metrics metrics;
+
+ length = to - from;
+ font = s->face->font;
+ info = (struct sfnt_font_info *) font;
+
+ rasters = alloca (length * sizeof *rasters);
+ x_coords = alloca (length * sizeof *x_coords);
+ current_x = x;
+
+ /* Get rasters and outlines for them. */
+ for (i = from; i < to; ++i)
+ {
+ /* Look up the metrics for this glyph. */
+ if (sfnt_lookup_glyph_metrics (s->char2b[i], font->pixel_size,
+ &metrics, info->hmtx, info->hhea,
+ info->head, info->maxp))
+ {
+ rasters[i - from] = NULL;
+ x_coords[i - from] = 0;
+ continue;
+ }
+
+ /* Look up the outline. */
+ outline = sfntfont_get_glyph_outline (s->char2b[i],
+ &info->outline_cache,
+ font->pixel_size,
+ &info->outline_cache_size,
+ info->glyf, info->head,
+ info->loca_short,
+ info->loca_long);
+ x_coords[i - from] = 0;
+
+ if (!outline)
+ {
+ rasters[i - from] = NULL;
+ continue;
+ }
+
+ /* Rasterize the outline. */
+ rasters[i - from] = sfntfont_get_glyph_raster (s->char2b[i],
+ &info->raster_cache,
+ outline,
+ &info->raster_cache_size);
+ sfntfont_dereference_outline (outline);
+
+ if (!rasters[i - from])
+ continue;
+
+ /* Now work out where to put the outline. */
+ x_coords[i - from] = current_x;
+ current_x += SFNT_CEIL_FIXED (metrics.advance) >> 16;
+ }
+
+ /* Call the window system function to put the glyphs to the
+ frame. */
+ sfnt_put_glyphs (s, from, to, x, y, with_background,
+ rasters, x_coords);
+
+ /* Dereference all the rasters. */
+ for (i = 0; i < from - to; ++i)
+ {
+ if (rasters[i])
+ sfntfont_dereference_raster (rasters[i]);
+ }
+
+ return 1;
+}
+
+\f
+
+/* Other callbacks. */
+
+/* Return a list of each font family known to Emacs. F is supposed to
+ be a frame but is ignored. */
+
+Lisp_Object
+sfntfont_list_family (struct frame *f)
+{
+ Lisp_Object families;
+ struct sfnt_font_desc *desc;
+
+ families = Qnil;
+
+ for (desc = system_fonts; desc; desc = desc->next)
+ /* Add desc->family to the list. */
+ families = Fcons (desc->family, families);
+
+ /* Not sure if deleting duplicates is worth it. Is this ever
+ called? */
+ return families;
+}
+
+\f
+
+void
+syms_of_sfntfont (void)
+{
+ DEFSYM (Qutf_16be, "utf-16be");
+ DEFSYM (Qmac_roman, "mac-roman");
+ DEFSYM (Qchinese_big5, "chinese-big5");
+ DEFSYM (Qunicode_bmp, "unicode-bmp");
+ DEFSYM (Qucs, "ucs");
+ DEFSYM (Qjapanese_jisx0208, "japanese-jisx0208");
+ DEFSYM (Qgbk, "gbk");
+ DEFSYM (Qkorean_ksc5601, "korean-ksc5601");
+ DEFSYM (Qapple_roman, "apple-roman");
+ DEFSYM (Qjisx0208_1983_0, "jisx0208.1983-0");
+ DEFSYM (Qksc5601_1987_0, "ksc5601.1987-0");
+
+ /* Char-table purpose. */
+ DEFSYM (Qfont_lookup_cache, "font-lookup-cache");
+
+ /* Set up staticpros. */
+ sfnt_vendor_name = Qnil;
+ staticpro (&sfnt_vendor_name);
+
+ /* This variable is supposed to be set by the platform specific part
+ of the font backend. */
+ DEFVAR_LISP ("sfnt-default-family-alist", Vsfnt_default_family_alist,
+ doc: /* Alist between "emulated" and actual font family names.
+
+Much Emacs code assumes that font families named "Monospace" and "Sans
+Serif" exist, and map to the default monospace and Sans Serif fonts on
+a system. When the `sfnt' font driver is asked to look for a font
+with one of the families in this alist, it uses its value instead. */);
+ Vsfnt_default_family_alist = Qnil;
+}
+
+void
+mark_sfntfont (void)
+{
+ struct sfnt_font_desc *desc;
+
+ /* Mark each font desc. */
+ for (desc = system_fonts; desc; desc = desc->next)
+ {
+ mark_object (desc->family);
+ mark_object (desc->style);
+ mark_object (desc->char_cache);
+ mark_object (desc->designer);
+ }
+}
+
+void
+init_sfntfont (void)
+{
+
+}
+
+\f
+
+/* Initialize the sfntfont font driver. VENDOR_TYPE is the type of
+ all font entities created. DRIVER is the font driver that is saved
+ in font objects. PUT_GLYPHS is a function that is called with 8
+ arguments, S, FROM, TO, X, Y, WITH_BACKGROUND, RASTERS, and
+ X_COORDS, and should draw all the rasters in RASTERS to S->f,
+ originating at X_COORDS[i], Y, along with filling the background if
+ WITH_BACKGROUND is specified. */
+
+void
+init_sfntfont_vendor (Lisp_Object vendor_name,
+ const struct font_driver *driver,
+ sfntfont_put_glyph_proc put_glyphs)
+{
+ sfnt_vendor_name = vendor_name;
+ sfnt_font_driver = driver;
+ sfnt_put_glyphs = put_glyphs;
}
#ifndef _SFNTFONT_H_
#define _SFNTFONT_H_
+#include "lisp.h"
+#include "frame.h"
+#include "font.h"
+#include "sfnt.h"
+
extern int sfnt_enum_font (const char *);
+\f
+/* Font driver callbacks. */
+
+extern Lisp_Object sfntfont_list (struct frame *, Lisp_Object);
+extern Lisp_Object sfntfont_match (struct frame *, Lisp_Object);
+extern Lisp_Object sfntfont_open (struct frame *, Lisp_Object, int);
+
+extern unsigned int sfntfont_encode_char (struct font *, int);
+extern void sfntfont_text_extents (struct font *, const unsigned int *,
+ int, struct font_metrics *);
+extern void sfntfont_close (struct font *);
+extern int sfntfont_draw (struct glyph_string *, int, int,
+ int, int, bool);
+extern Lisp_Object sfntfont_list_family (struct frame *);
+
+\f
+/* Initialization functions. */
+
+typedef void (*sfntfont_put_glyph_proc) (struct glyph_string *, int, int,
+ int, int, bool, struct sfnt_raster **,
+ int *);
+
+extern void syms_of_sfntfont (void);
+extern void init_sfntfont (void);
+extern void mark_sfntfont (void);
+extern void init_sfntfont_vendor (Lisp_Object, const struct font_driver *,
+ sfntfont_put_glyph_proc);
+
#endif /* _SFNTFONT_H_ */
return intersection_p;
}
+/* EXPORT:
+ Determine the union of the rectangles A and B. Return the smallest
+ rectangle encompassing both the bounds of A and B in *RESULT. It
+ is safe for all three arguments to point to each other. */
+
+void
+gui_union_rectangles (const Emacs_Rectangle *a, const Emacs_Rectangle *b,
+ Emacs_Rectangle *result)
+{
+ struct gui_box a_box, b_box, result_box;
+
+ /* Handle special cases where one of the rectangles is empty. */
+
+ if (!a->width || !a->height)
+ {
+ *result = *b;
+ return;
+ }
+ else if (!b->width || !b->height)
+ {
+ *result = *a;
+ return;
+ }
+
+ /* Convert A and B to boxes. */
+ a_box.x1 = a->x;
+ a_box.y1 = a->y;
+ a_box.x2 = a->x + a->width;
+ a_box.y2 = a->y + a->height;
+
+ b_box.x1 = b->x;
+ b_box.y1 = b->y;
+ b_box.x2 = b->x + b->width;
+ b_box.y2 = b->y + b->height;
+
+ /* Compute the union of the boxes. */
+ result_box.x1 = min (a_box.x1, b_box.x1);
+ result_box.y1 = min (a_box.y1, b_box.y1);
+ result_box.x2 = max (a_box.x2, b_box.x2);
+ result_box.y2 = max (a_box.y2, b_box.y2);
+
+ /* Convert result_box to an XRectangle and put the result in
+ RESULT. */
+ result->x = result_box.x1;
+ result->y = result_box.y1;
+ result->width = result_box.x2 - result_box.x1;
+ result->height = result_box.y2 - result_box.y1;
+}
+
#endif /* HAVE_WINDOW_SYSTEM */
\f