https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
The non-english articles have code.
- compute the set of bits (called a ‘region’) to operate on
- call the appropriate function to erase/fill/… that region
I would guess drawing ovals was done this way:
- create a region for a circle with radius equal to that of the radius of the corners.
- insert horizontal parts to each row of bits in the region to ‘stretch’ the region horizontally into a rounded rectangle that has the correct width, but is only as high as the circle.
- insert vertical parts to each column of bits in the region to ‘stretch’ the region vertically into a rounded rectangle that has the correct width and height.
The first step was identical for the code for drawing circles; the region data structure made the last two operations cheap; they did not require any memory allocations. You had to walk the entire data structure, but for small corner radiuses, it wasn’t that large. Also, one could probably optimize for speed by doing that while creating the region for the circle.
I can’t find a good description of the region data structure, but https://www.folklore.org/StoryView.py?project=Macintosh&stor... might be enough for some to figure out how it, conceptually, worked.
And remember: the original Mac had about 28 kilobytes of RAM free for applications. The system unloaded icons, code and fonts that were available on disk all the time. Few objects were ‘tiny’ at the time.