pcffont 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pcffont/__init__.py ADDED
@@ -0,0 +1,10 @@
1
+ from pcffont.font import PcfFont
2
+ from pcffont.header import PcfTableType
3
+ from pcffont.metric import PcfMetric
4
+ from pcffont.t_properties import PcfProperties
5
+ from pcffont.t_accelerators import PcfAccelerators
6
+ from pcffont.t_metrics import PcfMetrics
7
+ from pcffont.t_bitmaps import PcfBitmaps
8
+ from pcffont.t_encodings import PcfBdfEncodings
9
+ from pcffont.t_scalable_widths import PcfScalableWidths
10
+ from pcffont.t_glyph_names import PcfGlyphNames
pcffont/error.py ADDED
@@ -0,0 +1,25 @@
1
+
2
+ class PcfError(Exception):
3
+ pass
4
+
5
+
6
+ class PcfPropKeyError(PcfError):
7
+ def __init__(self, key: str, reason: str):
8
+ self.key = key
9
+ self.reason = reason
10
+ super().__init__(f"'{key}': {reason}")
11
+
12
+
13
+ class PcfPropValueError(PcfError):
14
+ def __init__(self, key: str, value: object, reason: str):
15
+ self.key = key
16
+ self.value = value
17
+ self.reason = reason
18
+ super().__init__(f"'{key}': '{value}': {reason}")
19
+
20
+
21
+ class PcfXlfdError(PcfError):
22
+ def __init__(self, font_name: str, reason: str):
23
+ self.font_name = font_name
24
+ self.reason = reason
25
+ super().__init__(f"'{font_name}': {reason}")
pcffont/font.py ADDED
@@ -0,0 +1,143 @@
1
+ import os
2
+ from collections import UserDict
3
+ from typing import BinaryIO
4
+
5
+ from pcffont.error import PcfError
6
+ from pcffont.header import PcfTableType, PcfHeader
7
+ from pcffont.internal import util
8
+ from pcffont.internal.buffer import Buffer
9
+ from pcffont.t_accelerators import PcfAccelerators
10
+ from pcffont.t_bitmaps import PcfBitmaps
11
+ from pcffont.t_encodings import PcfBdfEncodings
12
+ from pcffont.t_glyph_names import PcfGlyphNames
13
+ from pcffont.t_metrics import PcfMetrics
14
+ from pcffont.t_properties import PcfProperties
15
+ from pcffont.t_scalable_widths import PcfScalableWidths
16
+ from pcffont.table import PcfTable
17
+
18
+
19
+ class PcfFont(UserDict[PcfTableType, PcfTable]):
20
+ @staticmethod
21
+ def parse(stream: BinaryIO) -> 'PcfFont':
22
+ buffer = Buffer(stream)
23
+
24
+ headers = PcfHeader.parse(buffer)
25
+
26
+ tables = {}
27
+ for header in headers:
28
+ if header.table_type in tables:
29
+ raise PcfError(f"Duplicate table '{header.table_type.name}'")
30
+ tables[header.table_type] = util.parse_table(buffer, header)
31
+
32
+ return PcfFont(tables)
33
+
34
+ @staticmethod
35
+ def load(file_path: str | bytes | os.PathLike[str] | os.PathLike[bytes]) -> 'PcfFont':
36
+ with open(file_path, 'rb') as file:
37
+ return PcfFont.parse(file)
38
+
39
+ def __init__(self, tables: dict[PcfTableType, PcfTable | None] = None):
40
+ super().__init__(tables)
41
+
42
+ def __setitem__(self, table_type: PcfTableType, table: PcfTable | None):
43
+ if table is None:
44
+ self.pop(table_type, None)
45
+ else:
46
+ if not isinstance(table, util.TABLE_TYPE_REGISTRY[table_type]):
47
+ raise PcfError(f"Mismatched table type: '{table_type.name}' -> '{type(table)}'")
48
+ super().__setitem__(table_type, table)
49
+
50
+ def __repr__(self) -> str:
51
+ return object.__repr__(self)
52
+
53
+ @property
54
+ def properties(self) -> PcfProperties | None:
55
+ return self.get(PcfTableType.PROPERTIES, None)
56
+
57
+ @properties.setter
58
+ def properties(self, table: PcfProperties | None):
59
+ self[PcfTableType.PROPERTIES] = table
60
+
61
+ @property
62
+ def accelerators(self) -> PcfAccelerators | None:
63
+ return self.get(PcfTableType.ACCELERATORS, None)
64
+
65
+ @accelerators.setter
66
+ def accelerators(self, table: PcfAccelerators | None):
67
+ self[PcfTableType.ACCELERATORS] = table
68
+
69
+ @property
70
+ def metrics(self) -> PcfMetrics | None:
71
+ return self.get(PcfTableType.METRICS, None)
72
+
73
+ @metrics.setter
74
+ def metrics(self, table: PcfMetrics | None):
75
+ self[PcfTableType.METRICS] = table
76
+
77
+ @property
78
+ def bitmaps(self) -> PcfBitmaps | None:
79
+ return self.get(PcfTableType.BITMAPS, None)
80
+
81
+ @bitmaps.setter
82
+ def bitmaps(self, table: PcfBitmaps | None):
83
+ self[PcfTableType.BITMAPS] = table
84
+
85
+ @property
86
+ def ink_metrics(self) -> PcfMetrics | None:
87
+ return self.get(PcfTableType.INK_METRICS, None)
88
+
89
+ @ink_metrics.setter
90
+ def ink_metrics(self, table: PcfMetrics | None):
91
+ self[PcfTableType.INK_METRICS] = table
92
+
93
+ @property
94
+ def bdf_encodings(self) -> PcfBdfEncodings | None:
95
+ return self.get(PcfTableType.BDF_ENCODINGS, None)
96
+
97
+ @bdf_encodings.setter
98
+ def bdf_encodings(self, table: PcfBdfEncodings | None):
99
+ self[PcfTableType.BDF_ENCODINGS] = table
100
+
101
+ @property
102
+ def scalable_widths(self) -> PcfScalableWidths | None:
103
+ return self.get(PcfTableType.SWIDTHS, None)
104
+
105
+ @scalable_widths.setter
106
+ def scalable_widths(self, table: PcfScalableWidths | None):
107
+ self[PcfTableType.SWIDTHS] = table
108
+
109
+ @property
110
+ def glyph_names(self) -> PcfGlyphNames | None:
111
+ return self.get(PcfTableType.GLYPH_NAMES, None)
112
+
113
+ @glyph_names.setter
114
+ def glyph_names(self, table: PcfGlyphNames | None):
115
+ self[PcfTableType.GLYPH_NAMES] = table
116
+
117
+ @property
118
+ def bdf_accelerators(self) -> PcfAccelerators | None:
119
+ return self.get(PcfTableType.BDF_ACCELERATORS, None)
120
+
121
+ @bdf_accelerators.setter
122
+ def bdf_accelerators(self, table: PcfAccelerators | None):
123
+ self[PcfTableType.BDF_ACCELERATORS] = table
124
+
125
+ def dump(self, stream: BinaryIO, compat_mode: bool = False):
126
+ buffer = Buffer(stream)
127
+
128
+ headers = []
129
+ table_offset = 4 + 4 + (4 * 4) * len(self)
130
+ for table_type, table in sorted(self.items()):
131
+ table_size = table.dump(buffer, table_offset, compat_mode)
132
+ headers.append(PcfHeader(table_type, table.table_format, table_size, table_offset))
133
+ table_offset += table_size
134
+
135
+ PcfHeader.dump(buffer, headers)
136
+
137
+ def save(
138
+ self,
139
+ file_path: str | bytes | os.PathLike[str] | os.PathLike[bytes],
140
+ compat_mode: bool = False,
141
+ ):
142
+ with open(file_path, 'wb') as file:
143
+ self.dump(file, compat_mode)
pcffont/header.py ADDED
@@ -0,0 +1,70 @@
1
+ from enum import IntEnum, IntFlag
2
+
3
+ from pcffont.error import PcfError
4
+ from pcffont.internal.buffer import Buffer
5
+
6
+ _MAGIC_STRING = b'\x01fcp'
7
+
8
+
9
+ class PcfTableType(IntEnum):
10
+ PROPERTIES = 1 << 0
11
+ ACCELERATORS = 1 << 1
12
+ METRICS = 1 << 2
13
+ BITMAPS = 1 << 3
14
+ INK_METRICS = 1 << 4
15
+ BDF_ENCODINGS = 1 << 5
16
+ SWIDTHS = 1 << 6
17
+ GLYPH_NAMES = 1 << 7
18
+ BDF_ACCELERATORS = 1 << 8
19
+
20
+
21
+ class PcfTableFormat(IntFlag):
22
+ DEFAULT_FORMAT = 0b_0000_0000_0000
23
+ INKBOUNDS = 0b_0010_0000_0000
24
+ ACCEL_W_INKBOUNDS = 0b_0001_0000_0000
25
+ COMPRESSED_METRICS = 0b_0001_0000_0000
26
+
27
+
28
+ class PcfTableFormatMask(IntFlag):
29
+ GLYPH_PAD = 0b_0000_0011
30
+ BYTE = 0b_0000_0100
31
+ BIT = 0b_0000_1000
32
+ SCAN_UNIT = 0b_0011_0000
33
+
34
+
35
+ class PcfHeader:
36
+ @staticmethod
37
+ def parse(buffer: Buffer) -> list['PcfHeader']:
38
+ buffer.seek(0)
39
+ if buffer.read(4) != _MAGIC_STRING:
40
+ raise PcfError('Not PCF format')
41
+
42
+ tables_count = buffer.read_int32_le()
43
+
44
+ headers = []
45
+ for _ in range(tables_count):
46
+ table_type = PcfTableType(buffer.read_int32_le())
47
+ table_format = buffer.read_int32_le()
48
+ table_size = buffer.read_int32_le()
49
+ table_offset = buffer.read_int32_le()
50
+ headers.append(PcfHeader(table_type, table_format, table_size, table_offset))
51
+
52
+ return headers
53
+
54
+ @staticmethod
55
+ def dump(buffer: Buffer, headers: list['PcfHeader']):
56
+ buffer.seek(0)
57
+ buffer.write(_MAGIC_STRING)
58
+
59
+ buffer.write_int32_le(len(headers))
60
+ for header in headers:
61
+ buffer.write_int32_le(header.table_type)
62
+ buffer.write_int32_le(header.table_format)
63
+ buffer.write_int32_le(header.table_size)
64
+ buffer.write_int32_le(header.table_offset)
65
+
66
+ def __init__(self, table_type: PcfTableType, table_format: int, table_size: int, table_offset: int):
67
+ self.table_type = table_type
68
+ self.table_format = table_format
69
+ self.table_size = table_size
70
+ self.table_offset = table_offset
File without changes
@@ -0,0 +1,122 @@
1
+ from typing import BinaryIO, Literal, TypeAlias
2
+
3
+ # TODO # type ByteOrder = Literal['little', 'big']
4
+ ByteOrder: TypeAlias = Literal['little', 'big']
5
+
6
+
7
+ class Buffer:
8
+ def __init__(self, stream: BinaryIO):
9
+ self.stream = stream
10
+
11
+ def read(self, n: int) -> bytes:
12
+ return self.stream.read(n)
13
+
14
+ def read_int(self, n: int, byte_order: ByteOrder) -> int:
15
+ return int.from_bytes(self.read(n), byte_order)
16
+
17
+ def read_int_le(self, n: int) -> int:
18
+ return self.read_int(n, 'little')
19
+
20
+ def read_int_be(self, n: int) -> int:
21
+ return self.read_int(n, 'big')
22
+
23
+ def read_int32(self, byte_order: ByteOrder) -> int:
24
+ return self.read_int(4, byte_order)
25
+
26
+ def read_int32_le(self) -> int:
27
+ return self.read_int32('little')
28
+
29
+ def read_int32_be(self) -> int:
30
+ return self.read_int32('big')
31
+
32
+ def read_int16(self, byte_order: ByteOrder) -> int:
33
+ return self.read_int(2, byte_order)
34
+
35
+ def read_int16_le(self) -> int:
36
+ return self.read_int16('little')
37
+
38
+ def read_int16_be(self) -> int:
39
+ return self.read_int16('big')
40
+
41
+ def read_int8(self, byte_order: ByteOrder) -> int:
42
+ return self.read_int(1, byte_order)
43
+
44
+ def read_int8_le(self) -> int:
45
+ return self.read_int8('little')
46
+
47
+ def read_int8_be(self) -> int:
48
+ return self.read_int8('big')
49
+
50
+ def read_bool(self) -> bool:
51
+ return self.read(1) != b'\x00'
52
+
53
+ def read_string(self) -> str:
54
+ data = bytearray()
55
+ while True:
56
+ b = self.read(1)
57
+ if b == b'\x00' or b == b'':
58
+ break
59
+ data.extend(b)
60
+ return data.decode('utf-8')
61
+
62
+ def write(self, s: bytes) -> int:
63
+ return self.stream.write(s)
64
+
65
+ def write_int(self, i: int, n: int, byte_order: ByteOrder) -> int:
66
+ return self.write(i.to_bytes(n, byte_order))
67
+
68
+ def write_int_le(self, i: int, n: int) -> int:
69
+ return self.write_int(i, n, 'little')
70
+
71
+ def write_int_be(self, i: int, n: int) -> int:
72
+ return self.write_int(i, n, 'big')
73
+
74
+ def write_int32(self, i: int, byte_order: ByteOrder) -> int:
75
+ return self.write_int(i, 4, byte_order)
76
+
77
+ def write_int32_le(self, i: int) -> int:
78
+ return self.write_int32(i, 'little')
79
+
80
+ def write_int32_be(self, i: int) -> int:
81
+ return self.write_int32(i, 'big')
82
+
83
+ def write_int16(self, i: int, byte_order: ByteOrder) -> int:
84
+ return self.write_int(i, 2, byte_order)
85
+
86
+ def write_int16_le(self, i: int) -> int:
87
+ return self.write_int16(i, 'little')
88
+
89
+ def write_int16_be(self, i: int) -> int:
90
+ return self.write_int16(i, 'big')
91
+
92
+ def write_int8(self, i: int, byte_order: ByteOrder) -> int:
93
+ return self.write_int(i, 1, byte_order)
94
+
95
+ def write_int8_le(self, i: int) -> int:
96
+ return self.write_int8(i, 'little')
97
+
98
+ def write_int8_be(self, i: int) -> int:
99
+ return self.write_int8(i, 'big')
100
+
101
+ def write_bool(self, b: bool) -> int:
102
+ return self.write(b'\x01' if b else b'\x00')
103
+
104
+ def write_nulls(self, n: int) -> int:
105
+ for _ in range(n):
106
+ self.write(b'\x00')
107
+ return n
108
+
109
+ def write_string(self, s: str) -> int:
110
+ return self.write(s.encode('utf-8')) + self.write_nulls(1)
111
+
112
+ def skip(self, n: int):
113
+ self.seek(self.tell() + n)
114
+
115
+ def skip_int(self):
116
+ self.skip(4)
117
+
118
+ def seek(self, offset: int):
119
+ self.stream.seek(offset)
120
+
121
+ def tell(self) -> int:
122
+ return self.stream.tell()
@@ -0,0 +1,49 @@
1
+ from pcffont.error import PcfError
2
+ from pcffont.header import PcfTableType, PcfTableFormatMask, PcfHeader
3
+ from pcffont.internal.buffer import ByteOrder, Buffer
4
+ from pcffont.t_accelerators import PcfAccelerators
5
+ from pcffont.t_bitmaps import PcfBitmaps
6
+ from pcffont.t_encodings import PcfBdfEncodings
7
+ from pcffont.t_glyph_names import PcfGlyphNames
8
+ from pcffont.t_metrics import PcfMetrics
9
+ from pcffont.t_properties import PcfProperties
10
+ from pcffont.t_scalable_widths import PcfScalableWidths
11
+ from pcffont.table import PcfTable
12
+
13
+ TABLE_TYPE_REGISTRY = {
14
+ PcfTableType.PROPERTIES: PcfProperties,
15
+ PcfTableType.ACCELERATORS: PcfAccelerators,
16
+ PcfTableType.METRICS: PcfMetrics,
17
+ PcfTableType.BITMAPS: PcfBitmaps,
18
+ PcfTableType.INK_METRICS: PcfMetrics,
19
+ PcfTableType.BDF_ENCODINGS: PcfBdfEncodings,
20
+ PcfTableType.SWIDTHS: PcfScalableWidths,
21
+ PcfTableType.GLYPH_NAMES: PcfGlyphNames,
22
+ PcfTableType.BDF_ACCELERATORS: PcfAccelerators,
23
+ }
24
+
25
+
26
+ def parse_table(buffer: Buffer, header: PcfHeader) -> PcfTable | None:
27
+ clz = TABLE_TYPE_REGISTRY.get(header.table_type, None)
28
+ if clz is not None:
29
+ return clz.parse(buffer, header)
30
+ return None
31
+
32
+
33
+ def read_and_check_table_format(buffer: Buffer, header: PcfHeader) -> int:
34
+ buffer.seek(header.table_offset)
35
+ table_format = buffer.read_int32_le()
36
+ if table_format != header.table_format:
37
+ raise PcfError(f"The table format definition is inconsistent with the header: type '{header.table_type.name}', offset {header.table_offset}")
38
+ return table_format
39
+
40
+
41
+ def get_table_byte_order(table_format: int) -> ByteOrder:
42
+ byte_mask = table_format & PcfTableFormatMask.BYTE > 0
43
+ bit_mask = table_format & PcfTableFormatMask.BIT > 0
44
+ if byte_mask and bit_mask:
45
+ return 'big'
46
+ elif (not byte_mask) and (not bit_mask):
47
+ return 'little'
48
+ else:
49
+ raise PcfError(f'Table format not supported: {table_format:b}')
pcffont/metric.py ADDED
@@ -0,0 +1,59 @@
1
+ from pcffont.internal.buffer import ByteOrder, Buffer
2
+
3
+
4
+ class PcfMetric:
5
+ @staticmethod
6
+ def parse(buffer: Buffer, byte_order: ByteOrder, is_compressed: bool) -> 'PcfMetric':
7
+ if is_compressed:
8
+ left_sided_bearing = buffer.read_int8(byte_order)
9
+ right_side_bearing = buffer.read_int8(byte_order)
10
+ character_width = buffer.read_int8(byte_order)
11
+ character_ascent = buffer.read_int8(byte_order)
12
+ character_descent = buffer.read_int8(byte_order)
13
+ character_attributes = 0
14
+ else:
15
+ left_sided_bearing = buffer.read_int16(byte_order)
16
+ right_side_bearing = buffer.read_int16(byte_order)
17
+ character_width = buffer.read_int16(byte_order)
18
+ character_ascent = buffer.read_int16(byte_order)
19
+ character_descent = buffer.read_int16(byte_order)
20
+ character_attributes = buffer.read_int16(byte_order)
21
+ return PcfMetric(
22
+ left_sided_bearing,
23
+ right_side_bearing,
24
+ character_width,
25
+ character_ascent,
26
+ character_descent,
27
+ character_attributes,
28
+ )
29
+
30
+ def __init__(
31
+ self,
32
+ left_sided_bearing: int,
33
+ right_side_bearing: int,
34
+ character_width: int,
35
+ character_ascent: int,
36
+ character_descent: int,
37
+ character_attributes: int = 0,
38
+ ):
39
+ self.left_sided_bearing = left_sided_bearing
40
+ self.right_side_bearing = right_side_bearing
41
+ self.character_width = character_width
42
+ self.character_ascent = character_ascent
43
+ self.character_descent = character_descent
44
+ self.character_attributes = character_attributes
45
+
46
+ def dump(self, buffer: Buffer, byte_order: ByteOrder, is_compressed: bool):
47
+ if is_compressed:
48
+ buffer.write_int8(self.left_sided_bearing, byte_order)
49
+ buffer.write_int8(self.right_side_bearing, byte_order)
50
+ buffer.write_int8(self.character_width, byte_order)
51
+ buffer.write_int8(self.character_ascent, byte_order)
52
+ buffer.write_int8(self.character_descent, byte_order)
53
+ else:
54
+ buffer.write_int16(self.left_sided_bearing, byte_order)
55
+ buffer.write_int16(self.right_side_bearing, byte_order)
56
+ buffer.write_int16(self.character_width, byte_order)
57
+ buffer.write_int16(self.character_ascent, byte_order)
58
+ buffer.write_int16(self.character_descent, byte_order)
59
+ buffer.write_int16(self.character_attributes, byte_order)
@@ -0,0 +1,143 @@
1
+ from pcffont.header import PcfTableFormat, PcfHeader
2
+ from pcffont.internal import util
3
+ from pcffont.internal.buffer import Buffer
4
+ from pcffont.metric import PcfMetric
5
+ from pcffont.table import PcfTable
6
+
7
+
8
+ class PcfAccelerators(PcfTable):
9
+ @staticmethod
10
+ def parse(buffer: Buffer, header: PcfHeader) -> 'PcfAccelerators':
11
+ table_format = util.read_and_check_table_format(buffer, header)
12
+ byte_order = util.get_table_byte_order(table_format)
13
+ is_accel_w_ink_bounds = table_format & PcfTableFormat.ACCEL_W_INKBOUNDS > 0
14
+
15
+ no_overlap = buffer.read_bool()
16
+ constant_metrics = buffer.read_bool()
17
+ terminal_font = buffer.read_bool()
18
+ constant_width = buffer.read_bool()
19
+ ink_inside = buffer.read_bool()
20
+ ink_metrics = buffer.read_bool()
21
+ draw_direction_right_to_left = buffer.read_bool()
22
+ buffer.skip(1)
23
+ font_ascent = buffer.read_int32(byte_order)
24
+ font_descent = buffer.read_int32(byte_order)
25
+ max_overlap = buffer.read_int32(byte_order)
26
+
27
+ min_bounds = PcfMetric.parse(buffer, byte_order, False)
28
+ max_bounds = PcfMetric.parse(buffer, byte_order, False)
29
+
30
+ _ink_bounds_chunk = None # TODO
31
+ _padding_chunk_info = None # TODO
32
+
33
+ if is_accel_w_ink_bounds:
34
+ ink_min_bounds = PcfMetric.parse(buffer, byte_order, False)
35
+ ink_max_bounds = PcfMetric.parse(buffer, byte_order, False)
36
+ else:
37
+ ink_min_bounds = None
38
+ ink_max_bounds = None
39
+ # TODO
40
+ if header.table_size >= buffer.tell() - header.table_offset + 2 * 6 * 2:
41
+ _ink_bounds_chunk = buffer.read(2 * 6 * 2)
42
+
43
+ # TODO
44
+ _padding = header.table_size - (buffer.tell() - header.table_offset)
45
+ if _padding > 0:
46
+ _padding_chunk_info = buffer.read(_padding), _padding
47
+
48
+ return PcfAccelerators(
49
+ table_format,
50
+ no_overlap,
51
+ constant_metrics,
52
+ terminal_font,
53
+ constant_width,
54
+ ink_inside,
55
+ ink_metrics,
56
+ draw_direction_right_to_left,
57
+ font_ascent,
58
+ font_descent,
59
+ max_overlap,
60
+ min_bounds,
61
+ max_bounds,
62
+ ink_min_bounds,
63
+ ink_max_bounds,
64
+ _ink_bounds_chunk, # TODO
65
+ _padding_chunk_info, # TODO
66
+ )
67
+
68
+ def __init__(
69
+ self,
70
+ table_format: int = PcfTable.DEFAULT_TABLE_FORMAT,
71
+ no_overlap: bool = False,
72
+ constant_metrics: bool = False,
73
+ terminal_font: bool = False,
74
+ constant_width: bool = False,
75
+ ink_inside: bool = False,
76
+ ink_metrics: bool = False,
77
+ draw_direction_right_to_left: bool = False,
78
+ font_ascent: int = 0,
79
+ font_descent: int = 0,
80
+ max_overlap: int = 0,
81
+ min_bounds: PcfMetric = None,
82
+ max_bounds: PcfMetric = None,
83
+ ink_min_bounds: PcfMetric = None,
84
+ ink_max_bounds: PcfMetric = None,
85
+ _ink_bounds_chunk: bytes = None, # TODO
86
+ _padding_chunk_info: tuple[bytes, int] = None, # TODO
87
+ ):
88
+ super().__init__(table_format)
89
+ self.no_overlap = no_overlap
90
+ self.constant_metrics = constant_metrics
91
+ self.terminal_font = terminal_font
92
+ self.constant_width = constant_width
93
+ self.ink_inside = ink_inside
94
+ self.ink_metrics = ink_metrics
95
+ self.draw_direction_right_to_left = draw_direction_right_to_left
96
+ self.font_ascent = font_ascent
97
+ self.font_descent = font_descent
98
+ self.max_overlap = max_overlap
99
+ self.min_bounds = min_bounds
100
+ self.max_bounds = max_bounds
101
+ self.ink_min_bounds = ink_min_bounds
102
+ self.ink_max_bounds = ink_max_bounds
103
+ self._ink_bounds_chunk = _ink_bounds_chunk # TODO
104
+ self._padding_chunk_info = _padding_chunk_info # TODO
105
+
106
+ def _dump(self, buffer: Buffer, table_offset: int, compat_mode: bool = False) -> int:
107
+ byte_order = util.get_table_byte_order(self.table_format)
108
+ is_accel_w_ink_bounds = self.table_format & PcfTableFormat.ACCEL_W_INKBOUNDS > 0
109
+
110
+ buffer.seek(table_offset)
111
+ buffer.write_int32_le(self.table_format)
112
+ buffer.write_bool(self.no_overlap)
113
+ buffer.write_bool(self.constant_metrics)
114
+ buffer.write_bool(self.terminal_font)
115
+ buffer.write_bool(self.constant_width)
116
+ buffer.write_bool(self.ink_inside)
117
+ buffer.write_bool(self.ink_metrics)
118
+ buffer.write_bool(self.draw_direction_right_to_left)
119
+ buffer.write_nulls(1)
120
+ buffer.write_int32(self.font_ascent, byte_order)
121
+ buffer.write_int32(self.font_descent, byte_order)
122
+ buffer.write_int32(self.max_overlap, byte_order)
123
+
124
+ self.min_bounds.dump(buffer, byte_order, False)
125
+ self.max_bounds.dump(buffer, byte_order, False)
126
+
127
+ if is_accel_w_ink_bounds:
128
+ self.ink_min_bounds.dump(buffer, byte_order, False)
129
+ self.ink_max_bounds.dump(buffer, byte_order, False)
130
+ else:
131
+ # TODO
132
+ if compat_mode and self._ink_bounds_chunk is not None:
133
+ buffer.write(self._ink_bounds_chunk)
134
+
135
+ table_size = buffer.tell() - table_offset
136
+
137
+ # TODO
138
+ if compat_mode and self._padding_chunk_info is not None:
139
+ _padding_chunk, _padding = self._padding_chunk_info
140
+ buffer.write(_padding_chunk)
141
+ table_size += _padding
142
+
143
+ return table_size