aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-01-16 19:50:02 +0800
committerPo Lu2023-01-16 19:50:02 +0800
commitad59d8986aee4498c0427449e024341d1a195a2d (patch)
treeda8ee046484e48cd991cb484ecc960a7432c91de /src
parentda9ae10636b84b88e9eb9c827b03cdaabd1611d1 (diff)
downloademacs-ad59d8986aee4498c0427449e024341d1a195a2d.tar.gz
emacs-ad59d8986aee4498c0427449e024341d1a195a2d.zip
Update Android port
* doc/emacs/android.texi (Android, Android Environment): Improve documentation. * doc/lispref/commands.texi (Touchscreen Events): Document changes to touchscreen support. * doc/lispref/display.texi (Defining Faces, Window Systems): * doc/lispref/frames.texi (Frame Layout, Font and Color Parameters): * doc/lispref/os.texi (System Environment): Document Android in various places. * java/org/gnu/emacs/EmacsWindow.java (figureChange): Fix crash. * lisp/loadup.el: ("touch-screen"): Load touch-screen.el. * lisp/pixel-scroll.el: Autoload two functions. * lisp/term/android-win.el: Add require 'touch-screen. * lisp/touch-screen.el (touch-screen-current-tool) (touch-screen-current-timer, touch-screen-delay) (touch-screen-relative-xy, touch-screen-handle-scroll) (touch-screen-handle-timeout, touch-screen-handle-point-update) (touch-screen-handle-point-up, touch-screen-handle-touch) (global-map, touch-screen): New file. * src/android.c (android_run_debug_thread): Fix build on 64 bit systems. (JNICALL, android_put_pixel): Likewise. (android_transform_coordinates, android_four_corners_bilinear) (android_fetch_pixel_bilinear, android_project_image_bilinear) (android_fetch_pixel_nearest_24, android_fetch_pixel_nearest_1) (android_project_image_nearest): New functions. * src/androidgui.h (struct android_transform): New structure. * src/androidterm.c (android_note_mouse_movement): Remove obsolete TODO. (android_get_scale_factor): New function. (android_draw_underwave): Scale underwave correctly. * src/dispextern.h: Support native image transforms on Android. * src/image.c (matrix_identity, matrix_rotate) (matrix_mirror_horizontal, matrix_translate): New functions. (image_set_transform): Implement native image transforms on Android. (Fimage_transforms_p): Implement on Android. * src/keyboard.c (make_lispy_event, syms_of_keyboard): Handle touch screen- menu bar events. * src/sfnt.c: Fix typo in comment. * src/sfntfont-android.c (sfntfont_android_blend, U255TO256) (sfntfont_android_put_glyphs): Avoid redundant swizzling. * src/sfntfont.c (sfntfont_lookup_char): Fix build on 64 bit systems.
Diffstat (limited to 'src')
-rw-r--r--src/android.c282
-rw-r--r--src/androidgui.h19
-rw-r--r--src/androidterm.c28
-rw-r--r--src/dispextern.h5
-rw-r--r--src/image.c310
-rw-r--r--src/keyboard.c70
-rw-r--r--src/sfnt.c2
-rw-r--r--src/sfntfont-android.c55
-rw-r--r--src/sfntfont.c2
9 files changed, 715 insertions, 58 deletions
diff --git a/src/android.c b/src/android.c
index 3a965286460..9b15ea9f15a 100644
--- a/src/android.c
+++ b/src/android.c
@@ -25,9 +25,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
25#include <signal.h> 25#include <signal.h>
26#include <semaphore.h> 26#include <semaphore.h>
27#include <dlfcn.h> 27#include <dlfcn.h>
28#include <errno.h>
28 29
29#include <sys/stat.h> 30#include <sys/stat.h>
30#include <sys/mman.h> 31#include <sys/mman.h>
32#include <sys/param.h>
31 33
32#include <assert.h> 34#include <assert.h>
33 35
@@ -513,7 +515,7 @@ android_run_debug_thread (void *data)
513 char *line; 515 char *line;
514 size_t n; 516 size_t n;
515 517
516 fd = (int) data; 518 fd = (int) (intptr_t) data;
517 file = fdopen (fd, "r"); 519 file = fdopen (fd, "r");
518 520
519 if (!file) 521 if (!file)
@@ -958,7 +960,7 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
958 close (pipefd[1]); 960 close (pipefd[1]);
959 961
960 if (pthread_create (&thread, NULL, android_run_debug_thread, 962 if (pthread_create (&thread, NULL, android_run_debug_thread,
961 (void *) pipefd[0])) 963 (void *) (intptr_t) pipefd[0]))
962 emacs_abort (); 964 emacs_abort ();
963 965
964 /* Now set the path to the site load directory. */ 966 /* Now set the path to the site load directory. */
@@ -2829,6 +2831,7 @@ android_put_pixel (struct android_image *ximg, int x, int y,
2829{ 2831{
2830 char *byte, *word; 2832 char *byte, *word;
2831 unsigned int r, g, b; 2833 unsigned int r, g, b;
2834 unsigned int pixel_int;
2832 2835
2833 /* Ignore out-of-bounds accesses. */ 2836 /* Ignore out-of-bounds accesses. */
2834 2837
@@ -2859,7 +2862,8 @@ android_put_pixel (struct android_image *ximg, int x, int y,
2859 b = pixel & 0x000000ff; 2862 b = pixel & 0x000000ff;
2860 pixel = (r >> 16) | g | (b << 16) | 0xff000000; 2863 pixel = (r >> 16) | g | (b << 16) | 0xff000000;
2861 2864
2862 memcpy (word, &pixel, sizeof pixel); 2865 pixel_int = pixel;
2866 memcpy (word, &pixel_int, sizeof pixel_int);
2863 break; 2867 break;
2864 } 2868 }
2865} 2869}
@@ -3734,6 +3738,262 @@ android_exception_check (void)
3734 } 3738 }
3735} 3739}
3736 3740
3741
3742
3743/* Native image transforms. */
3744
3745/* Transform the coordinates X and Y by the specified affine
3746 transformation MATRIX. Place the result in *XOUT and *YOUT. */
3747
3748static void
3749android_transform_coordinates (int x, int y,
3750 struct android_transform *transform,
3751 float *xout, float *yout)
3752{
3753 /* Apply the specified affine transformation.
3754 A transform looks like:
3755
3756 M1 M2 M3 X
3757 M4 M5 M6 * Y
3758
3759 =
3760
3761 M1*X + M2*Y + M3*1 = X1
3762 M4*X + M5*Y + M6*1 = Y1
3763
3764 (In most transforms, there is another row at the bottom for
3765 mathematical reasons. Since Z1 is always 1.0, the row is simply
3766 implied to be 0 0 1, because 0 * x + 0 * y + 1 * 1 = 1.0. See
3767 the definition of matrix3x3 in image.c for some more explanations
3768 about this.) */
3769
3770 *xout = transform->m1 * x + transform->m2 * y + transform->m3;
3771 *yout = transform->m4 * x + transform->m5 * y + transform->m6;
3772}
3773
3774/* Return the interpolation of the four pixels TL, TR, BL, and BR,
3775 according to the weights DISTX and DISTY. */
3776
3777static unsigned int
3778android_four_corners_bilinear (unsigned int tl, unsigned int tr,
3779 unsigned int bl, unsigned int br,
3780 int distx, int disty)
3781{
3782 int distxy, distxiy, distixy, distixiy;
3783 uint32_t f, r;
3784
3785 distxy = distx * disty;
3786 distxiy = (distx << 8) - distxy;
3787 distixy = (disty << 8) - distxy;
3788 distixiy = (256 * 256 - (disty << 8)
3789 - (distx << 8) + distxy);
3790
3791 /* Red */
3792 r = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
3793 + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy);
3794
3795 /* Green */
3796 f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
3797 + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy);
3798 r |= f & 0xff000000;
3799
3800 /* Now do the upper two components. */
3801 tl >>= 16;
3802 tr >>= 16;
3803 bl >>= 16;
3804 br >>= 16;
3805 r >>= 16;
3806
3807 /* Blue */
3808 f = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
3809 + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy);
3810 r |= f & 0x00ff0000;
3811
3812 /* Alpha */
3813 f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
3814 + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy);
3815 r |= f & 0xff000000;
3816
3817 return r;
3818}
3819
3820/* Return the interpolation of the four pixels closest to at X, Y in
3821 IMAGE, according to weights in both axes computed from X and Y.
3822 IMAGE must be depth 24, or the behavior is undefined. */
3823
3824static unsigned int
3825android_fetch_pixel_bilinear (struct android_image *image,
3826 float x, float y)
3827{
3828 int x1, y1, x2, y2;
3829 float distx, disty;
3830 unsigned int top_left, top_right;
3831 unsigned int bottom_left, bottom_right;
3832 char *word;
3833
3834 /* Compute the four closest corners to X and Y. */
3835 x1 = (int) x;
3836 x2 = x1 + 1;
3837 y1 = (int) y;
3838 y2 = y1 + 1;
3839
3840 /* Make sure all four corners are within range. */
3841 x1 = MAX (0, MIN (image->width - 1, x1));
3842 y1 = MAX (0, MIN (image->height - 1, y1));
3843 x2 = MAX (0, MIN (image->width - 1, x2));
3844 y2 = MAX (0, MIN (image->height - 1, y2));
3845
3846 /* Compute the X and Y biases. These are numbers between 0f and
3847 1f. */
3848 distx = x - x1;
3849 disty = y - y1;
3850
3851 /* Fetch the four closest pixels. */
3852 word = image->data + y1 * image->bytes_per_line + x1 * 4;
3853 memcpy (&top_left, word, sizeof top_left);
3854 word = image->data + y1 * image->bytes_per_line + x2 * 4;
3855 memcpy (&top_right, word, sizeof top_right);
3856 word = image->data + y2 * image->bytes_per_line + x1 * 4;
3857 memcpy (&bottom_left, word, sizeof bottom_left);
3858 word = image->data + y2 * image->bytes_per_line + x2 * 4;
3859 memcpy (&bottom_right, word, sizeof bottom_right);
3860
3861 /* Do the interpolation. */
3862 return android_four_corners_bilinear (top_left, top_right, bottom_left,
3863 bottom_right, distx * 256,
3864 disty * 256);
3865}
3866
3867/* Transform the depth 24 image IMAGE by the 3x2 affine transformation
3868 matrix MATRIX utilizing a bilinear filter. Place the result in
3869 OUT. The matrix maps from the coordinate space of OUT to
3870 IMAGE. */
3871
3872void
3873android_project_image_bilinear (struct android_image *image,
3874 struct android_image *out,
3875 struct android_transform *transform)
3876{
3877 int x, y;
3878 unsigned int pixel;
3879 float xout, yout;
3880 char *word;
3881
3882 /* Loop through each pixel in OUT. Transform it by TRANSFORM, then
3883 interpolate it to IMAGE, and place the result back in OUT. */
3884
3885 for (y = 0; y < out->height; ++y)
3886 {
3887 for (x = 0; x < out->width; ++x)
3888 {
3889 /* Transform the coordinates by TRANSFORM. */
3890 android_transform_coordinates (x, y, transform,
3891 &xout, &yout);
3892
3893 /* Interpolate back to IMAGE. */
3894 pixel = android_fetch_pixel_bilinear (image, xout, yout);
3895
3896 /* Put the pixel back in OUT. */
3897 word = out->data + y * out->bytes_per_line + x * 4;
3898 memcpy (word, &pixel, sizeof pixel);
3899 }
3900 }
3901}
3902
3903/* Return the interpolation of X, Y to IMAGE, a depth 24 image. */
3904
3905static unsigned int
3906android_fetch_pixel_nearest_24 (struct android_image *image, float x,
3907 float y)
3908{
3909 int x1, y1;
3910 char *word;
3911 unsigned int pixel;
3912
3913 x1 = MAX (0, MIN (image->width - 1, (int) roundf (x)));
3914 y1 = MAX (0, MIN (image->height - 1, (int) roundf (y)));
3915
3916 word = image->data + y1 * image->bytes_per_line + x1 * 4;
3917 memcpy (&pixel, word, sizeof pixel);
3918
3919 return pixel;
3920}
3921
3922/* Return the interpolation of X, Y to IMAGE, a depth 1 image. */
3923
3924static unsigned int
3925android_fetch_pixel_nearest_1 (struct android_image *image, float x,
3926 float y)
3927{
3928 int x1, y1;
3929 char *byte;
3930
3931 x1 = MAX (0, MIN (image->width - 1, (int) roundf (x)));
3932 y1 = MAX (0, MIN (image->height - 1, (int) roundf (y)));
3933
3934 byte = image->data + y1 * image->bytes_per_line;
3935 return (byte[x1 / 8] & (1 << x1 % 8)) ? 1 : 0;
3936}
3937
3938/* Transform the depth 24 or 1 image IMAGE by the 3x2 affine
3939 transformation matrix MATRIX. Place the result in OUT. The matrix
3940 maps from the coordinate space of OUT to IMAGE. Use a
3941 nearest-neighbor filter. */
3942
3943void
3944android_project_image_nearest (struct android_image *image,
3945 struct android_image *out,
3946 struct android_transform *transform)
3947{
3948 int x, y;
3949 unsigned int pixel;
3950 float xout, yout;
3951 char *word, *byte;
3952
3953 if (image->depth == 1)
3954 {
3955 for (y = 0; y < out->height; ++y)
3956 {
3957 for (x = 0; x < out->width; ++x)
3958 {
3959 /* Transform the coordinates by TRANSFORM. */
3960 android_transform_coordinates (x, y, transform,
3961 &xout, &yout);
3962
3963 /* Interpolate back to IMAGE. */
3964 pixel = android_fetch_pixel_nearest_1 (image, xout, yout);
3965
3966 /* Put the pixel back in OUT. */
3967 byte = out->data + y * out->bytes_per_line + x / 8;
3968
3969 if (pixel)
3970 *byte |= (1 << x % 8);
3971 else
3972 *byte &= ~(1 << x % 8);
3973 }
3974 }
3975
3976 return;
3977 }
3978
3979 for (y = 0; y < out->height; ++y)
3980 {
3981 for (x = 0; x < out->width; ++x)
3982 {
3983 /* Transform the coordinates by TRANSFORM. */
3984 android_transform_coordinates (x, y, transform,
3985 &xout, &yout);
3986
3987 /* Interpolate back to IMAGE. */
3988 pixel = android_fetch_pixel_nearest_24 (image, xout, yout);
3989
3990 /* Put the pixel back in OUT. */
3991 word = out->data + y * out->bytes_per_line + x * 4;
3992 memcpy (word, &pixel, sizeof pixel);
3993 }
3994 }
3995}
3996
3737#else /* ANDROID_STUBIFY */ 3997#else /* ANDROID_STUBIFY */
3738 3998
3739/* X emulation functions for Android. */ 3999/* X emulation functions for Android. */
@@ -3793,4 +4053,20 @@ android_put_image (android_pixmap pixmap,
3793 emacs_abort (); 4053 emacs_abort ();
3794} 4054}
3795 4055
4056void
4057android_project_image_bilinear (struct android_image *image,
4058 struct android_image *out,
4059 struct android_transform *transform)
4060{
4061 emacs_abort ();
4062}
4063
4064void
4065android_project_image_nearest (struct android_image *image,
4066 struct android_image *out,
4067 struct android_transform *transform)
4068{
4069 emacs_abort ();
4070}
4071
3796#endif 4072#endif
diff --git a/src/androidgui.h b/src/androidgui.h
index 9df5b073a7c..1f28c18ff34 100644
--- a/src/androidgui.h
+++ b/src/androidgui.h
@@ -542,6 +542,25 @@ extern struct android_image *android_get_image (android_drawable,
542 enum android_image_format); 542 enum android_image_format);
543extern void android_put_image (android_pixmap, struct android_image *); 543extern void android_put_image (android_pixmap, struct android_image *);
544 544
545
546/* Native image transforms. */
547
548/* 3x2 matrix describing a projective transform. See
549 android_transform_coordinates for details. */
550
551struct android_transform
552{
553 float m1, m2, m3;
554 float m4, m5, m6;
555};
556
557extern void android_project_image_bilinear (struct android_image *,
558 struct android_image *,
559 struct android_transform *);
560extern void android_project_image_nearest (struct android_image *,
561 struct android_image *,
562 struct android_transform *);
563
545 564
546 565
547/* X emulation stuff also needed while building stubs. */ 566/* X emulation stuff also needed while building stubs. */
diff --git a/src/androidterm.c b/src/androidterm.c
index 6f452a52d85..cc2da279bb3 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -417,8 +417,6 @@ android_note_mouse_movement (struct frame *frame,
417 || event->y < r->y || event->y >= r->y + r->height) 417 || event->y < r->y || event->y >= r->y + r->height)
418 { 418 {
419 frame->mouse_moved = true; 419 frame->mouse_moved = true;
420 /* TODO
421 dpyinfo->last_mouse_scroll_bar = NULL; */
422 note_mouse_highlight (frame, event->x, event->y); 420 note_mouse_highlight (frame, event->x, event->y);
423 /* Remember which glyph we're now on. */ 421 /* Remember which glyph we're now on. */
424 remember_mouse_glyph (frame, event->x, event->y, r); 422 remember_mouse_glyph (frame, event->x, event->y, r);
@@ -2960,9 +2958,33 @@ android_draw_stretch_glyph_string (struct glyph_string *s)
2960} 2958}
2961 2959
2962static void 2960static void
2961android_get_scale_factor (int *scale_x, int *scale_y)
2962{
2963 /* This is 96 everywhere else, but 160 on Android. */
2964 const int base_res = 160;
2965 struct android_display_info *dpyinfo;
2966
2967 dpyinfo = x_display_list;
2968 *scale_x = *scale_y = 1;
2969
2970 if (dpyinfo)
2971 {
2972 if (dpyinfo->resx > base_res)
2973 *scale_x = floor (dpyinfo->resx / base_res);
2974 if (dpyinfo->resy > base_res)
2975 *scale_y = floor (dpyinfo->resy / base_res);
2976 }
2977}
2978
2979static void
2963android_draw_underwave (struct glyph_string *s, int decoration_width) 2980android_draw_underwave (struct glyph_string *s, int decoration_width)
2964{ 2981{
2965 int wave_height = 3, wave_length = 2; 2982 int scale_x, scale_y;
2983
2984 android_get_scale_factor (&scale_x, &scale_y);
2985
2986 int wave_height = 3 * scale_y, wave_length = 2 * scale_x;
2987
2966 int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax; 2988 int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax;
2967 bool odd; 2989 bool odd;
2968 struct android_rectangle wave_clip, string_clip, final_clip; 2990 struct android_rectangle wave_clip, string_clip, final_clip;
diff --git a/src/dispextern.h b/src/dispextern.h
index 2ceed53813e..bc3556114c5 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -3098,8 +3098,9 @@ struct redisplay_interface
3098 3098
3099#ifdef HAVE_WINDOW_SYSTEM 3099#ifdef HAVE_WINDOW_SYSTEM
3100 3100
3101# if (defined USE_CAIRO || defined HAVE_XRENDER \ 3101# if (defined USE_CAIRO || defined HAVE_XRENDER \
3102 || defined HAVE_NS || defined HAVE_NTGUI || defined HAVE_HAIKU) 3102 || defined HAVE_NS || defined HAVE_NTGUI || defined HAVE_HAIKU \
3103 || defined HAVE_ANDROID)
3103# define HAVE_NATIVE_TRANSFORMS 3104# define HAVE_NATIVE_TRANSFORMS
3104# endif 3105# endif
3105 3106
diff --git a/src/image.c b/src/image.c
index 364ddd96e31..16618f49f1e 100644
--- a/src/image.c
+++ b/src/image.c
@@ -2631,11 +2631,11 @@ compute_image_size (double width, double height,
2631 finally move the origin back to the top left of the image, which 2631 finally move the origin back to the top left of the image, which
2632 may now be a different corner. 2632 may now be a different corner.
2633 2633
2634 Note that different GUI backends (X, Cairo, w32, NS, Haiku) want 2634 Note that different GUI backends (X, Cairo, w32, NS, Haiku,
2635 the transform matrix defined as transform from the original image 2635 Android) want the transform matrix defined as transform from the
2636 to the transformed image, while others want the matrix to describe 2636 original image to the transformed image, while others want the
2637 the transform of the space, which boils down to inverting the 2637 matrix to describe the transform of the space, which boils down to
2638 matrix. 2638 inverting the matrix.
2639 2639
2640 It's possible to pre-calculate the matrix multiplications and just 2640 It's possible to pre-calculate the matrix multiplications and just
2641 generate one transform matrix that will do everything we need in a 2641 generate one transform matrix that will do everything we need in a
@@ -2677,6 +2677,96 @@ compute_image_rotation (struct image *img, double *rotation)
2677 *rotation = XFIXNUM (reduced_angle); 2677 *rotation = XFIXNUM (reduced_angle);
2678} 2678}
2679 2679
2680#ifdef HAVE_ANDROID
2681
2682static void
2683matrix_identity (matrix3x3 matrix)
2684{
2685 memset (matrix, 0, sizeof (matrix3x3));
2686
2687 matrix[0][0] = 1.0;
2688 matrix[1][1] = 1.0;
2689 matrix[2][2] = 1.0;
2690}
2691
2692/* Translate the matrix TRANSFORM to X, Y, and then perform clockwise
2693 rotation by the given angle THETA in radians and translate back.
2694 As the transform is being performed in a coordinate system where Y
2695 grows downwards, the given angle describes a clockwise
2696 rotation. */
2697
2698static void
2699matrix_rotate (matrix3x3 transform, double theta, double x, double y)
2700{
2701 matrix3x3 temp, copy;
2702
2703 /* 1. Translate the matrix so X and Y are in the center. */
2704
2705 matrix_identity (temp);
2706 memcpy (copy, transform, sizeof copy);
2707
2708 temp[0][2] = x;
2709 temp[1][2] = y;
2710
2711 matrix3x3_mult (copy, temp, transform);
2712 matrix_identity (temp);
2713 memcpy (copy, transform, sizeof copy);
2714
2715 /* 2. Rotate the matrix counter-clockwise, assuming a coordinate
2716 system where Y grows downwards. */
2717
2718 temp[0][0] = cos (theta);
2719 temp[0][1] = -sin (theta);
2720 temp[1][0] = sinf (theta);
2721 temp[1][1] = cosf (theta);
2722
2723 matrix3x3_mult (copy, temp, transform);
2724 matrix_identity (temp);
2725 memcpy (copy, transform, sizeof copy);
2726
2727 /* 3. Translate back. */
2728
2729 temp[0][2] = -x;
2730 temp[1][2] = -y;
2731
2732 matrix3x3_mult (copy, temp, transform);
2733}
2734
2735/* Scale the matrix TRANSFORM by -1, and then apply a TX of width, in
2736 effect flipping the image horizontally. */
2737
2738static void
2739matrix_mirror_horizontal (matrix3x3 transform, double width)
2740{
2741 matrix3x3 temp, copy;
2742
2743 matrix_identity (temp);
2744 memcpy (copy, transform, sizeof copy);
2745
2746 temp[0][0] = -1.0f;
2747 temp[0][2] = width;
2748
2749 matrix3x3_mult (copy, temp, transform);
2750}
2751
2752static void
2753matrix_translate (matrix3x3 transform, float tx, float ty)
2754{
2755 matrix3x3 temp, copy;
2756
2757 matrix_identity (temp);
2758 memcpy (copy, transform, sizeof copy);
2759
2760 /* Set the tx and ty. */
2761 temp[0][2] = tx;
2762 temp[1][2] = ty;
2763
2764 /* Multiply it with the transform. */
2765 matrix3x3_mult (copy, temp, transform);
2766}
2767
2768#endif
2769
2680static void 2770static void
2681image_set_transform (struct frame *f, struct image *img) 2771image_set_transform (struct frame *f, struct image *img)
2682{ 2772{
@@ -2696,6 +2786,14 @@ image_set_transform (struct frame *f, struct image *img)
2696 memcpy (&img->transform, identity, sizeof identity); 2786 memcpy (&img->transform, identity, sizeof identity);
2697#endif 2787#endif
2698 2788
2789#if defined HAVE_ANDROID
2790 matrix3x3 identity = {
2791 { 1, 0, 0 },
2792 { 0, 1, 0 },
2793 { 0, 0, 1 },
2794 };
2795#endif
2796
2699# if (defined HAVE_IMAGEMAGICK \ 2797# if (defined HAVE_IMAGEMAGICK \
2700 && !defined DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE) 2798 && !defined DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE)
2701 /* ImageMagick images already have the correct transform. */ 2799 /* ImageMagick images already have the correct transform. */
@@ -2733,7 +2831,8 @@ image_set_transform (struct frame *f, struct image *img)
2733 /* Determine flipping. */ 2831 /* Determine flipping. */
2734 flip = !NILP (image_spec_value (img->spec, QCflip, NULL)); 2832 flip = !NILP (image_spec_value (img->spec, QCflip, NULL));
2735 2833
2736# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_HAIKU 2834# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_HAIKU \
2835 || defined HAVE_ANDROID
2737 /* We want scale up operations to use a nearest neighbor filter to 2836 /* We want scale up operations to use a nearest neighbor filter to
2738 show real pixels instead of munging them, but scale down 2837 show real pixels instead of munging them, but scale down
2739 operations to use a blended filter, to avoid aliasing and the like. 2838 operations to use a blended filter, to avoid aliasing and the like.
@@ -2755,7 +2854,7 @@ image_set_transform (struct frame *f, struct image *img)
2755 2854
2756 matrix3x3 matrix 2855 matrix3x3 matrix
2757 = { 2856 = {
2758# if defined USE_CAIRO || defined HAVE_XRENDER 2857# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_ANDROID
2759 [0][0] = (!IEEE_FLOATING_POINT && width == 0 ? DBL_MAX 2858 [0][0] = (!IEEE_FLOATING_POINT && width == 0 ? DBL_MAX
2760 : img->width / (double) width), 2859 : img->width / (double) width),
2761 [1][1] = (!IEEE_FLOATING_POINT && height == 0 ? DBL_MAX 2860 [1][1] = (!IEEE_FLOATING_POINT && height == 0 ? DBL_MAX
@@ -2778,7 +2877,7 @@ image_set_transform (struct frame *f, struct image *img)
2778 2877
2779 /* Haiku needs this, since the transformation is done on the basis 2878 /* Haiku needs this, since the transformation is done on the basis
2780 of the view, and not the image. */ 2879 of the view, and not the image. */
2781#ifdef HAVE_HAIKU 2880#if defined HAVE_HAIKU
2782 int extra_tx, extra_ty; 2881 int extra_tx, extra_ty;
2783 2882
2784 extra_tx = 0; 2883 extra_tx = 0;
@@ -2789,8 +2888,9 @@ image_set_transform (struct frame *f, struct image *img)
2789 rotate_flag = 0; 2888 rotate_flag = 0;
2790 else 2889 else
2791 { 2890 {
2792# if (defined USE_CAIRO || defined HAVE_XRENDER \ 2891#ifndef HAVE_ANDROID
2793 || defined HAVE_NTGUI || defined HAVE_NS \ 2892# if (defined USE_CAIRO || defined HAVE_XRENDER \
2893 || defined HAVE_NTGUI || defined HAVE_NS \
2794 || defined HAVE_HAIKU) 2894 || defined HAVE_HAIKU)
2795 int cos_r, sin_r; 2895 int cos_r, sin_r;
2796 if (rotation == 0) 2896 if (rotation == 0)
@@ -2817,7 +2917,7 @@ image_set_transform (struct frame *f, struct image *img)
2817 sin_r = 1; 2917 sin_r = 1;
2818 rotate_flag = 1; 2918 rotate_flag = 1;
2819 2919
2820#ifdef HAVE_HAIKU 2920#if defined HAVE_HAIKU
2821 if (!flip) 2921 if (!flip)
2822 extra_ty = height; 2922 extra_ty = height;
2823 extra_tx = 0; 2923 extra_tx = 0;
@@ -2853,7 +2953,7 @@ image_set_transform (struct frame *f, struct image *img)
2853 2953
2854 if (0 < rotate_flag) 2954 if (0 < rotate_flag)
2855 { 2955 {
2856# if defined USE_CAIRO || defined HAVE_XRENDER 2956# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_ANDROID
2857 /* 1. Translate so (0, 0) is in the center of the image. */ 2957 /* 1. Translate so (0, 0) is in the center of the image. */
2858 matrix3x3 t 2958 matrix3x3 t
2859 = { [0][0] = 1, 2959 = { [0][0] = 1,
@@ -2904,6 +3004,93 @@ image_set_transform (struct frame *f, struct image *img)
2904 img->height = height; 3004 img->height = height;
2905 } 3005 }
2906# endif 3006# endif
3007#else
3008 /* Calculate the inverse transform from the destination to the
3009 source. The matrix is currently identity with scale
3010 applied.
3011
3012 This code makes more sense to me than what lies above. But
3013 I'm not touching what works. */
3014
3015 if (rotation != 0 && rotation != 90
3016 && rotation != 180 && rotation != 270)
3017 {
3018 rotate_flag = 0;
3019 goto bail;
3020 }
3021
3022 rotate_flag = 1;
3023
3024 switch ((int) rotation + (flip ? 1 : 0))
3025 {
3026 case 0:
3027 break;
3028
3029 case 90:
3030 /* Rotate the image 90 degrees clockwise. IOW, rotate the
3031 destination by 90 degrees counterclockwise, which is 270
3032 degrees clockwise. */
3033 matrix_rotate (matrix, M_PI * 1.5, 0, 0);
3034 matrix_translate (matrix, -height, 0);
3035 break;
3036
3037 case 180:
3038 /* Apply clockwise 180 degree rotation around the
3039 center. */
3040 matrix_rotate (matrix, M_PI, width / 2.0, height / 2.0);
3041 break;
3042
3043 case 270:
3044 /* Apply 270 degree counterclockwise rotation to the
3045 destination, which is 90 degrees clockwise. */
3046 matrix_rotate (matrix, M_PI * 0.5, 0, 0);
3047 matrix_translate (matrix, 0, -width);
3048 break;
3049
3050 case 1:
3051 /* Flipped. Apply horizontal flip. */
3052 matrix_mirror_horizontal (matrix, width);
3053 break;
3054
3055 case 91:
3056 /* Apply a flip but otherwise treat this the same as 90. */
3057 matrix_rotate (matrix, M_PI * 1.5, 0, 0);
3058 matrix_translate (matrix, -height, 0);
3059 matrix_mirror_horizontal (matrix, height);
3060 break;
3061
3062 case 181:
3063 /* Flipped 180 degrees. Apply a flip and treat this the
3064 same as 180. */
3065 matrix_rotate (matrix, M_PI, width / 2.0, height / 2.0);
3066 matrix_mirror_horizontal (matrix, width);
3067 break;
3068
3069 case 271:
3070 /* Flipped 270 degrees. Apply a flip and treat this the
3071 same as 270. */
3072 matrix_rotate (matrix, M_PI * 0.5, 0, 0);
3073 matrix_translate (matrix, 0, -width);
3074 matrix_mirror_horizontal (matrix, height);
3075 break;
3076 }
3077
3078 /* Now set img->width and img->height. Flip them if the
3079 rotation being applied requires so. */
3080
3081 if (rotation != 270 && rotation != 90)
3082 {
3083 img->width = width;
3084 img->height = height;
3085 }
3086 else
3087 {
3088 img->height = width;
3089 img->width = height;
3090 }
3091 bail:
3092 ;
3093#endif
2907 } 3094 }
2908 3095
2909 if (rotate_flag < 0) 3096 if (rotate_flag < 0)
@@ -2968,6 +3155,103 @@ image_set_transform (struct frame *f, struct image *img)
2968 img->transform[0][2] = extra_tx; 3155 img->transform[0][2] = extra_tx;
2969 img->transform[1][2] = extra_ty; 3156 img->transform[1][2] = extra_ty;
2970 } 3157 }
3158# elif defined HAVE_ANDROID
3159 /* Create a new image of the right size, then turn it into a pixmap
3160 and set that as img->pixmap. Destroy img->mask for now (this is
3161 not right.) */
3162
3163 struct android_image *transformed_image, *image;
3164 struct android_transform transform;
3165
3166 /* If there is no transform, simply return. */
3167 if (!memcmp (&matrix, &identity, sizeof matrix))
3168 return;
3169
3170 /* First, get the source image. */
3171 image = image_get_x_image (f, img, false);
3172
3173 /* Make the transformed image. */
3174 transformed_image = android_create_image (image->depth,
3175 ANDROID_Z_PIXMAP,
3176 NULL, img->width,
3177 img->height);
3178
3179 /* Allocate memory for that image. */
3180 transformed_image->data
3181 = xmalloc (transformed_image->bytes_per_line
3182 * transformed_image->height);
3183
3184 /* Do the transform. */
3185 transform.m1 = matrix[0][0];
3186 transform.m2 = matrix[0][1];
3187 transform.m3 = matrix[0][2];
3188 transform.m4 = matrix[1][0];
3189 transform.m5 = matrix[1][1];
3190 transform.m6 = matrix[1][2];
3191
3192 if (image->depth == 24 && smoothing)
3193 android_project_image_bilinear (image, transformed_image,
3194 &transform);
3195 else
3196 android_project_image_nearest (image, transformed_image,
3197 &transform);
3198
3199 image_unget_x_image (img, false, image);
3200
3201 /* Now replace the image. */
3202
3203 if (img->ximg)
3204 image_destroy_x_image (img->ximg);
3205
3206 img->ximg = transformed_image;
3207
3208#ifndef ANDROID_STUBIFY
3209 /* Then replace the pixmap. */
3210 android_free_pixmap (img->pixmap);
3211
3212 /* In case android_create_pixmap signals. */
3213 img->pixmap = ANDROID_NONE;
3214 img->pixmap = android_create_pixmap (img->width, img->height,
3215 transformed_image->depth);
3216 android_put_image (img->pixmap, transformed_image);
3217#else
3218 emacs_abort ();
3219#endif
3220
3221 /* Now, transform the mask. The mask should be depth 1, and is
3222 always transformed using a nearest neighbor filter. */
3223
3224 if (img->mask_img || img->mask)
3225 {
3226 image = image_get_x_image (f, img, true);
3227 transformed_image = android_create_image (1, ANDROID_Z_PIXMAP,
3228 NULL, img->width,
3229 img->height);
3230 transformed_image->data
3231 = xmalloc (transformed_image->bytes_per_line
3232 * transformed_image->height);
3233 android_project_image_nearest (image, transformed_image,
3234 &transform);
3235 image_unget_x_image (img, false, image);
3236
3237 /* Now replace the image. */
3238
3239 if (img->mask_img)
3240 image_destroy_x_image (img->mask_img);
3241
3242 img->mask_img = transformed_image;
3243
3244#ifndef ANDROID_STUBIFY
3245 if (img->mask)
3246 android_free_pixmap (img->mask);
3247
3248 img->mask = ANDROID_NONE;
3249 img->mask = android_create_pixmap (img->width, img->height, 1);
3250 android_put_image (img->mask, transformed_image);
3251#endif
3252 }
3253
3254 /* Done! */
2971#endif 3255#endif
2972} 3256}
2973 3257
@@ -12087,7 +12371,7 @@ The list of capabilities can include one or more of the following:
12087 { 12371 {
12088#ifdef HAVE_NATIVE_TRANSFORMS 12372#ifdef HAVE_NATIVE_TRANSFORMS
12089# if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS) \ 12373# if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS) \
12090 || defined (HAVE_HAIKU) 12374 || defined (HAVE_HAIKU) | defined HAVE_ANDROID
12091 return list2 (Qscale, Qrotate90); 12375 return list2 (Qscale, Qrotate90);
12092# elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER) 12376# elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER)
12093 if (FRAME_DISPLAY_INFO (f)->xrender_supported_p) 12377 if (FRAME_DISPLAY_INFO (f)->xrender_supported_p)
diff --git a/src/keyboard.c b/src/keyboard.c
index 78637ef4f15..306fea354e2 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -339,6 +339,10 @@ static struct timespec timer_last_idleness_start_time;
339static Lisp_Object virtual_core_pointer_name; 339static Lisp_Object virtual_core_pointer_name;
340static Lisp_Object virtual_core_keyboard_name; 340static Lisp_Object virtual_core_keyboard_name;
341 341
342/* If not nil, ID of the last TOUCHSCREEN_END_EVENT to land on the
343 menu bar. */
344static Lisp_Object menu_bar_touch_id;
345
342 346
343/* Global variable declarations. */ 347/* Global variable declarations. */
344 348
@@ -6445,11 +6449,74 @@ make_lispy_event (struct input_event *event)
6445 { 6449 {
6446 Lisp_Object x, y, id, position; 6450 Lisp_Object x, y, id, position;
6447 struct frame *f = XFRAME (event->frame_or_window); 6451 struct frame *f = XFRAME (event->frame_or_window);
6452#if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR
6453 int column, row, dummy;
6454#endif
6448 6455
6449 id = event->arg; 6456 id = event->arg;
6450 x = event->x; 6457 x = event->x;
6451 y = event->y; 6458 y = event->y;
6452 6459
6460#if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR
6461 if (event->kind == TOUCHSCREEN_BEGIN_EVENT
6462 && coords_in_menu_bar_window (f, XFIXNUM (x), XFIXNUM (y)))
6463 {
6464 /* If the tap began in the menu bar window, then save the
6465 id. */
6466 menu_bar_touch_id = id;
6467 return Qnil;
6468 }
6469 else if (event->kind == TOUCHSCREEN_END_EVENT
6470 && EQ (menu_bar_touch_id, id))
6471 {
6472 /* This touch should activate the menu bar. Generate the
6473 menu bar event. */
6474 menu_bar_touch_id = Qnil;
6475
6476 if (f->menu_bar_window)
6477 {
6478 x_y_to_hpos_vpos (XWINDOW (f->menu_bar_window), XFIXNUM (x),
6479 XFIXNUM (y), &column, &row, NULL, NULL,
6480 &dummy);
6481
6482 if (row >= 0 && row < FRAME_MENU_BAR_LINES (f))
6483 {
6484 Lisp_Object items, item;
6485
6486 /* Find the menu bar item under `column'. */
6487 item = Qnil;
6488 items = FRAME_MENU_BAR_ITEMS (f);
6489 for (i = 0; i < ASIZE (items); i += 4)
6490 {
6491 Lisp_Object pos, string;
6492 string = AREF (items, i + 1);
6493 pos = AREF (items, i + 3);
6494 if (NILP (string))
6495 break;
6496 if (column >= XFIXNUM (pos)
6497 && column < XFIXNUM (pos) + SCHARS (string))
6498 {
6499 item = AREF (items, i);
6500 break;
6501 }
6502 }
6503
6504 /* ELisp manual 2.4b says (x y) are window
6505 relative but code says they are
6506 frame-relative. */
6507 position = list4 (event->frame_or_window,
6508 Qmenu_bar,
6509 Fcons (event->x, event->y),
6510 INT_TO_INTEGER (event->timestamp));
6511
6512 return list2 (item, position);
6513 }
6514 }
6515
6516 return Qnil;
6517 }
6518#endif
6519
6453 position = make_lispy_position (f, x, y, event->timestamp); 6520 position = make_lispy_position (f, x, y, event->timestamp);
6454 6521
6455 return list2 (((event->kind 6522 return list2 (((event->kind
@@ -12462,6 +12529,9 @@ syms_of_keyboard (void)
12462 virtual_core_keyboard_name = Qnil; 12529 virtual_core_keyboard_name = Qnil;
12463 staticpro (&virtual_core_keyboard_name); 12530 staticpro (&virtual_core_keyboard_name);
12464 12531
12532 menu_bar_touch_id = Qnil;
12533 staticpro (&menu_bar_touch_id);
12534
12465 defsubr (&Scurrent_idle_time); 12535 defsubr (&Scurrent_idle_time);
12466 defsubr (&Sevent_symbol_parse_modifiers); 12536 defsubr (&Sevent_symbol_parse_modifiers);
12467 defsubr (&Sevent_convert_list); 12537 defsubr (&Sevent_convert_list);
diff --git a/src/sfnt.c b/src/sfnt.c
index 9b6c421212a..09fda82382b 100644
--- a/src/sfnt.c
+++ b/src/sfnt.c
@@ -3436,7 +3436,7 @@ sfnt_compare_edges (const void *a, const void *b)
3436 that now overlap with Y, keeping them sorted by X. Poly those 3436 that now overlap with Y, keeping them sorted by X. Poly those
3437 edges through SPAN_FUNC. Then, move upwards by SFNT_POLY_STEP, 3437 edges through SPAN_FUNC. Then, move upwards by SFNT_POLY_STEP,
3438 remove edges that no longer apply, and interpolate the remaining 3438 remove edges that no longer apply, and interpolate the remaining
3439 edge's X coordinates. Repeat until all the edges have been polyed. 3439 edges' X coordinates. Repeat until all the edges have been polyed.
3440 3440
3441 Or alternatively, think of this as such: each edge is actually a 3441 Or alternatively, think of this as such: each edge is actually a
3442 vector from its bottom position towards its top most position. 3442 vector from its bottom position towards its top most position.
diff --git a/src/sfntfont-android.c b/src/sfntfont-android.c
index 01bfdbaaf58..cddb3fd40f3 100644
--- a/src/sfntfont-android.c
+++ b/src/sfntfont-android.c
@@ -73,48 +73,22 @@ sfntfont_android_mul8x2 (unsigned int a8, unsigned int b32)
73 return (i + ((i >> 8) & 0xff00ff)) >> 8 & 0xff00ff; 73 return (i + ((i >> 8) & 0xff00ff)) >> 8 & 0xff00ff;
74} 74}
75 75
76/* Blend two pixels SRC and DST without utilizing any control flow.
77 SRC must be in premultiplied ARGB8888 format, and DST must be in
78 premultiplied ABGR8888 format. Value is in premultiplied ABGR8888
79 format. */
80
81static unsigned int
82sfntfont_android_blend (unsigned int src, unsigned int dst)
83{
84 unsigned int a, br_part, ag_part, src_rb, both;
85
86 a = (src >> 24);
87 br_part = sfntfont_android_mul8x2 (255 - a, dst);
88 ag_part = sfntfont_android_mul8x2 (255 - a, dst >> 8) << 8;
89
90 both = ag_part | br_part;
91
92 /* Swizzle src. */
93 src_rb = src & 0x00ff00ff;
94 src = src & ~0x00ff00ff;
95 src |= (src_rb >> 16 | src_rb << 16);
96
97 /* This addition need not be saturating because both has already
98 been multiplied by 255 - a. */
99 return both + src;
100}
101
102#define U255TO256(x) ((unsigned short) (x) + ((x) >> 7)) 76#define U255TO256(x) ((unsigned short) (x) + ((x) >> 7))
103 77
104/* Blend two pixels SRC and DST without utilizing any control flow. 78/* Blend two pixels SRC and DST without utilizing any control flow.
105 Both SRC and DST are expected to be in premultiplied ARGB8888 79 Both SRC and DST are expected to be in premultiplied ABGB8888
106 format. Value is returned in premultiplied ARGB8888 format. */ 80 format. Value is returned in premultiplied ARGB8888 format. */
107 81
108static unsigned int 82static unsigned int
109sfntfont_android_blendrgb (unsigned int src, unsigned int dst) 83sfntfont_android_blend (unsigned int src, unsigned int dst)
110{ 84{
111 unsigned int a, rb_part, ag_part, both; 85 unsigned int a, br_part, ag_part, both;
112 86
113 a = (src >> 24); 87 a = (src >> 24);
114 rb_part = sfntfont_android_mul8x2 (255 - a, dst); 88 br_part = sfntfont_android_mul8x2 (255 - a, dst);
115 ag_part = sfntfont_android_mul8x2 (255 - a, dst >> 8) << 8; 89 ag_part = sfntfont_android_mul8x2 (255 - a, dst >> 8) << 8;
116 90
117 both = ag_part | rb_part; 91 both = ag_part | br_part;
118 92
119 /* This addition need not be saturating because both has already 93 /* This addition need not be saturating because both has already
120 been multiplied by 255 - a. */ 94 been multiplied by 255 - a. */
@@ -210,6 +184,7 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from,
210 jobject bitmap; 184 jobject bitmap;
211 int left, top, temp_y; 185 int left, top, temp_y;
212 unsigned int prod, raster_y; 186 unsigned int prod, raster_y;
187 unsigned long foreground, back_pixel, rb;
213 188
214 if (!s->gc->num_clip_rects) 189 if (!s->gc->num_clip_rects)
215 /* Clip region is empty. */ 190 /* Clip region is empty. */
@@ -219,6 +194,17 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from,
219 /* Nothing to draw. */ 194 /* Nothing to draw. */
220 return; 195 return;
221 196
197 /* Swizzle the foreground and background in s->gc into BGR, then add
198 an alpha channel. */
199 foreground = s->gc->foreground;
200 back_pixel = s->gc->background;
201 rb = foreground & 0x00ff00ff;
202 foreground &= ~0x00ff00ff;
203 foreground |= rb >> 16 | rb << 16 | 0xff000000;
204 rb = back_pixel & 0x00ff00ff;
205 back_pixel &= ~0x00ff00ff;
206 back_pixel |= rb >> 16 | rb << 16 | 0xff000000;
207
222 USE_SAFE_ALLOCA; 208 USE_SAFE_ALLOCA;
223 209
224 prepare_face_for_display (s->f, s->face); 210 prepare_face_for_display (s->f, s->face);
@@ -294,7 +280,7 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from,
294 + stride * temp_y); 280 + stride * temp_y);
295 281
296 for (x = background.x; x < background.x + background.width; ++x) 282 for (x = background.x; x < background.x + background.width; ++x)
297 row[x] = s->gc->background | 0xff000000; 283 row[x] = back_pixel;
298 } 284 }
299 } 285 }
300 286
@@ -327,10 +313,9 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from,
327 { 313 {
328 prod 314 prod
329 = sfntfont_android_scale32 (U255TO256 (raster_row[x]), 315 = sfntfont_android_scale32 (U255TO256 (raster_row[x]),
330 (s->gc->foreground 316 foreground);
331 | 0xff000000));
332 row[left + x] 317 row[left + x]
333 = sfntfont_android_blendrgb (prod, row[left + x]); 318 = sfntfont_android_blend (prod, row[left + x]);
334 } 319 }
335 } 320 }
336 } 321 }
diff --git a/src/sfntfont.c b/src/sfntfont.c
index 25cea59f6a7..56977622211 100644
--- a/src/sfntfont.c
+++ b/src/sfntfont.c
@@ -860,7 +860,7 @@ sfntfont_lookup_char (struct sfnt_font_desc *desc, Lisp_Object character,
860 /* Emacs missing charsets? */ 860 /* Emacs missing charsets? */
861 return false; 861 return false;
862 862
863 font_character = ENCODE_CHAR (charset, XFIXNUM (character)); 863 font_character = ENCODE_CHAR (charset, (int) XFIXNUM (character));
864 864
865 if (font_character == CHARSET_INVALID_CODE (charset)) 865 if (font_character == CHARSET_INVALID_CODE (charset))
866 return false; 866 return false;