File: htmlsys.h

package info (click to toggle)
qtads 2.1.6-1
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 16,156 kB
  • ctags: 18,767
  • sloc: cpp: 133,078; ansic: 26,048; xml: 18; makefile: 11
file content (2562 lines) | stat: -rw-r--r-- 121,253 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
/* $Header: d:/cvsroot/tads/html/htmlsys.h,v 1.4 1999/07/11 00:46:40 MJRoberts Exp $ */

/* 
 *   Copyright (c) 1997 by Michael J. Roberts.  All Rights Reserved.
 *   
 *   Please see the accompanying license file, LICENSE.TXT, for information
 *   on using and copying this software.  
 */
/*
Name
  htmlsys.h - HTML system API interface
Function
  These classes define a set of system-dependent functions that the
  HTML formatter needs to do its work.  These classes must be implemented
  separately for each operating and/or window system.  The purpose
  of these classes is to provide a portable interface to these system-
  dependent functions, so that the HTML formatter doesn't need to be
  modified for each new operating system that it's ported to.  These
  classes isolate the system-dependent code so that it can be easily
  found for porting purposes.

  Note that these classes are designed as abstract interfaces.  The
  reason for this design is to allow these classes to be easily used
  with an existing C++ application framework.  To use the classes from
  an application framework to implement the window object interface
  (CHtmlSysWin), for example, simply create a subclass of the
  appropriate window class from your framework, and make your subclass
  multiply inherit from CHtmlSysWin as well as from the framework
  class.  Because CHtmlSysWin is an abstract interface class, it
  should always be easy to use it in a multiple inheritance design
  without worrying about any of the problematic aspects of multiple
  inheritance (such as virtual base classes).
Notes

Modified
  09/07/97 MJRoberts  - Creation
*/

#ifndef HTMLSYS_H
#define HTMLSYS_H

#include <stdarg.h>
#include <time.h>

#ifndef HTML_OS_H
#include "html_os.h"
#endif
#ifndef TADSHTML_H
#include "tadshtml.h"
#endif


/* ------------------------------------------------------------------------ */
/*
 *   Font description.  This is used to specify the characteristics of a
 *   desired font to a window, so that the window can create an
 *   appropriate system font appropriate for the description.
 *   
 *   The oshtml_charset_id_t type is a system-defined type that specifies
 *   the character set to be used for the font.  On systems such as
 *   Windows where fonts are mapped to particular code pages, we use this
 *   to select a font that contains the code page mapping that we need for
 *   each text string.
 *   
 *   Note that this is a portable concrete class - there is no need to
 *   subclass this class per platform.  This class is defined to provide a
 *   portable means of describing a font, so that an appropriate system
 *   font object can be created based on a description generated by
 *   portable code.  
 */
const int HTMLFONTDESC_FACE_MAX = 128;
class CHtmlFontDesc
{
public:
    CHtmlFontDesc()
    {
        face[0] = '\0';
        face_set_explicitly = FALSE;
        pointsize = 0;
        default_color = TRUE;
        default_bgcolor = TRUE;
        color = 0;
        bgcolor = 0;
        weight = 400;
        italic = FALSE;
        underline = FALSE;
        strikeout = FALSE;
        fixed_pitch = FALSE;
        serif = TRUE;
        htmlsize = 0;
        superscript = subscript = FALSE;
        pe_big = pe_small = FALSE;
        pe_em = pe_strong = pe_dfn = pe_code = pe_samp = pe_kbd
            = pe_var = pe_cite = pe_address = FALSE;
        default_charset = TRUE;
    }

    void copy_from(const CHtmlFontDesc *src);

    /*
     *   Size of the font in points.  Note that we will ignore the
     *   pointsize if the htmlsize member is set to a non-zero value.  
     */
    int pointsize;

    /*
     *   Weight, on a scale of 0 to 1000.  The weights available for a
     *   particular font vary, but by convention the following weights
     *   apply to most faces: 200 is light; 400 is normal or book weight;
     *   700 is bold; 900 is black (ultrabold).  
     */
    int weight;

    /* italic, underline, strike-out */
    int italic : 1;
    int underline : 1;
    int strikeout : 1;

    /*
     *   Color.  If default_color is TRUE, we'll ignore this and use an
     *   appropriate default text color instead.
     *   
     *   Note that font descriptors only contain RGB values.  Special color
     *   ID values (the HTML_COLOR_xxx parameterized color IDs) are not used
     *   in font descriptors.  
     */
    int default_color : 1;
    HTML_color_t color;

    /*
     *   Background color.  If default_bgcolor is TRUE, we'll ignore this and
     *   draw text transparently over the existing background. 
     *   
     *   Note that font descriptors only contain RGB values.  Special color
     *   ID values (the HTML_COLOR_xxx parameterized color IDs) are not used
     *   in font descriptors.  
     */
    int default_bgcolor : 1;
    HTML_color_t bgcolor;

    /*
     *   Face name.  If the face name is provided, we'll use the face to
     *   choose a font and ignore the characteristics.  If the face name
     *   is left empty, we'll use the characteristics to choose a font.
     *   Multiple face names can be specified by separating the names with
     *   commas; the first face that is available on the machine at
     *   run-time is used.
     *   
     *   Note that the following parameterized font names can be used.
     *   These names must be mapped to an appropriate actual font on each
     *   system.  The purpose of these names is to allow games more
     *   control over choosing a specific style of font while retaining
     *   portability and also giving the player more control of the
     *   presentation.  When possible, the player should be allowed to
     *   select the actual system font to be used for each of these fonts
     *   through a preferences mechanism.  Note that these parameterized
     *   font names are mapped to actual system fonts by
     *   CHtmlSysWin::get_font().
     *   
     *   TADS-serif - a serifed font, usually proportional
     *.  TADS-sans - a san serif font, usually proportional
     *.  TADS-script - a script or cursive font, usually proportional
     *.  TADS-typewriter - a typewriter-style font, usually fixed-width
     *.  TADS-input - the font to use for player commands
     */
    textchar_t face[HTMLFONTDESC_FACE_MAX];

    /* 
     *   The parameterized font names.  Note that, as with tag and attribute
     *   names, these names are to be parsed WITHOUT case sensitivity.  
     */
#define HTMLFONT_TADS_SERIF        "TADS-serif"
#define HTMLFONT_TADS_SANS         "TADS-sans"
#define HTMLFONT_TADS_SCRIPT       "TADS-script"
#define HTMLFONT_TADS_TYPEWRITER   "TADS-typewriter"
#define HTMLFONT_TADS_INPUT        "TADS-input"

    /*
     *   Flag: the face was set explicitly in the descriptor.  This is set
     *   in cases where the face name is being explicitly changed, rather
     *   than inherited from an enclosing block of text.  When this is set
     *   to true, if the face is a parameterized font name (such as
     *   "TADS-input"), and the parameterized font carries other attributes
     *   such as color and italics settings, we will apply the other
     *   attributes.  When this is set to false, we'll use the parameterized
     *   face name, but we'll otherwise ignore the extra baggage carried
     *   with the face, if any.
     *   
     *   For example, suppose that we're formatting along in a string of
     *   text, and we want to change the text color to red for a bit of
     *   text, but we want to continue using the other attributes of the
     *   text up to this point; in such a case, we'd copy the font
     *   descriptor currently in use, so we'd fill in the current face name,
     *   but we'd leave this flag set to false to indicate that we don't
     *   want any of the baggage associated with the font if it's a
     *   parameterized font.  
     */
    int face_set_explicitly : 1;

    /*
     *   Characteristics.  In the absence of an explicit face name, we
     *   can use these characteristics to choose a font suitable for a
     *   particular HTML usage.  If the face name is provided, these
     *   characteristics are ignored.  
     */

    /* true -> fixed pitch, false -> variable pitch */
    int fixed_pitch : 1;

    /* true -> serif face, false -> sans serif face */
    int serif : 1;

    /*
     *   HTML size, on a scale of 1 to 7.  If this value is zero, the
     *   pointsize member will be used instead.  
     */
    int htmlsize;

    /* superscript/subscript (mutually exclusive) */
    int superscript : 1;
    int subscript : 1;

    /* HTML BIG/SMALL settings (mutually exclusive) */
    int pe_big : 1;
    int pe_small : 1;

    /* HTML phrase/block elements that select a font */
    int pe_em : 1;
    int pe_strong : 1;
    int pe_dfn : 1;
    int pe_code : 1;
    int pe_samp : 1;
    int pe_kbd : 1;
    int pe_var : 1;
    int pe_cite : 1;
    int pe_address : 1;

    /* 
     *   Character set identifier; this is system-dependent, and is opaque
     *   to the generic code.  Character set identifiers can be obtained
     *   from the system (for example, via the CHtmlSysWinGroup method
     *   get_default_win_charset()), and can then be passed back to the
     *   system when, for example, creating a font.
     *   
     *   When a font descriptor is used to create a font object,
     *   'default_charset' can be set to TRUE to use the default system
     *   character set.  In this case, 'charset' is ignored.
     *   
     *   Once a font object is created, the system must set 'charset' to a
     *   valid character set if 'default_charset' is specified in the
     *   creation descriptor.  This allows a caller to obtain the actual
     *   character set for a font object, even if the font was created with
     *   the default flag (and thus no valid 'charset' data).  
     */
    oshtml_charset_id_t charset;
    int default_charset;
};


/* ------------------------------------------------------------------------ */
/*
 *   System font object.  This is an abstract interface; each system must
 *   have its own implementation of the interface.
 *   
 *   Note that instances of (concrete subclasses of) CHtmlSysFont are created
 *   by the system window code.  Refer to CHtmlSysWin::get_font().
 *   
 *   A note on memory management: The portable code never deletes font
 *   objects.  Instead, the system code is expected to keep a list of all of
 *   the font objects ever created.  Each time a caller asks to create a new
 *   font via CHtmlSysWin::get_font(), the system code first scans the list
 *   to see if the same font (with the identical descriptor) has been
 *   allocated already; if so, it simply returns the existing CHtmlSysFont
 *   instance.  If not, it creates a new CHtmlSysFont instance, adds it to
 *   the list, and returns the new instance.
 *   
 *   So, even though the portable code never deletes font objects, it won't
 *   leak memory as long as the system code uses this cache list approach.
 *   Font memory will never shrink, but it will only grow up to a fixed upper
 *   limit - specifically, the maximum font memory will be the amount needed
 *   to hold one instance of each distinct font used in the game.
 *   
 *   The reasoning behind this approach is that (a) a given game has a
 *   relatively small number of distinct fonts it uses, (b) each font tends
 *   to be used over and over many times, and (c) on many systems it's a
 *   relatively heavy operation to create a system font resource.  So it's
 *   more efficient to use this cache approach than to create and destroy
 *   font objects on each use.  Fonts objects would also be fairly complex to
 *   account for, so this scheme avoids the need for reference counting or
 *   other means to avoid font memory leaks.  
 */
class CHtmlSysFont
{
public:
    virtual ~CHtmlSysFont() { }

    /* get the metrics for the font */
    virtual void get_font_metrics(class CHtmlFontMetrics *) = 0;

    /* 
     *   Is this a fixed-pitch font?  This indicates whether or not the
     *   actual system font that this object represents is monospaced.  For
     *   efficiency, implementations should (if possible) note the font's
     *   type upon instantiation of this object, and simply return the
     *   remembered information here.  
     */
    virtual int is_fixed_pitch() = 0;

    /*
     *   Get the "em" size of the font, expressed in pixels.  On many
     *   systems, a font's em size is a design property of the font, stored
     *   with the font's OS-level resource (or equivalent) information.
     *   
     *   For systems where the em size isn't stored with the font,
     *   implementations should simply return the nominal point size of the
     *   font translated to a pixel size.  In traditional typography, a
     *   font's em size is the same as the font's nominal height.
     *   
     *   For efficiency, implementations should (if possible) note the em
     *   size upon instantiation of this object, and simply return the stored
     *   size information here.  
     */
    virtual int get_em_size() = 0;

    /* 
     *   Get the description of the font (or a pointer to it).  This is the
     *   concrete description, which isn't necessarily identical to the
     *   descriptor that was used to create the font, since the font creation
     *   process might have resolved parameterized font names (TADS-Input,
     *   TADS-Sans, etc) and filled in concrete values for defaults.  
     */
    void get_font_desc(class CHtmlFontDesc *dst) const
        { dst->copy_from(&desc_); }
    const CHtmlFontDesc *get_font_desc_ref() const { return &desc_; }

    /*
     *   Get the color, and whether this color should be used (if not, an
     *   appropriate default color should be used instead).
     */
    HTML_color_t get_font_color() const { return desc_.color; }
    int use_font_color() const { return !desc_.default_color; }

