aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-08-04 14:29:55 +0800
committerPo Lu2023-08-04 14:29:55 +0800
commitbfbdf4eb892935536fc665d6cc986fd669364263 (patch)
treef82fdd0cafacdd9133356f5c264514a726018a18 /src
parent709195fea6a082e3512c14fe16c4f9ea2f99824c (diff)
downloademacs-bfbdf4eb892935536fc665d6cc986fd669364263.tar.gz
emacs-bfbdf4eb892935536fc665d6cc986fd669364263.zip
Optimize creation of multibyte menu items on Android
* src/androidvfs.c (android_verify_jni_string): Move to android.c. * src/android.c (android_verify_jni_string): New function. (android_build_string): Forgo encoding menu text if TEXT is a multibyte string that's also a valid JNI string. * src/android.h: Update prototypes.
Diffstat (limited to 'src')
-rw-r--r--src/android.c81
-rw-r--r--src/android.h1
-rw-r--r--src/androidvfs.c63
3 files changed, 76 insertions, 69 deletions
diff --git a/src/android.c b/src/android.c
index c30d7b58979..bd19107f53a 100644
--- a/src/android.c
+++ b/src/android.c
@@ -5480,6 +5480,69 @@ android_check_string (Lisp_Object text)
5480 return true; 5480 return true;
5481} 5481}
5482 5482
5483/* Verify that the specified NULL-terminated STRING is a valid JNI
5484 ``UTF-8'' string. Return 0 if so, 1 otherwise.
5485
5486 Do not perform GC, enabling NAME to be a direct reference to string
5487 data.
5488
5489 The native coding system used by the JVM to store strings derives
5490 from UTF-8, but deviates from it in two aspects in an attempt to
5491 better represent the UCS-16 based Java String format, and to let
5492 strings contain NULL characters while remaining valid C strings:
5493 NULL bytes are encoded as two-byte sequences, and Unicode surrogate
5494 pairs encoded as two-byte sequences are prefered to four-byte
5495 sequences when encoding characters above the BMP. */
5496
5497int
5498android_verify_jni_string (const char *name)
5499{
5500 const unsigned char *chars;
5501
5502 chars = (unsigned char *) name;
5503 while (*chars)
5504 {
5505 /* Switch on the high 4 bits. */
5506
5507 switch (*chars++ >> 4)
5508 {
5509 case 0 ... 7:
5510 /* The 8th bit is clean, so this is a regular C
5511 character. */
5512 break;
5513
5514 case 8 ... 0xb:
5515 /* Invalid starting byte! */
5516 return 1;
5517
5518 case 0xf:
5519 /* The start of a four byte sequence. These aren't allowed
5520 in Java. */
5521 return 1;
5522
5523 case 0xe:
5524 /* The start of a three byte sequence. Verify that its
5525 continued. */
5526
5527 if ((*chars++ & 0xc0) != 0x80)
5528 return 1;
5529
5530 FALLTHROUGH;
5531
5532 case 0xc ... 0xd:
5533 /* The start of a two byte sequence. Verify that the
5534 next byte exists and has its high bit set. */
5535
5536 if ((*chars++ & 0xc0) != 0x80)
5537 return 1;
5538
5539 break;
5540 }
5541 }
5542
5543 return 0;
5544}
5545
5483/* Given a Lisp string TEXT, return a local reference to an equivalent 5546/* Given a Lisp string TEXT, return a local reference to an equivalent
5484 Java string. */ 5547 Java string. */
5485 5548
@@ -5492,12 +5555,18 @@ android_build_string (Lisp_Object text)
5492 jchar *characters; 5555 jchar *characters;
5493 USE_SAFE_ALLOCA; 5556 USE_SAFE_ALLOCA;
5494 5557
5495 /* Directly encode TEXT if it contains no multibyte 5558 /* Directly encode TEXT if it contains no non-ASCII characters, or
5496 characters. This is okay because the Java extended UTF 5559 is multibyte and a valid Modified UTF-8 string. This is okay
5497 format is compatible with ASCII. */ 5560 because the Java extended UTF format is compatible with
5498 5561 ASCII. */
5499 if (SBYTES (text) == SCHARS (text) 5562
5500 && android_check_string (text)) 5563 if ((SBYTES (text) == SCHARS (text)
5564 && android_check_string (text))
5565 /* If TEXT is a multibyte string, then it's using Emacs's
5566 internal UTF-8 coding system, a significant subset of which
5567 is compatible with JNI. */
5568 || (STRING_MULTIBYTE (text)
5569 && !android_verify_jni_string (SSDATA (text))))
5501 { 5570 {
5502 string = (*android_java_env)->NewStringUTF (android_java_env, 5571 string = (*android_java_env)->NewStringUTF (android_java_env,
5503 SSDATA (text)); 5572 SSDATA (text));
diff --git a/src/android.h b/src/android.h
index cecdfab002f..a052d3a3b21 100644
--- a/src/android.h
+++ b/src/android.h
@@ -105,6 +105,7 @@ extern bool android_detect_mouse (void);
105extern void android_set_dont_focus_on_map (android_window, bool); 105extern void android_set_dont_focus_on_map (android_window, bool);
106extern void android_set_dont_accept_focus (android_window, bool); 106extern void android_set_dont_accept_focus (android_window, bool);
107 107
108extern int android_verify_jni_string (const char *);
108extern jstring android_build_string (Lisp_Object); 109extern jstring android_build_string (Lisp_Object);
109extern jstring android_build_jstring (const char *); 110extern jstring android_build_jstring (const char *);
110extern void android_exception_check (void); 111extern void android_exception_check (void);
diff --git a/src/androidvfs.c b/src/androidvfs.c
index 2b467bc444f..0d99116c75c 100644
--- a/src/androidvfs.c
+++ b/src/androidvfs.c
@@ -3299,9 +3299,6 @@ static struct android_saf_root_vdir *all_saf_root_vdirs;
3299static struct android_vnode *android_saf_tree_from_name (char *, const char *, 3299static struct android_vnode *android_saf_tree_from_name (char *, const char *,
3300 const char *); 3300 const char *);
3301 3301
3302/* Forward declaration. */
3303static int android_verify_jni_string (const char *);
3304
3305/* Ascertain and return whether or not AUTHORITY designates a content 3302/* Ascertain and return whether or not AUTHORITY designates a content
3306 provider offering at least one directory tree accessible to 3303 provider offering at least one directory tree accessible to
3307 Emacs. */ 3304 Emacs. */
@@ -4437,66 +4434,6 @@ static struct android_vops saf_new_vfs_ops;
4437/* Chain of all open SAF directory streams. */ 4434/* Chain of all open SAF directory streams. */
4438static struct android_saf_tree_vdir *all_saf_tree_vdirs; 4435static struct android_saf_tree_vdir *all_saf_tree_vdirs;
4439 4436
4440/* Verify that the specified NULL-terminated STRING is a valid JNI
4441 ``UTF-8'' string. Return 0 if so, 1 otherwise.
4442
4443 The native coding system used by the JVM to store strings derives
4444 from UTF-8, but deviates from it in two aspects in an attempt to
4445 better represent the UCS-16 based Java String format, and to let
4446 strings contain NULL characters while remaining valid C strings:
4447 NULL bytes are encoded as two-byte sequences, and Unicode surrogate
4448 pairs encoded as two-byte sequences are prefered to four-byte
4449 sequences when encoding characters above the BMP. */
4450
4451static int
4452android_verify_jni_string (const char *name)
4453{
4454 const unsigned char *chars;
4455
4456 chars = (unsigned char *) name;
4457 while (*chars)
4458 {
4459 /* Switch on the high 4 bits. */
4460
4461 switch (*chars++ >> 4)
4462 {
4463 case 0 ... 7:
4464 /* The 8th bit is clean, so this is a regular C
4465 character. */
4466 break;
4467
4468 case 8 ... 0xb:
4469 /* Invalid starting byte! */
4470 return 1;
4471
4472 case 0xf:
4473 /* The start of a four byte sequence. These aren't allowed
4474 in Java. */
4475 return 1;
4476
4477 case 0xe:
4478 /* The start of a three byte sequence. Verify that its
4479 continued. */
4480
4481 if ((*chars++ & 0xc0) != 0x80)
4482 return 1;
4483
4484 FALLTHROUGH;
4485
4486 case 0xc ... 0xd:
4487 /* The start of a two byte sequence. Verify that the
4488 next byte exists and has its high bit set. */
4489
4490 if ((*chars++ & 0xc0) != 0x80)
4491 return 1;
4492
4493 break;
4494 }
4495 }
4496
4497 return 0;
4498}
4499
4500/* Find the document ID of the file within TREE_URI designated by 4437/* Find the document ID of the file within TREE_URI designated by
4501 NAME. 4438 NAME.
4502 4439