1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-09 15:50:40 -08:00

Bring up the sfnt-android font driver

* configure.ac (ANDROID_CFLAGS): Add sfnt-related font objects
to ANDROID_OBJ when not building stubs.
* lisp/startup.el (android-fonts-enumerated): New variable.
(normal-top-level): Set it.  Also enumerate fonts as early as
possible upon startup.

* src/alloc.c (cleanup_vector): Only finalize Android font
entities.
(garbage_collect): Mark sfntfont.c.

* src/android.c (struct android_emacs_drawable): New field
`damage_rect'.
(android_init_emacs_drawable): Initialize
Lorg/gnu/emacs/EmacsDrawable;#damageRect(Landroid/graphics/rect;)V.
(android_create_gc): Initialize cached GC fields.
(android_free_gc): Free cached GC clip rectangles.
(android_change_gc): Cache fields as appropriate.
(android_set_clip_rectangles): Set cached clip rectangles for
easy access from C.
(android_get_gc_values): Use cached values.
(android_get_image): Remove obsolete comment.
(android_lock_bitmap, android_damage_window): New functions that
don't parallel anything on X.

* src/android.h: Update prototypes.

* src/androidfns.c (android_default_font_parameter): Set Droid
Sans Mono as the default monospace font.
(Fx_create_frame): Register the sfntfont driver.

* src/androidgui.h (struct android_gc): Add C side caches for
clip rectangles and the foreground and background colors.

* src/androidterm.h: Update prototypes.

* src/dispextern.h (struct gui_box): New struct.
(gui_union_rectangles): New function.

* src/emacs.c (android_emacs_init): Initialize Android font
stuff late.
* src/font.c (font_make_entity): Clear `is_android' field on
Android.
(font_make_entity_android): Set `is_android' field.
* src/font.h (struct font_entity): New field `is_android'.

* src/print.c (print_vectorlike): Don't print private data,
which could include Lisp_Misc.

* src/sfnt.c (sfnt_read_cmap_format_0, sfnt_read_cmap_format_2)
(sfnt_read_cmap_format_4, sfnt_read_cmap_format_6)
(sfnt_read_cmap_format_8, sfnt_read_cmap_format_12): Remove
buggy pragmas.
(sfnt_lookup_glyph_4_1): New function.
(sfnt_lookup_glyph_4): Handle malformed lookup tables found on
Android.
(sfnt_lookup_glyph): Fix overflow problems in glyph checks.
(sfnt_read_glyph): Handle empty glyphs.  This implements some
behavior which everyone else seems to as well, but I can't find
documented in the TrueType Reference Manual.
(sfnt_free_glyph): Export correctly.
(sfnt_transform_coordinates): Make faster.
(sfnt_lerp_half): Fix lerping in some cases.
(sfnt_decompose_glyph): Handle empty glyphs correctly.  Close
contours manually instead of waiting for the edge building
process to do that.  This lets curves be handled correctly.
(struct sfnt_build_glyph_outline_context): Move internal struct
back to sfnt.c.
(sfnt_build_append): Fix detection of initial entry.
(sfnt_curve_to_and_build_1): Fix De Casteljau implementation.
(sfnt_curve_to_and_build): Use fixed point arithmetic to scale
outlines.
(sfnt_build_glyph_outline): Clear reference counts.  Use fixed
point arithmetic.
(sfnt_prepare_raster): Align rasters to 4 bytes,
SFNT_POLY_ALIGNMENT.  Fix calculation of offx and offy.
(sfnt_step_edge_by): Step edge by previously computed step_x.
(sfnt_build_outline_edges): Adjust for already closed contours.
Ignore edges abandoned after grid fit.  Also precompute step_x
to avoid multiplication on each span rastered.
(sfnt_poly_edges): Improve alignment.
(sfnt_fill_span): Rewrite to avoid control flow in while loop.
(sfnt_poly_span): Remove unnecessary code.
(sfnt_raster_glyph_outline): Use raster stride instead of width.
(sfnt_test_edge, sfnt_test_raster, main): Improve debugging
code.

* src/sfnt.h (struct sfnt_glyph_outline): Add refcount field to
outline.
(struct sfnt_build_glyph_outline_context): Remove private
struct.
(struct sfnt_raster): Add refcount field to raster.
(struct sfnt_edge): Improve doc.  Add `source_x' field used when
built with TEST.
(SFNT_CEIL_FIXED): New macro.

* src/sfntfont-android.c (sfntfont_android_saturate32)
(sfntfont_android_scale32, sfntfont_android_mul8x2)
(sfntfont_android_blend, U255TO256)
(sfntfont_android_composite_bitmap, sfntfont_android_union_boxes)
(sfntfont_android_put_glyphs, sfntfont_android_get_cache): New
functions.
(android_sfntfont_driver): New font driver.
(Fandroid_enumerate_fonts): New function.
(syms_of_sfntfont_android_for_pdumper, init_sfntfont_android)
(syms_of_sfntfont_android): Initialize default fonts, special
family mapping and font driver.
* src/sfntfont.c (struct sfnt_font_desc): New fields
`char_cache', `cmap_invalid' and `subtable'.
(sfnt_setup_coding_system): Improve commentary.  Add default
branch.  Fix return value.
(sfnt_safe_encode_coding_object_1)
(sfnt_safe_encode_coding_object_2):
(sfnt_safe_encode_coding_object): Use decode_coding_object
instead of encode_coding_object.
(sfnt_decode_font_string): Adjust for rename.
(sfnt_decode_foundry_name): New function.
(sfnt_weight_descriptions, sfnt_slant_descriptions)
(sfnt_width_descriptions): Fix definitions.
(sfnt_parse_style): Make function work.
(sfnt_enum_font): Initialize designer, char-cache and subtable
platform ID.
(sfntfont_charset_for_name, mark_sfntfont)
(sfntfont_charset_for_cmap): New functions.
(syms_of_sfntfont): New variable `sfnt-default-family-alist'.

* src/sfntfont.h (_SFNTFONT_H_): Update prototypes.

* src/xdisp.c (gui_union_rectangles): New function.
This commit is contained in:
Po Lu 2023-01-11 16:06:15 +08:00
parent 4c09b9a5a6
commit 494bedde32
19 changed files with 2958 additions and 248 deletions

View file

