From 1584a58efd63d6806dbff51adcbfec054533b316 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 8 Jan 2023 15:42:37 +0800 Subject: [PATCH] Update Android port Note that the port currently does not work as of this check-in. * src/android.c (android_change_gc): Fix situations where clip rects are cleared. (android_create_pixmap_from_bitmap_data): Fix bitmap data iteration. * src/androidfns.c (Fx_show_tip, Fx_hide_tip): Remove annoying errors. * src/androidgui.h (enum android_event_type): (struct android_crossing_event): (struct android_motion_event): (struct android_button_event): (union android_event): New crossing, motion and button events. * src/androidterm.c (android_note_mouse_movement) (mouse_or_wdesc_frame, android_construct_mouse_click) (handle_one_android_event, android_mouse_position) (android_wait_for_event, android_set_window_size_1) (android_bitmap_icon, android_free_frame_resources) (syms_of_androidterm): New functions. Handle crossing, motion and button events. * src/androidterm.h (struct android_display_info): New field `last_mouse_movement_time'. (struct android_output): Remove unused `need_buffer_flip' field. * src/emacs.c (android_emacs_init): Initialize sfntfont. * src/frame.c (syms_of_frame): Set frame_inhibit_implied_resize to some reasonable value. * src/frame.h (GCALIGNED_STRUCT): Set wait_event_type on Android. * src/sfnt.c (eassert): (TEST_STATIC): (available): (enum sfnt_table): (sfnt_table_names): (SFNT_ENDOF): (struct sfnt_table_directory): (enum sfnt_scaler_type): (sfnt_coerce_fixed): (struct sfnt_hhea_table): (struct sfnt_cmap_table): (enum sfnt_platform_id): (enum sfnt_unicode_platform_specific_id): (enum sfnt_macintosh_platform_specific_id): (enum sfnt_microsoft_platform_specific_id): (struct sfnt_cmap_encoding_subtable): (struct sfnt_cmap_encoding_subtable_data): (struct sfnt_cmap_format_0): (struct sfnt_cmap_format_2_subheader): (struct sfnt_cmap_format_2): (struct sfnt_cmap_format_4): (struct sfnt_cmap_format_6): (struct sfnt_cmap_format_8_or_12_group): (struct sfnt_cmap_format_8): (struct sfnt_cmap_format_12): (struct sfnt_maxp_table): (struct sfnt_loca_table_short): (struct sfnt_loca_table_long): (struct sfnt_glyf_table): (struct sfnt_simple_glyph): (struct sfnt_compound_glyph_component): (struct sfnt_compound_glyph): (struct sfnt_glyph): (sfnt_read_table_directory): (file): (sfnt_read_cmap_table): (sfnt_read_head_table): (success): (sfnt_read_hhea_table): (sfnt_read_loca_table_short): (sfnt_read_loca_table_long): (sfnt_read_maxp_table): (sfnt_read_glyf_table): (sfnt_read_compound_glyph): (sfnt_read_glyph): (struct sfnt_point): (sfnt_expand_compound_glyph_context): (sfnt_decompose_compound_glyph): (struct sfnt_glyph_outline): (enum sfnt_glyph_outline_flags): (struct sfnt_build_glyph_outline_context): (sfnt_build_append): (sfnt_build_glyph_outline): (struct sfnt_raster): (struct sfnt_edge): (sfnt_prepare_raster): (sfnt_build_outline_edges): (sfnt_raster_glyph_outline): Move structures to sfnt.h. (struct sfnt_long_hor_metric): (struct sfnt_hmtx_table): (struct sfnt_glyph_metrics): (sfnt_read_hmtx_table): (sfnt_lookup_glyph_metrics): (sfnt_read_name_table): (sfnt_find_name): (sfnt_read_meta_table): (sfnt_find_metadata): (sfnt_test_edge_ignore): New functions. (main): Add new tests. * src/xdisp.c (redisplay_tool_bar): --- src/android.c | 102 +++- src/androidfns.c | 3 +- src/androidgui.h | 34 ++ src/androidterm.c | 443 +++++++++++++++- src/androidterm.h | 13 +- src/emacs.c | 8 + src/frame.c | 2 +- src/frame.h | 5 +- src/sfnt.c | 1293 ++++++++++++++++----------------------------- src/xdisp.c | 9 + 10 files changed, 1063 insertions(+), 849 deletions(-) diff --git a/src/android.c b/src/android.c index db12e244275..e2056b666d6 100644 --- a/src/android.c +++ b/src/android.c @@ -1254,6 +1254,92 @@ NATIVE_NAME (sendWindowAction) (JNIEnv *env, jobject object, android_write_event (&event); } +extern JNIEXPORT void JNICALL +NATIVE_NAME (sendEnterNotify) (JNIEnv *env, jobject object, + jshort window, jint x, jint y, + jlong time) +{ + union android_event event; + + event.xcrossing.type = ANDROID_ENTER_NOTIFY; + event.xcrossing.window = window; + event.xcrossing.x = x; + event.xcrossing.y = y; + event.xcrossing.time = time; + + android_write_event (&event); +} + +extern JNIEXPORT void JNICALL +NATIVE_NAME (sendLeaveNotify) (JNIEnv *env, jobject object, + jshort window, jint x, jint y, + jlong time) +{ + union android_event event; + + event.xcrossing.type = ANDROID_LEAVE_NOTIFY; + event.xcrossing.window = window; + event.xcrossing.x = x; + event.xcrossing.y = y; + event.xcrossing.time = time; + + android_write_event (&event); +} + +extern JNIEXPORT void JNICALL +NATIVE_NAME (sendMotionNotify) (JNIEnv *env, jobject object, + jshort window, jint x, jint y, + jlong time) +{ + union android_event event; + + event.xmotion.type = ANDROID_MOTION_NOTIFY; + event.xmotion.window = window; + event.xmotion.x = x; + event.xmotion.y = y; + event.xmotion.time = time; + + android_write_event (&event); +} + +extern JNIEXPORT void JNICALL +NATIVE_NAME (sendButtonPress) (JNIEnv *env, jobject object, + jshort window, jint x, jint y, + jlong time, jint state, + jint button) +{ + union android_event event; + + event.xbutton.type = ANDROID_BUTTON_PRESS; + event.xbutton.window = window; + event.xbutton.x = x; + event.xbutton.y = y; + event.xbutton.time = time; + event.xbutton.state = state; + event.xbutton.button = button; + + android_write_event (&event); +} + +extern JNIEXPORT void JNICALL +NATIVE_NAME (sendButtonRelease) (JNIEnv *env, jobject object, + jshort window, jint x, jint y, + jlong time, jint state, + jint button) +{ + union android_event event; + + event.xbutton.type = ANDROID_BUTTON_RELEASE; + event.xbutton.window = window; + event.xbutton.x = x; + event.xbutton.y = y; + event.xbutton.time = time; + event.xbutton.state = state; + event.xbutton.button = button; + + android_write_event (&event); +} + #pragma clang diagnostic pop @@ -1747,12 +1833,11 @@ android_change_gc (struct android_gc *gc, emacs_gc_clip_mask, what); - /* Clearing GCClipMask also clears the clip rectangles. */ - if (!what) - (*android_java_env)->SetObjectField (android_java_env, - gcontext, - emacs_gc_clip_rects, - NULL); + /* Changing GCClipMask also clears the clip rectangles. */ + (*android_java_env)->SetObjectField (android_java_env, + gcontext, + emacs_gc_clip_rects, + NULL); } if (mask & ANDROID_GC_STIPPLE) @@ -2133,14 +2218,14 @@ android_create_pixmap_from_bitmap_data (char *data, unsigned int width, /* The alpha channels must be set, or otherwise, the pixmap will be created entirely transparent. */ - if (data[y * (width + 7) / 8 + x / 8] & (1 << (x % 8))) + if (data[x / 8] & (1 << (x % 8))) region[x] = foreground | 0xff000000; else region[x] = background | 0xff000000; } else { - if (data[y * (width + 7) / 8 + x / 8] & (1 << (x % 8))) + if (data[x / 8] & (1 << (x % 8))) region[x] = foreground; else region[x] = background; @@ -2151,6 +2236,7 @@ android_create_pixmap_from_bitmap_data (char *data, unsigned int width, colors, width * y, width, region); + data += width / 8; } /* First, allocate the pixmap handle. */ diff --git a/src/androidfns.c b/src/androidfns.c index a78b35fc8ff..7fdb2f14141 100644 --- a/src/androidfns.c +++ b/src/androidfns.c @@ -1347,7 +1347,7 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, error ("Android cross-compilation stub called!"); return Qnil; #else - error ("Not implemented"); + /* TODO tooltips */ return Qnil; #endif } @@ -1360,7 +1360,6 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, error ("Android cross-compilation stub called!"); return Qnil; #else - error ("Not implemented"); return Qnil; #endif } diff --git a/src/androidgui.h b/src/androidgui.h index b0ea820cfdf..d51b73a764d 100644 --- a/src/androidgui.h +++ b/src/androidgui.h @@ -204,6 +204,11 @@ enum android_event_type ANDROID_FOCUS_IN, ANDROID_FOCUS_OUT, ANDROID_WINDOW_ACTION, + ANDROID_ENTER_NOTIFY, + ANDROID_LEAVE_NOTIFY, + ANDROID_MOTION_NOTIFY, + ANDROID_BUTTON_PRESS, + ANDROID_BUTTON_RELEASE, }; struct android_any_event @@ -268,6 +273,32 @@ struct android_window_action_event unsigned int action; }; +struct android_crossing_event +{ + enum android_event_type type; + android_window window; + int x, y; + unsigned long time; +}; + +struct android_motion_event +{ + enum android_event_type type; + android_window window; + int x, y; + unsigned long time; +}; + +struct android_button_event +{ + enum android_event_type type; + android_window window; + int x, y; + unsigned long time; + unsigned int state; + unsigned int button; +}; + union android_event { enum android_event_type type; @@ -276,6 +307,9 @@ union android_event struct android_configure_event xconfigure; struct android_focus_event xfocus; struct android_window_action_event xaction; + struct android_crossing_event xcrossing; + struct android_motion_event xmotion; + struct android_button_event xbutton; }; extern int android_pending (void); diff --git a/src/androidterm.c b/src/androidterm.c index 0279da4f58d..05fe7f01bf9 100644 --- a/src/androidterm.c +++ b/src/androidterm.c @@ -41,6 +41,11 @@ struct android_display_info *x_display_list; #include +/* Non-zero means that a HELP_EVENT has been generated since Emacs + start. */ + +static bool any_help_event_p; + enum { ANDROID_EVENT_NORMAL, @@ -261,6 +266,94 @@ android_detect_focus_change (struct android_display_info *dpyinfo, } } +static bool +android_note_mouse_movement (struct frame *frame, + struct android_motion_event *event) +{ + struct android_display_info *dpyinfo; + Emacs_Rectangle *r; + + if (!FRAME_ANDROID_OUTPUT (frame)) + return false; + + dpyinfo = FRAME_DISPLAY_INFO (frame); + dpyinfo->last_mouse_motion_frame = frame; + dpyinfo->last_mouse_motion_x = event->x; + dpyinfo->last_mouse_motion_y = event->y; + dpyinfo->last_mouse_movement_time = event->time; + + /* Has the mouse moved off the glyph it was on at the last sighting? */ + r = &dpyinfo->last_mouse_glyph; + if (frame != dpyinfo->last_mouse_glyph_frame + || event->x < r->x || event->x >= r->x + r->width + || event->y < r->y || event->y >= r->y + r->height) + { + frame->mouse_moved = true; + /* TODO + dpyinfo->last_mouse_scroll_bar = NULL; */ + note_mouse_highlight (frame, event->x, event->y); + /* Remember which glyph we're now on. */ + remember_mouse_glyph (frame, event->x, event->y, r); + dpyinfo->last_mouse_glyph_frame = frame; + return true; + } + + return false; +} + +static struct frame * +mouse_or_wdesc_frame (struct android_display_info *dpyinfo, int wdesc) +{ + struct frame *lm_f = (gui_mouse_grabbed (dpyinfo) + ? dpyinfo->last_mouse_frame + : NULL); + + if (lm_f && !EQ (track_mouse, Qdropping) + && !EQ (track_mouse, Qdrag_source)) + return lm_f; + else + { + struct frame *w_f = android_window_to_frame (dpyinfo, wdesc); + + /* Do not return a tooltip frame. */ + if (!w_f || FRAME_TOOLTIP_P (w_f)) + return EQ (track_mouse, Qdropping) ? lm_f : NULL; + else + /* When dropping it would be probably nice to raise w_f + here. */ + return w_f; + } +} + +static Lisp_Object +android_construct_mouse_click (struct input_event *result, + struct android_button_event *event, + struct frame *f) +{ + struct android_display_info *dpyinfo; + int x, y; + + dpyinfo = FRAME_DISPLAY_INFO (f); + x = event->x; + y = event->y; + + /* Make the event type NO_EVENT; we'll change that when we decide + otherwise. */ + result->kind = MOUSE_CLICK_EVENT; + result->code = event->button - 1; + result->timestamp = event->time; + result->modifiers = (android_android_to_emacs_modifiers (dpyinfo, + event->state) + | (event->type == ANDROID_BUTTON_RELEASE + ? up_modifier : down_modifier)); + + XSETINT (result->x, x); + XSETINT (result->y, y); + XSETFRAME (result->frame_or_window, f); + result->arg = Qnil; + return Qnil; +} + static int handle_one_android_event (struct android_display_info *dpyinfo, union android_event *event, int *finish, @@ -270,17 +363,20 @@ handle_one_android_event (struct android_display_info *dpyinfo, struct frame *f, *any, *mouse_frame; Mouse_HLInfo *hlinfo; union buffered_input_event inev; - int modifiers, count; + int modifiers, count, do_help; /* It is okay for this to not resemble handle_one_xevent so much. Differences in event handling code are much less nasty than stuble differences in the graphics code. */ - count = 0; + do_help = count = 0; hlinfo = &dpyinfo->mouse_highlight; *finish = ANDROID_EVENT_NORMAL; any = android_window_to_frame (dpyinfo, event->xany.window); + if (any && any->wait_event_type == event->type) + any->wait_event_type = 0; /* Indicates we got it. */ + EVENT_INIT (inev.ie); switch (event->type) @@ -410,6 +506,213 @@ handle_one_android_event (struct android_display_info *dpyinfo, /* A new frame must be created. */; } + case ANDROID_ENTER_NOTIFY: + f = any; + + if (f) + android_note_mouse_movement (f, &event->xmotion); + goto OTHER; + + case ANDROID_MOTION_NOTIFY: + f = any; + + if (f) + { + /* Maybe generate a SELECT_WINDOW_EVENT for + `mouse-autoselect-window' but don't let popup menus + interfere with this (Bug#1261). */ + if (!NILP (Vmouse_autoselect_window) + && !popup_activated () + /* Don't switch if we're currently in the minibuffer. + This tries to work around problems where the + minibuffer gets unselected unexpectedly, and where + you then have to move your mouse all the way down to + the minibuffer to select it. */ + && !MINI_WINDOW_P (XWINDOW (selected_window)) + /* With `focus-follows-mouse' non-nil create an event + also when the target window is on another frame. */ + && (f == XFRAME (selected_frame) + || !NILP (focus_follows_mouse))) + { + static Lisp_Object last_mouse_window; + Lisp_Object window + = window_from_coordinates (f, event->xmotion.x, + event->xmotion.y, 0, + false, false); + + /* A window will be autoselected only when it is not + selected now and the last mouse movement event was + not in it. The remainder of the code is a bit vague + wrt what a "window" is. For immediate autoselection, + the window is usually the entire window but for GTK + where the scroll bars don't count. For delayed + autoselection the window is usually the window's text + area including the margins. */ + if (WINDOWP (window) + && !EQ (window, last_mouse_window) + && !EQ (window, selected_window)) + { + inev.ie.kind = SELECT_WINDOW_EVENT; + inev.ie.frame_or_window = window; + } + + /* Remember the last window where we saw the mouse. */ + last_mouse_window = window; + } + + if (!android_note_mouse_movement (f, &event->xmotion)) + help_echo_string = previous_help_echo_string; + } + + /* If the contents of the global variable help_echo_string + has changed, generate a HELP_EVENT. */ + if (!NILP (help_echo_string) + || !NILP (previous_help_echo_string)) + do_help = 1; + + if (f) + android_flush_dirty_back_buffer_on (f); + + goto OTHER; + + case ANDROID_LEAVE_NOTIFY: + f = any; + + if (f) + { + /* Now clear dpyinfo->last_mouse_motion_frame, or + gui_redo_mouse_highlight will end up highlighting the + last known position of the mouse if a tooltip frame is + later unmapped. */ + + if (f == dpyinfo->last_mouse_motion_frame) + dpyinfo->last_mouse_motion_frame = NULL; + + /* Something similar applies to + dpyinfo->last_mouse_glyph_frame. */ + if (f == dpyinfo->last_mouse_glyph_frame) + dpyinfo->last_mouse_glyph_frame = NULL; + + if (f == hlinfo->mouse_face_mouse_frame) + { + /* If we move outside the frame, then we're + certainly no longer on any text in the frame. */ + clear_mouse_face (hlinfo); + hlinfo->mouse_face_mouse_frame = 0; + android_flush_dirty_back_buffer_on (f); + } + + /* Generate a nil HELP_EVENT to cancel a help-echo. + Do it only if there's something to cancel. + Otherwise, the startup message is cleared when + the mouse leaves the frame. */ + if (any_help_event_p + /* But never if `mouse-drag-and-drop-region' is in + progress, since that results in the tooltip being + dismissed when the mouse moves on top. */ + && !((EQ (track_mouse, Qdrag_source) + || EQ (track_mouse, Qdropping)) + && gui_mouse_grabbed (dpyinfo))) + do_help = -1; + } + + goto OTHER; + + case ANDROID_BUTTON_PRESS: + case ANDROID_BUTTON_RELEASE: + /* If we decide we want to generate an event to be seen + by the rest of Emacs, we put it here. */ + + f = any; + + Lisp_Object tab_bar_arg = Qnil; + bool tab_bar_p = false; + bool tool_bar_p = false; + + dpyinfo->last_mouse_glyph_frame = NULL; + + f = mouse_or_wdesc_frame (dpyinfo, event->xbutton.window); + + if (f) + { + /* Is this in the tab-bar? */ + if (WINDOWP (f->tab_bar_window) + && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window))) + { + Lisp_Object window; + int x = event->xbutton.x; + int y = event->xbutton.y; + + window = window_from_coordinates (f, x, y, 0, true, true); + tab_bar_p = EQ (window, f->tab_bar_window); + + if (tab_bar_p) + { + tab_bar_arg = handle_tab_bar_click + (f, x, y, (event->xbutton.type + == ANDROID_BUTTON_PRESS), + android_android_to_emacs_modifiers (dpyinfo, + event->xbutton.state)); + android_flush_dirty_back_buffer_on (f); + } + } + + /* Is this in the tool-bar? */ + if (WINDOWP (f->tool_bar_window) + && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window))) + { + Lisp_Object window; + int x = event->xbutton.x; + int y = event->xbutton.y; + + window = window_from_coordinates (f, x, y, 0, true, true); + tool_bar_p = (EQ (window, f->tool_bar_window) + && ((event->xbutton.type + != ANDROID_BUTTON_RELEASE) + || f->last_tool_bar_item != -1)); + + if (tool_bar_p && event->xbutton.button < 4) + { + handle_tool_bar_click + (f, x, y, (event->xbutton.type + == ANDROID_BUTTON_PRESS), + android_android_to_emacs_modifiers (dpyinfo, + event->xbutton.state)); + android_flush_dirty_back_buffer_on (f); + } + } + + if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p) + { + android_construct_mouse_click (&inev.ie, &event->xbutton, f); + + if (!NILP (tab_bar_arg)) + inev.ie.arg = tab_bar_arg; + } + } + else + { + /* TODO: scroll bars */ + } + + if (event->type == ANDROID_BUTTON_PRESS) + { + dpyinfo->grabbed |= (1 << event->xbutton.button); + dpyinfo->last_mouse_frame = f; + if (f && !tab_bar_p) + f->last_tab_bar_item = -1; + if (f && !tool_bar_p) + f->last_tool_bar_item = -1; + } + else + dpyinfo->grabbed &= ~(1 << event->xbutton.button); + + /* Ignore any mouse motion that happened before this event; + any subsequent mouse-movement Emacs events should reflect + only motion after the ButtonPress/Release. */ + if (f != 0) + f->mouse_moved = false; + goto OTHER; default: @@ -423,6 +726,30 @@ handle_one_android_event (struct android_display_info *dpyinfo, count++; } + if (do_help + && !(hold_quit && hold_quit->kind != NO_EVENT)) + { + Lisp_Object frame; + + if (f) + XSETFRAME (frame, f); + else + frame = Qnil; + + if (do_help > 0) + { + any_help_event_p = true; + gen_help_event (help_echo_string, frame, help_echo_window, + help_echo_object, help_echo_pos); + } + else + { + help_echo_string = Qnil; + gen_help_event (Qnil, frame, Qnil, Qnil, 0); + } + count++; + } + return count; } @@ -562,7 +889,32 @@ android_mouse_position (struct frame **fp, int insist, enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y, Time *timestamp) { - /* TODO */ + Lisp_Object tail, frame; + struct android_display_info *dpyinfo; + + dpyinfo = FRAME_DISPLAY_INFO (*fp); + + /* This is the best implementation possible on Android, where the + system doesn't let Emacs obtain any information about the mouse + pointer at all. */ + + if (dpyinfo->last_mouse_motion_frame) + { + *fp = dpyinfo->last_mouse_motion_frame; + *timestamp = dpyinfo->last_mouse_movement_time; + *x = make_fixnum (dpyinfo->last_mouse_motion_x); + *y = make_fixnum (dpyinfo->last_mouse_motion_y); + *bar_window = Qnil; + *part = scroll_bar_nowhere; + + FOR_EACH_FRAME (tail, frame) + { + if (FRAME_ANDROID_P (XFRAME (frame))) + XFRAME (frame)->mouse_moved = false; + } + + dpyinfo->last_mouse_motion_frame->mouse_moved = false; + } } static Lisp_Object @@ -678,6 +1030,45 @@ android_iconify_frame (struct frame *f) /* TODO */ } +static void +android_wait_for_event (struct frame *f, int eventtype) +{ + if (!FLOATP (Vandroid_wait_for_event_timeout)) + return; + + int level = interrupt_input_blocked; + struct timespec tmo, tmo_at, time_now; + + f->wait_event_type = eventtype; + + /* Default timeout is 0.1 second. Hopefully not noticeable. */ + double timeout = XFLOAT_DATA (Vandroid_wait_for_event_timeout); + time_t timeout_seconds = (time_t) timeout; + tmo = make_timespec (timeout_seconds, + (long int) ((timeout - timeout_seconds) + * 1000 * 1000 * 1000)); + tmo_at = timespec_add (current_timespec (), tmo); + + while (f->wait_event_type) + { + pending_signals = true; + totally_unblock_input (); + /* XTread_socket is called after unblock. */ + block_input (); + interrupt_input_blocked = level; + + time_now = current_timespec (); + if (timespec_cmp (tmo_at, time_now) < 0) + break; + + tmo = timespec_sub (tmo_at, time_now); + if (android_select (0, NULL, NULL, NULL, &tmo, NULL) == 0) + break; /* Timeout */ + } + + f->wait_event_type = 0; +} + static void android_set_window_size_1 (struct frame *f, bool change_gravity, int width, int height) @@ -688,11 +1079,29 @@ android_set_window_size_1 (struct frame *f, bool change_gravity, android_resize_window (FRAME_ANDROID_WINDOW (f), width, height); - /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to - receive in the ConfigureNotify event; if we get what we asked - for, then the event won't cause the screen to become garbaged, so - we have to make sure to do it here. */ SET_FRAME_GARBAGED (f); + + if (FRAME_VISIBLE_P (f)) + { + android_wait_for_event (f, ANDROID_CONFIGURE_NOTIFY); + + if (CONSP (frame_size_history)) + frame_size_history_extra (f, build_string ("set_window_size_1 visible"), + FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f), + width, height, f->new_width, f->new_height); + } + else + { + if (CONSP (frame_size_history)) + frame_size_history_extra (f, build_string ("set_window_size_1 " + "invisible"), + FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f), + width, height, f->new_width, f->new_height); + + adjust_frame_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, width), + FRAME_PIXEL_TO_TEXT_HEIGHT (f, height), + 5, 0, Qx_set_window_size_1); + } } void @@ -792,7 +1201,6 @@ android_new_font (struct frame *f, Lisp_Object font_object, int fontset) static bool android_bitmap_icon (struct frame *f, Lisp_Object file) { - /* TODO */ return false; } @@ -841,6 +1249,13 @@ android_free_frame_resources (struct frame *f) if (f == hlinfo->mouse_face_mouse_frame) reset_mouse_highlight (hlinfo); + /* These two need to be freed now that they are used to compute the + mouse position, I think. */ + if (f == dpyinfo->last_mouse_motion_frame) + dpyinfo->last_mouse_motion_frame = NULL; + if (f == dpyinfo->last_mouse_frame) + dpyinfo->last_mouse_frame = NULL; + unblock_input (); } @@ -3233,6 +3648,18 @@ syms_of_androidterm (void) { Fprovide (Qandroid, Qnil); + DEFVAR_LISP ("android-wait-for-event-timeout", + Vandroid_wait_for_event_timeout, + doc: /* How long to wait for Android events. + +Emacs will wait up to this many seconds to receive events after +making changes which affect the state of the graphical interface. +Under some situations this can take an indefinite amount of time, +so it is important to limit the wait. + +If set to a non-float value, there will be no wait at all. */); + Vandroid_wait_for_event_timeout = make_float (0.1); + DEFVAR_BOOL ("x-use-underline-position-properties", x_use_underline_position_properties, doc: /* SKIP: real doc in xterm.c. */); diff --git a/src/androidterm.h b/src/androidterm.h index c834ffb70e5..562dcdead17 100644 --- a/src/androidterm.h +++ b/src/androidterm.h @@ -129,6 +129,9 @@ struct android_display_info /* Where the mouse was the last time the mouse moved. */ Emacs_Rectangle last_mouse_glyph; + + /* The time of the last mouse movement. */ + Time last_mouse_movement_time; }; struct android_output @@ -193,11 +196,6 @@ struct android_output and inactive states. */ bool_bf alpha_identical_p : 1; - /* Flag that indicates whether we've modified the back buffer and - need to publish our modifications to the front buffer at a - convenient time. */ - bool_bf need_buffer_flip : 1; - /* Flag that indicates whether or not the frame contents are complete and can be safely flushed while handling async input. */ @@ -376,6 +374,11 @@ extern void syms_of_androidfont (void); extern void android_finalize_font_entity (struct font_entity *); +/* Defined in sfntfont-android.c. */ + +extern void init_sfntfont_android (void); +extern void syms_of_sfntfont_android (void); + #define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b)) diff --git a/src/emacs.c b/src/emacs.c index 72b2e5e3dd0..e287ba53e13 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -37,6 +37,10 @@ along with GNU Emacs. If not, see . */ #include "androidterm.h" #endif +#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY +#include "sfntfont.h" +#endif + #ifdef WINDOWSNT #include #include @@ -2396,6 +2400,8 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem syms_of_fontset (); #if !defined ANDROID_STUBIFY syms_of_androidfont (); + syms_of_sfntfont (); + syms_of_sfntfont_android (); #endif /* !ANDROID_STUBIFY */ #endif /* HAVE_ANDROID */ @@ -2461,6 +2467,8 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY init_androidfont (); + init_sfntfont (); + init_sfntfont_android (); #endif init_charset (); diff --git a/src/frame.c b/src/frame.c index ddb49219cbd..36a256f1f3d 100644 --- a/src/frame.c +++ b/src/frame.c @@ -6644,7 +6644,7 @@ implicitly when there's no window system support. Note that when a frame is not large enough to accommodate a change of any of the parameters listed above, Emacs may try to enlarge the frame even if this option is non-nil. */); -#if defined (HAVE_WINDOW_SYSTEM) +#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_ANDROID) #if defined (USE_GTK) || defined (HAVE_NS) frame_inhibit_implied_resize = list1 (Qtab_bar_lines); #else diff --git a/src/frame.h b/src/frame.h index d39a4d5e571..4405c2df860 100644 --- a/src/frame.h +++ b/src/frame.h @@ -599,8 +599,9 @@ struct frame /* List of font-drivers available on the frame. */ struct font_driver_list *font_driver_list; -#if defined (HAVE_X_WINDOWS) - /* Used by x_wait_for_event when watching for an X event on this frame. */ +#if defined HAVE_X_WINDOWS || defined HAVE_ANDROID + /* Used by x_wait_for_event when watching for an X event on this + frame. */ int wait_event_type; #endif diff --git a/src/sfnt.c b/src/sfnt.c index 9ac023ddba9..dfdc4f7acf8 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -20,7 +20,10 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include +#include "sfnt.h" + #include +#include #include #include #include @@ -54,14 +57,12 @@ xfree (void *ptr) return free (ptr); } -static void -eassert (bool condition) -{ - if (!condition) - abort (); -} +/* Use this for functions that are static while building in test mode, + but are used outside as well. */ +#define TEST_STATIC static #else +#define TEST_STATIC #include "lisp.h" #endif @@ -75,33 +76,21 @@ eassert (bool condition) libraries such as FreeType are not easily available, and the native font library is too limited for Emacs to support properly. - Unlike most popular libraries for handling fonts, no "font" or - "face" type is provided. Instead, routines and structure + Unlike most popular libraries for handling fonts, no ``font'' or + ``face'' type is provided. Instead, routines and structure definitions for accessing and making use of individual tables in a font file are exported, which allows for flexibility in the rest of - Emacs. */ - - + Emacs. -/* The sfnt container format is organized into different tables, such - as ``cmap'' or ``glyf''. Each of these tables has a specific - format and use. These are all the tables known to Emacs. */ + Try not to keep this file too dependent on Emacs. Everything Lisp + related goes in sfntfont.c. The author wants to keep using it for + some other (free) software. */ -enum sfnt_table - { - SFNT_TABLE_CMAP, - SFNT_TABLE_GLYF, - SFNT_TABLE_HEAD, - SFNT_TABLE_HHEA, - SFNT_TABLE_HMTX, - SFNT_TABLE_LOCA, - SFNT_TABLE_MAXP, - SFNT_TABLE_NAME, - }; + /* Mapping between sfnt table names and their identifiers. */ -uint32_t sfnt_table_names[] = +static uint32_t sfnt_table_names[] = { [SFNT_TABLE_CMAP] = 0x636d6170, [SFNT_TABLE_GLYF] = 0x676c7966, @@ -111,580 +100,9 @@ uint32_t sfnt_table_names[] = [SFNT_TABLE_LOCA] = 0x6c6f6361, [SFNT_TABLE_MAXP] = 0x6d617870, [SFNT_TABLE_NAME] = 0x6e616d65, + [SFNT_TABLE_META] = 0x6d657461, }; -#define SFNT_ENDOF(type, field, type1) \ - ((size_t) offsetof (type, field) + sizeof (type1)) - -/* Each of these structures must be aligned so that no compiler will - ever generate padding bytes on platforms where the alignment - requirements for uint32_t and uint16_t are no larger than 4 and 2 - bytes respectively. */ - -struct sfnt_offset_subtable -{ - /* The scaler type. */ - uint32_t scaler_type; - - /* The number of tables. */ - uint16_t num_tables; - - /* (Maximum power of 2 <= numTables) * 16. */ - uint16_t search_range; - - /* log2 (maximum power of 2 <= numTables) */ - uint16_t entry_selector; - - /* numTables * 16 - searchRange. */ - uint16_t range_shift; - - /* Variable length data. */ - struct sfnt_table_directory *subtables; -}; - -/* The table directory. Follows the offset subtable, with one for - each table. */ - -struct sfnt_table_directory -{ - /* 4-byte identifier for each table. See sfnt_table_names. */ - uint32_t tag; - - /* Table checksum. */ - uint32_t checksum; - - /* Offset from the start of the file. */ - uint32_t offset; - - /* Length of the table in bytes, not subject to padding. */ - uint32_t length; -}; - -enum sfnt_scaler_type - { - SFNT_SCALER_TRUE = 0x74727565, - SFNT_SCALER_VER1 = 0x00010000, - SFNT_SCALER_TYP1 = 0x74797031, - SFNT_SCALER_OTTO = 0x4F54544F, - }; - -typedef int32_t sfnt_fixed; -typedef int16_t sfnt_fword; -typedef uint16_t sfnt_ufword; - -#define sfnt_coerce_fixed(fixed) ((sfnt_fixed) (fixed) / 65535.0) - -typedef unsigned int sfnt_glyph; -typedef unsigned int sfnt_char; - -struct sfnt_head_table -{ - /* The version. This is a 16.16 fixed point number. */ - sfnt_fixed version; - - /* The revision. */ - sfnt_fixed revision; - - /* Checksum adjustment. */ - uint32_t checksum_adjustment; - - /* Magic number, should be 0x5F0F3CF5. */ - uint32_t magic; - - /* Flags for the font. */ - uint16_t flags; - - /* Units per em. */ - uint16_t units_per_em; - - /* Time of creation. */ - uint32_t created_high, created_low; - - /* Time of modification. */ - uint32_t modified_high, modified_low; - - /* Minimum bounds. */ - sfnt_fword xmin, ymin, xmax, ymax; - - /* Mac specific stuff. */ - uint16_t mac_style; - - /* Smallest readable size in pixels. */ - uint16_t lowest_rec_ppem; - - /* Font direction hint. */ - int16_t font_direction_hint; - - /* Index to loc format. 0 for short offsets, 1 for long. */ - int16_t index_to_loc_format; - - /* Unused. */ - int16_t glyph_data_format; -}; - -struct sfnt_hhea_table -{ - /* The version. This is a 16.16 fixed point number. */ - sfnt_fixed version; - - /* The maximum ascent and descent values for this font. */ - sfnt_fword ascent, descent; - - /* The typographic line gap. */ - sfnt_fword line_gap; - - /* The maximum advance width. */ - sfnt_ufword advance_width_max; - - /* The minimum bearings on either side. */ - sfnt_fword min_left_side_bearing, min_right_side_bearing; - - /* The maximum extent. */ - sfnt_fword x_max_extent; - - /* Caret slope. */ - int16_t caret_slope_rise, caret_slope_run; - - /* Caret offset for non slanted fonts. */ - sfnt_fword caret_offset; - - /* Reserved values. */ - int16_t reserved1, reserved2, reserved3, reserved4; - - /* Should always be zero. */ - int16_t metric_data_format; - - /* Number of advanced widths in metrics table. */ - uint16_t num_of_long_hor_metrics; -}; - -struct sfnt_cmap_table -{ - /* Should be zero. */ - uint16_t version; - - /* Number of subtables. */ - uint16_t num_subtables; -}; - -enum sfnt_platform_id - { - SFNT_PLATFORM_UNICODE = 0, - SFNT_PLATFORM_MACINTOSH = 1, - SFNT_PLATFORM_RESERVED = 2, - SFNT_PLATFORM_MICROSOFT = 3, - }; - -enum sfnt_unicode_platform_specific_id - { - SFNT_UNICODE_1_0 = 0, - SFNT_UNICODE_1_1 = 1, - SFNT_UNICODE_ISO_10646_1993 = 2, - SFNT_UNICODE_2_0_BMP = 3, - SFNT_UNICODE_2_0 = 4, - SFNT_UNICODE_VARIATION_SEQUENCES = 5, - SFNT_UNICODE_LAST_RESORT = 6, - }; - -enum sfnt_macintosh_platform_specific_id - { - SFNT_MACINTOSH_ROMAN = 0, - SFNT_MACINTOSH_JAPANESE = 1, - SFNT_MACINTOSH_TRADITIONAL_CHINESE = 2, - SFNT_MACINTOSH_KOREAN = 3, - SFNT_MACINTOSH_ARABIC = 4, - SFNT_MACINTOSH_HEBREW = 5, - SFNT_MACINTOSH_GREEK = 6, - SFNT_MACINTOSH_RUSSIAN = 7, - SFNT_MACINTOSH_RSYMBOL = 8, - SFNT_MACINTOSH_DEVANGARI = 9, - SFNT_MACINTOSH_GURMUKHI = 10, - SFNT_MACINTOSH_GUJARATI = 11, - SFNT_MACINTOSH_ORIYA = 12, - SFNT_MACINTOSH_BENGALI = 13, - SFNT_MACINTOSH_TAMIL = 14, - SFNT_MACINTOSH_TELUGU = 15, - SFNT_MACINTOSH_KANNADA = 16, - SFNT_MACINTOSH_MALAYALAM = 17, - SFNT_MACINTOSH_SINHALESE = 18, - SFNT_MACINTOSH_BURMESE = 19, - SFNT_MACINTOSH_KHMER = 20, - SFNT_MACINTOSH_THAI = 21, - SFNT_MACINTOSH_LAOTIAN = 22, - SFNT_MACINTOSH_GEORGIAN = 23, - SFNT_MACINTOSH_ARMENIAN = 24, - SFNT_MACINTOSH_SIMPLIFIED_CHINESE = 25, - SFNT_MACINTOSH_TIBETIAN = 26, - SFNT_MACINTOSH_MONGOLIAN = 27, - SFNT_MACINTOSH_GEEZ = 28, - SFNT_MACINTOSH_SLAVIC = 29, - SFNT_MACINTOSH_VIETNAMESE = 30, - SFNT_MACINTOSH_SINDHI = 31, - SFNT_MACINTOSH_UNINTERPRETED = 32, - }; - -enum sfnt_microsoft_platform_specific_id - { - SFNT_MICROSOFT_SYMBOL = 0, - SFNT_MICROSOFT_UNICODE_BMP = 1, - SFNT_MICROSOFT_SHIFT_JIS = 2, - SFNT_MICROSOFT_PRC = 3, - SFNT_MICROSOFT_BIG_FIVE = 4, - SFNT_MICROSOFT_JOHAB = 5, - SFNT_MICROSOFT_UNICODE_UCS_4 = 6, - }; - -struct sfnt_cmap_encoding_subtable -{ - /* The platform ID. */ - uint16_t platform_id; - - /* Platform specific ID. */ - uint16_t platform_specific_id; - - /* Mapping table offset. */ - uint32_t offset; -}; - -struct sfnt_cmap_encoding_subtable_data -{ - /* Format and possibly the length in bytes. */ - uint16_t format, length; -}; - -struct sfnt_cmap_format_0 -{ - /* Format, set to 0. */ - uint16_t format; - - /* Length in bytes. Should be 262. */ - uint16_t length; - - /* Language code. */ - uint16_t language; - - /* Character code to glyph index map. */ - uint8_t glyph_index_array[256]; -}; - -struct sfnt_cmap_format_2_subheader -{ - uint16_t first_code; - uint16_t entry_count; - int16_t id_delta; - uint16_t id_range_offset; -}; - -struct sfnt_cmap_format_2 -{ - /* Format, set to 2. */ - uint16_t format; - - /* Length in bytes. */ - uint16_t length; - - /* Language code. */ - uint16_t language; - - /* Array mapping high bytes to subheaders. */ - uint16_t sub_header_keys[256]; - - /* Variable length data. */ - struct sfnt_cmap_format_2_subheader *subheaders; - uint16_t *glyph_index_array; - uint16_t num_glyphs; -}; - -struct sfnt_cmap_format_4 -{ - /* Format, set to 4. */ - uint16_t format; - - /* Length in bytes. */ - uint16_t length; - - /* Language code. */ - uint16_t language; - - /* 2 * seg_count. */ - uint16_t seg_count_x2; - - /* 2 * (2**FLOOR(log2(segCount))) */ - uint16_t search_range; - - /* log2(searchRange/2) */ - uint16_t entry_selector; - - /* Variable-length data. */ - uint16_t *end_code; - uint16_t *reserved_pad; - uint16_t *start_code; - int16_t *id_delta; - int16_t *id_range_offset; - uint16_t *glyph_index_array; - - /* The number of elements in glyph_index_array. */ - size_t glyph_index_size; -}; - -struct sfnt_cmap_format_6 -{ - /* Format, set to 6. */ - uint16_t format; - - /* Length in bytes. */ - uint16_t length; - - /* Language code. */ - uint16_t language; - - /* First character code in subrange. */ - uint16_t first_code; - - /* Number of character codes. */ - uint16_t entry_count; - - /* Variable-length data. */ - uint16_t *glyph_index_array; -}; - -struct sfnt_cmap_format_8_or_12_group -{ - uint32_t start_char_code; - uint32_t end_char_code; - uint32_t start_glyph_code; -}; - -struct sfnt_cmap_format_8 -{ - /* Format, set to 8. */ - uint16_t format; - - /* Reserved. */ - uint16_t reserved; - - /* Length in bytes. */ - uint32_t length; - - /* Language code. */ - uint32_t language; - - /* Tightly packed array of bits (8K bytes total) indicating whether - the particular 16-bit (index) value is the start of a 32-bit - character code. */ - uint8_t is32[65536]; - - /* Number of groups. */ - uint32_t num_groups; - - /* Variable length data. */ - struct sfnt_cmap_format_8_or_12_group *groups; -}; - -/* cmap formats 10, 13 and 14 unsupported. */ - -struct sfnt_cmap_format_12 -{ - /* Format, set to 12. */ - uint16_t format; - - /* Reserved. */ - uint16_t reserved; - - /* Length in bytes. */ - uint32_t length; - - /* Language code. */ - uint32_t language; - - /* Number of groups. */ - uint32_t num_groups; - - /* Variable length data. */ - struct sfnt_cmap_format_8_or_12_group *groups; -}; - -struct sfnt_maxp_table -{ - /* Table version. */ - sfnt_fixed version; - - /* The number of glyphs in this font - 1. Set at version 0.5 or - later. */ - uint16_t num_glyphs; - - /* These fields are only set in version 1.0 or later. Maximum - points in a non-composite glyph. */ - uint16_t max_points; - - /* Maximum contours in a non-composite glyph. */ - uint16_t max_contours; - - /* Maximum points in a composite glyph. */ - uint16_t max_composite_points; - - /* Maximum contours in a composite glyph. */ - uint16_t max_composite_contours; - - /* 1 if instructions do not use the twilight zone (Z0), or 2 if - instructions do use Z0; should be set to 2 in most cases. */ - uint16_t max_zones; - - /* Maximum points used in Z0. */ - uint16_t max_twilight_points; - - /* Number of Storage Area locations. */ - uint16_t max_storage; - - /* Number of FDEFs, equal to the highest function number + 1. */ - uint16_t max_function_defs; - - /* Number of IDEFs. */ - uint16_t max_instruction_defs; - - /* Maximum stack depth across Font Program ('fpgm' table), CVT - Program ('prep' table) and all glyph instructions (in the 'glyf' - table). */ - uint16_t max_stack_elements; - - /* Maximum byte count for glyph instructions. */ - uint16_t max_size_of_instructions; - - /* Maximum number of components referenced at ``top level'' for any - composite glyph. */ - uint16_t max_component_elements; - - /* Maximum levels of recursion; 1 for simple components. */ - uint16_t max_component_depth; -}; - -struct sfnt_loca_table_short -{ - /* Offsets to glyph data divided by two. */ - uint16_t *offsets; - - /* Size of the offsets list. */ - size_t num_offsets; -}; - -struct sfnt_loca_table_long -{ - /* Offsets to glyph data. */ - uint32_t *offsets; - - /* Size of the offsets list. */ - size_t num_offsets; -}; - -struct sfnt_glyf_table -{ - /* Size of the glyph data. */ - size_t size; - - /* Pointer to possibly unaligned glyph data. */ - unsigned char *glyphs; -}; - -struct sfnt_simple_glyph -{ - /* The total number of points in this glyph. */ - size_t number_of_points; - - /* Array containing the last points of each contour. */ - uint16_t *end_pts_of_contours; - - /* Total number of bytes needed for instructions. */ - uint16_t instruction_length; - - /* Instruction data. */ - uint8_t *instructions; - - /* Array of flags. */ - uint8_t *flags; - - /* Array of X coordinates. */ - int16_t *x_coordinates; - - /* Array of Y coordinates. */ - int16_t *y_coordinates; - - /* Pointer to the end of that array. */ - int16_t *y_coordinates_end; -}; - -struct sfnt_compound_glyph_component -{ - /* Compound glyph flags. */ - uint16_t flags; - - /* Component glyph index. */ - uint16_t glyph_index; - - /* X-offset for component or point number; type depends on bits 0 - and 1 in component flags. */ - union { - uint8_t a; - int8_t b; - uint16_t c; - int16_t d; - } argument1; - - /* Y-offset for component or point number; type depends on bits 0 - and 1 in component flags. */ - union { - uint8_t a; - int8_t b; - uint16_t c; - int16_t d; - } argument2; - - /* Various scale formats. */ - union { - uint16_t scale; - struct { - uint16_t xscale; - uint16_t yscale; - } a; - struct { - uint16_t xscale; - uint16_t scale01; - uint16_t scale10; - uint16_t yscale; - } b; - } u; -}; - -struct sfnt_compound_glyph -{ - /* Pointer to array of components. */ - struct sfnt_compound_glyph_component *components; - - /* Number of elements in that array. */ - size_t num_components; - - /* Instruction data. */ - uint8_t *instructions; - - /* Length of instructions. */ - uint16_t instruction_length; -}; - -struct sfnt_glyph -{ - /* Number of contours in this glyph. */ - int16_t number_of_contours; - - /* Coordinate bounds. */ - sfnt_fword xmin, ymin, xmax, ymax; - - /* Either a simple glyph or a compound glyph, depending on which is - set. */ - struct sfnt_simple_glyph *simple; - struct sfnt_compound_glyph *compound; -}; - - - /* Swap values from TrueType to system byte order. */ static void @@ -710,7 +128,7 @@ _sfnt_swap32 (uint32_t *value) the start of the file, and must be seekable. Return the table directory upon success, else NULL. */ -static struct sfnt_offset_subtable * +TEST_STATIC struct sfnt_offset_subtable * sfnt_read_table_directory (int fd) { struct sfnt_offset_subtable *subtable; @@ -1375,7 +793,7 @@ sfnt_read_cmap_table_1 (int fd, uint32_t directory_offset, Return the CMAP table and a list of encoding subtables in *SUBTABLES and *DATA upon success, else NULL. */ -static struct sfnt_cmap_table * +TEST_STATIC struct sfnt_cmap_table * sfnt_read_cmap_table (int fd, struct sfnt_offset_subtable *subtable, struct sfnt_cmap_encoding_subtable **subtables, struct sfnt_cmap_encoding_subtable_data ***data) @@ -1732,7 +1150,7 @@ sfnt_lookup_glyph (sfnt_char character, Return the head table upon success, else NULL. */ -static struct sfnt_head_table * +TEST_STATIC struct sfnt_head_table * sfnt_read_head_table (int fd, struct sfnt_offset_subtable *subtable) { struct sfnt_table_directory *directory; @@ -1804,7 +1222,7 @@ sfnt_read_head_table (int fd, struct sfnt_offset_subtable *subtable) Return the head table upon success, else NULL. */ -static struct sfnt_hhea_table * +TEST_STATIC struct sfnt_hhea_table * sfnt_read_hhea_table (int fd, struct sfnt_offset_subtable *subtable) { struct sfnt_table_directory *directory; @@ -1870,7 +1288,7 @@ sfnt_read_hhea_table (int fd, struct sfnt_offset_subtable *subtable) Return the short table upon success, else NULL. */ -static struct sfnt_loca_table_short * +TEST_STATIC struct sfnt_loca_table_short * sfnt_read_loca_table_short (int fd, struct sfnt_offset_subtable *subtable) { struct sfnt_table_directory *directory; @@ -1915,7 +1333,7 @@ sfnt_read_loca_table_short (int fd, struct sfnt_offset_subtable *subtable) Return the long table upon success, else NULL. */ -static struct sfnt_loca_table_long * +TEST_STATIC struct sfnt_loca_table_long * sfnt_read_loca_table_long (int fd, struct sfnt_offset_subtable *subtable) { struct sfnt_table_directory *directory; @@ -1961,7 +1379,7 @@ sfnt_read_loca_table_long (int fd, struct sfnt_offset_subtable *subtable) Return the maxp table upon success, else NULL. If the version is 0.5, fields past num_glyphs will not be populated. */ -static struct sfnt_maxp_table * +TEST_STATIC struct sfnt_maxp_table * sfnt_read_maxp_table (int fd, struct sfnt_offset_subtable *subtable) { struct sfnt_table_directory *directory; @@ -2048,7 +1466,7 @@ sfnt_read_maxp_table (int fd, struct sfnt_offset_subtable *subtable) Return the glyf table upon success, else NULL. */ -static struct sfnt_glyf_table * +TEST_STATIC struct sfnt_glyf_table * sfnt_read_glyf_table (int fd, struct sfnt_offset_subtable *subtable) { struct sfnt_table_directory *directory; @@ -2545,6 +1963,9 @@ sfnt_read_compound_glyph (struct sfnt_glyph *glyph, data += sizeof words4; } + /* Record the component flags. */ + glyph->compound->components[i].flags = flags; + i++; } while (flags & 040); /* MORE_COMPONENTS */ @@ -2595,7 +2016,7 @@ sfnt_read_compound_glyph (struct sfnt_glyph *glyph, glyf table, using the offsets of LOCA_SHORT or LOCA_LONG, depending on which is non-NULL. */ -static struct sfnt_glyph * +TEST_STATIC struct sfnt_glyph * sfnt_read_glyph (sfnt_glyph glyph_code, struct sfnt_glyf_table *glyf, struct sfnt_loca_table_short *loca_short, @@ -2696,22 +2117,6 @@ sfnt_free_glyph (struct sfnt_glyph *glyph) /* Glyph outline decomposition. */ -struct sfnt_point -{ - /* X and Y in em space. */ - sfnt_fixed x, y; -}; - -typedef void (*sfnt_move_to_proc) (struct sfnt_point, void *); -typedef void (*sfnt_line_to_proc) (struct sfnt_point, void *); -typedef void (*sfnt_curve_to_proc) (struct sfnt_point, - struct sfnt_point, - void *); - -typedef struct sfnt_glyph *(*sfnt_get_glyph_proc) (sfnt_glyph, void *, - bool *); -typedef void (*sfnt_free_glyph_proc) (struct sfnt_glyph *, void *); - /* Apply the transform in the compound glyph component COMPONENT to the array of points of length NUM_COORDINATES given as X and Y. */ @@ -2834,7 +2239,8 @@ sfnt_expand_compound_glyph_context (struct sfnt_compound_glyph_context *context, size_bytes); context->y_coordinates = xrealloc (context->y_coordinates, size_bytes); - context->flags = xrealloc (context->flags, context->num_points); + context->flags = xrealloc (context->flags, + context->points_size); } /* Set x_base and y_base. */ @@ -2900,7 +2306,7 @@ sfnt_decompose_compound_glyph (struct sfnt_glyph *glyph, void *dcontext) { struct sfnt_glyph *subglyph; - int i, rc; + int i, j, rc; bool need_free; struct sfnt_compound_glyph_component *component; sfnt_fixed x, y, xtemp, ytemp; @@ -2918,10 +2324,10 @@ sfnt_decompose_compound_glyph (struct sfnt_glyph *glyph, /* Set up the base index. */ base_index = context->num_points; - for (i = 0; i < glyph->compound->num_components; ++i) + for (j = 0; j < glyph->compound->num_components; ++j) { /* Look up the associated subglyph. */ - component = &glyph->compound->components[i]; + component = &glyph->compound->components[j]; subglyph = get_glyph (component->glyph_index, dcontext, &need_free); @@ -3345,49 +2751,6 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph, return 1; } -/* Structure describing a single recorded outline in fixed pixel - space. */ - -struct sfnt_glyph_outline -{ - /* Packed outline data. This is made of aligned, signed, 4 byte - words. The first word is a number containing flags. The second - and third words are a point in 16.16 fixed format. */ - int *outline; - - /* Size of the outline data in word increments, and how much is - full. */ - size_t outline_size, outline_used; - - /* Rectangle defining bounds of the outline. Namely, the minimum - and maximum X and Y positions. */ - sfnt_fixed xmin, ymin, xmax, ymax; -}; - -enum sfnt_glyph_outline_flags - { - SFNT_GLYPH_OUTLINE_LINETO = (1 << 1), - }; - -struct sfnt_build_glyph_outline_context -{ - /* The outline being built. */ - struct sfnt_glyph_outline *outline; - - /* The head table. */ - struct sfnt_head_table *head; - - /* The pixel size being used, and any extra flags to apply to the - outline at this point. */ - int pixel_size; - - /* Factor to multiply positions by to get the pixel width. */ - double factor; - - /* The position of the pen in 16.16 fixed point format. */ - sfnt_fixed x, y; -}; - /* Global state for sfnt_build_glyph_outline and related functions. */ static struct sfnt_build_glyph_outline_context build_outline_context; @@ -3397,7 +2760,7 @@ static struct sfnt_build_glyph_outline_context build_outline_context; memory. */ static struct sfnt_glyph_outline * -sfnt_build_append (unsigned int flags, unsigned int x, unsigned int y) +sfnt_build_append (int flags, sfnt_fixed x, sfnt_fixed y) { struct sfnt_glyph_outline *outline; @@ -3407,7 +2770,7 @@ sfnt_build_append (unsigned int flags, unsigned int x, unsigned int y) return build_outline_context.outline; outline = build_outline_context.outline; - outline->outline_used += 3; + outline->outline_used++; /* See if the outline has to be extended. Checking for overflow should not be necessary. */ @@ -3420,13 +2783,14 @@ sfnt_build_append (unsigned int flags, unsigned int x, unsigned int y) outline = xrealloc (outline, (sizeof *outline + (outline->outline_size * sizeof *outline->outline))); - outline->outline = (int *) (outline + 1); + outline->outline + = (struct sfnt_glyph_outline_command *) (outline + 1); } /* Write the outline data. */ - outline->outline[outline->outline_used - 3] = flags; - outline->outline[outline->outline_used - 2] = x; - outline->outline[outline->outline_used - 1] = y; + outline->outline[outline->outline_used - 1].flags = flags; + outline->outline[outline->outline_used - 1].x = x; + outline->outline[outline->outline_used - 1].y = y; /* Extend outline bounding box. */ @@ -3650,7 +3014,7 @@ sfnt_curve_to_and_build (struct sfnt_point control, HEAD should be the `head' table of the font. */ -static struct sfnt_glyph_outline * +TEST_STATIC struct sfnt_glyph_outline * sfnt_build_glyph_outline (struct sfnt_glyph *glyph, struct sfnt_head_table *head, int pixel_size, @@ -3662,10 +3026,11 @@ sfnt_build_glyph_outline (struct sfnt_glyph *glyph, int rc; /* Allocate the outline now with enough for 44 words at the end. */ - outline = xmalloc (sizeof *outline + 44 * sizeof (unsigned int)); - outline->outline_size = 44; + outline = xmalloc (sizeof *outline + 40 * sizeof (*outline->outline)); + outline->outline_size = 40; outline->outline_used = 0; - outline->outline = (int *) (outline + 1); + outline->outline + = (struct sfnt_glyph_outline_command *) (outline + 1); /* DCONTEXT will be passed to GET_GLYPH and FREE_GLYPH, so global variables must be used to communicate with the decomposition @@ -3722,50 +3087,6 @@ sfnt_build_glyph_outline (struct sfnt_glyph *glyph, Then, a bog standard edge filler is used to turn them into spans. */ -struct sfnt_raster -{ - /* Basic dimensions of the raster. */ - unsigned short width, height; - - /* Integer offset to apply to positions in the raster. */ - unsigned short offx, offy; - - /* Pointer to coverage data. */ - unsigned char *cells; -}; - -struct sfnt_edge -{ - /* Next edge in this chain. */ - struct sfnt_edge *next; - - /* Winding direction. 1 if clockwise, -1 if counterclockwise. */ - int winding; - - /* inc_x is which direction (left or right) a vector from this edge - to the edge on top goes. */ - int inc_x; - - /* X position, top and bottom of edges. */ - sfnt_fixed x, top, bottom; - - /* DX and DY are the total delta between this edge and the next edge - on top. */ - sfnt_fixed dx, dy; - - /* step_x is how many pixels to move for each increase in Y. */ - sfnt_fixed step_x; -}; - -enum - { - SFNT_POLY_SHIFT = 2, - SFNT_POLY_SAMPLE = (1 << SFNT_POLY_SHIFT), - SFNT_POLY_MASK = (SFNT_POLY_SAMPLE - 1), - SFNT_POLY_STEP = (0x10000 >> SFNT_POLY_SHIFT), - SFNT_POLY_START = (SFNT_POLY_STEP >> 1), - }; - /* Coverage table. This is a four dimensional array indiced by the Y, then X axis fractional, shifted down to 2 bits. */ @@ -3802,7 +3123,7 @@ sfnt_prepare_raster (struct sfnt_raster *raster, raster->offx = sfnt_floor_fixed (outline->xmin); raster->offy - = sfnt_floor_fixed (outline->xmax); + = sfnt_floor_fixed (raster->height - outline->ymax); } typedef void (*sfnt_edge_proc) (struct sfnt_edge *, size_t, @@ -3831,39 +3152,37 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline *outline, { struct sfnt_edge *edges; size_t i, edge, start, next_vertex, y; + sfnt_fixed dx, dy, bot; + int inc_x; + size_t top, bottom; - eassert (!(outline->outline_used % 3)); - - /* outline->outline uses 3 words for each point. */ - edges = alloca (outline->outline_used / 3 * sizeof *edges); + edges = alloca (outline->outline_used * sizeof *edges); edge = 0; /* First outline currently being processed. */ start = 0; - for (i = 0; i < outline->outline_used; i += 3) + for (i = 0; i < outline->outline_used; i++) { - if (!(outline->outline[i] & SFNT_GLYPH_OUTLINE_LINETO)) + if (!(outline->outline[i].flags & SFNT_GLYPH_OUTLINE_LINETO)) /* Flush the edge. */ start = i; /* Set NEXT_VERTEX to the next point (vertex) in this contour. If i + 3 is the end of the contour, then the next point is its start, so wrap it around to there. */ - next_vertex = i + 3; + next_vertex = i + 1; if (next_vertex == outline->outline_used - || !(outline->outline[next_vertex] + || !(outline->outline[next_vertex].flags & SFNT_GLYPH_OUTLINE_LINETO)) next_vertex = start; /* Skip past horizontal vertices. */ - if (outline->outline[next_vertex + 2] /* next_vertex->y */ - == outline->outline[i + 2]) + if (outline->outline[next_vertex].y == outline->outline[i].y) continue; /* Figure out the winding direction. */ - if (outline->outline[next_vertex + 2] /* next_vertex->y */ - < outline->outline[i + 2]) + if (outline->outline[next_vertex].y < outline->outline[i].y) /* Vector will cross imaginary ray from its bottom from the left of the ray. Winding is thus 1. */ edges[edge].winding = 1; @@ -3876,68 +3195,49 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline *outline, If the next edge is above, then top is there and this is the bottom. */ - if (outline->outline[next_vertex + 2] < outline->outline[i + 2]) + if (outline->outline[next_vertex].y < outline->outline[i].y) { - /* Next edge is below this one (keep in mind this is a + /* End of edge is below this one (keep in mind this is a cartesian coordinate system, so smaller values are below larger ones.) */ - edges[edge].top = (outline->outline[i + 2] - - outline->ymin); - edges[edge].bottom = (outline->outline[next_vertex + 2] - - outline->ymin); - - /* Record the edge. Rasterization happens from bottom to - up, so record the X at the bottom. */ - edges[edge].x = (outline->outline[next_vertex + 1] - - outline->xmin); - - eassert (edges[edge].top >= edges[edge].bottom); - - edges[edge].dx = (outline->outline[i + 1] - - outline->outline[next_vertex + 1]); + top = i; + bottom = next_vertex; } else { - /* Next edge is below this one. */ - edges[edge].bottom = (outline->outline[i + 2] - - outline->ymin); - edges[edge].top = (outline->outline[next_vertex + 2] - - outline->ymin); - - /* Record the edge. Rasterization happens from bottom to - up, so record the X at the bottom. */ - edges[edge].x = (outline->outline[i + 1] - - outline->xmin); - - eassert (edges[edge].top >= edges[edge].bottom); - - edges[edge].dx = (outline->outline[next_vertex + 1] - - outline->outline[i + 1]); + /* End of edge is above this one. */ + bottom = i; + top = next_vertex; } - edges[edge].dy = abs (outline->outline[i + 2] - - outline->outline[next_vertex + 2]); + bot = (outline->outline[bottom].y - outline->ymin); + edges[edge].top = (outline->outline[top].y - outline->ymin); + + /* Record the edge. Rasterization happens from bottom to + up, so record the X at the bottom. */ + edges[edge].x = (outline->outline[bottom].x - outline->xmin); + dx = (outline->outline[top].x - outline->outline[bottom].x); + dy = abs (outline->outline[top].y + - outline->outline[bottom].y); /* Compute the increment. This is which direction X moves in for each increase in Y. */ - if (edges[edge].dx >= 0) - edges[edge].inc_x = 1; + if (dx >= 0) + inc_x = 1; else { - edges[edge].inc_x = -1; - edges[edge].dx = -edges[edge].dx; + inc_x = -1; + dx = -dx; } /* Compute the step X. This is how much X changes for each increase in Y. */ - edges[edge].step_x = (edges[edge].inc_x - * sfnt_div_fixed (edges[edge].dx, - edges[edge].dy)); + edges[edge].step_x = inc_x * sfnt_div_fixed (dx, dy); /* Step to first grid point. */ - y = sfnt_poly_grid_ceil (edges[edge].bottom); - sfnt_step_edge_by (&edges[edge], edges[edge].bottom - y); + y = sfnt_poly_grid_ceil (bot); + sfnt_step_edge_by (&edges[edge], bot - y); edges[edge].bottom = y; edges[edge].next = NULL; @@ -4219,7 +3519,7 @@ sfnt_raster_edge (struct sfnt_edge *edges, size_t num_edges, /* Generate an alpha mask for the glyph outline OUTLINE. Value is the alpha mask upon success, NULL upon failure. */ -static struct sfnt_raster * +TEST_STATIC struct sfnt_raster * sfnt_raster_glyph_outline (struct sfnt_glyph_outline *outline) { struct sfnt_raster raster, *data; @@ -4245,35 +3545,6 @@ sfnt_raster_glyph_outline (struct sfnt_glyph_outline *outline) /* Glyph metrics computation. */ -struct sfnt_long_hor_metric -{ - uint16_t advance_width; - int16_t left_side_bearing; -}; - -struct sfnt_hmtx_table -{ - /* Array of horizontal metrics for each glyph. */ - struct sfnt_long_hor_metric *h_metrics; - - /* Lbearing for remaining glyphs. */ - int16_t *left_side_bearing; -}; - -/* Structure describing the metrics of a single glyph. The fields - mean the same as in XCharStruct, except they are 16.16 fixed point - values, and are missing significant information. */ - -struct sfnt_glyph_metrics -{ - /* Distance between origin and left edge of raster. Positive - changes move rightwards. */ - sfnt_fixed lbearing; - - /* Advance to next glyph's origin. */ - sfnt_fixed advance; -}; - /* Read an hmtx table from the font FD, using the table directory specified as SUBTABLE, the maxp table MAXP, and the hhea table HHEA. @@ -4284,7 +3555,7 @@ struct sfnt_glyph_metrics HHEA->num_of_long_hor_metrics determines the number of left-side bearings present. */ -static struct sfnt_hmtx_table * +TEST_STATIC struct sfnt_hmtx_table * sfnt_read_hmtx_table (int fd, struct sfnt_offset_subtable *subtable, struct sfnt_hhea_table *hhea, struct sfnt_maxp_table *maxp) @@ -4344,8 +3615,8 @@ sfnt_read_hmtx_table (int fd, struct sfnt_offset_subtable *subtable, sfnt_swap16 (&hmtx->h_metrics[i].left_side_bearing); } - for (; i <= maxp->num_glyphs; ++i) - sfnt_swap16 (&hmtx->left_side_bearing[i]); + for (; i < maxp->num_glyphs; ++i) + sfnt_swap16 (&hmtx->left_side_bearing[i - hhea->num_of_long_hor_metrics]); /* All done. */ return hmtx; @@ -4358,7 +3629,7 @@ sfnt_read_hmtx_table (int fd, struct sfnt_offset_subtable *subtable, HMTX, HHEA, HEAD and MAXP should be the hmtx, hhea, head, and maxp tables of the font respectively. */ -static int +TEST_STATIC int sfnt_lookup_glyph_metrics (sfnt_glyph glyph, int pixel_size, struct sfnt_glyph_metrics *metrics, struct sfnt_hmtx_table *hmtx, @@ -4377,7 +3648,7 @@ sfnt_lookup_glyph_metrics (sfnt_glyph glyph, int pixel_size, advance = hmtx->h_metrics[glyph].advance_width; } else if (hhea->num_of_long_hor_metrics - && glyph <= maxp->num_glyphs) + && glyph < maxp->num_glyphs) { /* There is a short entry in the hmtx table. */ lbearing @@ -4404,6 +3675,342 @@ sfnt_lookup_glyph_metrics (sfnt_glyph glyph, int pixel_size, +/* Font style parsing. */ + +/* Read the name table from the given font FD, using the table + directory specified as SUBTABLE. Perform validation on the offsets + in the name records. Return NULL upon failure, else the name + table. */ + +TEST_STATIC struct sfnt_name_table * +sfnt_read_name_table (int fd, struct sfnt_offset_subtable *subtable) +{ + struct sfnt_table_directory *directory; + struct sfnt_name_table *name; + size_t required; + ssize_t rc; + int i; + + /* Find the table in the directory. */ + + directory = sfnt_find_table (subtable, SFNT_TABLE_NAME); + + if (!directory) + return NULL; + + /* Seek to the location given in the directory. */ + if (lseek (fd, directory->offset, SEEK_SET) == (off_t) -1) + return NULL; + + /* Figure out the minimum that has to be read. */ + required = SFNT_ENDOF (struct sfnt_name_table, + string_offset, uint16_t); + + if (directory->length < required) + return NULL; + + /* Allocate enough to hold the name table and variable length + data. */ + name = xmalloc (sizeof *name + directory->length); + + /* Read the fixed length data. */ + rc = read (fd, name, required); + if (rc < required) + { + xfree (name); + return NULL; + } + + /* Swap what was read. */ + sfnt_swap16 (&name->format); + sfnt_swap16 (&name->count); + sfnt_swap16 (&name->string_offset); + + /* Reject unsupported formats. */ + if (name->format) + { + xfree (name); + return NULL; + } + + /* Set the pointer to the start of the variable length data. */ + name->name_records + = (struct sfnt_name_record *) (name + 1); + + /* Check there is enough for the name records. */ + required = directory->length - required; + if (required < name->count * sizeof *name->name_records) + { + xfree (name); + return NULL; + } + + /* Read the variable length data. First, read the name records. */ + rc = read (fd, name->name_records, + (name->count + * sizeof *name->name_records)); + if (rc < (name->count + * sizeof *name->name_records)) + { + xfree (name); + return NULL; + } + + /* Swap each of the name records. */ + for (i = 0; i < name->count; ++i) + { + sfnt_swap16 (&name->name_records[i].platform_id); + sfnt_swap16 (&name->name_records[i].platform_specific_id); + sfnt_swap16 (&name->name_records[i].language_id); + sfnt_swap16 (&name->name_records[i].name_id); + sfnt_swap16 (&name->name_records[i].length); + sfnt_swap16 (&name->name_records[i].offset); + } + + /* Now, read the name data. */ + + if (name->string_offset > directory->length) + { + xfree (name); + return NULL; + } + + required = directory->length - name->string_offset; + + /* It can happen that the string offset comes before the name + records, and as a result exceeds the number of bytes + previously allocated. Extend name if that is the case. */ + + if (required > (directory->length + - (name->count + * sizeof *name->name_records))) + { + name = xrealloc (name, (sizeof *name + + (name->count + * sizeof *name->name_records) + + required)); + name->name_records = (struct sfnt_name_record *) (name + 1); + } + + /* There is enough space past name->name_records to hold REQUIRED + bytes. Seek to the right offset. */ + + if (lseek (fd, directory->offset + name->string_offset, + SEEK_SET) == (off_t) -1) + { + xfree (name); + return NULL; + } + + /* Read REQURIED bytes into the string data. */ + name->data = (unsigned char *) (name->name_records + + name->count); + rc = read (fd, name->data, required); + if (rc < required) + { + xfree (name); + return NULL; + } + + /* Now validate each of the name records. */ + for (i = 0; i < name->count; ++i) + { + if (((int) name->name_records[i].offset + + name->name_records[i].length) > required) + { + /* The name is out of bounds! */ + xfree (name); + return NULL; + } + } + + /* Return the name table. */ + return name; +} + +/* Return a pointer to the name data corresponding with CODE under the + name table NAME. Return the start of the data and the name record + under *RECORD upon success, and NULL otherwise. */ + +TEST_STATIC unsigned char * +sfnt_find_name (struct sfnt_name_table *name, + enum sfnt_name_identifier_code code, + struct sfnt_name_record *record) +{ + int i; + + for (i = 0; i < name->count; ++i) + { + if (name->name_records[i].name_id == code) + { + /* The offsets within have already been validated. */ + *record = name->name_records[i]; + return name->data + record->offset; + } + } + + return NULL; +} + +/* Read the meta table from the give font FD, using the table + directory specified as SUBTABLE. Perform validation on the offsets + in each metadata record. Return NULL upon failure, else the meta + table. */ + +TEST_STATIC struct sfnt_meta_table * +sfnt_read_meta_table (int fd, struct sfnt_offset_subtable *subtable) +{ + struct sfnt_table_directory *directory; + struct sfnt_meta_table *meta; + size_t required, i, data_size, map_size, offset; + ssize_t rc; + + /* Find the table in the directory. */ + + directory = sfnt_find_table (subtable, SFNT_TABLE_META); + + if (!directory) + return NULL; + + /* Seek to the location given in the directory. */ + if (lseek (fd, directory->offset, SEEK_SET) == (off_t) -1) + return NULL; + + /* Figure out the minimum that has to be read. */ + required = SFNT_ENDOF (struct sfnt_meta_table, + num_data_maps, uint32_t); + + if (directory->length < required) + return NULL; + + /* Allocate enough to hold it. */ + meta = xmalloc (sizeof *meta); + + /* Read the header. */ + rc = read (fd, meta, required); + if (rc < required) + { + xfree (meta); + return NULL; + } + + /* Swap what has been read so far. */ + sfnt_swap32 (&meta->version); + sfnt_swap32 (&meta->flags); + sfnt_swap32 (&meta->data_offset); + sfnt_swap32 (&meta->num_data_maps); + + /* Make sure the meta is supported. */ + if (meta->version != 1) + { + xfree (meta); + return NULL; + } + + /* Reallocate the table to hold sizeof *meta + meta->num_data_maps + times sizeof meta->data_maps + directory->length bytes. This is + because it is ok for metadata to point into the data map itself, + so an unswapped copy of the whole meta contents must be + retained. */ + + if (INT_MULTIPLY_WRAPV (sizeof *meta->data_maps, meta->num_data_maps, + &map_size) + /* Do so while checking for overflow from bad sfnt files. */ + || INT_ADD_WRAPV (map_size, sizeof *meta, &data_size) + || INT_ADD_WRAPV (data_size, directory->length, &data_size)) + { + xfree (meta); + return NULL; + } + + /* Do the reallocation. */ + meta = xrealloc (meta, data_size); + + /* Check that the remaining data is big enough to hold the data + maps. */ + if (directory->length - required < map_size) + { + xfree (meta); + return NULL; + } + + /* Set pointers to data_maps and data. */ + meta->data_maps = (struct sfnt_meta_data_map *) (meta + 1); + meta->data = (unsigned char *) (meta->data_maps + + meta->num_data_maps); + + /* Now, seek back. Read the entire table into meta->data. */ + if (lseek (fd, directory->offset, SEEK_SET) == (off_t) -1) + { + xfree (meta); + return NULL; + } + + rc = read (fd, meta->data, directory->length); + if (rc < directory->length) + { + xfree (meta); + return NULL; + } + + /* Copy the data maps into meta->data_maps and swap them one by + one. */ + memcpy (meta->data_maps, meta->data + required, + map_size); + + for (i = 0; i < meta->num_data_maps; ++i) + { + sfnt_swap32 (&meta->data_maps[i].tag); + sfnt_swap32 (&meta->data_maps[i].data_offset); + sfnt_swap32 (&meta->data_maps[i].data_length); + + /* Verify the data offsets. Overflow checking is particularly + important here. */ + + if (INT_ADD_WRAPV (meta->data_maps[i].data_offset, + meta->data_maps[i].data_length, + &offset)) + { + xfree (meta); + return NULL; + } + + if (offset > directory->length) + { + xfree (meta); + return NULL; + } + } + + /* All done. */ + return meta; +} + +/* Return a pointer to the metadata corresponding to TAG under the + meta table META. Return the start of the data and the metadata map + under *MAP upon success, and NULL otherwise. */ + +MAYBE_UNUSED TEST_STATIC char * +sfnt_find_metadata (struct sfnt_meta_table *meta, + enum sfnt_meta_data_tag tag, + struct sfnt_meta_data_map *map) +{ + int i; + + for (i = 0; i < meta->num_data_maps; ++i) + { + if (meta->data_maps[i].tag == tag) + { + *map = meta->data_maps[i]; + return (char *) meta->data + map->data_offset; + } + } + + return NULL; +} + + + #ifdef TEST struct sfnt_test_dcontext @@ -4507,6 +4114,13 @@ sfnt_test_span (struct sfnt_edge *edge, sfnt_fixed y, #endif } +static void +sfnt_test_edge_ignore (struct sfnt_edge *edges, size_t num_edges, + void *dcontext) +{ + +} + static void sfnt_test_edge (struct sfnt_edge *edges, size_t num_edges, void *dcontext) @@ -4593,11 +4207,15 @@ main (int argc, char **argv) sfnt_glyph code; struct sfnt_test_dcontext dcontext; struct sfnt_glyph_outline *outline; - struct timespec start, end, sub, sub1; + struct timespec start, end, sub, sub1, sub2; static struct sfnt_maxp_table *maxp; struct sfnt_raster *raster; struct sfnt_hmtx_table *hmtx; struct sfnt_glyph_metrics metrics; + struct sfnt_name_table *name; + unsigned char *string; + struct sfnt_name_record record; + struct sfnt_meta_table *meta; if (argc != 2) return 1; @@ -4644,6 +4262,8 @@ main (int argc, char **argv) hhea = sfnt_read_hhea_table (fd, font); glyf = sfnt_read_glyf_table (fd, font); maxp = sfnt_read_maxp_table (fd, font); + name = sfnt_read_name_table (fd, font); + meta = sfnt_read_meta_table (fd, font); hmtx = NULL; if (hhea && maxp) @@ -4653,6 +4273,23 @@ main (int argc, char **argv) fprintf (stderr, "maxp says num glyphs is %"PRIu16"\n", maxp->num_glyphs); + if (name) + { + fprintf (stderr, "name table of format: %"PRIu16" count: %" + PRIu16"\n", name->format, name->count); + + string = sfnt_find_name (name, SFNT_NAME_FONT_FAMILY, + &record); + + if (string) + fprintf (stderr, "FONT_FAMILY: %"PRIu16", %"PRIu16"\n", + record.platform_id, record.length); + } + + if (meta) + fprintf (stderr, "meta table with count: %"PRIu32"\n", + meta->num_data_maps); + loca_long = NULL; loca_short = NULL; @@ -4787,29 +4424,35 @@ main (int argc, char **argv) { sfnt_test_max = outline->ymax - outline->ymin; - for (i = 0; i < outline->outline_used; i += 3) + for (i = 0; i < outline->outline_used; i++) { printf ("ctx.%s (%g, %g) /* %g, %g */\n", - (outline->outline[i] & SFNT_GLYPH_OUTLINE_LINETO + (outline->outline[i].flags & SFNT_GLYPH_OUTLINE_LINETO ? "lineTo" : "moveTo"), - sfnt_coerce_fixed (outline->outline[i + 1] + sfnt_coerce_fixed (outline->outline[i].x - outline->xmin), sfnt_coerce_fixed (sfnt_test_max - - (outline->outline[i + 2] + - (outline->outline[i].y - outline->ymin)), - sfnt_coerce_fixed (outline->outline[i + 1] + sfnt_coerce_fixed (outline->outline[i].x - outline->xmin), - sfnt_coerce_fixed (outline->outline[i + 2] + sfnt_coerce_fixed (outline->outline[i].y - outline->ymin)); } + clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start); + sfnt_build_outline_edges (outline, sfnt_test_edge_ignore, + NULL); + clock_gettime (CLOCK_THREAD_CPUTIME_ID, &end); + sub1 = timespec_sub (end, start); + sfnt_build_outline_edges (outline, sfnt_test_edge, NULL); clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start); raster = sfnt_raster_glyph_outline (outline); clock_gettime (CLOCK_THREAD_CPUTIME_ID, &end); - sub1 = timespec_sub (end, start); + sub2 = timespec_sub (end, start); /* Print out the raster. */ sfnt_test_raster (raster); @@ -4836,8 +4479,10 @@ main (int argc, char **argv) printf ("time spent outlining: %lld sec %ld nsec\n", (long long) sub.tv_sec, sub.tv_nsec); - printf ("time spent rasterizing: %lld sec %ld nsec\n", + printf ("time spent building edges: %lld sec %ld nsec\n", (long long) sub1.tv_sec, sub1.tv_nsec); + printf ("time spent rasterizing: %lld sec %ld nsec\n", + (long long) sub2.tv_sec, sub2.tv_nsec); xfree (outline); } @@ -4861,6 +4506,8 @@ main (int argc, char **argv) xfree (glyf); xfree (maxp); xfree (hmtx); + xfree (name); + xfree (meta); return 0; } diff --git a/src/xdisp.c b/src/xdisp.c index 3e4e4c7bc3b..96402fac56c 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -15230,6 +15230,15 @@ redisplay_tool_bar (struct frame *f) /* Always do that now. */ clear_glyph_matrix (w->desired_matrix); f->fonts_changed = true; + + /* Kludge (this applies to the X Windows version as well as + Android): when the tool bar size changes, + adjust_window_size (presumably called by + change_tool_bar_height_hook) does not call through to + resize_frame_windows. Pending further investigation, + just call it here as well. */ + resize_frame_windows (f, FRAME_INNER_HEIGHT (f), false); + return true; } } -- 2.39.5