% Package : fontscale -- A flexible interface for setting font sizes % Copyright : 2024 (c) Oliver Beery % CTAN : https://ctan.org/pkg/fontscale % Repository: https://github.com/beeryoliver/fontscale % License : The LaTeX Project Public License 1.3c % LaTeX2e version 2023-11-01 added \IfExplAtLeastTF. \NeedsTeXFormat{LaTeX2e}[2023-11-01] \ProvidesExplPackage {fontscale} {2024-08-02} {2.0.0} {A flexible interface for setting font sizes} % l3kernel version 2023-10-10 added many 'e'-variants. \IfExplAtLeastTF { 2023-10-10 } { } { \msg_new:nnn { fontscale } { expl3-out-of-date } { The~ fontscale~ package~ could~ not~ load.~ This~ package~ requires~ L3~ programming~ layer~ version~ 2023-10-10~ or~ newer. } \msg_critical:nn { fontscale } { expl3-out-of-date } } % This package does not require any other packages! % DECLARE FONT SIZE PARAMETER VARIABLES \fp_const:Nn \c_fontscale_tiny_step_fp { -4 } \fp_const:Nn \c_fontscale_scriptsize_step_fp { -3 } \fp_const:Nn \c_fontscale_footnotesize_step_fp { -2 } \fp_const:Nn \c_fontscale_small_step_fp { -1 } \fp_const:Nn \c_fontscale_normalsize_step_fp { 0 } \fp_const:Nn \c_fontscale_large_step_fp { 1 } \fp_const:Nn \c_fontscale_Large_step_fp { 2 } \fp_const:Nn \c_fontscale_LARGE_step_fp { 3 } \fp_const:Nn \c_fontscale_huge_step_fp { 4 } \fp_const:Nn \c_fontscale_Huge_step_fp { 5 } \fp_const:Nn \c_fontscale_normalsize_scale_fp { 1 } \fp_new:N \l_fontscale_tiny_scale_fp \fp_new:N \l_fontscale_scriptsize_scale_fp \fp_new:N \l_fontscale_footnotesize_scale_fp \fp_new:N \l_fontscale_small_scale_fp \fp_new:N \l_fontscale_large_scale_fp \fp_new:N \l_fontscale_Large_scale_fp \fp_new:N \l_fontscale_LARGE_scale_fp \fp_new:N \l_fontscale_huge_scale_fp \fp_new:N \l_fontscale_Huge_scale_fp \dim_new:N \l_fontscale_tiny_size_dim \dim_new:N \l_fontscale_scriptsize_size_dim \dim_new:N \l_fontscale_footnotesize_size_dim \dim_new:N \l_fontscale_small_size_dim \dim_new:N \l_fontscale_normalsize_size_dim \dim_new:N \l_fontscale_large_size_dim \dim_new:N \l_fontscale_Large_size_dim \dim_new:N \l_fontscale_LARGE_size_dim \dim_new:N \l_fontscale_huge_size_dim \dim_new:N \l_fontscale_Huge_size_dim \skip_new:N \l_fontscale_tiny_baselineskip_skip \skip_new:N \l_fontscale_scriptsize_baselineskip_skip \skip_new:N \l_fontscale_footnotesize_baselineskip_skip \skip_new:N \l_fontscale_small_baselineskip_skip \skip_new:N \l_fontscale_normalsize_baselineskip_skip \skip_new:N \l_fontscale_large_baselineskip_skip \skip_new:N \l_fontscale_Large_baselineskip_skip \skip_new:N \l_fontscale_LARGE_baselineskip_skip \skip_new:N \l_fontscale_huge_baselineskip_skip \skip_new:N \l_fontscale_Huge_baselineskip_skip % INITIALIZE FONT SIZE PARAMETER VARIABLES \fp_set:Nn \l_fontscale_tiny_scale_fp { 0.6 } \fp_set:Nn \l_fontscale_scriptsize_scale_fp { 0.7 } \fp_set:Nn \l_fontscale_footnotesize_scale_fp { 0.8 } \fp_set:Nn \l_fontscale_small_scale_fp { 0.9 } \fp_set:Nn \l_fontscale_large_scale_fp { 1.1 } \fp_set:Nn \l_fontscale_Large_scale_fp { 1.2 } \fp_set:Nn \l_fontscale_LARGE_scale_fp { 1.4 } \fp_set:Nn \l_fontscale_huge_scale_fp { 1.6 } \fp_set:Nn \l_fontscale_Huge_scale_fp { 1.8 } \dim_set:Nn \l_fontscale_tiny_size_dim { 6pt } \dim_set:Nn \l_fontscale_scriptsize_size_dim { 7pt } \dim_set:Nn \l_fontscale_footnotesize_size_dim { 8pt } \dim_set:Nn \l_fontscale_small_size_dim { 9pt } \dim_set:Nn \l_fontscale_normalsize_size_dim { 10pt } \dim_set:Nn \l_fontscale_large_size_dim { 11pt } \dim_set:Nn \l_fontscale_Large_size_dim { 12pt } \dim_set:Nn \l_fontscale_LARGE_size_dim { 14pt } \dim_set:Nn \l_fontscale_huge_size_dim { 16pt } \dim_set:Nn \l_fontscale_Huge_size_dim { 18pt } \skip_set:Nn \l_fontscale_tiny_baselineskip_skip { 7.2pt } \skip_set:Nn \l_fontscale_scriptsize_baselineskip_skip { 8.4pt } \skip_set:Nn \l_fontscale_footnotesize_baselineskip_skip { 9.6pt } \skip_set:Nn \l_fontscale_small_baselineskip_skip { 10.8pt } \skip_set:Nn \l_fontscale_normalsize_baselineskip_skip { 12 pt } \skip_set:Nn \l_fontscale_large_baselineskip_skip { 13.2pt } \skip_set:Nn \l_fontscale_Large_baselineskip_skip { 14.4pt } \skip_set:Nn \l_fontscale_LARGE_baselineskip_skip { 16.8pt } \skip_set:Nn \l_fontscale_huge_baselineskip_skip { 19.2pt } \skip_set:Nn \l_fontscale_Huge_baselineskip_skip { 21.6pt } % SOME VARIABLES % Used to speed up floating point calculations. \fp_new:N \l__fontscale_normalsize_size_fp \fp_set:Nn \l__fontscale_normalsize_size_fp { 10 } \fp_new:N \l__fontscale_musical_base_fp \fp_new:N \l__fontscale_musical_notes_fp % Scratch variables \tl_new:N \l__fontscale_tmp_tl \dim_new:N \l__fontscale_tmp_dim \fp_new:N \l__fontscale_tmp_fp % SOME HELPER FUNCTIONS % Sets a dimen/skip variable from a dimen/skip expression, appending a default % unit of pt. \cs_new_protected:Npn \__fontscale_dim_set_default_pt:Nn #1#2 { \@defaultunits #1 = \dimexpr #2 pt \relax \relax \@nnil } \cs_generate_variant:Nn \__fontscale_dim_set_default_pt:Nn { c } \cs_new_protected:Npn \__fontscale_skip_set_default_pt:Nn #1#2 { \@defaultunits #1 = \glueexpr #2 pt \relax \@nnil } \cs_generate_variant:Nn \__fontscale_skip_set_default_pt:Nn { c } % Similar to \@setfontsize. Used to define \tiny to \Huge. Need \dim_use:N for % compatibility with the microtype package. \cs_new_protected:Npn \__fontscale_fontsize:NNN #1#2#3 { \mode_if_math:TF { \msg_warning:nne { fontscale } { math-mode-warning } { \token_to_str:N #1 } } { \cs_set_eq:NN \@currsize #1 \fontsize { \dim_use:N #2 } #3 \selectfont } } % Similar to \fontsize + \selectfont, except that it: % (1) Takes dimen and skip expressions as arguments. % (2) Avoids the issue where \f@size is set to the new font size before the % second argument is expanded. % (3) Provides error checking for the font size and font baselineskip. \dim_new:N \l__fontscale_fontsize_dim \skip_new:N \l__fontscale_fontsize_skip \cs_new_protected:Npn \__fontscale_fontsize:nn #1#2 { \__fontscale_dim_set_default_pt:Nn \l__fontscale_fontsize_dim {#1} \__fontscale_skip_set_default_pt:Nn \l__fontscale_fontsize_skip {#2} \dim_compare:nNnTF \l__fontscale_fontsize_dim > \c_zero_dim { \dim_compare:nNnTF \l__fontscale_fontsize_skip < \l__fontscale_fontsize_dim { \msg_error:nn { fontscale } { font-baselineskip-out-of-bounds } } { \fontsize \l__fontscale_fontsize_dim \l__fontscale_fontsize_skip \selectfont } } { \msg_error:nn { fontscale } { font-size-out-of-bounds } } } % Similar to the above function, except that it sets the font baselineskip % equal to the new font size times the baselineskip-size-ratio. \cs_new_protected:Npn \__fontscale_fontsize:n #1 { \__fontscale_dim_set_default_pt:Nn \l__fontscale_fontsize_dim {#1} \dim_compare:nNnTF \l__fontscale_fontsize_dim > \c_zero_dim { \fontsize \l__fontscale_fontsize_dim { \fp_to_dim:n { \l__fontscale_fontsize_dim * \l__fontscale_baselineskip_size_ratio_fp } } \selectfont } { \msg_error:nn { fontscale } { font-size-out-of-bounds } } } % MESSAGES \msg_new:nnn { fontscale } { key-baselineskip-size-ratio-out-of-bounds } { The~ value~ of~ the~ key~ 'baselineskip-size-ratio'~ \msg_line_context: \c_space_tl must~ be~ at~ least~ 1. } \msg_new:nnn { fontscale } { key-musical-base-out-of-bounds } { The~ value~ of~ the~ key~ 'musical / base'~ \msg_line_context: \c_space_tl must~ be~ a~ positive~ length. } \msg_new:nnn { fontscale } { key-musical-ratio-out-of-bounds } { The~ value~ of~ the~ key~ 'musical / ratio'~ \msg_line_context: \c_space_tl must~ be~ greater~ than~ 1. } \msg_new:nnn { fontscale } { key-musical-notes-out-of-bounds } { The~ value~ of~ the~ key~ 'musical / notes'~ \msg_line_context: \c_space_tl must~ be~ a~ positive~ integer. } \msg_new:nnn { fontscale } { key-font-scale-out-of-bounds } { The~ value~ of~ the~ key~ '#1 / scale'~ \msg_line_context: \c_space_tl must~ be~ positive. } \msg_new:nnn { fontscale } { key-font-size-out-of-bounds } { The~ value~ of~ the~ key~ '#1 / size'~ \msg_line_context: \c_space_tl must~ be~ a~ positive~ length. } \msg_new:nnn { fontscale } { key-font-scale-overwritten } { The~ font~ size~ set~ by~ the~ key~ '#1 / scale'~ has~ been~ overwritten~ by~ the~ key~ '#1 / size'~ \msg_line_context:. } \msg_new:nnn { fontscale } { key-font-baselineskip-out-of-bounds } { The~ value~ of~ the~ key~ '#1 / baselineskip'~ \msg_line_context: \c_space_tl must~ be~ greater~ than~ or~ equal~ to~ the~ font~ size~ of~ '\iow_char:N \\#1'. } \msg_new:nnn { fontscale } { font-sizes-out-of-order } { The~ font~ sizes~ \msg_line_context: \c_space_tl are~ not~ in~ the~ correct~ order.~ The~ lengths~ of~ the~ font~ sizes~ should~ be~ ordered~ from~ '\iow_char:N \\tiny'~ to~ '\iow_char:N \\Huge'. } \msg_new:nnn { fontscale } { font-baselineskips-out-of-order } { The~ font~ baselineskips~ \msg_line_context: \c_space_tl are~ not~ in~ the~ correct~ order.~ The~ lengths~ of~ the~ font~ baselineskips~ should~ be~ ordered~ from~ '\iow_char:N \\tiny'~ to~ '\iow_char:N \\Huge'. } \msg_new:nnn { fontscale } { math-mode-warning } { '#1'~ \msg_line_context: \c_space_tl does~ nothing~ if~ used~ in~ math~ mode. } \msg_new:nnn { fontscale } { math-mode-error } { '#1'~ \msg_line_context: \c_space_tl cannot~ be~ used~ in~ math~ mode. } \msg_new:nnn { fontscale } { font-size-out-of-bounds } { The~ font~ size~ \msg_line_context: \c_space_tl must~ be~ a~ positive~ length. } \msg_new:nnn { fontscale } { font-baselineskip-out-of-bounds } { The~ font~ baselineskip~ \msg_line_context: \c_space_tl must~ be~ greater~ than~ or~ equal~ to~ the~ font~ size. } \msg_new:nnn { fontscale } { font-step-out-of-bounds } { The~ font~ step~ \msg_line_context: \c_space_tl must~ equal~ an~ integer~ from~ -4~ to~ 5,~ unless~ the~ value~ of~ the~ key~ 'typographic-scale'~ is~ 'musical'. } \msg_new:nnn { fontscale } { current-font-step-out-of-bounds } { '\iow_char:N \\SetFontStep*'~ \msg_line_context: \c_space_tl could~ not~ calculate~ the~ new~ font~ step~ because~ the~ current~ font~ step~ is~ undefined.~ \msg_see_documentation_text:n { fontscale } } % DEFINE KEYS \str_new:N \l__fontscale_typographic_scale_str \dim_new:N \l__fontscale_musical_base_dim \cs_new_protected:Npn \__fontscale_keys_name:n #1 { \tl_if_in:nnTF {#1} { / } { \__fontscale_keys_name_split:ww #1 \q_stop } { \tl_set:cn { l__fontscale_ \l_keys_key_str _size_tl } {#1} } } \cs_new_protected:Npn \__fontscale_keys_name_split:ww #1 / #2 \q_stop { \tl_set:cn { l__fontscale_ \l_keys_key_str _size_tl } {#1} \tl_set:cn { l__fontscale_ \l_keys_key_str _baselineskip_tl } {#2} } \keys_define:nn { fontscale } { baselineskip-size-ratio .fp_set:N = \l__fontscale_baselineskip_size_ratio_fp , baselineskip-size-ratio .value_required:n = true , typographic-scale .choices:nn = { classic-10pt , classic-11pt , classic-12pt , musical } { \str_set:Nn \l__fontscale_typographic_scale_str {#1} } , typographic-scale .value_required:n = true , classic-10pt .meta:n = { typographic-scale = classic-10pt } , classic-10pt .value_forbidden:n = true , classic-11pt .meta:n = { typographic-scale = classic-11pt } , classic-11pt .value_forbidden:n = true , classic-12pt .meta:n = { typographic-scale = classic-12pt } , classic-12pt .value_forbidden:n = true , musical .meta:n = { typographic-scale = musical } , musical .value_forbidden:n = true } \keys_define:nn { fontscale / musical } { base .code:n = \__fontscale_dim_set_default_pt:Nn \l__fontscale_musical_base_dim {#1} , base .value_required:n = true , ratio .fp_set:N = \l__fontscale_musical_ratio_fp , ratio .value_required:n = true , notes .int_set:N = \l__fontscale_musical_notes_int , notes .value_required:n = true } \keys_define:nn { fontscale / tiny } { scale .tl_set:N = \l__fontscale_tiny_scale_tl , scale .value_required:n = true , size .tl_set:N = \l__fontscale_tiny_size_tl , size .value_required:n = true , baselineskip .tl_set:N = \l__fontscale_tiny_baselineskip_tl , baselineskip .value_required:n = true } \keys_define:nn { fontscale / scriptsize } { scale .tl_set:N = \l__fontscale_scriptsize_scale_tl , scale .value_required:n = true , size .tl_set:N = \l__fontscale_scriptsize_size_tl , size .value_required:n = true , baselineskip .tl_set:N = \l__fontscale_scriptsize_baselineskip_tl , baselineskip .value_required:n = true } \keys_define:nn { fontscale / footnotesize } { scale .tl_set:N = \l__fontscale_footnotesize_scale_tl , scale .value_required:n = true , size .tl_set:N = \l__fontscale_footnotesize_size_tl , size .value_required:n = true , baselineskip .tl_set:N = \l__fontscale_footnotesize_baselineskip_tl , baselineskip .value_required:n = true } \keys_define:nn { fontscale / small } { scale .tl_set:N = \l__fontscale_small_scale_tl , scale .value_required:n = true , size .tl_set:N = \l__fontscale_small_size_tl , size .value_required:n = true , baselineskip .tl_set:N = \l__fontscale_small_baselineskip_tl , baselineskip .value_required:n = true } \keys_define:nn { fontscale / normalsize } { size .tl_set:N = \l__fontscale_normalsize_size_tl , size .value_required:n = true , baselineskip .tl_set:N = \l__fontscale_normalsize_baselineskip_tl , baselineskip .value_required:n = true } \keys_define:nn { fontscale / large } { scale .tl_set:N = \l__fontscale_large_scale_tl , scale .value_required:n = true , size .tl_set:N = \l__fontscale_large_size_tl , size .value_required:n = true , baselineskip .tl_set:N = \l__fontscale_large_baselineskip_tl , baselineskip .value_required:n = true } \keys_define:nn { fontscale / Large } { scale .tl_set:N = \l__fontscale_Large_scale_tl , scale .value_required:n = true , size .tl_set:N = \l__fontscale_Large_size_tl , size .value_required:n = true , baselineskip .tl_set:N = \l__fontscale_Large_baselineskip_tl , baselineskip .value_required:n = true } \keys_define:nn { fontscale / LARGE } { scale .tl_set:N = \l__fontscale_LARGE_scale_tl , scale .value_required:n = true , size .tl_set:N = \l__fontscale_LARGE_size_tl , size .value_required:n = true , baselineskip .tl_set:N = \l__fontscale_LARGE_baselineskip_tl , baselineskip .value_required:n = true } \keys_define:nn { fontscale / huge } { scale .tl_set:N = \l__fontscale_huge_scale_tl , scale .value_required:n = true , size .tl_set:N = \l__fontscale_huge_size_tl , size .value_required:n = true , baselineskip .tl_set:N = \l__fontscale_huge_baselineskip_tl , baselineskip .value_required:n = true } \keys_define:nn { fontscale / Huge } { scale .tl_set:N = \l__fontscale_Huge_scale_tl , scale .value_required:n = true , size .tl_set:N = \l__fontscale_Huge_size_tl , size .value_required:n = true , baselineskip .tl_set:N = \l__fontscale_Huge_baselineskip_tl , baselineskip .value_required:n = true } \keys_define:nn { fontscale } { tiny .code:n = \__fontscale_keys_name:n {#1} , tiny .value_required:n = true , scriptsize .code:n = \__fontscale_keys_name:n {#1} , scriptsize .value_required:n = true , footnotesize .code:n = \__fontscale_keys_name:n {#1} , footnotesize .value_required:n = true , small .code:n = \__fontscale_keys_name:n {#1} , small .value_required:n = true , normalsize .code:n = \__fontscale_keys_name:n {#1} , normalsize .value_required:n = true , large .code:n = \__fontscale_keys_name:n {#1} , large .value_required:n = true , Large .code:n = \__fontscale_keys_name:n {#1} , Large .value_required:n = true , LARGE .code:n = \__fontscale_keys_name:n {#1} , LARGE .value_required:n = true , huge .code:n = \__fontscale_keys_name:n {#1} , huge .value_required:n = true , Huge .code:n = \__fontscale_keys_name:n {#1} , Huge .value_required:n = true } % INITIALIZE AND PRE-COMPILE KEYS % Pre-compiles the keys with their initial values and then sets the keys to % their initial values. This is done by hand for speed. \cs_new_protected:Npn \__fontscale_keys_set_initial: { \fp_set:Nn \l__fontscale_baselineskip_size_ratio_fp { 1.2 } \str_set:Nn \l__fontscale_typographic_scale_str { classic-10pt } \dim_set:Nn \l__fontscale_musical_base_dim { 10pt } \fp_set:Nn \l__fontscale_musical_ratio_fp { 2 } \int_set:Nn \l__fontscale_musical_notes_int { 5 } \tl_set:Nn \l__fontscale_tiny_scale_tl { \q_no_value } \tl_set:Nn \l__fontscale_scriptsize_scale_tl { \q_no_value } \tl_set:Nn \l__fontscale_footnotesize_scale_tl { \q_no_value } \tl_set:Nn \l__fontscale_small_scale_tl { \q_no_value } \tl_set:Nn \l__fontscale_large_scale_tl { \q_no_value } \tl_set:Nn \l__fontscale_Large_scale_tl { \q_no_value } \tl_set:Nn \l__fontscale_LARGE_scale_tl { \q_no_value } \tl_set:Nn \l__fontscale_huge_scale_tl { \q_no_value } \tl_set:Nn \l__fontscale_Huge_scale_tl { \q_no_value } \tl_set:Nn \l__fontscale_tiny_size_tl { \q_no_value } \tl_set:Nn \l__fontscale_scriptsize_size_tl { \q_no_value } \tl_set:Nn \l__fontscale_footnotesize_size_tl { \q_no_value } \tl_set:Nn \l__fontscale_small_size_tl { \q_no_value } \tl_set:Nn \l__fontscale_normalsize_size_tl { \q_no_value } \tl_set:Nn \l__fontscale_large_size_tl { \q_no_value } \tl_set:Nn \l__fontscale_Large_size_tl { \q_no_value } \tl_set:Nn \l__fontscale_LARGE_size_tl { \q_no_value } \tl_set:Nn \l__fontscale_huge_size_tl { \q_no_value } \tl_set:Nn \l__fontscale_Huge_size_tl { \q_no_value } \tl_set:Nn \l__fontscale_tiny_baselineskip_tl { \q_no_value } \tl_set:Nn \l__fontscale_scriptsize_baselineskip_tl { \q_no_value } \tl_set:Nn \l__fontscale_footnotesize_baselineskip_tl { \q_no_value } \tl_set:Nn \l__fontscale_small_baselineskip_tl { \q_no_value } \tl_set:Nn \l__fontscale_normalsize_baselineskip_tl { \q_no_value } \tl_set:Nn \l__fontscale_large_baselineskip_tl { \q_no_value } \tl_set:Nn \l__fontscale_Large_baselineskip_tl { \q_no_value } \tl_set:Nn \l__fontscale_LARGE_baselineskip_tl { \q_no_value } \tl_set:Nn \l__fontscale_huge_baselineskip_tl { \q_no_value } \tl_set:Nn \l__fontscale_Huge_baselineskip_tl { \q_no_value } } \__fontscale_keys_set_initial: % SET AND PROCESS KEYS \NewDocumentCommand \fontscalesetup { s m } { \mode_if_math:TF { \msg_warning:nne { fontscale } { math-mode-warning } { \token_to_str:N \fontscalesetup } } { \IfBooleanTF #1 { \__fontscale_keys_reset:n {#2} } { \__fontscale_keys_set:n {#2} } } } \cs_new_protected:Npn \__fontscale_keys_set:n #1 { \keys_set:nn { fontscale } {#1} \__fontscale_keys_process: \normalsize \prg_break: \prg_break_point: } \cs_new_protected:Npn \__fontscale_keys_reset:n { \__fontscale_keys_set_initial: \__fontscale_keys_set:n } \cs_new_protected:Npn \__fontscale_keys_process: { \__fontscale_keys_process_start: \__fontscale_keys_process_normalsize: \__fontscale_keys_process_other: \__fontscale_keys_process_check_order: } \cs_new_protected:Npn \__fontscale_keys_process_start: { \fp_compare:nNnT \l__fontscale_baselineskip_size_ratio_fp < \c_one_fp { \msg_error:nn { fontscale } { key-baselineskip-size-ratio-out-of-bounds } \prg_break: } \dim_compare:nNnF \l__fontscale_musical_base_dim > \c_zero_dim { \msg_error:nn { fontscale } { key-musical-base-out-of-bounds } \prg_break: } \fp_compare:nNnF \l__fontscale_musical_ratio_fp > \c_one_fp { \msg_error:nn { fontscale } { key-musical-ratio-out-of-bounds } \prg_break: } \int_compare:nNnF \l__fontscale_musical_notes_int > 0 { \msg_error:nn { fontscale } { key-musical-notes-out-of-bounds } \prg_break: } } % Sets the font size and font baselineskip of \normalsize. \cs_new_protected:Npn \__fontscale_keys_process_normalsize: { \quark_if_no_value:NTF \l__fontscale_normalsize_size_tl { \dim_set:Nn \l_fontscale_normalsize_size_dim { \str_case:Vn \l__fontscale_typographic_scale_str { { classic-10pt } { 10pt } { classic-11pt } { 11pt } { classic-12pt } { 12pt } { musical } { \l__fontscale_musical_base_dim } } } } { \__fontscale_dim_set_default_pt:Nn \l_fontscale_normalsize_size_dim { \l__fontscale_normalsize_size_tl } \dim_compare:nNnF \l_fontscale_normalsize_size_dim > \c_zero_dim { \msg_error:nnn { fontscale } { key-font-size-out-of-bounds } { normalsize } \prg_break: } } \fp_set:Nn \l__fontscale_normalsize_size_fp { \l_fontscale_normalsize_size_dim } \quark_if_no_value:NTF \l__fontscale_normalsize_baselineskip_tl { \skip_set:Nn \l_fontscale_normalsize_baselineskip_skip { \fp_to_dim:n { \l__fontscale_normalsize_size_fp * \l__fontscale_baselineskip_size_ratio_fp } } } { \__fontscale_skip_set_default_pt:Nn \l_fontscale_normalsize_baselineskip_skip { \l__fontscale_normalsize_baselineskip_tl } \dim_compare:nNnT \l_fontscale_normalsize_baselineskip_skip < \l_fontscale_normalsize_size_dim { \msg_error:nnn { fontscale } { key-font-baselineskip-out-of-bounds } { normalsize } \prg_break: } } } % Auxiliary functions that expand to the font size depending on the name of the % font size command. \cs_new:Npn \__fontscale_keys_process_other_classic_xpt:n #1 { \str_case:nn {#1} { { tiny } { 6pt } { scriptsize } { 7pt } { footnotesize } { 8pt } { small } { 9pt } { large } { 11pt } { Large } { 12pt } { LARGE } { 14pt } { huge } { 16pt } { Huge } { 18pt } } } \cs_new:Npn \__fontscale_keys_process_other_classic_xipt:n #1 { \str_case:nn {#1} { { tiny } { 7pt } { scriptsize } { 8pt } { footnotesize } { 9pt } { small } { 10pt } { large } { 12pt } { Large } { 14pt } { LARGE } { 16pt } { huge } { 18pt } { Huge } { 21pt } } } \cs_new:Npn \__fontscale_keys_process_other_classic_xiipt:n #1 { \str_case:nn {#1} { { tiny } { 8pt } { scriptsize } { 9pt } { footnotesize } { 10pt } { small } { 11pt } { large } { 14pt } { Large } { 16pt } { LARGE } { 18pt } { huge } { 21pt } { Huge } { 24pt } } } \cs_new:Npn \__fontscale_keys_process_other_musical:n #1 { \fp_to_dim:n { \l__fontscale_musical_base_fp * \l__fontscale_musical_ratio_fp ^ ( \use:c { c_fontscale_#1_step_fp } / \l__fontscale_musical_notes_fp ) } } % Sets the font size, font scale, and font baselineskip of the other font size % commands. \cs_new_protected:Npn \__fontscale_keys_process_other: { \str_case:Vn \l__fontscale_typographic_scale_str { { classic-10pt } { \cs_set_eq:NN \__fontscale_keys_process_other_fn_aux:n \__fontscale_keys_process_other_classic_xpt:n } { classic-11pt } { \cs_set_eq:NN \__fontscale_keys_process_other_fn_aux:n \__fontscale_keys_process_other_classic_xipt:n } { classic-12pt } { \cs_set_eq:NN \__fontscale_keys_process_other_fn_aux:n \__fontscale_keys_process_other_classic_xiipt:n } { musical } { \cs_set_eq:NN \__fontscale_keys_process_other_fn_aux:n \__fontscale_keys_process_other_musical:n \fp_set:Nn \l__fontscale_musical_base_fp { \l__fontscale_musical_base_dim } \fp_set:Nn \l__fontscale_musical_notes_fp { \l__fontscale_musical_notes_int } } } \tl_map_function:nN { {tiny} {scriptsize} {footnotesize} {small} {large} {Large} {LARGE} {huge} {Huge} } \__fontscale_keys_process_other_fn:n } \cs_new_protected:Npn \__fontscale_keys_process_other_fn:n #1 { \quark_if_no_value:cF { l__fontscale_#1_scale_tl } { \dim_set:cn { l_fontscale_#1_size_dim } { \fp_to_dim:n { \l__fontscale_normalsize_size_fp * ( \use:c { l__fontscale_#1_scale_tl } ) } } \dim_compare:nNnF { \use:c { l_fontscale_#1_size_dim } } > \c_zero_dim { \tl_map_break:n { \msg_error:nnn { fontscale } { key-font-scale-out-of-bounds } {#1} \prg_break: } } \quark_if_no_value:cT { l__fontscale_#1_size_tl } { \prg_break: } } \quark_if_no_value:cF { l__fontscale_#1_size_tl } { \__fontscale_dim_set_default_pt:cn { l_fontscale_#1_size_dim } { \use:c { l__fontscale_#1_size_tl } } \dim_compare:nNnF { \use:c { l_fontscale_#1_size_dim } } > \c_zero_dim { \tl_map_break:n { \msg_error:nnn { fontscale } { key-font-size-out-of-bounds } {#1} \prg_break: } } \quark_if_no_value:cF { l__fontscale_#1_scale_tl } { \msg_warning:nnn { fontscale } { key-font-scale-overwritten } {#1} } \prg_break: } \dim_set:cn { l_fontscale_#1_size_dim } { \__fontscale_keys_process_other_fn_aux:n {#1} } \prg_break: \prg_break_point: \fp_set:cn { l_fontscale_#1_scale_fp } { \use:c { l_fontscale_#1_size_dim } / \l__fontscale_normalsize_size_fp } \quark_if_no_value:cTF { l__fontscale_#1_baselineskip_tl } { \skip_set:cn { l_fontscale_#1_baselineskip_skip } { \fp_to_dim:n { \use:c { l_fontscale_#1_size_dim } * \l__fontscale_baselineskip_size_ratio_fp } } } { \__fontscale_skip_set_default_pt:cn { l_fontscale_#1_baselineskip_skip } { \use:c { l__fontscale_#1_baselineskip_tl } } \dim_compare:nNnT { \use:c { l_fontscale_#1_baselineskip_skip } } < { \use:c { l_fontscale_#1_size_dim } } { \tl_map_break:n { \msg_error:nnn { fontscale } { key-font-baselineskip-out-of-bounds } {#1} \prg_break: } } } } % Issues a warning if the font sizes or font baselineskips (ignoring the % stretch and shrink components) are not in the correct order. \cs_new_protected:Npn \__fontscale_keys_process_check_order: { \dim_compare:nF { \l_fontscale_tiny_size_dim < \l_fontscale_scriptsize_size_dim < \l_fontscale_footnotesize_size_dim < \l_fontscale_small_size_dim < \l_fontscale_normalsize_size_dim < \l_fontscale_large_size_dim < \l_fontscale_Large_size_dim < \l_fontscale_LARGE_size_dim < \l_fontscale_huge_size_dim < \l_fontscale_Huge_size_dim } { \msg_warning:nn { fontscale } { font-sizes-out-of-order } } \dim_compare:nF { \l_fontscale_tiny_baselineskip_skip < \l_fontscale_scriptsize_baselineskip_skip < \l_fontscale_footnotesize_baselineskip_skip < \l_fontscale_small_baselineskip_skip < \l_fontscale_normalsize_baselineskip_skip < \l_fontscale_large_baselineskip_skip < \l_fontscale_Large_baselineskip_skip < \l_fontscale_LARGE_baselineskip_skip < \l_fontscale_huge_baselineskip_skip < \l_fontscale_Huge_baselineskip_skip } { \msg_warning:nn { fontscale } { font-baselineskips-out-of-order } } } % DOCUMENT COMMANDS % Defines the standard LaTeX font size commands from \tiny to \Huge and % initializes to \normalsize. \DeclareDocumentCommand \tiny { } { \__fontscale_fontsize:NNN \tiny \l_fontscale_tiny_size_dim \l_fontscale_tiny_baselineskip_skip } \DeclareDocumentCommand \scriptsize { } { \__fontscale_fontsize:NNN \scriptsize \l_fontscale_scriptsize_size_dim \l_fontscale_scriptsize_baselineskip_skip } \DeclareDocumentCommand \footnotesize { } { \__fontscale_fontsize:NNN \footnotesize \l_fontscale_footnotesize_size_dim \l_fontscale_footnotesize_baselineskip_skip } \DeclareDocumentCommand \small { } { \__fontscale_fontsize:NNN \small \l_fontscale_small_size_dim \l_fontscale_small_baselineskip_skip } \DeclareDocumentCommand \normalsize { } { \__fontscale_fontsize:NNN \normalsize \l_fontscale_normalsize_size_dim \l_fontscale_normalsize_baselineskip_skip } \DeclareDocumentCommand \large { } { \__fontscale_fontsize:NNN \large \l_fontscale_large_size_dim \l_fontscale_large_baselineskip_skip } \DeclareDocumentCommand \Large { } { \__fontscale_fontsize:NNN \Large \l_fontscale_Large_size_dim \l_fontscale_Large_baselineskip_skip } \DeclareDocumentCommand \LARGE { } { \__fontscale_fontsize:NNN \LARGE \l_fontscale_LARGE_size_dim \l_fontscale_LARGE_baselineskip_skip } \DeclareDocumentCommand \huge { } { \__fontscale_fontsize:NNN \huge \l_fontscale_huge_size_dim \l_fontscale_huge_baselineskip_skip } \DeclareDocumentCommand \Huge { } { \__fontscale_fontsize:NNN \Huge \l_fontscale_Huge_size_dim \l_fontscale_Huge_baselineskip_skip } \normalsize \NewExpandableDocumentCommand \CurrentFontStep { } { \__fontscale_step: } \cs_new:Npn \__fontscale_step: { \dim_case:nnF { \f@size pt } { { \l_fontscale_tiny_size_dim } { -4 } { \l_fontscale_scriptsize_size_dim } { -3 } { \l_fontscale_footnotesize_size_dim } { -2 } { \l_fontscale_small_size_dim } { -1 } { \l_fontscale_normalsize_size_dim } { 0 } { \l_fontscale_large_size_dim } { 1 } { \l_fontscale_Large_size_dim } { 2 } { \l_fontscale_LARGE_size_dim } { 3 } { \l_fontscale_huge_size_dim } { 4 } { \l_fontscale_Huge_size_dim } { 5 } } { \str_if_eq:VnT \l__fontscale_typographic_scale_str { musical } { \fp_eval:n { \l__fontscale_musical_notes_fp * ln ( \f@size / \l__fontscale_musical_base_fp ) / ln ( \l__fontscale_musical_ratio_fp ) } } } } \NewExpandableDocumentCommand \CurrentFontScale { } { \__fontscale_scale: } \cs_new:Npn \__fontscale_scale: { \fp_eval:n { \f@size / \l__fontscale_normalsize_size_fp } } \NewExpandableDocumentCommand \CurrentFontSize { } { \__fontscale_size: } \cs_new:Npn \__fontscale_size: { \f@size pt } \NewExpandableDocumentCommand \CurrentFontBaselineskip { } { \__fontscale_baselineskip: } \cs_new:Npn \__fontscale_baselineskip: { \f@baselineskip } \NewDocumentCommand \SetFontStep { s m } { \mode_if_math:TF { \msg_warning:nne { fontscale } { math-mode-warning } { \token_to_str:N \SetFontStep } } { \IfBooleanTF #1 { \__fontscale_add_font_step:n {#2} } { \__fontscale_set_font_step:n {#2} } } } % Using \str_case: here is significantly faster (and easier to write) than % repeatedly testing \fp_compare:. \cs_new_protected:Npn \__fontscale_set_font_step:n #1 { \str_case:enF { \fp_eval:n {#1} } { { -4 } { \tiny } { -3 } { \scriptsize } { -2 } { \footnotesize } { -1 } { \small } { 0 } { \normalsize } { 1 } { \large } { 2 } { \Large } { 3 } { \LARGE } { 4 } { \huge } { 5 } { \Huge } } { \str_if_eq:VnTF \l__fontscale_typographic_scale_str { musical } { \__fontscale_fontsize:n { \fp_to_dim:n { \l__fontscale_musical_base_fp * \l__fontscale_musical_ratio_fp ^ ( (#1) / \l__fontscale_musical_notes_fp ) } } } { \msg_error:nn { fontscale } { font-step-out-of-bounds } } } } \cs_new_protected:Npn \__fontscale_add_font_step:n #1 { \tl_set:Ne \l__fontscale_tmp_tl { \__fontscale_step: } \tl_if_empty:NTF \l__fontscale_tmp_tl { \msg_error:nn { fontscale } { current-font-step-out-of-bounds } } { \__fontscale_add_font_step_aux:n { (#1) + \l__fontscale_tmp_tl } } } \cs_new_eq:NN \__fontscale_add_font_step_aux:n \__fontscale_set_font_step:n \NewDocumentCommand \SetFontScale { s m } { \mode_if_math:TF { \msg_warning:nne { fontscale } { math-mode-warning } { \token_to_str:N \SetFontScale } } { \IfBooleanTF #1 { \__fontscale_add_font_scale:n {#2} } { \__fontscale_set_font_scale:n {#2} } } } \cs_new_protected:Npn \__fontscale_set_font_scale:n #1 { \__fontscale_fontsize:n { \fp_to_dim:n { \l__fontscale_normalsize_size_fp * (#1) } } } \cs_new_protected:Npn \__fontscale_add_font_scale:n #1 { \__fontscale_fontsize:n { \fp_to_dim:n { \l__fontscale_normalsize_size_fp * (#1) + \f@size } } } \NewDocumentCommand \SetFontSize { s m } { \mode_if_math:TF { \msg_warning:nne { fontscale } { math-mode-warning } { \token_to_str:N \SetFontSize } } { \IfBooleanTF #1 { \__fontscale_add_font_size:n {#2} } { \__fontscale_set_font_size:n {#2} } } } \cs_new_eq:NN \__fontscale_set_font_size:n \__fontscale_fontsize:n \cs_new_protected:Npn \__fontscale_add_font_size:n #1 { \__fontscale_dim_set_default_pt:Nn \l__fontscale_tmp_dim {#1} \__fontscale_fontsize:n { \l__fontscale_tmp_dim + \f@size pt } } \NewDocumentCommand \ScaleFont { m } { \mode_if_math:TF { \msg_warning:nne { fontscale } { math-mode-warning } { \token_to_str:N \ScaleFont } } { \__fontscale_scale_font:n {#1} } } \cs_new_protected:Npn \__fontscale_scale_font:n #1 { \fp_set:Nn \l__fontscale_tmp_fp {#1} \__fontscale_fontsize:nn { \fp_to_dim:n { \f@size * \l__fontscale_tmp_fp } } { \fp_to_dim:n { \dim_to_fp:n { \f@baselineskip } * \l__fontscale_tmp_fp } } } \NewDocumentCommand \SetFontSizeBaselineskip { m m } { \mode_if_math:TF { \msg_warning:nne { fontscale } { math-mode-warning } { \token_to_str:N \SetFontSizeBaselineskip } } { \__fontscale_set_font_size_baselineskip:nn {#1} {#2} } } \cs_new_eq:NN \__fontscale_set_font_size_baselineskip:nn \__fontscale_fontsize:nn \NewDocumentCommand \PrintFontSizeParameters { } { \__fontscale_print_font_size_parameters: } \cs_new_protected:Npn \__fontscale_print_font_size_parameters: { step ~=~ \__fontscale_step: ,~ scale ~=~ \__fontscale_scale: ,~ size ~=~ \__fontscale_size: ,~ baselineskip ~=~ \__fontscale_baselineskip: } \NewDocumentCommand \PrintAllFontSizeParameters { } { \mode_if_math:TF { \msg_error:nne { fontscale } { math-mode-error } { \token_to_str:N \PrintAllFontSizeParameters } } { \__fontscale_print_all_font_size_parameters: } } \cs_new_protected:Npn \__fontscale_print_all_font_size_parameters: { \token_to_str:N \tiny \c_colon_str \c_space_tl step ~=~ -4 ,~ scale ~=~ \fp_use:N \l_fontscale_tiny_scale_fp ,~ size ~=~ \dim_use:N \l_fontscale_tiny_size_dim ,~ baselineskip ~=~ \skip_use:N \l_fontscale_tiny_baselineskip_skip \newline \token_to_str:N \scriptsize \c_colon_str \c_space_tl step ~=~ -3 ,~ scale ~=~ \fp_use:N \l_fontscale_scriptsize_scale_fp ,~ size ~=~ \dim_use:N \l_fontscale_scriptsize_size_dim ,~ baselineskip ~=~ \skip_use:N \l_fontscale_scriptsize_baselineskip_skip \newline \token_to_str:N \footnotesize \c_colon_str \c_space_tl step ~=~ -2 ,~ scale ~=~ \fp_use:N \l_fontscale_footnotesize_scale_fp ,~ size ~=~ \dim_use:N \l_fontscale_footnotesize_size_dim ,~ baselineskip ~=~ \skip_use:N \l_fontscale_footnotesize_baselineskip_skip \newline \token_to_str:N \small \c_colon_str \c_space_tl step ~=~ -1 ,~ scale ~=~ \fp_use:N \l_fontscale_small_scale_fp ,~ size ~=~ \dim_use:N \l_fontscale_small_size_dim ,~ baselineskip ~=~ \skip_use:N \l_fontscale_small_baselineskip_skip \newline \token_to_str:N \normalsize \c_colon_str \c_space_tl step ~=~ 0 ,~ scale ~=~ 1 ,~ size ~=~ \dim_use:N \l_fontscale_normalsize_size_dim ,~ baselineskip ~=~ \skip_use:N \l_fontscale_normalsize_baselineskip_skip \newline \token_to_str:N \large \c_colon_str \c_space_tl step ~=~ 1 ,~ scale ~=~ \fp_use:N \l_fontscale_large_scale_fp ,~ size ~=~ \dim_use:N \l_fontscale_large_size_dim ,~ baselineskip ~=~ \skip_use:N \l_fontscale_large_baselineskip_skip \newline \token_to_str:N \Large \c_colon_str \c_space_tl step ~=~ 2 ,~ scale ~=~ \fp_use:N \l_fontscale_Large_scale_fp ,~ size ~=~ \dim_use:N \l_fontscale_Large_size_dim ,~ baselineskip ~=~ \skip_use:N \l_fontscale_Large_baselineskip_skip \newline \token_to_str:N \LARGE \@ \c_colon_str \c_space_tl step ~=~ 3 ,~ scale ~=~ \fp_use:N \l_fontscale_LARGE_scale_fp ,~ size ~=~ \dim_use:N \l_fontscale_LARGE_size_dim ,~ baselineskip ~=~ \skip_use:N \l_fontscale_LARGE_baselineskip_skip \newline \token_to_str:N \huge \c_colon_str \c_space_tl step ~=~ 4 ,~ scale ~=~ \fp_use:N \l_fontscale_huge_scale_fp ,~ size ~=~ \dim_use:N \l_fontscale_huge_size_dim ,~ baselineskip ~=~ \skip_use:N \l_fontscale_huge_baselineskip_skip \newline \token_to_str:N \Huge \c_colon_str \c_space_tl step ~=~ 5 ,~ scale ~=~ \fp_use:N \l_fontscale_Huge_scale_fp ,~ size ~=~ \dim_use:N \l_fontscale_Huge_size_dim ,~ baselineskip ~=~ \skip_use:N \l_fontscale_Huge_baselineskip_skip } \NewDocumentCommand \PrintSampleText { s +m } { \mode_if_math:TF { \msg_error:nne { fontscale } { math-mode-error } { \token_to_str:N \PrintSampleText } } { \IfBooleanTF #1 { \__fontscale_print_sample_text_descending_order:n {#2} } { \__fontscale_print_sample_text_ascending_order:n {#2} } } } \cs_new_protected:Npn \__fontscale_print_sample_text_ascending_order:n #1 { { \tiny #1 \par } { \scriptsize #1 \par } { \footnotesize #1 \par } { \small #1 \par } { \normalsize #1 \par } { \large #1 \par } { \Large #1 \par } { \LARGE #1 \par } { \huge #1 \par } { \Huge #1 \par } } \cs_new_protected:Npn \__fontscale_print_sample_text_descending_order:n #1 { { \Huge #1 \par } { \huge #1 \par } { \LARGE #1 \par } { \Large #1 \par } { \large #1 \par } { \normalsize #1 \par } { \small #1 \par } { \footnotesize #1 \par } { \scriptsize #1 \par } { \tiny #1 \par } } \NewDocumentCommand \PrintFontSizeCommand { } { \mode_if_math:TF { \msg_error:nne { fontscale } { math-mode-error } { \token_to_str:N \PrintFontSizeCommand } } { \__fontscale_print_name: } } \cs_new_protected:Npn \__fontscale_print_name: { \dim_case:nn { \f@size pt } { { \l_fontscale_tiny_size_dim } { \skip_if_eq:nnT { \f@baselineskip } { \l_fontscale_tiny_baselineskip_skip } { \token_to_str:N \tiny \prg_break: } } { \l_fontscale_scriptsize_size_dim } { \skip_if_eq:nnT { \f@baselineskip } { \l_fontscale_scriptsize_baselineskip_skip } { \token_to_str:N \scriptsize \prg_break: } } { \l_fontscale_footnotesize_size_dim } { \skip_if_eq:nnT { \f@baselineskip } { \l_fontscale_footnotesize_baselineskip_skip } { \token_to_str:N \footnotesize \prg_break: } } { \l_fontscale_small_size_dim } { \skip_if_eq:nnT { \f@baselineskip } { \l_fontscale_small_baselineskip_skip } { \token_to_str:N \small \prg_break: } } { \l_fontscale_normalsize_size_dim } { \skip_if_eq:nnT { \f@baselineskip } { \l_fontscale_normalsize_baselineskip_skip } { \token_to_str:N \normalsize \prg_break: } } { \l_fontscale_large_size_dim } { \skip_if_eq:nnT { \f@baselineskip } { \l_fontscale_large_baselineskip_skip } { \token_to_str:N \large \prg_break: } } { \l_fontscale_Large_size_dim } { \skip_if_eq:nnT { \f@baselineskip } { \l_fontscale_Large_baselineskip_skip } { \token_to_str:N \Large \prg_break: } } { \l_fontscale_LARGE_size_dim } { \skip_if_eq:nnT { \f@baselineskip } { \l_fontscale_LARGE_baselineskip_skip } { \token_to_str:N \LARGE \@ \prg_break: } } { \l_fontscale_huge_size_dim } { \skip_if_eq:nnT { \f@baselineskip } { \l_fontscale_huge_baselineskip_skip } { \token_to_str:N \huge \prg_break: } } { \l_fontscale_Huge_size_dim } { \skip_if_eq:nnT { \f@baselineskip } { \l_fontscale_Huge_baselineskip_skip } { \token_to_str:N \Huge \prg_break: } } } \token_to_str:N \undefined \prg_break: \prg_break_point: } % TEXT PURIFY \cs_new:Npn \__fontscale_remove_arg_spec_sm:n #1 { \bool_lazy_all:nT { { \tl_if_single_p:n {#1} } { \tl_if_single_token_p:n #1 } { \token_if_eq_meaning_p:NN #1 * } } { \use_none:n } } \text_declare_purify_equivalent:Nn \fontscalesetup { \__fontscale_remove_arg_spec_sm:n } \text_declare_purify_equivalent:Nn \SetFontStep { \__fontscale_remove_arg_spec_sm:n } \text_declare_purify_equivalent:Nn \SetFontScale { \__fontscale_remove_arg_spec_sm:n } \text_declare_purify_equivalent:Nn \SetFontSize { \__fontscale_remove_arg_spec_sm:n } \text_declare_purify_equivalent:Nn \ScaleFont { \use_none:n } \text_declare_purify_equivalent:Nn \SetFontSizeBaselineskip { \use_none:nn }