diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/fontspec/fontspec-code-internal.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/fontspec/fontspec-code-internal.dtx | 1190 |
1 files changed, 1190 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/fontspec/fontspec-code-internal.dtx b/Master/texmf-dist/source/latex/fontspec/fontspec-code-internal.dtx new file mode 100644 index 00000000000..a8d8c49763c --- /dev/null +++ b/Master/texmf-dist/source/latex/fontspec/fontspec-code-internal.dtx @@ -0,0 +1,1190 @@ +%%^^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_lower_case: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:Nnn \l_fontspec_font + { \@@_construct_font_call:nn { \l_@@_fontname_up_tl } {} } {\f@size pt} + \@@_primitive_font_if_null:NT \l_fontspec_font { \@@_error:nx {font-not-found} {\l_@@_fontname_up_tl} } + \@@_set_font_type:N \l_fontspec_font +%<debug>\typeout{Set~ base~ font~ properly: \@@_construct_font_call:nn { \l_@@_fontname_up_tl } {} } + \@@_primitive_font_gset:Nnn \l_fontspec_font + { \@@_construct_font_call:nn { \l_@@_fontname_up_tl } {} } {\f@size pt} + \l_fontspec_font % 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_fontspec_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:NTF \l_@@_script_name_tl + { + \@@_check_script:NnTF \l_fontspec_font {latn} + { + \tl_set:Nn \l_@@_script_name_tl {Latin} + \tl_if_empty:NT \l_@@_lang_name_tl + { + \tl_set:Nn \l_@@_lang_name_tl {Default} + } + \keys_set:nx {fontspec-opentype} {Script=\l_@@_script_name_tl} + \keys_set:nx {fontspec-opentype} {Language=\l_@@_lang_name_tl} +%<debug> \typeout{:::: Script=\l_@@_script_name_tl, Language=\l_@@_lang_name_tl} + } + { +%<debug> \typeout{:::: NADA} + \@@_info:n {no-scripts} + \bool_set_true:N \l_@@_never_check_bool + } + } + { + \tl_if_empty:NT \l_@@_lang_name_tl + { + \tl_set:Nn \l_@@_lang_name_tl {Default} + } + \keys_set:nx {fontspec-opentype} {Script=\l_@@_script_name_tl} + \keys_set:nx {fontspec-opentype} {Language=\l_@@_lang_name_tl} +%<debug> \typeout{:::: Script=\l_@@_script_name_tl, 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_fontspec_script_tl + \prop_gput:cnV {g_@@_fontinfo_ \g_@@_nfss_family_tl _prop} {lang-tag} \l_fontspec_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 \updefault \l_fontspec_fontname_tl \l_@@_fontfeat_up_clist + \@@_add_nfssfont:nnnn \bfdefault \updefault \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_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_fontspec_renderer_tl { \tl_set:Nn \l_fontspec_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_fontspec_renderer_tl { \tl_set:Nn \l_fontspec_renderer_tl {/OT} } + \or +%<debug> \typeout{:::: Graphite} + \bool_set_true:N \l_@@_graphite_bool + \tl_if_empty:NT \l_fontspec_renderer_tl { \tl_set:Nn \l_fontspec_renderer_tl {/GR} } + \fi +%</XE> +% \end{macrocode} +% If automatic, the \cmd{\l_fontspec_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} + { + \@@_primitive_font_set:Nnn \l_tmpa_font { \@@_construct_font_call:nn {#1} {} } {\f@size pt} + \@@_primitive_font_set:Nnn \l_tmpb_font { \@@_construct_font_call:nn {#1#2} {} } {\f@size pt} + \str_if_eq:eeTF { \fontname \l_tmpa_font } { \fontname \l_tmpb_font } + { \prg_return_false: } + { \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:n {#1} + \@@_declare_shape:nnxx {#2} {#3} { \l_@@_fontopts_clist, \l_@@_leftover_clist } {#5} + \group_end: + } +% \end{macrocode} +% +% \begin{macrocode} +\cs_new:Nn \@@_load_fontname:n + { +%<debug> \typeout{:: @@_load_fontname:n {#1} } + \@@_load_external_fontoptions:Nn \l_fontspec_fontname_tl {#1} + \prop_get:NVNF \g_@@_fontopts_prop \l_fontspec_fontname_tl \l_@@_fontopts_clist + { \clist_clear:N \l_@@_fontopts_clist } + \keys_set_groups:nnV {fontspec/fontname} {getfontname} \l_@@_fontopts_clist + \@@_primitive_font_set:Nnn \l_fontspec_font { \@@_construct_font_call:nn {\l_fontspec_fontname_tl} {} } {\f@size pt} + \@@_primitive_font_if_null:NT \l_fontspec_font { \@@_error:nx {font-not-found} {#1} } + } +% \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_clear:N \l_@@_nfss_tl + \tl_clear: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} } + + \@@_declare_shapes_normal:nn {#1} {#2} + \@@_declare_shapes_smcaps:nn {#1} {#2} + \@@_declare_shape_slanted: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:n {\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:n {\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_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_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/\updefault} {'normal'~} + {\bfdefault/\updefault} {'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/\itscdefault} {'italic~ small~ caps'~} + {\bfdefault/\itscdefault} {'bold~ italic~ small~ caps'~} + {\mddefault/\slscdefault} {'slanted~ small~ caps'~} + {\bfdefault/\slscdefault} {'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_fontspec_script_tl + { + script = \l_fontspec_script_tl ; + language = \l_fontspec_lang_tl ; + } + } + } +%</XE> +%<*LU> + { + mode = \l_fontspec_mode_tl ; + \tl_if_empty:NF \l_fontspec_script_tl + { + script = \l_fontspec_script_tl ; + language = \l_fontspec_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 + { + \@@_check_ot_feat:NnTF \l_fontspec_font {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 + { \@@_make_AAT_feature_string:NnnTF \l_fontspec_font {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;} + } + } +% \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_fontspec_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_fontspec_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 + { + \@@_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} } + + \str_if_eq:eeTF {#2#3#4#5#6} {DFLT} + { + \int_set:Nn #1 {0} + } + { + + \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} +\cs_generate_variant:Nn \@@_iv_str_to_num:Nn {No} +% \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-2019 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/>. +% ------------------------------------------------ +% ©/ |