From b077ab9cacab5e6fa2f644a13ecf8d76297f4875 Mon Sep 17 00:00:00 2001
From: Karl Berry <karl@freefriends.org>
Date: Mon, 8 Jul 2013 22:01:34 +0000
Subject: xecjk (8jul13)

git-svn-id: svn://tug.org/texlive/trunk@31138 c570f23f-e606-0410-a88d-b1316a301751
---
 Master/texmf-dist/tex/xelatex/xecjk/xeCJK.sty | 872 ++++++++++++++++----------
 1 file changed, 545 insertions(+), 327 deletions(-)

(limited to 'Master/texmf-dist/tex/xelatex/xecjk/xeCJK.sty')

diff --git a/Master/texmf-dist/tex/xelatex/xecjk/xeCJK.sty b/Master/texmf-dist/tex/xelatex/xecjk/xeCJK.sty
index 1d1d0fcb2ad..86734bccd7d 100644
--- a/Master/texmf-dist/tex/xelatex/xecjk/xeCJK.sty
+++ b/Master/texmf-dist/tex/xelatex/xecjk/xeCJK.sty
@@ -6,7 +6,7 @@
 %%
 %% xeCJK.dtx  (with options: `package')
 %% 
-%% $Id: xeCJK.dtx 438 2013-06-11 14:17:42Z sobenlee $
+%% $Id: xeCJK.dtx 465 2013-07-06 10:30:24Z sobenlee $
 %% $URL: https://ctex-kit.googlecode.com/svn/trunk/xeCJK/xeCJK.dtx $
 %% -----------------------------------------------------------------
 %%    Author:
@@ -33,11 +33,11 @@
 %% 
 \NeedsTeXFormat{LaTeX2e}
 \RequirePackage{expl3}
-\GetIdInfo$Id: xeCJK.dtx 438 2013-06-11 14:17:42Z sobenlee $
+\GetIdInfo$Id: xeCJK.dtx 465 2013-07-06 10:30:24Z sobenlee $
   {Typesetting CJK scripts with XeLaTeX}
 \ProvidesExplPackage
   {\ExplFileName}
-  {\ExplFileDate}{3.2.3}{\ExplFileDescription}
+  {\ExplFileDate}{3.2.4}{\ExplFileDescription}
 \msg_new:nnn { xeCJK } { Require-XeTeX }
   {
     The~xeCJK~package~requires~XeTeX~to~function.\\\\
@@ -46,6 +46,23 @@
     Loading~xeCJK~will~abort!
   }
 \xetex_if_engine:F { \msg_critical:nn { xeCJK } { Require-XeTeX } }
+\msg_new:nnn { xeCJK } { incompatible-package }
+  {
+    The~`#1'~package~and~xeCJK~are~incompatible.\\\\
+    Please ~ \str_if_eq:nnTF {#1} { CJKnumb }
+      { load~it~after~xeCJK. } { do~not~use~it. }
+  }
+\clist_map_inline:nn { CJKnumb , CJKulem , CJKvert , CJKpunct , CJKutf8 , CJK }
+  {
+    \@ifpackageloaded {#1}
+      { \msg_error:nnn { xeCJK } { incompatible-package } {#1} }
+      { }
+  }
+\tl_gset:cn { ver@CJK.sty } { 9999/99/99 }
+\tl_gset_eq:cc { ver@CJKutf8.sty }  { ver@CJK.sty }
+\tl_gset_eq:cc { ver@CJKvert.sty }  { ver@CJK.sty }
+\tl_gset_eq:cc { ver@CJKulem.sty }  { ver@CJK.sty }
+\tl_gset_eq:cc { ver@CJKpunct.sty } { ver@CJK.sty }
 \msg_new:nnn { xeCJK } { l3-too-old }
   {
     Support~package~`#1'~too~old. \\\\
@@ -60,17 +77,13 @@
 \@ifpackagelater { xtemplate } { 2012/11/10 } { }
   { \msg_error:nnn { xeCJK } { l3-too-old } { xtemplate } }
 \RequirePackage { xparse , l3keys2e }
-\tl_new:N \l__xeCJK_tmpa_tl
-\tl_new:N \l__xeCJK_tmpb_tl
-\int_new:N \l__xeCJK_tmpa_int
-\int_new:N \l__xeCJK_tmpb_int
-\int_new:N \l__xeCJK_tmpc_int
+\tl_new:N \l__xeCJK_tmp_tl
+\int_new:N \l__xeCJK_tmp_int
 \box_new:N \l__xeCJK_tmp_box
 \dim_new:N \l__xeCJK_tmp_dim
+\bool_new:N \l__xeCJK_tmp_bool
 \skip_new:N \l__xeCJK_tmp_skip
-\prop_new:N \l__xeCJK_tmp_prop
-\clist_new:N \l__xeCJK_tmpa_clist
-\clist_new:N \l__xeCJK_tmpb_clist
+\clist_new:N \l__xeCJK_tmp_clist
 \cs_new_protected_nopar:Npn \__xeCJK_msg_new:nn  { \msg_new:nnn      { xeCJK } }
 \cs_new_protected_nopar:Npn \__xeCJK_error:n     { \msg_error:nn     { xeCJK } }
 \cs_new_protected_nopar:Npn \__xeCJK_error:nx    { \msg_error:nnx    { xeCJK } }
@@ -120,15 +133,20 @@
 \cs_new_protected_nopar:Npn \xeCJK_tl_remove_outer_braces:N #1
   { \tl_set:Nx #1 { \exp_args:NV \xeCJK_tl_remove_outer_braces:n #1 } }
 \cs_new:Npn \xeCJK_tl_remove_outer_braces:n #1
-  { \__xeCJK_tl_remove_outer_braces:w #1 \q_stop }
-\cs_new:Npn \__xeCJK_tl_remove_outer_braces:w #1 \q_stop
   {
-    \bool_if:nTF { \tl_if_single_p:n {#1} && \tl_if_head_is_group_p:n {#1} }
-      { \__xeCJK_tl_remove_outer_braces:w #1 \q_stop }
+    \exp_last_unbraced:Nf
+    \__xeCJK_tl_remove_outer_braces:w { \tl_trim_spaces:n {#1} } \s__stop
+  }
+\cs_new:Npn \__xeCJK_tl_remove_outer_braces:w #1 \s__stop
+  {
+    \bool_if:nTF { \tl_if_single_p:n {#1} && ! ( \tl_if_head_is_N_type_p:n {#1} ) }
+      { \xeCJK_tl_remove_outer_braces:n {#1} }
       { \tl_trim_spaces:n {#1} }
   }
-\cs_new_eq:NN \xeCJK_cs_clear:N \tl_clear:N
-\cs_new_eq:NN \xeCJK_cs_gclear:N \tl_gclear:N
+\cs_new_protected:Npn \xeCJK_cs_clear:N #1
+  { \cs_set_eq:NN #1 \prg_do_nothing: }
+\cs_new_protected:Npn \xeCJK_cs_gclear:N #1
+  { \cs_gset_eq:NN #1 \prg_do_nothing: }
 \cs_new_protected:Npn \xeCJK_swap_cs:NN #1#2
   {
     \cs_set_eq:NN \__xeCJK_swap_cs_aux:w #1
@@ -221,6 +239,8 @@
   { \__xeCJK_int_until_do:wn \use_none:n { \reverse_if:N \if_int_compare:w #1#2 } }
 \cs_new_protected:Npn \__xeCJK_int_until_do:wn \use_none:n #1
   { #1 \exp_after:wN \__xeCJK_int_until_do:wn \fi: \use_none:n {#1} }
+\int_new:N \l__xeCJK_begin_int
+\int_new:N \l__xeCJK_end_int
 \cs_new_protected:Npn \xeCJK_peek_catcode_ignore_spaces:NTF #1#2#3
   {
     \cs_set_eq:NN \l__peek_search_token #1 \scan_stop:
@@ -248,6 +268,8 @@
       \fi:
     \fi:
   }
+\tl_new:N \__xeCJK_peek_catcode_true:w
+\tl_new:N \__xeCJK_peek_catcode_false:w
 \bool_new:N \l__xeCJK_peek_ignore_spaces_bool
 \cs_new_protected:Npn \xeCJK_peek_after_ignore_spaces:nw #1
   {
@@ -269,15 +291,22 @@
   { \XeTeXcharclass \xeCJK_token_value_charcode:N #1 }
 \cs_new_nopar:Npn \xeCJK_token_value_charcode:N #1
   { \exp_after:wN \__xeCJK_token_value_charcode:w \token_to_meaning:N #1 \q_stop }
-\str_if_eq_x:nnTF { \token_to_str:N \Umathcode } { \token_to_meaning:N \Umathcode }
+\fp_compare:nNnTF { \int_use:N \xetex_XeTeXversion:D \XeTeXrevision } > { 0.9998 }
   {
-    \cs_new_nopar:Npn \__xeCJK_token_value_charcode:w #1 ~ #2 ~ #3 \q_stop
-      { `#3 }
+    \cs_new_nopar:Npn \__xeCJK_token_value_charcode:w #1 ~ #2 ~ #3#4 \q_stop
+      {
+        \int_eval:n
+          {
+            \tl_if_empty:nTF {#4}
+              { `#3 }
+              { ( `#3 - "D800 ) * "400 + ( `#4 - "DC00 ) + "10000 }
+          }
+      }
     \cs_new_eq:NN \xeCJK_xetex_mathcode:w \Umathcode
   }
   {
     \cs_new_nopar:Npn \__xeCJK_token_value_charcode:w #1 ~ #2 ~ #3#4 \q_stop
-      { \tl_if_empty:nTF {#4} { `#3 } { "20000 } }
+      { \int_eval:n { \tl_if_empty:nTF {#4} { `#3 } { "20000 } } }
     \cs_new_eq:NN \xeCJK_xetex_mathcode:w \XeTeXmathcode
   }
 \prg_new_conditional:Npnn \xeCJK_if_CJK_class:N #1 { p , T , F , TF }
@@ -328,7 +357,7 @@
       }
   }
 \cs_new_nopar:Npn \__xeCJK_class_csname:n #1 { c__xeCJK_#1_class_int }
-\cs_new_eq:cN { \__xeCJK_class_csname:n { Others } } \l__xeCJK_tmpa_int
+\cs_new_eq:cN { \__xeCJK_class_csname:n { Others } } \l__xeCJK_tmp_int
 \__xeCJK_msg_new:nn { class-already-defined }
   {
     XeTeX~character~class~`#1'~has~been~already~defined.\\\\
@@ -355,11 +384,12 @@
     "301D , "FE17 , "FE35 , "FE37 , "FE39 , "FE3B , "FE3D , "FE3F , "FE41 , "FE43 ,
     "FE47 , "FE59 , "FE5B , "FE5D , "FF08 , "FF3B , "FF5B , "FF5F , "FF62
   }
-\clist_const:Nn \c__xeCJK_PO_chars_clist { "FE6A , "FF05 , "FFE0 }
+\clist_const:Nn \c__xeCJK_PR_chars_clist
+  { "20A9 , "FE69 , "FF04 , "FFE1 , "FFE5 , "FFE6 }
 \clist_const:Nx \c__xeCJK_FullLeft_chars_clist
   {
     \c__xeCJK_OP_chars_clist ,
-    \c__xeCJK_PO_chars_clist
+    \c__xeCJK_PR_chars_clist
   }
 \clist_const:Nn \c__xeCJK_CL_chars_clist
   {
@@ -386,8 +416,7 @@
     "31FF , "FF67 , "FF68 , "FF69 , "FF6A , "FF6B , "FF6C , "FF6D , "FF6E , "FF6F ,
     "FF70
   }
-\clist_const:Nn \c__xeCJK_PR_chars_clist
-  { "20A9 , "FE69 , "FF04 , "FFE1 , "FFE5 , "FFE6 }
+\clist_const:Nn \c__xeCJK_PO_chars_clist { "FE6A , "FF05 , "FFE0 }
 \clist_const:Nx \c__xeCJK_FullRight_chars_clist
   {
     \c__xeCJK_CL_chars_clist ,
@@ -395,7 +424,7 @@
     \c__xeCJK_EX_chars_clist ,
     \c__xeCJK_IS_chars_clist ,
     \c__xeCJK_CJ_chars_clist ,
-    \c__xeCJK_PR_chars_clist
+    \c__xeCJK_PO_chars_clist
   }
 \clist_const:Nn \c__xeCJK_CJK_chars_clist
   {
@@ -459,10 +488,10 @@
   }
 \cs_new_protected_nopar:Npn \xeCJK_declare_char_class:nn #1#2
   {
-    \clist_set:Nn \l__xeCJK_tmpa_clist {#2}
+    \clist_set:Nn \l__xeCJK_tmp_clist {#2}
     \clist_gconcat:ccN
-      { g__xeCJK_#1_range_clist } { g__xeCJK_#1_range_clist } \l__xeCJK_tmpa_clist
-    \clist_map_inline:Nn \l__xeCJK_tmpa_clist
+      { g__xeCJK_#1_range_clist } { g__xeCJK_#1_range_clist } \l__xeCJK_tmp_clist
+    \clist_map_inline:Nn \l__xeCJK_tmp_clist
       {
         \str_if_eq:nnF {##1} { -> }
           {
@@ -490,19 +519,19 @@
   }
 \cs_new_protected_nopar:Npn \xeCJK_set_char_class:nnn #1#2#3
   {
-    \__xeCJK_check_num_range:nnNN {#1} {#2} \l__xeCJK_tmpa_int \l__xeCJK_tmpb_int
-    \int_set:Nn \l__xeCJK_tmpc_int {#3}
-    \xeCJK_int_until_do:nn { \l__xeCJK_tmpa_int > \l__xeCJK_tmpb_int }
+    \__xeCJK_check_num_range:nnNN {#1} {#2} \l__xeCJK_begin_int \l__xeCJK_end_int
+    \int_set:Nn \l__xeCJK_tmp_int {#3}
+    \xeCJK_int_until_do:nn { \l__xeCJK_begin_int > \l__xeCJK_end_int }
       {
-        \XeTeXcharclass \l__xeCJK_tmpa_int = \l__xeCJK_tmpc_int
-        \int_incr:N \l__xeCJK_tmpa_int
+        \XeTeXcharclass \l__xeCJK_begin_int = \l__xeCJK_tmp_int
+        \int_incr:N \l__xeCJK_begin_int
       }
   }
 \cs_new_protected_nopar:Npn \__xeCJK_set_char_class_eq:nn #1#2
   {
-    \int_set:Nn \l__xeCJK_tmpa_int { \xeCJK_class_num:n {#2} }
+    \int_set:Nn \l__xeCJK_tmp_int { \xeCJK_class_num:n {#2} }
     \clist_map_inline:cn { c__xeCJK_#1_chars_clist }
-      { \XeTeXcharclass ##1 = \l__xeCJK_tmpa_int }
+      { \XeTeXcharclass ##1 = \l__xeCJK_tmp_int }
   }
 \NewDocumentCommand \normalspacedchars { m }
   {
@@ -545,17 +574,17 @@
 \cs_generate_variant:Nn \xeCJK_app_inter_class_toks:nnn { nnc , nnx }
 \cs_new_protected_nopar:Npn \xeCJK_copy_inter_class_toks:nnnn #1#2#3#4
   {
-    \tl_set:Nx \l__xeCJK_tmpa_tl { \xeCJK_get_inter_class_toks:nn {#3} {#4} }
-    \tl_if_empty:NF \l__xeCJK_tmpa_tl
-      { \xeCJK_inter_class_toks:nnx {#1} {#2} { \exp_not:V \l__xeCJK_tmpa_tl } }
+    \tl_set:Nx \l__xeCJK_tmp_tl { \xeCJK_get_inter_class_toks:nn {#3} {#4} }
+    \tl_if_empty:NF \l__xeCJK_tmp_tl
+      { \xeCJK_inter_class_toks:nnx {#1} {#2} { \exp_not:V \l__xeCJK_tmp_tl } }
   }
 \cs_new_protected_nopar:Npn \xeCJK_replace_inter_class_toks:nnnn #1#2#3#4
   {
-    \tl_set:Nx \l__xeCJK_tmpa_tl { \xeCJK_get_inter_class_toks:nn {#1} {#2} }
-    \tl_if_empty:NF \l__xeCJK_tmpa_tl
+    \tl_set:Nx \l__xeCJK_tmp_tl { \xeCJK_get_inter_class_toks:nn {#1} {#2} }
+    \tl_if_empty:NF \l__xeCJK_tmp_tl
       {
-        \tl_replace_all:Nnn \l__xeCJK_tmpa_tl {#3} {#4}
-        \xeCJK_inter_class_toks:nnx {#1} {#2} { \exp_not:V \l__xeCJK_tmpa_tl }
+        \tl_replace_all:Nnn \l__xeCJK_tmp_tl {#3} {#4}
+        \xeCJK_inter_class_toks:nnx {#1} {#2} { \exp_not:V \l__xeCJK_tmp_tl }
       }
   }
 \cs_new_protected_nopar:Npn \xeCJK_clear_Boundary_and_CJK_toks:
@@ -591,30 +620,39 @@
   }
 \clist_map_inline:nn { Default , HalfLeft , NormalSpace }
   {
-    \xeCJK_inter_class_toks:nnn { Boundary } {#1}
+    \xeCJK_inter_class_toks:nnn { Boundary } {#1} { \xeCJK_Boundary_and_Default: }
+    \str_if_eq:nnF {#1} { NormalSpace }
+      { \xeCJK_app_inter_class_toks:nnn { CJK } {#1} { \CJKecglue } }
+  }
+\cs_new_protected_nopar:Npn \xeCJK_Boundary_and_Default:
+  {
+    \bool_if:nTF
       {
+        \l__xeCJK_xecglue_bool &&
+        \int_compare_p:nNn \etex_lastnodetype:D = \c_eleven &&
+        \skip_if_eq_p:nn \tex_lastskip:D \c_xeCJK_space_skip_tl
+      }
+      {
+        \tex_unskip:D
         \bool_if:nTF
           {
-            \l__xeCJK_xecglue_bool &&
-            \int_compare_p:nNn \etex_lastnodetype:D = \c_eleven &&
-            \skip_if_eq_p:nn \tex_lastskip:D \c_xeCJK_space_skip_tl
+            \xeCJK_if_last_node_p:n { CJK }       ||
+            \xeCJK_if_last_node_p:n { CJK-space }
           }
+          { \xeCJK_remove_node: \CJKecglue } { ~ }
+      }
+      {
+        \bool_if:nTF
           {
-            \tex_unskip:D
-            \bool_if:nTF
-              {
-                \xeCJK_if_last_node_p:n { CJK }       ||
-                \xeCJK_if_last_node_p:n { CJK-space }
-              }
-              { \CJKecglue } { ~ }
+            \xeCJK_if_last_node_p:n { CJK }         ||
+            \xeCJK_if_last_node_p:n { CJK-nobreak }
           }
+          { \xeCJK_remove_node: \CJKecglue }
           {
-            \xeCJK_if_last_node:nTF { CJK } { \CJKecglue }
-              { \xeCJK_if_last_node:nT { CJK-space } { \__xeCJK_space_or_xecglue: } }
+            \xeCJK_if_last_node:nT { CJK-space }
+              { \xeCJK_remove_node: \xeCJK_space_or_xecglue: }
           }
       }
-    \str_if_eq:nnF {#1} { NormalSpace }
-      { \xeCJK_app_inter_class_toks:nnn { CJK } {#1} { \CJKecglue } }
   }
 \clist_map_inline:nn { Default , HalfRight , NormalSpace }
   {
@@ -644,39 +682,47 @@
   {
     \bool_if:nTF
       { \xeCJK_if_last_node_p:n { CJK } || \xeCJK_if_last_node_p:n { CJK-space } }
-      { \CJKglue }
+      { \xeCJK_remove_node: \CJKglue }
       {
-        \bool_if:nTF
-          {
-            \xeCJK_if_last_node_p:n { default }              ||
-            \int_compare_p:nNn \etex_lastnodetype:D = \c_ten
-          }
-          { \CJKecglue }
+        \xeCJK_if_last_node:nTF { CJK-nobreak }
+          { \xeCJK_remove_node: \xeCJK_no_break: \CJKglue }
           {
-            \bool_if:nT
+            \bool_if:nTF
               {
-                \l__xeCJK_xecglue_bool &&
-                \int_compare_p:nNn \etex_lastnodetype:D = \c_eleven &&
-                ( \skip_if_eq_p:nn \tex_lastskip:D \c_xeCJK_space_skip_tl ||
-                  \skip_if_eq_p:nn \tex_lastskip:D \l__xeCJK_ecglue_skip )
+                \xeCJK_if_last_node_p:n { default }              ||
+                \int_compare_p:nNn \etex_lastnodetype:D = \c_ten
               }
+              { \xeCJK_remove_node: \CJKecglue }
               {
-                \tex_unskip:D
-                \bool_if:nTF
+                \bool_if:nT
                   {
-                    \xeCJK_if_last_node_p:n { default-space }        ||
-                    \int_compare_p:nNn \etex_lastnodetype:D = \c_ten ||
-                    \xeCJK_if_last_node_p:n { default }
+                    \l__xeCJK_xecglue_bool &&
+                    \int_compare_p:nNn \etex_lastnodetype:D = \c_eleven &&
+                    ( \skip_if_eq_p:nn \tex_lastskip:D \c_xeCJK_space_skip_tl ||
+                      \skip_if_eq_p:nn \tex_lastskip:D \l__xeCJK_ecglue_skip )
                   }
-                  { \CJKecglue }
                   {
+                    \tex_unskip:D
                     \bool_if:nTF
                       {
-                        \xeCJK_if_last_node_p:n { CJK }       ||
-                        \xeCJK_if_last_node_p:n { CJK-space }
+                        \xeCJK_if_last_node_p:n { default-space }        ||
+                        \int_compare_p:nNn \etex_lastnodetype:D = \c_ten ||
+                        \xeCJK_if_last_node_p:n { default }
+                      }
+                      { \xeCJK_remove_node: \CJKecglue }
+                      {
+                        \bool_if:nTF
+                          {
+                            \xeCJK_if_last_node_p:n { CJK }       ||
+                            \xeCJK_if_last_node_p:n { CJK-space }
+                          }
+                          {
+                            \xeCJK_remove_node:
+                            \bool_if:NTF \l__xeCJK_reserve_space_bool
+                              { ~ } { \CJKglue }
+                          }
+                          { ~ }
                       }
-                      { \bool_if:NTF \l__xeCJK_reserve_space_bool { ~ } { \CJKglue } }
-                      { ~ }
                   }
               }
           }
@@ -698,10 +744,13 @@
     \tex_kern:D - \use:c { c__xeCJK_#1_node_dim }
     \tex_kern:D   \use:c { c__xeCJK_#1_node_dim }
   }
+\cs_new_protected_nopar:Npn \xeCJK_remove_node:
+  { \tex_unkern:D \tex_unkern:D }
 \xeCJK_def_node:nn { CJK }           { 11 sp }
 \xeCJK_def_node:nn { CJK-space }     { 12 sp }
 \xeCJK_def_node:nn { default }       { 13 sp }
 \xeCJK_def_node:nn { default-space } { 14 sp }
+\xeCJK_def_node:nn { CJK-nobreak }   { 15 sp }
 \keys_define:nn { xeCJK / options }
   {
     CJKglue .code:n =
@@ -722,19 +771,19 @@
     xCJKecglue / true    .code:n =
       {
         \bool_set_true:N  \l__xeCJK_xecglue_bool
-        \cs_set_eq:NN \__xeCJK_space_or_xecglue: \CJKecglue
+        \cs_set_eq:NN \xeCJK_space_or_xecglue: \CJKecglue
       } ,
     xCJKecglue / false   .code:n =
       {
         \bool_set_false:N \l__xeCJK_xecglue_bool
-        \cs_set_eq:NN \__xeCJK_space_or_xecglue: \c_space_tl
+        \cs_set_eq:NN \xeCJK_space_or_xecglue: \c_space_tl
       } ,
     xCJKecglue / unknown .code:n =
       {
         \bool_set_true:N  \l__xeCJK_xecglue_bool
         \cs_set_protected_nopar:Npn \CJKecglue {#1}
         \xeCJK_glue_to_skip:nN {#1} \l__xeCJK_ecglue_skip
-        \cs_set_eq:NN \__xeCJK_space_or_xecglue: \CJKecglue
+        \cs_set_eq:NN \xeCJK_space_or_xecglue: \CJKecglue
       } ,
     xCJKecglue        .default:n = { true }
   }
@@ -757,24 +806,26 @@
     \xeCJK_peek_catcode_ignore_spaces:NTF \c_math_toggle_token
       {
         \bool_if:NTF \l__xeCJK_peek_ignore_spaces_bool
-          { \__xeCJK_space_or_xecglue: } { \CJKecglue }
+          { \xeCJK_space_or_xecglue: } { \CJKecglue }
       }
       {
         \bool_if:NTF \l__xeCJK_peek_ignore_spaces_bool
           {
-            \tex_unkern:D \tex_unkern:D
+            \xeCJK_remove_node:
             { \xeCJK_make_node:n { CJK-space } }
             \bool_if:nT
               {
                 \token_if_macro_p:N \l_peek_token ||
                 ( \l__xeCJK_reserve_space_bool &&
-                  \token_if_other_p:N \l_peek_token )
+                  \token_if_letter_p:N \l_peek_token )
               }
-              { \__xeCJK_space_or_xecglue: }
+              { \xeCJK_space_or_xecglue: }
           }
-          { \cs_if_exist:NF \l_peek_token \exp_not:N }
+          { \__xeCJK_CJK_and_Boundary_aux: }
       }
   }
+\cs_new_protected_nopar:Npn \__xeCJK_CJK_and_Boundary_aux:
+  { \cs_if_exist:NF \l_peek_token \exp_not:N }
 \xeCJK_inter_class_toks:nnn { CJK } { CJK } { \xeCJK_CJK_and_CJK:N }
 \cs_new_protected_nopar:Npn \xeCJK_CJK_and_CJK:N #1 { \CJKglue \CJKsymbol {#1} }
 \xeCJK_inter_class_toks:nnn { FullLeft }  { CJK }
@@ -896,11 +947,29 @@
   {
     \int_case:nnn { \etex_lastnodetype:D }
       {
-        { \c_one       } { \__xeCJK_zero_glue: }
-        { \c_minus_one } { }
-        { \c_eleven    } { }
-        { \c_thirteen  } { }
+        { \c_one       } { \__xeCJK_zero_glue: \use_none:n }
+        { \c_minus_one } { \use_none:n }
+        { \c_eleven    }
+        {
+          \bool_if:nF
+            {
+              ! ( \skip_if_finite_p:n { \tex_lastskip:D } ) ||
+              \skip_if_eq_p:nn { \tex_lastskip:D } { 1 sp }
+            }
+        }
+        { \c_thirteen  }
+        {
+          \int_compare:nNnTF \tex_lastpenalty:D = \c_zero
+            {
+              \tex_unpenalty:D
+              \int_compare:nNnTF \etex_lastnodetype:D = \c_one
+                { \tex_penalty:D \c_zero \use_none:n }
+                { \tex_penalty:D \c_zero \use:n }
+            }
+            { \use:n }
+        }
       }
+      { \use:n }
       { \__xeCJK_punct_glue:NN \c__xeCJK_left_tl {#1} }
   }
 \cs_new_protected_nopar:Npn \xeCJK_Default_and_FullRight:nN #1#2
@@ -942,9 +1011,9 @@
     \__xeCJK_punct_if_long:NTF {#1}
       { \CJKglue }
       {
-        \__xeCJK_punct_if_middle:NTF {#1}
-          { \xeCJK_no_break: \__xeCJK_punct_glue:NN \c__xeCJK_right_tl {#1} }
-          { \xeCJK_no_break: \__xeCJK_zero_glue: }
+        \xeCJK_no_break:
+        \__xeCJK_punct_if_middle:NT {#1}
+          {  \__xeCJK_punct_glue:NN \c__xeCJK_right_tl {#1} }
       }
   }
 \cs_new_eq:NN \__xeCJK_Default_and_FullRight_glue:N \__xeCJK_CJK_and_FullRight_glue:N
@@ -971,11 +1040,27 @@
   {
     \xeCJK_get_punct_bounds:NN \c__xeCJK_left_tl {#1}
     \xeCJK_get_punct_kerning:oN \g__xeCJK_last_punct_tl {#1}
-    \__xeCJK_punct_kern:NN \g__xeCJK_last_punct_tl {#1}
+    \xeCJK_punct_kern:NN \g__xeCJK_last_punct_tl {#1}
     \tl_gset:Nx \g__xeCJK_last_punct_tl {#1}
-    \__xeCJK_punct_break:
     \CJKpunctsymbol {#1}
   }
+\cs_new_protected_nopar:Npn \__xeCJK_punct_nobreak_kern:NN #1#2
+  {
+    \__xeCJK_punct_kern:NN #1#2
+    \xeCJK_no_break:
+  }
+\cs_new_eq:NN \xeCJK_punct_kern:NN \__xeCJK_punct_nobreak_kern:NN
+\cs_new_protected_nopar:Npn \__xeCJK_punct_breakable_kern:NN #1#2
+  {
+    \__xeCJK_punct_rule:NN \c__xeCJK_right_tl #1
+    \__xeCJK_punct_hskip:n
+      {
+        \__xeCJK_use_punct_dim:nnn { kern } {#1} {#2} +
+        \__xeCJK_use_punct_dim:nnn { bound } { \c__xeCJK_right_tl } {#1} +
+        \__xeCJK_use_punct_dim:nnn { bound } { \c__xeCJK_left_tl }  {#2}
+      }
+    \__xeCJK_punct_rule:NN \c__xeCJK_left_tl #2
+  }
 \cs_new_protected_nopar:Npn \xeCJK_FullRight_and_FullRight:N #1
   {
     \xeCJK_get_punct_bounds:NN \c__xeCJK_right_tl {#1}
@@ -1054,20 +1139,19 @@
   \l__xeCJK_no_break_cs_case_tl \l__xeCJK_no_break_cs_seq { \xeCJK_no_break: } { }
 \NewDocumentCommand \xeCJKnobreak { }
   {
-    \int_zero:N \l__xeCJK_tmpa_int
+    \bool_set_true:N \l__xeCJK_tmp_bool
     \int_while_do:nNnn \etex_lastnodetype:D = \c_eleven
       {
-        \int_if_even:nTF \l__xeCJK_tmpa_int
+        \bool_if:NTF \l__xeCJK_tmp_bool
           {
-            \int_incr:N \l__xeCJK_tmpa_int
+            \bool_set_false:N \l__xeCJK_tmp_bool
             \skip_set_eq:NN \l__xeCJK_tmp_skip \tex_lastskip:D
           }
           { \skip_add:Nn \l__xeCJK_tmp_skip \tex_lastskip:D }
         \tex_unskip:D
       }
     \xeCJK_no_break:
-    \int_if_even:nF \l__xeCJK_tmpa_int
-      { \skip_horizontal:N \l__xeCJK_tmp_skip }
+    \bool_if:NF \l__xeCJK_tmp_bool { \skip_horizontal:N \l__xeCJK_tmp_skip }
   }
 \keys_define:nn { xeCJK / options }
   {
@@ -1169,7 +1253,7 @@
     \peek_catcode:NTF \c_math_toggle_token
       {
         \xeCJK_no_break: \__xeCJK_check_single_save:N #1
-        \xeCJK_no_break: #2 #4
+        \xeCJK_make_node:n { CJK-nobreak } #2 #4
       }
       { \__xeCJK_check_single_save:N #1 #2#3#4 }
   }
@@ -1182,7 +1266,7 @@
       { \xeCJK_check_single_env:nnNn }
       {
         \xeCJK_no_break: \__xeCJK_check_single_save:N #1
-        \xeCJK_no_break: #2
+        \xeCJK_make_node:n { CJK-nobreak } #2
       }
       { \__xeCJK_check_single_save:N #1 #2#3 }
   }
@@ -1359,9 +1443,15 @@
   {
     AllowBreakBetweenPuncts .choice: ,
     AllowBreakBetweenPuncts / true  .code:n =
-      { \cs_set_eq:NN \__xeCJK_punct_break: \xeCJK_allow_break: } ,
+      {
+        \bool_set_true:N \l__xeCJK_punct_breakable_bool
+        \cs_set_eq:NN \xeCJK_punct_kern:NN \__xeCJK_punct_breakable_kern:NN
+      } ,
     AllowBreakBetweenPuncts / false .code:n =
-      { \cs_set_eq:NN \__xeCJK_punct_break: \xeCJK_no_break: } ,
+      {
+        \bool_set_false:N \l__xeCJK_punct_breakable_bool
+        \cs_set_eq:NN \xeCJK_punct_kern:NN \__xeCJK_punct_nobreak_kern:NN
+      } ,
     AllowBreakBetweenPuncts      .default:n = { true } ,
     KaiMingPunct  .code:n = { \__xeCJK_set_special_punct:nn { mixed_width } {#1} } ,
     KaiMingPunct+ .code:n = { \__xeCJK_add_special_punct:nn { mixed_width } {#1} } ,
@@ -1374,6 +1464,7 @@
     MiddlePunct-  .code:n = { \__xeCJK_sub_special_punct:nn { middle } {#1} } ,
     PunctWidth .tl_gset:N = \g__xeCJK_punct_width_tl
   }
+\bool_new:N \l__xeCJK_punct_breakable_bool
 \clist_new:N \g__xeCJK_special_punct_clist
 \clist_gset:Nn \g__xeCJK_special_punct_clist { mixed_width , long , middle }
 \cs_new_nopar:Npn \__xeCJK_special_punct_seq:n #1 { g__xeCJK_special_punct_#1_seq }
@@ -1425,21 +1516,19 @@
       }
   }
 \cs_new_nopar:Npn \__xeCJK_punct_dim_csname:nn #1#2
-  { g__\l_xeCJK_current_font_tl/\l_xeCJK_punct_style_tl/#1/#2/tl }
+  { c__\l_xeCJK_current_font_tl/\l_xeCJK_punct_style_tl/#1/#2/tl }
 \cs_new_nopar:Npn \__xeCJK_punct_dim_csname:nnn
   { \__xeCJK_punct_dim_csname:nnnn { \l_xeCJK_punct_style_tl } }
 \cs_new_nopar:Npn \__xeCJK_punct_dim_csname:nnnn #1#2#3#4
-  { g__\l_xeCJK_current_font_tl/#1/#2/#3/#4/tl }
+  { c__\l_xeCJK_current_font_tl/#1/#2/#3/#4/tl }
 \cs_new_nopar:Npn \__xeCJK_use_punct_dim:nn #1#2
   { \tl_use:c { \__xeCJK_punct_dim_csname:nn {#1} {#2} } }
 \cs_new_nopar:Npn \__xeCJK_use_punct_dim:nnn #1#2#3
   { \tl_use:c { \__xeCJK_punct_dim_csname:nnn {#1} {#2} {#3} } }
 \cs_new_protected_nopar:Npn \__xeCJK_gset_punct_dim:nnx #1#2#3
-  { \tl_gset:cx { \__xeCJK_punct_dim_csname:nn {#1} {#2} } {#3} }
+  { \tl_const:cx { \__xeCJK_punct_dim_csname:nn {#1} {#2} } {#3} }
 \cs_new_protected_nopar:Npn \__xeCJK_gset_punct_dim:nnnx #1#2#3#4
-  { \tl_gset:cx { \__xeCJK_punct_dim_csname:nnn {#1} {#2} {#3} } {#4} }
-\cs_new_protected_nopar:Npn \__xeCJK_gset_punct_dim:nnnnx #1#2#3#4#5
-  { \tl_gset:cx { \__xeCJK_punct_dim_csname:nnnn {#1} {#2} {#3} {#4} } {#5} }
+  { \tl_const:cx { \__xeCJK_punct_dim_csname:nnn {#1} {#2} {#3} } {#4} }
 \DeclareObjectType { xeCJK / punctuation } { \c_three }
 \DeclareTemplateInterface { xeCJK / punctuation } { basic } { \c_three }
   {
@@ -1511,8 +1600,8 @@
   }
 \cs_new_protected_nopar:Npn \xeCJK_punct_margin_process:NN #1#2
   {
-    \tl_set:Nx \l__xeCJK_tmpa_tl { \__xeCJK_use_punct_dim:nnn { bound } {#1} {#2} }
-    \tl_set:Nx \l__xeCJK_tmpb_tl
+    \dim_set:Nn \l__xeCJK_bound_dim { \__xeCJK_use_punct_dim:nnn { bound } {#1} {#2} }
+    \dim_set:Nn \l__xeCJK_reverse_bound_dim
       {
         \__xeCJK_use_punct_dim:nnn { bound }
           { \xeCJK_reverse:nnn {#1} \c__xeCJK_left_tl \c__xeCJK_right_tl } {#2}
@@ -1555,17 +1644,20 @@
                   }
                   {
                     \bool_if:NTF \l__xeCJK_optimize_margin_bool
-                      { \dim_max:nn { \dim_min:nn \l__xeCJK_tmpa_tl \l__xeCJK_tmpb_tl } }
+                      {
+                        \dim_max:nn
+                          { \dim_min:nn \l__xeCJK_bound_dim \l__xeCJK_reverse_bound_dim }
+                      }
                       { \use:n }
                       {
-                        \l__xeCJK_tmp_dim - ( \l__xeCJK_tmpb_tl )
+                        \l__xeCJK_tmp_dim - \l__xeCJK_reverse_bound_dim
                         - ( \__xeCJK_use_punct_dim:nn { dimen } {#2} )
                       }
                   }
               }
               {
                 \bool_if:NTF \l__xeCJK_optimize_margin_bool
-                  { \dim_min:nn { \l__xeCJK_tmpa_tl } }
+                  { \dim_min:nn { \l__xeCJK_bound_dim } }
                   { \use:n }
                   {
                     \__xeCJK_punct_if_middle:NTF {#2}
@@ -1575,7 +1667,7 @@
                           {
                             \fp_use:N \l__xeCJK_middle_margin_ratio_fp
                             \etex_dimexpr:D
-                              ( \l__xeCJK_tmpa_tl + \l__xeCJK_tmpb_tl ) / \c_two
+                              ( \l__xeCJK_bound_dim + \l__xeCJK_reverse_bound_dim ) / \c_two
                             \scan_stop:
                           }
                       }
@@ -1589,6 +1681,8 @@
           }
       }
   }
+\dim_new:N \l__xeCJK_bound_dim
+\dim_new:N \l__xeCJK_reverse_bound_dim
 \cs_new_nopar:Npn \__xeCJK_punct_width_or_ratio:nN #1#2
   {
     \dim_compare:nNnTF { \use:c { l__xeCJK_#1_punct_width_dim } } < \c_max_dim
@@ -1608,10 +1702,10 @@
       { \use:c { l__xeCJK_#1_margin_width_dim } }
       {
         \fp_use:c { l__xeCJK_#1_margin_ratio_fp }
-        \etex_dimexpr:D \l__xeCJK_tmpa_tl \scan_stop:
+        \etex_dimexpr:D \l__xeCJK_bound_dim \scan_stop:
       }
     \bool_if:NT \l__xeCJK_add_min_bound_to_margin_bool
-      { + \dim_min:nn \l__xeCJK_tmpa_tl \l__xeCJK_tmpb_tl }
+      { + \dim_min:nn \l__xeCJK_bound_dim \l__xeCJK_reverse_bound_dim }
   }
 \cs_new_protected_nopar:Npn \xeCJK_punct_kerning_process:NN #1#2
   {
@@ -1767,18 +1861,15 @@
       { \dim_eval:n { \__xeCJK_use_punct_dim:nn { width } {#1} - \l__xeCJK_tmp_dim } }
     \__xeCJK_punct_if_long:NT {#1}
       {
-        \seq_map_inline:Nn \g__xeCJK_punct_style_seq
+        \__xeCJK_gset_punct_dim:nnnx { kern } {#1} {#1}
           {
-            \__xeCJK_gset_punct_dim:nnnnx {##1} { kern } {#1} {#1}
+            \bool_if:nTF
               {
-                \bool_if:nTF
-                  {
-                    \str_if_eq_p:nn {#1} { ^^^^2025 } ||
-                    \str_if_eq_p:nn {#1} { ^^^^2026 }
-                  }
-                  { \c_zero_dim }
-                  { - \dim_use:N \l__xeCJK_tmp_dim }
+                \str_if_eq_p:nn {#1} { ^^^^2025 } ||
+                \str_if_eq_p:nn {#1} { ^^^^2026 }
               }
+              { \c_zero_dim }
+              { - \dim_use:N \l__xeCJK_tmp_dim }
           }
       }
   }
@@ -1818,6 +1909,7 @@
           { \__xeCJK_error:nx { punct-style-unknown } { \l_keys_value_tl } }
       }
   }
+\tl_new:N \l_xeCJK_punct_style_tl
 \tl_const:Nn \c__xeCJK_punct_style_plain_tl { plain }
 \__xeCJK_msg_new:nn { punct-style-unknown }
   {
@@ -1893,58 +1985,65 @@
   {
     \xeCJK_glyph_if_exist:NTF {#1}
       { \__xeCJK_fallback_save_CJKsymbol:N {#1} }
-      { { \xeCJK_fallback_loop:Nn {#1} { \l_xeCJK_family_tl/FallBack } } }
+      {
+        \xeCJK_class_group_begin:
+        \tl_set_eq:NN \l__xeCJK_fallback_family_tl \l_xeCJK_family_tl
+        \xeCJK_fallback_loop:Nn {#1} { \l__xeCJK_fallback_family_tl/FallBack }
+        \xeCJK_class_group_end:
+      }
   }
 \cs_new_protected_nopar:Npn \xeCJK_fallback_loop:Nn #1#2
   {
     \xeCJK_family_if_exist:xTF {#2}
       {
         \xeCJK_select_font:x {#2}
+        \tl_set:Nx \l__xeCJK_fallback_family_tl {#2}
         \xeCJK_glyph_if_exist:NTF {#1}
           { \__xeCJK_fallback_save_CJKsymbol:N {#1} }
-          { \xeCJK_fallback_loop:Nn {#1} { #2/FallBack } }
+          { \xeCJK_fallback_loop:Nn {#1} { \l__xeCJK_fallback_family_tl/FallBack } }
       }
       {
-        \xeCJK_family_if_exist:xT { \l_xeCJK_family_tl/FallBack }
-          { \__xeCJK_warning:nxx { fallback } {#1} {#2} }
-        \__xeCJK_fallback_save_CJKsymbol:N {#1}
+        \str_if_eq_x:nnTF { \CJKfamilydefault } { \l_xeCJK_family_tl }
+          {
+            \use:x
+              {
+                \msg_warning:nnnnn { xeCJK } { missing-glyph }
+                  { \l__xeCJK_fallback_family_tl } {#1} { \int_to_hexadecimal:n { `#1 } }
+              }
+            \__xeCJK_fallback_save_CJKsymbol:N {#1}
+          }
+          {
+            \tl_set:Nx \l_xeCJK_family_tl { \CJKfamilydefault }
+            \xeCJK_fallback_loop:Nn {#1} { \l_xeCJK_family_tl }
+          }
       }
   }
-\__xeCJK_msg_new:nn { fallback }
+\__xeCJK_msg_new:nn { missing-glyph }
   {
-    CJKfamily~`#2'~
-    ( \prop_get:No \g__xeCJK_family_font_name_prop {#2} )~
-    does~not~contain~glyph~`#1'~(U+\int_to_hexadecimal:n {`#1}).\\
+    CJKfamily~`\__xeCJK_msg_family_map:n {#1}'~
+    ( \prop_get:Nn \g__xeCJK_family_font_name_prop {#1} )~
+    does~not~contain~glyph~`#2'~(U+#3).\\
   }
-\bool_new:N \l__xeCJK_fallback_first_bool
-\cs_generate_variant:Nn \prop_get:Nn { No }
-\NewDocumentCommand \setCJKfallbackfamilyfont { m O{} m }
-  {
-    \clist_set:Nx \l__xeCJK_tmpa_clist {#3}
-    \int_compare:nNnTF { \clist_count:N \l__xeCJK_tmpa_clist } > \c_one
-      { \xeCJK_set_family_fallback:xxN {#1} {#2} \l__xeCJK_tmpa_clist }
-      { \xeCJK_set_family:xxx { #1/FallBack } {#2} {#3} }
-  }
-\cs_new_protected_nopar:Npn \xeCJK_set_family_fallback:nnN #1#2#3
+\NewDocumentCommand \setCJKfallbackfamilyfont { m O { } m }
+  { \use:x { \xeCJK_set_family_fallback:nnn {#1} {#2} {#3} } }
+\cs_new_protected_nopar:Npn \xeCJK_set_family_fallback:nnn #1#2#3
   {
     \group_begin:
     \tl_set:Nn \l__xeCJK_fallback_family_tl {#1}
     \prop_get:NVNF \g__xeCJK_family_font_name_prop
       \l__xeCJK_fallback_family_tl \l__xeCJK_font_name_tl
       { \tl_clear:N \l__xeCJK_font_name_tl }
-    \clist_map_inline:Nn #3
+    \clist_map_inline:nn {#3}
       {
         \tl_put_right:Nn \l__xeCJK_fallback_family_tl { /FallBack }
         \__xeCJK_get_sub_features:Vn \l__xeCJK_fallback_family_tl {##1}
-        \clist_put_left:cn
-          { l__xeCJK_ \l__xeCJK_fallback_family_tl _font_options_clist } {#2}
-        \xeCJK_set_family:Vvv \l__xeCJK_fallback_family_tl
-          { l__xeCJK_ \l__xeCJK_fallback_family_tl _font_options_clist }
-          { l__xeCJK_ \l__xeCJK_fallback_family_tl _font_name_tl }
+        \clist_put_left:Nn \l__xeCJK_sub_font_options_clist {#2}
+        \xeCJK_set_family:VVV \l__xeCJK_fallback_family_tl
+          \l__xeCJK_sub_font_options_clist \l__xeCJK_sub_font_name_tl
       }
     \group_end:
   }
-\cs_generate_variant:Nn \xeCJK_set_family_fallback:nnN { xx }
+\tl_new:N \l__xeCJK_fallback_family_tl
 \bool_new:N \g__xeCJK_auto_fake_bold_bool
 \bool_new:N \g__xeCJK_auto_fake_slant_bool
 \fp_new:N \g__xeCJK_embolden_factor_fp
@@ -1984,22 +2083,14 @@
           {
             \tl_if_blank:nTF {##1}
               {
-                \bool_set_false:c { l__xeCJK_copy_#1_bool }
-                \bool_set_false:c { l__xeCJK_add_#1_bool }
+                \prop_clear:N \l__xeCJK_sub_key_prop
                 \tl_put_right:Nn \l__xeCJK_family_name_tl { /#1 }
+                \clist_remove_all:Nn \l__xeCJK_font_options_clist {#1}
               }
               {
-                \seq_put_right:Nn \l__xeCJK_sub_key_seq {#1}
                 \str_if_eq:nnTF {##1} { * }
-                  {
-                    \bool_set_true:c  { l__xeCJK_copy_#1_bool }
-                    \bool_set_false:c { l__xeCJK_add_#1_bool }
-                  }
-                  {
-                    \bool_set_false:c { l__xeCJK_copy_#1_bool }
-                    \bool_set_true:c  { l__xeCJK_add_#1_bool }
-                    \__xeCJK_get_sub_features:nn {#1} {##1}
-                  }
+                  { \prop_put:Nnn \l__xeCJK_sub_key_prop {#1} { \q_no_value } }
+                  { \__xeCJK_get_sub_features:nn {#1} {##1} }
               }
           } ,
         #1 .default:n = { }
@@ -2007,33 +2098,35 @@
   }
 \cs_new_protected_nopar:Npn \__xeCJK_get_sub_features:nn #1#2
   {
-    \tl_set:Nx \l__xeCJK_tmpa_tl { \xeCJK_tl_remove_outer_braces:n {#2} }
+    \tl_set:Nx \l__xeCJK_tmp_tl { \xeCJK_tl_remove_outer_braces:n {#2} }
     \clist_clear:N \l__xeCJK_sub_font_options_clist
-    \tl_if_head_eq_meaning:VNTF \l__xeCJK_tmpa_tl [ % ]
-      {
-        \exp_after:wN \__xeCJK_get_sub_features:wn \l__xeCJK_tmpa_tl \c_empty_tl
-        \tl_if_blank:VT \l__xeCJK_sub_font_name_tl
-          {
-            \tl_set_eq:NN \l__xeCJK_sub_font_name_tl \l__xeCJK_tmpa_tl
-            \clist_clear:N \l__xeCJK_sub_font_options_clist
-          }
-      }
-      { \tl_set_eq:NN \l__xeCJK_sub_font_name_tl \l__xeCJK_tmpa_tl }
-    \tl_if_blank:VTF \l__xeCJK_sub_font_name_tl
+    \exp_after:wN \__xeCJK_get_sub_features:w \l__xeCJK_tmp_tl
+      \q_mark [ \q_nil ] \q_mark \q_stop
+    \tl_if_empty:NTF \l__xeCJK_sub_font_name_tl
       { \tl_set_eq:NN \l__xeCJK_sub_font_name_tl \l__xeCJK_font_name_tl }
       { \tl_replace_all:NnV \l__xeCJK_sub_font_name_tl { * } \l__xeCJK_font_name_tl }
-    \clist_set_eq:cN { l__xeCJK_#1_font_options_clist } \l__xeCJK_sub_font_options_clist
-    \tl_set_eq:cN { l__xeCJK_#1_font_name_tl } \l__xeCJK_sub_font_name_tl
+    \prop_put:Nnx \l__xeCJK_sub_key_prop {#1}
+      {
+        { \exp_not:V \l__xeCJK_sub_font_options_clist }
+        { \exp_not:V \l__xeCJK_sub_font_name_tl }
+      }
   }
-\cs_new_protected_nopar:Npn \__xeCJK_get_sub_features:wn [#1] #2
+\cs_new_protected_nopar:Npn \__xeCJK_get_sub_features:w #1 [#2] #3 \q_mark #4 \q_stop
   {
-    \clist_set:Nn \l__xeCJK_sub_font_options_clist {#1}
-    \str_if_eq:nnTF {#2} { \c_empty_tl }
-      { \tl_set_eq:NN \l__xeCJK_sub_font_name_tl \c_empty_tl }
-      { \tl_set:Nn \l__xeCJK_sub_font_name_tl {#2} }
+    \quark_if_nil:nTF {#2}
+      { \tl_set_eq:NN \l__xeCJK_sub_font_name_tl \l__xeCJK_tmp_tl }
+      {
+        \tl_set:Nx \l__xeCJK_sub_font_name_tl
+          { \xeCJK_tl_remove_outer_braces:n {#3} }
+        \tl_if_empty:NTF \l__xeCJK_sub_font_name_tl
+          { \tl_set_eq:NN \l__xeCJK_sub_font_name_tl \l__xeCJK_tmp_tl }
+          { \clist_set:Nn \l__xeCJK_sub_font_options_clist {#2} }
+      }
   }
+\tl_new:N \l__xeCJK_sub_family_name_tl
+\tl_new:N \l__xeCJK_sub_font_name_tl
+\clist_new:N \l__xeCJK_sub_font_options_clist
 \cs_generate_variant:Nn \__xeCJK_get_sub_features:nn { V }
-\cs_generate_variant:Nn \tl_if_head_eq_meaning:nNTF { V }
 \cs_generate_variant:Nn \tl_replace_all:Nnn { NnV }
 \xeCJK_new_sub_key:n { FallBack }
 \prop_new:N \g__xeCJK_features_id_prop
@@ -2075,24 +2168,26 @@
   {
     \int_gincr:N \g__xeCJK_family_int
     \prop_clear:N \l__xeCJK_add_font_prop
+    \prop_clear:N \l__xeCJK_sub_key_prop
     \prop_map_inline:Nn \g__xeCJK_features_id_prop
       {
         \tl_clear:c { l__xeCJK_font_name_##1_tl }
         \clist_clear:c { l__xeCJK_font_feat_##1_clist }
       }
     \clist_clear:N \l__xeCJK_fontspec_options_clist
-    \seq_clear:N \l__xeCJK_sub_key_seq
-    \seq_map_inline:Nn \g__xeCJK_sub_key_seq
-      {
-        \bool_set_false:c { l__xeCJK_copy_##1_bool }
-        \bool_set_false:c { l__xeCJK_add_##1_bool  }
-      }
     \bool_set_eq:NN \l__xeCJK_auto_fake_bold_bool   \g__xeCJK_auto_fake_bold_bool
     \bool_set_eq:NN \l__xeCJK_auto_fake_slant_bool  \g__xeCJK_auto_fake_slant_bool
     \fp_set_eq:NN \l__xeCJK_embolden_factor_fp \g__xeCJK_embolden_factor_fp
     \fp_set_eq:NN \l__xeCJK_slant_factor_fp    \g__xeCJK_slant_factor_fp
   }
 \int_new:N \g__xeCJK_family_int
+\prop_new:N \l__xeCJK_add_font_prop
+\prop_new:N \l__xeCJK_sub_key_prop
+\clist_new:N \l__xeCJK_fontspec_options_clist
+\bool_new:N \l__xeCJK_auto_fake_bold_bool
+\bool_new:N \l__xeCJK_auto_fake_slant_bool
+\fp_new:N \l__xeCJK_embolden_factor_fp
+\fp_new:N \l__xeCJK_slant_factor_fp
 \cs_new_protected_nopar:Npn \xeCJK_set_family:nnn #1#2#3
   {
     \group_begin:
@@ -2100,11 +2195,11 @@
     \tl_set:Nn \l__xeCJK_family_name_tl {#1}
     \clist_set:Nn \l__xeCJK_font_options_clist {#2}
     \tl_set:Nn \l__xeCJK_font_name_tl {#3}
-    \clist_concat:NNN \l__xeCJK_font_features_clist
+    \clist_concat:NNN \l__xeCJK_font_options_clist
       \g__xeCJK_default_features_clist \l__xeCJK_font_options_clist
-    \__xeCJK_remove_duplicate_keys:N \l__xeCJK_font_features_clist
+    \__xeCJK_remove_duplicate_keys:N \l__xeCJK_font_options_clist
     \keys_set_known:nVN { xeCJK / features }
-      \l__xeCJK_font_features_clist \l__xeCJK_fontspec_options_clist
+      \l__xeCJK_font_options_clist \l__xeCJK_fontspec_options_clist
     \__xeCJK_parse_features:
     \__xeCJK_pass_features:
     \__xeCJK_check_family:V \l__xeCJK_family_name_tl
@@ -2113,24 +2208,34 @@
     \__xeCJK_set_sub_block_family:
     \group_end:
   }
-\cs_generate_variant:Nn \xeCJK_set_family:nnn { Vnn , xxx , Vvv }
+\tl_new:N \l__xeCJK_family_name_tl
+\tl_new:N \l__xeCJK_font_name_tl
+\clist_new:N \l__xeCJK_font_options_clist
+\cs_generate_variant:Nn \xeCJK_set_family:nnn { Vnn , VVV , Voo }
+\cs_new_protected_nopar:Npn \xeCJK_set_family:xxx #1#2#3
+  { \use:x { \xeCJK_set_family:nnn {#1} {#2} {#3} } }
 \cs_new_protected_nopar:Npn \__xeCJK_remove_duplicate_keys:N #1
   {
-    \prop_clear:N \l__xeCJK_tmp_prop
+    \prop_clear:N \l__xeCJK_font_options_prop
     \keyval_parse:NNV \__xeCJK_prop_put_aux:n \__xeCJK_prop_put_aux:nn #1
     \clist_clear:N #1
-    \prop_map_inline:Nn \l__xeCJK_tmp_prop
+    \prop_map_inline:Nn \l__xeCJK_font_options_prop
       {
-        \tl_if_blank:nTF {##2}
-          { \clist_put_right:Nn #1 {##1} }
-          { \clist_put_right:Nn #1 { ##1 = {##2} } }
+        \tl_set:No \l__xeCJK_tmp_tl { \use_ii:nn ##2 }
+        \tl_if_blank:VTF \l__xeCJK_tmp_tl
+          { \clist_put_right:No #1 { \use_i:nn ##2 } }
+          {
+            \clist_put_right:Nx #1
+              { \exp_not:o { \use_i:nn ##2 } = { \exp_not:V \l__xeCJK_tmp_tl } }
+          }
       }
   }
+\prop_new:N \l__xeCJK_font_options_prop
 \cs_generate_variant:Nn \keyval_parse:NNn { NNV }
 \cs_new_protected_nopar:Npn \__xeCJK_prop_put_aux:n #1
-  { \prop_put:Nnn \l__xeCJK_tmp_prop {#1} { } }
+  { \prop_put:Nnn \l__xeCJK_font_options_prop {#1} { {#1} {  } } }
 \cs_new_protected_nopar:Npn \__xeCJK_prop_put_aux:nn #1#2
-  { \prop_put:Nnn \l__xeCJK_tmp_prop {#1} {#2} }
+  { \prop_put:Nnn \l__xeCJK_font_options_prop {#1} { {#1} {#2} } }
 \cs_new_protected_nopar:Npn \__xeCJK_gset_family_cs:x #1
   {
     \cs_gset_protected_nopar:cpx { \__xeCJK_family_csname:n {#1} }
@@ -2144,13 +2249,14 @@
         \group_end:
       }
   }
+\tl_new:N \l__xeCJK_fontspec_family_tl
 \cs_new_protected_nopar:Npn \__xeCJK_check_family:n #1
   {
-    \prop_get:NnNT \g__xeCJK_family_font_name_prop {#1} \l__xeCJK_tmpa_tl
+    \prop_get:NnNT \g__xeCJK_family_font_name_prop {#1} \l__xeCJK_tmp_tl
       {
-        \prop_gpop:NnNT \g__xeCJK_family_name_prop {#1} \l__xeCJK_tmpa_tl
+        \prop_gpop:NnNT \g__xeCJK_family_name_prop {#1} \l__xeCJK_tmp_tl
           { \cs_undefine:c { \__xeCJK_family_nfss_csname:n {#1} } }
-        \__xeCJK_warning:nxx { CJKfamily-redef } {#1} { \l__xeCJK_tmpa_tl }
+        \__xeCJK_warning:nxx { CJKfamily-redef } {#1} { \l__xeCJK_tmp_tl }
       }
   }
 \cs_generate_variant:Nn \__xeCJK_check_family:n { V }
@@ -2269,8 +2375,6 @@
 \cs_new_protected_nopar:Npn \__xeCJK_save_family_info:
   {
     \group_begin:
-    \seq_map_inline:Nn \g__xeCJK_CJK_sub_class_seq
-      { \clist_remove_all:Nn \l__xeCJK_font_options_clist {##1} }
     \prop_gput:NVV \g__xeCJK_family_font_name_prop
       \l__xeCJK_family_name_tl \l__xeCJK_font_name_tl
     \prop_gput:NVV \g__xeCJK_family_font_options_prop
@@ -2279,42 +2383,44 @@
   }
 \cs_new_protected_nopar:Npn \__xeCJK_set_sub_block_family:
   {
-    \seq_map_inline:Nn \l__xeCJK_sub_key_seq
+    \prop_map_inline:Nn \l__xeCJK_sub_key_prop
       {
-        \tl_set:Nx \l__xeCJK_sub_family_tl { \l__xeCJK_family_name_tl/##1 }
-        \bool_if:cT { l__xeCJK_copy_##1_bool } { \__xeCJK_copy_sub_family:n {##1} }
-        \bool_if:cT { l__xeCJK_add_##1_bool }
+        \tl_set:Nx \l__xeCJK_sub_family_name_tl { \l__xeCJK_family_name_tl/##1 }
+        \quark_if_no_value:nTF {##2}
+          { \__xeCJK_copy_sub_family:n {##1} }
           {
-            \xeCJK_set_family:Vvv \l__xeCJK_sub_family_tl
-              { l__xeCJK_##1_font_options_clist } { l__xeCJK_##1_font_name_tl }
+            \xeCJK_set_family:Voo \l__xeCJK_sub_family_name_tl
+              { \use_i:nn ##2 } { \use_ii:nn ##2 }
           }
       }
   }
 \cs_new_protected_nopar:Npn \__xeCJK_copy_sub_family:n #1
   {
-    \__xeCJK_check_family:V \l__xeCJK_sub_family_tl
+    \__xeCJK_check_family:V \l__xeCJK_sub_family_name_tl
     \prop_get:NVNT \g__xeCJK_family_font_name_prop
-      \l__xeCJK_family_name_tl \l__xeCJK_tmpa_tl
+      \l__xeCJK_family_name_tl \l__xeCJK_sub_font_name_tl
       {
         \prop_gput:NVV \g__xeCJK_family_font_name_prop
-          \l__xeCJK_sub_family_tl \l__xeCJK_tmpa_tl
+          \l__xeCJK_sub_family_name_tl \l__xeCJK_sub_font_name_tl
       }
     \prop_get:NVNT \g__xeCJK_family_font_options_prop
-      \l__xeCJK_family_name_tl \l__xeCJK_tmpa_clist
+      \l__xeCJK_family_name_tl \l__xeCJK_sub_font_options_clist
       {
-        \clist_remove_all:Nn \l__xeCJK_tmpa_clist { #1 = * }
+        \clist_remove_all:Nn \l__xeCJK_sub_font_options_clist { #1 = * }
         \prop_gput:NVV \g__xeCJK_family_font_options_prop
-          \l__xeCJK_sub_family_tl \l__xeCJK_tmpa_clist
+          \l__xeCJK_sub_family_name_tl \l__xeCJK_sub_font_options_clist
       }
-    \cs_gset_protected_nopar:cpx { \__xeCJK_family_csname:n { \l__xeCJK_sub_family_tl } }
+    \cs_gset_protected_nopar:cpx
+      { \__xeCJK_family_csname:n { \l__xeCJK_sub_family_name_tl } }
       {
         \xeCJK_family_if_exist:xT { \l__xeCJK_family_name_tl }
           {
             \prop_get:NnNT \exp_not:N \g__xeCJK_family_name_prop
-              { \l__xeCJK_family_name_tl } \exp_not:N \l__xeCJK_tmpa_tl
+              { \l__xeCJK_family_name_tl } \exp_not:N \l__xeCJK_fontspec_family_tl
               {
                 \__xeCJK_gset_family_nfss_cs:xx
-                  { \l__xeCJK_sub_family_tl } { \exp_not:N \l__xeCJK_tmpa_tl }
+                  { \l__xeCJK_sub_family_name_tl }
+                  { \exp_not:N \l__xeCJK_fontspec_family_tl }
               }
           }
       }
@@ -2330,8 +2436,8 @@
             \g__xeCJK_family_font_options_prop
           }
           {
-            \prop_get:NnNT ##1 {#2} \l__xeCJK_tmpa_tl
-              { \prop_gput:NnV ##1 {#1} \l__xeCJK_tmpa_tl }
+            \prop_get:NnNT ##1 {#2} \l__xeCJK_tmp_tl
+              { \prop_gput:NnV ##1 {#1} \l__xeCJK_tmp_tl }
           }
         \cs_gset_eq:cc
           { \__xeCJK_family_nfss_csname:n {#1} }
@@ -2360,6 +2466,7 @@
         \xeCJK_font_gset_to_current:c { \l__xeCJK_current_coor_tl }
       }
   }
+\tl_new:N \l__xeCJK_current_coor_tl
 \cs_new_eq:NN \xeCJK@setfont \xeCJK_select_font:
 \cs_new_protected_nopar:Npn \__xeCJK_switch_font:nn #1#2
   {
@@ -2433,6 +2540,15 @@
       }
     \tex_ignorespaces:D
   }
+\cs_new_protected_nopar:Npn \xeCJK_switch_family:n #1
+  {
+    \xeCJK_family_if_exist:xTF {#1}
+      {
+        \tl_set:Nx \l_xeCJK_family_tl {#1}
+        \tl_set_eq:NN \xeCJK@family \l_xeCJK_family_tl
+      }
+      { \__xeCJK_family_unknown_warning:x {#1} }
+  }
 \tl_new:N \l_xeCJK_family_tl
 \cs_new_protected_nopar:Npn \__xeCJK_gobble_CJKfamily:
   { \cs_set_eq:NN \CJKfamily \__xeCJK_gobble_CJKfamily:wn }
@@ -2482,18 +2598,18 @@
       }
       {#1}
   }
-\NewDocumentCommand \setCJKmainfont { O{} m }
+\NewDocumentCommand \setCJKmainfont { O { } m }
   {
     \xeCJK_set_family:xxx { \CJKrmdefault } {#1} {#2}
     \normalfont
   }
 \cs_new_eq:NN \setCJKromanfont \setCJKmainfont
-\NewDocumentCommand \setCJKsansfont { O{} m }
+\NewDocumentCommand \setCJKsansfont { O { } m }
   {
     \xeCJK_set_family:xxx { \CJKsfdefault } {#1} {#2}
     \normalfont
   }
-\NewDocumentCommand \setCJKmonofont { O{} m }
+\NewDocumentCommand \setCJKmonofont { O { } m }
   {
     \xeCJK_set_family:xxx { \CJKttdefault } {#1} {#2}
     \normalfont
@@ -2503,83 +2619,131 @@
 \@onlypreamble \setCJKsansfont
 \@onlypreamble \setCJKmonofont
 \@onlypreamble \setCJKromanfont
-\NewDocumentCommand \setCJKfamilyfont { m O{} m }
+\NewDocumentCommand \setCJKfamilyfont { m O { } m }
   { \xeCJK_set_family:xxx {#1} {#2} {#3} }
-\NewDocumentCommand \newCJKfontfamily { o m O{} m }
+\NewDocumentCommand \newCJKfontfamily { o m O { } m }
   {
-    \tl_set:Nx \l__xeCJK_tmpa_tl { \IfNoValueTF {#1} { \cs_to_str:N #2 } {#1} }
-    \cs_new_protected_nopar:Npx #2 { \CJKfamily { \l__xeCJK_tmpa_tl } }
-    \xeCJK_set_family:xxx { \l__xeCJK_tmpa_tl } {#3} {#4}
+    \tl_set:Nx \l__xeCJK_tmp_tl { \IfNoValueTF {#1} { \cs_to_str:N #2 } {#1} }
+    \cs_new_protected_nopar:Npx #2 { \xeCJK_switch_family:n { \l__xeCJK_tmp_tl } }
+    \xeCJK_set_family:xxx { \l__xeCJK_tmp_tl } {#3} {#4}
   }
-\NewDocumentCommand \CJKfontspec { O{} m }
+\NewDocumentCommand \CJKfontspec { O { } m }
   {
-    \xeCJK_fontspec:xx {#1} {#2}
+    \use:x { \xeCJK_fontspec:nn {#1} {#2} }
     \tex_ignorespaces:D
   }
 \cs_new_protected_nopar:Npn \xeCJK_fontspec:nn #1#2
   {
-    \tl_set:Nx \l__xeCJK_tmpa_tl { \tl_to_str:n { CJKfontspec/#1/#2/id } }
-    \tl_if_exist:cF { \l__xeCJK_tmpa_tl }
+    \prop_get:NnNTF \g__xeCJK_fontspec_prop
+      { CJKfontspec/#1/#2/id } \l_xeCJK_family_tl
+      { \tl_set_eq:NN \xeCJK@family \l_xeCJK_family_tl }
       {
-        \tl_set:Nx \l__xeCJK_tmpb_tl
+        \__xeCJK_fontspec:xnn
           { CJKfontspec ( \int_eval:n { \g__xeCJK_family_int + \c_one } ) }
-        \tl_gset_eq:cN { \l__xeCJK_tmpa_tl } \l__xeCJK_tmpb_tl
-        \xeCJK_set_family:Vnn \l__xeCJK_tmpb_tl {#1} {#2}
+          {#1} {#2}
       }
-    \exp_args:Nc \CJKfamily { \l__xeCJK_tmpa_tl }
   }
-\cs_generate_variant:Nn \xeCJK_fontspec:nn { VV , xx }
+\cs_new_protected_nopar:Npn \__xeCJK_fontspec:nnn #1#2#3
+  {
+    \prop_gput:Nnn \g__xeCJK_fontspec_prop { CJKfontspec/#2/#3/id } {#1}
+    \xeCJK_set_family:nnn {#1} {#2} {#3}
+    \xeCJK_switch_family:n {#1}
+  }
+\cs_generate_variant:Nn \xeCJK_fontspec:nn { VV }
+\cs_generate_variant:Nn \__xeCJK_fontspec:nnn { x }
+\prop_new:N \g__xeCJK_fontspec_prop
 \clist_new:N \g__xeCJK_default_features_clist
 \NewDocumentCommand \defaultCJKfontfeatures { m }
   { \clist_gset:Nn \g__xeCJK_default_features_clist {#1} }
 \@onlypreamble \defaultCJKfontfeatures
-\NewDocumentCommand \addCJKfontfeatures { m }
+\NewDocumentCommand \addCJKfontfeatures { s O { } m }
   {
-    \xeCJK_add_font_features:x {#1}
+    \xeCJK_add_font_features:Nxx #1 {#2} {#3}
     \tex_ignorespaces:D
   }
 \cs_new_eq:NN \addCJKfontfeature \addCJKfontfeatures
-\cs_new_protected_nopar:Npn \xeCJK_add_font_features:n #1
+\cs_new_protected_nopar:Npn \xeCJK_add_font_features:Nnn #1#2#3
   {
-    \prop_get:NVNTF \g__xeCJK_family_font_name_prop \l_xeCJK_family_tl \l__xeCJK_tmpa_tl
+    \prop_get:NVNTF \g__xeCJK_family_font_name_prop
+      \l_xeCJK_family_tl \l__xeCJK_font_name_tl
       {
-        \clist_set:Nn \l__xeCJK_tmpa_clist {#1}
-        \seq_map_function:NN
-          \g__xeCJK_CJK_sub_class_seq \__xeCJK_parse_sub_class_features:n
+        \clist_set:Nn \l__xeCJK_add_font_features_clist {#3}
+        \seq_map_inline:Nn \g__xeCJK_sub_key_seq
+          { \clist_remove_all:Nn \l__xeCJK_add_font_features_clist {##1} }
+        \seq_clear:N \l__xeCJK_sub_key_seq
+        \clist_clear:N \l__xeCJK_add_block_features_clist
+        \clist_map_inline:nn {#2}
+          {
+            \seq_if_in:NnTF \g__xeCJK_sub_key_seq {##1}
+              {
+                \seq_put_right:Nn \l__xeCJK_sub_key_seq {##1}
+                \__xeCJK_add_sub_class_features:n {##1}
+              }
+              { \__xeCJK_warning:nx { SubBlock-undefined } {##1} }
+          }
+        \bool_if:nT { #1 && \seq_if_empty_p:N \l__xeCJK_sub_key_seq }
+          {
+            \seq_map_function:NN
+              \g__xeCJK_sub_key_seq \__xeCJK_add_sub_class_features:n
+          }
         \prop_get:NVNT \g__xeCJK_family_font_options_prop
-          \l_xeCJK_family_tl \l__xeCJK_tmpb_clist
+          \l_xeCJK_family_tl \l__xeCJK_font_options_clist
           {
-            \clist_concat:NNN
-              \l__xeCJK_tmpa_clist \l__xeCJK_tmpb_clist \l__xeCJK_tmpa_clist
+            \bool_if:nT
+              { \seq_if_empty_p:N \l__xeCJK_sub_key_seq || #1 }
+              {
+                \clist_concat:NNN \l__xeCJK_font_options_clist
+                  \l__xeCJK_font_options_clist \l__xeCJK_add_font_features_clist
+              }
+            \clist_concat:NNN \l__xeCJK_font_options_clist
+              \l__xeCJK_font_options_clist \l__xeCJK_add_block_features_clist
           }
-        \xeCJK_fontspec:VV \l__xeCJK_tmpa_clist \l__xeCJK_tmpa_tl
+        \xeCJK_fontspec:VV \l__xeCJK_font_options_clist \l__xeCJK_font_name_tl
       }
       { \__xeCJK_warning:n { addCJKfontfeature-ignored } }
   }
-\cs_generate_variant:Nn \xeCJK_add_font_features:n { x }
+\clist_new:N \l__xeCJK_add_font_features_clist
+\clist_new:N \l__xeCJK_add_block_features_clist
+\cs_generate_variant:Nn \xeCJK_add_font_features:Nnn { Nxx , Nnx }
 \__xeCJK_msg_new:nn { addCJKfontfeature-ignored }
   {
     \token_to_str:N \addCJKfontfeature (s)~ignored.\\\\
     It~cannot~be~used~with~a~font~that~wasn't~selected~by~xeCJK.
   }
-\cs_new_protected_nopar:Npn \__xeCJK_parse_sub_class_features:n #1
+\cs_new_protected_nopar:Npn \__xeCJK_add_sub_class_features:n #1
   {
-    \clist_if_in:NnT \l__xeCJK_tmpa_clist {#1}
+    \prop_get:NoNTF \g__xeCJK_family_font_name_prop
+      { \l_xeCJK_family_tl/#1 } \l__xeCJK_sub_font_name_tl
+      {
+        \prop_get:NoN \g__xeCJK_family_font_options_prop
+          { \l_xeCJK_family_tl/#1 } \l__xeCJK_sub_font_options_clist
+      }
       {
-        \clist_remove_all:Nn \l__xeCJK_tmpa_clist {#1}
-        \prop_get:NoNF \g__xeCJK_family_font_name_prop
-          { \l_xeCJK_family_tl/#1 } \l__xeCJK_tmpb_tl
+        \prop_get:NxNTF \g__xeCJK_family_font_name_prop
+          { \CJKfamilydefault/#1 } \l__xeCJK_sub_font_name_tl
           {
-            \prop_get:NxNF \g__xeCJK_family_font_name_prop
-              { \CJKfamilydefault/#1 } \l__xeCJK_tmpb_tl
-              { \tl_set_eq:NN \l__xeCJK_tmpb_tl \l__xeCJK_tmpa_tl }
+            \prop_get:NxN \g__xeCJK_family_font_options_prop
+              { \CJKfamilydefault/#1 } \l__xeCJK_sub_font_options_clist
+          }
+          {
+            \prop_get:NVN \g__xeCJK_family_font_options_prop
+              \l_xeCJK_family_tl \l__xeCJK_sub_font_options_clist
+            \tl_set_eq:NN \l__xeCJK_sub_font_name_tl \l__xeCJK_font_name_tl
+          }
+      }
+    \clist_concat:NNN \l__xeCJK_sub_font_options_clist
+      \l__xeCJK_sub_font_options_clist \l__xeCJK_add_font_features_clist
+    \clist_put_right:Nx \l__xeCJK_add_block_features_clist
+      {
+        #1 =
+          {
+            [ \exp_not:V \l__xeCJK_sub_font_options_clist ]
+            { \exp_not:V \l__xeCJK_sub_font_name_tl }
           }
-        \clist_set:Nx \l__xeCJK_tmpa_clist
-          { #1 = { [ \exp_not:V \l__xeCJK_tmpa_clist ] { \exp_not:V \l__xeCJK_tmpb_tl } } }
-        \clist_map_break:
       }
   }
-\cs_generate_variant:Nn \prop_get:NnNF { Nx }
+\cs_generate_variant:Nn \prop_get:NnN   { Nx }
+\cs_generate_variant:Nn \prop_get:NnNTF { Nx }
 \__xeCJK_at_end_preamble:n
   {
     \cs_set_eq:NN \__xeCJK_family_default_wrap:n \exp_not:n
@@ -2602,7 +2766,7 @@
       {
         \xeCJK_family_if_exist:xF { \CJKfamilydefault }
           {
-            \tl_set_eq:NN \l__xeCJK_tmpa_tl \CJKfamilydefault
+            \tl_set_eq:NN \l__xeCJK_tmp_tl \CJKfamilydefault
             \str_if_eq_x:nnTF { \CJKfamilydefault } { \CJKrmdefault }
               { \use:n }
               {
@@ -2611,12 +2775,15 @@
               }
               {
                 \prop_map_inline:Nn \g__xeCJK_family_font_name_prop
-                  { \prop_map_break:n { \tl_gset:Nn \CJKfamilydefault {#1} } }
+                  {
+                    \prop_map_break:n
+                      { \tl_gset_rescan:Nnn \CJKfamilydefault { } {#1} }
+                  }
               }
             \__xeCJK_warning:nxx { CJKfamilydefault-undefined }
-              { \l__xeCJK_tmpa_tl } { \CJKfamilydefault }
+              { \l__xeCJK_tmp_tl } { \CJKfamilydefault }
           }
-        \CJKfamily { \CJKfamilydefault }
+        \xeCJK_switch_family:n { \CJKfamilydefault }
         \bool_if:NT \g__xeCJK_math_bool { \xeCJK_set_mathfont: }
       }
   }
@@ -2634,31 +2801,31 @@
     Try~to~use~`\__xeCJK_msg_def_family_map:n {#1}'~to~define~it.
   }
 \keys_define:nn { xeCJK / options } { CJKmath .bool_gset:N = \g__xeCJK_math_bool }
-\NewDocumentCommand \setCJKmathfont { O{} m }
+\NewDocumentCommand \setCJKmathfont { O { } m }
   { \xeCJK_set_family:xxx { \c__xeCJK_math_tl } {#1} {#2} }
 \tl_const:Nn \c__xeCJK_math_tl { CJKmath }
 \cs_new_protected_nopar:Npn \xeCJK_set_mathfont:
   {
     \xeCJK_family_if_exist:xTF { \c__xeCJK_math_tl }
-      { \tl_set:Nx \l__xeCJK_tmpa_tl { \c__xeCJK_math_tl } }
+      { \tl_set:Nx \l__xeCJK_tmp_tl { \c__xeCJK_math_tl } }
       {
         \xeCJK_family_if_exist:xTF { \CJKfamilydefault }
-          { \tl_set:Nx \l__xeCJK_tmpa_tl { \CJKfamilydefault } }
+          { \tl_set:Nx \l__xeCJK_tmp_tl { \CJKfamilydefault } }
           { \use_none:nnnnn }
       }
-    \prop_get:NVNT \g__xeCJK_family_name_prop \l__xeCJK_tmpa_tl \l__xeCJK_tmpb_tl
+    \prop_get:NVNT \g__xeCJK_family_name_prop \l__xeCJK_tmp_tl \l__xeCJK_tmp_tl
       {
-        \tl_const:Nx \c__xeCJK_math_family_tl { \l__xeCJK_tmpb_tl }
+        \tl_const:Nx \c__xeCJK_math_family_tl { \l__xeCJK_tmp_tl }
         \DeclareSymbolFont \c__xeCJK_math_tl
           \c__xeCJK_encoding_tl \c__xeCJK_math_family_tl \mddefault \shapedefault
         \SetSymbolFont \c__xeCJK_math_tl { bold }
           \c__xeCJK_encoding_tl \c__xeCJK_math_family_tl \bfdefault \shapedefault
         \int_const:Nn \c_xeCJK_math_fam_int { \use:c { sym \c__xeCJK_math_tl } }
-        \clist_concat:NNN
-          \l__xeCJK_tmpa_clist \c__xeCJK_CJK_chars_clist \c__xeCJK_FullLeft_chars_clist
-        \clist_concat:NNN
-          \l__xeCJK_tmpa_clist \l__xeCJK_tmpa_clist \c__xeCJK_FullRight_chars_clist
-        \clist_map_inline:Nn \l__xeCJK_tmpa_clist
+        \clist_concat:NNN \l__xeCJK_tmp_clist
+          \c__xeCJK_CJK_chars_clist \c__xeCJK_FullLeft_chars_clist
+        \clist_concat:NNN \l__xeCJK_tmp_clist
+          \l__xeCJK_tmp_clist \c__xeCJK_FullRight_chars_clist
+        \clist_map_inline:Nn \l__xeCJK_tmp_clist
           {
             \__xeCJK_set_char_class_aux:Nnw \xeCJK_gset_mathcode:nnnn {##1}
               { \c_seven } { \c_xeCJK_math_fam_int }
@@ -2667,12 +2834,12 @@
   }
 \cs_new_protected_nopar:Npn \xeCJK_gset_mathcode:nnnn #1#2#3#4
   {
-    \__xeCJK_check_num_range:nnNN {#1} {#2} \l__xeCJK_tmpa_int \l__xeCJK_tmpb_int
-    \xeCJK_int_until_do:nn { \l__xeCJK_tmpa_int > \l__xeCJK_tmpb_int }
+    \__xeCJK_check_num_range:nnNN {#1} {#2} \l__xeCJK_begin_int \l__xeCJK_end_int
+    \xeCJK_int_until_do:nn { \l__xeCJK_begin_int > \l__xeCJK_end_int }
       {
         \tex_global:D \xeCJK_xetex_mathcode:w
-          \l__xeCJK_tmpa_int = #3 ~ #4 \l__xeCJK_tmpa_int
-        \int_incr:N \l__xeCJK_tmpa_int
+          \l__xeCJK_begin_int = #3 ~ #4 \l__xeCJK_begin_int
+        \int_incr:N \l__xeCJK_begin_int
       }
   }
 \keys_define:nn { xeCJK / options }
@@ -2681,7 +2848,8 @@
     Verb / true  .code:n = { \int_set_eq:NN \l__xeCJK_verb_case_int \c_zero } ,
     Verb / env   .code:n = { \int_set_eq:NN \l__xeCJK_verb_case_int \c_one } ,
     Verb / env+  .code:n = { \int_set_eq:NN \l__xeCJK_verb_case_int \c_two } ,
-    Verb / false .code:n = { \int_set_eq:NN \l__xeCJK_verb_case_int \c_three }
+    Verb / false .code:n = { \int_set_eq:NN \l__xeCJK_verb_case_int \c_three } ,
+    Verb      .default:n = { env }
   }
 \int_new:N \l__xeCJK_verb_case_int
 \__xeCJK_after_preamble:n
@@ -2759,9 +2927,9 @@
           }
         \xeCJKsetup { xCJKecglue = false }
         \cs_set_protected_nopar:Npn \CJKglue
-          { \skip_horizontal:N \g__xeCJK_verb_exspace_skip }
+          { \skip_horizontal:N \l__xeCJK_verb_exspace_skip }
         \cs_set_protected_nopar:Npn \CJKecglue
-          { \skip_horizontal:n { 0.5 \g__xeCJK_verb_exspace_skip } }
+          { \skip_horizontal:n { 0.5 \l__xeCJK_verb_exspace_skip } }
         \cs_set_eq:NN \xeCJK_check_for_glue: \CJKecglue
         \cs_set_eq:NN \xeCJK_ignore_spaces:w \CJKecglue
         \skip_set:Nn \tex_rightskip:D { \c_zero_dim plus 1 fil }
@@ -2769,36 +2937,76 @@
   }
 \cs_new_protected_nopar:Npn \__xeCJK_reset_char_class:n #1
   {
-    \int_set:Nn \l__xeCJK_tmpa_int { \xeCJK_class_num:n {#1} }
+    \int_set:Nn \l__xeCJK_tmp_int { \xeCJK_class_num:n {#1} }
     \clist_map_inline:cn { c__xeCJK_#1_chars_clist }
-      { \XeTeXcharclass ##1 = \l__xeCJK_tmpa_int }
+      { \XeTeXcharclass ##1 = \l__xeCJK_tmp_int }
   }
 \bool_new:N \l__xeCJK_verb_addon_bool
 \cs_new_eq:NN \CJKfixedspacing \xeCJKVerbAddon
 \cs_new_protected_nopar:Npn \__xeCJK_set_verb_exspace:
   {
-    \tl_if_exist:cF { xeCJK/verb/\l_xeCJK_family_tl/\curr@fontshape/\f@size }
+    \tl_if_exist:cTF { xeCJK/verb/\l_xeCJK_family_tl/\curr@fontshape/\f@size }
       {
-        \group_begin:
-        \xeCJK_select_font:
+        \skip_set:Nn \l__xeCJK_verb_exspace_skip
+          { \use:c { xeCJK/verb/\l_xeCJK_family_tl/\curr@fontshape/\f@size } }
+      }
+      {
+        \tl_set:Nx \l__xeCJK_current_coor_tl { \l_xeCJK_family_tl/\curr@fontshape }
+        \prop_get:NVNTF \g__xeCJK_scale_family_prop
+          \l__xeCJK_current_coor_tl \l_xeCJK_family_tl
+          {
+            \tl_set_eq:NN \xeCJK@family \l_xeCJK_family_tl
+            \skip_zero:N \l__xeCJK_verb_exspace_skip
+          }
+          {
+            \group_begin: \xeCJK_select_font: \exp_after:wN \group_end:
+            \exp_after:wN \__xeCJK_set_verb_exspace:n
+            \exp_after:wN { \dim_use:N \etex_fontcharwd:D \tex_font:D "4E00 }
+          }
+      }
+  }
+\skip_new:N \l__xeCJK_verb_exspace_skip
+\cs_new_protected_nopar:Npn \__xeCJK_set_verb_exspace:n #1
+  {
+    \skip_set:Nn \l__xeCJK_verb_exspace_skip
+      { \c_two \tex_fontdimen:D \c_two \tex_font:D - #1 }
+    \dim_compare:nNnTF \l__xeCJK_verb_exspace_skip < \c_zero_dim
+      {
+        \skip_zero:N \l__xeCJK_verb_exspace_skip
         \use:x
           {
-            \group_end:
-            \tl_gset:cx
-            \exp_not:n { { xeCJK/verb/\l_xeCJK_family_tl/\curr@fontshape/\f@size } }
-              {
-                \exp_not:N \dim_max:nn { \c_zero_dim }
-                  {
-                    \c_two \tex_fontdimen:D \c_two \tex_font:D -
-                    \dim_use:N \etex_fontcharwd:D \tex_font:D "4E00
-                  }
-              }
+            \__xeCJK_set_verb_scale:nn
+              { \dim_to_fp:n { \c_two \tex_fontdimen:D \c_two \tex_font:D } }
+              { \dim_to_fp:n {#1} }
           }
       }
-    \skip_gset:Nn \g__xeCJK_verb_exspace_skip
-      { \use:c { xeCJK/verb/\l_xeCJK_family_tl/\curr@fontshape/\f@size } }
+      {
+        \tl_const:cx { xeCJK/verb/\l_xeCJK_family_tl/\curr@fontshape/\f@size }
+          { \skip_use:N \l__xeCJK_verb_exspace_skip }
+      }
+  }
+\cs_new_protected_nopar:Npn \__xeCJK_set_verb_scale:nn #1#2
+  {
+    \fp_set:Nn \l__xeCJK_scale_factor_fp { #1 / #2 }
+    \__xeCJK_warning:nxx { scale-factor }
+      { \fp_eval:n { round - ( \l__xeCJK_scale_factor_fp , 2 ) } }
+      { \fp_eval:n { round + ( #2 / #1 , 2 ) } }
+    \xeCJK_add_font_features:Nnx \c_true_bool
+      { } { Scale = { \fp_use:N \l__xeCJK_scale_factor_fp } }
+    \prop_gput:NVV \g__xeCJK_scale_family_prop
+      \l__xeCJK_current_coor_tl \l_xeCJK_family_tl
+  }
+\__xeCJK_msg_new:nn { scale-factor }
+  {
+    `\token_to_str:N \xeCJKVerbAddon'~may~not~work~properly.\\\\
+    You~may~set~`Scale=#1'~to~CJKfamily~
+    `\__xeCJK_msg_family_map:n { \l_xeCJK_family_tl }',\\
+    or~set~`Scale=#2'~to~family~
+    `\str_if_eq_x:nnTF \f@family \ttdefault
+      { \token_to_str:N \ttdefault } { \f@family }'.
   }
-\skip_new:N \g__xeCJK_verb_exspace_skip
+\fp_new:N \l__xeCJK_scale_factor_fp
+\prop_new:N \g__xeCJK_scale_family_prop
 \cs_new_protected_nopar:Npn \xeCJK_visible_space_fallback:
   { {
       \cs_if_exist_use:cF { xeCJK/space/\curr@fontshape/\f@size }
@@ -3037,10 +3245,10 @@
       {
         \str_case:nnn {#1}
           {
-            { \rmdefault }     { \CJKfamily { \CJKrmdefault } }
-            { \sfdefault }     { \CJKfamily { \CJKsfdefault } }
-            { \ttdefault }     { \CJKfamily { \CJKttdefault } }
-            { \familydefault } { \CJKfamily { \CJKfamilydefault } }
+            { \rmdefault }     { \xeCJK_switch_family:n { \CJKrmdefault } }
+            { \sfdefault }     { \xeCJK_switch_family:n { \CJKsfdefault } }
+            { \ttdefault }     { \xeCJK_switch_family:n { \CJKttdefault } }
+            { \familydefault } { \xeCJK_switch_family:n { \CJKfamilydefault } }
           }
           { }
       }
@@ -3055,19 +3263,19 @@
       {
         \xeCJK_if_last_node:nTF { default }
           {
-            \tex_unkern:D \tex_unkern:D \@@italiccorr
+            \xeCJK_remove_node: \@@italiccorr
             { \xeCJK_make_node:n { default } }
           }
           {
             \xeCJK_if_last_node:nTF { CJK }
               {
-                \tex_unkern:D \tex_unkern:D \@@italiccorr
+                \xeCJK_remove_node: \@@italiccorr
                 { \xeCJK_make_node:n { CJK } } \use:n
               }
               {
                 \xeCJK_if_last_node:nTF { CJK-space }
                   {
-                    \tex_unkern:D \tex_unkern:D \@@italiccorr
+                    \xeCJK_remove_node: \@@italiccorr
                     { \xeCJK_make_node:n { CJK-space } } \use:n
                   }
                   { \@@italiccorr \use_none:n }
@@ -3170,9 +3378,6 @@
       { \xeCJK_if_package_loaded_p:n { cprotect } && \cs_if_exist_p:N \icprotect }
       { \exp_after:wN \tex_let:D \cs:w cprotect \cs_end: \icprotect }
   }
-\tl_set:cn { ver@CJK.sty } { 9999/99/99 }
-\tl_set_eq:cc { ver@CJKulem.sty }  { ver@CJK.sty }
-\tl_set_eq:cc { ver@CJKpunct.sty } { ver@CJK.sty }
 \cs_if_exist:NF \CJK@ifundefined
   { \cs_set_eq:NN \CJK@ifundefined \cs_if_free:NTF }
 \NewDocumentCommand \xeCJKcaption { o m }
@@ -3207,18 +3412,31 @@
     \xeCJK_if_package_loaded:nT { listings }
       { \RequirePackage { xeCJK-listings } }
   }
-\bool_if:NT \g__xeCJK_number_bool
+\cs_new_protected:Npn \CJKaddEncHook #1#2
   {
-    \tl_set:Nn \CJK@UnicodeEnc { UTF8 }
-    \cs_set_protected:Npn \CJKaddEncHook #1#2
-      { \cs_set:cpn { __xeCJK_enc_#1_hook: } {#2} }
-    \cs_set_protected_nopar:Npn \Unicode #1#2
-      { \tex_char:D \etex_numexpr:D (#1) * \c_two_hundred_fifty_six + (#2) \scan_stop: }
-    \RequirePackage { CJKnumb }
-    \cs_if_exist_use:c { __xeCJK_enc_ \CJK@UnicodeEnc _hook: }
-    \tl_set:Nn \CJK@tenthousand    { \Unicode { 78 } { 7 } }
-    \tl_set:Nn \CJK@hundredmillion { \Unicode { 78 } { 191 } }
+    \str_if_eq:nnT {#1} { \CJK@UnicodeEnc }
+      {
+        \group_begin:
+        \cs_set_nopar:Npn \Unicode ##1##2
+          { (##1) * \c_two_hundred_fifty_six + (##2) }
+        \cs_set_eq:NN \def \xeCJK_char_from_charcode:Nn
+        #2
+        \group_end:
+        \tl_gset:Nn \CJK@tenthousand    { ^^^^4e07 }
+        \tl_gset:Nn \CJK@hundredmillion { ^^^^4ebf }
+      }
+  }
+\cs_new_protected_nopar:Npn \xeCJK_char_from_charcode:Nn #1#2
+  {
+    \group_begin:
+    \char_set_lccode:nn { "4E00 } {#2}
+    \tl_to_lowercase:n
+      {
+        \group_end:
+        \tl_const:Nn #1 { ^^^^4e00 }
+      }
   }
+\bool_if:NT \g__xeCJK_number_bool { \RequirePackage { CJKnumb } }
 \bool_if:NT \g__xeCJK_config_bool
   {
     \tl_const:Nn \c__xeCJK_config_ext_tl { cfg }
-- 
cgit v1.2.3

