// 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.
///|
/// Shaping caches (font metadata + feature store).
///
/// Ported from `upstream swash/src/shape/cache.rs`.
pub type Epoch = UInt64
///|
pub struct FontEntry {
metrics : @swash.MetricsProxy
charmap : @swash.CharmapProxy
coord_count : UInt16
metadata : EngineMetadata
}
///|
///|
pub fn FontEntry::FontEntry(font : @swash.FontRef) -> FontEntry {
let coords = font.variations().iter().to_array()
{
metrics: @swash.MetricsProxy::from_font(font),
charmap: @swash.CharmapProxy::from_font(font),
coord_count: coords.length().to_uint16(),
metadata: EngineMetadata::from_font(font),
}
}
///|
priv struct FeatureEntry {
mut epoch : Epoch
mut id0 : UInt64
mut id1 : UInt64
coords : Array[Int32]
mut tags : (UInt32, UInt32, UInt32, UInt32)
store : Ref[FeatureStore]
}
///|
priv struct FeatureCache {
entries : Array[FeatureEntry]
mut epoch : Epoch
max_entries : Int32
}
///|
///|
priv enum FeatureCacheEntry {
New(Ref[FeatureStore])
Present(Ref[FeatureStore])
}
///|
fn FeatureCache::FeatureCache(max_entries : Int32) -> FeatureCache {
let max_entries = if max_entries < 1 { 1 } else { max_entries }
{ entries: [], epoch: 0, max_entries, }
}
///|
fn FeatureCache::entry(
self : FeatureCache,
id : (UInt64, UInt64),
coords : ArrayView[Int32],
has_feature_vars : Bool,
tags : (UInt32, UInt32, UInt32, UInt32),
) -> FeatureCacheEntry {
let (found, index) = self.find_entry(id, coords, has_feature_vars, tags)
let e = self.entries.at(index)
e.epoch = self.epoch
self.entries.set(index, e)
if found {
Present(e.store)
} else {
New(e.store)
}
}
///|
fn coords_eq(a : ArrayView[Int32], b : Array[Int32]) -> Bool {
if a.length() != b.length() {
return false
}
for i in 0.. (Bool, Int32) {
let mut lowest_epoch = self.epoch
let mut lowest_index = 0
for i in 0..