@ -1360,6 +1360,9 @@ AS_IF([test $gl_gcc_warnings = no],
nw="$nw -Wsync-nand" # irrelevant here, and provokes ObjC warning nw="$nw -Wsync-nand" # irrelevant here, and provokes ObjC warning
nw="$nw -Wunsafe-loop-optimizations" # OK to suppress unsafe optimizations nw="$nw -Wunsafe-loop-optimizations" # OK to suppress unsafe optimizations
nw="$nw -Wbad-function-cast" # These casts are no worse than others. 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 # Emacs doesn't care about shadowing; see
# <https://lists.gnu.org/r/emacs-diffs/2011-11/msg00265.html>. # <https://lists.gnu.org/r/emacs-diffs/2011-11/msg00265.html>.
@ -2250,12 +2253,16 @@ for Android, but all API calls need to be stubbed out])
# requires Emacs be built as a position independent executable. # requires Emacs be built as a position independent executable.
ANDROID_CFLAGS="-fPIC -fvisibility=hidden" 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. # Link with libraries required for Android support.
ANDROID_LIBS="-landroid -llog -ljnigraphics" ANDROID_LIBS="-landroid -llog -ljnigraphics"
# Link with the sfnt font library and sfntfont.o, along with # Link with the sfnt font library and sfntfont.o, along with
# sfntfont-android.o. # 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
fi fi

View file

