Ship out *box* at offset *xy*, converting it to an `Output`. Since boxes can be inside of boxes inside of boxes, the main work of `ship` is done by two mutually recursive routines, `hlist_out` and `vlist_out`, which traverse the `Hlist` nodes and `Vlist` nodes inside of horizontal
(box: Box, xy: tuple[float, float] = (0, 0))
| 1706 | |
| 1707 | |
| 1708 | def ship(box: Box, xy: tuple[float, float] = (0, 0)) -> Output: |
| 1709 | """ |
| 1710 | Ship out *box* at offset *xy*, converting it to an `Output`. |
| 1711 | |
| 1712 | Since boxes can be inside of boxes inside of boxes, the main work of `ship` |
| 1713 | is done by two mutually recursive routines, `hlist_out` and `vlist_out`, |
| 1714 | which traverse the `Hlist` nodes and `Vlist` nodes inside of horizontal |
| 1715 | and vertical boxes. The global variables used in TeX to store state as it |
| 1716 | processes have become local variables here. |
| 1717 | """ |
| 1718 | ox, oy = xy |
| 1719 | cur_v = 0. |
| 1720 | cur_h = 0. |
| 1721 | off_h = ox |
| 1722 | off_v = oy + box.height |
| 1723 | output = Output(box) |
| 1724 | phantom: list[bool] = [] |
| 1725 | |
| 1726 | def render(node, *args): |
| 1727 | if not any(phantom): |
| 1728 | node.render(*args) |
| 1729 | |
| 1730 | def clamp(value: float) -> float: |
| 1731 | return -1e9 if value < -1e9 else +1e9 if value > +1e9 else value |
| 1732 | |
| 1733 | def hlist_out(box: Hlist) -> None: |
| 1734 | nonlocal cur_v, cur_h |
| 1735 | |
| 1736 | cur_g = 0 |
| 1737 | cur_glue = 0. |
| 1738 | glue_order = box.glue_order |
| 1739 | glue_sign = box.glue_sign |
| 1740 | base_line = cur_v |
| 1741 | left_edge = cur_h |
| 1742 | |
| 1743 | phantom.append(box.is_phantom) |
| 1744 | |
| 1745 | for p in box.children: |
| 1746 | if isinstance(p, Char): |
| 1747 | render(p, output, cur_h + off_h, cur_v + off_v) |
| 1748 | cur_h += p.width |
| 1749 | elif isinstance(p, Kern): |
| 1750 | cur_h += p.width |
| 1751 | elif isinstance(p, List): |
| 1752 | # node623 |
| 1753 | if len(p.children) == 0: |
| 1754 | cur_h += p.width |
| 1755 | else: |
| 1756 | edge = cur_h |
| 1757 | cur_v = base_line + p.shift_amount |
| 1758 | if isinstance(p, Hlist): |
| 1759 | hlist_out(p) |
| 1760 | elif isinstance(p, Vlist): |
| 1761 | # p.vpack(box.height + box.depth, 'exactly') |
| 1762 | vlist_out(p) |
| 1763 | else: |
| 1764 | assert False, "unreachable code" |
| 1765 | cur_h = edge + p.width |