(font: TTFont, all_weight_map: dict[str, int])
| 442 | |
| 443 | |
| 444 | def patch_instance(font: TTFont, all_weight_map: dict[str, int]): |
| 445 | if all_weight_map == default_weight_map: |
| 446 | print("Skip weight remapping since nothing changed.") |
| 447 | return |
| 448 | |
| 449 | if "fvar" not in font or "STAT" not in font: |
| 450 | return |
| 451 | |
| 452 | if all_weight_map["thin"] != 100: |
| 453 | raise Exception("Font weight of `thin` must be 100") |
| 454 | |
| 455 | if all_weight_map["extrabold"] != 800: |
| 456 | raise Exception("Font weight of `extrabold` must be 800") |
| 457 | |
| 458 | value_to_name = {v: k for k, v in default_weight_map.items()} |
| 459 | |
| 460 | for instance in font["fvar"].instances: # type: ignore |
| 461 | current_weight = int(instance.coordinates["wght"]) |
| 462 | weight_name = value_to_name.get(current_weight) |
| 463 | if weight_name and weight_name in all_weight_map: |
| 464 | instance.coordinates["wght"] = all_weight_map[weight_name] |
| 465 | |
| 466 | axes = font["fvar"].axes # type: ignore |
| 467 | wght_index = next((i for i, ax in enumerate(axes) if ax.axisTag == "wght"), None) |
| 468 | if wght_index is None: |
| 469 | return |
| 470 | |
| 471 | stat = font["STAT"].table # type: ignore |
| 472 | if not stat.AxisValueArray: |
| 473 | return |
| 474 | |
| 475 | handlers = { |
| 476 | 1: lambda av: patch_single_value(av, "Value"), |
| 477 | 2: lambda av: patch_range_value(av), |
| 478 | 3: lambda av: ( |
| 479 | patch_single_value(av, "Value"), |
| 480 | patch_single_value(av, "LinkedValue"), |
| 481 | ), |
| 482 | 4: lambda av: [ |
| 483 | patch_single_value(rec, "Value") |
| 484 | for rec in av.AxisValueRecord |
| 485 | if rec.AxisIndex == wght_index |
| 486 | ], |
| 487 | } |
| 488 | |
| 489 | def patch_single_value(obj, attr: str) -> None: |
| 490 | current_value = int(getattr(obj, attr)) |
| 491 | weight_name = value_to_name.get(current_value) |
| 492 | if weight_name and weight_name in all_weight_map: |
| 493 | setattr(obj, attr, all_weight_map[weight_name]) |
| 494 | |
| 495 | def patch_range_value(av) -> None: |
| 496 | current_value = int(av.NominalValue) |
| 497 | weight_name = value_to_name.get(current_value) |
| 498 | if weight_name and weight_name in all_weight_map: |
| 499 | new_value = all_weight_map[weight_name] |
| 500 | delta = new_value - av.NominalValue |
| 501 | av.RangeMinValue += delta |
no test coverage detected