    /* get the character set of the font */
    oshtml_charset_id_t get_charset() const { return desc_.charset; }

    /* 
     *   Get the background color, and whether this color should be used.  If
     *   the background color is not to be used, the text should be displayed
     *   over the existing background.  If the background color is to be
     *   used, then the background color should fill in the bounding
     *   rectangle of the text. 
     */
    HTML_color_t get_font_bgcolor() const { return desc_.bgcolor; }
    int use_font_bgcolor() const { return !desc_.default_bgcolor; }

protected:
    /* 
     *   the font descriptor - the system must set this to the font
     *   descriptor when the font is created 
     */
    CHtmlFontDesc desc_;
};



/*
 *   Font metrics (portable class; this is used to parameterize certain
 *   functions that measure text displays).  
 *   
 *   The 'ascent height' is the distance between the TOP of the box
 *   containing any character in the font and the BASELINE.  The baseline is
 *   defined by the font's designer, but in general it's the alignment point
 *   for the bottoms of the capital letters and of the minuscules that don't
 *   have tails (tails: g, j, p, q, y - the bits that drop below the
 *   baseline).  The reason the ascent height is important is that it tells
 *   us where the baseline is relative to the overall rectangle containing a
 *   character in the font, and the baseline is important because it's the
 *   reference point for aligning adjacent text from different fonts.
 *   
 *   The 'descent height' is the height below the baseline.
 *   
 *   The total height is the sum of the ascender and descender heights.  
 */
class CHtmlFontMetrics
{
public:
    int ascender_height;                /* height in pixels above baseline  */
    int descender_height;                /* height in pixels below baseline */
    int total_height;                             /* total height in pixels */
};


/* ------------------------------------------------------------------------ */
/*
 *   Enumeration status code return values for status functions.  These are
 *   not currently used in the portable interface, but are included here for
 *   possible future use, and can be used within the platform-specific
 *   implementation if convenient.
 *   
 *   These are obsolescent - the corresponding OS_EVT_xxx status codes
 *   should be used instead.  
 */
enum htmlsys_input_stat_t
{
    /* input successfully read */
    HTMLSYS_INPUT_STAT_OK,

    /* end of file, application terminated, or other error reading input */
    HTMLSYS_INPUT_STAT_EOF,

    /* operation timed out - input interrupted before user pressed "Enter" */
    HTMLSYS_INPUT_STAT_TIMEOUT
};


/* ------------------------------------------------------------------------ */
/*
 *   Banner position settings.  Banners can be horizontal, in which case they
 *   are above or below the main window and run across the whole width of the
 *   main window; or vertical, in which case they are left or right of the
 *   main window and run down its entire height.
 *   
 *   Multiple banners can be created with the same alignment, in which case
 *   each new banner is aligned just inside of the previous banner.  ("Inside
 *   of" in the sense of relative to the boundaries of the outer frame
 *   window.)
 *   
 *   For example, the first top-aligned banner goes at the top of the main
 *   window, with the second top-aligned banner aligned immediately below it,
 *   and the input window immediately below that.  Similarly, the first
 *   right-aligned banner is aligned at the right edge of the main window,
 *   the second right-aligned banner is just to the left of the first, and
 *   the main window is just to the left of those.
 *   
 *   Every window is always rectangular.  To determine the positioning of the
 *   banners, start off with the input window equal in size to the overall
 *   main window.  For each banner, divide the input window's area according
 *   to the type of banner and its size.  For example, for a bottom-aligned
 *   banner, divide the main window into two horizontal bands -- one for the
 *   banner and one for the remaining input window -- each the full width of
 *   the input window; the banner is given an amount of vertical space
 *   determined by its height, and the remainder is left for the new input
 *   window area.  Shrink the input window to the new size left over after
 *   removing the new banner's area from the original input window area.  Now
 *   apply the same process to each subsequent banner window.
 *   
 *   Note that these codes are mapped directly to the corresponding
 *   OS_BANNER_ALIGN_xxx codes, to simplify using our banner window system as
 *   an implementation of the tads 2 os_banner interface.  
 */
enum HTML_BannerWin_Pos_t
{
    /*
     *   Default alignment - the banner is positioned at the top of the main
     *   window, and runs across the whole width of the main window 
     */
    HTML_BANNERWIN_POS_TOP = OS_BANNER_ALIGN_TOP,

    /* banner is at the bottom of the main input window */
    HTML_BANNERWIN_POS_BOTTOM = OS_BANNER_ALIGN_BOTTOM,

    /*
     *   The banner divides the main window vertically, and is aligned at the
     *   left edge of the main window.  The banner runs down the entire
     *   height of the main window.  
     */
    HTML_BANNERWIN_POS_LEFT = OS_BANNER_ALIGN_LEFT,

    /* vertical banner aligned at the right edge of the main window */
    HTML_BANNERWIN_POS_RIGHT = OS_BANNER_ALIGN_RIGHT
};

/*
 *   Banner window size units.  These are used to specify the interpretation
 *   of the size value when a size is specified.  
 */
enum HTML_BannerWin_Units_t
{
    /*
     *   Percentage size.  The size is given as a percentage of the REMAINING
     *   space available in the parent window.  
     */
    HTML_BANNERWIN_UNITS_PCT,

    /*
     *   "Character" size.  The size is given in rows or columns of
     *   characters.  For a window with proportionally-spaced text, or
     *   varying text sizes, this is in terms of the size of a '0' character
     *   in the window's default font. 
     */
    HTML_BANNERWIN_UNITS_CHARS,

    /*
     *   Pixel size.  The size is given in pixels.
     */
    HTML_BANNERWIN_UNITS_PIX
};


/*
 *   Banner window type codes.  When a banner window is created, one of these
 *   type codes will be passed to the system code to let it know what's going
 *   on in the window.
 */
enum HTML_BannerWin_Type_t
{
    /* 
     *   <BANNER> tag window.  This type of window is created for an in-line
     *   <BANNER> tag in the main window's HTML.  This type of window is
     *   based on contents from the same output stream as the main game
     *   window.  
     */
    HTML_BANNERWIN_BANNERTAG,

    /* 
     *   Text stream window, created programmatically (such as through the
     *   os_banner API).  This type of window has an independent output
     *   stream from the main game window, but otherwise behaves pretty much
     *   the same as a <BANNER> tag window.  
     */
    HTML_BANNERWIN_TEXT,

    /*
     *   Text grid window.  This type of window doesn't have an HTML parser,
     *   although it does use the same list of display items (CHtmlDisp
     *   objects) as any other window, so the OS window implementation
     *   doesn't usually have to do anything extra to support this.  
     */
    HTML_BANNERWIN_TEXTGRID
};

/* ------------------------------------------------------------------------ */
/*
 *   System application frame interface.  This interface must be implemented
 *   by some object in the system-dependent layer to provide the interface
 *   that the HTML version of the TADS display OS interface layer uses to
 *   operate the HTML display.
 *   
 *   This interface can be implemented by the main system window object
 *   (i.e., the same C++ object that implements the CHtmlSysWin interface),
 *   if desired; alternatively, it can be implemented by another object, such
 *   as the main application object (if there is one in the system-dependent
 *   implementation).
 *   
 *   Note: the system-dependent code is responsible for creating a singleton
 *   CHtmlSysFrame object.  After creating the object, the system code must
 *   call CHtmlSysFrame::set_frame_obj() to tell the oshtml layer about the
 *   object.  Similarly, the system code must call
 *   CHtmlSysFrame::set_frame_obj(0) when the frame object is about to be
 *   deleted, to ensure that the portable code doesn't attempt to make any
 *   calls to it after it's gone.  
 */
class CHtmlSysFrame
{
public:
    virtual ~CHtmlSysFrame() {}

    /*
     *   Set the system frame object.
     *   
     *   During initialization, the system-specific code must call this
     *   routine to initialize the frame object as soon as the frame object
     *   has been created.  (The system-specific code is responsible for
     *   creating the frame object in the first place, too.)
     *   
     *   During termination, the system code should call this to set the
     *   frame object to a null pointer so we know it's forgotten.  
     */
    static void set_frame_obj(CHtmlSysFrame *frame) { app_frame_ = frame; }

    /* get the app frame object */
    static CHtmlSysFrame *get_frame_obj() { return app_frame_; }

    /*
     *   Kill the process.  This is a static function that must be
     *   implemented by the port-specific code.
     *   
     *   This is called when the input layer (in oshtml.cpp) finds that the
     *   program is looping on input after EOF.  This routine should force
     *   the program to terminate, by explicitly killing the process via the
     *   OS API if possible.
     */
    static void kill_process();

    /* 
     *   Flush the text output buffer.
     *   
     *   If 'fmt' is true, format the new text and add it to the display;
     *   otherwise, simply parse it.
     *   
     *   If 'immediate_redraw' is true, the contents of the window should be
     *   updated on the display immediately if possible.  This is used to
     *   ensure that the display is updated before a possibly lengthy
     *   computation; on event-driven operating systems, we might not be
     *   able to process any redraw events during the computation, so we
     *   want to ensure that any necessary drawing is done before the
     *   computation begins to avoid the appearance that the program is
     *   frozen during the delay.  
     */
    virtual void flush_txtbuf(int fmt, int immediate_redraw) = 0;

    /* get the parser associated with the main window */
    virtual class CHtmlParser *get_parser() = 0;

    /* 
     *   Start a new page.  This clears out the main text window, including
     *   any banner windows created with <BANNER> tags in the main text
     *   window.
     *   
     *   Note that this should NOT remove banner windows created through the
     *   os_banner API - it should ONLY remove <BANNER> tag windows.  Most
     *   implementations will simply call remove_all_banners() on the main
     *   text window's CHtmlFormatter object; this will automatically remove
     *   the <BANNER> tag windows and preserve any os_banner API windows.  
     */
    virtual void start_new_page() = 0;

    /* 
     *   Set non-stop mode.  The system window must handle MORE prompting, so
     *   it will need to keep track of this non-stop mode setting.  
     */
    virtual void set_nonstop_mode(int flag) = 0;

    /* 
     *   Display the string of the given byte length.  Note that because an
     *   explicit length is given, the string might not be null-terminated.  
     */
    virtual void display_output(const textchar_t *buf, size_t len) = 0;

    /* 
     *   Check for a break key sequence.  Returns true if the
     *   (system-defined) break key has been hit, false if not.  
     */
    virtual int check_break_key() = 0;

    /*
     *   Read a keyboard command.  Returns false if the application is
     *   quitting, true otherwise.
     */
    virtual int get_input(textchar_t *buf, size_t bufsiz) = 0;

    /*
     *   Read a keyboard command, with an optional timeout.  This is
     *   essentially an implementation of os_gets_timeout() and behaves in
     *   essentially the same way; refer to osifc.h for full details on that
     *   routine.
     *   
     *   Returns an OS_EVT_xxx code as follows:
     *   
     *   OS_EVT_LINE - we successfully read a line of input, terminated by
     *   the user pressing Return (or the local equivalent).  If the user
     *   entered data in some other fashion that would normally work in
     *   get_input(), such as clicking on a hyperlink or selecting a command
     *   from a menu, this routine still returns OS_EVT_LINE; we are not
     *   interested in any arbitrary events, but only complete input lines.
     *   The buffer should be filled in with the line of text the user
     *   entered.
     *   
     *   OS_EVT_EOF - an error occurred, or the application is being
     *   terminated.  
     *   
     *   OS_EVT_TIMEOUT - the timeout expired without the user having
     *   completed input.  The buffer should be filled in with the text the
     *   user entered before the timeout expired.  Everything should be left
     *   as-is in the user interface, in case we resume editing the same
     *   input with no intervening operations.  This routine must statically
     *   store its complete editing state, including the text being edited,
     *   caret position, selected text range, insert/overwrite mode, and
     *   anything else that is significant, so that the routine can restore
     *   the same editing state seamlessly if the routine is invoked
     *   subsequently without an intervening call to get_input_cancel().
     *   
     *   Note that the timeout is optional.  If use_timeout is FALSE, the
     *   routine should behave roughly the same as the regular get_input(),
     *   except that this routine should still resume the previously
     *   interrupted editing session if there is one.  
     */
    virtual int get_input_timeout(textchar_t *buf, size_t buflen,
                                  unsigned long timeout, int use_timeout) = 0;

    /*
     *   Cancel input that was interrupted by a timeout.  This routine
     *   terminates the input operation that was interrupted, making any
     *   associated display changes (such as moving the caret to a new line
     *   and removing the selected text range) that would normally be made
     *   when editing is finished on a line of text.
     *   
     *   If 'reset' is true, it means that we are to forget all of our
     *   static editing state from the interrupted editing, so that the next
     *   call to get_input_timeout() starts with an empty line of text.  If
     *   'reset' is false, then the next call to get_input_timeout() will
     *   resume the previous editing session.
     *   
     *   (The distinction between "canceling" and "resetting" is subtle.
     *   Canceling simply finishes the previous editing in terms of the user
     *   interface state, so that new display operations can be performed;
     *   the effect is the same as though the user had pressed Return to
     *   terminate the input that timed out, except that we don't forget the
     *   input.  After canceling, when we call get_input_timeout(), we
     *   re-display the saved input from the interrupted session, and resume
     *   the session where we left off, but with a freshly-displayed copy of
     *   the command line on the screen.  Resetting does everything that
     *   canceling does, but in addition forgets all of the state from the
     *   interrupted editing session, so that the next get_input_timeout()
     *   simply starts from scratch with an empty input buffer.)
     *   
     *   This routine MUST be called before any display operation (input or
     *   output) can be performed after get_input_timeout() returns
     *   OS_EVT_TIMEOUT, *except* that os_input_timeout() can be called
     *   again to resume the interrupted session.  
     */
    virtual void get_input_cancel(int reset) = 0;
    
    /*
     *   Read an input event.  This routine follows the semantics of the
     *   TADS os_get_event() interface, and returns one of the OS_EVT_xxx
     *   event types.  
     */
    virtual int get_input_event(unsigned long timeout_in_milliseconds,
                                int use_timeout, os_event_info_t *info) = 0;

    /* 
     *   Wait for a keystroke from the main window.  Returns the character
     *   corresponding to the keystroke, if it's a "normal" (i.e., ascii)
     *   character, zero if it's a system-specific keystroke, such as a
     *   function key.  If 'pause_only' is true, it means that the caller
     *   doesn't actually care about the keystroke returned, but is asking
     *   for a keystroke purely for the purpose of pausing until the user
     *   acknowledges a message by hitting a key; the window may want to
     *   display an appropriate status line message or provide a similar
     *   indication that we're waiting for a player keystroke.  
     */
    virtual textchar_t wait_for_keystroke(int pause_only) = 0;

    /* 
     *   Pause before exiting.  Wait for a keystroke.  This is similar to
     *   wait_for_keystroke(); it's a separate routine in case the window
     *   wants to display something to notify the user that the program
     *   will exit on the next keystroke, such as a status line message to
     *   this effect.  
     */
    virtual void pause_for_exit() = 0;

    /*
     *   Display the MORE prompt, wait for the user to respond, and remove
     *   the MORE prompt.
     */
    virtual void pause_for_more() = 0;

    /*
     *   Display a message to the debug log window.  The debug window is
     *   optional, so these functions can have empty implementations.  The
     *   debug window is used to display internal HTML TADS status
     *   messages when the system is compiled with the macro
     *   TADSHTML_DEBUG; in addition, it's used to display HTML error
     *   messages that game authors may find helpful in debugging their
     *   games. 
     */
    virtual void dbg_print(const char *msg) = 0;

    /*
     *   Create a banner window.  Return null if this is not possible.
     *   
     *   'parent' is the parent window.  If this is null, then the new
     *   banner is a child of the main game window (the text window
     *   containing the main game transcript).  Otherwise, 'parent' is an
     *   existing banner subwindow; the new window is carved out of the
     *   space of the parent.
     *   
     *   'where' specifies where the banner goes in the list of children of
     *   the given parent, which determines how the space is divided among
     *   the windows.  This is OS_BANNER_FIRST to make the new banner window
     *   the first child of its parent, OS_BANNER_LAST to make it the last
     *   child, OS_BANNER_BEFORE to put it immediately before the banner
     *   window specified by 'other', or OS_BANNER_AFTER to put it
     *   immediately after 'other'.  When BEFORE or AFTER are specified,
     *   'other' must be an existing child of the given parent; if 'other'
     *   isn't a child of the parent, then the routine should behave as
     *   though OS_BANNER_LAST were specified.
     *   
     *   'pos' gives the alignment type of the banner.
     *   
     *   'style' is a combination of OS_BANNER_STYLE_xxx flags, as defined in
     *   osifc.h (from the tads 2 sources).  
     */
    virtual class CHtmlSysWin
        *create_banner_window(class CHtmlSysWin *parent,
                              HTML_BannerWin_Type_t window_type,
                              class CHtmlFormatter *formatter,
                              int where, class CHtmlSysWin *other,
                              HTML_BannerWin_Pos_t pos,
                              unsigned long style) = 0;

    /*
     *   "Orphan" a banner window.  This is simply an implementation of
     *   os_banner_orphan() from the tads 2 osifc definition.
     *   
     *   A valid implementation is simply to call os_banner_delete(),
     *   passing the formatter object as the banner handle.
     *   
     *   If the OS implementation wishes to keep orphaned banner windows on
     *   the screen for a while after they're orphaned, it can take
     *   ownership of the banner here, and delete the banner at leisure.  
     */
    virtual void orphan_banner_window(
        class CHtmlFormatterBannerExt *banner) = 0;

    /*
     *   Create a window for an "about box."  Return null if this is not
     *   possible.  If the system has a customary way of displaying an "about
     *   box" (a dialog that displays information on the application, such as
     *   its name, version, and copyright information), the window returned
     *   should be used when the about box is needed.  This window will be a
     *   standard HTML display window, which the game will fill in with HTML
     *   as it desires.
     *   
     *   Only one about box is needed for the entire application; if an about
     *   box subwindow already exists, this routine should simply return the
     *   existing window.  Note that this about box is for information about
     *   the *game*, so any menu item that accesses it should say something
     *   like "About This Game" rather than "About HTML TADS."  
     */
    virtual CHtmlSysWin
        *create_aboutbox_window(class CHtmlFormatter *formatter) = 0;

    /*
     *   Remove a banner subwindow.  This call can be ignored if the window
     *   doesn't support banners.  The CHtmlSysWin object must be deleted by
     *   this call, so the caller cannot refer to the window after this call
     *   returns.  
     */
    virtual void remove_banner_window(CHtmlSysWin *win) = 0;

    /*
     *   Look up an "embedded resource."  This is a resource (an image file,
     *   sound file, etc) that's bundled with the interpreter application
     *   itself - not part of a game, but part of the interpreter system.
     *   
     *   The resource finder calls this routine to resolve any resource name
     *   that can't be found in the game file (the .GAM or .T3 file).  In
     *   most cases, the system will want to adopt a local naming convention;
     *   on Windows, for example, these names are all prefixed with "exe:",
     *   but each system can use its own convention, as the only uses of
     *   these resources are in the system-specific code to begin with.
     *   
     *   If the resource is found, copy the name of the OS file containing
     *   the resource into the caller's buffer, set *seek_pos and *siz to the
     *   seek offset within the file and the size (in bytes) of the
     *   resource's data within the file, respectively, and return true.  If
     *   there is no such embedded resource, return false.
     *   
     *   This function is purely for the use of the system-specific
     *   interpreter implementation.  If the interpreter doesn't have any use
     *   for embedded resources, this need not be implemented.  This function
     *   was originally created to allow HTML TADS on Windows to use an HTML
     *   window for its "About" box - this routine is used to allow the HTML
     *   in the About box to refer to a JPEG image file that's embedded in
     *   the interpreter .EXE file.  This function is called from the
     *   portable code, but only in response to HTML text that's generated by
     *   the platform-specific code - so if your platform doesn't generate
     *   any such HTML source in its own internal dialogs or whatever, this
     *   will never be called.  
     */
    virtual int get_exe_resource(const textchar_t *resname, size_t resnamelen,
                                 textchar_t *fname_buf, size_t fname_buf_len,
                                 unsigned long *seek_pos,
                                 unsigned long *siz) = 0;

private:
    /*
     *   The system frame is a singleton object, defined and managed by the
     *   OS code, that implements the CHtmlSysFrame interface.  The OS code
     *   must create this object at startup and delete it at termination.  
     */
    static CHtmlSysFrame *app_frame_;
};


/* ------------------------------------------------------------------------ */
/*
 *   Window Group interface.  This interface should be associated with the
 *   object that contains the main HTML window and any banner subwindows.
 *   
 *   Depending on how the system code is designed, this interface could be
 *   associated with the same object as the CHtmlSysWin interface for the
 *   main HTML window, or could be associated with the entire application.
 *   This interface is provided separately from either of those two
 *   interfaces to allow for the possibility of an intermediate container.
 *   (This is how the Windows implementation is designed - the
 *   intermediate container object is a container window that provides a
 *   single system window frame for the main HTML window and its
 *   associated banner subwindows.)  
 */
class CHtmlSysWinGroup
{
public:
    virtual ~CHtmlSysWinGroup() {}

    /*
     *   Get the current default character set ID for the frame.  This
     *   will normally reflect the system-wide localization settings,
     *   although on some systems, the application may wish to provide a
     *   user preference to change the default character set, on an
     *   application-wide basis or possibly even per window, depending on
     *   system localization conventions.  
     */
    virtual oshtml_charset_id_t get_default_win_charset() const = 0;

    /*
     *   Translate an HTML 4 character code point value to a local
     *   character code point.  This is used to map '&' entities, both
     *   named and numeric, to local character set code points.  The HTML
     *   4 character codes are the same as Unicode values.  HTML TADS
     *   attempts to support at least the ISO Latin-1 character set plus
     *   the HTML 4 named symbol entity character set.
     *   
     *   If 'charset' is not null, this routine should fill in *charset
     *   with the OS-specific character set ID to use for the character.
     *   If 'charset' is null, the caller cannot change the character set,
     *   so we must attempt to map the character to the current default
     *   character set.  If the character cannot be mapped (either because
     *   no mapping is available at all, or because charset is null and
     *   the character can't be mapped to the current default character
     *   set), this routine should produce a suitable invalid character
     *   value.
     *   
     *   If 'charset' is not null, 'changed_charset' should be non-null as
     *   well.  On return, we'll set *changed_charset to true if we
     *   returned a non-default character set in *charset, false otherwise.
     *   
     *   The return value is the length in bytes of the result.  This
     *   routine is allowed to return more than a single byte to allow for
     *   multi-character approximations; for example, a copyright symbol
     *   could be approximated as "(c)" when the local character set
     *   doesn't have a suitable character value.  
     */
    virtual size_t xlat_html4_entity(textchar_t *result, size_t result_size,
                                     unsigned int charval,
                                     oshtml_charset_id_t *charset,
                                     int *changed_charset) = 0;
};

/* ------------------------------------------------------------------------ */
/*
 *   System window object.  This is an abstract interface; each system must
 *   have its own implementation of the interface.
 *   
 *   Note that, for simplicity, the same system window interface is used for
 *   regular HTML windows and HTML banner windows.
 *   
 *   Instances of (concrete subclasses of) CHtmlSysWin are created by system
 *   code.  The startup code (which is always system-specific) creates the
 *   main game window, and CHtmlSysFrame::create_banner_window() creates
 *   banner windows.  
 */


/*
 *   for inval_doc_coords, these values can be used for the .right and
 *   .bottom settings to indicate that the window should be invalidated
 *   all the way to the right or all the way to the bottom, respectively 
 */
const long HTMLSYSWIN_MAX_RIGHT = -1;
const long HTMLSYSWIN_MAX_BOTTOM = -1;

/*
 *   Bullet styles 
 */
enum HTML_SysWin_Bullet_t
{
    HTML_SYSWIN_BULLET_SQUARE,                          /* filled-in square */
    HTML_SYSWIN_BULLET_CIRCLE,                            /* circle outline */
    HTML_SYSWIN_BULLET_DISC,                            /* filled-in circle */
    HTML_SYSWIN_BULLET_PLAIN                    /* plain - no bullet at all */
};

class CHtmlSysWin
{
public:
    CHtmlSysWin(class CHtmlFormatter *formatter)
        { formatter_ = formatter; }
    virtual ~CHtmlSysWin() { }

    /* get the formatter associated with the window */
    class CHtmlFormatter *get_formatter() const { return formatter_; }

    /* 
     *   forget my formatter; since the container application owns the
     *   formatter, it will have to delete it at some point, and can use this
     *   routine to notify the window that the formatter is about to be
     *   deleted 
     */
    void forget_formatter() { formatter_ = 0; }

    /* get the window group object for the group I'm associated with */
    virtual class CHtmlSysWinGroup *get_win_group() = 0;

    /* 
     *   Receive notification that the contents of the window are being
     *   cleared.  The portable code calls this to let the system layer know
     *   that it's clearing the window.
     *   
     *   The system code isn't required to do anything here; this is purely a
     *   notification to let the system code take care of any necessary
     *   internal bookkeeping.  For example, a window might want to clear its
     *   internal MORE mode counter here, if it uses one, to reflect the fact
     *   that we're starting over with fresh content.  
     */
    virtual void notify_clear_contents() = 0;

    /*
     *   Close the window.  Returns true if the window successfully
     *   closed, false if not; the window may not be closed, for example,
     *   if the user cancelled a "save changes" dialog.  If 'force' is true,
     *   the window should be closed without asking the user any questions
     *   (about saving work, for example).  This should always return true
     *   if 'force' is true.  
     */
    virtual int close_window(int force) = 0;

    /* get the current width of the HTML display area of the window */
    virtual long get_disp_width() = 0;

    /* get the current height of the HTML display area of the window */
    virtual long get_disp_height() = 0;

    /* get the number of pixels per inch */
    virtual long get_pix_per_inch() = 0;

    /*
     *   Get the bounds of a string rendered in the given font.  Returns a
     *   point, with x set to the width of the *string* as rendered, and y
     *   set to the height of the *font*.  The returned point's y value
     *   should give the total height of the text, including ascenders and
     *   descenders.  If 'ascent' is not null, it should be filled in with
     *   the portion of the height above the text baseline (i.e., the
     *   ascender size for the font).
     *   
     *   The width returned should indicate the *positioning* width of the
     *   text, which might not necessarily be the same as the bounding box of
     *   the glyphs contained in the text.  The difference is that the
     *   positioning width tells us where the next piece of text will go if
     *   we're drawing a string piecewise.  For example, suppose we have a
     *   string "ABCDEF", and we call draw_text() to render it at position
     *   (0,0).  Now suppose we have to redraw a portion of the string, say
     *   the "CDE" part, to adjust the display for a visual change that
     *   doesn't affect character positioning - the user selected the text
     *   with the mouse, say.  In this case, the portable code would call
     *   measure_text() on the part *up to* the part we're redrawing - "AB" -
     *   to figure out where to position the part we *are* redrawing - "CDE".
     *   It would add the width returned from measure_text("AB") to the
     *   original position (0,0) to figure out where to draw "CDE".  So, it's
     *   important that the width returned from measure_text("AB") properly
     *   reflects the character positioning distance.  On most modern systems
     *   with proportional typefaces, the positioning width of a character
     *   often differs from its rendering width, because a glyph can overhang
     *   its positioning area and overlap the previous and next glyph areas.
     *   System APIs usually therefore offer separate measurement functions
     *   for the bounding box (the overall area occupied by all pixels in a
     *   string) and the positioning box (the area used to calculate where
     *   adjacent glyphs should be drawn).
     *   
     *   Note that the heights returned - both the returned y value giving
     *   the overall box height, as well as the ascent height - must be the
     *   DESIGN HEIGHTS for the font, NOT the actual height of the specific
     *   set of characters in 'str'.  The returned height is thus the
     *   *maximum* of the individual heights of *all* of the characters in
     *   the font.  This DOESN'T mean that a port has to actually run through
     *   all of the possible characters in a font and measure each one to
     *   find the largest value - instead, you should be able to call a
     *   simple OS API that gets this information directly.  Virtually every
     *   GUI font engine stores the design metrics as part of its internal
     *   data about a font, and makes them available to apps via a function
     *   that retrieves "font metrics" or something of the like.
     *   
     *   (The 'ascent height' is the distance between the TOP of the box
     *   containing any character in the font and the BASELINE.  The baseline
     *   is defined by the font's designer, but in general it's the alignment
     *   point for the bottoms of the capital letters and of the minuscules
     *   that don't have tails (tails: g, j, p, q, y - the bits that drop
     *   below the baseline).  The reason the ascent height is important is
     *   that it tells us where the baseline is relative to the overall
     *   rectangle containing a character in the font, and the baseline is
     *   important because it's the reference point for aligning adjacent
     *   text from different fonts.)  
     */
    virtual CHtmlPoint measure_text(class CHtmlSysFont *font,
                                    const textchar_t *str, size_t len,
                                    int *ascent) = 0;

    /*
     *   Get the size of the debugger source window control icon.  This is
     *   a small icon in the left margin of a line of text displayed in a
     *   debugger source window; the icon is meant to show the current
     *   status of the line (current line, breakpoint set on line, etc).
     *   This routine is only needed if the platform implements the TADS
     *   debugger; provide an empty implementation if you're not
     *   implementing the debugger on your platform. 
     */
    virtual CHtmlPoint measure_dbgsrc_icon() = 0;

    /*
     *   Determine how much of a given string can fit in a given width,
     *   assuming that the text is all on one line.  This routine is an
     *   optimization that allows an operating system mechanism to be used
     *   directly when we need to figure out how much text we can put on a
     *   line.  If the operating system doesn't provide a native mechanism
     *   for determining this, this routine should scan the string using the
     *   OS's text measuring mechanism.  In such cases, an efficient means
     *   should be used, such as a binary search through the string for the
     *   appropriate length.  If the entire string fits in the given width,
     *   the length of the string should be returned.
     *   
     *   The return value is expressed in byte units, even for multi-byte
     *   character sets.  The system implementation must take care to handle
     *   multi-byte characters properly, if the system supports MBCS's.  
     */
    virtual size_t get_max_chars_in_width(class CHtmlSysFont *font,
                                          const textchar_t *str,
                                          size_t len, long wid) = 0;

    /*
     *   Draw text.  The text is to be drawn with its upper left corner
     *   at the given position.  If hilite is true, the text should be
     *   drawn with selection highlighting; otherwise, it should be drawn
     *   normally.  
     */
    virtual void draw_text(int hilite, long x, long y,
                           class CHtmlSysFont *font,
                           const textchar_t *str, size_t len) = 0;

    /*
     *   Draw typographical text space.  This is related to draw_text(), but
     *   rather than drawing text, this simply draws a space of the given
     *   pixel width in the given font.  The effect should be as though
     *   draw_text() were called with a string consisting of a number of
     *   spaces equal in total horizontal extent to the given pixel width
     *   (note, however, that the width need not be an integral multiple of
     *   the width of a single ordinary space, so it's not possible in all
     *   cases to obtain the identical effect with draw_text).  This can be
     *   used for purposes such as drawing typographical spaces (spaces of
     *   particular special sizes), or inserting extra space for flush
     *   justification.
     *   
     *   Note that all of the same attributes of regular text drawing should
     *   apply.  Highlighting should work the same as with ordinary text,
     *   and if the font would draw ordinary space characters with any sort
     *   of decoration (such as underlines, strikethroughs, or overbars),
     *   the same decorations should be applied here.
     *   
     *   The simplest and safest implementation of this function is as
     *   follows.  Measure the size of an ordinary space in the given font.
     *   Start at the given x,y coordinates.  With clipping to the full
     *   height of the font and the given width, draw a space character.
     *   Move right by the width of the space.  Repeat until past the
     *   desired drawing width.  This approach will ensure that the space
     *   drawn will have exactly the same appearance as ordinary spaces; the
     *   iteration will ensure enough space is filled, and the clipping will
     *   ensure that there is no drawing beyond the desired space.  
     */
    virtual void draw_text_space(int hilite, long x, long y,
                                 class CHtmlSysFont *font, long wid) = 0;

    /* draw a bullet */
    virtual void draw_bullet(int hilite, long x, long y,
                             class CHtmlSysFont *font,
                             HTML_SysWin_Bullet_t style) = 0;

    /*
     *   Draw a horizontal rule covering the given rectangle.  If shade is
     *   true, draw with 3D-style shading, otherwise draw as a solid bar.
     */
    virtual void draw_hrule(const CHtmlRect *pos, int shade) = 0;

    /*
     *   Draw a table or cell border.  The border should be drawn inside
     *   the given rectangle with the given width.  If cell is true, this
     *   is an individual cell border, otherwise it's the overall table's
     *   border.  
     */
    virtual void draw_table_border(const CHtmlRect *pos, int width,
                                   int cell) = 0;

    /*
     *   Draw a table or cell's background.  This should simply fill in
     *   the given area with the given color. 
     */
    virtual void draw_table_bkg(const CHtmlRect *pos,
                                HTML_color_t bgcolor) = 0;

    /*
     *   Draw a debugger source line icon.  This is used only for the TADS
     *   debugger; if this platform doesn't implement the debugger, this
     *   routine can have an empty implementation.
     *   
     *   'stat' gives a status code; this is a combination of the
     *   HTMLTDB_STAT_xxx codes (see tadshtml.h).  
     */
    virtual void draw_dbgsrc_icon(const CHtmlRect *pos,
                                  unsigned int stat) = 0;


    /*
     *   Do formatting -- run the formatter until it runs out of content
     *   to format.  This routine can be implemented simply to call the
     *   formatter's formatting routine until the formatter reports that
     *   it's out of tags to format; however, we provide this method in
     *   the window class so that the window can optimize redrawing.  This
     *   routine should return true if it did any display updating, false
     *   if not.  If show_status is true, it indicates that the operation
     *   may be lengthy, so a status line message, wait cursor, and/or
     *   other indication of the busy status should be displayed;
     *   otherwise the operation is expected to finish quickly enough that
     *   no such display is desired.  show_status should be set to true
     *   when reformatting after operations that will reformat the entire
     *   window, such as resizing the window.  If update_win is true, we
     *   should update the window as soon as possible (i.e., as soon as
     *   we've formatted enough text to redraw the window); otherwise, we
     *   should leave redrawing to the normal draw message handler.  If
     *   freeze_display is true, the formatter should be told not to
     *   update the window until it's done; this is used when the whole
     *   window needs to be reformatted, such as after a font preference
     *   change, to avoid making the user watch the window's entire
     *   contents scroll by as the reformatting is done.
     */
    virtual int do_formatting(int show_status, int update_win,
                              int freeze_display) = 0;


    /* -------------------------------------------------------------------- */
    /*
     *   Palette management.  These routines are needed only if we're
     *   using an index-based palette to display colors, and then only if
     *   applications must manage the palette.  For systems with high
     *   color resolution (generally greater than 8-bit color) or
     *   automatic color table management, these routines can have empty
     *   implementations.  
     */
    
    /*
     *   Recalculate the palette.  The formatter calls this routine when
     *   it adds a new image to the list of initial images, which are used
     *   to determine the system palette.  If the system is not using a
     *   palette, this routine doesn't need to do anything.
     */
    virtual void recalc_palette() = 0;

    /*
     *   Determine if we need to use a palette.  If this system is
     *   currently using an index-based palette to select display colors,
     *   this should return true, otherwise it should return false.  Some
     *   systems use an index-based palette when the display hardware is
     *   showing 8 bits of color resolution or less (notably Windows).  
     */
    virtual int get_use_palette() = 0;

    /* -------------------------------------------------------------------- */
    /*
     *   Font management.  The window always owns all of the font
     *   objects, which means that it is responsible for tracking them and
     *   deleting them when the window is destroyed.  Fonts that are given
     *   to a formatter must remain valid as long as the window is in
     *   existence.  Note that this doesn't mean that the font class can't
     *   internally release system resources, if it's necessary on a given
     *   system to minimize the number of system font resources in use
     *   simultaneously -- the portable code can never access the actual
     *   system resources directly, so the implementation of this
     *   interface can manage the system resources internally as
     *   appropriate.  
     */
    
    /* get the default font */
    virtual class CHtmlSysFont *get_default_font() = 0;

    /* 
     *   Get a font suitable for the given characteristics.  Note that this
     *   routine is responsible for checking the font descriptor for the
     *   following parameterized names, and providing the appropriate actual
     *   system font when one of the parameterized names is used (the names
     *   are case-insensitive):
     *   
     *   TADS-serif - a serifed font, usually proportional
     *.  TADS-sans - a san serif font, usually proportional
     *.  TADS-script - a script or cursive font, usually proportional
     *.  TADS-typewriter - a typewriter-style font, usually fixed-width
     *.  TADS-input - the font to use for player commands
     *   
     *   When possible, the player should be able to select the parameterized
     *   fonts in a "preferences" dialog or similar mechanism.  The purpose
     *   of the parameterized fonts is to allow the game to specify the style
     *   to use, while letting the player specify the exact details of the
     *   presentation.
     *   
     *   Note that, on some systems, parameterized fonts might let the user
     *   specify attributes in addition to the font face.  For example, on
     *   the Windows interpreter, "TADS-Input" lets the user specify the text
     *   color and set boldface and italics.  When these additional
     *   attributes are part of a parameterized font name, they should be
     *   applied ONLY when the 'face_set_explicitly' flag in the font_desc is
     *   set to TRUE - this ensures that the attributes can be overridden by
     *   nesting other attribute tags (<font color=red> or <i>, for example)
     *   within the <font> tag that explicitly selects the font face.
     *   
     *   Note on memory management: the portable code never deletes a font
     *   object obtained from this routine.  Instead, this routine is
     *   expected to keep a list of font objects previously allocated, and to
     *   reuse an existing object if there's one in the list that matches the
     *   descriptor.  This ensures that the lack of deletion won't leak
     *   memory: a given font object is never deleted, but only one font
     *   object will ever be created for a given descriptor.  
     */
    virtual class CHtmlSysFont
        *get_font(const class CHtmlFontDesc *font_desc) = 0;

    /* 
     *   Get the font for drawing bullets, given a text font.  This can
     *   simply return the same font if there isn't a separate bullet font
     *   or bullets are drawn independently of the font.  The current font
     *   is provided so that a suitable size can be selected in the bullet
     *   font.  
     */
    virtual class CHtmlSysFont
        *get_bullet_font(class CHtmlSysFont *current_font) = 0;

    /* -------------------------------------------------------------------- */
    /*
     *   Timers
     */

    /*
     *   Register a timer callback routine.  This routine should be called
     *   with the given context data as its argument periodically.  If
     *   possible, the routine should be called about once per second, but
     *   the precise interval isn't important; all that's important is to
     *   call the function every so often so that the function can check
     *   for pending work.  Since the frequency of the callback invocation
     *   is not tightly specified, the callback must check the current
     *   time if it's time-sensitive.
     *   
     *   The callback should not be invoked via an interrupt or in a
     *   separate thread; instead, it should be invoked in the course of
     *   the window's normal event message dispatching mechanism.
     *   
     *   Note that any number of timer functions may be simultaneously
     *   registered.  The order in which such functions are called is
     *   unspecified.  
     */
    virtual void register_timer_func(void (*timer_func)(void *),
                                     void *func_ctx) = 0;

    /*
     *   Remove an timer callback function previously registered.  
     */
    virtual void unregister_timer_func(void (*timer_func)(void *),
                                       void *func_ctx) = 0;

    /*
     *   Create a timer object that calls a given callback function when the
     *   timer event occurs.  This doesn't register a timer, but merely
     *   creates a timer object that can be used in set_timer().
     *   
     *   Returns a CHtmlSysTimer object that can be used to unregister the
     *   timer.  
     */
    virtual class CHtmlSysTimer *create_timer(void (*timer_func)(void *),
                                              void *func_ctx) = 0;


    /*
     *   Set a timer, previously created with create_timer(), to the given
     *   interval in milliseconds.  If 'repeat' is true, we'll invoke the
     *   callback associated with the timer repeatedly at the given interval;
     *   otherwise, we'll invoke the callback just once and then make the
     *   timer inactive. 
     */
    virtual void set_timer(class CHtmlSysTimer *timer, long interval_ms,
                           int repeat) = 0;

    /*
     *   Cancel a timer. 
     */
    virtual void cancel_timer(class CHtmlSysTimer *timer) = 0;
    
    /*
     *   Delete a timer previously created with register_timer_func_ms().  If
     *   the timer is currently active, it is cancelled.  
     */
    virtual void delete_timer(class CHtmlSysTimer *timer) = 0;


    /* -------------------------------------------------------------------- */
    /*
     *   General HTML operations 
     */

    /*
     *   Adjust the horizontal scrollbar.  The formatter calls this whenever
     *   a new line is formatted that exceeds the maximum line width so far.
     *   This routine should adjust the horizontal scrollbar accordingly -
     *   that is, it should update the range (min/max) of the OS-level
     *   scrollbar control to match the new document width.
     *   
     *   Note that the routine should by default NOT perform any horizonal
     *   scrolling here - it should simply update the min/max RANGE of the
     *   scrollbar and leave the scrolling position unchanged.  However, if
     *   the window is a banner window with the style flag
     *   OS_BANNER_STYLE_AUTO_HSCROLL set (via create_banner_window() or
     *   set_banner_info()), then this routine should immediately scroll the
     *   window horizontally to bring the right edge of the document into
     *   view; the window should be invalidated and/or redrawn as needed, and
     *   the scrollbar's thumb position should be updated accordingly.  
     */
    virtual void fmt_adjust_hscroll() = 0;

    /*
     *   Adjust the vertical scrollbar.  The formatter calls this whenever a
     *   new line is added or the document otherwise grows vertically.  This
     *   routine should adjust the min/max range of the vertical scrollbar to
     *   match the new document height.
     *   
     *   Note that this routine should normally NOT perform any vertical
     *   scrolling - it should simply update the RANGE of the min/max
     *   scrollbar and leave the current scrolling position unchanged.
     *   However, if the window is a banner window with the style flag
     *   OS_BANNER_STYLE_AUTO_VSCROLL set (via create_banner_window() or
     *   set_banner_info()), then this routine should immediately scroll the
     *   window vertically to bring the bottom edge of the document into
     *   view; the window should be invalidated and/or redrawn as needed, and
     *   the scrollbar's thumb position should be updated accordingly.
     *   
     *   MORE MODE: We leave it up to the port code to determine how to
     *   handle MORE mode, if such a thing exists locally.  In a regular
     *   "main" window, or in a banner window with the style flag
     *   OS_BANNER_STYLE_MOREMODE set, the port should implement MORE mode
     *   according to local conventions.  One possible implementation is to
     *   do nothing special: since we presumably are showing the text in a
     *   standard GUI window with a scrollbar, any text that spills beyond
     *   the vertical extent of the window will simply be scrolled off the
     *   bottom, and we can leave it up to the user to manually use the
     *   scrollbar to see the text below the bottom of the window.  
     *   
     *   In most cases, though, it's best to simulate the behavior of the
     *   Unix "more" program, since (a) this is much more convenient for
     *   users, and (b) it's what most users are accustomed to in a
     *   terminal-style interface like ours.  Here's roughly how this works.
     *   Whenever fmt_adjust_vscroll() notifies the window that the document
     *   has grown vertically beyond the current vertical extent of the
     *   window, the window sets an internal flag saying "more mode is
     *   pending."  Whenever the program makes an input call (get_input(),
     *   get_input_timeout(), etc), the window checks the "more mode pending"
     *   flag, and if set, clears that flag and sets another one saying "more
     *   mode is active."  In the input routines, as long as the "more mode"
     *   flag is set, we treat keyboard input specially: the SPACE key
     *   scrolls down by a page, the RETURN key scrolls down by a "line"
     *   (which is an essentially arbitrary unit, since we can have a mixture
     *   of text heights in the window - the design height of the default or
     *   current font is usually a good choice), the up/down arrow keys
     *   scroll by a line one way or the other; assign other keys according
     *   to local conventions or your preferences, but generally ignore keys
     *   to which you haven't assigned a special more-mode meaning.  When in
     *   more mode, if at any time the vertical scroll position becomes such
     *   that the bottom of the document is in view, cancel more mode and
     *   switch to ordinary input mode.  In ordinary input mode, you'd
     *   normally use a different scrolling behavior: if the input caret
     *   isn't visible, and the user presses any key that affects the input,
     *   immediately jump directly to a scrolling position that brings the
     *   caret into view.  This allows the user to scroll up to look at old
     *   text in the transcript, but then immediately jump back to the
     *   command line just by starting to type some input.
     *   
     *   We leave all of this up to the port code, though, because we want to
     *   give each port maximum flexibility in applying local customs.  Some
     *   ports might not even want a MORE mode at all, and some might use
     *   different key mappings or different overall behaviors.  Some ports
     *   might provide a visual indication that MORE mode is active
     *   (something like the "[More]" prompt that the Unix "more" command and
     *   the TADS text-only interpreters display), while some might be
     *   content to rely on the scrollbars as a sufficient visual cue.  The
     *   Windows interpreter uses something like the traditional "[More]"
     *   prompt, but it has a couple of user-configurable options for how to
     *   display it: it can be shown in the status bar along the bottom of
     *   the window frame, or it can be displayed as an overlay within the
     *   document area of the window itself, superimposed over the document's
     *   own contents at the bottom of the window.  (The status line approach
     *   is a lot easier to implement.)  
     */
    virtual void fmt_adjust_vscroll() = 0;

    /*
     *   Invalidate the window area given by the document coordinates (i.e.,
     *   before taking into account any scrolling).
     *   
     *   Note that the area->right and area->bottom coordinates can be passed
     *   in as HTMLSYSWIN_MAX_RIGHT and/or HTMLSYSWIN_MAX_BOTTOM, defined
     *   above - these indicate that you should invalidate all the way to the
     *   right or bottom edge of the window.
     */
    virtual void inval_doc_coords(const class CHtmlRect *area) = 0;

    /*
     *   Receive notification that the formatter associated with this
     *   window is about to reset the display list, deleting all existing
     *   display list items.  Any display list items that the window is
     *   referencing should be forgotten.  It's particularly likely that
     *   the window is keeping track of a link display item, such as the
     *   link that the mouse is hovering over.  The window should simply
     *   forget about any such display list items at this time.  
     */
    virtual void advise_clearing_disp_list() = 0;

    /*
     *   Scroll a document position into view.  This should try to scroll
     *   the window so that the given coordinates appear at the middle of
     *   the window.  If possible, the entire rectangle should be within
     *   the window.  
     */
    virtual void scroll_to_doc_coords(const class CHtmlRect *pos) = 0;

    /*
     *   Get the current scrolling position in document coordinates.
     *   Returns a value suitable for passing to scroll_to_doc_coords to
     *   restore this same scrolling position at a later time.  
     */
    virtual void get_scroll_doc_coords(class CHtmlRect *pos) = 0;

    /* set the window's title */
    virtual void set_window_title(const textchar_t *title) = 0;

    /*
     *   Set the background color, text color, and link colors.  If
     *   use_default for a particular color is true, we'll ignore the
     *   provided color and use the default color instead.  These calls are
     *   used to advise the system window implementation of the color
     *   settings made programmatically, such as through the <BODY> tag.
     *   
     *   The "background" color is the color used to fill the background of
     *   the window, where no text or graphics are explicitly drawn.
     *   
     *   The "text" color is the default color for ordinary text (i.e., text
     *   that isn't hyperlinked or given an explicit font color via <FONT
     *   COLOR=xxx> or the like).
     *   
     *   The "input" color is the color to use for input text.
     *   
     *   The "link" color is the color for hyperlinked text - that is, text
     *   inside an <A HREF> tag.
     *   
     *   The "vlink" color is the "visited" hyperlink text color.  We include
     *   this for completeness, but currently we don't use it, since we don't
     *   really have a sense of visited vs unvisited links in the same way
     *   that a browser would.
     *   
     *   The "alink" color is the color for "active" hyperlink text.  This is
     *   the color for hyperlink text when the link is being clicked by the
     *   mouse; that is, when the user has moved the mouse over the hyperlink
     *   and then clicked and held down the button.  This is the color to use
     *   as long as the button is being held down.
     *   
     *   The "hlink" color is the "hover" hyperlink text color.  This is the
     *   color for when the mouse is hovering over the hyperlink, but the
     *   mouse button isn't being held down.
     *   
     *   Note that the system implementation is free to ignore all of these
     *   color settings, or to use them only if user preferences allow, or
     *   under any other conditions suitable for the local system.  On most
     *   systems, there are four possible color sources for any given text
     *   fragment: user preferences; set_html_xxx_color() settings; explicit
     *   <FONT> and other settings; and OS defaults.  The interpreter then
     *   implements a hierarchy to determine which of these to use.  The
     *   exact hierarchy is up to the interpreter, but it's usually like
     *   this:
     *   
     *   - If the user preferences allow the user to select an "override"
     *   option, and the user selects this option, use the user preference
     *   color setting applicable to a given text fragment.  (The user
     *   preferences might allow the user to select each of these color types
     *   individually - text, background, input, alink, vlink, etc - in which
     *   case the interpreter should pick the right one for the context.  If
     *   the preferences don't distinguish color by context, just use the
     *   single color setting.)
     *   
     *   - If "override" isn't selected (or isn't offered), and there's a
     *   <FONT COLOR=xxx> setting for a given text fragment, use that.
     *   
     *   - Otherwise, if there's been a call to set_html_xxx_color() for the
     *   given context with use_default=FALSE, use that color.
     *   
     *   - If there's been no call to set_html_xxx_color() for the given
     *   context, or there's been a call with use_default=TRUE, AND there's a
     *   user preference setting applicable to the context, use the user
     *   preference setting.
     *   
     *   - Otherwise, use the system defaults.  
     */
    virtual void set_html_bg_color(HTML_color_t color, int use_default) = 0;
    virtual void set_html_text_color(HTML_color_t color, int use_default) = 0;
    virtual void set_html_input_color(HTML_color_t clr, int use_default) = 0;
    virtual void set_html_link_colors(HTML_color_t link_color,
                                      int link_use_default,
                                      HTML_color_t vlink_color,
                                      int vlink_use_default,
                                      HTML_color_t alink_color,
                                      int alink_use_default,
                                      HTML_color_t hlink_color,
                                      int hlink_use_default) = 0;

    /*
     *   Map a special parameterized color value to the corresponding RGB
     *   value.  The parameterized color values are the HTML_COLOR_xxx
     *   values defined in tadshtml.h.  The system should use an
     *   appropriate mechanism for determining the colors; the system may
     *   use fixed values, or may choose colors appropriate for the
     *   current display device, or can let the user control these
     *   settings through a preferences mechanism. 
     */
    virtual HTML_color_t map_system_color(HTML_color_t color) = 0;

    /* 
     *   Get the link colors.  The link colors are stored in the window
     *   object, so that the system-specific code can save, use, and
     *   customize user preferences as needed.  The colors are normal (link),
     *   activated/clicked (alink), visited (vlink), and hovering (hlink).
     *   These are the colors that are used to draw hyperlinked text in the
     *   respective states.
     *   
     *   Note that these should return the colors appropriate for the current
     *   system-specific preference settings.  For example, if the user
     *   preferences the user to select whether or not links are highlighted
     *   on "hovering" with the mouse cursor, and hover highlighting is
     *   currently turned off, then the hlink color should return the same as
     *   the normal link color.  
     */
    virtual HTML_color_t get_html_link_color() const = 0;
    virtual HTML_color_t get_html_alink_color() const = 0;
    virtual HTML_color_t get_html_vlink_color() const = 0;
    virtual HTML_color_t get_html_hlink_color() const = 0;

    /* determine if textual links should be drawn underlined */
    virtual int get_html_link_underline() const = 0;

    /*
     *   Determine if links are to be shown.  This should be offered as a
     *   user-settable preference if possible.  Returns true if links
     *   should be shown as links, false if not.  If links are not to be
     *   shown as links, we'll draw links as ordinary text.  
     */
    virtual int get_html_show_links() const = 0;

    /*
     *   Determine if graphics can be displayed.  On systems where
     *   graphics can be displayed, this should be offered as a
     *   user-settable preference if possible.  On systems where graphics
     *   can't be displayed at all, this should always return false.  If
     *   this returns false, we'll render graphics using a suitable
     *   textual substitute if possible, such as the ALT attribute of an
     *   IMG tag, or simply leave any graphics out entirely.  If this
     *   returns true, we'll render graphics as normal.  
     */
    virtual int get_html_show_graphics() const = 0;

    /*
     *   Set the background image.  The image is an ordinary HTML resource
     *   cache entry, whose get_image() method will return a CHtmlSysImage
     *   object (or null if there's not a valid object associated with the
     *   cache entry).
     *   
     *   In graphical implementations, the background image is normally drawn
     *   as the background of the document, tiled to fill out the window
     *   space.  The image should scroll with the document.  As the document
     *   scrolls down, the image is normally repeatedly tiled vertically to
     *   fill in all displayed space.  The image is normally drawn out to the
     *   visible edges of the window; no empty margin space is normally shown
     *   between the interior edges of the window's frame and the image.  
     */
    virtual void set_html_bg_image(class CHtmlResCacheObject *image) = 0;

    /*
     *   Invalidate a portion of the background image.  This is called when
     *   the background image is animated to trigger redrawing of the
     *   portions of the image changed from one animation frame to the next.
     *   
     *   The coordinates given are relative to the upper left corner of the
     *   background image itself.  These are not in document or window
     *   coordinates - they're in *image* coordinates.  The portable caller
     *   can't make any assumptions about the placement of the background
     *   image relative to the window or document coordinate systems, so we
     *   must rely on the window itself to figure out what needs to be
     *   invalidated within the image.
     *   
     *   It's important to note that if the image is tiled, so that it's
     *   drawn multiple times in the window, then *each visible tile* must be
     *   invalidated here.  If all of the visible tiles are not invalidated,
     *   they would incorrectly remain un-updated - but they'd draw in their
     *   new form eventually when the window is next updated by virtue of
     *   having a portion uncovered.  Therefore, it's crucial that this
     *   routine properly invalidate all visible copies of the image.  
     */
    virtual void inval_html_bg_image(unsigned int x, unsigned int y,
                                     unsigned int wid, unsigned int ht) = 0;

    /*
     *   Set the size of this window as a banner.  A call to this routine
     *   should be ignored for a main window.
     *   
     *   Note that normally only one of the dimensions is actually used.  If
     *   this is a horizontal banner, normally only the height is meaningful,
     *   because horizontal banners are constrained to run across the entire
     *   width of the main window.  Similarly, only the width is meaningful
     *   for vertical banners.
     *   
     *   If use_height is false, it means that the height parameter value
     *   should be ignored and the current window height retained; likewise
     *   use_width.  
     */
    virtual void set_banner_size(
        long width, HTML_BannerWin_Units_t width_units, int use_width,
        long height, HTML_BannerWin_Units_t height_units, int use_height) = 0;

    /*
     *   Set alignment and style for this existing banner window.  A call to
     *   this routine should be ignored for a main window.
     *   
     *   'style' is a combination of OS_BANNER_STYLE_xxx flags, as defined
     *   in osifc.h (from tads 2).  
     */
    virtual void set_banner_info(HTML_BannerWin_Pos_t pos,
                                 unsigned long style) = 0;

    /*
     *   Get information on this banner window.  '*pos' is filled in with the
     *   banner's alignment, and '*style' is filed in with a combination of
     *   OS_BANNER_STYLE_xxx flags describing the styles actually provided by
     *   the window.
     *   
     *   Note that the style flags returned might not be the same ones as
     *   originally requested in CHtmlSysFrame::create_banner_window(),
     *   because we might not support some styles that the caller requested,
     *   and we might unconditionally use some styles not requested.  The
     *   style flags returned here describe the *actual* window, not the
     *   requested one.  
     */
    virtual void get_banner_info(HTML_BannerWin_Pos_t *pos,
                                 unsigned long *style) = 0;


protected:
    /* formatter for the window */
    class CHtmlFormatter *formatter_;
};

/* ------------------------------------------------------------------------ */
/*
 *   Timer.  This is an opaque object for the system window implementation's
 *   use.
 */
class CHtmlSysTimer
{
public:
    CHtmlSysTimer(void (*func)(void *), void *ctx)
    {
        /* remember the function and its context */
        func_ = func;
        func_ctx_ = ctx;

        /* presume we won't repeat */
        repeat_ = FALSE;

        /* we're not yet active */
        active_ = FALSE;
    }

    /* set repeat mode */
    void set_repeating(int repeat) { repeat_ = repeat; }

    /* am I a repeating timer? */
    int is_repeating() const { return repeat_; }

    /* invoke my function */
    void invoke_callback() { (*func_)(func_ctx_); }

    /* get/set active status */
    int is_active() const { return active_; }
    void set_active(int active) { active_ = active; }

protected:
    /* function (and its context) to call upon timer expiration */
    void (*func_)(void *ctx);
    void *func_ctx_;

    /* flag: the timer is active */
    int active_;

    /* flag: the timer is to be repeated (as opposed to called just once) */
    int repeat_;
};

/* ------------------------------------------------------------------------ */
/*
 *   System resource object interface.  This is the base type for resources,
 *   such as sounds and images.  This interface is subclassed to provide the
 *   specific resource types; the subclassed interfaces must in turn be
 *   implemented by the non-portable system-dependent code.  This interface
 *   itself is not to be implemented by system code -- only the final
 *   subclasses of this interface need to be implemented.
 *   
 *   We generally deal with resources at a generic level, since we can't tell
 *   the type of an image until we've loaded it.  However, when we use a
 *   resource, we generally need to downcast the resource to a particular
 *   "branch" of the resource taxonomy based on context; for example, when
 *   we're attempting to draw a resource loaded from an <IMG> tag, we'll need
 *   a CHtmlSysImage object.  To accommodate the need to downcast resources
 *   with type safety, this interface provides virtuals that cast to the
 *   major resource type branches.  Note that it should never be necessary to
 *   downcast beyond the immediate subclasses of this interface, since any
 *   further subclasses should be invisible to client code (for example,
 *   CHtmlSysImage is sufficiently polymorphic that client code can do
 *   everything it needs to do to an image without having to worry about
 *   whether it's a PNG or JPEG image).  The downcast methods return null for
 *   resources that are not of the requested type.  
 */
class CHtmlSysResource
{
public:
    virtual ~CHtmlSysResource() { }

    /* get the resource type */
    virtual HTML_res_type_t get_res_type() const = 0;
    
    /* downcasts to major resource types */
    virtual class CHtmlSysImage *cast_image() { return 0; }
    virtual class CHtmlSysSound *cast_sound() { return 0; }

    /* 
     *   Can the resource be kept in the resource cache and reused?  This is
     *   true for stateless resources, such as static pictures, and false for
     *   stateful resources, such as animated images (MNG's, for example).
     *   Stateful resources cannot be reused if they appear multiple times in
     *   a document because each copy in the document must have a separate
     *   resource instance to manage its state.  
     */
    virtual int is_cacheable() const { return TRUE; }
};

/* ------------------------------------------------------------------------ */
/* 
 *   drawing modes - these specify how to draw an image into a rectangle
 *   whose size differs from the size of the image 
 */
enum htmlimg_draw_mode_t
{
    /* 
     *   Draw the image at its exact size, aligning the upper left corner of
     *   the image at the upper left corner of the drawing rectangle.  Clip
     *   the image at the right and bottom to fit the drawing area if the
     *   image is too big.  Leave any excess right and bottom margin
     *   unaffected if the image is smaller than the drawing area.  
     */
    HTMLIMG_DRAW_CLIP,

    /*
     *   Stretch the image to fit the drawing area, by expanding or shrinking
     *   the image as needed.  The image should be scaled as visually
     *   smoothly as possible.  
     */
    HTMLIMG_DRAW_STRETCH,

    /*
     *   Tile the image to fit the bounding area, starting at the upper left
     *   corner and drawing it repeatedly without any space between adjacent
     *   tiles.  If the image is too large to fit the area, clip it to fit,
     *   aligning the upper left corner of the image at the upper left
     *   corner of the target rectangle.  
     */
    HTMLIMG_DRAW_TILE
};

/* ------------------------------------------------------------------------ */
/*
 *   System image object.  This type of object allows us to display an
 *   image.  This interface must be subclassed for each image type (JPEG,
 *   etc).  This interface is not to be implemented by system code; only
 *   the final subclasses that provide interfaces for the specific image
 *   types need to be implemented.  
 */
class CHtmlSysImage: public CHtmlSysResource
{
public:
    virtual ~CHtmlSysImage() { }

    /* this is an image - override the downcast method */
    CHtmlSysImage *cast_image() { return this; }

    /* cast to an animated image */
    virtual class CHtmlSysImageAnimated *cast_animated() { return 0; }

    /*
     *   Set the display site.  This is REQUIRED for animated images.  For
     *   non-animated images, this has no effect, but as a convenience, we
     *   define the method as a virtual in the base image class so that an
     *   image container can simply always set the site if it provides one.
     */
    virtual void set_display_site(class CHtmlSysImageDisplaySite *) { }

    /*
     *   Cancel playback.  If the image is animated, this should halt the
     *   animation.  This has no effect for static images.
     */
    virtual void cancel_playback() { }

    /*
     *   Pause/resume playback.  If the image is animated, this should pause
     *   playback until 'resume' is called.  This has no effect for static
     *   images.  
     */
    virtual void pause_playback() { }
    virtual void resume_playback() { }
    
    /* 
     *   Display the image at a given position in a given window.  The 'mode'
     *   argument indicates what to do if the size of the image doesn't
     *   exactly match the size of the rectangle we're drawing into: we can
     *   clip, stretch, or tile the image.  
     */
    virtual void draw_image(class CHtmlSysWin *win, class CHtmlRect *pos,
                            htmlimg_draw_mode_t mode) = 0;

    /* get the image's dimensions */
    virtual unsigned long get_width() const = 0;
    virtual unsigned long get_height() const = 0;

