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:
parent
4c09b9a5a6
commit
494bedde32
19 changed files with 2958 additions and 248 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"))
|
||||||
|
|
|
||||||
12
src/alloc.c
12
src/alloc.c
|
|
@ -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
|
||||||
|
|
|
||||||
153
src/android.c
153
src/android.c
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
||||||
22
src/emacs.c
22
src/emacs.c
|
|
@ -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 ();
|
||||||
|
|
|
||||||
10
src/font.c
10
src/font.c
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
17
src/print.c
17
src/print.c
|
|
@ -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
|
||||||
|
|
|
||||||
492
src/sfnt.c
492
src/sfnt.c
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
55
src/sfnt.h
55
src/sfnt.h
|
|
@ -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 *, \
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1802
src/sfntfont.c
1802
src/sfntfont.c
File diff suppressed because it is too large
Load diff
|
|
@ -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_ */
|
||||||
|
|
|
||||||
49
src/xdisp.c
49
src/xdisp.c
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue