summaryrefslogtreecommitdiff
path: root/macros/unicodetex/latex/fontspec/fontspec-code-internal.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/unicodetex/latex/fontspec/fontspec-code-internal.dtx')
-rw-r--r--macros/unicodetex/latex/fontspec/fontspec-code-internal.dtx1217
1 files changed, 1217 insertions, 0 deletions
diff --git a/macros/unicodetex/latex/fontspec/fontspec-code-internal.dtx b/macros/unicodetex/latex/fontspec/fontspec-code-internal.dtx
new file mode 100644
index 0000000000..375fc7be2e
--- /dev/null
+++ b/macros/unicodetex/latex/fontspec/fontspec-code-internal.dtx
@@ -0,0 +1,1217 @@
+%%^^A%% fontspec-code-internal.dtx -- part of FONTSPEC <wspr.io/fontspec>
+
+% \section{Internals}
+%
+% \iffalse
+% \begin{macrocode}
+%<*fontspec>
+% \end{macrocode}
+% \fi
+%
+% \subsection{The main function for setting fonts}
+%
+% \begin{macro}{\@@_select_font_family:nn}
+% This is the command that defines font families for use, the underlying
+% procedure of all \cmd\fontspec-like commands. Given a
+% list of font features (|#1|) for a requested font (|#2|),
+% it will define an NFSS
+% family for that font and put the family name (globally) into \cs{l_fontspec_family_tl}.
+% The \TeX\ `\cs{font}' command is (globally) stored in \cs{l_fontspec_font}.
+%
+% This macro does its processing inside a group to attempt to restrict the scope of its internal processing.
+% This works to some degree to insulate the internal commands from having to be manually cleared.
+%
+% Some often-used variables to know about:
+% \begin{itemize}
+% \item \cmd{\l_fontspec_fontname_tl} is used as the generic name of the font being defined.
+% \item \cmd{\l_@@_fontid_tl} is the unique identifier of the font with all its features.
+% \item \cmd{\l_@@_fontname_up_tl} is the font specifically to be used as the upright font.
+% \item \cmd{\l_@@_basename_tl} is the (immutable) original argument used for |*|-replacing.
+% \item \cmd{\l_fontspec_font} is the plain \TeX{} font of the upright font requested.
+% \end{itemize}
+% \begin{macrocode}
+\cs_new_protected:Nn \@@_select_font_family:nn
+ {
+%<debug>\typeout{^^J^^J::::::::::::::::::::::::::::::^^J:: fontspec_select:nn~ {#1}~ {#2} }
+ \group_begin:
+ \@@_font_suppress_not_found_error:
+ \@@_init:
+
+ \@@_sanitise_fontname:Nn \l_fontspec_fontname_tl {#2}
+ \@@_sanitise_fontname:Nn \l_@@_fontname_up_tl {#2}
+ \@@_sanitise_fontname:Nn \l_@@_basename_tl {#2}
+
+ \@@_if_detect_external:nT {#2}
+ { \keys_set:nn {fontspec-preparse-external} {Path} }
+
+ \keys_set_known:nn {fontspec-preparse-cfg} {#1}
+
+ \@@_init_ttc:n {#2}
+ \@@_load_external_fontoptions:Nn \l_fontspec_fontname_tl {#2}
+
+ \@@_extract_all_features:n {#1}
+ \tl_set:Nx \l_@@_fontid_tl { \tl_to_str:N \l_fontspec_fontname_tl-:-\tl_to_str:N \l_@@_all_features_clist }
+
+%<debug>\typeout{fontid: \l_@@_fontid_tl}
+
+ \@@_preparse_features:
+ \@@_load_font:
+ \@@_set_scriptlang:
+ \@@_get_features:n {}
+ \bool_set_false:N \l_@@_firsttime_bool
+
+ \@@_save_family_needed:nTF {#2}
+ {
+ \@@_save_family:nn {#1} {#2}
+%<debug>\@@_warning:nxx {defining-font} {#1} {#2}
+ }
+ {
+%<debug>\typeout{Font~ family~ already~ defined.}
+ }
+ \group_end:
+
+ \tl_set_eq:NN \l_fontspec_family_tl \g_@@_nfss_family_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\fontspec_select:nn}
+% This old name has been used by 3rd party packages so for compatibility:
+% \begin{macrocode}
+\cs_set_eq:NN \fontspec_select:nn \@@_select_font_family:nn %% deprecated, for compatibility only
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_sanitise_fontname:Nn}
+% Assigns font name |#2| to token list variable |#1| and strips extension(s) from it in the case of an external font.
+% We strip spaces for luatex for consistency with luaotfload, although I'm not sure this is necessary any more.
+% At one stage this also lowercased the name, but this step has been removed unless someone can remind me why it was necessary.
+% \begin{macrocode}
+\cs_new:Nn \@@_sanitise_fontname:Nn
+ {
+ \tl_set:Nx #1 {#2}
+%<LU> \tl_remove_all:Nn #1 {~}
+ \clist_map_inline:Nn \l_@@_extensions_clist
+ {
+ \tl_if_in:NnT #1 {##1}
+ {
+ \tl_remove_once:Nn #1 {##1}
+ \tl_set:Nn \l_@@_extension_tl {##1}
+ \clist_map_break:
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_if_detect_external:nT}
+% Check if either the fontname ends with a known font extension.
+% \begin{macrocode}
+\prg_new_conditional:Nnn \@@_if_detect_external:n {T}
+ {
+%<debug> \typeout{:: @@_if_detect_external:n { \exp_not:n {#1} } }
+ \clist_map_inline:Nn \l_@@_extensions_clist
+ {
+ \bool_set_false:N \l_@@_tmpa_bool
+ \exp_args:Nx % <- this should be handled earlier
+ \tl_if_in:nnT {#1 <= end_of_string} {##1 <= end_of_string}
+ { \bool_set_true:N \l_@@_tmpa_bool \clist_map_break: }
+ }
+ \bool_if:NTF \l_@@_tmpa_bool \prg_return_true: \prg_return_false:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_init_ttc:n}
+% For TTC fonts we assume they will be loading the italic/bold fonts from the same file,
+% so prepopulate the fontnames to avoid needing to do it manually.
+% \begin{macrocode}
+\cs_new:Nn \@@_init_ttc:n
+ {
+ \str_if_eq:eeT { \str_lowercase:f {\l_@@_extension_tl} } {.ttc}
+ {
+ \@@_sanitise_fontname:Nn \l_@@_fontname_it_tl {#1}
+ \@@_sanitise_fontname:Nn \l_@@_fontname_bf_tl {#1}
+ \@@_sanitise_fontname:Nn \l_@@_fontname_bfit_tl {#1}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_load_external_fontoptions:Nn}
+% Load a possible \texttt{.fontspec} font configuration file.
+% This file could set font-specific options for the font about to be loaded.
+% \begin{macrocode}
+\cs_new:Nn \@@_load_external_fontoptions:Nn
+ {
+ \bool_if:NT \l_@@_fontcfg_bool
+ {
+%<debug> \typeout{:: @@_load_external_fontoptions:Nn \exp_not:N #1 {#2} }
+ \@@_sanitise_fontname:Nn #1 {#2}
+ \tl_set:Nx \l_@@_ext_filename_tl {#1.fontspec}
+ \tl_remove_all:Nn \l_@@_ext_filename_tl {~}
+ \prop_if_in:NVF \g_@@_fontopts_prop #1
+ {
+ \exp_args:No \file_if_exist:nT { \l_@@_ext_filename_tl }
+ { \file_input:n { \l_@@_ext_filename_tl } }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_extract_all_features:}
+% \begin{macrocode}
+\cs_new:Nn \@@_extract_all_features:n
+ {
+%<debug> \typeout{:: @@_extract_all_features:n { \unexpanded {#1} } }
+ \bool_if:NTF \l_@@_disable_defaults_bool
+ {
+ \clist_set:Nx \l_@@_all_features_clist {#1}
+ }
+ {
+ \prop_get:NVNF \g_@@_fontopts_prop \l_fontspec_fontname_tl \l_@@_fontopts_clist
+ { \clist_clear:N \l_@@_fontopts_clist }
+
+ \prop_get:NVNF \g_@@_fontopts_prop \l_@@_family_label_tl \l_@@_family_fontopts_clist
+ { \clist_clear:N \l_@@_family_fontopts_clist }
+ \tl_clear:N \l_@@_family_label_tl
+
+ \clist_set:Nx \l_@@_all_features_clist
+ {
+ \g_@@_default_fontopts_clist,
+ \l_@@_family_fontopts_clist,
+ \l_@@_fontopts_clist,
+ #1
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_preparse_features:}
+% \darg{feature options}
+% \darg{font name}
+% Perform the (multi-step) feature parsing process.
+%
+% Convert the requested features to font definition
+% strings. First the features are parsed for information about font
+% loading (whether it's a named font or external font, etc.), and then
+% information is extracted for the names of the other shape fonts.
+% \begin{macrocode}
+\cs_new:Nn \@@_preparse_features:
+ {
+%<debug> \typeout{:: @@_preparse_features:}
+% \end{macrocode}
+% Detect if external fonts are to be used, possibly automatically, and
+% parse fontspec features for bold/italic fonts and their features.
+% \begin{macrocode}
+
+ \@@_keys_set_known:nxN {fontspec-preparse-external}
+ { \l_@@_all_features_clist }
+ \l_@@_keys_leftover_clist
+
+% \end{macrocode}
+% When \cmd{\l_fontspec_fontname_tl} is augmented with a prefix or whatever to create
+% the name of the upright font (\cmd{\l_@@_fontname_up_tl}), this latter is the new `general
+% font name' to use.
+% \begin{macrocode}
+ \tl_set_eq:NN \l_fontspec_fontname_tl \l_@@_fontname_up_tl
+ \@@_keys_set_known:nxN {fontspec-renderer} {\l_@@_keys_leftover_clist}
+ \l_@@_keys_leftover_clist
+ \@@_keys_set_known:nxN {fontspec-preparse} {\l_@@_keys_leftover_clist}
+ \l_@@_fontfeat_clist
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_load_font:}
+% \begin{macrocode}
+\cs_new:Nn \@@_load_font:
+ {
+%<debug>\typeout{:: @@_load_font}
+
+%<debug>\typeout{Set~ base~ font~ for~ preliminary~ analysis: \@@_construct_font_call:nn { \l_@@_fontname_up_tl } {} }
+ \@@_primitive_font_set:NnnF \l_@@_test_font
+ { \@@_construct_font_call:nn { \l_@@_fontname_up_tl } { \l_@@_pre_feat_sclist } }
+ { \f@size pt - 2sp }
+ { \@@_error:nx {font-not-found} {\l_@@_fontname_up_tl} }
+
+%<debug>\typeout{Set~ base~ font~ properly: \@@_construct_font_call:nn { \l_@@_fontname_up_tl } {} }
+ \@@_set_font_type:N \l_@@_test_font
+ \@@_primitive_font_gset:Onn \l_@@_fontface_cs_tl
+ { \@@_construct_font_call:nn { \l_@@_fontname_up_tl } { \l_@@_pre_feat_sclist } }
+ { \f@size pt + 2sp }
+
+ \l_@@_fontface_cs_tl % this is necessary for LuaLaTeX to check the scripts properly
+
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_construct_font_call:nn}
+% Constructs the complete font invocation.
+% \darg{Base name}
+% \darg{Extension}
+% \darg{TTC Index}
+% \darg{Renderer}
+% \darg{Optical size}
+% \darg{Font features}
+% We check if \meta{Font features} are empty and if so don't add in the separator colon.
+% \begin{macrocode}
+\cs_new:Nn \@@_construct_font_call:nnnnnn
+ {
+%<XE> " \@@_fontname_wrap:n { #1 #2 #3 }
+%<LU> " \@@_fontname_wrap:n { #1 #2 } #3
+ #4 #5
+ \str_if_eq:eeF {#6}{} {:#6} "
+ }
+% \end{macrocode}
+% In practice, we don't use the six-argument version, since most arguments are constructed on-the-fly:
+% \begin{macrocode}
+\cs_new:Nn \@@_construct_font_call:nn
+ {
+ \@@_construct_font_call:nnnnnn
+ {#1}
+ \l_@@_extension_tl
+ \l_@@_ttc_index_tl
+ \l_@@_renderer_tl
+ \l_@@_optical_size_tl
+ {#2}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_font_is_file:,\@@_font_is_name:}
+% The \cs{@@_fontname_wrap:n} command takes the font name and either passes it through unchanged or wraps it in the syntax for loading a font `by filename'.
+% \XeTeX's syntax is followed since \pkg{luaotfload} provides compatibility.
+% \begin{macrocode}
+\cs_new:Nn \@@_font_is_name:
+ {
+ \cs_set_eq:NN \@@_fontname_wrap:n \use:n
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new:Nn \@@_font_is_file:
+ {
+ \cs_set:Npn \@@_fontname_wrap:n ##1 { [ \l_@@_font_path_tl ##1 ] }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_set_scriptlang:}
+% Only necessary for OpenType fonts.
+% First check if the font supports scripts, then apply defaults if
+% none are explicitly requested. Similarly with the language settings.
+% \begin{macrocode}
+\cs_new:Nn \@@_set_scriptlang:
+ {
+%<debug> \typeout{:: _set_scriptlang:}
+ \bool_if:NT \l_@@_firsttime_bool
+ {
+ \tl_if_empty:NF \l_@@_script_name_tl
+ {
+%<debug> \typeout{:::: Script=\l_@@_script_name_tl, Language=\l_@@_lang_name_tl}
+ \keys_set:nx {fontspec-opentype} {Script=\l_@@_script_name_tl}
+ \keys_set:nx {fontspec-opentype} {Language=\l_@@_lang_name_tl}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_get_features:Nn}
+% This macro is a wrapper for |\keys_set:nn| which expands and adds a
+% default specification to the original passed options. It begins by
+% initialising the commands used to hold font-feature specific
+% strings.
+% Its argument is any additional features to prepend to the default.
+%
+% Do not set the colour if not explicitly spec'd else \verb|\color| (using
+% specials) will not work.
+% \begin{macrocode}
+\cs_new:Nn \@@_get_features:n
+ {
+%<debug> \typeout{:: @@_get_features:Nn { \exp_not:n {#1} } }
+ \@@_init_fontface:
+ \@@_keys_set_known:nxN {fontspec-renderer} {\l_@@_fontfeat_clist,#1}
+ \l_@@_keys_leftover_clist
+ \@@_keys_set_known:nxN {fontspec} {\l_@@_keys_leftover_clist} \l_@@_keys_leftover_clist
+%<*XE>
+ \bool_if:NTF \l_@@_ot_bool
+ {
+%<debug> \typeout{::: Setting~ keys~ for~ OpenType~ font~ features:~"\l_@@_keys_leftover_clist"}
+ \keys_set:nV {fontspec-opentype} \l_@@_keys_leftover_clist
+ }
+ {
+%<debug> \typeout{::: Setting~ keys~ for~ AAT/Graphite~ font~ features:~"\l_@@_keys_leftover_clist"}
+ \bool_if:nT { \l_@@_atsui_bool || \l_@@_graphite_bool }
+ { \keys_set:nV {fontspec-aat} \l_@@_keys_leftover_clist }
+ }
+%</XE>
+%<*LU>
+%<debug> \typeout{::: Setting~ keys~ for~ OpenType~ font~ features:~"\l_@@_keys_leftover_clist"}
+ \keys_set:nV {fontspec-opentype} \l_@@_keys_leftover_clist
+%</LU>
+
+ \tl_if_empty:NF \l_@@_mapping_tl
+ { \@@_update_featstr:n { mapping = \l_@@_mapping_tl } }
+
+ \str_if_eq:eeF { \l_@@_hexcol_tl \l_@@_opacity_tl }
+ { \c_@@_hexcol_tl \c_@@_opacity_tl }
+ { \@@_update_featstr:n { color = \l_@@_hexcol_tl\l_@@_opacity_tl } }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_save_family_needed:nTF}
+% Check if the family is unique and, if so, save its information.
+% (\cs{addfontfeature} and other macros use this data.)
+% Then the font family and its shapes are defined in the NFSS.
+%
+% Now we have a unique (in fact, too unique!) string that contains
+% the family name and every option in abbreviated form. This is used
+% with a counter to create a simple NFSS family name for the font we're
+% selecting.
+%
+% \begin{macrocode}
+\prg_new_conditional:Nnn \@@_save_family_needed:n { TF }
+ {
+
+%<debug> \typeout{save~ family:~ #1}
+%<debug> \typeout{== fontid_tl: "\l_@@_fontid_tl".}
+
+ \tl_if_empty:NTF \l_@@_nfss_fam_tl
+ {
+ \prop_get:NVNTF \g_@@_fontid_family_prop \l_@@_fontid_tl \l_@@_tmp_tl
+ {
+ \tl_gset_eq:NN \g_@@_nfss_family_tl \l_@@_tmp_tl
+ \prg_return_false:
+ }
+ {
+ \tl_set:Nx \l_@@_tmp_tl {#1}
+ \tl_remove_all:Nn \l_@@_tmp_tl { ~ }
+ \@@_save_fontid_family:VV \l_@@_fontid_tl \l_@@_tmp_tl
+ \prg_return_true:
+ }
+ }
+ {
+ \tl_gset_eq:NN \g_@@_nfss_family_tl \l_@@_nfss_fam_tl
+ \cs_undefine:c { g_@@_fontinfo_ \g_@@_nfss_family_tl _prop }
+ \prg_return_true:
+ }
+ }
+% \end{macrocode}
+% \begin{macrocode}
+\cs_new:Nn \@@_save_fontid_family:nn
+ {
+ \prop_get:NnNTF \g_@@_family_int_prop {#2} \l_@@_tmp_tl
+ {
+ \tl_set:Nx \l_@@_tmp_tl
+ { \int_eval:n { \l_@@_tmp_tl + 1 } }
+ }
+ { \tl_set:Nn \l_@@_tmp_tl { 0 } }
+ \prop_gput:NnV \g_@@_family_int_prop {#2} \l_@@_tmp_tl
+ \tl_gset:Nx \g_@@_nfss_family_tl { #2 ( \l_@@_tmp_tl ) }
+ \prop_gput:NnV \g_@@_fontid_family_prop {#1} \g_@@_nfss_family_tl
+ }
+\cs_generate_variant:Nn \@@_save_fontid_family:nn { VV }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_save_family:nn}
+% Saves the relevant font information for future processing.
+% \begin{macrocode}
+\cs_new:Nn \@@_save_family:nn
+ {
+ \@@_save_fontinfo:n {#2}
+ \@@_find_autofonts:
+ \DeclareFontFamily{\g_@@_nfss_enc_tl}{\g_@@_nfss_family_tl}{}
+ \@@_set_faces:
+ \@@_info:nxx {defining-font} {#1} {#2}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_save_fontinfo:n}
+% Saves the relevant font information for future processing.
+% \begin{macrocode}
+\cs_new:Nn \@@_save_fontinfo:n
+ {
+ \prop_new:c {g_@@_fontinfo_ \g_@@_nfss_family_tl _prop}
+ \prop_gput:cnx {g_@@_fontinfo_ \g_@@_nfss_family_tl _prop} {fontname} { #1 }
+ \prop_gput:cnx {g_@@_fontinfo_ \g_@@_nfss_family_tl _prop} {options} { \l_@@_all_features_clist }
+ \prop_gput:cnx {g_@@_fontinfo_ \g_@@_nfss_family_tl _prop} {fontdef}
+ {
+ \@@_construct_font_call:nn {\l_fontspec_fontname_tl}
+ { \l_@@_pre_feat_sclist \g_@@_rawfeatures_sclist }
+ }
+ \prop_gput:cnV {g_@@_fontinfo_ \g_@@_nfss_family_tl _prop} {script-num} \l_@@_script_int
+ \prop_gput:cnV {g_@@_fontinfo_ \g_@@_nfss_family_tl _prop} {lang-num} \l_@@_language_int
+ \prop_gput:cnV {g_@@_fontinfo_ \g_@@_nfss_family_tl _prop} {script-tag} \l_@@_script_tl
+ \prop_gput:cnV {g_@@_fontinfo_ \g_@@_nfss_family_tl _prop} {lang-tag} \l_@@_lang_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Setting font shapes in a family}
+%
+% All NFSS specifications take their default values, so if any of them
+% are redefined, the shapes will be selected to fit in with the
+% current state. For example, if \cmd\bfdefault\ is redefined to |b|, all
+% bold shapes defined by this package will also be assigned to |b|.
+%
+% The combination shapes are searched first because they use information that may be redefined in the single cases.
+% E.g., if no bold font is specified then |set_autofont| will attempt to set it.
+% This has subtle/small ramifications on the logic of choosing the bold italic font.
+%
+% \begin{macro}{\@@_find_autofonts:}
+% \begin{macrocode}
+\cs_new:Nn \@@_find_autofonts:
+ {
+ \bool_if:nF {\l_@@_noit_bool || \l_@@_nobf_bool}
+ {
+ \@@_set_autofont:Nnn \l_@@_fontname_bfit_tl {\l_@@_fontname_it_tl} {/B}
+ \@@_set_autofont:Nnn \l_@@_fontname_bfit_tl {\l_@@_fontname_bf_tl} {/I}
+ \@@_set_autofont:Nnn \l_@@_fontname_bfit_tl {\l_fontspec_fontname_tl} {/BI}
+ }
+
+ \bool_if:NF \l_@@_nobf_bool
+ {
+ \@@_set_autofont:Nnn \l_@@_fontname_bf_tl {\l_fontspec_fontname_tl} {/B}
+ }
+
+ \bool_if:NF \l_@@_noit_bool
+ {
+ \@@_set_autofont:Nnn \l_@@_fontname_it_tl {\l_fontspec_fontname_tl} {/I}
+ }
+
+ \@@_set_autofont:Nnn \l_@@_fontname_bfsl_tl {\l_@@_fontname_sl_tl} {/B}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_set_faces:}
+% \begin{macrocode}
+\cs_new:Nn \@@_set_faces:
+ {
+ \@@_add_nfssfont:nnnn \mddefault \shapedefault \l_fontspec_fontname_tl \l_@@_fontfeat_up_clist
+ \@@_add_nfssfont:nnnn \bfdefault \shapedefault \l_@@_fontname_bf_tl \l_@@_fontfeat_bf_clist
+ \@@_add_nfssfont:nnnn \mddefault \itdefault \l_@@_fontname_it_tl \l_@@_fontfeat_it_clist
+ \@@_add_nfssfont:nnnn \mddefault \sldefault \l_@@_fontname_sl_tl \l_@@_fontfeat_sl_clist
+ \@@_add_nfssfont:nnnn \bfdefault \itdefault \l_@@_fontname_bfit_tl \l_@@_fontfeat_bfit_clist
+ \@@_add_nfssfont:nnnn \bfdefault \sldefault \l_@@_fontname_bfsl_tl \l_@@_fontfeat_bfsl_clist
+ \prop_map_inline:Nn \l_@@_nfssfont_prop { \@@_set_faces_aux:nnnnn ##2 }
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new:Nn \@@_set_faces_aux:nnnnn
+ {
+ \fontspec_complete_fontname:Nn \l_@@_curr_fontname_tl {#3}
+ \@@_make_font_shapes:Nnnnn \l_@@_curr_fontname_tl {#1} {#2} {#4} {#5}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\fontspec_complete_fontname:Nn}
+% This macro defines |#1| as the input with any |*| tokens of its input
+% replaced by the font name. This lets us define supplementary fonts in full
+% (``\texttt{Baskerville Semibold}'') or in abbreviation (``\texttt{* Semibold}'').
+% \begin{macrocode}
+\cs_new:Nn \fontspec_complete_fontname:Nn
+ {
+ \tl_set:Nx #1 {#2}
+ \tl_replace_all:Nnx #1 {*} {\l_@@_basename_tl}
+%<LU> \tl_remove_all:Nn #1 {~}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_add_nfssfont:nnnn}
+% \darg{series}
+% \darg{shape}
+% \darg{fontname}
+% \darg{fontspec features}
+% \begin{macrocode}
+\cs_new:Nn \@@_add_nfssfont:nnnn
+ {
+ \tl_set:Nx \l_@@_this_font_tl {#3}
+
+ \tl_if_empty:xTF {#4}
+ { \clist_set:Nn \l_@@_sizefeat_clist {Size={-}} }
+ { \@@_keys_set_known:nxN {fontspec-preparse-nested} {#4} \l_@@_tmp_tl }
+
+ \tl_if_empty:NF \l_@@_this_font_tl
+ {
+ \prop_put:Nxx \l_@@_nfssfont_prop {#1/#2}
+ { {#1}{#2}{\l_@@_this_font_tl}{#4}{\l_@@_sizefeat_clist} }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Fonts}
+%
+% \begin{macro}{\@@_set_font_type:N}
+% Now check if the font is to be rendered with \ATSUI\ or Harfbuzz. This will either
+% be automatic (based on the font type), or specified by the user via a font feature.
+%
+% This macro sets booleans
+% accordingly depending if the font in \cmd\l_fontspec_test_font\ is an \AAT\
+% font or an OpenType font or a font with feature axes (either \AAT\ or
+% Multiple Master), respectively.
+% \begin{macrocode}
+\cs_new:Nn \@@_set_font_type:N
+ {
+%<debug> \typeout{:: @@_set_font_type:}
+%<*XE>
+ \bool_set_false:N \l_@@_tfm_bool
+ \bool_set_false:N \l_@@_atsui_bool
+ \bool_set_false:N \l_@@_ot_bool
+ \bool_set_false:N \l_@@_mm_bool
+ \bool_set_false:N \l_@@_graphite_bool
+ \ifcase\XeTeXfonttype #1
+%<debug> \typeout{:::: TFM}
+ \bool_set_true:N \l_@@_tfm_bool
+ \or
+%<debug> \typeout{:::: AAT}
+ \bool_set_true:N \l_@@_atsui_bool
+ \tl_if_empty:NT \l_@@_renderer_tl { \tl_set:Nn \l_@@_renderer_tl {/AAT} }
+ \ifnum\XeTeXcountvariations #1 > 0\relax
+%<debug> \typeout{:::: MM}
+ \bool_set_true:N \l_@@_mm_bool
+ \fi
+ \or
+%<debug> \typeout{:::: OpenType}
+ \bool_set_true:N \l_@@_ot_bool
+ \tl_if_empty:NT \l_@@_renderer_tl { \tl_set:Nn \l_@@_renderer_tl {/OT} }
+ \or
+%<debug> \typeout{:::: Graphite}
+ \bool_set_true:N \l_@@_graphite_bool
+ \tl_if_empty:NT \l_@@_renderer_tl { \tl_set:Nn \l_@@_renderer_tl {/GR} }
+ \fi
+%</XE>
+% \end{macrocode}
+% If automatic, the \cmd{\l_@@_renderer_tl} token list will still be
+% empty (other suffices that could be added will be later in the feature
+% processing), and if it is indeed still empty, assign it a value so that the
+% other weights of the font are specifically loaded with the same renderer.
+%
+% LuaTeX only supports one:
+% \begin{macrocode}
+%<*LU>
+ \bool_set_true:N \l_@@_ot_bool
+%</LU>
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_set_autofont:Nnn}
+% \darg{Font name tl}
+% \darg{Base font name}
+% \darg{Font name modifier}
+%
+% This function looks for font with \meta{name} and \meta{modifier} |#2#3|, and if found (i.e., different to font with name |#2|) stores it in tl |#1|. A modifier is something like |/B| to look for a bold font, for example.
+%
+% We can't match external fonts in this way (in \XeTeX\ anyway; todo: test with LuaTeX).
+% If \meta{font name tl} is not empty, then it's already been specified by the user so abort.
+% If \meta{Base font name} is not given, we also abort for obvious reasons.
+%
+% If \meta{font name tl} is empty, then proceed.
+% If not found, \meta{font name tl} remains empty.
+% Otherwise, we have a match.
+% \begin{macrocode}
+\cs_new:Nn \@@_set_autofont:Nnn
+ {
+ \bool_if:NF \l_@@_external_bool
+ {
+ \tl_if_empty:xF {#2}
+ {
+ \tl_if_empty:NT #1
+ {
+ \@@_if_autofont:nnTF {#2} {#3}
+ { \tl_set:Nx #1 {#2#3} }
+ { \@@_info:nx {no-font-shape} {#2#3} }
+ }
+ }
+ }
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\prg_new_conditional:Nnn \@@_if_autofont:nn {T,TF}
+ {
+ \group_begin:
+ \@@_primitive_font_set:Nnn \l_@@_tmpa_font { \@@_construct_font_call:nn {#1} { \l_@@_pre_feat_sclist } } { \f@size pt + 1sp }
+ \@@_primitive_font_set:Nnn \l_@@_tmpb_font { \@@_construct_font_call:nn {#1#2} { \l_@@_pre_feat_sclist } } { \f@size pt + 1sp }
+ \str_if_eq:eeTF { \@@_primitive_font_get_name:N \l_@@_tmpa_font } { \@@_primitive_font_get_name:N \l_@@_tmpb_font }
+ { \group_end: \prg_return_false: }
+ { \group_end: \prg_return_true: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_make_font_shapes:Nnnnn}
+% \darg{Font name}
+% \darg{Font series}
+% \darg{Font shape}
+% \darg{Font features}
+% \darg{Size features}
+% This macro eventually uses \cs{DeclareFontShape} to define the font shape in
+% question.
+% \begin{macrocode}
+\cs_new:Nn \@@_make_font_shapes:Nnnnn
+ {
+ \group_begin:
+ \@@_keys_set_known:nxN {fontspec-preparse-external} { #4 } \l_@@_leftover_clist
+ \@@_load_fontname:Nn \l_fontspec_fontname_tl {#1}
+ \@@_declare_shape:nnxx {#2} {#3} { \l_@@_fontopts_clist, \l_@@_leftover_clist } {#5}
+ \group_end:
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new:Nn \@@_load_fontname:Nn
+ {
+%<debug> \typeout{:: @@_load_fontname:Nn \exp_not:N #1 (#1) {#2} }
+ \@@_load_external_fontoptions:Nn #1 {#2}
+ \prop_get:NVNF \g_@@_fontopts_prop #1 \l_@@_fontopts_clist
+ { \clist_clear:N \l_@@_fontopts_clist }
+ \keys_set_groups:nnV {fontspec/fontname} {getfontname} \l_@@_fontopts_clist
+ \@@_primitive_font_set:OnnF \l_@@_fontface_cs_tl
+ { \@@_construct_font_call:nn {#1} { \l_@@_pre_feat_sclist } } { \f@size pt + 2sp }
+ { \@@_error:nx {font-not-found} {#2} }
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\keys_define:nn {fontspec/fontname}
+ {
+ Font .tl_set:N = \l_fontspec_fontname_tl ,
+ Font .groups:n = {getfontname} ,
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_declare_shape:nnnn}
+% \darg{Font series}
+% \darg{Font shape}
+% \darg{Font features}
+% \darg{Size features}
+% Wrapper for \cmd\DeclareFontShape.
+% And finally the actual font shape declaration using \cmd\l_@@_nfss_tl\ defined above.
+% \cmd\l_@@_postadjust_tl\ is defined in various places to deal with things like the hyphenation
+% character and interword spacing.
+%
+% The main part is to loop through \feat{SizeFeatures} arguments, which are of the form
+% {\par\centering |SizeFeatures={{<one>},{<two>},{<three>}}|.\par}
+% \begin{macrocode}
+\cs_new:Nn \@@_declare_shape:nnnn
+ {
+%<debug>\typeout{=~ declare_shape:~{\l_fontspec_fontname_tl}~{#1}~{#2}}
+ \tl_build_begin:N \l_@@_nfss_tl
+ \tl_build_begin:N \l_@@_nfss_sc_tl
+ \tl_set_eq:NN \l_@@_saved_fontname_tl \l_fontspec_fontname_tl
+
+ \exp_args:Nx \clist_map_inline:nn {#4} { \@@_setup_single_size:nn {#3} {##1} }
+
+ \tl_build_end:N \l_@@_nfss_tl
+ \tl_build_end:N \l_@@_nfss_sc_tl
+
+ \@@_declare_shapes_normal:nn {#1} {#2}
+ \@@_declare_shapes_smcaps:nn {#1} {#2}
+ \@@_declare_shape_slanted:nn {#1} {#2}
+ \@@_declare_shapes_bx:nn {#1} {#2}
+ \@@_declare_shape_loginfo:nn {#1} {#2}
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_generate_variant:Nn \@@_declare_shape:nnnn {nnxx}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_setup_single_size:nn}
+% \begin{macrocode}
+\cs_new:Nn \@@_setup_single_size:nn
+ {
+ \tl_clear:N \l_@@_size_tl
+ \tl_set_eq:NN \l_@@_sizedfont_tl \l_@@_saved_fontname_tl % in case not spec'ed
+
+ \keys_set_known:nxN {fontspec-sizing} { \exp_after:wN \use:n #2 }
+ \l_@@_sizing_leftover_clist
+ \tl_if_empty:NT \l_@@_size_tl { \@@_error:n {no-size-info} }
+%<debug>\typeout{==~ size:~\l_@@_size_tl}
+
+ % "normal"
+ \@@_load_fontname:Nn \l_fontspec_fontname_tl {\l_@@_sizedfont_tl}
+ \@@_setup_nfss:Nnnn \l_@@_nfss_tl {#1} {\l_@@_sizing_leftover_clist} {}
+%<debug> \typeout{===~ sized~ font:~ \l_@@_sizedfont_tl}
+
+ % small caps
+ \clist_set_eq:NN \l_@@_fontfeat_curr_clist \l_@@_fontfeat_sc_clist
+
+ \bool_if:NF \l_@@_nosc_bool
+ {
+ \tl_if_empty:NTF \l_@@_fontname_sc_tl
+ {
+ \@@_make_smallcaps:TF
+ {
+%<debug>\typeout{====~Small~ caps~ found.}
+ \clist_put_left:Nn \l_@@_fontfeat_curr_clist {Letters=SmallCaps}
+ }
+ {
+%<debug>\typeout{====~Small~ caps~ not~ found.}
+ \bool_set_true:N \l_@@_nosc_bool
+ }
+ }
+ { \@@_load_fontname:Nn \l_fontspec_fontname_tl {\l_@@_fontname_sc_tl} }% local for each size
+ }
+
+ \bool_if:NF \l_@@_nosc_bool
+ {
+ \@@_setup_nfss:Nnnn \l_@@_nfss_sc_tl
+ {#1} {\l_@@_sizing_leftover_clist} {\l_@@_fontfeat_curr_clist}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_setup_nfss:Nnnn}
+% \begin{macrocode}
+\cs_new:Nn \@@_setup_nfss:Nnnn
+ {
+%<debug>\typeout{====~Setup~NFSS~shape:~<\l_@@_size_tl>~\l_fontspec_fontname_tl}
+
+ \@@_get_features:n { #2 , #3 , #4 }
+%<debug>\typeout{====~Gathered~features:~\g_@@_rawfeatures_sclist}
+
+ \tl_if_empty:NF \l_@@_scale_tl
+ {
+ \tl_set:Nx \l_@@_scale_tl { s*[\l_@@_scale_tl] }
+ }
+
+ \tl_build_put_right:Nx #1
+ {
+ <\l_@@_size_tl> \l_@@_scale_tl
+ \@@_construct_font_call:nn { \l_fontspec_fontname_tl }
+ { \l_@@_pre_feat_sclist \g_@@_rawfeatures_sclist }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_declare_shapes_normal:nn}
+% \begin{macrocode}
+\cs_new:Nn \@@_declare_shapes_normal:nn
+ {
+ \@@_DeclareFontShape:xxxxxx {\g_@@_nfss_enc_tl} {\g_@@_nfss_family_tl}
+ {#1} {#2} {\l_@@_nfss_tl}{\l_@@_postadjust_tl}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_declare_shapes_smcaps:nn}
+% \begin{macrocode}
+\cs_new:Nn \@@_declare_shapes_smcaps:nn
+ {
+ \tl_if_empty:NF \l_@@_nfss_sc_tl
+ {
+ \@@_DeclareFontShape:xxxxxx {\g_@@_nfss_enc_tl} {\g_@@_nfss_family_tl} {#1}
+ { \@@_combo_sc_shape:n {#2} } {\l_@@_nfss_sc_tl} {\l_@@_postadjust_tl}
+ }
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new:Nn \@@_combo_sc_shape:n
+ {
+ \tl_if_exist:cTF { \@@_shape_merge:nn {#1} {\scdefault} }
+ { \tl_use:c { \@@_shape_merge:nn {#1} {\scdefault} } }
+ { \scdefault }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_DeclareFontShape:nnnnnn}
+% \begin{macrocode}
+\cs_new:Nn \@@_DeclareFontShape:nnnnnn
+ {
+%<debug>\typeout{DeclareFontShape:~{#1}{#2}{#3}{#4}...}
+ \group_begin:
+ \normalsize
+ \cs_undefine:c {#1/#2/#3/#4/\f@size}
+ \group_end:
+ \DeclareFontShape{#1}{#2}{#3}{#4}{#5}{#6}
+ }
+\cs_generate_variant:Nn \@@_DeclareFontShape:nnnnnn {xxxxxx}
+% \end{macrocode}
+%
+% \begin{macro}{\@@_declare_shape_slanted:nn}
+% This extra stuff for the slanted shape substitution is a little bit awkward.
+% We define the slanted shape to be a synonym for it when (a)~we're defining an italic font, but also (b)~when the default slanted shape isn't `it'.
+% (Presumably this turned up once in a test and I realised it caused problems. I doubt this would happen much.)
+%
+% We should test when a slanted font has been specified and not run this code if so, but the \verb|\@@_set_slanted:| code will overwrite this anyway if necessary.
+% \begin{macrocode}
+\cs_new:Nn \@@_declare_shape_slanted:nn
+ {
+ \bool_if:nT
+ {
+ \str_if_eq_p:ee {#2} {\itdefault} &&
+ !(\str_if_eq_p:ee {\itdefault} {\sldefault})
+ }
+ {
+ \@@_DeclareFontShape:xxxxxx {\g_@@_nfss_enc_tl}{\g_@@_nfss_family_tl}{#1}{\sldefault}
+ {<->ssub*\g_@@_nfss_family_tl/#1/\itdefault}{\l_@@_postadjust_tl}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_declare_shapes_bx:nn}
+% Similar processing for setting up b/bx substitutions.
+% \begin{macrocode}
+\cs_new:Nn \@@_declare_shapes_bx:nn
+ {
+ \bool_if:nT
+ {
+ \str_if_eq_p:ee {#1} {\bfdefault} &&
+ !(\str_if_eq_p:ee {\bfdefault} {bx})
+ }
+ {
+ % bx/?
+ \@@_DeclareFontShape:xxxxxx {\g_@@_nfss_enc_tl} {\g_@@_nfss_family_tl}
+ {bx} {#2}
+ { <->ssub*\g_@@_nfss_family_tl/\bfdefault/#2 }
+ { \l_@@_postadjust_tl }
+
+ % bx/sc -> b/sc
+ \tl_if_empty:NF \l_@@_nfss_sc_tl
+ {
+ \@@_DeclareFontShape:xxxxxx {\g_@@_nfss_enc_tl} {\g_@@_nfss_family_tl}
+ {bx} { \@@_combo_sc_shape:n {#2} }
+ { <->ssub*\g_@@_nfss_family_tl/\bfdefault/#2 }
+ { \l_@@_postadjust_tl }
+ }
+
+ % bx/sl -> bx/it
+ \bool_if:nT
+ {
+ \str_if_eq_p:ee {#2} {\itdefault} &&
+ !(\str_if_eq_p:ee {\itdefault} {\sldefault})
+ }
+ {
+ \@@_DeclareFontShape:xxxxxx {\g_@@_nfss_enc_tl} {\g_@@_nfss_family_tl}
+ {bx} {\sldefault}
+ { <->ssub*\g_@@_nfss_family_tl/bx/\itdefault }
+ { \l_@@_postadjust_tl }
+ }
+
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_declare_shape_loginfo:nn}
+% Lastly some informative messaging.
+% \begin{macrocode}
+\cs_new:Nn \@@_declare_shape_loginfo:nn
+ {
+ \tl_gput_right:Nx \g_@@_defined_shapes_tl
+ {
+ \exp_not:n { \\ }
+ -~ \exp_not:N \str_case:nn {#1/#2}
+ {
+ {\mddefault/\shapedefault} {'normal'~}
+ {\bfdefault/\shapedefault} {'bold'~}
+ {\mddefault/\itdefault} {'italic'~}
+ {\mddefault/\sldefault} {'slanted'~}
+ {\bfdefault/\itdefault} {'bold~ italic'~}
+ {\bfdefault/\sldefault} {'bold~ slanted'~}
+ } (#1/#2)~
+ with~ NFSS~ spec.:~
+ \l_@@_nfss_tl
+ \exp_not:n { \\ }
+ -~ \exp_not:N \str_case:nn { #1 / \@@_combo_sc_shape:n {#2} }
+ {
+ {\mddefault/\scdefault} {'small~ caps'~}
+ {\bfdefault/\scdefault} {'bold~ small~ caps'~}
+ {\mddefault/\scitdefault} {'italic~ small~ caps'~}
+ {\bfdefault/\scitdefault} {'bold~ italic~ small~ caps'~}
+ {\mddefault/\scsldefault} {'slanted~ small~ caps'~}
+ {\bfdefault/\scsldefault} {'bold~ slanted~ small~ caps'~}
+ }~( #1 / \@@_combo_sc_shape:n {#2} )~
+ with~ NFSS~ spec.:~
+ \l_@@_nfss_sc_tl
+ \tl_if_empty:fF {\l_@@_postadjust_tl}
+ {
+ \exp_not:N \\ and~ font~ adjustment~ code:
+ \exp_not:N \\ \l_@@_postadjust_tl
+ }
+ }
+ }
+% \end{macrocode}
+% Maybe |\str_if_eq:eeF| would be better?
+% \end{macro}
+%
+%
+% \subsubsection{Features}
+%
+% \begin{macro}{\l_@@_pre_feat_sclist}
+% These are the features always applied to a font selection before other
+% features.
+% \begin{macrocode}
+\tl_set:Nn \l_@@_pre_feat_sclist
+%<*XE>
+ {
+ \bool_if:NT \l_@@_ot_bool
+ {
+ \tl_if_empty:NF \l_@@_script_tl { script = \l_@@_script_tl ; }
+ \tl_if_empty:NF \l_@@_lang_tl { language = \l_@@_lang_tl ; }
+ }
+ }
+%</XE>
+%<*LU>
+ {
+ mode = \l_@@_mode_tl ;
+ \tl_if_empty:NF \l_@@_shaper_tl { shaper = \l_@@_shaper_tl ; }
+ \tl_if_empty:NF \l_@@_script_tl { script = \l_@@_script_tl ; }
+ \tl_if_empty:NF \l_@@_lang_tl { language = \l_@@_lang_tl ; }
+ }
+%</LU>
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_make_ot_smallcaps:TF}
+% \label{mac:makesmallcaps}
+% This macro checks if the font contains small caps.
+% \begin{macrocode}
+%<LU>\cs_new:Nn \@@_make_smallcaps:TF
+%<XE>\cs_new:Nn \@@_make_ot_smallcaps:TF
+ {
+ \exp_args:No \@@_check_ot_feat:NnTF \l_@@_fontface_cs_tl {smcp} {#1} {#2}
+ }
+%<*XE>
+\cs_new:Nn \@@_make_smallcaps:TF
+ {
+ \bool_if:NTF \l_@@_ot_bool
+ { \@@_make_ot_smallcaps:TF {#1} {#2} }
+ {
+ \bool_if:NT \l_@@_atsui_bool
+ {
+ \exp_args:No \@@_make_AAT_feature_string:NnnTF
+ \l_@@_fontface_cs_tl {3} {3} {#1} {#2}
+ }
+ }
+ }
+%</XE>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_update_featstr:n}
+% \cmd{\g_@@_rawfeatures_sclist} is the string used to define the list of specific
+% font features. Each time another font feature is requested, this
+% macro is used to add that feature to the list. Font features are
+% separated by semicolons.
+% \begin{macrocode}
+\cs_new:Nn \@@_update_featstr:n
+ {
+%<debug> \typeout{:::: @@_update_featstr:n {#1}}
+ \bool_if:NF \l_@@_firsttime_bool
+ {
+ \tl_gset:Nx \g_@@_single_feat_tl { #1 }
+%<debug> \typeout{::::~ Adding~ feature.}
+ \tl_gput_right:Nx \g_@@_rawfeatures_sclist {#1;}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_remove_clashing_featstr:n}
+% \begin{macrocode}
+\cs_new:Nn \@@_remove_clashing_featstr:n
+ {
+%<debug> \typeout{:::: @@_remove_clashing_featstr:n {#1}}
+ \clist_map_inline:nn {#1}
+ {
+%<debug> \typeout{::::~ Removing~ feature~ "##1;"}
+ \tl_gremove_all:Nn \g_@@_rawfeatures_sclist {##1;}
+ }
+ }
+\cs_generate_variant:Nn \@@_remove_clashing_featstr:n {x}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Initialisation}
+%
+% \begin{macro}{\@@_init:}
+% Initialisations that need to occur once per fontspec font invocation.
+% (Some of these may be redundant.
+% Check whether they're assigned to globally or not.)
+% \begin{macrocode}
+\cs_set:Npn \@@_init:
+ {
+%<debug> \typeout{:: @@_init:}
+ \bool_set_false:N \l_@@_ot_bool
+ \bool_set_true:N \l_@@_firsttime_bool
+ \@@_font_is_name:
+ \tl_clear:N \l_@@_font_path_tl
+ \tl_clear:N \l_@@_optical_size_tl
+ \tl_clear:N \l_@@_ttc_index_tl
+ \tl_clear:N \l_@@_renderer_tl
+ \tl_gclear:N \g_@@_defined_shapes_tl
+ \tl_gclear:N \g_@@_curr_series_tl
+ \tl_gset_eq:NN \g_@@_nfss_enc_tl \g_fontspec_encoding_tl
+%<*LU>
+ \tl_set:Nn \l_@@_mode_tl {node}
+ \int_set:Nn \prehyphenchar { `\- } % fixme
+ \int_zero:N \posthyphenchar % fixme
+ \int_zero:N \preexhyphenchar % fixme
+ \int_zero:N \postexhyphenchar % fixme
+%</LU>
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_init_fontface:}
+% Executed in \cs{@@_get_features:Nn}.
+% \begin{macrocode}
+\cs_new:Nn \@@_init_fontface:
+ {
+ \tl_gclear:N \g_@@_rawfeatures_sclist
+ \tl_clear:N \l_@@_scale_tl
+ \tl_set_eq:NN \l_@@_opacity_tl \c_@@_opacity_tl
+ \tl_set_eq:NN \l_@@_hexcol_tl \c_@@_hexcol_tl
+ \tl_set_eq:NN \l_@@_postadjust_tl \c_@@_postadjust_tl
+ \tl_clear:N \l_@@_wordspace_adjust_tl
+ \tl_clear:N \l_@@_punctspace_adjust_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Miscellaneous}
+%
+% \begin{macro}{\@@_ot_validate_tag:n}
+% This macro takes an OpenType tag and validates it.
+% \begin{macrocode}
+%<*LU>
+% \end{macrocode}
+% \begin{macrocode}
+\cs_new_protected:Nn \@@_ot_validate_tag:n
+ {
+ \@@_ot_validate_tag:w #1 \q_nil
+ }
+\cs_generate_variant:Nn \@@_ot_validate_tag:n {x}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_set:Npn \@@_ot_validate_tag:w #1 #2 \q_nil
+ {
+ \bool_if:nTF { \str_if_eq_p:nn {#1} {+} || \str_if_eq_p:nn {#1} {-} }
+ { \@@_ot_validate_tag_aux:w #2 \c_empty_tl \c_empty_tl \q_nil }
+ { \@@_ot_validate_tag_aux:w #1#2 \c_empty_tl \c_empty_tl \q_nil }
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_set:Npn \@@_ot_validate_tag_aux:w #1#2#3#4#5 \q_nil
+ {
+ \int_compare:nT { \tl_count:n {#5} > 2 }
+ { \@@_error:nx {ot-tag-too-long} {#1#2#3#4#5} }
+ }
+% \end{macrocode}
+% \begin{macrocode}
+%</LU>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_iv_str_to_num:Nn}
+% This macro takes a four character string and converts it to the
+% numerical representation required for \XeTeX\ OpenType script/language/feature
+% purposes. The output is stored in |#1|.
+%
+% This code is not used in Lua\TeX, as the checking for that engine is done via Lua code
+% provided by \pkg{luaotfload}.
+% \begin{macrocode}
+%<*XE>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new:Nn \@@_iv_str_to_num:Nn
+ {
+%<debug>\typeout{_iv_str_to_num:~#1~/~#2}
+ \@@_strip_leading_sign:Nw #1#2 \q_nil
+ }
+\cs_generate_variant:Nn \@@_iv_str_to_num:Nn {Nx}
+% \end{macrocode}
+%
+% The input can be of the form of any of these:
+% `|abcd|', `|abc|', `|abc |', `|ab|', `|ab |', \etc.
+% (It is assumed the first two chars are \emph{always} not spaces.) So this macro
+% reads in the string padded with \cmd\@empty s,
+% and anything beyond four chars is snipped. The \cmd\@empty s then are used to reconstruct
+% the spaces in the string to number calculation.
+%
+% For backwards compatibility this code also strips a leading |+| or |-|.
+%
+% \begin{macrocode}
+\cs_set:Npn \@@_strip_leading_sign:Nw #1#2#3 \q_nil
+ {
+ \bool_if:nTF { \str_if_eq_p:nn {#2} {+} || \str_if_eq_p:nn {#2} {-} }
+ { \@@_iv_str_to_num:w #1 \q_nil #3 \c_empty_tl \c_empty_tl \q_nil }
+ { \@@_iv_str_to_num:w #1 \q_nil #2#3 \c_empty_tl \c_empty_tl \q_nil }
+ }
+% \end{macrocode}
+% If input string (after sign is stripped) is more than 4 chars, \verb|#6| will contain
+% `\meta{excess}\cs{c_empty_tl}\cs{c_empty_tl}'. Therefore use \verb|#6| to verify string length.
+% \begin{macrocode}
+\cs_set:Npn \@@_iv_str_to_num:w #1 \q_nil #2#3#4#5#6 \q_nil
+ {
+ \int_compare:nT { \tl_count:n {#6} > 2 }
+ { \@@_error:nx {ot-tag-too-long} {#2#3#4#5#6} }
+
+ \int_set:Nn #1
+ {
+ `#2 * "1000000
+ + `#3 * "10000
+ + \ifx \c_empty_tl #4 32 \else `#4 \fi * "100
+ + \ifx \c_empty_tl #5 32 \else `#5 \fi
+ }
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</XE>
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \iffalse
+% \begin{macrocode}
+%</fontspec>
+% \end{macrocode}
+% \fi
+
+
+\endinput
+
+% /©
+% ------------------------------------------------
+% The FONTSPEC package <wspr.io/fontspec>
+% ------------------------------------------------
+% Copyright 2004-2020 Will Robertson, LPPL "maintainer"
+% Copyright 2009-2015 Khaled Hosny
+% Copyright 2013 Philipp Gesang
+% Copyright 2013-2016 Joseph Wright
+% ------------------------------------------------
+% This package is free software and may be redistributed and/or modified under
+% the conditions of the LaTeX Project Public License, version 1.3c or higher
+% (your choice): <http://www.latex-project.org/lppl/>.
+% ------------------------------------------------
+% ©/