    /*
     *   Map the image's palette.  If 'foreground' is true, the image's
     *   palette should take over the system palette, if possible;
     *   otherwise, the image's palette should be mapped as well as
     *   possible into the existing system palette.  Returns true if
     *   anything changed in the system palette, false if not.  For
     *   systems that don't use palettes, this routine doesn't need to do
     *   anything.  
     */
    virtual int map_palette(class CHtmlSysWin *win, int foreground) = 0;
};

/*
 *   System JPEG image object. 
 */
class CHtmlSysImageJpeg: public CHtmlSysImage
{
public:
    virtual HTML_res_type_t get_res_type() const
        { return HTML_res_type_JPEG; }

    /*
     *   Create a new system-specific JPEG object, loading the JPEG data
     *   from the given seek offset in the given file.  Note that this is
     *   a static routine that must be implemented for this class in a
     *   system-specific module.  This routine should return a new
     *   instance of the correct subclass of this class for the current
     *   operating system.
     *   
     *   Note that 'filesize' is the size of the data starting at
     *   'seekpos' that the resource loader considers to be part of this
     *   resource; the actual file may be larger than this value, since
     *   other data may follow the resource in the file.
     *   
     *   'url' is provided for diagnostic purposes; it should be used in
     *   any error message that this routine generates (with
     *   oshtml_dbg_printf).  It can otherwise be ignored.
     *   
     *   The 'win' argument is provided so that the loader can check the
     *   current environment for any information necessary for loading the
     *   resource.  For example, the loader may want to call
     *   win->get_use_palette() to determine if the image's color map must
     *   be mapped to a palette.  
     */
    static CHtmlSysResource *create_jpeg(const class CHtmlUrl *url,
                                         const textchar_t *filename,
                                         unsigned long seekpos,
                                         unsigned long filesize,
                                         class CHtmlSysWin *win);
};

/*
 *   System PNG image object 
 */
class CHtmlSysImagePng: public CHtmlSysImage
{
public:
    virtual HTML_res_type_t get_res_type() const
        { return HTML_res_type_PNG; }

    /*
     *   Create a new system-specific PNG object, loading the PNG data
     *   from the given seek offset in the given file.  Note that this is
     *   a static routine that must be implemented for this class in a
     *   system-specific module.  This routine should return a new
     *   instance of the correct subclass of this class for the current
     *   operating system.
     *   
     *   Note that 'filesize' is the size of the data starting at
     *   'seekpos' that the resource loader considers to be part of this
     *   resource; the actual file may be larger than this value, since
     *   other data may follow the resource in the file.
     *   
     *   'url' is provided for diagnostic purposes; it should be used in
     *   any error message that this routine generates (with
     *   oshtml_dbg_printf).  It can otherwise be ignored.
     *   
     *   The 'win' argument is provided so that the loader can check the
     *   current environment for any information necessary for loading the
     *   resource.  For example, the loader may want to call
     *   win->get_use_palette() to determine if the image's color map must
     *   be mapped to a palette.  
     */
    static CHtmlSysResource *create_png(const class CHtmlUrl *url,
                                        const textchar_t *filename,
                                        unsigned long seekpos,
                                        unsigned long filesize,
                                        class CHtmlSysWin *win);
};

/*
 *   System Animated Image object.  This subclass of image is for animated
 *   image types; these objects require special interaction with their
 *   display site to manage timed playback.  
 */
class CHtmlSysImageAnimated: public CHtmlSysImage
{
public:
    /* cast to an animated image */
    virtual class CHtmlSysImageAnimated *cast_animated() { return this; }

    /* 
     *   Animated images are all non-shareable, because an animated image
     *   resource must keep track of state information (i.e., where it is in
     *   displaying the animation).  
     */
    virtual int is_cacheable() const { return FALSE; }

    /*
     *   Receive notification from the display site of a timer event.  The
     *   display site must call this method after a given delay has occurred
     *   after a request from the image made to the display site via the
     *   display site interface (CHtmlSysImageDisplaySite).  
     */
    virtual void notify_timer() = 0;

    /*
     *   Receive notification from the image helper (if we use one) that the
     *   image has changed.  This doesn't necessarily need to be implemented:
     *   it's only needed if the system implementation of this class uses a
     *   portable helper object, and the helper object can change the image
     *   in response to a timer, and the system implementation of this class
     *   has its own separate buffer that it must refresh from the helper
     *   object in such cases. 
     */
    virtual void notify_image_change(int x, int y, int wid, int ht) = 0;
};

/*
 *   System MNG image object 
 */
class CHtmlSysImageMng: public CHtmlSysImageAnimated
{
public:
    virtual HTML_res_type_t get_res_type() const
        { return HTML_res_type_MNG; }

    /*
     *   Create a new system-specific MNG object, loading the MNG data from
     *   the given seek offset in the given file.  Note that this is a static
     *   routine that must be implemented for this class in a system-specific
     *   module.  This routine should return a new instance of the correct
     *   subclass of this class for the current operating system.
     *   
     *   Note that 'filesize' is the size of the data starting at 'seekpos'
     *   that the resource loader considers to be part of this resource; the
     *   actual file may be larger than this value, since other data may
     *   follow the resource in the file.
     *   
     *   'url' is provided for diagnostic purposes; it should be used in any
     *   error message that this routine generates (with oshtml_dbg_printf).
     *   It can otherwise be ignored.
     *   
     *   The 'win' argument is provided so that the loader can check the
     *   current environment for any information necessary for loading the
     *   resource.
     */
    static CHtmlSysResource *create_mng(const class CHtmlUrl *url,
                                        const textchar_t *filename,
                                        unsigned long seekpos,
                                        unsigned long filesize,
                                        class CHtmlSysWin *win);
};

/* ------------------------------------------------------------------------ */
/*
 *   Display site interface.  Unlike static images, where the display site
 *   runs the show and always calls the image to cause a display, animated
 *   images are active, so they have to be able to notify the display site
 *   whenever an animation event occurs.  This interface provides a means for
 *   an animated image object to notify the window (or object within a
 *   window) where the animation is displayed when events occur.
 *   
 *   Since this is an abstract interface, animated images not bound to any
 *   particular type of display container; any class that wants to display an
 *   animated image resource can implement this interface.  
 */
class CHtmlSysImageDisplaySite
{
public:
    virtual ~CHtmlSysImageDisplaySite() {}

    /*
     *   Invalidate a portion of the display site: the MNG image's contents
     *   have changed (due to animation playback) within the invalidated
     *   area, so the area should be redisplayed as soon as possible.  The
     *   area to be invalidated is given relative to the upper left corner of
     *   the display site.  
     */
    virtual void dispsite_inval(unsigned int x, unsigned int y,
                                unsigned int width, unsigned int height) = 0;

    /*
     *   Set a timer event.  The site must call the image object's
     *   notify_timer() method as soon as possible after the given real-time
     *   interval (in milliseconds) elapses.
     *   
     *   We will request only one timer at any given time.  If there's still
     *   a timer request outstanding when we make a new timer request, the
     *   new request should REPLACE the old request.  
     */
    virtual void dispsite_set_timer(unsigned long delay_ms,
                                    class CHtmlSysImageAnimated *image) = 0;

    /*
     *   Cancel the timer.  Any pending timer request should be cancelled.
     *   No further calls to notify_timer() in the image object are desired.
     */
    virtual void dispsite_cancel_timer(class CHtmlSysImageAnimated *) = 0;
};


/* ------------------------------------------------------------------------ */
/*
 *   System sound object.  This type of object allows us to play back a
 *   sound.  This interface must be subclasses for each sound type (MIDI,
 *   WAV).  This interface is not to be implemented by system code; only
 *   the final subclasses that provide interfaces for the specific sound
 *   types need to be implemented.  
 */
class CHtmlSysSound: public CHtmlSysResource
{
public:
    virtual ~CHtmlSysSound() { }

    /* this is a sound - override the downcast method */
    CHtmlSysSound *cast_sound() { return this; }

    /* 
     *   sounds are not cacheable, because sound resources must keep track of
     *   where they are in the playback 
     */
    virtual int is_cacheable() const { return FALSE; }

    /*
     *   Start playing the sound.  When the sound is finished, invoke the
     *   given callback (which can be null, to indicate that no callback is
     *   to be invoked) with the given context.  The 'repeat_count' parameter
     *   to the callback indicates how many times the sound has been played.
     *   
     *   'repeat' is the number of times to play back the sound; 0 indicates
     *   that the sound should be played forever (or until cancel_sound is
     *   called, whichever comes first).  The player can ignore the repeat
     *   count, however (this is to simplify the implementation when it's not
     *   convenient or useful to implement repetition in the player itself).
     *   If the repeat count is obeyed, the callback will be invoked after
     *   all iterations have been performed, and will indicate the number of
     *   iterations completed.  If the repeat count is ignored, the callback
     *   will be invoked after the single iteration we'll perform and will
     *   indicate that only one iteration has been played.  In this case,
     *   caller can simply requeue the sound (if still desired) with the next
     *   lower repeat count.
     *   
     *   'vol' is the base playback volume for the track, in the range
     *   0..100, where 0 is silence and 100 is unattenuated (i.e., play the
     *   track at the full volume level of the recorded data).  Values
     *   outside this range are invalid and should be pegged to the range
     *   (i.e., treat anything below 0 as 0, and anything over 100 as 100).
     *   This volume level is NOT a master volume for the whole computer or
     *   whole application - it shouldn't affect any other sound levels in
     *   the system or be used to adjust the physical speaker volume.  This
     *   parameter instead simply sets the relative playback volume of this
     *   track.  A volume level of 0 means the track should effectively be
     *   muted; 100 means it should be played back unattenuated, at the full
     *   native volume recorded in the sound file.  Values between 0 and 100
     *   should be perceptually linear volume levels, akin to adjusting a
     *   speaker volume knob between minimum and maximum volume.  If the
     *   local system can't implement per-track relative volume control,
     *   simply ignore this parameter and play back the track at its native
     *   volume level.  (Although you might still want to treat volume 0 as
     *   mute in this case, if possible.)
     *   
     *   'fade_in' and 'fade_out' are the start-of-track and end-of-track
     *   fade times, in milliseconds.  Zero means that the track should
     *   start/end at full volume.  If a non-zero fade time is given, it
     *   means that the volume on the track should fade in or out over the
     *   given interval - fade_in is the interval for fading in at the start
     *   of the track, and fade_out is the interval for fading out at the end
     *   of the track.  This is a "best effort" feature - if fades can't be
     *   implemented on the platform, or can't be implemented for certain
     *   audio formats, simply ignore the fade parameters and start/stop at
     *   full volume.
     *   
     *   'crossfade' indicates whether the end-of-track fade-out should be a
     *   cross-fade or a regular fade.  True means cross-fade: as soon as the
     *   fade-out begins, call the 'done' callback, which will tell the queue
     *   manager that it can start playing the next track in the queue
     *   immediately, even while the fade is proceeding.  False means a
     *   regular fade-out: the 'done' callback should be invoked after the
     *   track is fully finished (including the fade), as normal.  If
     *   cross-fades can't be implemented on the platform, ignore this
     *   parameter and do a normal fade-out.
     *   
     *   Note that 'crossfade' doesn't affect the fade-in.  Any cross-fade at
     *   fade-in is controlled by the *outgoing* track - it's up to the
     *   previous track to determine when to call the 'done' callback to
     *   enable to next queued track to begin playing.
     *   
     *   When the repeat count is 0 or >1, the fade-in should be applied only
     *   to the first iteration, and the fade-out should be applied only to
     *   the last iteration.  There should be no fade between repeated
     *   iterations of the same track.
     *   
     *   Returns zero on success, non-zero on error.  If a non-zero value is
     *   returned, the callback is NOT invoked.
     *   
     *   The URL is provided for diagnostic purposes.  If the routine
     *   encounters an error and wants to provide details, it can use the URL
     *   in a debugging message to indicate the object that caused the error.
     */
    virtual int play_sound(class CHtmlSysWin *win,
                           void (*done_func)(void *, int repeat_count),
                           void *done_func_ctx, int repeat,
                           const textchar_t *url, int vol,
                           long fade_in, long fade_out, int crossfade) = 0;