@ -574,11 +574,24 @@ the updated value."
(setq startup--original-eln-load-path (setq startup--original-eln-load-path
(copy-sequence native-comp-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 () (defun normal-top-level ()
"Emacs calls this function when it first starts up. "Emacs calls this function when it first starts up.
It sets `command-line-processed', processes the command-line, It sets `command-line-processed', processes the command-line,
reads the initialization files, etc. reads the initialization files, etc.
It is the default value of the variable `top-level'." 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. ;; Allow disabling automatic .elc->.eln processing.
(setq inhibit-automatic-native-compilation (setq inhibit-automatic-native-compilation
(getenv "EMACS_INHIBIT_AUTOMATIC_NATIVE_COMPILATION")) (getenv "EMACS_INHIBIT_AUTOMATIC_NATIVE_COMPILATION"))

View file

@ -50,6 +50,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include TERM_HEADER #include TERM_HEADER
#endif /* HAVE_WINDOW_SYSTEM */ #endif /* HAVE_WINDOW_SYSTEM */
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
#include "sfntfont.h"
#endif
#ifdef HAVE_TREE_SITTER #ifdef HAVE_TREE_SITTER
#include "treesit.h" #include "treesit.h"
#endif #endif
@ -3346,8 +3350,9 @@ cleanup_vector (struct Lisp_Vector *vector)
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
/* The Android font driver needs the ability to associate extra /* The Android font driver needs the ability to associate extra
information with font entities. */ information with font entities. */
if ((vector->header.size & PSEUDOVECTOR_SIZE_MASK) if (((vector->header.size & PSEUDOVECTOR_SIZE_MASK)
== FONT_ENTITY_MAX) == FONT_ENTITY_MAX)
&& PSEUDOVEC_STRUCT (vector, font_entity)->is_android)
android_finalize_font_entity (PSEUDOVEC_STRUCT (vector, font_entity)); android_finalize_font_entity (PSEUDOVEC_STRUCT (vector, font_entity));
#endif #endif
} }
@ -6477,6 +6482,9 @@ garbage_collect (void)
#ifdef HAVE_ANDROID #ifdef HAVE_ANDROID
mark_androidterm (); mark_androidterm ();
#ifndef ANDROID_STUBIFY
mark_sfntfont ();
#endif
#endif #endif
#ifdef HAVE_NS #ifdef HAVE_NS

View file

@ -101,6 +101,7 @@ struct android_emacs_drawable
{ {
jclass class; jclass class;
jmethodID get_bitmap; jmethodID get_bitmap;
jmethodID damage_rect;
}; };
/* The asset manager being used. */ /* The asset manager being used. */
@ -1102,6 +1103,7 @@ android_init_emacs_drawable (void)
assert (drawable_class.c_name); assert (drawable_class.c_name);
FIND_METHOD (get_bitmap, "getBitmap", "()Landroid/graphics/Bitmap;"); FIND_METHOD (get_bitmap, "getBitmap", "()Landroid/graphics/Bitmap;");
FIND_METHOD (damage_rect, "damageRect", "(Landroid/graphics/Rect;)V");
#undef FIND_METHOD #undef FIND_METHOD
} }
@ -1743,6 +1745,12 @@ android_create_gc (enum android_gc_value_mask mask,
gc = xmalloc (sizeof *gc); gc = xmalloc (sizeof *gc);
prev_max_handle = max_handle; prev_max_handle = max_handle;
gc->gcontext = android_alloc_id (); 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) if (!gc->gcontext)
{ {
@ -1780,6 +1788,8 @@ void
android_free_gc (struct android_gc *gc) android_free_gc (struct android_gc *gc)
{ {
android_destroy_handle (gc->gcontext); android_destroy_handle (gc->gcontext);
xfree (gc->clip_rects);
xfree (gc); xfree (gc);
} }
@ -1795,16 +1805,22 @@ android_change_gc (struct android_gc *gc,
ANDROID_HANDLE_GCONTEXT); ANDROID_HANDLE_GCONTEXT);
if (mask & ANDROID_GC_FOREGROUND) if (mask & ANDROID_GC_FOREGROUND)
(*android_java_env)->SetIntField (android_java_env, {
gcontext, (*android_java_env)->SetIntField (android_java_env,
emacs_gc_foreground, gcontext,
values->foreground); emacs_gc_foreground,
values->foreground);
gc->foreground = values->foreground;
}
if (mask & ANDROID_GC_BACKGROUND) if (mask & ANDROID_GC_BACKGROUND)
(*android_java_env)->SetIntField (android_java_env, {
gcontext, (*android_java_env)->SetIntField (android_java_env,
emacs_gc_background, gcontext,
values->background); emacs_gc_background,
values->background);
gc->background = values->background;
}
if (mask & ANDROID_GC_FUNCTION) if (mask & ANDROID_GC_FUNCTION)
(*android_java_env)->SetIntField (android_java_env, (*android_java_env)->SetIntField (android_java_env,
@ -1838,6 +1854,10 @@ android_change_gc (struct android_gc *gc,
gcontext, gcontext,
emacs_gc_clip_rects, emacs_gc_clip_rects,
NULL); NULL);
xfree (gc->clip_rects);
gc->clip_rects = NULL;
gc->num_clip_rects = -1;
} }
if (mask & ANDROID_GC_STIPPLE) if (mask & ANDROID_GC_STIPPLE)
@ -1943,6 +1963,19 @@ android_set_clip_rectangles (struct android_gc *gc, int clip_x_origin,
(*android_java_env)->CallVoidMethod (android_java_env, (*android_java_env)->CallVoidMethod (android_java_env,
gcontext, gcontext,
emacs_gc_mark_dirty); 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 void
@ -2098,16 +2131,10 @@ android_get_gc_values (struct android_gc *gc,
if (mask & ANDROID_GC_FOREGROUND) if (mask & ANDROID_GC_FOREGROUND)
/* GCs never have 32 bit colors, so we don't have to worry about /* GCs never have 32 bit colors, so we don't have to worry about
sign extension here. */ sign extension here. */
values->foreground values->foreground = gc->foreground;
= (*android_java_env)->GetIntField (android_java_env,
gcontext,
emacs_gc_foreground);
if (mask & ANDROID_GC_BACKGROUND) if (mask & ANDROID_GC_BACKGROUND)
values->background values->background = gc->background;
= (*android_java_env)->GetIntField (android_java_env,
gcontext,
emacs_gc_background);
if (mask & ANDROID_GC_FUNCTION) if (mask & ANDROID_GC_FUNCTION)
values->function values->function
@ -2657,8 +2684,6 @@ android_get_image (android_drawable handle,
unsigned char *data1, *data2; unsigned char *data1, *data2;
int i, x; 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, drawable = android_resolve_handle2 (handle, ANDROID_HANDLE_WINDOW,
ANDROID_HANDLE_PIXMAP); ANDROID_HANDLE_PIXMAP);
@ -2881,6 +2906,98 @@ android_put_image (android_pixmap handle, struct android_image *image)
/* 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);
}
#undef faccessat #undef faccessat
/* Replace the system faccessat with one which understands AT_EACCESS. /* Replace the system faccessat with one which understands AT_EACCESS.

View file

@ -29,6 +29,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <pwd.h> #include <pwd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <android/bitmap.h>
#include "androidgui.h" #include "androidgui.h"
#endif #endif
@ -64,6 +66,11 @@ enum android_handle_type
extern jobject android_resolve_handle (android_handle, extern jobject android_resolve_handle (android_handle,
enum android_handle_type); 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 #endif

View file

@ -531,8 +531,7 @@ android_default_font_parameter (struct frame *f, Lisp_Object parms)
if (! FONTP (font) && ! STRINGP (font)) if (! FONTP (font) && ! STRINGP (font))
{ {
const char *names[] = { const char *names[] = {
/* This will find the normal font. The default font size on "Droid Sans Mono",
Android is 8. */
"monospace", "monospace",
"DroidSansMono", "DroidSansMono",
NULL NULL
@ -772,6 +771,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
} }
register_font_driver (&androidfont_driver, f); register_font_driver (&androidfont_driver, f);
register_font_driver (&android_sfntfont_driver, f);
image_cache_refcount = (FRAME_IMAGE_CACHE (f) image_cache_refcount = (FRAME_IMAGE_CACHE (f)
? FRAME_IMAGE_CACHE (f)->refcount ? FRAME_IMAGE_CACHE (f)->refcount

View file

@ -116,8 +116,21 @@ struct android_gc_values
struct android_gc 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. */ /* The Java-side handle. */
android_gcontext gcontext; android_gcontext gcontext;
/* Current foreground color. */
unsigned long foreground;
/* Current background color. */
unsigned long background;
}; };
enum android_swap_action enum android_swap_action

View file

@ -376,6 +376,8 @@ extern void android_finalize_font_entity (struct font_entity *);
/* Defined in sfntfont-android.c. */ /* Defined in sfntfont-android.c. */
extern const struct font_driver android_sfntfont_driver;
extern void init_sfntfont_android (void); extern void init_sfntfont_android (void);
extern void syms_of_sfntfont_android (void); extern void syms_of_sfntfont_android (void);

View file

@ -177,6 +177,22 @@ typedef void *Emacs_Cursor;
#define NativeRectangle int #define NativeRectangle int
#endif #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. */ /* Text cursor types. */
enum text_cursor_kinds enum text_cursor_kinds
@ -3525,6 +3541,9 @@ extern void expose_frame (struct frame *, int, int, int, int);
extern bool gui_intersect_rectangles (const Emacs_Rectangle *, extern bool gui_intersect_rectangles (const Emacs_Rectangle *,
const Emacs_Rectangle *, const Emacs_Rectangle *,
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); extern void gui_consider_frame_title (Lisp_Object);
#endif /* HAVE_WINDOW_SYSTEM */ #endif /* HAVE_WINDOW_SYSTEM */

View file

@ -2465,12 +2465,6 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
init_haiku_select (); init_haiku_select ();
#endif #endif
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
init_androidfont ();
init_sfntfont ();
init_sfntfont_android ();
#endif
init_charset (); init_charset ();
/* This calls putenv and so must precede init_process_emacs. */ /* This calls putenv and so must precede init_process_emacs. */
@ -2505,6 +2499,12 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
init_window (); init_window ();
init_font (); init_font ();
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
init_androidfont ();
init_sfntfont ();
init_sfntfont_android ();
#endif
if (!initialized) if (!initialized)
{ {
char *file; char *file;
@ -2559,6 +2559,16 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
safe_run_hooks (Qafter_pdump_load_hook); safe_run_hooks (Qafter_pdump_load_hook);
#endif #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. */ /* Enter editor command loop. This never returns. */
set_initial_minibuffer_mode (); set_initial_minibuffer_mode ();
Frecursive_edit (); Frecursive_edit ();

View file

@ -177,6 +177,11 @@ font_make_entity (void)
allocate_pseudovector (VECSIZE (struct font_entity), allocate_pseudovector (VECSIZE (struct font_entity),
FONT_ENTITY_MAX, FONT_ENTITY_MAX, PVEC_FONT)); FONT_ENTITY_MAX, FONT_ENTITY_MAX, PVEC_FONT));
XSETFONT (font_entity, entity); XSETFONT (font_entity, entity);
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
entity->is_android = false;
#endif
return font_entity; return font_entity;
} }
@ -190,6 +195,11 @@ font_make_entity_android (int size)
= ((struct font_entity *) = ((struct font_entity *)
allocate_pseudovector (size, FONT_ENTITY_MAX, FONT_ENTITY_MAX, allocate_pseudovector (size, FONT_ENTITY_MAX, FONT_ENTITY_MAX,
PVEC_FONT)); PVEC_FONT));
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
entity->is_android = true;
#endif
XSETFONT (font_entity, entity); XSETFONT (font_entity, entity);
return font_entity; return font_entity;
} }

View file

@ -260,6 +260,11 @@ struct font_entity
{ {
union vectorlike_header header; union vectorlike_header header;
Lisp_Object props[FONT_ENTITY_MAX]; 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 /* A value which may appear in the member `encoding' of struct font

View file

@ -1913,12 +1913,17 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
print_c_string ("#<font-entity", printcharfun); print_c_string ("#<font-entity", printcharfun);
for (int i = 0; i < FONT_SPEC_MAX; i++) for (int i = 0; i < FONT_SPEC_MAX; i++)
{ {
printchar (' ', printcharfun); /* FONT_EXTRA_INDEX can contain private information in
if (i < FONT_WEIGHT_INDEX || i > FONT_WIDTH_INDEX) font entities which isn't safe to print. */
print_object (AREF (obj, i), printcharfun, escapeflag); if (i != FONT_EXTRA_INDEX || !FONT_ENTITY_P (obj))
else {
print_object (font_style_symbolic (obj, i, 0), printchar (' ', printcharfun);
printcharfun, escapeflag); 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 else

View file

@ -34,6 +34,10 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#if defined __GNUC__ && !defined __clang__
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
#ifdef TEST #ifdef TEST
#include <time.h> #include <time.h>
@ -221,17 +225,12 @@ sfnt_read_cmap_format_0 (int fd,
format0->format = header->format; format0->format = header->format;
format0->length = header->length; format0->length = header->length;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
/* Read the rest. */ /* Read the rest. */
wanted_size = (sizeof *format0 wanted_size = (sizeof *format0
- offsetof (struct sfnt_cmap_format_0, - offsetof (struct sfnt_cmap_format_0,
language)); language));
rc = read (fd, &format0->language, wanted_size); rc = read (fd, &format0->language, wanted_size);
#pragma GCC diagnostic pop
if (rc < wanted_size) if (rc < wanted_size)
{ {
xfree (format0); xfree (format0);
@ -267,9 +266,6 @@ sfnt_read_cmap_format_2 (int fd,
format2->format = header->format; format2->format = header->format;
format2->length = header->length; format2->length = header->length;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
/* Read the part before the variable length data. */ /* Read the part before the variable length data. */
min_bytes -= offsetof (struct sfnt_cmap_format_2, language); min_bytes -= offsetof (struct sfnt_cmap_format_2, language);
rc = read (fd, &format2->language, min_bytes); rc = read (fd, &format2->language, min_bytes);
@ -313,8 +309,6 @@ sfnt_read_cmap_format_2 (int fd,
return (struct sfnt_cmap_format_2 *) -1; return (struct sfnt_cmap_format_2 *) -1;
} }
#pragma GCC diagnostic pop
/* Check whether or not the data is of the correct size. */ /* Check whether or not the data is of the correct size. */
if (min_bytes < nsub * sizeof *format2->subheaders) if (min_bytes < nsub * sizeof *format2->subheaders)
{ {
@ -377,9 +371,6 @@ sfnt_read_cmap_format_4 (int fd,
format4->format = header->format; format4->format = header->format;
format4->length = header->length; format4->length = header->length;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
/* Read the initial data. */ /* Read the initial data. */
min_bytes -= offsetof (struct sfnt_cmap_format_4, language); min_bytes -= offsetof (struct sfnt_cmap_format_4, language);
rc = read (fd, &format4->language, min_bytes); rc = read (fd, &format4->language, min_bytes);
@ -453,8 +444,6 @@ sfnt_read_cmap_format_4 (int fd,
for (i = 0; i < format4->glyph_index_size; ++i) for (i = 0; i < format4->glyph_index_size; ++i)
sfnt_swap16 (&format4->glyph_index_array[i]); sfnt_swap16 (&format4->glyph_index_array[i]);
#pragma GCC diagnostic pop
/* Done. Return the format 4 character map. */ /* Done. Return the format 4 character map. */
return format4; return format4;
} }
@ -486,9 +475,6 @@ sfnt_read_cmap_format_6 (int fd,
format6->format = header->format; format6->format = header->format;
format6->length = header->length; format6->length = header->length;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
/* Read the fixed size data. */ /* Read the fixed size data. */
min_size -= offsetof (struct sfnt_cmap_format_6, language); min_size -= offsetof (struct sfnt_cmap_format_6, language);
rc = read (fd, &format6->language, min_size); rc = read (fd, &format6->language, min_size);
@ -522,8 +508,6 @@ sfnt_read_cmap_format_6 (int fd,
return (struct sfnt_cmap_format_6 *) -1; return (struct sfnt_cmap_format_6 *) -1;
} }
#pragma GCC diagnostic pop
/* Set the data pointer and swap everything. */ /* Set the data pointer and swap everything. */
format6->glyph_index_array = (uint16_t *) (format6 + 1); format6->glyph_index_array = (uint16_t *) (format6 + 1);
for (i = 0; i < format6->entry_count; ++i) for (i = 0; i < format6->entry_count; ++i)
@ -565,9 +549,6 @@ sfnt_read_cmap_format_8 (int fd,
format8->reserved = header->length; format8->reserved = header->length;
format8->length = length; format8->length = length;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
/* Read the fixed length data. */ /* Read the fixed length data. */
min_size -= offsetof (struct sfnt_cmap_format_8, language); min_size -= offsetof (struct sfnt_cmap_format_8, language);
rc = read (fd, &format8->language, min_size); rc = read (fd, &format8->language, min_size);
@ -613,8 +594,6 @@ sfnt_read_cmap_format_8 (int fd,
return (struct sfnt_cmap_format_8 *) -1; return (struct sfnt_cmap_format_8 *) -1;
} }
#pragma GCC diagnostic pop
/* Set the pointer to the variable length data. */ /* Set the pointer to the variable length data. */
format8->groups format8->groups
= (struct sfnt_cmap_format_8_or_12_group *) (format8 + 1); = (struct sfnt_cmap_format_8_or_12_group *) (format8 + 1);
@ -662,9 +641,6 @@ sfnt_read_cmap_format_12 (int fd,
format12->reserved = header->length; format12->reserved = header->length;
format12->length = length; format12->length = length;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
/* Read the fixed length data. */ /* Read the fixed length data. */
min_size -= offsetof (struct sfnt_cmap_format_12, language); min_size -= offsetof (struct sfnt_cmap_format_12, language);
rc = read (fd, &format12->language, min_size); rc = read (fd, &format12->language, min_size);
@ -674,8 +650,6 @@ sfnt_read_cmap_format_12 (int fd,
return (struct sfnt_cmap_format_12 *) -1; return (struct sfnt_cmap_format_12 *) -1;
} }
#pragma GCC diagnostic pop
/* Swap what was read. */ /* Swap what was read. */
sfnt_swap32 (&format12->language); sfnt_swap32 (&format12->language);
sfnt_swap32 (&format12->num_groups); sfnt_swap32 (&format12->num_groups);
@ -991,31 +965,15 @@ sfnt_compare_uint16 (const void *a, const void *b)
return ((int) *((uint16_t *) a)) - ((int) *((uint16_t *) b)); return ((int) *((uint16_t *) a)) - ((int) *((uint16_t *) b));
} }
/* Look up the glyph corresponding to CHARACTER in the format 4 cmap /* Look up the glyph corresponding to CODE in the format 4 cmap
FORMAT4. Return 0 if no glyph was found. */ FORMAT4, using the table segment SEGMENT. Value is 0 if no glyph
was found. */
static sfnt_glyph static sfnt_glyph
sfnt_lookup_glyph_4 (sfnt_char character, sfnt_lookup_glyph_4_1 (uint16_t code, uint16_t segment,
struct sfnt_cmap_format_4 *format4) struct sfnt_cmap_format_4 *format4)
{ {
uint16_t *segment_address, *index; uint16_t *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;
if (format4->id_range_offset[segment]) if (format4->id_range_offset[segment])
{ {
@ -1040,6 +998,63 @@ sfnt_lookup_glyph_4 (sfnt_char character,
return (format4->id_delta[segment] + code) % 65536; 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 /* Look up the glyph corresponding to CHARACTER in the format 6 cmap
FORMAT6. Return 0 if no glyph was found. */ FORMAT6. Return 0 if no glyph was found. */
@ -1107,7 +1122,7 @@ sfnt_lookup_glyph_12 (sfnt_char character,
which must be in the correct encoding for the cmap table pointed to which must be in the correct encoding for the cmap table pointed to
by DATA. */ by DATA. */
static sfnt_glyph TEST_STATIC sfnt_glyph
sfnt_lookup_glyph (sfnt_char character, sfnt_lookup_glyph (sfnt_char character,
struct sfnt_cmap_encoding_subtable_data *data) struct sfnt_cmap_encoding_subtable_data *data)
{ {
@ -1520,7 +1535,7 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph,
/* Calculate the minimum size of the glyph data. This is the size /* Calculate the minimum size of the glyph data. This is the size
of the instruction length field followed by 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) min_size = (glyph->number_of_contours * sizeof (uint16_t)
+ sizeof (uint16_t)); + sizeof (uint16_t));
@ -2023,26 +2038,51 @@ sfnt_read_glyph (sfnt_glyph glyph_code,
struct sfnt_loca_table_long *loca_long) struct sfnt_loca_table_long *loca_long)
{ {
struct sfnt_glyph glyph, *memory; 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) if (loca_short)
{ {
/* Check that the glyph is within bounds. */ /* Check that the glyph is within bounds. glyph_code + 1 is the
if (glyph_code > loca_short->num_offsets) entry in the table which defines the length of the glyph. */
if (glyph_code + 1 >= loca_short->num_offsets)
return NULL; return NULL;
offset = loca_short->offsets[glyph_code] * 2; offset = loca_short->offsets[glyph_code] * 2;
next_offset = loca_short->offsets[glyph_code + 1] * 2;
} }
else if (loca_long) else if (loca_long)
{ {
if (glyph_code > loca_long->num_offsets) if (glyph_code + 1 >= loca_long->num_offsets)
return NULL; return NULL;
offset = loca_long->offsets[glyph_code]; offset = loca_long->offsets[glyph_code];
next_offset = loca_long->offsets[glyph_code + 1];
} }
else else
abort (); 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. */ /* Verify that GLYF is big enough to hold a glyph at OFFSET. */
if (glyf->size < offset + SFNT_ENDOF (struct sfnt_glyph, if (glyf->size < offset + SFNT_ENDOF (struct sfnt_glyph,
ymax, sfnt_fword)) ymax, sfnt_fword))
@ -2102,7 +2142,7 @@ sfnt_read_glyph (sfnt_glyph glyph_code,
/* Free a glyph returned from sfnt_read_glyph. GLYPH may be NULL. */ /* Free a glyph returned from sfnt_read_glyph. GLYPH may be NULL. */
static void TEST_STATIC void
sfnt_free_glyph (struct sfnt_glyph *glyph) sfnt_free_glyph (struct sfnt_glyph *glyph)
{ {
if (!glyph) if (!glyph)
@ -2122,7 +2162,7 @@ sfnt_free_glyph (struct sfnt_glyph *glyph)
static void static void
sfnt_transform_coordinates (struct sfnt_compound_glyph_component *component, 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) size_t num_coordinates)
{ {
double m1, m2, m3; double m1, m2, m3;
@ -2516,8 +2556,8 @@ static void
sfnt_lerp_half (struct sfnt_point *control1, struct sfnt_point *control2, sfnt_lerp_half (struct sfnt_point *control1, struct sfnt_point *control2,
struct sfnt_point *result) struct sfnt_point *result)
{ {
result->x = (control1->x + control2->x) / 2; result->x = control1->x + ((control2->x - control1->x) >> 1);
result->y = (control1->y + control2->y) / 2; result->y = control1->y + ((control2->y - control1->y) >> 1);
} }
/* Decompose GLYPH into its individual components. Call MOVE_TO to /* Decompose GLYPH into its individual components. Call MOVE_TO to
@ -2548,7 +2588,7 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
sfnt_free_glyph_proc free_glyph, sfnt_free_glyph_proc free_glyph,
void *dcontext) void *dcontext)
{ {
size_t here, last; size_t here, start, last;
struct sfnt_point pen, control1, control2; struct sfnt_point pen, control1, control2;
struct sfnt_compound_glyph_context context; struct sfnt_compound_glyph_context context;
size_t n; size_t n;
@ -2556,8 +2596,8 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
if (glyph->simple) if (glyph->simple)
{ {
if (!glyph->number_of_contours) if (!glyph->number_of_contours)
/* No contours. */ /* No contours. Nothing needs to be decomposed. */
return 1; return 0;
here = 0; here = 0;
@ -2573,6 +2613,9 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
pen.y = glyph->simple->y_coordinates[here] << 16U; pen.y = glyph->simple->y_coordinates[here] << 16U;
move_to (pen, dcontext); 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 /* If there is only one point in a contour, draw a one pixel
wide line. */ wide line. */
if (last == here) if (last == here)
@ -2635,6 +2678,39 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
curve_to (control1, pen, dcontext); 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; return 0;
@ -2659,7 +2735,7 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
if (!context.num_end_points) if (!context.num_end_points)
/* No contours. */ /* No contours. */
goto fail; goto early;
here = 0; here = 0;
@ -2675,6 +2751,9 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
pen.y = context.y_coordinates[here]; pen.y = context.y_coordinates[here];
move_to (pen, dcontext); 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 /* If there is only one point in a contour, draw a one pixel
wide line. */ wide line. */
if (last == here) if (last == here)
@ -2735,8 +2814,40 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
curve_to (control1, pen, dcontext); 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.x_coordinates);
xfree (context.y_coordinates); xfree (context.y_coordinates);
xfree (context.flags); xfree (context.flags);
@ -2751,6 +2862,25 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
return 1; 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 /* Global state for sfnt_build_glyph_outline and related
functions. */ functions. */
static struct sfnt_build_glyph_outline_context build_outline_context; static struct sfnt_build_glyph_outline_context build_outline_context;
@ -2794,7 +2924,7 @@ sfnt_build_append (int flags, sfnt_fixed x, sfnt_fixed y)
/* Extend outline bounding box. */ /* Extend outline bounding box. */
if (outline->outline_used == 3) if (outline->outline_used == 1)
{ {
/* These are the first points in the outline. */ /* These are the first points in the outline. */
outline->xmin = outline->xmax = x; outline->xmin = outline->xmax = x;
@ -2811,40 +2941,6 @@ sfnt_build_append (int flags, sfnt_fixed x, sfnt_fixed y)
return outline; 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 /* Multiply the two 16.16 fixed point numbers X and Y. Return the
result regardless of overflow. */ result regardless of overflow. */
@ -2878,6 +2974,40 @@ sfnt_mul_fixed (sfnt_fixed x, sfnt_fixed y)
#endif #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 /* Divide the two 16.16 fixed point numbers X and Y. Return the
result regardless of overflow. */ result regardless of overflow. */
@ -2957,7 +3087,7 @@ sfnt_curve_to_and_build_1 (struct sfnt_point control0,
struct sfnt_point control1, struct sfnt_point control1,
struct sfnt_point endpoint) struct sfnt_point endpoint)
{ {
struct sfnt_point ab; struct sfnt_point ab, bc, abbc;
/* control0, control and endpoint make up the spline. Figure out /* control0, control and endpoint make up the spline. Figure out
its distance from a line. */ its distance from a line. */
@ -2972,15 +3102,17 @@ sfnt_curve_to_and_build_1 (struct sfnt_point control0,
} }
else else
{ {
/* Split the spline between control0 and control1. /* Calculate new control points.
Maybe apply a recursion limit here? */ Maybe apply a recursion limit here? */
sfnt_lerp_half (&control0, &control1, &ab); 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. */ /* 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. */ /* 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);
} }
} }
@ -2997,17 +3129,21 @@ sfnt_curve_to_and_build (struct sfnt_point control,
control0.x = build_outline_context.x; control0.x = build_outline_context.x;
control0.y = build_outline_context.y; control0.y = build_outline_context.y;
control.x *= build_outline_context.factor; control.x = sfnt_mul_fixed (control.x,
control.y *= build_outline_context.factor; build_outline_context.factor);
endpoint.x *= build_outline_context.factor; control.y = sfnt_mul_fixed (control.y,
endpoint.y *= build_outline_context.factor; 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); sfnt_curve_to_and_build_1 (control0, control, endpoint);
} }
/* Non-reentrantly build the outline for the specified GLYPH at the /* Non-reentrantly build the outline for the specified GLYPH at the
given pixel size. Return the outline data upon success, or NULL given pixel size. Return the outline data with a refcount of 0
upon failure. upon success, or NULL upon failure.
Call GET_GLYPH and FREE_GLYPH with the specified DCONTEXT to obtain Call GET_GLYPH and FREE_GLYPH with the specified DCONTEXT to obtain
glyphs for compound glyph subcomponents. glyphs for compound glyph subcomponents.
@ -3029,6 +3165,7 @@ sfnt_build_glyph_outline (struct sfnt_glyph *glyph,
outline = xmalloc (sizeof *outline + 40 * sizeof (*outline->outline)); outline = xmalloc (sizeof *outline + 40 * sizeof (*outline->outline));
outline->outline_size = 40; outline->outline_size = 40;
outline->outline_used = 0; outline->outline_used = 0;
outline->refcount = 0;
outline->outline outline->outline
= (struct sfnt_glyph_outline_command *) (outline + 1); = (struct sfnt_glyph_outline_command *) (outline + 1);
@ -3059,7 +3196,8 @@ sfnt_build_glyph_outline (struct sfnt_glyph *glyph,
It would be nice to get rid of this floating point arithmetic at It would be nice to get rid of this floating point arithmetic at
some point. */ some point. */
build_outline_context.factor 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. */ /* Decompose the outline. */
rc = sfnt_decompose_glyph (glyph, sfnt_move_to_and_build, rc = sfnt_decompose_glyph (glyph, sfnt_move_to_and_build,
@ -3108,11 +3246,17 @@ sfnt_poly_grid_ceil (sfnt_fixed f)
& ~(SFNT_POLY_STEP - 1)) + SFNT_POLY_START); & ~(SFNT_POLY_STEP - 1)) + SFNT_POLY_START);
} }
/* Initialize the specified RASTER in preparation for displaying spans enum
for OUTLINE. The caller must then set RASTER->cells to a zeroed {
array of size RASTER->width * RASTER->height. */ SFNT_POLY_ALIGNMENT = 4,
};
static void /* Initialize the specified RASTER in preparation for displaying spans
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. */
TEST_STATIC void
sfnt_prepare_raster (struct sfnt_raster *raster, sfnt_prepare_raster (struct sfnt_raster *raster,
struct sfnt_glyph_outline *outline) struct sfnt_glyph_outline *outline)
{ {
@ -3120,10 +3264,17 @@ sfnt_prepare_raster (struct sfnt_raster *raster,
= sfnt_ceil_fixed (outline->xmax - outline->xmin) >> 16; = sfnt_ceil_fixed (outline->xmax - outline->xmin) >> 16;
raster->height raster->height
= sfnt_ceil_fixed (outline->ymax - outline->ymin) >> 16; = 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 raster->offx
= sfnt_floor_fixed (outline->xmin); = sfnt_floor_fixed (outline->xmin) >> 16;
raster->offy 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_edge_proc) (struct sfnt_edge *, size_t,
@ -3131,13 +3282,13 @@ typedef void (*sfnt_edge_proc) (struct sfnt_edge *, size_t,
typedef void (*sfnt_span_proc) (struct sfnt_edge *, sfnt_fixed, void *); typedef void (*sfnt_span_proc) (struct sfnt_edge *, sfnt_fixed, void *);
/* Move EDGE->x forward, assuming that the scanline has moved upwards /* Move EDGE->x forward, assuming that the scanline has moved upwards
by DY. */ by SFNT_POLY_STEP. */
static void static void
sfnt_step_edge_by (struct sfnt_edge *edge, sfnt_fixed dy) sfnt_step_edge (struct sfnt_edge *edge)
{ {
/* Step 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 /* Build a list of edges for each contour in OUTLINE, applying
@ -3151,31 +3302,26 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline *outline,
sfnt_edge_proc edge_proc, void *dcontext) sfnt_edge_proc edge_proc, void *dcontext)
{ {
struct sfnt_edge *edges; struct sfnt_edge *edges;
size_t i, edge, start, next_vertex, y; size_t i, edge, next_vertex;
sfnt_fixed dx, dy, bot; sfnt_fixed dx, dy, bot, step_x;
int inc_x; int inc_x;
size_t top, bottom; size_t top, bottom, y;
edges = alloca (outline->outline_used * sizeof *edges); edges = alloca (outline->outline_used * sizeof *edges);
edge = 0; edge = 0;
/* First outline currently being processed. */ for (i = 0; i < outline->outline_used; ++i)
start = 0;
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. /* 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; next_vertex = i + 1;
if (next_vertex == outline->outline_used if (next_vertex == outline->outline_used
|| !(outline->outline[next_vertex].flags || !(outline->outline[next_vertex].flags
& SFNT_GLYPH_OUTLINE_LINETO)) & SFNT_GLYPH_OUTLINE_LINETO))
next_vertex = start; continue;
/* Skip past horizontal vertices. */ /* Skip past horizontal vertices. */
if (outline->outline[next_vertex].y == outline->outline[i].y) if (outline->outline[next_vertex].y == outline->outline[i].y)
@ -3220,6 +3366,10 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline *outline,
dy = abs (outline->outline[top].y dy = abs (outline->outline[top].y
- outline->outline[bottom].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 /* Compute the increment. This is which direction X moves in
for each increase in Y. */ for each increase in Y. */
@ -3233,14 +3383,24 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline *outline,
/* Compute the step X. This is how much X changes for each /* Compute the step X. This is how much X changes for each
increase in Y. */ 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. */ /* Step to first grid point. */
y = sfnt_poly_grid_ceil (bot); 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].bottom = y;
edges[edge].next = NULL; 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++; edge++;
} }
@ -3344,7 +3504,7 @@ sfnt_poly_edges (struct sfnt_edge *edges, size_t size,
/* Step all edges. */ /* Step all edges. */
for (a = active; a; a = a->next) for (a = active; a; a = a->next)
sfnt_step_edge_by (a, SFNT_POLY_STEP); sfnt_step_edge (a);
/* Resort on X axis. */ /* Resort on X axis. */
for (prev = &active; (a = *prev) && (n = a->next);) for (prev = &active; (a = *prev) && (n = a->next);)
@ -3380,7 +3540,7 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y,
{ {
unsigned char *start; unsigned char *start;
unsigned char *coverage; unsigned char *coverage;
sfnt_fixed left, right; sfnt_fixed left, right, end;
unsigned short w, a; unsigned short w, a;
int row, col; int row, col;
@ -3408,7 +3568,13 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y,
right are now 16.2. */ right are now 16.2. */
left = sfnt_poly_grid_ceil (x0) >> (16 - SFNT_POLY_SHIFT); left = sfnt_poly_grid_ceil (x0) >> (16 - SFNT_POLY_SHIFT);
right = sfnt_poly_grid_ceil (x1) >> (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; start += left >> SFNT_POLY_SHIFT;
/* Compute coverage for first pixel, then poly. */ /* Compute coverage for first pixel, then poly. */
@ -3420,7 +3586,10 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y,
map, unlike row which indexes the raster. */ map, unlike row which indexes the raster. */
col = 0; 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++]; left++, w += coverage[col++];
a = *start + w; a = *start + w;
@ -3477,10 +3646,6 @@ sfnt_poly_span (struct sfnt_edge *start, sfnt_fixed y,
for (edge = start; edge; edge = edge->next) 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) if (!winding)
x0 = edge->x; x0 = edge->x;
else else
@ -3528,10 +3693,10 @@ sfnt_raster_glyph_outline (struct sfnt_glyph_outline *outline)
sfnt_prepare_raster (&raster, outline); sfnt_prepare_raster (&raster, outline);
/* Allocate the raster data. */ /* Allocate the raster data. */
data = xmalloc (sizeof *data + raster.width * raster.height); data = xmalloc (sizeof *data + raster.stride * raster.height);
*data = raster; *data = raster;
data->cells = (unsigned char *) (data + 1); 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 /* Generate edges for the outline, polying each array of edges to
the raster. */ the raster. */
@ -4131,16 +4296,25 @@ sfnt_test_edge (struct sfnt_edge *edges, size_t num_edges,
for (i = 0; i < num_edges; ++i) 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].x),
sfnt_coerce_fixed (edges[i].top), sfnt_coerce_fixed (edges[i].top),
sfnt_coerce_fixed (edges[i].bottom), 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 #ifdef TEST_VERTEX
printf ("ctx.fillRect (%g, %g, 1, 1);\n", printf ("ctx.fillRect (%g, %g, 1, 1);\n",
sfnt_coerce_fixed (edges[i].x), sfnt_coerce_fixed (edges[i].x),
sfnt_coerce_fixed (sfnt_test_max sfnt_coerce_fixed (sfnt_test_max
- edges[i].y)); - 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 #endif
} }
@ -4157,7 +4331,7 @@ sfnt_test_raster (struct sfnt_raster *raster)
for (y = 0; y < raster->height; ++y) for (y = 0; y < raster->height; ++y)
{ {
for (x = 0; x < raster->width; ++x) 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 (""); puts ("");
} }
} }
@ -4411,7 +4585,7 @@ main (int argc, char **argv)
/* Time this important bit. */ /* Time this important bit. */
clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start); clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start);
outline = sfnt_build_glyph_outline (glyph, head, outline = sfnt_build_glyph_outline (glyph, head,
40, 45,
sfnt_test_get_glyph, sfnt_test_get_glyph,
sfnt_test_free_glyph, sfnt_test_free_glyph,
&dcontext); &dcontext);
@ -4449,13 +4623,23 @@ main (int argc, char **argv)
sfnt_build_outline_edges (outline, sfnt_test_edge, sfnt_build_outline_edges (outline, sfnt_test_edge,
NULL); NULL);
raster = NULL;
clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start); 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); clock_gettime (CLOCK_THREAD_CPUTIME_ID, &end);
sub2 = timespec_sub (end, start); sub2 = timespec_sub (end, start);
/* Print out the raster. */ /* Print out the raster. */
sfnt_test_raster (raster); sfnt_test_raster (raster);
printf ("raster offsets: %d, %d\n",
raster->offx, raster->offy);
xfree (raster); xfree (raster);
@ -4468,7 +4652,7 @@ main (int argc, char **argv)
if (hmtx && head) if (hmtx && head)
{ {
if (!sfnt_lookup_glyph_metrics (code, 40, if (!sfnt_lookup_glyph_metrics (code, 36,
&metrics, &metrics,
hmtx, hhea, hmtx, hhea,
head, maxp)) head, maxp))
@ -4482,7 +4666,7 @@ main (int argc, char **argv)
printf ("time spent building edges: %lld sec %ld nsec\n", printf ("time spent building edges: %lld sec %ld nsec\n",
(long long) sub1.tv_sec, sub1.tv_nsec); (long long) sub1.tv_sec, sub1.tv_nsec);
printf ("time spent rasterizing: %lld sec %ld nsec\n", 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); xfree (outline);
} }

View file

@ -663,6 +663,9 @@ struct sfnt_glyph_outline
/* Rectangle defining bounds of the outline. Namely, the minimum /* Rectangle defining bounds of the outline. Namely, the minimum
and maximum X and Y positions. */ and maximum X and Y positions. */
sfnt_fixed xmin, ymin, xmax, ymax; sfnt_fixed xmin, ymin, xmax, ymax;
/* Reference count. Initially zero. */
short refcount;
}; };
enum sfnt_glyph_outline_flags enum sfnt_glyph_outline_flags
@ -670,39 +673,26 @@ enum sfnt_glyph_outline_flags
SFNT_GLYPH_OUTLINE_LINETO = (1 << 1), 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;
};
/* Glyph rasterization. */ /* Glyph rasterization. */
struct sfnt_raster struct sfnt_raster
{ {
/* Pointer to coverage data. */
unsigned char *cells;
/* Basic dimensions of the raster. */ /* Basic dimensions of the raster. */
unsigned short width, height; unsigned short width, height;
/* Integer offset to apply to positions in the raster. */ /* Integer offset to apply to positions in the raster. */
unsigned short offx, offy; short offx, offy;
/* Pointer to coverage data. */ /* The raster stride. */
unsigned char *cells; unsigned short stride;
/* Reference count. Initially zero. */
unsigned short refcount;
}; };
struct sfnt_edge struct sfnt_edge
@ -716,8 +706,15 @@ struct sfnt_edge
/* X position, top and bottom of edges. */ /* X position, top and bottom of edges. */
sfnt_fixed x, top, bottom; 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; sfnt_fixed step_x;
#ifdef TEST
/* Value of x before initial adjustment of bottom to match the
grid. */
sfnt_fixed source_x;
#endif
}; };
@ -878,6 +875,12 @@ enum sfnt_meta_data_tag
#define SFNT_CEIL_FIXED(fixed) \
(!((fixed) & 0177777) ? (fixed) \
: ((fixed) + 0200000) & 037777600000)
/* Function declarations. Keep these sorted by the order in which /* Function declarations. Keep these sorted by the order in which
they appear in sfnt.c. Keep each line no longer than 80 they appear in sfnt.c. Keep each line no longer than 80
columns. */ columns. */
@ -890,9 +893,12 @@ extern struct sfnt_offset_subtable *sfnt_read_table_directory (int);
int, struct sfnt_offset_subtable *, \ int, struct sfnt_offset_subtable *, \
struct sfnt_cmap_encoding_subtable **, \ struct sfnt_cmap_encoding_subtable **, \
struct sfnt_cmap_encoding_subtable_data *** 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 #undef PROTOTYPE
extern sfnt_glyph sfnt_lookup_glyph (sfnt_char,
struct sfnt_cmap_encoding_subtable_data *);
#define PROTOTYPE int, struct sfnt_offset_subtable * #define PROTOTYPE int, struct sfnt_offset_subtable *
extern struct sfnt_head_table *sfnt_read_head_table (PROTOTYPE); extern struct sfnt_head_table *sfnt_read_head_table (PROTOTYPE);
extern struct sfnt_hhea_table *sfnt_read_hhea_table (PROTOTYPE); extern struct sfnt_hhea_table *sfnt_read_hhea_table (PROTOTYPE);
@ -905,6 +911,7 @@ extern struct sfnt_glyf_table *sfnt_read_glyf_table (PROTOTYPE);
extern struct sfnt_glyph *sfnt_read_glyph (sfnt_glyph, struct sfnt_glyf_table *, extern struct sfnt_glyph *sfnt_read_glyph (sfnt_glyph, struct sfnt_glyf_table *,
struct sfnt_loca_table_short *, struct sfnt_loca_table_short *,
struct sfnt_loca_table_long *); struct sfnt_loca_table_long *);
extern void sfnt_free_glyph (struct sfnt_glyph *);
#define PROTOTYPE \ #define PROTOTYPE \
struct sfnt_glyph *, \ struct sfnt_glyph *, \

View file

@ -19,18 +19,505 @@ along with GNU Emacs. If not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <config.h> #include <config.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <android/api-level.h>
#include "androidterm.h" #include "androidterm.h"
#include "sfntfont.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;
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 ();
}
/* 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. */
};
/* 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;
}
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 void
init_sfntfont_android (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 void
syms_of_sfntfont_android (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);
} }

File diff suppressed because it is too large Load diff

View file

@ -21,6 +21,39 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef _SFNTFONT_H_ #ifndef _SFNTFONT_H_
#define _SFNTFONT_H_ #define _SFNTFONT_H_
#include "lisp.h"
#include "frame.h"
#include "font.h"
#include "sfnt.h"
extern int sfnt_enum_font (const char *); extern int sfnt_enum_font (const char *);
/* 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 *);
/* 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_ */ #endif /* _SFNTFONT_H_ */

View file

@ -36227,6 +36227,55 @@ gui_intersect_rectangles (const Emacs_Rectangle *r1, const Emacs_Rectangle *r2,
return intersection_p; 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 */ #endif /* HAVE_WINDOW_SYSTEM */