Add support for c2sc OpenType feature in smallcaps (#5655)

This commit is contained in:
Malo 2025-01-23 19:24:35 +01:00 committed by GitHub
parent b7546bace7
commit 2d33393df9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 42 additions and 13 deletions

View File

@ -38,7 +38,8 @@ use crate::model::{
};
use crate::routines::{EvalMode, Routines};
use crate::text::{
FontStyle, Lang, LocalName, Region, SubElem, SuperElem, TextElem, WeightDelta,
FontStyle, Lang, LocalName, Region, Smallcaps, SubElem, SuperElem, TextElem,
WeightDelta,
};
use crate::World;
@ -1046,7 +1047,8 @@ fn apply_formatting(mut content: Content, format: &hayagriva::Formatting) -> Con
match format.font_variant {
citationberg::FontVariant::Normal => {}
citationberg::FontVariant::SmallCaps => {
content = content.styled(TextElem::set_smallcaps(true));
content =
content.styled(TextElem::set_smallcaps(Some(Smallcaps::Minuscules)));
}
}

View File

@ -755,11 +755,10 @@ pub struct TextElem {
#[ghost]
pub case: Option<Case>,
/// Whether small capital glyphs should be used. ("smcp")
/// Whether small capital glyphs should be used. ("smcp", "c2sc")
#[internal]
#[default(false)]
#[ghost]
pub smallcaps: bool,
pub smallcaps: Option<Smallcaps>,
}
impl TextElem {
@ -1249,8 +1248,11 @@ pub fn features(styles: StyleChain) -> Vec<Feature> {
}
// Features that are off by default in Harfbuzz are only added if enabled.
if TextElem::smallcaps_in(styles) {
if let Some(sc) = TextElem::smallcaps_in(styles) {
feat(b"smcp", 1);
if sc == Smallcaps::All {
feat(b"c2sc", 1);
}
}
if TextElem::alternates_in(styles) {

View File

@ -12,11 +12,11 @@ use crate::text::TextElem;
/// ```
///
/// # Smallcaps fonts
/// By default, this enables the OpenType `smcp` feature for the font. Not all
/// fonts support this feature. Sometimes smallcaps are part of a dedicated
/// font. This is, for example, the case for the _Latin Modern_ family of fonts.
/// In those cases, you can use a show-set rule to customize the appearance of
/// the text in smallcaps:
/// By default, this uses the `smcp` and `c2sc` OpenType features on the font.
/// Not all fonts support these features. Sometimes, smallcaps are part of a
/// dedicated font. This is, for example, the case for the _Latin Modern_ family
/// of fonts. In those cases, you can use a show-set rule to customize the
/// appearance of the text in smallcaps:
///
/// ```typ
/// #show smallcaps: set text(font: "Latin Modern Roman Caps")
@ -45,6 +45,17 @@ use crate::text::TextElem;
/// ```
#[elem(title = "Small Capitals", Show)]
pub struct SmallcapsElem {
/// Whether to turn uppercase letters into small capitals as well.
///
/// Unless overridden by a show rule, this enables the `c2sc` OpenType
/// feature.
///
/// ```example
/// #smallcaps(all: true)[UNICEF] is an
/// agency of #smallcaps(all: true)[UN].
/// ```
#[default(false)]
pub all: bool,
/// The content to display in small capitals.
#[required]
pub body: Content,
@ -52,7 +63,17 @@ pub struct SmallcapsElem {
impl Show for Packed<SmallcapsElem> {
#[typst_macros::time(name = "smallcaps", span = self.span())]
fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> {
Ok(self.body.clone().styled(TextElem::set_smallcaps(true)))
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
let sc = if self.all(styles) { Smallcaps::All } else { Smallcaps::Minuscules };
Ok(self.body.clone().styled(TextElem::set_smallcaps(Some(sc))))
}
}
/// What becomes small capitals.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Smallcaps {
/// Minuscules become small capitals.
Minuscules,
/// All letters become small capitals.
All,
}

BIN
tests/ref/smallcaps-all.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

View File

@ -10,3 +10,7 @@
#show smallcaps: set text(fill: red)
#smallcaps[Smallcaps]
--- smallcaps-all ---
#smallcaps(all: false)[Test 012] \
#smallcaps(all: true)[Test 012]