// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
/// Instance-related types.
///
/// Ported from `fontations/skrifa` (Apache-2.0 OR MIT).
pub type NormalizedCoord = Int
///|
pub struct Size {
ppem : Double?
}
///|
pub fn Size::Size(size : Double) -> Size {
{ ppem: Some(size) }
}
///|
pub fn Size::unscaled() -> Size {
{ ppem: None }
}
///|
pub fn Size::ppem(self : Size) -> Double? {
self.ppem
}
///|
/// Computes a linear scale factor for this font size and the given units-per-em.
///
/// Returns 1.0 for an unscaled size or when `units_per_em` is 0.
pub fn Size::linear_scale(self : Size, units_per_em : UInt16) -> Double {
match self.ppem {
Some(ppem) => {
let upem = units_per_em.to_int()
if upem != 0 {
ppem / upem.to_double()
} else {
1.0
}
}
None => 1.0
}
}
///|
/// Computes a 16.16 fixed-point linear scale factor that matches FreeType.
///
/// This is intended for internal routines that apply the FreeType-style
/// `mul_div(value, scale, 64)` pattern.
pub fn Size::fixed_linear_scale(self : Size, units_per_em : UInt16) -> Int {
match self.ppem {
Some(ppem) => {
let upem = units_per_em.to_int()
if upem > 0 {
let scaled_h = (ppem * 64.0).to_int()
(scaled_h << 16) / upem
} else {
0x10000 * 64
}
}
None => 0x10000 * 64
}
}
///|
/// Legacy helper for the earlier API.
pub fn Size::value(self : Size) -> Double {
match self.ppem {
Some(ppem) => ppem
None => 0.0
}
}
///|
/// Maximum number of coords to store inline in a `Location` object.
const MAX_INLINE_COORDS : Int = 8
///|
/// Reference to an ordered sequence of normalized variation coordinates.
///
/// This is a minimal port of `LocationRef` from upstream.
pub struct LocationRef {
priv coords : ArrayView[NormalizedCoord]
}
///|
pub fn LocationRef::LocationRef(
coords : ArrayView[NormalizedCoord],
) -> LocationRef {
{ coords, }
}
///|
pub fn LocationRef::default() -> LocationRef {
let empty : Array[NormalizedCoord] = Array::new()
LocationRef(empty.op_as_view())
}
///|
pub fn LocationRef::coords(self : LocationRef) -> ArrayView[NormalizedCoord] {
self.coords
}
///|
pub fn LocationRef::is_default(self : LocationRef) -> Bool {
self.coords.is_empty() || self.coords.all(fn(coord) { coord == 0 })
}
///|
/// Returns the underlying coordinate array if any entries are non-zero.
///
/// Otherwise returns an empty view (to bypass downstream variation logic).
pub fn LocationRef::effective_coords(
self : LocationRef,
) -> ArrayView[NormalizedCoord] {
if self.is_default() {
let empty : Array[NormalizedCoord] = Array::new()
empty.op_as_view()
} else {
self.coords
}
}
///|
/// Owned ordered sequence of normalized variation coordinates.
pub struct Location {
priv coords : SmallVec[NormalizedCoord]
}
///|
pub fn Location::Location(len : Int) -> Location {
{ coords: SmallVec::with_len(len, 0, MAX_INLINE_COORDS) }
}
///|
pub fn Location::from_array(coords : Array[NormalizedCoord]) -> Location {
let len = coords.length()
let mut v = SmallVec::with_len(len, 0, MAX_INLINE_COORDS)
for i in 0.. ArrayView[NormalizedCoord] {
self.coords.as_view()
}
///|
pub fn Location::as_ref(self : Location) -> LocationRef {
LocationRef(self.coords.as_view())
}