
% \section{Font loading (\pkg{keyval}) definitions}
%
% This is the tedious section where we correlate all possible
% (eventually) font feature requests with their \XeTeX\ representations.
%
% \iffalse
%    \begin{macrocode}
%<*fontspec&(xetexx|luatex)>
%    \end{macrocode}
% \fi
%
%
%    \begin{macrocode}
\clist_set:Nn \g_@@_all_keyval_modules_clist
  {
    fontspec, fontspec-opentype, fontspec-aat,
    fontspec-preparse, fontspec-preparse-cfg, fontspec-preparse-external, fontspec-preparse-nested,
    fontspec-renderer
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_new:Nn \@@_keys_define_code:nnn
  {
   \keys_define:nn {#1} { #2 .code:n = {#3} }
  }
%    \end{macrocode}
%
% For catching features that cannot be used in |\addfontfeatures|:
%    \begin{macrocode}
\cs_new:Nn \@@_aff_error:n
  {
    \@@_keys_define_code:nnn {fontspec-addfeatures} {#1}
      { \@@_error:nx {not-in-addfontfeatures} {#1} }
  }
%    \end{macrocode}
%
% \subsubsection{Pre-parsing naming information}
%
% These features are extracted from the font feature list before all others.
%
% \paragraph{Don't load font config file}
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse-cfg} {IgnoreFontspecFile}
  {
    \bool_set_false:N \l_@@_fontcfg_bool
  }
\@@_keys_define_code:nnn {fontspec-preparse-external} {IgnoreFontspecFile}
  {
    \bool_set_false:N \l_@@_fontcfg_bool
  }
%    \end{macrocode}
%
% \begin{macro}{Path}
% For fonts that aren't installed in the system. If no argument is given, the font is located
% with |kpsewhich|; it's either in the current directory or the \TeX\ tree. Otherwise, the
% argument given defines the file path of the font.
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse-external} {Path}
 {
  \bool_set_true:N \l_@@_nobf_bool
  \bool_set_true:N \l_@@_noit_bool
  \bool_set_true:N \l_@@_external_bool
  \tl_set:Nn \l_@@_font_path_tl {#1}
  \@@_font_is_file:
%<*xetexx>
  \keys_set:nn {fontspec-renderer} {Renderer=OpenType}
%</xetexx>
 }
\aliasfontfeature{Path}{ExternalLocation}
\@@_keys_define_code:nnn {fontspec} {Path} {}
%    \end{macrocode}
% \end{macro}
%
% \paragraph{\feat{Extension}}
% For fonts that aren't installed in the system. Specifies the font extension
% to use.
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse-external} {Extension}
 {
  \tl_set:Nn \l_@@_extension_tl {#1}
  \bool_if:NF \l_@@_external_bool
   {
    \keys_set:nn {fontspec-preparse-external} {Path}
   }
 }
\tl_clear:N \l_@@_extension_tl
\@@_keys_define_code:nnn {fontspec} {Extension} {}
%    \end{macrocode}
%
% \subsubsection{Pre-parsed features}
%
% After the font name(s) have been sorted out, now need to extract any
% renderer/font configuration features that need to be processed before
% all other font features.
%
% \paragraph{\feat{Renderer}}
% This feature must be processed before all others (the other font shape and features options are also pre-parsed for convenience) because the renderer determines the format of the features and even whether certain features are available.
%    \begin{macrocode}
\keys_define:nn {fontspec-renderer}
 {
  Renderer .choices:nn =
   {AAT,ICU,OpenType,Graphite,Full,Basic}
   {
    \int_compare:nTF {\l_keys_choice_int <= 4} {
%<*xetexx>
      \tl_set:Nv \l_fontspec_renderer_tl
        { g_fontspec_renderer_tag_ \l_keys_choice_tl }
      \tl_gset:Nx \g_@@_single_feat_tl { \l_fontspec_renderer_tl }
%</xetexx>
%<*luatex>
      \@@_warning:nx {only-xetex-feature} {Renderer=AAT/OpenType/Graphite}
%</luatex>
     }
     {
%<*xetexx>
      \@@_warning:nx {only-luatex-feature} {Renderer=Full/Basic}
%</xetexx>
%<*luatex>
      \tl_set:Nv \l_fontspec_mode_tl
        { g_fontspec_mode_tag_ \l_keys_choice_tl }
      \tl_gset:Nx \g_@@_single_feat_tl { mode=\l_fontspec_mode_tl }
%</luatex>
     }
   }
 }
\tl_set:cn {g_fontspec_renderer_tag_AAT} {/AAT}
\tl_set:cn {g_fontspec_renderer_tag_ICU} {/OT}
\tl_set:cn {g_fontspec_renderer_tag_OpenType} {/OT}
\tl_set:cn {g_fontspec_renderer_tag_Graphite} {/GR}
\tl_set:cn {g_fontspec_mode_tag_Full}  {node}
\tl_set:cn {g_fontspec_mode_tag_Basic} {base}
%    \end{macrocode}
%
% \paragraph{OpenType script/language}
% See later for the resolutions from \pkg{fontspec} features to OpenType definitions.
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse} {Script}
 {
%<xetexx>    \keys_set:nn {fontspec-renderer} {Renderer=OpenType}
  \tl_set:Nn \l_@@_script_name_tl {#1}
 }
%    \end{macrocode}
% Exactly the same:
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse} {Language}
 {
%<xetexx>    \keys_set:nn {fontspec-renderer} {Renderer=OpenType}
  \tl_set:Nn \l_@@_lang_name_tl {#1}
 }
%    \end{macrocode}
%
% \paragraph{TTC font index}
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse} {FontIndex}
 {
  \str_if_eq_x:nnF { \str_lower_case:f {\l_@@_extension_tl} } {.ttc}
    { \@@_warning:n {font-index-needs-ttc} }
%<xetexx>  \tl_set:Nn \l_@@_ttc_index_tl {:#1}
%<luatex>  \tl_set:Nn \l_@@_ttc_index_tl {(#1)}
 }
\@@_keys_define_code:nnn {fontspec} {FontIndex}
 {
%<xetexx>  \tl_set:Nn \l_@@_ttc_index_tl {:#1}
%<luatex>  \tl_set:Nn \l_@@_ttc_index_tl {(#1)}
 }
%    \end{macrocode}
%
% \subsubsection{Bold/italic choosing options}
%
% The \feat{Bold}, \feat{Italic}, and \feat{BoldItalic}
% features are for defining explicitly the bold and italic fonts used
% in a font family.
%
% \paragraph{Bold (NFSS) Series}
% By default, \pkg{fontspec} uses the default bold series, \cs{bfdefault}.
% We want to be able to make this extensible.
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse-external} {BoldSeries}
 {
  \tl_gset:Nx \g_@@_curr_series_tl { #1 }
  \seq_gput_right:Nx \g_@@_bf_series_seq { #1 }
 }
%    \end{macrocode}
%
% \paragraph{Fonts}
% Upright:
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse-external} {UprightFont}
 {
  \fontspec_complete_fontname:Nn \l_@@_fontname_up_tl {#1}
 }
\@@_keys_define_code:nnn {fontspec-preparse-external} {FontName}
 {
  \fontspec_complete_fontname:Nn \l_@@_fontname_up_tl {#1}
 }
%    \end{macrocode}
% Bold:
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse-external} {BoldFont}
 {
  \tl_if_empty:nTF {#1}
   {
    \bool_set_true:N \l_@@_nobf_bool
   }
   {
    \bool_set_false:N \l_@@_nobf_bool
    \fontspec_complete_fontname:Nn \l_@@_curr_bfname_tl {#1}

    \seq_if_empty:NT \g_@@_bf_series_seq
     {
      \tl_gset:Nx \g_@@_curr_series_tl {\bfdefault}
      \seq_put_right:Nx \g_@@_bf_series_seq {\bfdefault}
     }
    \tl_if_eq:oxT \g_@@_curr_series_tl {\bfdefault}
     { \tl_set_eq:NN \l_@@_fontname_bf_tl \l_@@_curr_bfname_tl }

%<debug>\typeout{Setting~bold~font~"\l_@@_curr_bfname_tl"~with~series~"\g_@@_curr_series_tl"}

    \prop_put:NxV \l_@@_nfss_prop
     {BoldFont-\g_@@_curr_series_tl} \l_@@_curr_bfname_tl

   }
 }
%    \end{macrocode}
% Same for italic:
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse-external} {ItalicFont}
 {
  \tl_if_empty:nTF {#1}
   {
    \bool_set_true:N \l_@@_noit_bool
   }
   {
    \bool_set_false:N \l_@@_noit_bool
    \fontspec_complete_fontname:Nn \l_@@_fontname_it_tl {#1}
   }
 }
%    \end{macrocode}
% Simpler for bold+italic \& slanted:
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse-external} {BoldItalicFont}
 {
  \fontspec_complete_fontname:Nn \l_@@_fontname_bfit_tl {#1}
 }
\@@_keys_define_code:nnn {fontspec-preparse-external} {SlantedFont}
 {
  \fontspec_complete_fontname:Nn \l_@@_fontname_sl_tl {#1}
 }
\@@_keys_define_code:nnn {fontspec-preparse-external} {BoldSlantedFont}
 {
  \fontspec_complete_fontname:Nn \l_@@_fontname_bfsl_tl {#1}
 }
%    \end{macrocode}
% Small caps isn't pre-parsed because it can vary with others above:
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec} {SmallCapsFont}
 {
  \tl_if_empty:nTF {#1}
   {
    \bool_set_true:N \l_@@_nosc_bool
   }
   {
    \bool_set_false:N \l_@@_nosc_bool
    \fontspec_complete_fontname:Nn \l_@@_fontname_sc_tl {#1}
   }
 }
%    \end{macrocode}
%
%
% \paragraph{Features}
%
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse} {UprightFeatures}
 {
  \clist_set:Nn \l_@@_fontfeat_up_clist {#1}
 }
\@@_keys_define_code:nnn {fontspec-preparse} {BoldFeatures}
 {
  \clist_set:Nn \l_@@_fontfeat_bf_clist {#1}

%  \prop_put:NxV \l_@@_nfss_prop
%     {BoldFont-\g_@@_curr_series_tl} \l_@@_curr_bfname_tl
 }
\@@_keys_define_code:nnn {fontspec-preparse} {ItalicFeatures}
 {
  \clist_set:Nn \l_@@_fontfeat_it_clist {#1}
 }
\@@_keys_define_code:nnn {fontspec-preparse} {BoldItalicFeatures}
 {
  \clist_set:Nn \l_@@_fontfeat_bfit_clist {#1}
 }
\@@_keys_define_code:nnn {fontspec-preparse} {SlantedFeatures}
 {
  \clist_set:Nn \l_@@_fontfeat_sl_clist {#1}
 }
\@@_keys_define_code:nnn {fontspec-preparse} {BoldSlantedFeatures}
 {
  \clist_set:Nn \l_@@_fontfeat_bfsl_clist {#1}
 }
%    \end{macrocode}
% Note that small caps features can vary by shape, so these in fact \emph{aren't} pre-parsed.
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec} {SmallCapsFeatures}
 {
  \bool_if:NF \l_@@_firsttime_bool
   {
    \clist_set:Nn \l_@@_fontfeat_sc_clist {#1}
   }
 }
%    \end{macrocode}
%
% paragraph{Features varying by size}
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse} {SizeFeatures}
 {
  \clist_set:Nn \l_@@_sizefeat_clist {#1}
  \clist_put_right:Nn \l_@@_fontfeat_up_clist { SizeFeatures = {#1} }
 }
\@@_keys_define_code:nnn {fontspec-preparse-nested} {SizeFeatures}
 {
  \clist_set:Nn \l_@@_sizefeat_clist {#1}
  \tl_if_empty:NT \l_@@_this_font_tl
   { \tl_set:Nn \l_@@_this_font_tl { -- } } % needs to be non-empty as a flag
 }
\@@_keys_define_code:nnn {fontspec-preparse-nested} {Font}
 {
  \tl_set:Nn \l_@@_this_font_tl {#1}
 }
\@@_keys_define_code:nnn {fontspec} {SizeFeatures}
 {
  % dummy
 }
\@@_keys_define_code:nnn {fontspec} {Font}
 {
  % dummy
 }
%    \end{macrocode}
%
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-sizing} {Size}
 {
  \tl_set:Nn \l_@@_size_tl {#1}
 }
\@@_keys_define_code:nnn {fontspec-sizing} {Font}
 {
  \fontspec_complete_fontname:Nn \l_@@_sizedfont_tl {#1}
 }
%    \end{macrocode}
%
% \subsubsection{Font-independent features}
%
% These features can be applied to any font.
%
% \paragraph{NFSS encoding}
% For the very brave.
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse} {NFSSEncoding}
 {
  \tl_gset:Nx \l_@@_nfss_enc_tl { #1 }
 }
%    \end{macrocode}
%
% \paragraph{NFSS family}
% Interactions with other packages will sometimes require setting the NFSS family explicitly.
% (By default \pkg{fontspec} auto-generates one based on the font name.)
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-preparse} {NFSSFamily}
 {
  \tl_set:Nx \l_@@_nfss_fam_tl { #1 }
  \cs_undefine:c {g_@@_UID_\l_@@_fontid_tl}
  \tl_if_exist:NT \l_fontspec_family_tl
   { \cs_undefine:c {g_@@_ \l_fontspec_family_tl _prop} }
 }
%    \end{macrocode}
%
% \paragraph{NFSS series/shape}
% This option looks similar in name but has a very different function.
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec} {FontFace}
 {
  \tl_set:No \l_@@_arg_tl { \use_iii:nnn #1 }
  \tl_set_eq:NN \l_@@_this_feat_tl \l_@@_arg_tl
  \tl_clear:N \l_@@_this_font_tl
  \int_compare:nT { \clist_count:N \l_@@_arg_tl = 1 }
   {
%<*debug>
    \typeout{FontFace~ parsing:~ one~ clist~ item}
%</debug>
    \tl_if_in:NnF \l_@@_arg_tl {=}
     {
%<*debug>
      \typeout{FontFace~ parsing:~ no~ equals~ =>~ font~ name~ only}
%</debug>
      \tl_set_eq:NN \l_@@_this_font_tl \l_@@_arg_tl
      \tl_clear:N \l_@@_this_feat_tl
     }
   }

  \@@_add_nfssfont:nnnn
   {\use_i:nnn #1}{\use_ii:nnn #1}{\l_@@_this_font_tl}{\l_@@_this_feat_tl}
 }
%    \end{macrocode}
%
%
%
% \paragraph{Scale}
% If the input isn't one of the pre-defined string options, then
% it's gotta be numerical. \cs{fontspec_calc_scale:n} does all the work in
% the auto-scaling cases.
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec} {Scale}
 {
  \str_case:nnF {#1}
   {
    {MatchLowercase} { \@@_calc_scale:n {5} }
    {MatchUppercase} { \@@_calc_scale:n {8} }
   }
   { \tl_set:Nx \l_@@_scale_tl {#1} }
  \tl_set:Nx \l_@@_scale_tl { s*[\l_@@_scale_tl] }
 }
%    \end{macrocode}
%
% \begin{macro}{\@@_calc_scale:n}
% This macro calculates the amount of scaling between the default
% roman font and the (default shape of) the font being selected such
% that the font dimension that is input is equal for both. The only
% font dimensions that justify this are 5 (lowercase height)
% and 8 (uppercase height in \XeTeX).
%
% This script is executed for every extra shape, which seems wasteful,
% but allows alternate italic shapes from a separate font, say, to
% be loaded and to be auto-scaled correctly. Even if this would be ugly.
%
% To begin, change to \cs{rmfamily} but use internal commands in case cs{rmfamily}
% has been overwritten.
% (Note that changing \cs{rmfamily} with fontspec resets \cs{encodingdefault}
% appropriately.)
%    \begin{macrocode}
\cs_new:Nn \@@_calc_scale:n
 {
  \group_begin:

    \fontencoding { \encodingdefault }
    \fontfamily { \rmdefault }
    \selectfont

    \@@_set_font_dimen:NnN \l_@@_tmpa_dim {#1} \font
    \@@_set_font_dimen:NnN \l_@@_tmpb_dim {#1} \l_fontspec_font

    \tl_gset:Nx \l_@@_scale_tl
      {
        \fp_eval:n { \dim_to_fp:n {\l_@@_tmpa_dim} /
                     \dim_to_fp:n {\l_@@_tmpb_dim} }
      }

    \@@_info:n {set-scale}
  \group_end:
 }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_set_font_dimen:NnN}
% This function sets the dimension |#1| (for font |#3|) to `fontdimen' |#2|
% for either font dimension 5 (x-height) or 8 (cap-height). If, for some
% reason, these return an incorrect `zero' value (as \cs{fontdimen8} might
% for a \texttt{.tfm} font), then we cheat and measure the height of a glyph.
% We assume in this case that the font contains either an `X' or an `x'.
%    \begin{macrocode}
\cs_new:Nn \@@_set_font_dimen:NnN
 {
  \dim_set:Nn #1 { \fontdimen #2 #3 }
  \dim_compare:nNnT #1 = {0pt}
   {
    \settoheight #1
     {
      \str_if_eq:nnTF {#3} {\font} \rmfamily #3
      \int_case:nnF #2
       {
         {5} {x} % x-height
         {8} {X} % cap-height
       } {?} % "else" clause; never reached.
     }
   }
 }
%    \end{macrocode}
% \end{macro}
%
%
% \paragraph{Inter-word space}
% These options set the relevant \cmd\fontdimen s for the
% font being loaded.
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec} {WordSpace}
 {
  \bool_if:NF \l_@@_firsttime_bool
   { \_fontspec_parse_wordspace:w #1,,,\q_stop }
 }
\@@_aff_error:n {WordSpace}
%    \end{macrocode}
%
% \begin{macro}{\_fontspec_parse_wordspace:w}
% This macro determines if the input to \feat{WordSpace} is
% of the form |{X}| or |{X,Y,Z}| and executes the font scaling.
% If the former input, it executes |{X,X,X}|.
%    \begin{macrocode}
\cs_set:Npn \_fontspec_parse_wordspace:w #1,#2,#3,#4 \q_stop
 {
  \tl_if_empty:nTF {#4}
   {
    \tl_set:Nn \l_@@_wordspace_adjust_tl
     {
      \fontdimen 2 \font = #1 \fontdimen 2 \font
      \fontdimen 3 \font = #1 \fontdimen 3 \font
      \fontdimen 4 \font = #1 \fontdimen 4 \font
     }
   }
   {
    \tl_set:Nn \l_@@_wordspace_adjust_tl
     {
      \fontdimen 2 \font = #1 \fontdimen 2 \font
      \fontdimen 3 \font = #2 \fontdimen 3 \font
      \fontdimen 4 \font = #3 \fontdimen 4 \font
     }
   }
 }
%    \end{macrocode}
% \end{macro}
%
% \paragraph{Punctuation space}
% Scaling factor for the nominal \cmd\fontdimen \#7.
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec} {PunctuationSpace}
 {
  \str_case_x:nnF {#1}
   {
    {WordSpace}
    {
     \tl_set:Nn \l_@@_punctspace_adjust_tl
      { \fontdimen 7 \font = 0 \fontdimen 2 \font }
    }
    {TwiceWordSpace}
    {
     \tl_set:Nn \l_@@_punctspace_adjust_tl
      { \fontdimen 7 \font = 1 \fontdimen 2 \font }
    }
   }
   {
     \tl_set:Nn \l_@@_punctspace_adjust_tl
     { \fontdimen 7 \font = #1 \fontdimen 7 \font }
   }
 }
\@@_aff_error:n {PunctuationSpace}
%    \end{macrocode}
%
% \paragraph{Secret hook into the font-adjustment code}
%
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec} {FontAdjustment}
 {
  \tl_put_right:Nx \l_@@_postadjust_tl {#1}
 }
%    \end{macrocode}
%
% \paragraph{Letterspacing}
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec} {LetterSpace}
 {
  \@@_update_featstr:n {letterspace=#1}
 }
%    \end{macrocode}
%
% \paragraph{Hyphenation character}
% This feature takes one of three arguments: `\opt{None}',
% \meta{glyph}, or \meta{slot}. If the input isn't the first,
% and it's one character, then it's the second; otherwise, it's
% the third.
%
% LuaTeX decouples hyphenation from font settings, so only \verb|HyphenChar=None| works
% for that engine.
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec} {HyphenChar}
 {
  \str_if_eq:nnTF {#1} {None}
   {
    \tl_put_right:Nn \l_@@_postadjust_tl
      { \@@_primitive_font_set_hyphenchar:Nn \font {-1} }
   }
   {
    \@@_warning:nx {only-xetex-feature} {HyphenChar}

    \tl_if_single:nTF {#1}
     { \tl_set:Nn \l_fontspec_hyphenchar_tl {`#1} }
     { \tl_set:Nn \l_fontspec_hyphenchar_tl { #1} }

    \@@_primitive_font_glyph_if_exist:NnTF \l_fontspec_font {\l_fontspec_hyphenchar_tl}
     {
      \tl_put_right:Nn \l_@@_postadjust_tl
        { \@@_primitive_font_set_hyphenchar:Nn \font { \l_fontspec_hyphenchar_tl } }
     }
     { \@@_error:nx {no-glyph}{#1} }

   }
 }
\@@_aff_error:n {HyphenChar}
%    \end{macrocode}
%
% \paragraph{Color}
% Hooks into pkg{xcolor}, which names its colours \texttt{\char`\\color@<name>}.
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec} {Color}
 {
  \cs_if_exist:cTF { \token_to_str:N \color@ #1 }
   {
    \convertcolorspec{named}{#1}{HTML}\l_@@_hexcol_tl
   }
   {
    \int_compare:nTF { \tl_count:n {#1} == 6 }
     { \tl_set:Nn \l_@@_hexcol_tl {#1} }
     {
      \int_compare:nTF { \tl_count:n {#1} == 8 }
       { \fontspec_parse_colour:viii #1 }
       {
        \bool_if:NF \l_@@_firsttime_bool
         { \@@_warning:nx {bad-colour} {#1} }
       }
     }
   }
 }
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_set:Npn \fontspec_parse_colour:viii #1#2#3#4#5#6#7#8
 {
  \tl_set:Nn \l_@@_hexcol_tl {#1#2#3#4#5#6}
  \tl_if_eq:NNF \l_@@_opacity_tl \g_@@_opacity_tl
   {
    \bool_if:NF \l_@@_firsttime_bool
     { \@@_warning:nx {opa-twice-col} {#7#8} }
   }
  \tl_set:Nn \l_@@_opacity_tl {#7#8}
 }
\aliasfontfeature{Color}{Colour}
%    \end{macrocode}
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec} {Opacity}
 {
  \int_set:Nn \l_@@_tmp_int {255}
  \@@_int_mult_truncate:Nn \l_@@_tmp_int { #1 }
  \tl_if_eq:NNF \l_@@_opacity_tl \g_@@_opacity_tl
   {
    \bool_if:NF \l_@@_firsttime_bool
     { \@@_warning:nx {opa-twice} {#1} }
   }
  \tl_set:Nx \l_@@_opacity_tl
   {
     \int_compare:nT { \l_@@_tmp_int <= "F } {0} % zero pad
     \int_to_hex:n { \l_@@_tmp_int }
   }
 }
%    \end{macrocode}
%
%
% \paragraph{Mapping}
%    \begin{macrocode}
%<*xetexx>
\@@_keys_define_code:nnn {fontspec-aat} {Mapping}
  {
    \tl_set:Nn \l_@@_mapping_tl { #1 }
  }
\@@_keys_define_code:nnn {fontspec-opentype} {Mapping}
  {
    \tl_set:Nn \l_@@_mapping_tl { #1 }
  }
%</xetexx>
%<*luatex>
\@@_keys_define_code:nnn {fontspec-opentype} {Mapping}
 {
  \str_if_eq:nnTF {#1} {tex-text}
   {
    \@@_warning:n {no-mapping-ligtex}
    \msg_redirect_name:nnn {fontspec} {no-mapping-ligtex} {none}
    \keys_set:nn {fontspec-opentype} { Ligatures=TeX }
   }
   { \@@_warning:n {no-mapping} }
 }
%</luatex>
%    \end{macrocode}
%
%
% \subsubsection{Continuous font axes}
%
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec} {Weight}
 {
  \@@_update_featstr:n{weight=#1}
 }
\@@_keys_define_code:nnn {fontspec} {Width}
 {
  \@@_update_featstr:n{width=#1}
 }
\@@_keys_define_code:nnn {fontspec} {OpticalSize}
%<*xetexx>
 {
  \bool_if:NTF \l_@@_ot_bool
   {
    \tl_set:Nn \l_@@_optical_size_tl {/ S = #1}
   }
   {
    \bool_if:NT \l_@@_mm_bool
     {
      \@@_update_featstr:n { optical size = #1 }
     }
   }
  \bool_if:nT { !\l_@@_ot_bool && !\l_@@_mm_bool }
   {
    \bool_if:NT \l_@@_firsttime_bool
     { \@@_warning:n {no-opticals} }
   }
 }
%</xetexx>
%<*luatex>
 {
  \tl_set:Nn \l_@@_optical_size_tl {/ S = #1}
 }
%</luatex>
%    \end{macrocode}
%
% \subsubsection{Font transformations}
% These are to be specified to apply directly to a font shape:
%    \begin{macrocode}
\keys_define:nn {fontspec}
 {
  FakeSlant .code:n =
   {
    \@@_update_featstr:n{slant=#1}
   },
  FakeSlant .default:n = {0.2}
}
\keys_define:nn {fontspec}
 {
  FakeStretch .code:n =
   {
    \@@_update_featstr:n{extend=#1}
   },
  FakeStretch .default:n = {1.2}
}
%<*xetexx>
\keys_define:nn {fontspec}
 {
  FakeBold .code:n =
   {
    \@@_update_featstr:n {embolden=#1}
   },
  FakeBold .default:n = {1.5}
 }
%</xetexx>
%<*luatex>
\keys_define:nn {fontspec}
 {
  FakeBold .code:n = { \@@_warning:n {fakebold-only-xetex} }
 }
%</luatex>
%    \end{macrocode}
% These are to be given to a shape that has no real bold/italic
% to signal that \pkg{fontspec} should automatically create `fake' shapes.
%
% The behaviour is currently that only if both \opt{AutoFakeSlant} \emph{and}
% \opt{AutoFakeBold} are specified, the bold italic is also faked.
%
% These features presently \emph{override} real shapes found in the font;
% in the future I'd like these features to be ignored in this case, instead.
% (This is just a bit harder to program in the current design of
% \pkg{fontspec}.)
%    \begin{macrocode}
\keys_define:nn {fontspec}
 {
  AutoFakeSlant .code:n =
   {
    \bool_if:NT \l_@@_firsttime_bool
     {
      \tl_set:Nn \l_@@_fake_slant_tl {#1}
      \clist_put_right:Nn \l_@@_fontfeat_it_clist {FakeSlant=#1}
      \tl_set_eq:NN \l_@@_fontname_it_tl \l_fontspec_fontname_tl
      \bool_set_false:N \l_@@_noit_bool

      \tl_if_empty:NF \l_@@_fake_embolden_tl
       {
        \clist_put_right:Nx \l_@@_fontfeat_bfit_clist
         {FakeBold=\l_@@_fake_embolden_tl}
        \clist_put_right:Nx \l_@@_fontfeat_bfit_clist {FakeSlant=#1}
        \tl_set_eq:NN \l_@@_fontname_bfit_tl \l_fontspec_fontname_tl
       }
     }
   },
  AutoFakeSlant .default:n = {0.2}
}
%    \end{macrocode}
% Same but reversed:
%    \begin{macrocode}
\keys_define:nn {fontspec}
 {
  AutoFakeBold .code:n =
   {
    \bool_if:NT \l_@@_firsttime_bool
     {
      \tl_set:Nn \l_@@_fake_embolden_tl {#1}
      \clist_put_right:Nn \l_@@_fontfeat_bf_clist {FakeBold=#1}
      \tl_set_eq:NN \l_@@_fontname_bf_tl \l_fontspec_fontname_tl
      \bool_set_false:N \l_@@_nobf_bool

      \tl_if_empty:NF \l_@@_fake_slant_tl
       {
        \clist_put_right:Nx \l_@@_fontfeat_bfit_clist
         {FakeSlant=\l_@@_fake_slant_tl}
        \clist_put_right:Nx \l_@@_fontfeat_bfit_clist {FakeBold=#1}
        \tl_set_eq:NN \l_@@_fontname_bfit_tl \l_fontspec_fontname_tl
       }
     }
   },
  AutoFakeBold .default:n = {1.5}
}
%    \end{macrocode}
%
%
% \subsubsection{Raw feature string}
% This allows savvy \XeTeX-ers to input font features manually if they have
% already memorised the OpenType abbreviations and don't mind not having error checking.
%    \begin{macrocode}
\@@_keys_define_code:nnn {fontspec-opentype} {RawFeature}
 {
  \@@_update_featstr:n {#1}
 }
\@@_keys_define_code:nnn {fontspec-aat} {RawFeature}
 {
  \@@_update_featstr:n {#1}
 }
%    \end{macrocode}
%
%
%
%
% \iffalse
%    \begin{macrocode}
%</fontspec&(xetexx|luatex)>
%    \end{macrocode}
% \fi
