altos: Add bitmap drawing code
authorKeith Packard <keithp@keithp.com>
Mon, 20 Feb 2017 20:17:42 +0000 (12:17 -0800)
committerKeith Packard <keithp@keithp.com>
Mon, 20 Feb 2017 20:34:02 +0000 (12:34 -0800)
Includes solid fills, text and lines.

Signed-off-by: Keith Packard <keithp@keithp.com>
13 files changed:
src/draw/5x7.bdf [new file with mode: 0644]
src/draw/Makefile [new file with mode: 0644]
src/draw/ao_blt.c [new file with mode: 0644]
src/draw/ao_copy.c [new file with mode: 0644]
src/draw/ao_draw.h [new file with mode: 0644]
src/draw/ao_draw_int.h [new file with mode: 0644]
src/draw/ao_font.h [new file with mode: 0644]
src/draw/ao_line.c [new file with mode: 0644]
src/draw/ao_pattern.c [new file with mode: 0644]
src/draw/ao_rect.c [new file with mode: 0644]
src/draw/ao_text.c [new file with mode: 0644]
src/draw/font-convert [new file with mode: 0755]
src/draw/line.5c [new file with mode: 0644]

diff --git a/src/draw/5x7.bdf b/src/draw/5x7.bdf
new file mode 100644 (file)
index 0000000..b511f28
--- /dev/null
@@ -0,0 +1,3190 @@
+STARTFONT 2.1
+COMMENT  Copyright 1991 Massachusetts Institute of Technology
+COMMENT  
+COMMENT  Permission to use, copy, modify, and distribute this software
+COMMENT  and its documentation for any purpose and without fee is
+COMMENT  hereby granted, provided that the above copyright notice
+COMMENT  appear in all copies and that both that copyright notice and
+COMMENT  this permission notice appear in supporting documentation,
+COMMENT  and that the name of M.I.T. not be used in advertising or
+COMMENT  publicity pertaining to distribution of the software without
+COMMENT  specific, written prior permission.  M.I.T. makes no
+COMMENT  representations about the suitability of this software for
+COMMENT  any purpose.  It is provided "as is" without express or
+COMMENT  implied warranty.
+COMMENT  
+COMMENT  M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+COMMENT  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+COMMENT  FITNESS, IN NO EVENT SHALL M.I.T.  BE LIABLE FOR ANY SPECIAL,
+COMMENT  INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+COMMENT  RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+COMMENT  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+COMMENT  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+COMMENT  OF THIS SOFTWARE.
+COMMENT  
+COMMENT  Author:  Stephen Gildea, MIT X Consortium, June 1991
+COMMENT  
+FONT -Misc-Fixed-Medium-R-Normal--7-70-75-75-C-50-ISO8859-1
+SIZE 7 75 75
+FONTBOUNDINGBOX 5 7 0 -1
+STARTPROPERTIES 21
+FONTNAME_REGISTRY ""
+FOUNDRY "Misc"
+FAMILY_NAME "Fixed"
+WEIGHT_NAME "Medium"
+SLANT "R"
+SETWIDTH_NAME "Normal"
+ADD_STYLE_NAME ""
+PIXEL_SIZE 7
+POINT_SIZE 70
+RESOLUTION_X 75
+RESOLUTION_Y 75
+SPACING "C"
+AVERAGE_WIDTH 50
+CHARSET_REGISTRY "ISO8859"
+CHARSET_ENCODING "1"
+FONT_ASCENT 6
+FONT_DESCENT 1
+UNDERLINE_POSITION 0
+DESTINATION 1
+DEFAULT_CHAR 0
+COPYRIGHT "Copyright 1991 Massachusetts Institute of Technology"
+ENDPROPERTIES
+CHARS 224
+STARTCHAR C000
+ENCODING 0
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+f0
+f0
+f0
+f0
+f0
+00
+ENDCHAR
+STARTCHAR C001
+ENCODING 1
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+20
+70
+f8
+70
+20
+00
+ENDCHAR
+STARTCHAR C002
+ENCODING 2
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+a0
+50
+a0
+50
+a0
+00
+ENDCHAR
+STARTCHAR C003
+ENCODING 3
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+e0
+a0
+a0
+70
+20
+20
+ENDCHAR
+STARTCHAR C004
+ENCODING 4
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+c0
+80
+c0
+b0
+20
+30
+20
+ENDCHAR
+STARTCHAR C005
+ENCODING 5
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+c0
+80
+c0
+60
+50
+60
+50
+ENDCHAR
+STARTCHAR C006
+ENCODING 6
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+80
+c0
+30
+20
+30
+20
+ENDCHAR
+STARTCHAR C007
+ENCODING 7
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+50
+20
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C010
+ENCODING 8
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+70
+20
+00
+70
+00
+00
+ENDCHAR
+STARTCHAR C011
+ENCODING 9
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+d0
+b0
+90
+20
+20
+30
+ENDCHAR
+STARTCHAR C012
+ENCODING 10
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+a0
+a0
+40
+70
+20
+20
+ENDCHAR
+STARTCHAR C013
+ENCODING 11
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+20
+e0
+00
+00
+00
+ENDCHAR
+STARTCHAR C014
+ENCODING 12
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+e0
+20
+20
+20
+ENDCHAR
+STARTCHAR C015
+ENCODING 13
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+38
+20
+20
+20
+ENDCHAR
+STARTCHAR C016
+ENCODING 14
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+20
+38
+00
+00
+00
+ENDCHAR
+STARTCHAR C017
+ENCODING 15
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+20
+f8
+20
+20
+20
+ENDCHAR
+STARTCHAR C020
+ENCODING 16
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+f8
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C021
+ENCODING 17
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 6 7 0 -1
+BITMAP
+00
+00
+f8
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C022
+ENCODING 18
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+f8
+00
+00
+00
+ENDCHAR
+STARTCHAR C023
+ENCODING 19
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+f8
+00
+00
+ENDCHAR
+STARTCHAR C024
+ENCODING 20
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+00
+f8
+00
+ENDCHAR
+STARTCHAR C025
+ENCODING 21
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+20
+38
+20
+20
+20
+ENDCHAR
+STARTCHAR C026
+ENCODING 22
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+20
+e0
+20
+20
+20
+ENDCHAR
+STARTCHAR C027
+ENCODING 23
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 6 7 0 -1
+BITMAP
+20
+20
+20
+f8
+00
+00
+00
+ENDCHAR
+STARTCHAR C030
+ENCODING 24
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+f8
+20
+20
+20
+ENDCHAR
+STARTCHAR C031
+ENCODING 25
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+20
+20
+20
+20
+20
+ENDCHAR
+STARTCHAR C032
+ENCODING 26
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+10
+20
+40
+20
+10
+70
+00
+ENDCHAR
+STARTCHAR C033
+ENCODING 27
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+20
+10
+20
+40
+70
+00
+ENDCHAR
+STARTCHAR C034
+ENCODING 28
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+70
+50
+50
+50
+00
+ENDCHAR
+STARTCHAR C035
+ENCODING 29
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+10
+70
+20
+70
+40
+00
+ENDCHAR
+STARTCHAR C036
+ENCODING 30
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+30
+40
+e0
+40
+b0
+00
+ENDCHAR
+STARTCHAR C037
+ENCODING 31
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+20
+00
+00
+00
+ENDCHAR
+STARTCHAR C040
+ENCODING 32
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR !
+ENCODING 33
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+20
+20
+00
+20
+00
+ENDCHAR
+STARTCHAR "
+ENCODING 34
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+50
+50
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR #
+ENCODING 35
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+50
+f8
+50
+f8
+50
+00
+ENDCHAR
+STARTCHAR $
+ENCODING 36
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+70
+a0
+70
+28
+70
+00
+ENDCHAR
+STARTCHAR %
+ENCODING 37
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+90
+20
+40
+90
+10
+00
+ENDCHAR
+STARTCHAR &
+ENCODING 38
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+40
+a0
+40
+a0
+50
+00
+ENDCHAR
+STARTCHAR '
+ENCODING 39
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+40
+80
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR (
+ENCODING 40
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+40
+40
+40
+20
+00
+ENDCHAR
+STARTCHAR )
+ENCODING 41
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+20
+20
+20
+20
+40
+00
+ENDCHAR
+STARTCHAR *
+ENCODING 42
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+a0
+40
+e0
+40
+a0
+00
+ENDCHAR
+STARTCHAR +
+ENCODING 43
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+20
+20
+f8
+20
+20
+00
+ENDCHAR
+STARTCHAR ,
+ENCODING 44
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+60
+40
+80
+ENDCHAR
+STARTCHAR -
+ENCODING 45
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+f0
+00
+00
+00
+ENDCHAR
+STARTCHAR .
+ENCODING 46
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+60
+60
+00
+ENDCHAR
+STARTCHAR /
+ENCODING 47
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+10
+20
+40
+80
+00
+00
+ENDCHAR
+STARTCHAR 0
+ENCODING 48
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+a0
+a0
+a0
+a0
+40
+00
+ENDCHAR
+STARTCHAR 1
+ENCODING 49
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+c0
+40
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR 2
+ENCODING 50
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+10
+20
+40
+f0
+00
+ENDCHAR
+STARTCHAR 3
+ENCODING 51
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+10
+60
+10
+90
+60
+00
+ENDCHAR
+STARTCHAR 4
+ENCODING 52
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+60
+a0
+f0
+20
+20
+00
+ENDCHAR
+STARTCHAR 5
+ENCODING 53
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+80
+e0
+10
+90
+60
+00
+ENDCHAR
+STARTCHAR 6
+ENCODING 54
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+80
+e0
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR 7
+ENCODING 55
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+10
+20
+20
+40
+40
+00
+ENDCHAR
+STARTCHAR 8
+ENCODING 56
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR 9
+ENCODING 57
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+70
+10
+60
+00
+ENDCHAR
+STARTCHAR :
+ENCODING 58
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+60
+60
+00
+60
+60
+00
+ENDCHAR
+STARTCHAR ;
+ENCODING 59
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+60
+60
+00
+60
+40
+80
+ENDCHAR
+STARTCHAR <
+ENCODING 60
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+20
+40
+80
+40
+20
+00
+ENDCHAR
+STARTCHAR =
+ENCODING 61
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+f0
+00
+f0
+00
+00
+ENDCHAR
+STARTCHAR >
+ENCODING 62
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+80
+40
+20
+40
+80
+00
+ENDCHAR
+STARTCHAR ?
+ENCODING 63
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+a0
+20
+40
+00
+40
+00
+ENDCHAR
+STARTCHAR @
+ENCODING 64
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+b0
+b0
+80
+60
+00
+ENDCHAR
+STARTCHAR A
+ENCODING 65
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR B
+ENCODING 66
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+90
+e0
+90
+90
+e0
+00
+ENDCHAR
+STARTCHAR C
+ENCODING 67
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+80
+80
+90
+60
+00
+ENDCHAR
+STARTCHAR D
+ENCODING 68
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+90
+90
+90
+90
+e0
+00
+ENDCHAR
+STARTCHAR E
+ENCODING 69
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+80
+e0
+80
+80
+f0
+00
+ENDCHAR
+STARTCHAR F
+ENCODING 70
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+80
+e0
+80
+80
+80
+00
+ENDCHAR
+STARTCHAR G
+ENCODING 71
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+80
+b0
+90
+70
+00
+ENDCHAR
+STARTCHAR H
+ENCODING 72
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+f0
+90
+90
+90
+00
+ENDCHAR
+STARTCHAR I
+ENCODING 73
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+40
+40
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR J
+ENCODING 74
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+10
+10
+10
+10
+90
+60
+00
+ENDCHAR
+STARTCHAR K
+ENCODING 75
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+a0
+c0
+c0
+a0
+90
+00
+ENDCHAR
+STARTCHAR L
+ENCODING 76
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+80
+80
+80
+80
+f0
+00
+ENDCHAR
+STARTCHAR M
+ENCODING 77
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+f0
+f0
+90
+90
+90
+00
+ENDCHAR
+STARTCHAR N
+ENCODING 78
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+d0
+d0
+b0
+b0
+90
+00
+ENDCHAR
+STARTCHAR O
+ENCODING 79
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR P
+ENCODING 80
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+90
+90
+e0
+80
+80
+00
+ENDCHAR
+STARTCHAR Q
+ENCODING 81
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+90
+d0
+60
+10
+ENDCHAR
+STARTCHAR R
+ENCODING 82
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+90
+90
+e0
+a0
+90
+00
+ENDCHAR
+STARTCHAR S
+ENCODING 83
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+40
+20
+90
+60
+00
+ENDCHAR
+STARTCHAR T
+ENCODING 84
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+40
+40
+40
+40
+40
+00
+ENDCHAR
+STARTCHAR U
+ENCODING 85
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR V
+ENCODING 86
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+90
+90
+60
+60
+00
+ENDCHAR
+STARTCHAR W
+ENCODING 87
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+90
+f0
+f0
+90
+00
+ENDCHAR
+STARTCHAR X
+ENCODING 88
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+60
+60
+90
+90
+00
+ENDCHAR
+STARTCHAR Y
+ENCODING 89
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+a0
+a0
+40
+40
+40
+00
+ENDCHAR
+STARTCHAR Z
+ENCODING 90
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+10
+20
+40
+80
+f0
+00
+ENDCHAR
+STARTCHAR [
+ENCODING 91
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+80
+80
+80
+80
+e0
+00
+ENDCHAR
+STARTCHAR \
+ENCODING 92
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+80
+40
+20
+10
+00
+00
+ENDCHAR
+STARTCHAR ]
+ENCODING 93
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+20
+20
+20
+20
+e0
+00
+ENDCHAR
+STARTCHAR ^
+ENCODING 94
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+a0
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR _
+ENCODING 95
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+00
+f0
+00
+ENDCHAR
+STARTCHAR `
+ENCODING 96
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+c0
+40
+20
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR a
+ENCODING 97
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+70
+90
+b0
+50
+00
+ENDCHAR
+STARTCHAR b
+ENCODING 98
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+80
+e0
+90
+90
+e0
+00
+ENDCHAR
+STARTCHAR c
+ENCODING 99
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+60
+80
+80
+60
+00
+ENDCHAR
+STARTCHAR d
+ENCODING 100
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+10
+10
+70
+90
+90
+70
+00
+ENDCHAR
+STARTCHAR e
+ENCODING 101
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+60
+b0
+c0
+60
+00
+ENDCHAR
+STARTCHAR f
+ENCODING 102
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+50
+40
+e0
+40
+40
+00
+ENDCHAR
+STARTCHAR g
+ENCODING 103
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+70
+90
+60
+80
+70
+ENDCHAR
+STARTCHAR h
+ENCODING 104
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+80
+e0
+90
+90
+90
+00
+ENDCHAR
+STARTCHAR i
+ENCODING 105
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+00
+c0
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR j
+ENCODING 106
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+00
+20
+20
+20
+a0
+40
+ENDCHAR
+STARTCHAR k
+ENCODING 107
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+80
+a0
+c0
+a0
+90
+00
+ENDCHAR
+STARTCHAR l
+ENCODING 108
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+c0
+40
+40
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR m
+ENCODING 109
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+a0
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR n
+ENCODING 110
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+e0
+90
+90
+90
+00
+ENDCHAR
+STARTCHAR o
+ENCODING 111
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR p
+ENCODING 112
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+e0
+90
+90
+e0
+80
+ENDCHAR
+STARTCHAR q
+ENCODING 113
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+70
+90
+90
+70
+10
+ENDCHAR
+STARTCHAR r
+ENCODING 114
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+e0
+90
+80
+80
+00
+ENDCHAR
+STARTCHAR s
+ENCODING 115
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 6 7 0 -1
+BITMAP
+00
+00
+70
+c0
+30
+e0
+00
+ENDCHAR
+STARTCHAR t
+ENCODING 116
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+40
+e0
+40
+40
+30
+00
+ENDCHAR
+STARTCHAR u
+ENCODING 117
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+90
+90
+90
+70
+00
+ENDCHAR
+STARTCHAR v
+ENCODING 118
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+a0
+a0
+a0
+40
+00
+ENDCHAR
+STARTCHAR w
+ENCODING 119
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+90
+90
+f0
+f0
+00
+ENDCHAR
+STARTCHAR x
+ENCODING 120
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+90
+60
+60
+90
+00
+ENDCHAR
+STARTCHAR y
+ENCODING 121
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+90
+90
+50
+20
+40
+ENDCHAR
+STARTCHAR z
+ENCODING 122
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+f0
+20
+40
+f0
+00
+ENDCHAR
+STARTCHAR {
+ENCODING 123
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+c0
+40
+40
+20
+00
+ENDCHAR
+STARTCHAR |
+ENCODING 124
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+40
+40
+40
+40
+40
+00
+ENDCHAR
+STARTCHAR }
+ENCODING 125
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 6 7 0 -1
+BITMAP
+80
+40
+60
+40
+40
+80
+00
+ENDCHAR
+STARTCHAR ~
+ENCODING 126
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+a0
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR Blank
+ENCODING 127
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C160
+ENCODING 160
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C161
+ENCODING 161
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+00
+20
+20
+20
+20
+00
+ENDCHAR
+STARTCHAR C162
+ENCODING 162
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+20
+70
+a0
+a0
+70
+20
+ENDCHAR
+STARTCHAR C163
+ENCODING 163
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+30
+40
+e0
+40
+b0
+00
+ENDCHAR
+STARTCHAR C164
+ENCODING 164
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+88
+70
+50
+70
+88
+00
+ENDCHAR
+STARTCHAR C165
+ENCODING 165
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+a0
+40
+e0
+40
+40
+00
+ENDCHAR
+STARTCHAR C166
+ENCODING 166
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+20
+20
+00
+20
+20
+00
+ENDCHAR
+STARTCHAR C167
+ENCODING 167
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+30
+40
+60
+50
+30
+10
+60
+ENDCHAR
+STARTCHAR C168
+ENCODING 168
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C169
+ENCODING 169
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+70
+88
+a8
+c8
+a8
+88
+70
+ENDCHAR
+STARTCHAR C170
+ENCODING 170
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+a0
+60
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C171
+ENCODING 171
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+48
+90
+48
+00
+00
+ENDCHAR
+STARTCHAR C172
+ENCODING 172
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+f0
+10
+00
+00
+00
+ENDCHAR
+STARTCHAR C173
+ENCODING 173
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+f0
+00
+00
+00
+ENDCHAR
+STARTCHAR C174
+ENCODING 174
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+70
+88
+e8
+c8
+c8
+88
+70
+ENDCHAR
+STARTCHAR C175
+ENCODING 175
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C176
+ENCODING 176
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+50
+20
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C177
+ENCODING 177
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+20
+f8
+20
+20
+f8
+00
+ENDCHAR
+STARTCHAR C178
+ENCODING 178
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+20
+40
+60
+00
+00
+00
+ENDCHAR
+STARTCHAR C179
+ENCODING 179
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+60
+20
+60
+00
+00
+00
+ENDCHAR
+STARTCHAR C180
+ENCODING 180
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C181
+ENCODING 181
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+90
+90
+90
+e0
+80
+ENDCHAR
+STARTCHAR C182
+ENCODING 182
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+70
+d0
+d0
+50
+50
+50
+00
+ENDCHAR
+STARTCHAR C183
+ENCODING 183
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+60
+60
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C184
+ENCODING 184
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+00
+00
+00
+20
+40
+ENDCHAR
+STARTCHAR C185
+ENCODING 185
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+60
+20
+70
+00
+00
+00
+ENDCHAR
+STARTCHAR C186
+ENCODING 186
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+a0
+40
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR C187
+ENCODING 187
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+90
+48
+90
+00
+00
+ENDCHAR
+STARTCHAR C188
+ENCODING 188
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+80
+80
+90
+30
+70
+10
+ENDCHAR
+STARTCHAR C189
+ENCODING 189
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+80
+80
+b0
+10
+20
+30
+ENDCHAR
+STARTCHAR C190
+ENCODING 190
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+c0
+c0
+40
+d0
+30
+70
+10
+ENDCHAR
+STARTCHAR C191
+ENCODING 191
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+00
+40
+80
+a0
+40
+00
+ENDCHAR
+STARTCHAR Agrave
+ENCODING 192
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR C193
+ENCODING 193
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR C194
+ENCODING 194
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR C195
+ENCODING 195
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR C196
+ENCODING 196
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR C197
+ENCODING 197
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+f0
+90
+90
+00
+ENDCHAR
+STARTCHAR C198
+ENCODING 198
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+70
+a0
+b0
+e0
+a0
+b0
+00
+ENDCHAR
+STARTCHAR C199
+ENCODING 199
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+80
+80
+90
+60
+40
+ENDCHAR
+STARTCHAR Egrave
+ENCODING 200
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+80
+e0
+80
+80
+f0
+00
+ENDCHAR
+STARTCHAR C201
+ENCODING 201
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+80
+e0
+80
+80
+f0
+00
+ENDCHAR
+STARTCHAR C202
+ENCODING 202
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+80
+e0
+80
+80
+f0
+00
+ENDCHAR
+STARTCHAR C203
+ENCODING 203
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+f0
+80
+e0
+80
+80
+f0
+00
+ENDCHAR
+STARTCHAR C204
+ENCODING 204
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+40
+40
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C205
+ENCODING 205
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+40
+40
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C206
+ENCODING 206
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+40
+40
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C207
+ENCODING 207
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+40
+40
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C208
+ENCODING 208
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+e0
+50
+d0
+50
+50
+e0
+00
+ENDCHAR
+STARTCHAR C209
+ENCODING 209
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+b0
+90
+d0
+b0
+b0
+90
+00
+ENDCHAR
+STARTCHAR Ograve
+ENCODING 210
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C211
+ENCODING 211
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C212
+ENCODING 212
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C213
+ENCODING 213
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C214
+ENCODING 214
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C215
+ENCODING 215
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+90
+60
+60
+90
+00
+ENDCHAR
+STARTCHAR C216
+ENCODING 216
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+70
+b0
+b0
+d0
+d0
+e0
+00
+ENDCHAR
+STARTCHAR Ugrave
+ENCODING 217
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C218
+ENCODING 218
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C219
+ENCODING 219
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C220
+ENCODING 220
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+90
+90
+90
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C221
+ENCODING 221
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+a0
+a0
+40
+40
+40
+00
+ENDCHAR
+STARTCHAR C222
+ENCODING 222
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+e0
+90
+e0
+80
+80
+00
+ENDCHAR
+STARTCHAR C223
+ENCODING 223
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+90
+e0
+90
+d0
+a0
+80
+ENDCHAR
+STARTCHAR a-grave
+ENCODING 224
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+20
+70
+90
+b0
+50
+00
+ENDCHAR
+STARTCHAR C225
+ENCODING 225
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+70
+90
+b0
+50
+00
+ENDCHAR
+STARTCHAR C226
+ENCODING 226
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+50
+70
+90
+b0
+50
+00
+ENDCHAR
+STARTCHAR C227
+ENCODING 227
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+a0
+70
+90
+b0
+50
+00
+ENDCHAR
+STARTCHAR C228
+ENCODING 228
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+00
+70
+90
+b0
+50
+00
+ENDCHAR
+STARTCHAR C229
+ENCODING 229
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+60
+70
+90
+b0
+50
+00
+ENDCHAR
+STARTCHAR C230
+ENCODING 230
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+70
+b0
+a0
+70
+00
+ENDCHAR
+STARTCHAR C231
+ENCODING 231
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+60
+80
+80
+60
+40
+ENDCHAR
+STARTCHAR e-grave
+ENCODING 232
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+20
+60
+b0
+c0
+60
+00
+ENDCHAR
+STARTCHAR C233
+ENCODING 233
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+60
+b0
+c0
+60
+00
+ENDCHAR
+STARTCHAR C234
+ENCODING 234
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+a0
+60
+b0
+c0
+60
+00
+ENDCHAR
+STARTCHAR C235
+ENCODING 235
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+00
+60
+b0
+c0
+60
+00
+ENDCHAR
+STARTCHAR C236
+ENCODING 236
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+80
+40
+c0
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C237
+ENCODING 237
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+80
+c0
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C238
+ENCODING 238
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+a0
+c0
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C239
+ENCODING 239
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+00
+c0
+40
+40
+e0
+00
+ENDCHAR
+STARTCHAR C240
+ENCODING 240
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+30
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C241
+ENCODING 241
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+a0
+e0
+90
+90
+90
+00
+ENDCHAR
+STARTCHAR C242
+ENCODING 242
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+20
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C243
+ENCODING 243
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C244
+ENCODING 244
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+00
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C245
+ENCODING 245
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+a0
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C246
+ENCODING 246
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+a0
+00
+60
+90
+90
+60
+00
+ENDCHAR
+STARTCHAR C247
+ENCODING 247
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+60
+00
+f0
+00
+60
+00
+ENDCHAR
+STARTCHAR C248
+ENCODING 248
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+00
+70
+b0
+d0
+e0
+00
+ENDCHAR
+STARTCHAR C249
+ENCODING 249
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+40
+20
+90
+90
+90
+70
+00
+ENDCHAR
+STARTCHAR C250
+ENCODING 250
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+90
+90
+90
+70
+00
+ENDCHAR
+STARTCHAR C251
+ENCODING 251
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+60
+00
+90
+90
+90
+70
+00
+ENDCHAR
+STARTCHAR C252
+ENCODING 252
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+00
+90
+90
+90
+70
+00
+ENDCHAR
+STARTCHAR C253
+ENCODING 253
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+20
+40
+90
+90
+50
+20
+40
+ENDCHAR
+STARTCHAR C254
+ENCODING 254
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+00
+80
+e0
+90
+90
+e0
+80
+ENDCHAR
+STARTCHAR C255
+ENCODING 255
+SWIDTH 686 0
+DWIDTH 5 0
+BBX 5 7 0 -1
+BITMAP
+50
+00
+90
+90
+50
+20
+40
+ENDCHAR
+ENDFONT
diff --git a/src/draw/Makefile b/src/draw/Makefile
new file mode 100644 (file)
index 0000000..0a542a1
--- /dev/null
@@ -0,0 +1,4 @@
+BDF=5x7.bdf
+
+ao_font.h: font-convert $(BDF)
+       nickle font-convert $(BDF) > $@
diff --git a/src/draw/ao_blt.c b/src/draw/ao_blt.c
new file mode 100644 (file)
index 0000000..e3f4522
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Copyright Â© 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include "ao.h"
+#include "ao_draw.h"
+#include "ao_draw_int.h"
+
+#define O 0
+#define I AO_ALLONES
+
+struct ao_merge_rop {
+       uint32_t        ca1, cx1, ca2, cx2;
+};
+
+const struct ao_merge_rop ao_merge_rop[16] = {
+    {O, O, O, O},               /* clear         0x0         0 */
+    {I, O, O, O},               /* and           0x1         src AND dst */
+    {I, O, I, O},               /* andReverse    0x2         src AND NOT dst */
+    {O, O, I, O},               /* copy          0x3         src */
+    {I, I, O, O},               /* andInverted   0x4         NOT src AND dst */
+    {O, I, O, O},               /* noop          0x5         dst */
+    {O, I, I, O},               /* xor           0x6         src XOR dst */
+    {I, I, I, O},               /* or            0x7         src OR dst */
+    {I, I, I, I},               /* nor           0x8         NOT src AND NOT dst */
+    {O, I, I, I},               /* equiv         0x9         NOT src XOR dst */
+    {O, I, O, I},               /* invert        0xa         NOT dst */
+    {I, I, O, I},               /* orReverse     0xb         src OR NOT dst */
+    {O, O, I, I},               /* copyInverted  0xc         NOT src */
+    {I, O, I, I},               /* orInverted    0xd         NOT src OR dst */
+    {I, O, O, I},               /* nand          0xe         NOT src OR NOT dst */
+    {O, O, O, I},               /* set           0xf         1 */
+};
+
+#define ao_do_merge_rop(src, dst) \
+    (((dst) & (((src) & _ca1) ^ _cx1)) ^ (((src) & _ca2) ^ _cx2))
+
+#define ao_do_dst_invarient_merge_rop(src)     (((src) & _ca2) ^ _cx2)
+
+#define ao_do_mask_merge_rop(src, dst, mask) \
+    (((dst) & ((((src) & _ca1) ^ _cx1) | ~(mask))) ^ ((((src) & _ca2) ^ _cx2) & (mask)))
+
+#define ao_dst_invarient_merge_rop()   (_ca1 == 0 && _cx1 == 0)
+
+void
+ao_blt(uint32_t                *src_line,
+       int16_t         src_stride,
+       int16_t         src_x,
+       uint32_t                *dst_line,
+       int16_t         dst_stride,
+       int16_t         dst_x,
+       int16_t         width,
+       int16_t         height,
+       uint8_t         rop,
+       uint8_t         reverse,
+       uint8_t         upsidedown)
+{
+       uint32_t        *src, *dst;
+       uint32_t        _ca1, _cx1, _ca2, _cx2;
+       uint8_t         dst_invarient;
+       uint32_t        startmask, endmask;
+       int16_t         nmiddle, n;
+       uint32_t        bits1, bits;
+       int16_t         left_shift, right_shift;
+
+       _ca1 = ao_merge_rop[rop].ca1;
+       _cx1 = ao_merge_rop[rop].cx1;
+       _ca2 = ao_merge_rop[rop].ca2;
+       _cx2 = ao_merge_rop[rop].cx2;
+       dst_invarient = ao_dst_invarient_merge_rop();
+
+       if (upsidedown) {
+               src_line += (height - 1) * src_stride;
+               dst_line += (height - 1) * dst_stride;
+               src_stride = -src_stride;
+               dst_stride = -dst_stride;
+       }
+
+       ao_mask_bits(dst_x, width, startmask, nmiddle, endmask);
+       if (reverse) {
+               src_line += ((src_x + width - 1) >> AO_SHIFT) + 1;
+               dst_line += ((dst_x + width - 1) >> AO_SHIFT) + 1;
+               src_x = (src_x + width - 1) & AO_MASK;
+               dst_x = (dst_x + width - 1) & AO_MASK;
+       } else {
+               src_line += src_x >> AO_SHIFT;
+               dst_line += dst_x >> AO_SHIFT;
+               src_x &= AO_MASK;
+               dst_x &= AO_MASK;
+       }
+       if (src_x == dst_x) {
+               while (height--) {
+                       src = src_line;
+                       src_line += src_stride;
+                       dst = dst_line;
+                       dst_line += dst_stride;
+                       if (reverse) {
+                               if (endmask) {
+                                       bits = *--src;
+                                       --dst;
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, endmask);
+                               }
+                               n = nmiddle;
+                               if (dst_invarient) {
+                                       while (n--)
+                                               *--dst = ao_do_dst_invarient_merge_rop(*--src);
+                               }
+                               else {
+                                       while (n--) {
+                                               bits = *--src;
+                                               --dst;
+                                               *dst = ao_do_merge_rop(bits, *dst);
+                                       }
+                               }
+                               if (startmask) {
+                                       bits = *--src;
+                                       --dst;
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, startmask);
+                               }
+                       }
+                       else {
+                               if (startmask) {
+                                       bits = *src++;
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, startmask);
+                                       dst++;
+                               }
+                               n = nmiddle;
+                               if (dst_invarient) {
+                                       while (n--)
+                                               *dst++ = ao_do_dst_invarient_merge_rop(*src++);
+                               }
+                               else {
+                                       while (n--) {
+                                               bits = *src++;
+                                               *dst = ao_do_merge_rop(bits, *dst);
+                                               dst++;
+                                       }
+                               }
+                               if (endmask) {
+                                       bits = *src;
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, endmask);
+                               }
+                       }
+               }
+       } else {
+               if (src_x > dst_x) {
+                       left_shift = src_x - dst_x;
+                       right_shift = AO_UNIT - left_shift;
+               } else {
+                       right_shift = dst_x - src_x;
+                       left_shift = AO_UNIT - right_shift;
+               }
+               while (height--) {
+                       src = src_line;
+                       src_line += src_stride;
+                       dst = dst_line;
+                       dst_line += dst_stride;
+
+                       bits1 = 0;
+                       if (reverse) {
+                               if (src_x < dst_x)
+                                       bits1 = *--src;
+                               if (endmask) {
+                                       bits = ao_right(bits1, right_shift);
+                                       if (ao_right(endmask, left_shift)) {
+                                               bits1 = *--src;
+                                               bits |= ao_left(bits1, left_shift);
+                                       }
+                                       --dst;
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, endmask);
+                               }
+                               n = nmiddle;
+                               if (dst_invarient) {
+                                       while (n--) {
+                                               bits = ao_right(bits1, right_shift);
+                                               bits1 = *--src;
+                                               bits |= ao_left(bits1, left_shift);
+                                               --dst;
+                                               *dst = ao_do_dst_invarient_merge_rop(bits);
+                                       }
+                               } else {
+                                       while (n--) {
+                                               bits = ao_right(bits1, right_shift);
+                                               bits1 = *--src;
+                                               bits |= ao_left(bits1, left_shift);
+                                               --dst;
+                                               *dst = ao_do_merge_rop(bits, *dst);
+                                       }
+                               }
+                               if (startmask) {
+                                       bits = ao_right(bits1, right_shift);
+                                       if (ao_right(startmask, left_shift)) {
+                                               bits1 = *--src;
+                                               bits |= ao_left(bits1, left_shift);
+                                       }
+                                       --dst;
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, startmask);
+                               }
+                       }
+                       else {
+                               if (src_x > dst_x)
+                                       bits1 = *src++;
+                               if (startmask) {
+                                       bits = ao_left(bits1, left_shift);
+                                       if (ao_left(startmask, right_shift)) {
+                                               bits1 = *src++;
+                                               bits |= ao_right(bits1, right_shift);
+                                       }
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, startmask);
+                                       dst++;
+                               }
+                               n = nmiddle;
+                               if (dst_invarient) {
+                                       while (n--) {
+                                               bits = ao_left(bits1, left_shift);
+                                               bits1 = *src++;
+                                               bits |= ao_right(bits1, right_shift);
+                                               *dst = ao_do_dst_invarient_merge_rop(bits);
+                                               dst++;
+                                       }
+                               }
+                               else {
+                                       while (n--) {
+                                               bits = ao_left(bits1, left_shift);
+                                               bits1 = *src++;
+                                               bits |= ao_right(bits1, right_shift);
+                                               *dst = ao_do_merge_rop(bits, *dst);
+                                               dst++;
+                                       }
+                               }
+                               if (endmask) {
+                                       bits = ao_left(bits1, left_shift);
+                                       if (ao_left(endmask, right_shift)) {
+                                               bits1 = *src;
+                                               bits |= ao_right(bits1, right_shift);
+                                       }
+                                       *dst = ao_do_mask_merge_rop(bits, *dst, endmask);
+                               }
+                       }
+               }
+       }
+}
+
+void
+ao_solid(uint32_t      and,
+        uint32_t       xor,
+        uint32_t       *dst,
+        int16_t        dst_stride,
+        int16_t        dst_x,
+        int16_t        width,
+        int16_t        height)
+{
+       uint32_t        startmask, endmask;
+       int16_t         nmiddle;
+       int16_t         n;
+
+       dst += dst_x >> AO_SHIFT;
+       dst_x &= AO_MASK;
+
+       ao_mask_bits(dst_x, width, startmask, nmiddle, endmask);
+
+       if (startmask)
+               dst_stride--;
+
+       dst_stride -= nmiddle;
+       while (height--) {
+               if (startmask) {
+                       *dst = ao_do_mask_rrop(*dst, and, xor, startmask);
+                       dst++;
+               }
+               n = nmiddle;
+               if (!and)
+                       while (n--)
+                               *dst++ = xor;
+               else
+                       while (n--) {
+                               *dst = ao_do_rrop(*dst, and, xor);
+                               dst++;
+                       }
+               if (endmask)
+                       *dst = ao_do_mask_rrop(*dst, and, xor, endmask);
+               dst += dst_stride;
+       }
+}
diff --git a/src/draw/ao_copy.c b/src/draw/ao_copy.c
new file mode 100644 (file)
index 0000000..47067bb
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright Â© 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include "ao.h"
+#include "ao_draw.h"
+#include "ao_draw_int.h"
+
+#define bound(val,max,other) do {              \
+               if (val < 0) {                  \
+                       other -= val;           \
+                       val = 0;                \
+               }                               \
+               if (val > max) {                \
+                       other -= (val - max);   \
+                       val = max;              \
+               }                               \
+       } while (0)
+
+#define bound2(a, max_a, b, max_b) do {                \
+               bound(a, max_a, b);             \
+               bound(b, max_b, a);             \
+       } while (0)
+
+void
+ao_copy(const struct ao_bitmap *dst,
+       int16_t                 dst_x,
+       int16_t                 dst_y,
+       int16_t                 width,
+       int16_t                 height,
+       const struct ao_bitmap  *src,
+       int16_t                 src_x,
+       int16_t                 src_y,
+       uint8_t                 rop)
+{
+       int16_t         dst_x2 = dst_x + width, dst_y2 = dst_y + height;
+       int16_t         src_x2 = src_x + width, src_y2 = src_y + height;
+       uint8_t         reverse = 0;
+       uint8_t         upsidedown = 0;
+
+       bound2(dst_x, dst->width, src_x, src->width);
+       bound2(dst_x2, dst->width, src_x2, src->width);
+       bound2(dst_y, dst->height, src_y, src->height);
+       bound2(dst_y2, dst->height, src_y2, src->height);
+
+       if (dst == src) {
+               reverse = (dst_x > src_x);
+               upsidedown = (dst_y > src_y);
+       }
+
+       if (dst_x < dst_x2 && dst_y < dst_y2) {
+               ao_blt(src->base + src_y * src->stride,
+                      src->stride,
+                      src_x,
+                      dst->base + dst_y * dst->stride,
+                      dst->stride,
+                      dst_x,
+                      dst_x2 - dst_x,
+                      dst_y2 - dst_y,
+                      rop,
+                      reverse,
+                      upsidedown);
+       }
+}
+
diff --git a/src/draw/ao_draw.h b/src/draw/ao_draw.h
new file mode 100644 (file)
index 0000000..92150fc
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright Â© 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _AO_DRAW_H_
+#define _AO_DRAW_H_
+
+struct ao_bitmap {
+       uint32_t        *base;
+       int16_t         stride; /* in units */
+       int16_t         width;  /* in pixels */
+       int16_t         height; /* in pixels */
+};
+
+struct ao_pattern {
+       uint8_t         pattern[8];
+};
+
+void
+ao_copy(const struct ao_bitmap *dst,
+       int16_t                 dst_x,
+       int16_t                 dst_y,
+       int16_t                 width,
+       int16_t                 height,
+       const struct ao_bitmap  *src,
+       int16_t                 src_x,
+       int16_t                 src_y,
+       uint8_t                 rop);
+
+void
+ao_rect(const struct ao_bitmap *dst,
+       int16_t                 x,
+       int16_t                 y,
+       int16_t                 width,
+       int16_t                 height,
+       uint32_t                fill,
+       uint8_t                 rop);
+
+void
+ao_pattern(const struct ao_bitmap      *dst,
+          int16_t                      x,
+          int16_t                      y,
+          int16_t                      width,
+          int16_t                      height,
+          const struct ao_pattern      *pattern,
+          int16_t                      pat_x,
+          int16_t                      pat_y,
+          uint8_t                      rop);
+
+void
+ao_line(const struct ao_bitmap *dst,
+       int16_t                 x1,
+       int16_t                 y1,
+       int16_t                 x2,
+       int16_t                 y2,
+       uint32_t                fill,
+       uint8_t                 rop);
+
+void
+ao_text(const struct ao_bitmap *dst,
+       int16_t                 x,
+       int16_t                 y,
+       char                    *string,
+       uint32_t                fill,
+       uint8_t                 rop);
+
+struct ao_font {
+       int     width;
+       int     height;
+       int     ascent;
+       int     descent;
+};
+
+extern const struct ao_font ao_font;
+
+#define AO_SHIFT       5
+#define AO_UNIT                (1 << AO_SHIFT)
+#define AO_MASK                (AO_UNIT - 1)
+#define AO_ALLONES     ((uint32_t) -1)
+
+/*
+ *         dst
+ *        0   1
+ *
+ *     0  a   b
+ *  src
+ *     1  c   d
+ *
+ *     ROP = abcd
+ */
+
+#define AO_CLEAR         0x0   /* 0 */
+#define AO_AND           0x1   /* src AND dst */
+#define AO_AND_REVERSE   0x2   /* src AND NOT dst */
+#define AO_COPY          0x3   /* src */
+#define AO_AND_INVERTED  0x4   /* NOT src AND dst */
+#define AO_NOOP          0x5   /* dst */
+#define AO_XOR           0x6   /* src XOR dst */
+#define AO_OR            0x7   /* src OR dst */
+#define AO_NOR           0x8   /* NOT src AND NOT dst */
+#define AO_EQUIV         0x9   /* NOT src XOR dst */
+#define AO_INVERT        0xa   /* NOT dst */
+#define AO_OR_REVERSE    0xb   /* src OR NOT dst */
+#define AO_COPY_INVERTED 0xc   /* NOT src */
+#define AO_OR_INVERTED   0xd   /* NOT src OR dst */
+#define AO_NAND          0xe   /* NOT src OR NOT dst */
+#define AO_SET           0xf   /* 1 */
+
+#endif /* _AO_DRAW_H_ */
diff --git a/src/draw/ao_draw_int.h b/src/draw/ao_draw_int.h
new file mode 100644 (file)
index 0000000..433aa40
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright Â© 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _AO_DRAW_INT_H_
+#define _AO_DRAW_INT_H_
+
+static inline uint32_t
+ao_expand(uint32_t bits)
+{
+       return ~((bits & 1)-1);
+}
+
+static inline uint32_t
+ao_xor(uint8_t rop, uint32_t fg)
+{
+       fg = ao_expand(fg);
+
+       return (fg & ao_expand(rop >> 1)) |
+               (~fg & ao_expand(rop >> 3));
+}
+
+static inline uint32_t
+ao_and(uint8_t rop, uint32_t fg)
+{
+       fg = ao_expand(fg);
+
+       return (fg & ao_expand(rop ^ (rop >> 1))) |
+               (~fg & ao_expand((rop>>2) ^ (rop>>3)));
+}
+
+static inline uint32_t
+ao_left(uint32_t bits, int16_t shift) {
+       return bits >> shift;
+}
+
+static inline uint32_t
+ao_right(uint32_t bits, int16_t shift) {
+       return bits << shift;
+}
+
+static inline uint32_t
+ao_right_mask(int16_t x) {
+       if ((AO_UNIT - x) & AO_MASK)
+               return ao_left(AO_ALLONES,(AO_UNIT - x) & AO_MASK);
+       else
+               return 0;
+}
+
+static inline uint32_t
+ao_left_mask(int16_t x) {
+       if (x & AO_MASK)
+               return ao_right(AO_ALLONES, x & AO_MASK);
+       else
+               return 0;
+}
+
+static inline uint32_t
+ao_bits_mask(int16_t x, int16_t w) {
+       return ao_right(AO_ALLONES, x & AO_MASK) &
+               ao_left(AO_ALLONES,(AO_UNIT - (x + w)) & AO_MASK);
+}
+
+#define ao_mask_bits(x,w,l,n,r) { \
+    n = (w); \
+    r = ao_right_mask((x)+n); \
+    l = ao_left_mask(x); \
+    if (l) { \
+       n -= AO_UNIT - ((x) & AO_MASK); \
+       if (n < 0) { \
+           n = 0; \
+           l &= r; \
+           r = 0; \
+       } \
+    } \
+    n >>= AO_SHIFT; \
+}
+
+#define ao_clip(val,min,max) do {              \
+               if (val < min) {                \
+                       val = min;              \
+               } else if (val > max) {         \
+                       val = max;              \
+               }                               \
+       } while (0)
+
+static inline uint32_t
+ao_do_mask_rrop(uint32_t dst, uint32_t and, uint32_t xor, uint32_t mask) {
+       return (dst & (and | ~mask)) ^ (xor & mask);
+}
+
+static inline uint32_t
+ao_do_rrop(uint32_t dst, uint32_t and, uint32_t xor) {
+       return (dst & and) ^ xor;
+}
+
+void
+ao_blt(uint32_t                *src_line,
+       int16_t         src_stride,
+       int16_t         src_x,
+       uint32_t                *dst_line,
+       int16_t         dst_stride,
+       int16_t         dst_x,
+       int16_t         width,
+       int16_t         height,
+       uint8_t         rop,
+       uint8_t         reverse,
+       uint8_t         upsidedown);
+
+void
+ao_solid(uint32_t      and,
+        uint32_t       xor,
+        uint32_t       *dst,
+        int16_t        dst_stride,
+        int16_t        dst_x,
+        int16_t        width,
+        int16_t        height);
+
+int16_t
+ao_glyph(const struct ao_bitmap        *dst,
+        int16_t                x,
+        int16_t                y,
+        uint8_t                c,
+        uint8_t                rop);
+
+#endif /* _AO_DRAW_INT_H_ */
diff --git a/src/draw/ao_font.h b/src/draw/ao_font.h
new file mode 100644 (file)
index 0000000..5e31dd1
--- /dev/null
@@ -0,0 +1,139 @@
+static const uint8_t glyph_bytes[1568] = {
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x04, 0x0e, 0x1f, 0x0e, 0x04, 0x00, 0x0a, 0x05, 
+       0x0a, 0x05, 0x0a, 0x05, 0x00, 0x05, 0x07, 0x05, 0x05, 0x0e, 0x04, 0x04, 0x03, 0x01, 0x03, 0x0d, 
+       0x04, 0x0c, 0x04, 0x03, 0x01, 0x03, 0x06, 0x0a, 0x06, 0x0a, 0x01, 0x01, 0x03, 0x0c, 0x04, 0x0c, 
+       0x04, 0x04, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0e, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x09, 
+       0x0b, 0x0d, 0x09, 0x04, 0x04, 0x0c, 0x05, 0x05, 0x05, 0x02, 0x0e, 0x04, 0x04, 0x04, 0x04, 0x04, 
+       0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x1c, 0x04, 
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x1f, 0x04, 0x04, 0x04, 
+       0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+       0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+       0x00, 0x1f, 0x00, 0x04, 0x04, 0x04, 0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, 0x04, 
+       0x04, 0x04, 0x04, 0x04, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x04, 0x04, 0x04, 0x04, 
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x04, 0x02, 0x04, 0x08, 0x0e, 0x00, 0x02, 0x04, 0x08, 
+       0x04, 0x02, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x08, 0x0e, 0x04, 0x0e, 
+       0x02, 0x00, 0x00, 0x0c, 0x02, 0x07, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04, 0x00, 0x0a, 0x0a, 
+       0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x1f, 0x0a, 0x1f, 0x0a, 0x00, 0x00, 0x0e, 0x05, 0x0e, 
+       0x14, 0x0e, 0x00, 0x01, 0x09, 0x04, 0x02, 0x09, 0x08, 0x00, 0x00, 0x02, 0x05, 0x02, 0x05, 0x0a, 
+       0x00, 0x06, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x02, 0x04, 0x00, 0x02, 
+       0x04, 0x04, 0x04, 0x04, 0x02, 0x00, 0x00, 0x05, 0x02, 0x07, 0x02, 0x05, 0x00, 0x00, 0x04, 0x04, 
+       0x1f, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00, 
+       0x02, 0x05, 0x05, 0x05, 0x05, 0x02, 0x00, 0x02, 0x03, 0x02, 0x02, 0x02, 0x07, 0x00, 0x06, 0x09, 
+       0x08, 0x04, 0x02, 0x0f, 0x00, 0x0f, 0x08, 0x06, 0x08, 0x09, 0x06, 0x00, 0x04, 0x06, 0x05, 0x0f, 
+       0x04, 0x04, 0x00, 0x0f, 0x01, 0x07, 0x08, 0x09, 0x06, 0x00, 0x06, 0x01, 0x07, 0x09, 0x09, 0x06, 
+       0x00, 0x0f, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x06, 0x09, 0x06, 0x09, 0x09, 0x06, 0x00, 0x06, 
+       0x09, 0x09, 0x0e, 0x08, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 
+       0x00, 0x06, 0x02, 0x01, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, 
+       0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x02, 0x01, 0x00, 0x02, 0x05, 0x04, 0x02, 0x00, 0x02, 0x00, 
+       0x06, 0x09, 0x0d, 0x0d, 0x01, 0x06, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x07, 0x09, 
+       0x07, 0x09, 0x09, 0x07, 0x00, 0x06, 0x09, 0x01, 0x01, 0x09, 0x06, 0x00, 0x07, 0x09, 0x09, 0x09, 
+       0x09, 0x07, 0x00, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x01, 
+       0x00, 0x06, 0x09, 0x01, 0x0d, 0x09, 0x0e, 0x00, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x09, 0x00, 0x07, 
+       0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x08, 0x08, 0x08, 0x08, 0x09, 0x06, 0x00, 0x09, 0x05, 0x03, 
+       0x03, 0x05, 0x09, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0f, 0x00, 0x09, 0x0f, 0x0f, 0x09, 0x09, 
+       0x09, 0x00, 0x09, 0x0b, 0x0b, 0x0d, 0x0d, 0x09, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 
+       0x07, 0x09, 0x09, 0x07, 0x01, 0x01, 0x00, 0x06, 0x09, 0x09, 0x09, 0x0b, 0x06, 0x08, 0x07, 0x09, 
+       0x09, 0x07, 0x05, 0x09, 0x00, 0x06, 0x09, 0x02, 0x04, 0x09, 0x06, 0x00, 0x07, 0x02, 0x02, 0x02, 
+       0x02, 0x02, 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, 0x09, 0x06, 0x06, 
+       0x00, 0x09, 0x09, 0x09, 0x0f, 0x0f, 0x09, 0x00, 0x09, 0x09, 0x06, 0x06, 0x09, 0x09, 0x00, 0x05, 
+       0x05, 0x05, 0x02, 0x02, 0x02, 0x00, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x0f, 0x00, 0x07, 0x01, 0x01, 
+       0x01, 0x01, 0x07, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x00, 0x00, 0x07, 0x04, 0x04, 0x04, 0x04, 
+       0x07, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 
+       0x03, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x01, 0x01, 
+       0x07, 0x09, 0x09, 0x07, 0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x06, 0x00, 0x08, 0x08, 0x0e, 0x09, 
+       0x09, 0x0e, 0x00, 0x00, 0x00, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x04, 0x0a, 0x02, 0x07, 0x02, 0x02, 
+       0x00, 0x00, 0x00, 0x0e, 0x09, 0x06, 0x01, 0x0e, 0x01, 0x01, 0x07, 0x09, 0x09, 0x09, 0x00, 0x02, 
+       0x00, 0x03, 0x02, 0x02, 0x07, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x05, 0x02, 0x01, 0x01, 0x05, 
+       0x03, 0x05, 0x09, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x00, 0x00, 0x05, 0x0f, 0x09, 
+       0x09, 0x00, 0x00, 0x00, 0x07, 0x09, 0x09, 0x09, 0x00, 0x00, 0x00, 0x06, 0x09, 0x09, 0x06, 0x00, 
+       0x00, 0x00, 0x07, 0x09, 0x09, 0x07, 0x01, 0x00, 0x00, 0x0e, 0x09, 0x09, 0x0e, 0x08, 0x00, 0x00, 
+       0x07, 0x09, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x0c, 0x07, 0x00, 0x02, 0x02, 0x07, 0x02, 
+       0x02, 0x0c, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x00, 0x00, 0x05, 0x05, 0x05, 0x02, 
+       0x00, 0x00, 0x00, 0x09, 0x09, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x09, 0x06, 0x06, 0x09, 0x00, 0x00, 
+       0x00, 0x09, 0x09, 0x0a, 0x04, 0x02, 0x00, 0x00, 0x0f, 0x04, 0x02, 0x0f, 0x00, 0x04, 0x02, 0x03, 
+       0x02, 0x02, 0x04, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x06, 0x02, 0x02, 
+       0x01, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x04, 
+       0x0e, 0x05, 0x05, 0x0e, 0x04, 0x00, 0x0c, 0x02, 0x07, 0x02, 0x0d, 0x00, 0x00, 0x11, 0x0e, 0x0a, 
+       0x0e, 0x11, 0x00, 0x05, 0x05, 0x02, 0x07, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x00, 0x04, 0x04, 
+       0x00, 0x0c, 0x02, 0x06, 0x0a, 0x0c, 0x08, 0x06, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 
+       0x11, 0x15, 0x13, 0x15, 0x11, 0x0e, 0x06, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 
+       0x09, 0x12, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 
+       0x00, 0x00, 0x0e, 0x11, 0x17, 0x13, 0x13, 0x11, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+       0x04, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x1f, 0x04, 0x04, 0x1f, 0x00, 0x06, 0x04, 
+       0x02, 0x06, 0x00, 0x00, 0x00, 0x06, 0x06, 0x04, 0x06, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x07, 0x01, 0x0e, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 
+       0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x04, 
+       0x06, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 
+       0x12, 0x09, 0x00, 0x00, 0x01, 0x01, 0x01, 0x09, 0x0c, 0x0e, 0x08, 0x01, 0x01, 0x01, 0x0d, 0x08, 
+       0x04, 0x0c, 0x03, 0x03, 0x02, 0x0b, 0x0c, 0x0e, 0x08, 0x02, 0x00, 0x02, 0x01, 0x05, 0x02, 0x00, 
+       0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, 
+       0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, 
+       0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x0e, 0x05, 0x0d, 0x07, 0x05, 0x0d, 
+       0x00, 0x06, 0x09, 0x01, 0x01, 0x09, 0x06, 0x02, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, 
+       0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, 0x01, 0x07, 
+       0x01, 0x01, 0x0f, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 
+       0x07, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 
+       0x07, 0x0a, 0x0b, 0x0a, 0x0a, 0x07, 0x00, 0x0d, 0x09, 0x0b, 0x0d, 0x0d, 0x09, 0x00, 0x06, 0x09, 
+       0x09, 0x09, 0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, 
+       0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, 
+       0x00, 0x00, 0x00, 0x09, 0x06, 0x06, 0x09, 0x00, 0x0e, 0x0d, 0x0d, 0x0b, 0x0b, 0x07, 0x00, 0x09, 
+       0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, 
+       0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x05, 0x05, 0x05, 0x02, 0x02, 
+       0x02, 0x00, 0x01, 0x07, 0x09, 0x07, 0x01, 0x01, 0x00, 0x06, 0x09, 0x07, 0x09, 0x0b, 0x05, 0x01, 
+       0x02, 0x04, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x04, 0x02, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x04, 0x0a, 
+       0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x0a, 0x05, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x0a, 0x00, 0x0e, 0x09, 
+       0x0d, 0x0a, 0x00, 0x06, 0x06, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0x0d, 0x05, 0x0e, 
+       0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x06, 0x02, 0x02, 0x04, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x04, 
+       0x02, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x02, 0x05, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x05, 0x00, 0x06, 
+       0x0d, 0x03, 0x06, 0x00, 0x01, 0x02, 0x03, 0x02, 0x02, 0x07, 0x00, 0x02, 0x01, 0x03, 0x02, 0x02, 
+       0x07, 0x00, 0x02, 0x05, 0x03, 0x02, 0x02, 0x07, 0x00, 0x05, 0x00, 0x03, 0x02, 0x02, 0x07, 0x00, 
+       0x02, 0x0c, 0x06, 0x09, 0x09, 0x06, 0x00, 0x0a, 0x05, 0x07, 0x09, 0x09, 0x09, 0x00, 0x02, 0x04, 
+       0x06, 0x09, 0x09, 0x06, 0x00, 0x04, 0x02, 0x06, 0x09, 0x09, 0x06, 0x00, 0x06, 0x00, 0x06, 0x09, 
+       0x09, 0x06, 0x00, 0x0a, 0x05, 0x06, 0x09, 0x09, 0x06, 0x00, 0x05, 0x00, 0x06, 0x09, 0x09, 0x06, 
+       0x00, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x0d, 0x0b, 0x07, 0x00, 0x02, 
+       0x04, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x04, 0x02, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x06, 0x00, 0x09, 
+       0x09, 0x09, 0x0e, 0x00, 0x0a, 0x00, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x04, 0x02, 0x09, 0x09, 0x0a, 
+       0x04, 0x02, 0x00, 0x01, 0x07, 0x09, 0x09, 0x07, 0x01, 0x0a, 0x00, 0x09, 0x09, 0x0a, 0x04, 0x02, 
+};
+
+static const uint16_t glyph_pos[256] = {
+          0,    7,   14,   21,   28,   35,   42,   49, 
+         56,   63,   70,   77,   84,   91,   98,  105, 
+        112,  119,  126,  133,  140,  147,  154,  161, 
+        168,  175,  182,  189,  196,  203,  210,  217, 
+        224,  231,  238,  245,  252,  259,  266,  273, 
+        280,  287,  294,  301,  308,  315,  322,  329, 
+        336,  343,  350,  357,  364,  371,  378,  385, 
+        392,  399,  406,  413,  420,  427,  434,  441, 
+        448,  455,  462,  469,  476,  483,  490,  497, 
+        504,  511,  518,  525,  532,  539,  546,  553, 
+        560,  567,  574,  581,  588,  595,  602,  609, 
+        616,  623,  630,  637,  644,  651,  658,  665, 
+        672,  679,  686,  693,  700,  707,  714,  721, 
+        728,  735,  742,  749,  756,  763,  770,  777, 
+        784,  791,  798,  805,  812,  819,  826,  833, 
+        840,  847,  854,  861,  868,  875,  882,  889, 
+          0,    0,    0,    0,    0,    0,    0,    0, 
+          0,    0,    0,    0,    0,    0,    0,    0, 
+          0,    0,    0,    0,    0,    0,    0,    0, 
+          0,    0,    0,    0,    0,    0,    0,    0, 
+        896,  903,  910,  917,  924,  931,  938,  945, 
+        952,  959,  966,  973,  980,  987,  994, 1001, 
+       1008, 1015, 1022, 1029, 1036, 1043, 1050, 1057, 
+       1064, 1071, 1078, 1085, 1092, 1099, 1106, 1113, 
+       1120, 1127, 1134, 1141, 1148, 1155, 1162, 1169, 
+       1176, 1183, 1190, 1197, 1204, 1211, 1218, 1225, 
+       1232, 1239, 1246, 1253, 1260, 1267, 1274, 1281, 
+       1288, 1295, 1302, 1309, 1316, 1323, 1330, 1337, 
+       1344, 1351, 1358, 1365, 1372, 1379, 1386, 1393, 
+       1400, 1407, 1414, 1421, 1428, 1435, 1442, 1449, 
+       1456, 1463, 1470, 1477, 1484, 1491, 1498, 1505, 
+       1512, 1519, 1526, 1533, 1540, 1547, 1554, 1561, 
+};
+
+#define GLYPH_WIDTH 5
+#define GLYPH_HEIGHT 7
+#define GLYPH_ASCENT 6
diff --git a/src/draw/ao_line.c b/src/draw/ao_line.c
new file mode 100644 (file)
index 0000000..ed1fc21
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright Â© 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include "ao.h"
+#include "ao_draw.h"
+#include "ao_draw_int.h"
+
+#define ao_mask(x,w)   (ao_right(AO_ALLONES,(x) & AO_MASK) & \
+                        ao_left(AO_ALLONES,(FB_UNIT - ((x)+(w))) & AO_MASK))
+
+
+/* out of clip region codes */
+#define OUT_LEFT 0x08
+#define OUT_RIGHT 0x04
+#define OUT_ABOVE 0x02
+#define OUT_BELOW 0x01
+
+/* major axis for bresenham's line */
+#define X_AXIS 0
+#define Y_AXIS 1
+
+/*
+ * Line clipping. Clip to the box, bringing the coordinates forward while
+ * preserving the actual slope and error
+ *
+ *
+ *     X major line, clip X:
+ *
+ *     adjust_x = -x;
+ *
+ *     e += adjust_x * e1;
+ *
+ *     adjust_y = (e + -e3-1) / -e3;
+ *
+ *     e -= adjust_y / -e3;
+ *
+ *     X major line, clip Y:
+ *
+ *     adjust_y = -y;
+
+ *
+ *     e -= adjust_y / -e3;
+ *
+ *     adjust_x = e / e1;
+ */
+
+
+
+
+static void
+ao_bres(const struct ao_bitmap *dst_bitmap,
+       int16_t         signdx,
+       int16_t         signdy,
+       int16_t         axis,
+       int16_t         x1,
+       int16_t         y1,
+       int16_t         e,
+       int16_t         e1,
+       int16_t         e3,
+       int16_t         len,
+       uint32_t        and,
+       uint32_t        xor)
+{
+       int16_t         stride = dst_bitmap->stride;
+       uint32_t        *dst = dst_bitmap->base;
+       uint32_t        mask0, mask;
+
+       mask0 = 1;
+       if (signdx < 0)
+               mask0 = ao_right(1, AO_UNIT - 1);
+
+       if (signdy < 0)
+               stride = -stride;
+
+       dst = dst + y1 * stride + (x1 >> AO_SHIFT);
+       mask = ao_right(1, x1 & AO_MASK);
+
+       while (len--) {
+               /* clip each point */
+
+               *dst = ao_do_mask_rrop(*dst, and, xor, mask);
+
+               if (axis == X_AXIS) {
+                       if (signdx < 0)
+                               mask = ao_left(mask, 1);
+                       else
+                               mask = ao_right(mask, 1);
+                       if (!mask) {
+                               dst += signdx;
+                               mask = mask0;
+                       }
+                       e += e1;
+                       if (e >= 0) {
+                               dst += stride;
+                               e += e3;
+                       }
+               } else {
+                       dst += stride;
+                       e += e1;
+                       if (e >= 0) {
+                               if (signdx < 0)
+                                       mask = ao_left(mask, 1);
+                               else
+                                       mask = ao_right(mask, 1);
+                               if (!mask) {
+                                       dst += signdx;
+                                       mask = mask0;
+                               }
+                               e += e3;
+                       }
+               }
+       }
+}
+
+struct ao_cc {
+       int16_t major;
+       int16_t minor;
+       int16_t sign_major;
+       int16_t sign_minor;
+       int16_t e;
+       int16_t e1;
+       int16_t e3;
+       int8_t  first;
+};
+
+/* line clipping box */
+struct ao_cbox {
+       int16_t maj1, min1;
+       int16_t maj2, min2;
+};
+
+/* -b <= a, so we need to make a bigger */
+static int16_t
+div_ceil(int32_t a, int16_t b) {
+       return (a + b + b - 1) / b - 1;
+}
+
+static int16_t
+div_floor_plus_one(int32_t a, int16_t b) {
+       return (a + b) / b;
+}
+
+static int8_t
+ao_clip_line(struct ao_cc *c, struct ao_cbox *b)
+{
+       int32_t adjust_major = 0, adjust_minor = 0;
+
+       /* Clip major axis */
+       if (c->major < b->maj1) {
+               if (c->sign_major <= 0)
+                       return FALSE;
+               adjust_major = b->maj1 - c->major;
+       } else if (c->major >= b->maj2) {
+               if (c->sign_major >= 0)
+                       return FALSE;
+               adjust_major = c->major - (b->maj2-1);
+       }
+
+       /* Clip minor axis */
+       if (c->minor < b->min1) {
+               if (c->sign_minor <= 0)
+                       return FALSE;
+               adjust_minor = b->min1 - c->minor;
+       } else if (c->minor >= b->min2) {
+               if (c->sign_minor >= 0)
+                       return FALSE;
+               adjust_minor = c->minor - (b->min2-1);
+       }
+
+       /* If unclipped, we're done */
+       if (adjust_major == 0 && adjust_minor == 0)
+               return TRUE;
+
+       /* See how much minor adjustment would happen during
+        * a major clip. This is a bit tricky because line drawing
+        * isn't symmetrical when the line passes exactly between
+        * two pixels, we have to pick which one gets drawn
+        */
+       int32_t adj_min;
+
+       if (!c->first)
+               adj_min = div_ceil(c->e + adjust_major * c->e1, -c->e3);
+       else
+               adj_min = div_floor_plus_one(c->e + adjust_major * c->e1, -c->e3);
+
+       if (adj_min < adjust_minor) {
+               if (c->first)
+                       adjust_major = div_ceil(c->e - adjust_minor * c->e3, c->e1);
+               else
+                       adjust_major = div_floor_plus_one(c->e - adjust_minor * c->e3, c->e1);
+       } else {
+               adjust_minor = adj_min;
+       }
+
+       c->e += adjust_major * c->e1 + adjust_minor * c->e3;
+
+       c->major += c->sign_major * adjust_major;
+       c->minor += c->sign_minor * adjust_minor;
+
+       return TRUE;
+}
+
+void
+ao_line(const struct ao_bitmap *dst,
+       int16_t                 x1,
+       int16_t                 y1,
+       int16_t                 x2,
+       int16_t                 y2,
+       uint32_t                fill,
+       uint8_t                 rop)
+{
+       int16_t adx, ady;
+       int16_t e, e1, e2, e3;
+       int16_t signdx = 1, signdy = 1;
+       int16_t axis;
+       int16_t len;
+       struct ao_cc    clip_1, clip_2;
+       struct ao_cbox  cbox;
+
+       if ((adx = x2 - x1) < 0) {
+               adx = -adx;
+               signdx = -1;
+       }
+       if ((ady = y2 - y1) < 0) {
+               ady = -ady;
+               signdy = -1;
+       }
+
+       if (adx > ady) {
+               axis = X_AXIS;
+               e1 = ady << 1;
+               e2 = e1 - (adx << 1);
+               e = e1 - adx;
+
+               clip_1.major = x1;
+               clip_1.minor = y1;
+               clip_2.major = x2;
+               clip_2.minor = y2;
+               clip_1.sign_major = signdx;
+               clip_1.sign_minor = signdy;
+
+               cbox.maj1 = 0;
+               cbox.maj2 = dst->width;
+               cbox.min1 = 0;
+               cbox.min2 = dst->height;
+       } else {
+               axis = Y_AXIS;
+               e1 = adx << 1;
+               e2 = e1 - (ady << 1);
+               e = e1 - ady;
+
+               clip_1.major = y1;
+               clip_1.minor = x1;
+               clip_2.major = y2;
+               clip_2.minor = x2;
+               clip_1.sign_major = signdy;
+               clip_1.sign_minor = signdx;
+
+               cbox.maj1 = 0;
+               cbox.maj2 = dst->height;
+               cbox.min1 = 0;
+               cbox.min2 = dst->width;
+       }
+
+       e3 = e2 - e1;
+       e = e - e1;
+
+       clip_1.first = TRUE;
+       clip_2.first = FALSE;
+       clip_2.e = clip_1.e = e;
+       clip_2.e1 = clip_1.e1 = e1;
+       clip_2.e3 = clip_1.e3 = e3;
+       clip_2.sign_major = -clip_1.sign_major;
+       clip_2.sign_minor = -clip_1.sign_minor;
+
+       if (!ao_clip_line(&clip_1, &cbox))
+               return;
+
+       if (!ao_clip_line(&clip_2, &cbox))
+               return;
+
+       len = clip_1.sign_major * (clip_2.major - clip_1.major) + clip_2.first;
+
+       if (len <= 0)
+               return;
+
+       if (adx > ady) {
+               x1 = clip_1.major;
+               y1 = clip_1.minor;
+       } else {
+               x1 = clip_1.minor;
+               y1 = clip_1.major;
+       }
+       ao_bres(dst,
+               signdx,
+               signdy,
+               axis,
+               x1,
+               y1,
+               clip_1.e, e1, e3, len,
+               ao_and(rop, fill),
+               ao_xor(rop, fill));
+}
diff --git a/src/draw/ao_pattern.c b/src/draw/ao_pattern.c
new file mode 100644 (file)
index 0000000..0d1dc76
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright Â© 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include "ao.h"
+#include "ao_draw.h"
+#include "ao_draw_int.h"
+
+static inline uint32_t
+ao_pattern_expand(uint8_t v, uint8_t rot)
+{
+       uint32_t        r;
+
+       if (rot)
+               v = ao_left(v, 8-rot) | ao_right(v, rot);
+       r = v;
+       return (r << 24) | (r << 16) | (r << 8) | (r);
+}
+
+static inline int
+min(int a, int b) {
+       return a < b ? a : b;
+}
+
+void
+ao_pattern(const struct ao_bitmap      *dst,
+          int16_t                      x,
+          int16_t                      y,
+          int16_t                      width,
+          int16_t                      height,
+          const struct ao_pattern      *pattern,
+          int16_t                      pat_x,
+          int16_t                      pat_y,
+          uint8_t                      rop)
+{
+       uint32_t        pat[8];
+
+       int16_t x2 = x + width;
+       int16_t y2 = y + height;
+
+       ao_clip(x, 0, dst->width);
+       ao_clip(x2, 0, dst->width);
+       ao_clip(y, 0, dst->height);
+       ao_clip(y2, 0, dst->height);
+
+       if (x < x2 && y < y2) {
+               int     xrot = (x - pat_x) & 7;
+               int     yrot = (y - pat_y) & 7;
+               int     i;
+               int16_t dst_x, dst_y;
+
+               for (i = 0; i < 8; i++)
+                       pat[(i + yrot) & 7] = ao_pattern_expand(pattern->pattern[i], xrot);
+               for (dst_y = y; dst_y < y2; dst_y += 8) {
+                       int     h = min(y2 - dst_y, 8);
+                       for (dst_x = x; dst_x < x2; dst_x += 8) {
+                               int     w = min(x2 - dst_x, 8);
+
+                               ao_blt(pat, 1, 0,
+                                      dst->base + dst_y * dst->stride,
+                                      dst->stride,
+                                      dst_x,
+                                      w, h,
+                                      rop,
+                                      0, 0);
+                       }
+               }
+       }
+}
+
diff --git a/src/draw/ao_rect.c b/src/draw/ao_rect.c
new file mode 100644 (file)
index 0000000..71fa4ae
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright Â© 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include "ao.h"
+#include "ao_draw.h"
+#include "ao_draw_int.h"
+
+void
+ao_rect(const struct ao_bitmap *dst,
+       int16_t                 x,
+       int16_t                 y,
+       int16_t                 width,
+       int16_t                 height,
+       uint32_t                fill,
+       uint8_t                 rop)
+{
+       int16_t x2 = x + width;
+       int16_t y2 = y + height;
+
+       ao_clip(x, 0, dst->width);
+       ao_clip(x2, 0, dst->width);
+       ao_clip(y, 0, dst->height);
+       ao_clip(y2, 0, dst->height);
+
+       if (x < x2 && y < y2) {
+               ao_solid(ao_and(rop, fill),
+                        ao_xor(rop, fill),
+                        dst->base + y * dst->stride,
+                        dst->stride,
+                        x,
+                        x2 - x,
+                        y2 - y);
+       }
+}
+
diff --git a/src/draw/ao_text.c b/src/draw/ao_text.c
new file mode 100644 (file)
index 0000000..7ce2a62
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright Â© 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include "ao.h"
+#include "ao_draw.h"
+#include "ao_draw_int.h"
+#include "ao_font.h"
+
+const struct ao_font ao_font = {
+       .width = GLYPH_WIDTH,
+       .height = GLYPH_HEIGHT,
+       .ascent = GLYPH_ASCENT,
+       .descent = GLYPH_HEIGHT - GLYPH_ASCENT,
+};
+
+void
+ao_text(const struct ao_bitmap *dst,
+       int16_t                 x,
+       int16_t                 y,
+       char                    *string,
+       uint32_t                fill,
+       uint8_t                 rop)
+{
+       uint32_t        src[GLYPH_HEIGHT];
+       char            c;
+       int             h;
+
+       struct ao_bitmap        src_bitmap = {
+               .base = src,
+               .stride = 1,
+               .width = GLYPH_WIDTH,
+               .height = GLYPH_HEIGHT
+       };
+
+       y -= GLYPH_ASCENT;
+
+       rop = (rop & 3) | 0x4;
+
+       if ((fill&1) == 0)
+               rop ^= 3;
+
+       while ((c = *string++)) {
+               const uint8_t   *bytes = &glyph_bytes[glyph_pos[(uint8_t) c]];
+
+               for (h = 0; h < GLYPH_HEIGHT; h++)
+                       src[h] = bytes[h];
+
+               ao_copy(dst,
+                       x, y, GLYPH_WIDTH, GLYPH_HEIGHT,
+                       &src_bitmap,
+                       0, 0, rop);
+               x += GLYPH_WIDTH;
+       }
+}
diff --git a/src/draw/font-convert b/src/draw/font-convert
new file mode 100755 (executable)
index 0000000..1985e41
--- /dev/null
@@ -0,0 +1,150 @@
+#!/usr/bin/nickle
+
+typedef struct {
+       int[]   bytes;
+       int     width;
+       int     height;
+       int     encoding;
+       int     location;
+} glyph_t;
+
+typedef struct {
+       glyph_t[...]    glyphs;
+       int             default_char;
+       int             ascent;
+} font_t;
+
+glyph_t
+read_glyph(file f)
+{
+       glyph_t glyph = { .encoding = -1, .bytes = (int[...]){}, .width = 0 };
+
+       while (!File::end(f)) {
+               string  l = fgets(f);
+
+               string[*] tokens = String::split(l, " ");
+               if (dim(tokens) == 0)
+                       continue;
+
+               switch (tokens[0]) {
+               case "ENCODING":
+                       glyph.encoding = atoi(tokens[1]);
+                       break;
+               case "DWIDTH":
+                       glyph.width = atoi(tokens[1]);
+                       break;
+               case "BBX":
+                       glyph.height = atoi(tokens[2]);
+                       break;
+               case "ENDCHAR":
+                       return glyph;
+               case "BITMAP":
+                       while (!File::end(f)) {
+                               string l = fgets(f);
+                               if (l == "ENDCHAR")
+                                       return glyph;
+                               glyph.bytes[dim(glyph.bytes)] = atoi(l, 16);
+                       }
+                       break;
+               }
+       }
+       return glyph;
+}
+
+font_t read_font(file f) {
+       font_t  font = { .glyphs = {}, .default_char = -1 };
+       bool in_head = true;
+
+       while (in_head && !File::end(f)) {
+               string l = File::fgets(f);
+
+               string[*] tokens = String::split(l, " ");
+               switch (tokens[0]) {
+               case "DEFAULT_CHAR":
+                       font.default_char = atoi(tokens[1]);
+                       break;
+               case "FONT_ASCENT":
+                       font.ascent = atoi(tokens[1]);
+                       break;
+               case "CHARS":
+                       in_head = false;
+                       break;
+               }
+       }
+       while (!File::end(f)) {
+               glyph_t glyph = read_glyph(f);
+               if (glyph.encoding == -1)
+                       break;
+               font.glyphs[dim(font.glyphs)] = glyph;
+       }
+       return font;
+}
+
+int
+flip_byte(int x)
+{
+       int     dest = 0;
+
+       for (int i = 0; i < 8; i++)
+               dest |= ((x >> (7 - i)) & 1) << i;
+       return dest;
+}
+
+void print_font(font_t font) {
+       int     width = font.glyphs[0].width;
+       int     height = font.glyphs[0].height;
+       int[256] pos = { -1 ... };
+       int[...] bytes;
+
+       if (false) {
+       for (int i = 1; i < dim(font.glyphs); i++) {
+               if (font.glyphs[i].width != width ||
+                  font.glyphs[i].height != height)
+               {
+                       File::fprintf(stderr, "font not constant size, glyph %d is %dx%d\n",
+                                     font.glyphs[i].encoding, font.glyphs[i].width, font.glyphs[i].height);
+                       exit(1);
+               }
+       }
+       }
+
+       if (font.default_char == -1)
+               font.default_char = font.glyphs[0].encoding;
+
+       /* build byte array */
+       for (int i = 0; i < dim(font.glyphs); i++) {
+               pos[font.glyphs[i].encoding] = dim(bytes);
+               for (int b = 0; b < dim(font.glyphs[i].bytes); b++)
+                       bytes[dim(bytes)] = font.glyphs[i].bytes[b];
+       }
+
+       /* Fill in default glyph */
+       for (int i = 0; i < dim(pos); i++)
+               if (pos[i] == -1)
+                       pos[i] = pos[font.default_char];
+
+       printf("static const uint8_t glyph_bytes[%d] = {", dim(bytes));
+       for (int b = 0; b < dim(bytes); b++) {
+               if ((b & 15) == 0)
+                       printf("\n\t");
+               printf("0x%02x, ", flip_byte(bytes[b]));
+       }
+       printf("\n};\n\n");
+
+       printf("static const uint16_t glyph_pos[%d] = {", dim(pos));
+       for (int i = 0; i < dim(pos); i++) {
+               if ((i & 7) == 0)
+                       printf("\n\t");
+               printf("%4d, ", pos[i]);
+       }
+       printf("\n};\n\n");
+
+       printf("#define GLYPH_WIDTH %d\n", width);
+       printf("#define GLYPH_HEIGHT %d\n", height);
+       printf("#define GLYPH_ASCENT %d\n", font.ascent);
+}
+
+twixt (file f = File::open(argv[1], "r"); File::close(f)) {
+       font_t font = read_font(f);
+       print_font(font);
+}
diff --git a/src/draw/line.5c b/src/draw/line.5c
new file mode 100644 (file)
index 0000000..747768b
--- /dev/null
@@ -0,0 +1,389 @@
+#!/usr/bin/nickle
+
+autoimport Cairo;
+autoload PRNG;
+
+int
+sign(int x)
+{
+       return x == 0 ? 0 : x < 0 ? -1 : 1;
+}
+
+int X_AXIS = 0;
+int Y_AXIS = 1;
+
+typedef struct {
+       int     major;
+       int     minor;
+       int     sign_major;
+       int     sign_minor;
+       int     e;
+       int     e1;
+       int     e3;
+       bool    first;
+} clip_context;
+
+typedef struct {
+       int     maj1, min1, maj2, min2;
+} clip_box;
+
+typedef struct {
+       int     x1, y1, x2, y2;
+} box;
+
+typedef struct {
+       int     x, y;
+} point;
+
+typedef struct {
+       int     x1, y1, x2, y2;
+       box     b;
+       point[] clipped;
+       point[] run;
+} test;
+
+box    bounds = { .x1 = 10, .x2 = 30, .y1 = 10, .y2 = 30 };
+
+int
+div_ceil(a, b) {
+       a += b;
+       assert(a >= 0 && b > 0, "bad divide args %d %d\n", a, b);
+       return (a + b - 1) // b - 1;
+}
+
+int
+div_floor_plus_one(a, b) {
+       a += b;
+       assert(a >= 0 && b > 0, "bad divide args %d %d\n", a, b);
+       return a // b;
+}
+
+bool
+clip(*clip_context c, *clip_box b)
+{
+       int     adjust_major = 0, adjust_minor = 0;
+
+       /* Clip major axis */
+       if (c->major < b->maj1) {
+               if (c->sign_major <= 0)
+                       return false;
+               adjust_major = b->maj1 - c->major;
+       } else if (c->major >= b->maj2) {
+               if (c->sign_major >= 0)
+                       return false;
+               adjust_major = c->major - (b->maj2-1);
+       }
+
+       /* Clip minor axis */
+       if (c->minor < b->min1) {
+               if (c->sign_minor <= 0)
+                       return false;
+               adjust_minor = b->min1 - c->minor;
+       } else if (c->minor >= b->min2) {
+               if (c->sign_minor >= 0)
+                       return false;
+               adjust_minor = c->minor - (b->min2-1);
+       }
+
+       /* If unclipped, we're done */
+       if (adjust_major == 0 && adjust_minor == 0)
+               return true;
+
+       /* See how much minor adjustment would happen during
+        * a major clip. This is a bit tricky because line drawing
+        * isn't symmetrical when the line passes exactly between
+        * two pixels, we have to pick which one gets drawn
+        */
+       int     adj_min;
+
+       if (!c->first)
+               adj_min = div_ceil(c->e + adjust_major * c->e1, -c->e3);
+       else
+               adj_min = div_floor_plus_one(c->e + adjust_major * c->e1, -c->e3);
+
+       /* Compare that to the minor clip and pick
+        * the larger amount.
+        */
+       printf ("\tinitial major %d minor %d error %d e1 %d e3 %d\n", c->major, c->minor, c->e, c->e1, c->e3);
+
+       if (adj_min < adjust_minor) {
+               printf("\tminor clip dominates %d < %d. adjust major %d -> ",
+                      adj_min, adjust_minor, adjust_major);
+               if (c->first)
+                       adjust_major = div_ceil(c->e - adjust_minor * c->e3, c->e1);
+               else
+                       adjust_major = div_floor_plus_one(c->e - adjust_minor * c->e3, c->e1);
+               printf("%d\n", adjust_major);
+       } else {
+               printf("\tminor clip dominates %d > %d. adjust minor %d -> ",
+                      adj_min, adjust_minor, adjust_minor);
+               adjust_minor = adj_min;
+               printf("%d\n", adjust_minor);
+       }
+
+       c->e += adjust_major * c->e1 + adjust_minor * c->e3;
+
+       c->major += c->sign_major * adjust_major;
+       c->minor += c->sign_minor * adjust_minor;
+
+       printf ("\tadjust major %d adjust minor %d e %d e1 %d e3 %e\n",
+               adjust_major, adjust_minor, c->e, c->e1, c->e3);
+
+       if (c->e >= 0)
+               printf ("error positive e %d e1 %d e3 %d\n",
+                       c->e, c->e1, c->e3);
+       if (c->e < c->e3)
+               printf ("error magnitude too large e %d e1 %d e3 %d\n", c->e, c->e1, c->e3);
+
+       return true;
+}
+
+test
+line(int x1, int y1, int x2, int y2, *box b) {
+
+       int     dx = x2 - x1;
+       int     dy = y2 - y1;
+       int     signdx = sign(dx);
+       int     signdy = sign(dy);
+       int     adx = abs(dx);
+       int     ady = abs(dy);
+       int     axis;
+       int     e, e1, e2, e3;
+       int     len;
+       clip_context    clip_1, clip_2;
+       clip_box        c;
+       bool            clipped = false;
+       test            t = {
+               .x1 = x1,
+               .y1 = y1,
+               .x2 = x2,
+               .y2 = y2,
+               .b = *b,
+               .clipped = (point[...]) {},
+               .run = (point[...]) {}
+       };
+
+       if (adx >= ady) {
+               axis = X_AXIS;
+               e1 = ady << 1;
+               e2 = e1 - (adx << 1);
+               e = e1 - adx;
+               len = adx;
+
+               clip_1.major = x1;
+               clip_1.minor = y1;
+               clip_2.major = x2;
+               clip_2.minor = y2;
+               clip_1.sign_major = signdx;
+               clip_1.sign_minor = signdy;
+
+               c.maj1 = b->x1;
+               c.maj2 = b->x2;
+               c.min1 = b->y1;
+               c.min2 = b->y2;
+       } else {
+               axis = Y_AXIS;
+               e1 = adx << 1;
+               e2 = e1 - (ady << 1);
+               e = e1 - ady;
+               len = ady;
+
+               clip_1.major = y1;
+               clip_1.minor = x1;
+               clip_2.major = y2;
+               clip_2.minor = x2;
+               clip_1.sign_major = signdy;
+               clip_1.sign_minor = signdx;
+               c.maj1 = b->y1;
+               c.maj2 = b->y2;
+               c.min1 = b->x1;
+               c.min2 = b->x2;
+       }
+
+       e3 = e2 - e1;
+       e = e - e1;
+
+       clip_1.first = true;
+       clip_2.first = false;
+       clip_2.e = clip_1.e = e;
+       clip_2.e1 = clip_1.e1 = e1;
+       clip_2.e3 = clip_1.e3 = e3;
+       clip_2.sign_major = -clip_1.sign_major;
+       clip_2.sign_minor = -clip_1.sign_minor;
+
+       printf ("clip start:\n");
+       if (!clip(&clip_1, &c))
+               clipped = true;
+
+       printf("clip end:\n");
+       if (!clip(&clip_2, &c))
+               clipped = true;
+
+       int     clip_len;
+       int     clip_x, clip_y;
+       int     clip_e;
+       int     x_major, x_minor;
+       int     y_major, y_minor;
+
+       clip_len = clip_1.sign_major * (clip_2.major - clip_1.major);
+       if (clip_len < 0)
+               clipped = true;
+
+       int x, y;
+
+       if (axis == X_AXIS) {
+               x = clip_1.major;
+               y = clip_1.minor;
+               x_major = clip_1.sign_major;
+               x_minor = 0;
+               y_major = 0;
+               y_minor = clip_1.sign_minor;
+       } else {
+               x = clip_1.minor;
+               y = clip_1.major;
+               x_major = 0;
+               x_minor = clip_1.sign_minor;
+               y_major = clip_1.sign_major;
+               y_minor = 0;
+       }
+
+       clip_e = clip_1.e;
+
+       if (clipped)
+               clip_len = -1;
+
+       while (clip_len-- >= 0) {
+               t.clipped[dim(t.clipped)] = (point) { .x = x, .y = y };
+               x += x_major;
+               y += y_major;
+               clip_e += e1;
+               if (clip_e >= 0) {
+                       x += x_minor;
+                       y += y_minor;
+                       clip_e += e3;
+               }
+       }
+
+       x = x1;
+       y = y1;
+
+       while (len-- >= 0) {
+               if (bounds.x1 <= x && x < bounds.x2 &&
+                   bounds.y1 <= y && y < bounds.y2) {
+                       t.run[dim(t.run)] = (point) { .x = x, .y = y };
+               }
+               x += x_major;
+               y += y_major;
+               e += e1;
+               if (e >= 0) {
+                       x += x_minor;
+                       y += y_minor;
+                       e += e3;
+               }
+       }
+       return t;
+}
+
+void read_events (Cairo::cairo_t cr)
+{
+       file    event = Cairo::open_event(cr);
+
+       while (!File::end(event)) {
+               string  event_line = File::fgets(event);
+               if (String::index(event_line, "delete") >= 0)
+                       exit(0);
+       }
+}
+
+#for (int y = 0; y < 20; y++)
+
+void
+show(cairo_t cr, test t)
+{
+       rectangle(cr, 0, 0, 40, 40);
+       set_source_rgba(cr, 1, 1, 1, 1);
+       fill(cr);
+
+       set_source_rgba(cr, 0, 1, 0, .2);
+       set_line_width(cr, 0.1);
+       for (int x = 0; x < 40; x++) {
+               move_to(cr, 0, x);
+               line_to(cr, 40, x);
+               move_to(cr, x, 0);
+               line_to(cr, x, 40);
+       }
+       stroke(cr);
+
+       rectangle(cr, t.b.x1, t.b.y1, t.b.x2 - t.b.x1, t.b.y2 - t.b.y1);
+       set_line_width(cr, 0.1);
+       set_source_rgba(cr, 0, 0, 0, 1);
+       stroke(cr);
+
+       move_to(cr, t.x1+.5, t.y1+.5);
+       line_to(cr, t.x2+.5, t.y2+.5);
+       move_to(cr, t.x2, t.y2);
+       line_to(cr, t.x2+1, t.y2+1);
+       move_to(cr, t.x2+1, t.y2);
+       line_to(cr, t.x2, t.y2+1);
+       stroke(cr);
+
+       void pixels(point[] pt) {
+               for (int i = 0; i < dim(pt); i++) {
+                       rectangle(cr, pt[i].x, pt[i].y, 1, 1);
+               }
+               fill(cr);
+       }
+
+       set_source_rgba(cr, 1, 0, 0, .5);
+       pixels(t.clipped);
+
+       set_source_rgba(cr, 0, 0, 1, .5);
+       pixels(t.run);
+}
+
+bool
+compare(test t)
+{
+       if (dim(t.clipped) != dim(t.run))
+               return false;
+
+       for (int i = 0; i < dim(t.clipped); i++)
+               if (t.clipped[i] != t.run[i])
+                       return false;
+       return true;
+}
+
+void
+doit(int i)
+{
+       int     n;
+       *box    b = &bounds;
+
+       cairo_t cr = new(800, 800);
+
+       scale(cr, 20, 20);
+
+       for (;;) {
+               PRNG::srandom(i);
+               int     x1 = PRNG::randint(40);
+               int     x2 = PRNG::randint(40);
+               int     y1 = PRNG::randint(40);
+               int     y2 = PRNG::randint(40);
+
+               test t = line (x1, y1, x2, y2, &bounds);
+               show(cr, t);
+               if (!compare(t)) {
+                       printf("line %d -- %d x %d - %d x %d\n", i, x1, y1, x2, y2);
+                       gets();
+               }
+               i++;
+       }
+
+       read_events(cr);
+}
+
+int i = 0;
+if (dim(argv) > 1)
+       i = atoi(argv[1]);
+
+doit(i);