"""FontForge bounds boundary and its small, run-owned process result. Only standard-library dependencies: safe in FontForge's embedded Python. This is a numeric result, not a serialized legacy font or a font cache. """ import math SCHEMA = 'mtp2otf7-compatibility-metrics/1' BOUNDARY = 'fontforge-legacy-windows-assignment' def assign_windows(font): """Compute Windows bounds over the native glyph set.""" ymin = ymax = 0 for glyph in font.glyphs(): box = glyph.boundingBox() if box[1] == box[3] == 0 and box[0] == box[2] == 0: continue ymin = min(ymin, box[1]) ymax = max(ymax, box[3]) font.os2_winascent = max(806, int(math.ceil(ymax))) font.os2_winascent_add = 0 font.os2_windescent = max(194, int(math.ceil(-ymin))) font.os2_windescent_add = 0 return [ymin, ymax] def capture(font, snapshot, bounds): result = { 'schema': SCHEMA, 'boundary': BOUNDARY, 'condition': 'legacy', 'identity': snapshot['build_identity'], 'input_hashes': snapshot['inputs'], 'Windows': [font.os2_winascent, font.os2_windescent], 'typo': [ font.os2_typoascent, font.os2_typodescent, font.os2_typolinegap ], 'hhea': [font.hhea_ascent, font.hhea_descent, font.hhea_linegap], 'upm': font.em, 'bounds_y': bounds, } validate(result, snapshot) return result def integer_values(obj, key, count, lower, upper): values = obj.get(key) if ( not isinstance(values, list) or len(values) != count or any( type(value) is not int or not lower <= value <= upper for value in values ) ): raise ValueError('compatibility metrics integer range: ' + key) return values def validate_identity(obj): identity = obj.get('identity') if ( not isinstance(identity, dict) or identity.get('edition') not in ('full', 'lite') or identity.get('donor_coverage') not in ('minimal', 'extended') or type(identity.get('upm')) is not int or identity['upm'] != 1000 or not isinstance(identity.get('run_id'), str) or len(identity['run_id']) != 32 or any(c not in '0123456789abcdef' for c in identity['run_id']) ): raise ValueError('compatibility metrics identity invalid') inputs = obj.get('input_hashes') if ( not isinstance(inputs, dict) or not inputs.get('mtpro2') or not inputs.get('donors') ): raise ValueError('compatibility metrics input identity missing') def validate(result, snapshot=None): if not isinstance(result, dict): raise ValueError('compatibility metrics result must be an object') if ( result.get('schema') != SCHEMA or result.get('boundary') != BOUNDARY or result.get('condition') != 'legacy' ): raise ValueError('invalid compatibility metrics boundary') validate_identity(result) windows = integer_values(result, 'Windows', 2, 0, 65535) for key in ('typo', 'hhea'): if integer_values(result, key, 3, -32768, 32767) != [806, -194, 200]: raise ValueError( 'compatibility metrics vertical metrics mismatch: ' + key ) if ( type(result.get('upm')) is not int or result['upm'] != result['identity']['upm'] ): raise ValueError('compatibility metrics UPM mismatch') bounds = result.get('bounds_y') if ( not isinstance(bounds, list) or len(bounds) != 2 or any( type(value) not in (int, float) or not math.isfinite(value) for value in bounds ) or not bounds[0] <= 0 <= bounds[1] ): raise ValueError('compatibility metrics bounds invalid') if windows != [ max(806, math.ceil(bounds[1])), max(194, math.ceil(-bounds[0])) ]: raise ValueError('compatibility metrics bounds/Windows mismatch') if snapshot is not None: if result['identity'] != snapshot['build_identity']: raise ValueError( 'compatibility metrics run/edition/coverage/UPM mismatch' ) if result['input_hashes'] != snapshot['inputs']: raise ValueError('compatibility metrics source input mismatch') return result