diff options
| author | Po Lu | 2023-01-17 22:10:43 +0800 |
|---|---|---|
| committer | Po Lu | 2023-01-17 22:10:43 +0800 |
| commit | 1b8258a1f2b6a080a4f0e819aa4a86c1ec2da89f (patch) | |
| tree | d6c709e513882f5d430a98508e631cc503469fab /src | |
| parent | 356249d9faf2b454879ff30f06d97beb97fb9a36 (diff) | |
| download | emacs-1b8258a1f2b6a080a4f0e819aa4a86c1ec2da89f.tar.gz emacs-1b8258a1f2b6a080a4f0e819aa4a86c1ec2da89f.zip | |
Update Android port
* doc/emacs/android.texi (Android Fonts): Document that TTC
format fonts are now supported.
* doc/emacs/emacs.texi (Top): Fix menus.
* doc/lispref/commands.texi (Touchscreen Events)
(Key Sequence Input): Document changes to touchscreen events.
* etc/DEBUG: Describe how to debug 64 bit binaries on Android.
* java/org/gnu/emacs/EmacsCopyArea.java (perform): Explicitly
recycle copy bitmap.
* java/org/gnu/emacs/EmacsDialog.java (EmacsDialog): New class.
* java/org/gnu/emacs/EmacsDrawRectangle.java (perform): Use 5
point PolyLine like X, because Android behaves like Postscript
on some devices and X elsewhere.
* java/org/gnu/emacs/EmacsFillRectangle.java (perform):
Explicitly recycle copy bitmap.
* java/org/gnu/emacs/EmacsPixmap.java (destroyHandle):
Explicitly recycle bitmap and GC if it is big.
* java/org/gnu/emacs/EmacsView.java (EmacsView): Make
`bitmapDirty' a boolean.
(handleDirtyBitmap): Reimplement in terms of that boolean.
Explicitly recycle old bitmap and GC.
(onLayout): Fix lock up.
(onDetachedFromWindow): Recycle bitmap and GC.
* java/org/gnu/emacs/EmacsWindow.java (requestViewLayout):
Update call to explicitlyDirtyBitmap.
* src/android.c (android_run_select_thread, android_select):
Really fix android_select.
(android_build_jstring): New function.
* src/android.h: Update prototypes.
* src/androidmenu.c (android_process_events_for_menu): Totally
unblock input before process_pending_signals.
(android_menu_show): Remove redundant unblock_input and
debugging code.
(struct android_emacs_dialog, android_init_emacs_dialog)
(android_dialog_show, android_popup_dialog, init_androidmenu):
Implement popup dialogs on Android.
* src/androidterm.c (android_update_tools)
(handle_one_android_event, android_frame_up_to_date): Allow
tapping tool bar items.
(android_create_terminal): Add dialog hook.
(android_wait_for_event): Adjust call to android_select.
* src/androidterm.h (struct android_touch_point): New field
`tool_bar_p'.
* src/keyboard.c (read_key_sequence, head_table)
(syms_of_keyboard): Prefix touchscreen events with posn.
* src/keyboard.h (EVENT_HEAD): Handle touchscreen events.
* src/process.c (wait_reading_process_output): Adjust call to
android_select.
* src/sfnt.c (sfnt_read_table_directory): If the first long
turns out to be ttcf, return -1.
(sfnt_read_ttc_header): New function.
(main): Test TTC support.
* src/sfnt.h (struct sfnt_ttc_header): New structure.
(enum sfnt_ttc_tag): New enum.
* src/sfntfont-android.c (struct
sfntfont_android_scanline_buffer): New structure.
(GET_SCANLINE_BUFFER): New macro. Try to avoid so much malloc
upon accessing the scanline buffer.
(sfntfont_android_put_glyphs): Do not use SAFE_ALLOCA to
allocate the scaline buffer.
(Fandroid_enumerate_fonts): Enumerate ttc fonts too.
* src/sfntfont.c (struct sfnt_font_desc): New field `offset'.
(sfnt_enum_font_1): Split out enumeration code from
sfnt_enum_font.
(sfnt_enum_font): Read TTC tables and enumerate each font
therein.
(sfntfont_open): Seek to the offset specified.
* xcompile/Makefile.in (maintainer-clean): Fix depends here.
Diffstat (limited to 'src')
| -rw-r--r-- | src/android.c | 62 | ||||
| -rw-r--r-- | src/android.h | 3 | ||||
| -rw-r--r-- | src/androidmenu.c | 240 | ||||
| -rw-r--r-- | src/androidterm.c | 100 | ||||
| -rw-r--r-- | src/androidterm.h | 7 | ||||
| -rw-r--r-- | src/keyboard.c | 7 | ||||
| -rw-r--r-- | src/keyboard.h | 13 | ||||
| -rw-r--r-- | src/process.c | 2 | ||||
| -rw-r--r-- | src/sfnt.c | 167 | ||||
| -rw-r--r-- | src/sfnt.h | 40 | ||||
| -rw-r--r-- | src/sfntfont-android.c | 99 | ||||
| -rw-r--r-- | src/sfntfont.c | 113 |
12 files changed, 771 insertions, 82 deletions
diff --git a/src/android.c b/src/android.c index 9b15ea9f15a..cfb79045c0b 100644 --- a/src/android.c +++ b/src/android.c | |||
| @@ -26,6 +26,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 26 | #include <semaphore.h> | 26 | #include <semaphore.h> |
| 27 | #include <dlfcn.h> | 27 | #include <dlfcn.h> |
| 28 | #include <errno.h> | 28 | #include <errno.h> |
| 29 | #include <math.h> | ||
| 29 | 30 | ||
| 30 | #include <sys/stat.h> | 31 | #include <sys/stat.h> |
| 31 | #include <sys/mman.h> | 32 | #include <sys/mman.h> |
| @@ -225,7 +226,6 @@ static fd_set *volatile android_pselect_readfds; | |||
| 225 | static fd_set *volatile android_pselect_writefds; | 226 | static fd_set *volatile android_pselect_writefds; |
| 226 | static fd_set *volatile android_pselect_exceptfds; | 227 | static fd_set *volatile android_pselect_exceptfds; |
| 227 | static struct timespec *volatile android_pselect_timeout; | 228 | static struct timespec *volatile android_pselect_timeout; |
| 228 | static const sigset_t *volatile android_pselect_sigset; | ||
| 229 | 229 | ||
| 230 | /* Value of pselect. */ | 230 | /* Value of pselect. */ |
| 231 | static int android_pselect_rc; | 231 | static int android_pselect_rc; |
| @@ -242,8 +242,8 @@ static sem_t android_pselect_sem, android_pselect_start_sem; | |||
| 242 | static void * | 242 | static void * |
| 243 | android_run_select_thread (void *data) | 243 | android_run_select_thread (void *data) |
| 244 | { | 244 | { |
| 245 | sigset_t signals, sigset; | 245 | sigset_t signals, waitset; |
| 246 | int rc; | 246 | int rc, sig; |
| 247 | 247 | ||
| 248 | sigfillset (&signals); | 248 | sigfillset (&signals); |
| 249 | 249 | ||
| @@ -253,6 +253,8 @@ android_run_select_thread (void *data) | |||
| 253 | strerror (errno)); | 253 | strerror (errno)); |
| 254 | 254 | ||
| 255 | sigdelset (&signals, SIGUSR1); | 255 | sigdelset (&signals, SIGUSR1); |
| 256 | sigemptyset (&waitset); | ||
| 257 | sigaddset (&waitset, SIGUSR1); | ||
| 256 | 258 | ||
| 257 | while (true) | 259 | while (true) |
| 258 | { | 260 | { |
| @@ -262,35 +264,33 @@ android_run_select_thread (void *data) | |||
| 262 | 264 | ||
| 263 | /* Get the select lock and call pselect. */ | 265 | /* Get the select lock and call pselect. */ |
| 264 | pthread_mutex_lock (&event_queue.select_mutex); | 266 | pthread_mutex_lock (&event_queue.select_mutex); |
| 265 | |||
| 266 | /* Make sure SIGUSR1 can always wake pselect up. */ | ||
| 267 | if (android_pselect_sigset) | ||
| 268 | { | ||
| 269 | sigset = *android_pselect_sigset; | ||
| 270 | sigdelset (&sigset, SIGUSR1); | ||
| 271 | android_pselect_sigset = &sigset; | ||
| 272 | } | ||
| 273 | else | ||
| 274 | android_pselect_sigset = &signals; | ||
| 275 | |||
| 276 | rc = pselect (android_pselect_nfds, | 267 | rc = pselect (android_pselect_nfds, |
| 277 | android_pselect_readfds, | 268 | android_pselect_readfds, |
| 278 | android_pselect_writefds, | 269 | android_pselect_writefds, |
| 279 | android_pselect_exceptfds, | 270 | android_pselect_exceptfds, |
| 280 | android_pselect_timeout, | 271 | android_pselect_timeout, |
| 281 | android_pselect_sigset); | 272 | &signals); |
| 282 | android_pselect_rc = rc; | 273 | android_pselect_rc = rc; |
| 283 | pthread_mutex_unlock (&event_queue.select_mutex); | 274 | pthread_mutex_unlock (&event_queue.select_mutex); |
| 284 | 275 | ||
| 276 | /* Signal the main thread that there is now data to read. | ||
| 277 | It is ok to signal this condition variable without holding | ||
| 278 | the event queue lock, because android_select will always | ||
| 279 | wait for this to complete before returning. */ | ||
| 280 | android_pselect_completed = true; | ||
| 281 | pthread_cond_signal (&event_queue.read_var); | ||
| 282 | |||
| 283 | if (rc != -1 || errno != EINTR) | ||
| 284 | /* Now, wait for SIGUSR1, unless pselect was interrupted and | ||
| 285 | the signal was already delivered. The Emacs thread will | ||
| 286 | always send this signal after read_var is triggered or the | ||
| 287 | UI thread has sent an event. */ | ||
| 288 | sigwait (&waitset, &sig); | ||
| 289 | |||
| 285 | /* Signal the Emacs thread that pselect is done. If read_var | 290 | /* Signal the Emacs thread that pselect is done. If read_var |
| 286 | was signaled by android_write_event, event_queue.mutex could | 291 | was signaled by android_write_event, event_queue.mutex could |
| 287 | still be locked, so this must come before. */ | 292 | still be locked, so this must come before. */ |
| 288 | sem_post (&android_pselect_sem); | 293 | sem_post (&android_pselect_sem); |
| 289 | |||
| 290 | pthread_mutex_lock (&event_queue.mutex); | ||
| 291 | android_pselect_completed = true; | ||
| 292 | pthread_cond_signal (&event_queue.read_var); | ||
| 293 | pthread_mutex_unlock (&event_queue.mutex); | ||
| 294 | } | 294 | } |
| 295 | } | 295 | } |
| 296 | 296 | ||
| @@ -445,8 +445,7 @@ android_write_event (union android_event *event) | |||
| 445 | 445 | ||
| 446 | int | 446 | int |
| 447 | android_select (int nfds, fd_set *readfds, fd_set *writefds, | 447 | android_select (int nfds, fd_set *readfds, fd_set *writefds, |
| 448 | fd_set *exceptfds, struct timespec *timeout, | 448 | fd_set *exceptfds, struct timespec *timeout) |
| 449 | const sigset_t *sigset) | ||
| 450 | { | 449 | { |
| 451 | int nfds_return; | 450 | int nfds_return; |
| 452 | 451 | ||
| @@ -467,7 +466,6 @@ android_select (int nfds, fd_set *readfds, fd_set *writefds, | |||
| 467 | android_pselect_writefds = writefds; | 466 | android_pselect_writefds = writefds; |
| 468 | android_pselect_exceptfds = exceptfds; | 467 | android_pselect_exceptfds = exceptfds; |
| 469 | android_pselect_timeout = timeout; | 468 | android_pselect_timeout = timeout; |
| 470 | android_pselect_sigset = sigset; | ||
| 471 | pthread_mutex_unlock (&event_queue.select_mutex); | 469 | pthread_mutex_unlock (&event_queue.select_mutex); |
| 472 | 470 | ||
| 473 | /* Release the select thread. */ | 471 | /* Release the select thread. */ |
| @@ -3725,6 +3723,24 @@ android_build_string (Lisp_Object text) | |||
| 3725 | return string; | 3723 | return string; |
| 3726 | } | 3724 | } |
| 3727 | 3725 | ||
| 3726 | /* Do the same, except TEXT is constant string data. */ | ||
| 3727 | |||
| 3728 | jstring | ||
| 3729 | android_build_jstring (const char *text) | ||
| 3730 | { | ||
| 3731 | jstring string; | ||
| 3732 | |||
| 3733 | string = (*android_java_env)->NewStringUTF (android_java_env, | ||
| 3734 | text); | ||
| 3735 | if (!string) | ||
| 3736 | { | ||
| 3737 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 3738 | memory_full (0); | ||
| 3739 | } | ||
| 3740 | |||
| 3741 | return string; | ||
| 3742 | } | ||
| 3743 | |||
| 3728 | /* Check for JNI exceptions and call memory_full in that | 3744 | /* Check for JNI exceptions and call memory_full in that |
| 3729 | situation. */ | 3745 | situation. */ |
| 3730 | 3746 | ||
diff --git a/src/android.h b/src/android.h index e68e0a51fbf..036e6d266fd 100644 --- a/src/android.h +++ b/src/android.h | |||
| @@ -48,7 +48,7 @@ extern int ANDROID_EXPORT android_emacs_init (int, char **); | |||
| 48 | #ifndef ANDROID_STUBIFY | 48 | #ifndef ANDROID_STUBIFY |
| 49 | 49 | ||
| 50 | extern int android_select (int, fd_set *, fd_set *, fd_set *, | 50 | extern int android_select (int, fd_set *, fd_set *, fd_set *, |
| 51 | struct timespec *, const sigset_t *); | 51 | struct timespec *); |
| 52 | 52 | ||
| 53 | extern bool android_file_access_p (const char *, int); | 53 | extern bool android_file_access_p (const char *, int); |
| 54 | extern int android_open (const char *, int, int); | 54 | extern int android_open (const char *, int, int); |
| @@ -86,6 +86,7 @@ extern void android_set_dont_focus_on_map (android_window, bool); | |||
| 86 | extern void android_set_dont_accept_focus (android_window, bool); | 86 | extern void android_set_dont_accept_focus (android_window, bool); |
| 87 | 87 | ||
| 88 | extern jstring android_build_string (Lisp_Object); | 88 | extern jstring android_build_string (Lisp_Object); |
| 89 | extern jstring android_build_jstring (const char *); | ||
| 89 | extern void android_exception_check (void); | 90 | extern void android_exception_check (void); |
| 90 | 91 | ||
| 91 | extern void android_get_keysym_name (int, char *, size_t); | 92 | extern void android_get_keysym_name (int, char *, size_t); |
diff --git a/src/androidmenu.c b/src/androidmenu.c index 6fb4963174b..f65b5d3ffd1 100644 --- a/src/androidmenu.c +++ b/src/androidmenu.c | |||
| @@ -168,11 +168,17 @@ android_dismiss_menu (void *pointer) | |||
| 168 | static void | 168 | static void |
| 169 | android_process_events_for_menu (int *id) | 169 | android_process_events_for_menu (int *id) |
| 170 | { | 170 | { |
| 171 | int blocked; | ||
| 172 | |||
| 171 | /* Set menu_event_id to -1; handle_one_android_event will set it to | 173 | /* Set menu_event_id to -1; handle_one_android_event will set it to |
| 172 | the event ID upon receiving a context menu event. This can cause | 174 | the event ID upon receiving a context menu event. This can cause |
| 173 | a non-local exit. */ | 175 | a non-local exit. */ |
| 174 | x_display_list->menu_event_id = -1; | 176 | x_display_list->menu_event_id = -1; |
| 175 | 177 | ||
| 178 | /* Unblock input completely. */ | ||
| 179 | blocked = interrupt_input_blocked; | ||
| 180 | totally_unblock_input (); | ||
| 181 | |||
| 176 | /* Now wait for the menu event ID to change. */ | 182 | /* Now wait for the menu event ID to change. */ |
| 177 | while (x_display_list->menu_event_id == -1) | 183 | while (x_display_list->menu_event_id == -1) |
| 178 | { | 184 | { |
| @@ -181,11 +187,11 @@ android_process_events_for_menu (int *id) | |||
| 181 | 187 | ||
| 182 | /* Process pending signals. */ | 188 | /* Process pending signals. */ |
| 183 | process_pending_signals (); | 189 | process_pending_signals (); |
| 184 | |||
| 185 | /* Maybe quit. */ | ||
| 186 | maybe_quit (); | ||
| 187 | } | 190 | } |
| 188 | 191 | ||
| 192 | /* Restore the input block. */ | ||
| 193 | interrupt_input_blocked = blocked; | ||
| 194 | |||
| 189 | /* Return the ID. */ | 195 | /* Return the ID. */ |
| 190 | *id = x_display_list->menu_event_id; | 196 | *id = x_display_list->menu_event_id; |
| 191 | } | 197 | } |
| @@ -420,9 +426,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 420 | 426 | ||
| 421 | /* Next, process events waiting for something to be selected. */ | 427 | /* Next, process events waiting for something to be selected. */ |
| 422 | popup_activated_flag = 1; | 428 | popup_activated_flag = 1; |
| 423 | unblock_input (); | ||
| 424 | android_process_events_for_menu (&id); | 429 | android_process_events_for_menu (&id); |
| 425 | block_input (); | ||
| 426 | 430 | ||
| 427 | if (!id) | 431 | if (!id) |
| 428 | /* This means no menu item was selected. */ | 432 | /* This means no menu item was selected. */ |
| @@ -498,8 +502,6 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 498 | } | 502 | } |
| 499 | } | 503 | } |
| 500 | 504 | ||
| 501 | Fprint (tem, Qexternal_debugging_output); | ||
| 502 | |||
| 503 | unblock_input (); | 505 | unblock_input (); |
| 504 | return unbind_to (count, tem); | 506 | return unbind_to (count, tem); |
| 505 | 507 | ||
| @@ -508,6 +510,229 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 508 | return unbind_to (count, Qnil); | 510 | return unbind_to (count, Qnil); |
| 509 | } | 511 | } |
| 510 | 512 | ||
| 513 | |||
| 514 | |||
| 515 | /* Toolkit dialog implementation. */ | ||
| 516 | |||
| 517 | /* Structure describing the EmacsDialog class. */ | ||
| 518 | |||
| 519 | struct android_emacs_dialog | ||
| 520 | { | ||
| 521 | jclass class; | ||
| 522 | jmethodID create_dialog; | ||
| 523 | jmethodID add_button; | ||
| 524 | jmethodID display; | ||
| 525 | }; | ||
| 526 | |||
| 527 | /* Identifiers associated with the EmacsDialog class. */ | ||
| 528 | static struct android_emacs_dialog dialog_class; | ||
| 529 | |||
| 530 | static void | ||
| 531 | android_init_emacs_dialog (void) | ||
| 532 | { | ||
| 533 | jclass old; | ||
| 534 | |||
| 535 | dialog_class.class | ||
| 536 | = (*android_java_env)->FindClass (android_java_env, | ||
| 537 | "org/gnu/emacs/EmacsDialog"); | ||
| 538 | eassert (dialog_class.class); | ||
| 539 | |||
| 540 | old = dialog_class.class; | ||
| 541 | dialog_class.class | ||
| 542 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 543 | (jobject) old); | ||
| 544 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 545 | |||
| 546 | if (!dialog_class.class) | ||
| 547 | emacs_abort (); | ||
| 548 | |||
| 549 | #define FIND_METHOD(c_name, name, signature) \ | ||
| 550 | dialog_class.c_name \ | ||
| 551 | = (*android_java_env)->GetMethodID (android_java_env, \ | ||
| 552 | dialog_class.class, \ | ||
| 553 | name, signature); \ | ||
| 554 | eassert (dialog_class.c_name); | ||
| 555 | |||
| 556 | #define FIND_METHOD_STATIC(c_name, name, signature) \ | ||
| 557 | dialog_class.c_name \ | ||
| 558 | = (*android_java_env)->GetStaticMethodID (android_java_env, \ | ||
| 559 | dialog_class.class, \ | ||
| 560 | name, signature); \ | ||
| 561 | |||
| 562 | FIND_METHOD_STATIC (create_dialog, "createDialog", "(Ljava/lang/String;" | ||
| 563 | "Ljava/lang/String;)Lorg/gnu/emacs/EmacsDialog;"); | ||
| 564 | FIND_METHOD (add_button, "addButton", "(Ljava/lang/String;IZ)V"); | ||
| 565 | FIND_METHOD (display, "display", "()Z"); | ||
| 566 | |||
| 567 | #undef FIND_METHOD | ||
| 568 | #undef FIND_METHOD_STATIC | ||
| 569 | } | ||
| 570 | |||
| 571 | static Lisp_Object | ||
| 572 | android_dialog_show (struct frame *f, Lisp_Object title, | ||
| 573 | Lisp_Object header, const char **error_name) | ||
| 574 | { | ||
| 575 | specpdl_ref count; | ||
| 576 | jobject dialog, java_header, java_title, temp; | ||
| 577 | size_t i; | ||
| 578 | Lisp_Object item_name, enable, entry; | ||
| 579 | bool rc; | ||
| 580 | int id; | ||
| 581 | jmethodID method; | ||
| 582 | |||
| 583 | if (menu_items_n_panes > 1) | ||
| 584 | { | ||
| 585 | *error_name = "Multiple panes in dialog box"; | ||
| 586 | return Qnil; | ||
| 587 | } | ||
| 588 | |||
| 589 | /* Do the initial setup. */ | ||
| 590 | count = SPECPDL_INDEX (); | ||
| 591 | *error_name = NULL; | ||
| 592 | |||
| 593 | android_push_local_frame (); | ||
| 594 | |||
| 595 | /* Figure out what header to use. */ | ||
| 596 | java_header = (!NILP (header) | ||
| 597 | ? android_build_jstring ("Information") | ||
| 598 | : android_build_jstring ("Question")); | ||
| 599 | |||
| 600 | /* And the title. */ | ||
| 601 | java_title = android_build_string (title); | ||
| 602 | |||
| 603 | /* Now create the dialog. */ | ||
| 604 | method = dialog_class.create_dialog; | ||
| 605 | dialog = (*android_java_env)->CallStaticObjectMethod (android_java_env, | ||
| 606 | dialog_class.class, | ||
| 607 | method, java_header, | ||
| 608 | java_title); | ||
| 609 | android_exception_check (); | ||
| 610 | |||
| 611 | /* Delete now unused local references. */ | ||
| 612 | if (java_header) | ||
| 613 | ANDROID_DELETE_LOCAL_REF (java_header); | ||
| 614 | ANDROID_DELETE_LOCAL_REF (java_title); | ||
| 615 | |||
| 616 | /* Create the buttons. */ | ||
| 617 | i = MENU_ITEMS_PANE_LENGTH; | ||
| 618 | while (i < menu_items_used) | ||
| 619 | { | ||
| 620 | item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); | ||
| 621 | enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); | ||
| 622 | |||
| 623 | /* Verify that there is no submenu here. */ | ||
| 624 | |||
| 625 | if (NILP (item_name)) | ||
| 626 | { | ||
| 627 | *error_name = "Submenu in dialog items"; | ||
| 628 | return unbind_to (count, Qnil); | ||
| 629 | } | ||
| 630 | |||
| 631 | /* Skip past boundaries between buttons on different sides. The | ||
| 632 | Android toolkit is too silly to understand this | ||
| 633 | distinction. */ | ||
| 634 | |||
| 635 | if (EQ (item_name, Qquote)) | ||
| 636 | ++i; | ||
| 637 | else | ||
| 638 | { | ||
| 639 | /* Make sure i is within bounds. */ | ||
| 640 | if (i > TYPE_MAXIMUM (jint)) | ||
| 641 | { | ||
| 642 | *error_name = "Dialog box too big"; | ||
| 643 | return unbind_to (count, Qnil); | ||
| 644 | } | ||
| 645 | |||
| 646 | /* Add the button. */ | ||
| 647 | temp = android_build_string (item_name); | ||
| 648 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 649 | dialog, | ||
| 650 | dialog_class.add_button, | ||
| 651 | temp, (jint) i, | ||
| 652 | (jboolean) NILP (enable)); | ||
| 653 | android_exception_check (); | ||
| 654 | ANDROID_DELETE_LOCAL_REF (temp); | ||
| 655 | i += MENU_ITEMS_ITEM_LENGTH; | ||
| 656 | } | ||
| 657 | } | ||
| 658 | |||
| 659 | /* The dialog is now built. Run it. */ | ||
| 660 | rc = (*android_java_env)->CallBooleanMethod (android_java_env, | ||
| 661 | dialog, | ||
| 662 | dialog_class.display); | ||
| 663 | android_exception_check (); | ||
| 664 | |||
| 665 | if (!rc) | ||
| 666 | quit (); | ||
| 667 | |||
| 668 | /* Wait for the menu ID to arrive. */ | ||
| 669 | android_process_events_for_menu (&id); | ||
| 670 | |||
| 671 | if (!id) | ||
| 672 | quit (); | ||
| 673 | |||
| 674 | /* Find the selected item, and its pane, to return | ||
| 675 | the proper value. */ | ||
| 676 | i = 0; | ||
| 677 | while (i < menu_items_used) | ||
| 678 | { | ||
| 679 | if (EQ (AREF (menu_items, i), Qt)) | ||
| 680 | i += MENU_ITEMS_PANE_LENGTH; | ||
| 681 | else if (EQ (AREF (menu_items, i), Qquote)) | ||
| 682 | /* This is the boundary between left-side elts and right-side | ||
| 683 | elts. */ | ||
| 684 | ++i; | ||
| 685 | else | ||
| 686 | { | ||
| 687 | entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); | ||
| 688 | |||
| 689 | if (id == i) | ||
| 690 | return entry; | ||
| 691 | |||
| 692 | i += MENU_ITEMS_ITEM_LENGTH; | ||
| 693 | } | ||
| 694 | } | ||
| 695 | |||
| 696 | return Qnil; | ||
| 697 | } | ||
| 698 | |||
| 699 | Lisp_Object | ||
| 700 | android_popup_dialog (struct frame *f, Lisp_Object header, | ||
| 701 | Lisp_Object contents) | ||
| 702 | { | ||
| 703 | Lisp_Object title; | ||
| 704 | const char *error_name; | ||
| 705 | Lisp_Object selection; | ||
| 706 | specpdl_ref specpdl_count = SPECPDL_INDEX (); | ||
| 707 | |||
| 708 | check_window_system (f); | ||
| 709 | |||
| 710 | /* Decode the dialog items from what was specified. */ | ||
| 711 | title = Fcar (contents); | ||
| 712 | CHECK_STRING (title); | ||
| 713 | record_unwind_protect_void (unuse_menu_items); | ||
| 714 | |||
| 715 | if (NILP (Fcar (Fcdr (contents)))) | ||
| 716 | /* No buttons specified, add an "Ok" button so users can pop down | ||
| 717 | the dialog. */ | ||
| 718 | contents = list2 (title, Fcons (build_string ("Ok"), Qt)); | ||
| 719 | |||
| 720 | list_of_panes (list1 (contents)); | ||
| 721 | |||
| 722 | /* Display them in a dialog box. */ | ||
| 723 | block_input (); | ||
| 724 | selection = android_dialog_show (f, title, header, &error_name); | ||
| 725 | unblock_input (); | ||
| 726 | |||
| 727 | unbind_to (specpdl_count, Qnil); | ||
| 728 | discard_menu_items (); | ||
| 729 | |||
| 730 | if (error_name) | ||
| 731 | error ("%s", error_name); | ||
| 732 | |||
| 733 | return selection; | ||
| 734 | } | ||
| 735 | |||
| 511 | #else | 736 | #else |
| 512 | 737 | ||
| 513 | int | 738 | int |
| @@ -531,6 +756,7 @@ init_androidmenu (void) | |||
| 531 | { | 756 | { |
| 532 | #ifndef ANDROID_STUBIFY | 757 | #ifndef ANDROID_STUBIFY |
| 533 | android_init_emacs_context_menu (); | 758 | android_init_emacs_context_menu (); |
| 759 | android_init_emacs_dialog (); | ||
| 534 | #endif | 760 | #endif |
| 535 | } | 761 | } |
| 536 | 762 | ||
diff --git a/src/androidterm.c b/src/androidterm.c index cc2da279bb3..f19cee5b11b 100644 --- a/src/androidterm.c +++ b/src/androidterm.c | |||
| @@ -496,10 +496,17 @@ android_update_tools (struct frame *f, struct input_event *ie) | |||
| 496 | /* Build the list of active touches. */ | 496 | /* Build the list of active touches. */ |
| 497 | for (touchpoint = FRAME_OUTPUT_DATA (f)->touch_points; | 497 | for (touchpoint = FRAME_OUTPUT_DATA (f)->touch_points; |
| 498 | touchpoint; touchpoint = touchpoint->next) | 498 | touchpoint; touchpoint = touchpoint->next) |
| 499 | ie->arg = Fcons (list3i (touchpoint->x, | 499 | { |
| 500 | touchpoint->y, | 500 | /* Skip touch points which originated on the tool bar. */ |
| 501 | touchpoint->tool_id), | 501 | |
| 502 | ie->arg); | 502 | if (touchpoint->tool_bar_p) |
| 503 | continue; | ||
| 504 | |||
| 505 | ie->arg = Fcons (list3i (touchpoint->x, | ||
| 506 | touchpoint->y, | ||
| 507 | touchpoint->tool_id), | ||
| 508 | ie->arg); | ||
| 509 | } | ||
| 503 | } | 510 | } |
| 504 | 511 | ||
| 505 | /* Find and return an existing tool pressed against FRAME, identified | 512 | /* Find and return an existing tool pressed against FRAME, identified |
| @@ -951,6 +958,59 @@ handle_one_android_event (struct android_display_info *dpyinfo, | |||
| 951 | touchpoint->next = FRAME_OUTPUT_DATA (any)->touch_points; | 958 | touchpoint->next = FRAME_OUTPUT_DATA (any)->touch_points; |
| 952 | FRAME_OUTPUT_DATA (any)->touch_points = touchpoint; | 959 | FRAME_OUTPUT_DATA (any)->touch_points = touchpoint; |
| 953 | 960 | ||
| 961 | /* Figure out whether or not the tool was pressed on the tool | ||
| 962 | bar. Note that the code which runs when it was is more or | ||
| 963 | less an abuse of the mouse highlight machinery, but it works | ||
| 964 | well enough in practice. */ | ||
| 965 | |||
| 966 | if (WINDOWP (any->tool_bar_window) | ||
| 967 | && WINDOW_TOTAL_LINES (XWINDOW (any->tool_bar_window))) | ||
| 968 | { | ||
| 969 | Lisp_Object window; | ||
| 970 | int x = event->touch.x; | ||
| 971 | int y = event->touch.y; | ||
| 972 | |||
| 973 | window = window_from_coordinates (any, x, y, 0, true, | ||
| 974 | true); | ||
| 975 | |||
| 976 | /* If this touch has started in the tool bar, do not | ||
| 977 | send it to Lisp. Instead, simulate a tool bar | ||
| 978 | click, releasing it once it goes away. */ | ||
| 979 | |||
| 980 | if (EQ (window, any->tool_bar_window)) | ||
| 981 | { | ||
| 982 | /* Call note_mouse_highlight on the tool bar | ||
| 983 | item. Otherwise, get_tool_bar_item will | ||
| 984 | return 1. | ||
| 985 | |||
| 986 | This is not necessary when mouse-highlight is | ||
| 987 | nil. */ | ||
| 988 | |||
| 989 | if (!NILP (Vmouse_highlight)) | ||
| 990 | { | ||
| 991 | note_mouse_highlight (any, x, y); | ||
| 992 | |||
| 993 | /* Always allow future mouse motion to | ||
| 994 | update the mouse highlight, no matter | ||
| 995 | where it is. */ | ||
| 996 | memset (&dpyinfo->last_mouse_glyph, 0, | ||
| 997 | sizeof dpyinfo->last_mouse_glyph); | ||
| 998 | dpyinfo->last_mouse_glyph_frame = any; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | handle_tool_bar_click (any, x, y, true, 0); | ||
| 1002 | |||
| 1003 | /* Flush any changes made by that to the front | ||
| 1004 | buffer. */ | ||
| 1005 | android_flush_dirty_back_buffer_on (any); | ||
| 1006 | |||
| 1007 | /* Mark the touch point as being grabbed by the tool | ||
| 1008 | bar. */ | ||
| 1009 | touchpoint->tool_bar_p = true; | ||
| 1010 | goto OTHER; | ||
| 1011 | } | ||
| 1012 | } | ||
| 1013 | |||
| 954 | /* Now generate the Emacs event. */ | 1014 | /* Now generate the Emacs event. */ |
| 955 | inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT; | 1015 | inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT; |
| 956 | inev.ie.timestamp = event->touch.time; | 1016 | inev.ie.timestamp = event->touch.time; |
| @@ -970,9 +1030,10 @@ handle_one_android_event (struct android_display_info *dpyinfo, | |||
| 970 | 1030 | ||
| 971 | touchpoint = android_find_tool (any, event->touch.pointer_id); | 1031 | touchpoint = android_find_tool (any, event->touch.pointer_id); |
| 972 | 1032 | ||
| 973 | /* If it doesn't exist, skip processing this event. */ | 1033 | /* If it doesn't exist or has been grabbed by the tool bar, skip |
| 1034 | processing this event. */ | ||
| 974 | 1035 | ||
| 975 | if (!touchpoint) | 1036 | if (!touchpoint || touchpoint->tool_bar_p) |
| 976 | goto OTHER; | 1037 | goto OTHER; |
| 977 | 1038 | ||
| 978 | /* Otherwise, update the position and send the update event. */ | 1039 | /* Otherwise, update the position and send the update event. */ |
| @@ -999,8 +1060,27 @@ handle_one_android_event (struct android_display_info *dpyinfo, | |||
| 999 | *last = touchpoint->next; | 1060 | *last = touchpoint->next; |
| 1000 | 1061 | ||
| 1001 | /* The tool was unlinked. Free it and generate the | 1062 | /* The tool was unlinked. Free it and generate the |
| 1002 | appropriate Emacs event. */ | 1063 | appropriate Emacs event (assuming that it was not |
| 1064 | grabbed by the tool bar). */ | ||
| 1003 | xfree (touchpoint); | 1065 | xfree (touchpoint); |
| 1066 | |||
| 1067 | if (touchpoint->tool_bar_p) | ||
| 1068 | { | ||
| 1069 | /* Do what is necessary to release the tool bar and | ||
| 1070 | possibly trigger a click. */ | ||
| 1071 | |||
| 1072 | if (any->last_tool_bar_item != -1) | ||
| 1073 | handle_tool_bar_click (any, event->touch.x, | ||
| 1074 | event->touch.y, false, | ||
| 1075 | 0); | ||
| 1076 | |||
| 1077 | /* Cancel any outstanding mouse highlight. */ | ||
| 1078 | note_mouse_highlight (any, -1, -1); | ||
| 1079 | android_flush_dirty_back_buffer_on (any); | ||
| 1080 | |||
| 1081 | goto OTHER; | ||
| 1082 | } | ||
| 1083 | |||
| 1004 | inev.ie.kind = TOUCHSCREEN_END_EVENT; | 1084 | inev.ie.kind = TOUCHSCREEN_END_EVENT; |
| 1005 | inev.ie.timestamp = event->touch.time; | 1085 | inev.ie.timestamp = event->touch.time; |
| 1006 | 1086 | ||
| @@ -1227,6 +1307,9 @@ android_frame_up_to_date (struct frame *f) | |||
| 1227 | 1307 | ||
| 1228 | /* The frame is now complete, as its contents have been drawn. */ | 1308 | /* The frame is now complete, as its contents have been drawn. */ |
| 1229 | FRAME_ANDROID_COMPLETE_P (f) = true; | 1309 | FRAME_ANDROID_COMPLETE_P (f) = true; |
| 1310 | |||
| 1311 | /* Shrink the scanline buffer used by the font backend. */ | ||
| 1312 | sfntfont_android_shrink_scanline_buffer (); | ||
| 1230 | unblock_input (); | 1313 | unblock_input (); |
| 1231 | } | 1314 | } |
| 1232 | 1315 | ||
| @@ -1513,7 +1596,7 @@ android_wait_for_event (struct frame *f, int eventtype) | |||
| 1513 | break; | 1596 | break; |
| 1514 | 1597 | ||
| 1515 | tmo = timespec_sub (tmo_at, time_now); | 1598 | tmo = timespec_sub (tmo_at, time_now); |
| 1516 | if (android_select (0, NULL, NULL, NULL, &tmo, NULL) == 0) | 1599 | if (android_select (0, NULL, NULL, NULL, &tmo) == 0) |
| 1517 | break; /* Timeout */ | 1600 | break; /* Timeout */ |
| 1518 | } | 1601 | } |
| 1519 | 1602 | ||
| @@ -4061,6 +4144,7 @@ android_create_terminal (struct android_display_info *dpyinfo) | |||
| 4061 | terminal->set_bitmap_icon_hook = android_bitmap_icon; | 4144 | terminal->set_bitmap_icon_hook = android_bitmap_icon; |
| 4062 | terminal->implicit_set_name_hook = android_implicitly_set_name; | 4145 | terminal->implicit_set_name_hook = android_implicitly_set_name; |
| 4063 | terminal->menu_show_hook = android_menu_show; | 4146 | terminal->menu_show_hook = android_menu_show; |
| 4147 | terminal->popup_dialog_hook = android_popup_dialog; | ||
| 4064 | terminal->change_tab_bar_height_hook = android_change_tab_bar_height; | 4148 | terminal->change_tab_bar_height_hook = android_change_tab_bar_height; |
| 4065 | terminal->change_tool_bar_height_hook = android_change_tool_bar_height; | 4149 | terminal->change_tool_bar_height_hook = android_change_tool_bar_height; |
| 4066 | terminal->set_scroll_bar_default_width_hook | 4150 | terminal->set_scroll_bar_default_width_hook |
diff --git a/src/androidterm.h b/src/androidterm.h index 9aa09877196..c0f862e35fb 100644 --- a/src/androidterm.h +++ b/src/androidterm.h | |||
| @@ -148,6 +148,9 @@ struct android_touch_point | |||
| 148 | 148 | ||
| 149 | /* The tool ID and the last known X and Y positions. */ | 149 | /* The tool ID and the last known X and Y positions. */ |
| 150 | int tool_id, x, y; | 150 | int tool_id, x, y; |
| 151 | |||
| 152 | /* Whether or not the tool is pressed on the tool bar. */ | ||
| 153 | bool tool_bar_p; | ||
| 151 | }; | 154 | }; |
| 152 | 155 | ||
| 153 | struct android_output | 156 | struct android_output |
| @@ -410,6 +413,9 @@ extern void android_finalize_font_entity (struct font_entity *); | |||
| 410 | 413 | ||
| 411 | extern Lisp_Object android_menu_show (struct frame *, int, int, int, | 414 | extern Lisp_Object android_menu_show (struct frame *, int, int, int, |
| 412 | Lisp_Object, const char **); | 415 | Lisp_Object, const char **); |
| 416 | extern Lisp_Object android_popup_dialog (struct frame *, Lisp_Object, | ||
| 417 | Lisp_Object); | ||
| 418 | |||
| 413 | extern void init_androidmenu (void); | 419 | extern void init_androidmenu (void); |
| 414 | extern void syms_of_androidmenu (void); | 420 | extern void syms_of_androidmenu (void); |
| 415 | 421 | ||
| @@ -417,6 +423,7 @@ extern void syms_of_androidmenu (void); | |||
| 417 | 423 | ||
| 418 | extern const struct font_driver android_sfntfont_driver; | 424 | extern const struct font_driver android_sfntfont_driver; |
| 419 | 425 | ||
| 426 | extern void sfntfont_android_shrink_scanline_buffer (void); | ||
| 420 | extern void init_sfntfont_android (void); | 427 | extern void init_sfntfont_android (void); |
| 421 | extern void syms_of_sfntfont_android (void); | 428 | extern void syms_of_sfntfont_android (void); |
| 422 | 429 | ||
diff --git a/src/keyboard.c b/src/keyboard.c index 990b5307f14..834049b496a 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -10380,7 +10380,7 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt, | |||
| 10380 | if (EVENT_HAS_PARAMETERS (key)) | 10380 | if (EVENT_HAS_PARAMETERS (key)) |
| 10381 | { | 10381 | { |
| 10382 | Lisp_Object kind = EVENT_HEAD_KIND (EVENT_HEAD (key)); | 10382 | Lisp_Object kind = EVENT_HEAD_KIND (EVENT_HEAD (key)); |
| 10383 | if (EQ (kind, Qmouse_click)) | 10383 | if (EQ (kind, Qmouse_click) || EQ (kind, Qtouchscreen)) |
| 10384 | { | 10384 | { |
| 10385 | Lisp_Object window = POSN_WINDOW (EVENT_START (key)); | 10385 | Lisp_Object window = POSN_WINDOW (EVENT_START (key)); |
| 10386 | Lisp_Object posn = POSN_POSN (EVENT_START (key)); | 10386 | Lisp_Object posn = POSN_POSN (EVENT_START (key)); |
| @@ -12185,7 +12185,9 @@ static const struct event_head head_table[] = { | |||
| 12185 | {SYMBOL_INDEX (Qmake_frame_visible), SYMBOL_INDEX (Qmake_frame_visible)}, | 12185 | {SYMBOL_INDEX (Qmake_frame_visible), SYMBOL_INDEX (Qmake_frame_visible)}, |
| 12186 | /* `select-window' should be handled just like `switch-frame' | 12186 | /* `select-window' should be handled just like `switch-frame' |
| 12187 | in read_key_sequence. */ | 12187 | in read_key_sequence. */ |
| 12188 | {SYMBOL_INDEX (Qselect_window), SYMBOL_INDEX (Qswitch_frame)} | 12188 | {SYMBOL_INDEX (Qselect_window), SYMBOL_INDEX (Qswitch_frame)}, |
| 12189 | /* Touchscreen events should be prefixed by the posn. */ | ||
| 12190 | {SYMBOL_INDEX (Qtouchscreen_begin), SYMBOL_INDEX (Qtouchscreen)}, | ||
| 12189 | }; | 12191 | }; |
| 12190 | 12192 | ||
| 12191 | static Lisp_Object | 12193 | static Lisp_Object |
| @@ -12895,6 +12897,7 @@ See also `pre-command-hook'. */); | |||
| 12895 | "display-monitors-changed-functions"); | 12897 | "display-monitors-changed-functions"); |
| 12896 | 12898 | ||
| 12897 | DEFSYM (Qcoding, "coding"); | 12899 | DEFSYM (Qcoding, "coding"); |
| 12900 | DEFSYM (Qtouchscreen, "touchscreen"); | ||
| 12898 | 12901 | ||
| 12899 | Fset (Qecho_area_clear_hook, Qnil); | 12902 | Fset (Qecho_area_clear_hook, Qnil); |
| 12900 | 12903 | ||
diff --git a/src/keyboard.h b/src/keyboard.h index 3f86a8e03ad..26eecd48b00 100644 --- a/src/keyboard.h +++ b/src/keyboard.h | |||
| @@ -395,8 +395,17 @@ extern void unuse_menu_items (void); | |||
| 395 | #define EVENT_HEAD(event) \ | 395 | #define EVENT_HEAD(event) \ |
| 396 | (EVENT_HAS_PARAMETERS (event) ? XCAR (event) : (event)) | 396 | (EVENT_HAS_PARAMETERS (event) ? XCAR (event) : (event)) |
| 397 | 397 | ||
| 398 | /* Extract the starting and ending positions from a composite event. */ | 398 | /* Extract the starting and ending positions from a composite event. */ |
| 399 | #define EVENT_START(event) (CAR_SAFE (CDR_SAFE (event))) | 399 | |
| 400 | /* Unlike Lisp `event-start', this also handles touch screen events, | ||
| 401 | which are not actually mouse events in the general sense. */ | ||
| 402 | #define EVENT_START(event) \ | ||
| 403 | ((EQ (EVENT_HEAD (event), Qtouchscreen_begin) \ | ||
| 404 | || EQ (EVENT_HEAD (event), Qtouchscreen_end)) \ | ||
| 405 | ? CDR_SAFE (CAR_SAFE (CDR_SAFE (event))) \ | ||
| 406 | : CAR_SAFE (CDR_SAFE (event))) | ||
| 407 | |||
| 408 | /* This does not handle touchscreen events. */ | ||
| 400 | #define EVENT_END(event) (CAR_SAFE (CDR_SAFE (CDR_SAFE (event)))) | 409 | #define EVENT_END(event) (CAR_SAFE (CDR_SAFE (CDR_SAFE (event)))) |
| 401 | 410 | ||
| 402 | /* Extract the click count from a multi-click event. */ | 411 | /* Extract the click count from a multi-click event. */ |
diff --git a/src/process.c b/src/process.c index 111e0c80e43..651b5fa035b 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -5689,7 +5689,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 5689 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | 5689 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY |
| 5690 | nfds = android_select (max_desc + 1, | 5690 | nfds = android_select (max_desc + 1, |
| 5691 | &Available, (check_write ? &Writeok : 0), | 5691 | &Available, (check_write ? &Writeok : 0), |
| 5692 | NULL, &timeout, NULL); | 5692 | NULL, &timeout); |
| 5693 | #else | 5693 | #else |
| 5694 | 5694 | ||
| 5695 | /* Non-macOS HAVE_GLIB builds call thread_select in | 5695 | /* Non-macOS HAVE_GLIB builds call thread_select in |
diff --git a/src/sfnt.c b/src/sfnt.c index ee74ba0fefe..6d58798c599 100644 --- a/src/sfnt.c +++ b/src/sfnt.c | |||
| @@ -129,8 +129,12 @@ _sfnt_swap32 (uint32_t *value) | |||
| 129 | #define sfnt_swap32(what) (_sfnt_swap32 ((uint32_t *) (what))) | 129 | #define sfnt_swap32(what) (_sfnt_swap32 ((uint32_t *) (what))) |
| 130 | 130 | ||
| 131 | /* Read the table directory from the file FD. FD must currently be at | 131 | /* Read the table directory from the file FD. FD must currently be at |
| 132 | the start of the file, and must be seekable. Return the table | 132 | the start of the file (or an offset defined in the TTC header, if |
| 133 | directory upon success, else NULL. */ | 133 | applicable), and must be seekable. Return the table directory upon |
| 134 | success, else NULL. | ||
| 135 | |||
| 136 | Value is NULL upon failure, and the offset subtable upon success. | ||
| 137 | If FD is actually a TrueType collection file, value is -1. */ | ||
| 134 | 138 | ||
| 135 | TEST_STATIC struct sfnt_offset_subtable * | 139 | TEST_STATIC struct sfnt_offset_subtable * |
| 136 | sfnt_read_table_directory (int fd) | 140 | sfnt_read_table_directory (int fd) |
| @@ -147,11 +151,34 @@ sfnt_read_table_directory (int fd) | |||
| 147 | 151 | ||
| 148 | if (rc < offset) | 152 | if (rc < offset) |
| 149 | { | 153 | { |
| 154 | if (rc >= sizeof (uint32_t)) | ||
| 155 | { | ||
| 156 | /* Detect a TTC file. In that case, the first long will be | ||
| 157 | ``ttcf''. */ | ||
| 158 | sfnt_swap32 (&subtable->scaler_type); | ||
| 159 | |||
| 160 | if (subtable->scaler_type == SFNT_TTC_TTCF) | ||
| 161 | { | ||
| 162 | xfree (subtable); | ||
| 163 | return (struct sfnt_offset_subtable *) -1; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 150 | xfree (subtable); | 167 | xfree (subtable); |
| 151 | return NULL; | 168 | return NULL; |
| 152 | } | 169 | } |
| 153 | 170 | ||
| 154 | sfnt_swap32 (&subtable->scaler_type); | 171 | sfnt_swap32 (&subtable->scaler_type); |
| 172 | |||
| 173 | /* Bail out early if this font is actually a TrueType collection | ||
| 174 | file. */ | ||
| 175 | |||
| 176 | if (subtable->scaler_type == SFNT_TTC_TTCF) | ||
| 177 | { | ||
| 178 | xfree (subtable); | ||
| 179 | return (struct sfnt_offset_subtable *) -1; | ||
| 180 | } | ||
| 181 | |||
| 155 | sfnt_swap16 (&subtable->num_tables); | 182 | sfnt_swap16 (&subtable->num_tables); |
| 156 | sfnt_swap16 (&subtable->search_range); | 183 | sfnt_swap16 (&subtable->search_range); |
| 157 | sfnt_swap16 (&subtable->entry_selector); | 184 | sfnt_swap16 (&subtable->entry_selector); |
| @@ -4183,6 +4210,101 @@ sfnt_find_metadata (struct sfnt_meta_table *meta, | |||
| 4183 | 4210 | ||
| 4184 | 4211 | ||
| 4185 | 4212 | ||
| 4213 | /* TrueType collection format support. */ | ||
| 4214 | |||
| 4215 | /* Read a TrueType collection header from the font file FD. | ||
| 4216 | FD must currently at the start of the file. | ||
| 4217 | |||
| 4218 | Value is the header upon success, else NULL. */ | ||
| 4219 | |||
| 4220 | TEST_STATIC struct sfnt_ttc_header * | ||
| 4221 | sfnt_read_ttc_header (int fd) | ||
| 4222 | { | ||
| 4223 | struct sfnt_ttc_header *ttc; | ||
| 4224 | size_t size, i; | ||
| 4225 | ssize_t rc; | ||
| 4226 | |||
| 4227 | /* First, allocate only as much as required. */ | ||
| 4228 | |||
| 4229 | ttc = xmalloc (sizeof *ttc); | ||
| 4230 | |||
| 4231 | /* Read the version 1.0 data. */ | ||
| 4232 | |||
| 4233 | size = SFNT_ENDOF (struct sfnt_ttc_header, num_fonts, | ||
| 4234 | uint32_t); | ||
| 4235 | rc = read (fd, ttc, size); | ||
| 4236 | if (rc < size) | ||
| 4237 | { | ||
| 4238 | xfree (ttc); | ||
| 4239 | return NULL; | ||
| 4240 | } | ||
| 4241 | |||
| 4242 | /* Now swap what was read. */ | ||
| 4243 | sfnt_swap32 (&ttc->ttctag); | ||
| 4244 | sfnt_swap32 (&ttc->version); | ||
| 4245 | sfnt_swap32 (&ttc->num_fonts); | ||
| 4246 | |||
| 4247 | /* Verify that the tag is as expected. */ | ||
| 4248 | if (ttc->ttctag != SFNT_TTC_TTCF) | ||
| 4249 | { | ||
| 4250 | xfree (ttc); | ||
| 4251 | return NULL; | ||
| 4252 | } | ||
| 4253 | |||
| 4254 | /* Now, read the variable length data. Make sure to check for | ||
| 4255 | overflow. */ | ||
| 4256 | |||
| 4257 | if (INT_MULTIPLY_WRAPV (ttc->num_fonts, | ||
| 4258 | sizeof *ttc->offset_table, | ||
| 4259 | &size)) | ||
| 4260 | { | ||
| 4261 | xfree (ttc); | ||
| 4262 | return NULL; | ||
| 4263 | } | ||
| 4264 | |||
| 4265 | ttc = xrealloc (ttc, sizeof *ttc + size); | ||
| 4266 | ttc->offset_table = (uint32_t *) (ttc + 1); | ||
| 4267 | rc = read (fd, ttc->offset_table, size); | ||
| 4268 | if (rc < size) | ||
| 4269 | { | ||
| 4270 | xfree (ttc); | ||
| 4271 | return NULL; | ||
| 4272 | } | ||
| 4273 | |||
| 4274 | /* Swap each of the offsets read. */ | ||
| 4275 | for (i = 0; i < ttc->num_fonts; ++i) | ||
| 4276 | sfnt_swap32 (&ttc->offset_table[i]); | ||
| 4277 | |||
| 4278 | /* Now, look at the version. If it is earlier than 2.0, then | ||
| 4279 | reading is finished. */ | ||
| 4280 | |||
| 4281 | if (ttc->version < 0x00020000) | ||
| 4282 | return ttc; | ||
| 4283 | |||
| 4284 | /* If it is 2.0 or later, then continue to read ul_dsig_tag to | ||
| 4285 | ul_dsig_offset. */ | ||
| 4286 | |||
| 4287 | size = (SFNT_ENDOF (struct sfnt_ttc_header, ul_dsig_offset, | ||
| 4288 | uint32_t) | ||
| 4289 | - offsetof (struct sfnt_ttc_header, ul_dsig_tag)); | ||
| 4290 | rc = read (fd, &ttc->ul_dsig_offset, size); | ||
| 4291 | if (rc < size) | ||
| 4292 | { | ||
| 4293 | xfree (ttc); | ||
| 4294 | return NULL; | ||
| 4295 | } | ||
| 4296 | |||
| 4297 | /* Swap what was read. */ | ||
| 4298 | sfnt_swap32 (&ttc->ul_dsig_tag); | ||
| 4299 | sfnt_swap32 (&ttc->ul_dsig_length); | ||
| 4300 | sfnt_swap32 (&ttc->ul_dsig_offset); | ||
| 4301 | |||
| 4302 | /* All done. */ | ||
| 4303 | return ttc; | ||
| 4304 | } | ||
| 4305 | |||
| 4306 | |||
| 4307 | |||
| 4186 | #ifdef TEST | 4308 | #ifdef TEST |
| 4187 | 4309 | ||
| 4188 | struct sfnt_test_dcontext | 4310 | struct sfnt_test_dcontext |
| @@ -4397,6 +4519,7 @@ main (int argc, char **argv) | |||
| 4397 | unsigned char *string; | 4519 | unsigned char *string; |
| 4398 | struct sfnt_name_record record; | 4520 | struct sfnt_name_record record; |
| 4399 | struct sfnt_meta_table *meta; | 4521 | struct sfnt_meta_table *meta; |
| 4522 | struct sfnt_ttc_header *ttc; | ||
| 4400 | 4523 | ||
| 4401 | if (argc != 2) | 4524 | if (argc != 2) |
| 4402 | return 1; | 4525 | return 1; |
| @@ -4406,8 +4529,41 @@ main (int argc, char **argv) | |||
| 4406 | if (fd < 1) | 4529 | if (fd < 1) |
| 4407 | return 1; | 4530 | return 1; |
| 4408 | 4531 | ||
| 4532 | ttc = NULL; | ||
| 4533 | |||
| 4409 | font = sfnt_read_table_directory (fd); | 4534 | font = sfnt_read_table_directory (fd); |
| 4410 | 4535 | ||
| 4536 | if (font == (struct sfnt_offset_subtable *) -1) | ||
| 4537 | { | ||
| 4538 | if (lseek (fd, 0, SEEK_SET) != 0) | ||
| 4539 | return 1; | ||
| 4540 | |||
| 4541 | ttc = sfnt_read_ttc_header (fd); | ||
| 4542 | |||
| 4543 | if (!ttc) | ||
| 4544 | return 1; | ||
| 4545 | |||
| 4546 | fprintf (stderr, "TrueType collection: %"PRIu32" fonts installed\n", | ||
| 4547 | ttc->num_fonts); | ||
| 4548 | fflush (stderr); | ||
| 4549 | |||
| 4550 | printf ("Which font? "); | ||
| 4551 | if (scanf ("%d", &i) == EOF) | ||
| 4552 | return 1; | ||
| 4553 | |||
| 4554 | if (i >= ttc->num_fonts || i < 0) | ||
| 4555 | { | ||
| 4556 | printf ("out of range\n"); | ||
| 4557 | return 1; | ||
| 4558 | } | ||
| 4559 | |||
| 4560 | if (lseek (fd, ttc->offset_table[i], SEEK_SET) | ||
| 4561 | != ttc->offset_table[i]) | ||
| 4562 | return 1; | ||
| 4563 | |||
| 4564 | font = sfnt_read_table_directory (fd); | ||
| 4565 | } | ||
| 4566 | |||
| 4411 | if (!font) | 4567 | if (!font) |
| 4412 | { | 4568 | { |
| 4413 | close (fd); | 4569 | close (fd); |
| @@ -4432,9 +4588,9 @@ main (int argc, char **argv) | |||
| 4432 | for (i = 0; i < table->num_subtables; ++i) | 4588 | for (i = 0; i < table->num_subtables; ++i) |
| 4433 | { | 4589 | { |
| 4434 | fprintf (stderr, "Found cmap table %"PRIu32": %p\n", | 4590 | fprintf (stderr, "Found cmap table %"PRIu32": %p\n", |
| 4435 | subtables[i].offset, data); | 4591 | subtables[i].offset, data[i]); |
| 4436 | 4592 | ||
| 4437 | if (data) | 4593 | if (data[i]) |
| 4438 | fprintf (stderr, " format: %"PRIu16"\n", | 4594 | fprintf (stderr, " format: %"PRIu16"\n", |
| 4439 | data[i]->format); | 4595 | data[i]->format); |
| 4440 | } | 4596 | } |
| @@ -4552,7 +4708,7 @@ main (int argc, char **argv) | |||
| 4552 | if (scanf ("%d %"SCNu32"", &i, &character) == EOF) | 4708 | if (scanf ("%d %"SCNu32"", &i, &character) == EOF) |
| 4553 | break; | 4709 | break; |
| 4554 | 4710 | ||
| 4555 | if (i >= table->num_subtables) | 4711 | if (i < 0 || i >= table->num_subtables) |
| 4556 | { | 4712 | { |
| 4557 | printf ("table out of range\n"); | 4713 | printf ("table out of range\n"); |
| 4558 | continue; | 4714 | continue; |
| @@ -4699,6 +4855,7 @@ main (int argc, char **argv) | |||
| 4699 | xfree (hmtx); | 4855 | xfree (hmtx); |
| 4700 | xfree (name); | 4856 | xfree (name); |
| 4701 | xfree (meta); | 4857 | xfree (meta); |
| 4858 | xfree (ttc); | ||
| 4702 | 4859 | ||
| 4703 | return 0; | 4860 | return 0; |
| 4704 | } | 4861 | } |
diff --git a/src/sfnt.h b/src/sfnt.h index 91d7b261cb0..fe6b6ec3dd7 100644 --- a/src/sfnt.h +++ b/src/sfnt.h | |||
| @@ -875,6 +875,44 @@ enum sfnt_meta_data_tag | |||
| 875 | 875 | ||
| 876 | 876 | ||
| 877 | 877 | ||
| 878 | /* TrueType collection format support. */ | ||
| 879 | |||
| 880 | struct sfnt_ttc_header | ||
| 881 | { | ||
| 882 | /* TrueType collection ID tag. */ | ||
| 883 | uint32_t ttctag; | ||
| 884 | |||
| 885 | /* Version of the TTC header. */ | ||
| 886 | uint32_t version; | ||
| 887 | |||
| 888 | /* Number of fonts in the TTC header. */ | ||
| 889 | uint32_t num_fonts; | ||
| 890 | |||
| 891 | /* Array of offsets to the offset table for each font in the | ||
| 892 | file. */ | ||
| 893 | uint32_t *offset_table; | ||
| 894 | |||
| 895 | /* Tag indicating that a DSIG table exists, or 0. Fields from here | ||
| 896 | on are only set on version 2.0 headers or later. */ | ||
| 897 | uint32_t ul_dsig_tag; | ||
| 898 | |||
| 899 | /* Length in bytes of the signature table, or 0 if there is no | ||
| 900 | signature. */ | ||
| 901 | uint32_t ul_dsig_length; | ||
| 902 | |||
| 903 | /* Offset in bytes of the dsig table from the beginning of the TTC | ||
| 904 | file. */ | ||
| 905 | uint32_t ul_dsig_offset; | ||
| 906 | }; | ||
| 907 | |||
| 908 | enum sfnt_ttc_tag | ||
| 909 | { | ||
| 910 | SFNT_TTC_TTCF = 0x74746366, | ||
| 911 | SFNT_TTC_DSIG = 0x44534947, | ||
| 912 | }; | ||
| 913 | |||
| 914 | |||
| 915 | |||
| 878 | #define SFNT_CEIL_FIXED(fixed) \ | 916 | #define SFNT_CEIL_FIXED(fixed) \ |
| 879 | (!((fixed) & 0177777) ? (fixed) \ | 917 | (!((fixed) & 0177777) ? (fixed) \ |
| 880 | : ((fixed) + 0200000) & 037777600000) | 918 | : ((fixed) + 0200000) & 037777600000) |
| @@ -960,5 +998,7 @@ extern char *sfnt_find_metadata (struct sfnt_meta_table *, | |||
| 960 | enum sfnt_meta_data_tag, | 998 | enum sfnt_meta_data_tag, |
| 961 | struct sfnt_meta_data_map *); | 999 | struct sfnt_meta_data_map *); |
| 962 | 1000 | ||
| 1001 | extern struct sfnt_ttc_header *sfnt_read_ttc_header (int); | ||
| 1002 | |||
| 963 | #endif /* TEST */ | 1003 | #endif /* TEST */ |
| 964 | #endif /* _SFNT_H_ */ | 1004 | #endif /* _SFNT_H_ */ |
diff --git a/src/sfntfont-android.c b/src/sfntfont-android.c index cddb3fd40f3..1b01a4d9be4 100644 --- a/src/sfntfont-android.c +++ b/src/sfntfont-android.c | |||
| @@ -31,6 +31,17 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |||
| 31 | #include "blockinput.h" | 31 | #include "blockinput.h" |
| 32 | #include "android.h" | 32 | #include "android.h" |
| 33 | 33 | ||
| 34 | /* Structure describing a temporary buffer. */ | ||
| 35 | |||
| 36 | struct sfntfont_android_scanline_buffer | ||
| 37 | { | ||
| 38 | /* Size of this buffer. */ | ||
| 39 | size_t buffer_size; | ||
| 40 | |||
| 41 | /* Pointer to the buffer data. */ | ||
| 42 | void *buffer_data; | ||
| 43 | }; | ||
| 44 | |||
| 34 | /* Array of directories to search for system fonts. */ | 45 | /* Array of directories to search for system fonts. */ |
| 35 | const char *system_font_directories[] = | 46 | const char *system_font_directories[] = |
| 36 | { | 47 | { |
| @@ -40,6 +51,49 @@ const char *system_font_directories[] = | |||
| 40 | /* The font cache. */ | 51 | /* The font cache. */ |
| 41 | static Lisp_Object font_cache; | 52 | static Lisp_Object font_cache; |
| 42 | 53 | ||
| 54 | /* The scanline buffer. */ | ||
| 55 | static struct sfntfont_android_scanline_buffer scanline_buffer; | ||
| 56 | |||
| 57 | /* The largest size of the scanline buffer since the last window | ||
| 58 | update. */ | ||
| 59 | static size_t max_scanline_buffer_size; | ||
| 60 | |||
| 61 | |||
| 62 | |||
| 63 | /* Return a temporary buffer for storing scan lines. | ||
| 64 | Set BUFFER to the buffer upon success. */ | ||
| 65 | |||
| 66 | #define GET_SCANLINE_BUFFER(buffer, height, stride) \ | ||
| 67 | do \ | ||
| 68 | { \ | ||
| 69 | size_t _size; \ | ||
| 70 | \ | ||
| 71 | if (INT_MULTIPLY_WRAPV (height, stride, &_size)) \ | ||
| 72 | memory_full (SIZE_MAX); \ | ||
| 73 | \ | ||
| 74 | if (_size < MAX_ALLOCA) \ | ||
| 75 | (buffer) = alloca (_size); \ | ||
| 76 | else \ | ||
| 77 | { \ | ||
| 78 | if (_size > scanline_buffer.buffer_size) \ | ||
| 79 | { \ | ||
| 80 | (buffer) \ | ||
| 81 | = scanline_buffer.buffer_data \ | ||
| 82 | = xrealloc (scanline_buffer.buffer_data, \ | ||
| 83 | _size); \ | ||
| 84 | scanline_buffer.buffer_size = _size; \ | ||
| 85 | } \ | ||
| 86 | else if (_size <= scanline_buffer.buffer_size) \ | ||
| 87 | (buffer) = scanline_buffer.buffer_data; \ | ||
| 88 | /* This is unreachable but clang says it is. */ \ | ||
| 89 | else \ | ||
| 90 | emacs_abort (); \ | ||
| 91 | \ | ||
| 92 | max_scanline_buffer_size \ | ||
| 93 | = max (_size, max_scanline_buffer_size); \ | ||
| 94 | } \ | ||
| 95 | } while (false); | ||
| 96 | |||
| 43 | 97 | ||
| 44 | 98 | ||
| 45 | /* Scale each of the four packed bytes in P in the low 16 bits of P by | 99 | /* Scale each of the four packed bytes in P in the low 16 bits of P by |
| @@ -205,8 +259,6 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from, | |||
| 205 | back_pixel &= ~0x00ff00ff; | 259 | back_pixel &= ~0x00ff00ff; |
| 206 | back_pixel |= rb >> 16 | rb << 16 | 0xff000000; | 260 | back_pixel |= rb >> 16 | rb << 16 | 0xff000000; |
| 207 | 261 | ||
| 208 | USE_SAFE_ALLOCA; | ||
| 209 | |||
| 210 | prepare_face_for_display (s->f, s->face); | 262 | prepare_face_for_display (s->f, s->face); |
| 211 | 263 | ||
| 212 | /* Build the scanline buffer. Figure out the bounds of the | 264 | /* Build the scanline buffer. Figure out the bounds of the |
| @@ -259,7 +311,7 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from, | |||
| 259 | /* Allocate enough to hold text_rectangle.height, aligned to 8 | 311 | /* Allocate enough to hold text_rectangle.height, aligned to 8 |
| 260 | bytes. Then fill it with the background. */ | 312 | bytes. Then fill it with the background. */ |
| 261 | stride = (text_rectangle.width * sizeof *buffer) + 7 & ~7; | 313 | stride = (text_rectangle.width * sizeof *buffer) + 7 & ~7; |
| 262 | SAFE_NALLOCA (buffer, text_rectangle.height, stride); | 314 | GET_SCANLINE_BUFFER (buffer, text_rectangle.height, stride); |
| 263 | memset (buffer, 0, text_rectangle.height * stride); | 315 | memset (buffer, 0, text_rectangle.height * stride); |
| 264 | 316 | ||
| 265 | if (with_background) | 317 | if (with_background) |
| @@ -327,10 +379,7 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from, | |||
| 327 | /* If locking the bitmap fails, just discard the data that was | 379 | /* If locking the bitmap fails, just discard the data that was |
| 328 | allocated. */ | 380 | allocated. */ |
| 329 | if (!bitmap_data) | 381 | if (!bitmap_data) |
| 330 | { | 382 | return; |
| 331 | SAFE_FREE (); | ||
| 332 | return; | ||
| 333 | } | ||
| 334 | 383 | ||
| 335 | /* Loop over each clip rect in the GC. */ | 384 | /* Loop over each clip rect in the GC. */ |
| 336 | eassert (bitmap_info.format == ANDROID_BITMAP_FORMAT_RGBA_8888); | 385 | eassert (bitmap_info.format == ANDROID_BITMAP_FORMAT_RGBA_8888); |
| @@ -366,8 +415,33 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from, | |||
| 366 | android_damage_window (FRAME_ANDROID_DRAWABLE (s->f), | 415 | android_damage_window (FRAME_ANDROID_DRAWABLE (s->f), |
| 367 | &text_rectangle); | 416 | &text_rectangle); |
| 368 | 417 | ||
| 369 | /* Release the temporary scanline buffer. */ | 418 | #undef MAX_ALLOCA |
| 370 | SAFE_FREE (); | 419 | } |
| 420 | |||
| 421 | |||
| 422 | |||
| 423 | /* Shrink the scanline buffer after a window update. If | ||
| 424 | max_scanline_buffer_size is not zero, and is less than | ||
| 425 | scanline_buffer.buffer_size / 2, then resize the scanline buffer to | ||
| 426 | max_scanline_buffer_size. */ | ||
| 427 | |||
| 428 | void | ||
| 429 | sfntfont_android_shrink_scanline_buffer (void) | ||
| 430 | { | ||
| 431 | if (!max_scanline_buffer_size) | ||
| 432 | return; | ||
| 433 | |||
| 434 | if (max_scanline_buffer_size | ||
| 435 | < scanline_buffer.buffer_size / 2) | ||
| 436 | { | ||
| 437 | scanline_buffer.buffer_size | ||
| 438 | = max_scanline_buffer_size; | ||
| 439 | scanline_buffer.buffer_data | ||
| 440 | = xrealloc (scanline_buffer.buffer_data, | ||
| 441 | max_scanline_buffer_size); | ||
| 442 | } | ||
| 443 | |||
| 444 | max_scanline_buffer_size = 0; | ||
| 371 | } | 445 | } |
| 372 | 446 | ||
| 373 | 447 | ||
| @@ -437,10 +511,11 @@ loaded before character sets are made available. */) | |||
| 437 | 511 | ||
| 438 | while ((dirent = readdir (dir))) | 512 | while ((dirent = readdir (dir))) |
| 439 | { | 513 | { |
| 440 | /* If it contains (not ends with!) with .ttf, then enumerate | 514 | /* If it contains (not ends with!) with .ttf or .ttc, then |
| 441 | it. */ | 515 | enumerate it. */ |
| 442 | 516 | ||
| 443 | if (strstr (dirent->d_name, ".ttf")) | 517 | if (strstr (dirent->d_name, ".ttf") |
| 518 | || strstr (dirent->d_name, ".ttc")) | ||
| 444 | { | 519 | { |
| 445 | sprintf (name, "%s/%s", system_font_directories[i], | 520 | sprintf (name, "%s/%s", system_font_directories[i], |
| 446 | dirent->d_name); | 521 | dirent->d_name); |
diff --git a/src/sfntfont.c b/src/sfntfont.c index 56977622211..e2d18517fcb 100644 --- a/src/sfntfont.c +++ b/src/sfntfont.c | |||
| @@ -77,6 +77,9 @@ struct sfnt_font_desc | |||
| 77 | /* The header of the cmap being used. May be invalid, in which case | 77 | /* The header of the cmap being used. May be invalid, in which case |
| 78 | platform_id will be 500. */ | 78 | platform_id will be 500. */ |
| 79 | struct sfnt_cmap_encoding_subtable subtable; | 79 | struct sfnt_cmap_encoding_subtable subtable; |
| 80 | |||
| 81 | /* The offset of the table directory within PATH. */ | ||
| 82 | off_t offset; | ||
| 80 | }; | 83 | }; |
| 81 | 84 | ||
| 82 | /* List of fonts. */ | 85 | /* List of fonts. */ |
| @@ -426,15 +429,17 @@ sfnt_parse_style (Lisp_Object style_name, struct sfnt_font_desc *desc) | |||
| 426 | } | 429 | } |
| 427 | } | 430 | } |
| 428 | 431 | ||
| 429 | /* Enumerate the font FILE into the list of system fonts. Return 1 if | 432 | /* Enumerate the offset subtable SUBTABLES in the file FD, whose file |
| 430 | it could not be enumerated, 0 otherwise. */ | 433 | name is FILE. OFFSET should be the offset of the subtable within |
| 434 | the font file, and is recorded for future use. Value is 1 upon | ||
| 435 | failure, else 0. */ | ||
| 431 | 436 | ||
| 432 | int | 437 | static int |
| 433 | sfnt_enum_font (const char *file) | 438 | sfnt_enum_font_1 (int fd, const char *file, |
| 439 | struct sfnt_offset_subtable *subtables, | ||
| 440 | off_t offset) | ||
| 434 | { | 441 | { |
| 435 | struct sfnt_font_desc *desc; | 442 | struct sfnt_font_desc *desc; |
| 436 | int fd; | ||
| 437 | struct sfnt_offset_subtable *subtables; | ||
| 438 | struct sfnt_head_table *head; | 443 | struct sfnt_head_table *head; |
| 439 | struct sfnt_name_table *name; | 444 | struct sfnt_name_table *name; |
| 440 | struct sfnt_meta_table *meta; | 445 | struct sfnt_meta_table *meta; |
| @@ -444,18 +449,7 @@ sfnt_enum_font (const char *file) | |||
| 444 | desc = xzalloc (sizeof *desc + strlen (file) + 1); | 449 | desc = xzalloc (sizeof *desc + strlen (file) + 1); |
| 445 | desc->path = (char *) (desc + 1); | 450 | desc->path = (char *) (desc + 1); |
| 446 | memcpy (desc->path, file, strlen (file) + 1); | 451 | memcpy (desc->path, file, strlen (file) + 1); |
| 447 | 452 | desc->offset = offset; | |
| 448 | /* Now open the font for reading. */ | ||
| 449 | fd = emacs_open (file, O_RDONLY, 0); | ||
| 450 | |||
| 451 | if (fd == -1) | ||
| 452 | goto bail; | ||
| 453 | |||
| 454 | /* Read the table directory. */ | ||
| 455 | subtables = sfnt_read_table_directory (fd); | ||
| 456 | |||
| 457 | if (!subtables) | ||
| 458 | goto bail0; | ||
| 459 | 453 | ||
| 460 | /* Check that this is a TrueType font. */ | 454 | /* Check that this is a TrueType font. */ |
| 461 | if (subtables->scaler_type != SFNT_SCALER_TRUE | 455 | if (subtables->scaler_type != SFNT_SCALER_TRUE |
| @@ -511,8 +505,6 @@ sfnt_enum_font (const char *file) | |||
| 511 | xfree (meta); | 505 | xfree (meta); |
| 512 | xfree (name); | 506 | xfree (name); |
| 513 | xfree (head); | 507 | xfree (head); |
| 514 | xfree (subtables); | ||
| 515 | emacs_close (fd); | ||
| 516 | return 0; | 508 | return 0; |
| 517 | 509 | ||
| 518 | bail3: | 510 | bail3: |
| @@ -521,11 +513,84 @@ sfnt_enum_font (const char *file) | |||
| 521 | bail2: | 513 | bail2: |
| 522 | xfree (head); | 514 | xfree (head); |
| 523 | bail1: | 515 | bail1: |
| 516 | xfree (desc); | ||
| 517 | return 1; | ||
| 518 | } | ||
| 519 | |||
| 520 | /* Enumerate the font FILE into the list of system fonts. Return 1 if | ||
| 521 | it could not be enumerated, 0 otherwise. | ||
| 522 | |||
| 523 | FILE can either be a TrueType collection file containing TrueType | ||
| 524 | fonts, or a TrueType font itself. */ | ||
| 525 | |||
| 526 | int | ||
| 527 | sfnt_enum_font (const char *file) | ||
| 528 | { | ||
| 529 | int fd, rc; | ||
| 530 | struct sfnt_offset_subtable *subtables; | ||
| 531 | struct sfnt_ttc_header *ttc; | ||
| 532 | size_t i; | ||
| 533 | |||
| 534 | /* Now open the font for reading. */ | ||
| 535 | fd = emacs_open (file, O_RDONLY, 0); | ||
| 536 | |||
| 537 | if (fd == -1) | ||
| 538 | goto bail; | ||
| 539 | |||
| 540 | /* Read the table directory. */ | ||
| 541 | subtables = sfnt_read_table_directory (fd); | ||
| 542 | |||
| 543 | if (subtables == (struct sfnt_offset_subtable *) -1) | ||
| 544 | { | ||
| 545 | /* This is actually a TrueType container file. Go back to the | ||
| 546 | beginning and read the TTC header. */ | ||
| 547 | |||
| 548 | if (lseek (fd, 0, SEEK_SET)) | ||
| 549 | goto bail0; | ||
| 550 | |||
| 551 | ttc = sfnt_read_ttc_header (fd); | ||
| 552 | |||
| 553 | if (!ttc) | ||
| 554 | goto bail0; | ||
| 555 | |||
| 556 | /* Enumerate each of the fonts in the collection. */ | ||
| 557 | |||
| 558 | for (i = 0; i < ttc->num_fonts; ++i) | ||
| 559 | { | ||
| 560 | if (lseek (fd, ttc->offset_table[i], SEEK_SET) | ||
| 561 | != ttc->offset_table[i]) | ||
| 562 | continue; | ||
| 563 | |||
| 564 | subtables = sfnt_read_table_directory (fd); | ||
| 565 | |||
| 566 | if (!subtables) | ||
| 567 | continue; | ||
| 568 | |||
| 569 | sfnt_enum_font_1 (fd, file, subtables, | ||
| 570 | ttc->offset_table[i]); | ||
| 571 | xfree (subtables); | ||
| 572 | } | ||
| 573 | |||
| 574 | /* Always treat reading containers as having been | ||
| 575 | successful. */ | ||
| 576 | |||
| 577 | emacs_close (fd); | ||
| 578 | xfree (ttc); | ||
| 579 | return 0; | ||
| 580 | } | ||
| 581 | |||
| 582 | if (!subtables) | ||
| 583 | goto bail0; | ||
| 584 | |||
| 585 | /* Now actually enumerate this font. */ | ||
| 586 | rc = sfnt_enum_font_1 (fd, file, subtables, 0); | ||
| 524 | xfree (subtables); | 587 | xfree (subtables); |
| 588 | emacs_close (fd); | ||
| 589 | return rc; | ||
| 590 | |||
| 525 | bail0: | 591 | bail0: |
| 526 | emacs_close (fd); | 592 | emacs_close (fd); |
| 527 | bail: | 593 | bail: |
| 528 | xfree (desc); | ||
| 529 | return 1; | 594 | return 1; |
| 530 | } | 595 | } |
| 531 | 596 | ||
| @@ -1730,6 +1795,12 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity, | |||
| 1730 | if (fd == -1) | 1795 | if (fd == -1) |
| 1731 | goto bail; | 1796 | goto bail; |
| 1732 | 1797 | ||
| 1798 | /* Seek to the offset specified. */ | ||
| 1799 | |||
| 1800 | if (desc->offset | ||
| 1801 | && lseek (fd, desc->offset, SEEK_SET) != desc->offset) | ||
| 1802 | goto bail; | ||
| 1803 | |||
| 1733 | /* Read the offset subtable. */ | 1804 | /* Read the offset subtable. */ |
| 1734 | subtable = sfnt_read_table_directory (fd); | 1805 | subtable = sfnt_read_table_directory (fd); |
| 1735 | 1806 | ||