https://github.com/gerph/riscos-font-controls-python
Parser for RISC OS Font control characters in Python
https://github.com/gerph/riscos-font-controls-python
python riscos
Last synced: 2 months ago
JSON representation
Parser for RISC OS Font control characters in Python
- Host: GitHub
- URL: https://github.com/gerph/riscos-font-controls-python
- Owner: gerph
- License: bsd-2-clause
- Created: 2021-10-23T19:28:06.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2026-01-12T14:11:25.000Z (2 months ago)
- Last Synced: 2026-01-12T20:12:42.728Z (2 months ago)
- Topics: python, riscos
- Language: Python
- Homepage:
- Size: 35.2 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Codeowners: CODEOWNERS
Awesome Lists containing this project
README
# RISC OS Font control parsing in Python
This repository contains a class (`FontControlParser`) for parsing font control codes from a
byte squence, in Python.
It is part of the RISC OS Pyromaniac font system, and provides support for the SWIs which operate
on the font strings:
* `Font_Paint` - uses the controls to determine what should be rendered.
* `Font_ScanString` - uses the controls to determine the size or break points of a string.
And all the other calls which call on to `Font_ScanString`:
* `Font_StringWidth` - reads the width of a string.
* `Font_StringBBox` - reads the coverage of a string.
* `Font_FindCaret` - finds the position of the caret within a string.
* `Font_FindCaretJ` - a variant of the `Font_FindCaret` call.
The `FontContext` provides information which allows the operation of the following calls:
* `Font_CurrentFont` - reads the current font.
* `Font_FutureFont` - reads what the font would be after one of the sizing calls.
* `Font_CurrentRGB` - reads the current colour.
* `Font_FutureRGB` - reads what the colour would be after one of the sizing calls.
## Usage
Inside RISC OS Pyromaniac...
* The `FontControlParser` is subclassed to allow the memory access to occur within the
emulated memory, not using the bytes.
* The `FontSpacing` is subclassed to create spacing from the memory blocks.
* The `FontContext` is subclassed to allow the GCOL/RGB operations, font lookups, sizing and rendering operations to be performed on the RISC OS graphics system.
A font context is created on initialisation, and will be updated by different operations:
```
self.context = FontContextPyromaniac(self.ro, self.fonts)
```
The font parser is constructed and supplied the memory buffers to parse:
```
memstring = self.ro.memory[regs[1]]
fc = FontControlParserPyromaniac(self.ro)
fc.debug_enable = self.debug_fontparser
fc.parse(memstring, string_length)
```
Once the other parameters for Font_Paint have been decoded and spacing and transformed written
to the `FontContext`, the paint operation is called.
```
self.context.x = xmilli
self.context.y = ymilli
self.context.transform = transform
with self.ro.kernel.graphics.vducursor.disable():
self.context.paint(fc.sequence, spacing)
# Update OS_ChangedBox
x0 = int(self.context.bounds.x0 / riscos.graphics.font.FontConstants.Font_OSUnit) >> xeig
y0 = int(self.context.bounds.y0 / riscos.graphics.font.FontConstants.Font_OSUnit) >> xeig
x1 = int(self.context.bounds.x1 / riscos.graphics.font.FontConstants.Font_OSUnit) >> yeig
y1 = int(self.context.bounds.y1 / riscos.graphics.font.FontConstants.Font_OSUnit) >> yeig
self.ro.kernel.graphics.changedbox_update(x0, y0, x1, y1)
```
`Font_ScanString` is similar, but instead of operating on the current context, the future context is updated:
```
self.context.copy(to=self.future_context)
...
memstring = self.ro.memory[regs[1]]
fc = FontControlParserPyromaniac(self.ro)
fc.debug_enable = self.debug_fontparser
fc.parse(memstring, string_length)
...
(split_offset, splits) = self.future_context.size(fc.sequence, spacing=spacing, limits=(xmilli, ymilli),
split_char=split_char)
```
This allows all the `Font_Future*` calls to query the `self.future_context`
## Tests
Tests exist to show that the module is working properly, intended for use on GitLab.
Code coverage is reported as well.
To test, use:
```
make tests PYTHON=python2
```
Tests don't work on Python 3 yet, due to some problems with the processing of byte sequences.
To run coverage, use:
```
make coverage
```