    /*
     *   Add an end-of-track cross-fade to this track, if it's currently
     *   playing.  This has no effect if the track isn't already playing or
     *   has finished playing.
     *   
     *   'ms' is the duration of the fade, in milliseconds.  The fade should
     *   begin 'ms' milliseconds before the end of the track; the volume
     *   level should be gradually decreased over that interval from the
     *   normal playback volume to silence.
     *   
     *   The point of this routine is to allow an *incoming* track to ask for
     *   a crossfade as it starts.  The request can't be made as part of the
     *   play_sound() on the incoming track - not just because play_sound()
     *   doesn't offer a way to do this, but because there's no way for
     *   play_sound() to offer a way to do this even if it wanted to.  A
     *   cross-fade is always a feature of an outgoing track, because the way
     *   you accomplish a cross-fade is to have the outgoing track signal
     *   that it's finished (by calling the 'done' callback) at the start of
     *   its fade-out, to let the next queued track begin playing.  So, the
     *   way to handle an incoming cross-fade is to queue the incoming sound,
     *   and call this routine on the immediately preceding sound in the
     *   queue.
     *   
     *   Note that there might already be a scheduled fade-out on this track,
     *   because play_sound() can request a cross-fade as well (and because
     *   this routine could conceivably be called more than once for a single
     *   track).  If there are multiple fade-outs for the same track, the
     *   recommended handling is to combine them by always setting the volume
     *   level to the MININUM of the volume levels from the competing fades.
     *   This will ensure a monotonic fade - the volume level won't jump
     *   around, because it will only be able to decrease over time.  The
     *   volume level might not decrease in a simple straight line (it could
     *   be a series of linear segments, because the different fade slopes
     *   might intersect), but this really shouldn't matter perceptually;
     *   most listeners probably won't even notice that the fade isn't
     *   perfectly linear as long as it's monotonic.
     *   
     *   If cross-fades can't be implemented on this platform, or it's not
     *   possible to add a cross-fade to a track already being played, simply
     *   ignore calls to this routine.  
     */
    virtual void add_crossfade(class CHtmlSysWin *win, long ms) = 0;

    /*
     *   Cancel the sound.
     *   
     *   If 'sync' is true, the sound must be canceled, and the callback
     *   invoked, BEFORE this routine returns.  If 'sync' is false, this
     *   routine MAY return before the sound has actually stopped, as long as
     *   the sound is scheduled for cancellation very shortly.  (Of course,
     *   the callback should still be invoked in this case, as soon as the
     *   sound actually stops playing.)
     *   
     *   (The point os 'sync' is to allow for situations where the playback
     *   is handled by a background thread, hardware sound card buffers, or
     *   another asynchronous player mechanism.  For example, if the playback
     *   is being handled by a background thread, when 'sync' is false this
     *   routine could simply post a message to the playback thread telling
     *   it to stop, then immediately return without waiting for the message
     *   to be received.  Playback might continue in this case for a few
     *   milliseconds, until the OS gets around to scheduling the playback
     *   thread for its next chance to run.  This type of approach helps keep
     *   the UI responsive by avoiding blocking waits for playback to catch
     *   up with UI activity.)
     *   
     *   If 'sync' is true OR 'fade_out_ms' is zero, the cancellation is
     *   abrupt - the sound should simply be cut off in mid-stream.  If a
     *   callback was registered when the sound was started, the callback
     *   should be invoked as though the track had reached its normal ending,
     *   as soon as the playback actually terminates.
     *   
     *   If 'fade_out_ms' is non-zero, it specifies a number of milliseconds
     *   over which the sound should gradually fade out.  The fade should
     *   start immediately; the volume of the playback for this sound (and
     *   ONLY this sound) should be reduced gradually from full volume to
     *   silence, over the course of the specified interval.
     *   
     *   If a non-zero fade interval is specified, the 'fade_in_bg' flag
     *   specifies how the callback function (if one was specified in
     *   play_sound) should be invoked.  If 'fade_in_bg' is true, it means
     *   that the callback should be invoked immediately, before the function
     *   returns.  Otherwise, the callback should be invoked as soon as the
     *   fade is finished.
     *   
     *   Note that regardless of the 'fade_in_bg' setting, the fade itself
     *   should happen "in the background" with respect to the UI, if
     *   possible.  That is, this routine should schedule the fade to begin
     *   immediately, and should then immediately return so that the UI
     *   remains responsive during the fade interval.  This routine should
     *   NOT wait until after the fade is finished to return to its caller.
     *   
     *   (The point of setting 'fade_in_bg' to true is to allow for
     *   cross-fade effects: since the callback is invoked immediately, the
     *   next sound in the same queue ("layer") will be able to start playing
     *   immediately, so the new sound will play concurrently while the old
     *   sound fades out.  Using a fade-in with the new sound will
     *   effectively cross-fade the two sounds, creating a smooth transition
     *   between adjacent tracks.)
     *   
     *   Synchronous mode and fade mode are mutually exclusive.  If 'sync' is
     *   true, the routine should simply ignore the fade parameters.
     *   
     *   Note that the fade setting specified here is independent of the
     *   end-of-track fade specified in play_sound().  The fade specified in
     *   play_sound() only applies when the track plays all the way through
     *   to the end.  The cancel_sound() fade, in contrast, specifies what
     *   should happen immediately at the time of the cancellation, so it
     *   effectively supersedes any play_sound() fade.  In particular, if
     *   'fade_out_ms' in cancel_sound() is zero, the sound should be stopped
     *   abruptly with no fade, EVEN IF play_sound() specified a fade-out.
     *   
     *   HANDLING PLATFORM LIMITATIONS:
     *   
     *   1. If the local platform can't support concurrent playback of two or
     *   more sounds, this routine should simply ignore fade_in_bg and always
     *   do "foreground" fades - that is, still process the fade in the
     *   background with respect to the UI, but don't invoke the callback
     *   until after the fade is finished.  Waiting to invoke the callback
     *   will ensure that the queue manager doesn't attempt to start playing
     *   another sound until the current sound is terminated.  This approach
     *   will still create a relatively smooth transition effect between
     *   adjacent tracks by doing a fade-out and then a fade-in - not exactly
     *   what the caller asks for when requesting a cross-fade, but a
     *   reasonable facsimile.
     *   
     *   2. If it's not possible to perform the fade in the background with
     *   respect to the UI, the recommended fallback is to limit the fade to
     *   a relatively short interval (e.g., one second: so if the caller
     *   requests a 5000ms fade, limit it to 1000ms) and then perform the
     *   fade as a blocking operation.  Keeping the fade time short will
     *   minimize the UI impact of freezing the UI during the fade, while
     *   still smoothing out sound transitions to some degree.
     *   
     *   3. If it's not possible to perform fades at all, simply ignore the
     *   fade parameters and stop the sound abruptly.  
     */
    virtual void cancel_sound(class CHtmlSysWin *win, int sync,
                              long fade_out_ms, int fade_in_bg) = 0;

    /*
     *   Suspend playback if necessary to make the sound device available
     *   for another sound.  If the given new sound can't be played
     *   simultaneously with this sound, suspend this sound so that the
     *   new sound can play.  (This routine is not meant to actually play
     *   the new sound; it simply suspends playback of the current sound
     *   so that the caller can then play the new sound.)  Return true if
     *   we did indeed suspend the sound, false if not.
     *   
     *   On systems where multiple sounds of any type can be played
     *   simultaneously, this routine should simply return false.  If the
     *   system allows multiple sounds to be played as long as they're not
     *   of the same type, this routine should check the type of the new
     *   sound; if it's the same as the current sound, the routine should
     *   suspend the current sound and return true, otherwise return false.
     *   
     *   The callback indicating that the sound is finished should NOT be
     *   invoked by this routine, since the routine should merely pause
     *   the current sound, not cancel it entirely.  
     */
    virtual int maybe_suspend(class CHtmlSysSound *new_sound) = 0;

    /*
     *   Resume playback.  If playback was previously suspended with
     *   maybe_suspend(), this should continue playing where we left off. 
     */
    virtual void resume() = 0;
};

/*
 *   System MIDI sound object.
 */
class CHtmlSysSoundMidi: public CHtmlSysSound
{
public:
    virtual HTML_res_type_t get_res_type() const
        { return HTML_res_type_MIDI; }

    /*
     *   Create a new system-specific MIDI object.  This is a static
     *   routine that must be implemented for this class in a
     *   system-specific module.  This routine should return a new
     *   instance of the correct subclass of this class for the current
     *   operating system. 
     *   
     *   Note that 'filesize' is the size of the data starting at
     *   'seekpos' that the resource loader considers to be part of this
     *   resource; the actual file may be larger than this value, since
     *   other data may follow the resource in the file.
     *   
     *   'url' is provided for diagnostic purposes; it should be used in
     *   any error message that this routine generates (with
     *   oshtml_dbg_printf).  It can otherwise be ignored.
     *   
     *   The 'win' argument is provided so that the loader can check the
     *   current environment for any information necessary for loading the
     *   resource.
     */
    static CHtmlSysResource *create_midi(const class CHtmlUrl *url,
                                         const textchar_t *filename,
                                         unsigned long seekpos,
                                         unsigned long filesize,
                                         class CHtmlSysWin *win);
};

/*
 *   System WAV sound object.
 */
class CHtmlSysSoundWav: public CHtmlSysSound
{
public:
    virtual HTML_res_type_t get_res_type() const
        { return HTML_res_type_WAV; }

    /*
     *   Create a new system-specific WAV object.  This is a static
     *   routine that must be implemented for this class in a
     *   system-specific module.  This routine should return a new
     *   instance of the correct subclass of this class for the current
     *   operating system. 
     *   
     *   Note that 'filesize' is the size of the data starting at
     *   'seekpos' that the resource loader considers to be part of this
     *   resource; the actual file may be larger than this value, since
     *   other data may follow the resource in the file.
     *   
     *   'url' is provided for diagnostic purposes; it should be used in
     *   any error message that this routine generates (with
     *   oshtml_dbg_printf).  It can otherwise be ignored.
     *   
     *   The 'win' argument is provided so that the loader can check the
     *   current environment for any information necessary for loading the
     *   resource.  
     */
    static CHtmlSysResource *create_wav(const class CHtmlUrl *url,
                                        const textchar_t *filename,
                                        unsigned long seekpos,
                                        unsigned long filesize,
                                        class CHtmlSysWin *win);
};

/*
 *   System MPEG 2.0 audio layer 1/2/3 sound object.  This single object
 *   is used for all three MPEG 2.0 audio layers, since all subtypes use a
 *   common header format, which can be used to determine the appropriate
 *   decoding algorithm.  
 */
class CHtmlSysSoundMpeg: public CHtmlSysSound
{
public:
    virtual HTML_res_type_t get_res_type() const
        { return HTML_res_type_WAV; }

    /*
     *   Create a new system-specific MPEG 2.0 layer 1/2/3 sound object.
     *   This is a static routine that must be implemented for this class
     *   in a system-specific module.  This routine should return a new
     *   instance of the correct subclass of this class for the current
     *   operating system. 
     *   
     *   Note that 'filesize' is the size of the data starting at
     *   'seekpos' that the resource loader considers to be part of this
     *   resource; the actual file may be larger than this value, since
     *   other data may follow the resource in the file.
     *   
     *   'url' is provided for diagnostic purposes; it should be used in
     *   any error message that this routine generates (with
     *   oshtml_dbg_printf).  It can otherwise be ignored.
     *   
     *   The 'win' argument is provided so that the loader can check the
     *   current environment for any information necessary for loading the
     *   resource.  
     */
    static CHtmlSysResource *create_mpeg(const class CHtmlUrl *url,
                                         const textchar_t *filename,
                                         unsigned long seekpos,
                                         unsigned long filesize,
                                         class CHtmlSysWin *win);
};

/*
 *   System Ogg Vorbis sound object.  
 */
class CHtmlSysSoundOgg: public CHtmlSysSound
{
public:
    virtual HTML_res_type_t get_res_type() const
        { return HTML_res_type_OGG; }

    /*
     *   Create a new system-specific Ogg Vorbis object.  This is a static
     *   routine that must be implemented for this class in a system-specific
     *   module.  This routine should return a new instance of the correct
     *   subclass of this class for the current operating system. 
     *   
     *   Note that 'filesize' is the size of the data starting at 'seekpos'
     *   that the resource loader considers to be part of this resource; the
     *   actual file may be larger than this value, since other data may
     *   follow the resource in the file.
     *   
     *   'url' is provided for diagnostic purposes; it should be used in any
     *   error message that this routine generates (with oshtml_dbg_printf).
     *   It can otherwise be ignored.
     *   
     *   The 'win' argument is provided so that the loader can check the
     *   current environment for any information necessary for loading the
     *   resource.  
     */
    static CHtmlSysResource *create_ogg(const class CHtmlUrl *url,
                                        const textchar_t *filename,
                                        unsigned long seekpos,
                                        unsigned long filesize,
                                        class CHtmlSysWin *win);
};

#endif /* HTMLSYS_H */