#[allow(non_camel_case_types, clippy::struct_excessive_bools)]
#[derive(Debug, Clone)]
pub struct CT_Font {
pub id: u32,
pub font_name: String,
pub family_name: Option<String>,
pub charset: Option<String>,
pub italic: bool,
pub bold: bool,
pub serif: bool,
pub fixed_width: bool,
pub font_file: Option<String>,
}
impl CT_Font {
#[must_use]
pub fn new(id: u32, font_name: impl Into<String>) -> Self {
Self {
id,
font_name: font_name.into(),
family_name: None,
charset: None,
italic: false,
bold: false,
serif: false,
fixed_width: false,
font_file: None,
}
}
#[must_use]
pub fn font_name(mut self, name: impl Into<String>) -> Self {
self.font_name = name.into();
self
}
#[must_use]
pub fn family_name(mut self, name: impl Into<String>) -> Self {
self.family_name = Some(name.into());
self
}
#[must_use]
pub fn charset(mut self, charset: impl Into<String>) -> Self {
self.charset = Some(charset.into());
self
}
#[must_use]
pub fn italic(mut self, italic: bool) -> Self {
self.italic = italic;
self
}
#[must_use]
pub fn bold(mut self, bold: bool) -> Self {
self.bold = bold;
self
}
#[must_use]
pub fn serif(mut self, serif: bool) -> Self {
self.serif = serif;
self
}
#[must_use]
pub fn fixed_width(mut self, fixed: bool) -> Self {
self.fixed_width = fixed;
self
}
#[must_use]
pub fn font_file(mut self, path: impl Into<String>) -> Self {
self.font_file = Some(path.into());
self
}
#[must_use]
pub fn get_id(&self) -> u32 {
self.id
}
#[must_use]
pub fn get_font_name(&self) -> &str {
&self.font_name
}
#[must_use]
pub fn get_family_name(&self) -> Option<&str> {
self.family_name.as_deref()
}
#[must_use]
pub fn get_charset(&self) -> Option<&str> {
self.charset.as_deref()
}
#[must_use]
pub fn is_italic(&self) -> bool {
self.italic
}
#[must_use]
pub fn is_bold(&self) -> bool {
self.bold
}
#[must_use]
pub fn is_serif(&self) -> bool {
self.serif
}
#[must_use]
pub fn is_fixed_width(&self) -> bool {
self.fixed_width
}
#[must_use]
pub fn to_xml_string(&self) -> String {
use std::fmt::Write;
let mut xml = format!(
"<ofd:Font ID=\"{}\" FontName=\"{}\"",
self.id, self.font_name
);
if let Some(ref fn_) = self.family_name {
write!(xml, " FamilyName=\"{fn_}\"").expect("写入内存缓冲区不会失败");
}
if let Some(ref cs) = self.charset {
write!(xml, " Charset=\"{cs}\"").expect("写入内存缓冲区不会失败");
}
if self.italic {
xml.push_str(" Italic=\"true\"");
}
if self.bold {
xml.push_str(" Bold=\"true\"");
}
if self.serif {
xml.push_str(" Serif=\"true\"");
}
if self.fixed_width {
xml.push_str(" FixedWidth=\"true\"");
}
if let Some(ref ff) = self.font_file {
write!(xml, " FontFile=\"{ff}\"").expect("写入内存缓冲区不会失败");
}
xml.push_str(" />");
xml
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ct_font_new() {
let font = CT_Font::new(1, "SimSun");
assert_eq!(font.id, 1);
assert_eq!(font.font_name, "SimSun");
assert!(!font.italic);
assert!(!font.bold);
assert!(!font.serif);
assert!(!font.fixed_width);
assert!(font.family_name.is_none());
assert!(font.font_file.is_none());
}
#[test]
fn test_ct_font_builder() {
let font = CT_Font::new(2, "SimHei")
.family_name("Sans-Serif")
.charset("Unicode")
.italic(true)
.bold(true)
.serif(false)
.fixed_width(true)
.font_file("simhei.ttf");
assert_eq!(font.get_font_name(), "SimHei");
assert_eq!(font.get_family_name(), Some("Sans-Serif"));
assert_eq!(font.get_charset(), Some("Unicode"));
assert!(font.is_italic());
assert!(font.is_bold());
assert!(!font.is_serif());
assert!(font.is_fixed_width());
assert_eq!(font.font_file.as_deref(), Some("simhei.ttf"));
}
#[test]
fn test_ct_font_to_xml_minimal() {
let font = CT_Font::new(1, "SimSun");
let xml = font.to_xml_string();
assert!(xml.contains("ID=\"1\""));
assert!(xml.contains("FontName=\"SimSun\""));
assert!(xml.contains("<ofd:Font"));
assert!(xml.ends_with(" />"));
}
#[test]
fn test_ct_font_to_xml_full() {
let font = CT_Font::new(5, "Arial")
.family_name("Sans-Serif")
.charset("Unicode")
.bold(true)
.italic(true)
.serif(true)
.fixed_width(true)
.font_file("arial.ttf");
let xml = font.to_xml_string();
assert!(xml.contains("ID=\"5\""));
assert!(xml.contains("FontName=\"Arial\""));
assert!(xml.contains("FamilyName=\"Sans-Serif\""));
assert!(xml.contains("Charset=\"Unicode\""));
assert!(xml.contains("Bold=\"true\""));
assert!(xml.contains("Italic=\"true\""));
assert!(xml.contains("Serif=\"true\""));
assert!(xml.contains("FixedWidth=\"true\""));
assert!(xml.contains("FontFile=\"arial.ttf\""));
}
#[test]
fn test_ct_font_clone_debug() {
let font = CT_Font::new(1, "x");
let font2 = font.clone();
assert_eq!(font2.get_font_name(), "x");
assert!(format!("{font:?}").contains("CT_Font"));
}
}