-
Notifications
You must be signed in to change notification settings - Fork 1
/
porting.htm
1219 lines (1019 loc) · 56.6 KB
/
porting.htm
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
<html>
<head>
<title>Notes on porting HTML TADS</title>
</head>
<body>
<h1>Notes on porting HTML TADS</h1>
<h2>Recent Changes Affecting Porting</h2>
<p><b>Version 2.5.10</b>
<ul>
<li>The "link" item class, CHtmlDispLink, has a new method,
is_clickable_link(). This method indicates whether or not the link is
clickable - that is, whether clicking on the link should be treated as
a hyperlink activation or as an ordinary click on the underlying item.
When is_clickable_link() returns TRUE, the platform-specific code
should act as it always has. However, when is_clickable_link()
returns FALSE, the UI code should treat a click on the link as though
the link weren't there at all - so the click should be treated the
same as a click on the underlying display item.
<li>The TADS2 "osifc" interface includes new <b>optional</b> UI
extensions. These extensions are optional because they're inherently
graphical, and could not readily be implemented on text-only
platforms. HTML TADS ports are generally graphical, though, so most
HTML TADS versions should be able to implement these. The extensions
are defined in a separate file, tads2/osifcext.h, to emphasize that
they're not part of the base osifc set. If you want to implement the
extensions, you should do so directly in your platform-specific code;
there's no provision for these in oshtml.cpp since there's simply no
generic support that the portable HTML TADS code could usefully
provide for these. In addition, if you do implement these, you should
enable TADS 3 VM access to the extended functionality by modifying
your TADS 3 makefile to include tads3/vmbifregx.cpp instead of
tads3/vmbifreg.cpp. The 'x' version includes the "extended" I/O
function set that provides program access to the new interfaces.
</ul>
<p><b>Version 2.5.8</b>
<ul>
<li>The os_banner API introduces the new concept of a "parent" window.
Each banner window can now optionally have a parent banner specified.
Refer to the TADS 2 porting notes (portnote.txt in the TADS 2
distribution), and the os_banner API documentation (os_banner.htm) for
details. This change requires a change to the interface ot the frame
window method CHtmlSysFrame::create_banner_subwin(), and also will
require changes to the banner window layout algorithm on all
implementing platforms. Note that the addition of the parent window
is mandatory for systems that implement the os_banner API; there is no
provision for systems to support the banner API without also
supporting parent window specifications.
<li>The os_banner API has a new style flag, OS_BANNER_STYLE_MOREMODE.
When this flag is set, the banner window must display a suitable
"More" prompt, and pause for user input, when text is about to scroll
out of view. In other words, this style flag should make the banner
show a "More" prompt just like the main game window does. This style
implies the auto-vscroll style, because that's the only way text would
ever scroll out of view. The system code manages the "More" prompting
in the HTML interpreters, so this style flag must be handled by the
system-specific CHtmlSysWin implementation. Note that this flag will
never be used except in banner API windows (in other words, it'll
never be used in windows created with the <BANNER> tag).
<li>The class CHtmlSysFont has a couple of new methods that provide
information on the system-level font. <tt>is_fixed_pitch()</tt>
returns TRUE if the font is monospaced, FALSE if it's proportionally
spaced. <tt>get_em_size()</tt> returns the "em" size of the font. On
many systems, the em size is a design property of each font, so it
can't be inferred in a portable fashion; for systems where this
information isn't stored in each font, the implementation should
simply return the height of the font in pixels (i.e., translate the
nominal point size of the font to pixels and return the result).
<li>The method CHtmlSysImage::draw_image() has a new third parameter,
specifying how to draw the image if the native size of the image
doesn't exactly match the size of the rectangle. In the past, the
handling was poorly specified in the interface comments, but it was
intended that the routine would linearly scale the image up or down
as needed to fill the target drawing rectangle. The new parameter
allows the caller to specify one of three treatments for size
mismatches: clip the image, stretch (scale) it, or tile it. The
comments describe the three modes in more detail. The old version
should have done exactly what the "stretch" mode now does.
<li>The class CHtmlSysWin has a new method, draw_text_space(), that
draws "typographical spaces," which is to say spaces of arbitrary
width. This is used for special proportional spacing effects where
it's necessary to draw what look like spaces, but not necessarily
in integral multiples of the width of the ordinary space character.
<li>In CHtmlSysWin::get_font(), when creating the new CHtmlSysFont
object, if the font descriptor specified has the 'default_charset'
member set to TRUE, then the new system font object must store the
ACTUAL character set identifier in the new font object's
'desc_.charset' element. There was no such requirement in the past.
This change is required so that the generic code can obtain the actual
character set information from a font object, so that the generic code
can pass character set ID's back to the system code.
<li>There's a new function, os_next_char(), that the system code must
implement. Each platform should provide a header for this function
(or, alternatively, define it as a macro) in the platform's
xxx/hos_xxx.h file. This function allows the system to provide
support for multi-byte character sets, if multi-byte character sets
are used locally. For systems that use only single-byte character
sets, this is trivial to implement (it's just a pointer increment).
Most systems that support multi-byte character sets at all provide
OS-level functions to traverse strings with proper MBCS handling,
so this should be easy to implement wherever it's needed.
<li>The new CHtmlSysFrame method set_nonstop_mode() lets the system
frame receive notification that the caller wants to run in non-stop
mode (or not - the default is NOT non-stop mode). In non-stop mode,
MORE prompting (or any local equivalent) is to be suppressed. This is
used when the UI is running under automated scripting control, which
means we don't want to require any user interaction. System
implementations are free to ignore this, but systems that have
something like a MORE mode (i.e., pausing for user input between each
screen-full of text displayed) should implement this method.
</ul>
<p><b>Version 2.5.7</b>
<ul>
<li>Several new SYSINFO_xxx codes have been added; the
os_get_sysinfo() routine should be updated for the new codes. In
particular, note that SYSINFO_BANNERS should return result code 1,
SYSINFO_TEXT_COLORS should return SYSINFO_TXC_RGB, SYSINFO_TEXT_HILITE
should return 1, and SYSINFO_INTERP_CLASS should return
SYSINFO_ICLASS_HTML. See osifc.h (in the tads 2 sources) for the
definitions of these constants.
<li>The new parameterized color HTML_COLOR_INPUT has been added, to
represent the color of command-line text.
CHtmlSysWin::map_system_color() should be updated with the new color
code.
<li>The new parameterized color HTML_COLOR_HLINK has been added, to
represent the color of hyperlink text when the mouse cursor is hovering
over the hyperlink. CHtmlSysWin::map_system_color() should be updated
with the new color code.
<li>The new os_banner API, introduced into "osifc" (the basic TADS
portability layer) in TADS 2.5.7, is <i>mostly</i> handled by the
portable HTML TADS code, so ports will get the new banner API without
much extra platform-specific work. We've tried to keep track of
specific changes that were necessary for the Windows version, and
outline them below; we expect that similar changes will be needed
on other systems.
<li>A few interface changes were necessary in classes defined in
htmlsys.h. The significant ones are described below; any not listed
should be fairly self-explanatory and should be obvious when
compiling.
<li>The oshtml_set_frame() routine has been renamed to
CHtmlSysFrame::set_frame_obj(). It works the same way; this is
just a superficial name change to make the naming more consistent
with the model.
<li>The CHtmlSysWin routines create_banner_subwin(),
remove_banner_subwin(), and create_aboutbox_subwin() have been moved
to CHtmlSysFrame. They really belonged there to start with, but the
stream-based design of the original <BANNER>-tag system
misleadingly suggested that they were part of the main text window.
In addition, these routines have been superfically renamed to use
'window' instead of 'subwin', for consistency with the new view of
banners as peers of the main text window, and not mere subwindows of
the main text window.
<li>The CHtmlSysWin routine set_banner_size() has changed slightly.
The "size is percentage" flags have been replaced with more general
"size units" parameters, which expand the range of possible size
settings by adding a new unit, "characters." The "pixels" unit is the
same as the old percentage==FALSE, and the "percentage" unit is the
same as the old percentage==TRUE. The "characters" unit is new: it
specifies the size in terms of the character width or height, which is
defined as the size of a "0" character in the window's default font.
<li>There's an additional, more subtle change in set_banner_size():
the meaning of the "percentage" size has changed. In the past, the
size was given as a percentage of the <i>application window</i> size;
now, the size is given as a percentage of the <i>remaining</i> size at
the time the banner is being laid out. So, suppose we have a game
with two banners, the first (in layout order) top-aligned and the
second bottom-aligned, and each with a percentage size of 33. In
the past, the two banners and the main text window would all have
the same size, one third of the total application window area. Now,
the top window, being first in layout order, still gets 33% of the
overall window, since the remaining size is the entire window at the
time it's laid out. We next lay out the bottom banner; this one gets
33% of the remaining size, which is two-thirds of the application window
size; hence, we get 33%*66% = 22% of the total application window.
The main text window gets what's left, which is 46% of the total
application window size.
<li>CHtmlSysFrame::flush_txtbuf() should now be sure to flush buffers
explicitly for any banner API windows, separately from the main game
window. Fortunately, the portable code makes this pretty easy: simply
run through the list of banner windows, and for each window's
CHtmlSysWin object 'win', call flush_txtbuf(fmt) on the window's
CHtmlFormatter object, where 'fmt' is the parameter of the same name
to CHtmlSysFrame::flush_txtbuf().
<li>The interface for CHtmlSysWin::create_banner_subwin() has changed
to use the OS_BANNER_STYLE_xxx flags to specify the style of the new
banner window. Note that this adds some new styles that weren't
possible to specify before. The os_banner interface explicitly specifies
that all style flags are optional, so the OS code is not required to
implement any of the new style flags. However, since the HTML
interpreters are generally the most full-featured interpreters
around, and since the GUI platforms where the HTML interpreters run
can easily support all of the new styles, it's highly desirable for
the OS code to implement the new styles. The new features in particular
are that scrollbars can be displayed in banner windows, and banners
can be set explicitly to "auto scroll" mode, so that whenever new
text is printed to a banner, the banner scrolls to show the new text.
<li>CHtmlFormatter::get_text_array() is now protected, so code in
other classes can no longer access this method. This change was made
because formatters can no longer be assumed to provide text arrays.
Any OS code that depended on being able to access the formatter's text
array should instead use the similar methods exposed directly by the
formatter itself. This refactoring of interfaces allows the
formatter's implementation to be better hidden, allowing more
flexibility in the formatter's internal design.
<li>On the Windows version, I had to make some adjustments to the way
the banner windows drew their borders when the banner windows became
scrollable. In particular, I had to exclude the border itself from
the scrollable region of the window. (This is a detail specific to
the Windows OS implementation, but I mention it because other
platforms could run into the same sort of thing.)
<li>Note that "tab alignment" is inherently always available in any
full HTML interpreter, since the portable HTML parser/renderer
handles the <TAB> tag. So, for the style flag
OS_BANNER_STYLE_TAB_ALIGN, you can ignore this flag on window
creation, and simply set it unconditionally in
CHtmlSysWin::get_banner_info().
<li>The behavior method CHtmlSysWin::start_new_page() has changed
slightly. In the past, this method simply cleared the entire frame,
which included deleting all banner windows. This method should no
longer delete banner windows unconditionally; instead, it should only
delete banners created with <BANNER> tags in the main window.
Most implementations will probably use the main window's formatter
object's remove_all_banners() method to delete the banners, in
which case they will <b>not</b> need any changes: the remove_all_banners()
method will do the right thing automatically.
<li>The Windows version maintains a "history" of screens that have
been cleared. Each time CHtmlSysFrame::start_new_page() is called,
the Windows implementation saves the outgoing page by "exporting" the
parser object's state to a CHtmlParserState object (this is all done
by invoking portable code). Users can later recall these saved
history pages using a menu or toolbar command to step back through
the list of old pages. The old pages are read-only, obviously. The
new banner model required some changes in the way the Windows version
handles this; these changes are entirely specific to the Windows
implementation, but we mention them in case other platforms have
similar mechanisms that will be affected in similar ways:
<ul>
<li>When viewing history, the Windows version now uses a separate
window for the history panel, rather than showing history in the
main window. When switching from the main page to viewing history,
the system makes the main page window invisible (by hiding the
window at the OS level) and makes the history window visible;
the history window is normally kept invisible. The system then
places the history window in exactly the same screen area that the
main window was previously occupying. Switching back from a history
page to the main window reverses this visible/invisible swap. This
change allows the main window to be left intact, so that the system
doesn't have to worry about saving and restoring its state with
respect to command input editing and the like.
<li>The history window uses a new subclass of the portable formatter
object; the new subclass is CHtmlFormatterHist. The main difference
between this new special formatter and the normal main window
formatter is that CHtmlFormatterHist simply ignores banner windows
embedded in the history. This allows paging through the history
without disturbing the layout of banner windows; it's crucial to
leave banner windows unaffected during history recall because of the
new programmatic access to banners.
</ul>
<li>In the Windows interpreter, any routine that adds output to the
main window is now careful to exit "history" mode and return to showing
the main page. In particular, CHtmlSysFrame::display_output() always
jumps to the active page if a history page is being viewed. This is
desirable in case a timed event causes output while the user is viewing a
history page; this change ensures that the effect of the timed event is
immediately apparent to the user.
</ul>
<p><b>Version 2.5.6</b>
<ul>
<li>Several new parameterized system colors have been added:
<tt>HTML_COLOR_LINK</tt> and <tt>HTML_COLOR_ALINK</tt>,
<tt>HTML_COLOR_TEXT</tt>, <tt>HTML_COLOR_BGCOLOR</tt>. The
system-specific <tt>CHtmlSysWin::map_system_color()</tt>
implementation should be updated to recognize these new color codes
and translate them to the appropriate colors; in most cases, these
will be translated according to user preference settings.
<li>The new member variable <tt>face_set_explicitly</tt> of the class
<tt>CHtmlFontDesc</tt> (defined in the portable header <tt>htmlsys.h</tt>)
allows you to distinguish cases where a typeface name has been explicitly
selected from cases where the typeface is inherited from surrounding
text. The latter case arises in situations such as when a <tt><b></tt>
tag appears: the font descriptor is filled in with all of the
information for the current text (i.e., the text
surrounding the boldface text), then the boldface tag changes the
<tt>weight</tt> member to select bold text. The <tt>face</tt> member
is filled in with the name of the typeface from the surrounding text,
but a new typeface isn't being selected - it's merely filled in because
we want all of the same attributes of the surrounding text except for
the weight. This new member has been added so that any system-specific
code that translates parameterized font names (such as "TADS-Input")
will know whether additional attributes associated with the parameterized
font name, such as color and boldness, should be applied to the font
descriptor. When <tt>face_set_explicitly</tt> is true, all of the
attributes of a parameterized font should be selected; if this member
variable is false, then only the face name should be translated, and the
other attributes should be left alone. On Windows, this affects
the "TADS-Input" font, because this font allows the user to select
(via the "preferences" dialog) the color, bold, and italics settings
for the command input font; <tt>CHtmlSysWin_win32::get_param_font()</tt>
in <tt>win32/htmlw32.cpp</tt> uses this information when
performing the parameterized font name translation.
<li>The new member variables <tt>bgcolor</tt> and
<tt>default_bgcolor</tt> of <tt>CHtmlFontDesc</tt> provide information
on the font's background color, if it has one. If
<tt>default_bgcolor</tt> is TRUE, then <tt>bgcolor</tt> should be
ignored; otherwise, <tt>bgcolor</tt> should be used as the fill color
for the bounding rectangle of text drawn with font.
<li>A new, more sophisticated timer interface has been added to
<tt>CHtmlSysWin</tt>. The system-specific window subclass must
implement a few new pure virtual functions to provide this mechanism:
<tt>CHtmlSysWin::create_timer()</tt>,
<tt>CHtmlSysWin::set_timer()</tt>,
<tt>CHtmlSysWin::cancel_timer()</tt>, and
<tt>CHtmlSysWin::delete_timer()</tt>. Related to this new mechanism
is the new class <tt>CHtmlSysTimer</tt>. The base type (defined in
htmlsys.h) keeps track of the generic information associated with the
new timer mechanism, and the system code is free to subclass this as
needed to add system-specific information.
<li><tt>CHtmlSysWin::draw_text()</tt> should be updated to use
the new background color information in <tt>CHtmlSysFont</tt>.
<li>The Ogg Vorbis compressed audio format has been added to
the standard set of media types. The new system-specific
subclass <tt>CHtmlSysSoundOgg</tt> must be implemented to provide
Ogg Vorbis playback.
<li>The MNG animated image format has been added to the standard set
of media types. The new system-specific subclass
<tt>CHtmlSysImageMng</tt> must be implemented to provide MNG support.
<li>The application frame class (<tt>CHtmlSysFrame</tt>) has a new
method that the system-specific code must implement,
<tt>get_formatter()</tt>, which returns the <tt>CHtmlFormatter</tt>
object associated with the main HTML window. This should be trivial
to implement in most cases, because the application frame must already
create a formatter object and keep track of it internally.
</ul>
<h2>Architectural Overview</h2>
<p>First the good news: most of HTML TADS is portable code; you shouldn't
need to make any changes to the portable parts in order to move HTML
TADS to a new operating system. Now the bad news: it's not <b>all</b>
portable code; some of the code is system-specific, and you'll need to
re-implement this non-portable portion to get HTML TADS running on a
new operating system.
<p>Even though you won't need to make any changes to the portable code,
you'll probably find it helpful to know a little about how it works,
since you'll make use of services in the portable code in the course
of implementing a new system-specific implementation. This section
is a brief overview of the design of HTML TADS.
HTML TADS has the following major components:
<ul>
<li><b>HTML parser</b>: this is implemented in the class CHtmlParser.
The HTML parser reads HTML source code and interprets the embedded
HTML command sequences (which are usually called "markups"). The
parser generates a data structure in memory that represents the
HTML text and commands; this data structure is called the <i>format
list</i>. The format list contains the same information as the
original HTML source code, but in a translated format that is easier
for the computer to use.
<p>
The format list is constructed from "tag" objects, which are subclasses
of the class CHtmlTag.
<li><b>Formatter</b>: this is implemented by the class CHtmlFormatter.
The formatter reads the format list (which was generated by the parser)
and converts it into another in-memory data structure, the <i>display
list</i>. Whereas the format list corresponds directly to the parsed
HTML code, the display list corresponds directly to the information
that will be displayed on the screen. The display list contains almost
entirely items that appear on-screen, and each item in the display list
has information on its size, position, and appearance. To produce the
display list from the format list, the formatter must figure out where
to insert line breaks, where each item will go in the display window,
and all other details of how the information will appear on the screen.
<p>
The display list is constructed from "display" objects, which are
subclasses of CHtmlDisp.
<li><b>Text array</b>: this is implemented in the class CHtmlTextArray.
The text array is a simple mechanism that stores the text in the
HTML source. The text array is a specialized memory manager that has
some special properties. In particular, it provides a virtual address
scheme that guarantees that addresses are allocated in monotonically
increasing order; the formatter exploits this feature to simplify its
manipulation of the text underlying the format and display lists.
<li><b>Resource cache</b>: this is implemented by the class CHtmlResCache.
The resource cache keeps track of resources (external binary data,
such as JPEG images) that have been loaded. Its function is to minimize
resource memory consumption and load time by re-using resources whenever
possible. Whenever HTML TADS is about to load a resource, it first looks
in the resource cache to see if the resource is present, and if so uses
the original copy of it.
<li><b>System HTML window</b>: this is implemented by your non-portable,
system-specific code. HTML TADS defines a portable interface to the
system window, which the formatter uses to obtain information about the
layout of the window and to display information in the window.
<li><b>Input buffer</b>: this is implemented by the class CHtmlInputBuf.
This class is a helper for your system-specific window implementation;
you don't need to use it, but it may be helpful. The input buffer handles
the internal (non-user-interface) details of implementing a command line
input editor. It provides services, such as selecting a range of text
or inserting a character, that make it easier to implement a command line
editor; if you use this class, your user interface code must handle actual
user interface events and call the corresponding methods in the input
buffer object. Your operating system or application class framework may
have its own object or service that provides this type of functionality,
in which case you probably won't need to use this object.
<li><b>Resource implementations</b>: the classes CHtmlJpeg and CHtmlPng
implement portable operations on JPEG and PNG files, respectively.
Additionally, you must implement system-specific objects that take the
portable data representations of these classes and convert them into
objects that your system can display.
<li><b>Property list</b>: the class CHtmlPropList provides an
implementation of a simple property list object. You can use this object
to store user preferences, if it's helpful.
<li><b>Resource finder</b>: this is implemented in class CHtmlResFinder.
The resource finder is a mechanism that lets HTML TADS find resources
stored in .GAM files through the TADS resource storage mechanism. The
resource finder works with the TADS file reader to construct a map of
resources stored in the .GAM file; when HTML TADS tries to load a resource
based on an URL, it first looks in the resource finder's list to see if
the resource can be loaded from the .GAM file.
</ul>
<h2>Steps in Porting HTML TADS</h2>
<p>The remainder of this document describes the steps you should follow
to port HTML TADS to a new system.
<h3>First, port the regular TADS to your system</h3>
<p>
The first thing you need to do is port TADS to your platform. Since
TADS has already been ported to most platforms, this should just be a
matter of finding the correct set of files for your system, setting
up a build environment, and compiling. There's a makefile or its
equivalent for most platforms as well, so you shouldn't need to
figure out the build commands from scratch.
<p>
HTML TADS only uses the TADS interpreter, so you only need to build this
component of the normal TADS at this point.
<h3>Obtain the Required Third-party Libraries</h3>
<p>On Windows, HTML TADS depends on a number of third-party libraries
to implement some of its functionality. In particular, the image
format support is provided mostly by third-party libraries.
<p>These libraries are <b>not</b> required by the portable code. The
Windows implementation uses them, but you don't necessarily have to on
another platform. The Macintosh version, for example, doesn't use any
of them, because there are better Mac-specific equivalents. We
mention these libraries only because they're highly portable, so
if you don't know of a better option for your system, these are
probably good bets.
<p>If you do use these third-party libraries, it will mean that you'll
need to do a little leg-work to integrate them. In the end, though,
it should save you a lot of effort compared to implementing all of
this functionality from scratch: these libraries are all free,
of high quality, and are already highly portable.
<p>
The libraries you might find useful are:
<ul>
<li>PNG (Portable Network Graphics). This library provides support
for the PNG image format. You can find the PNG home page, which
has links to lots of information about PNG, including C source
code for the PNG library, at
<a href="http://www.cdrom.com/pub/png/">http://www.cdrom.com/pub/png/
</a>. I'm currently using libpng version 0.95 (also known as 1.0
beta 5), but future versions will probably work as well.
<li>ZLIB, a data-compression library. HTML TADS doesn't use ZLIB
directly, but the PNG libraries described above need it. You can
find the ZLIB home page at
<a href="http://www.cdrom.com/pub/infozip/zlib/">
http://www.cdrom.com/pub/infozip/zlib/</a>; this page has links to
the C source code.
<li>JPEG, a portable image format. There are several implementations
of JPEG available, so if there's one for your platform that you're
already familiar with, you should use that. The reference
implementation, though, is the Independent JPEG Group's library;
you can find the C source code at
<a href="ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/jpegsr6b.zip">
ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/jpegsr6b.zip</a>
(for an MSDOS ZIP file), or
<a href="ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz">
ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz</a>
for a Gnu-tools-friendly version. (Apart from the bundling format,
both of these should contain the same source files.)
Note that you should use <b>version 6b</b> or higher - past versions did
not handle conversion of the gray-scale storage format to RGB for
display, which the portable CHtmlJpeg code generally requires.
<li>Libvorbis (the reference Ogg Vorbis decoder library), at
<a href='http://www.vorbis.com'>www.vorbis.com</a>.
<li>Libmng (the reference MNG library), at <a href='http://www.libmng.com'>
libmng.com</a>.
</ul>
Each of the libraries above has been widely ported; there's a good
chance there's already a makefile for your platform included in
the archive. If not, each includes documentation that describes how
to port the library to a new platform.
<h3>The TADS virtual OS layer</h3>
<p> The regular character-mode TADS has a "virtual operating system"
layer of code. This is the interface that TADS uses to perform
system-specific operations. The interface itself is defined portably
-- there's a set of functions that TADS can call from portable code,
and these functions provide the same behavior on all platforms. The
implementations of these functions are different on each platform,
though. These functions provide a virtual OS by providing
system-specific functionality through a standardized, portable
interface.
<h3>HTML TADS: a replacement virtual OS layer</h3>
<p>
HTML TADS is designed to look like a virtual OS layer, from TADS's
perspective. TADS doesn't know much about HTML; as far as TADS is
concerned, it's just generating output the same way it would on DOS
or Macintosh or Unix: TADS puts together a buffer with text it wants
to display, then calls the virtual OS display-text function.
<p>
So, to port HTML TADS to a new platform, you should start with a
port of TADS to that platform, then <i>remove</i> a number of the virtual
OS function implementations that you would normally use for that
platform. You remove them because HTML TADS provides new
implementations for them.
<p>
For a normal port of TADS, most of the virtual OS functions are
in files with names like osdos.c or osmac.c. Some systems have more
extensive OS layers than others, so some systems have all of their OS
implementation in a single .c file, while others use several files.
There's also a file called osgen.c, which provides some OS-specific
functions that have a common implementation across a number of
systems. Your system's TADS makefile should be helpful in
determining which files are used on your platform.
<h3>oshtml.c</h3>
<p> To determine which of the normal platform OS functions to remove
from your build, look at the HTML TADS file called oshtml.c. This
file contains the implementation of the HTML TADS replacements for
the normal virtual OS functions. Despite its name, oshtml.c is a
portable file -- it is the same on all platforms. You don't need to
port this file.
<p>
Go through the function definitions in oshtml.c; for each one,
you need to remove the corresponding implementation in the normal OS
layer for your system.
<h3>htmlsys.h</h3>
<p>
Now comes the real work. Just as TADS has a virtual OS layer, HTML
TADS has its own virtual OS layer. The functionality of this layer
is defined in the HTML TADS file htmlsys.h.
<p>
TADS is written in C, but HTML TADS is written in C++. The TADS
virtual OS layer used C functions; the HTML TADS virtual OS layer, on
the other hand, is defined through a set of C++ classes and methods
on those classes. The file htmlsys.h defines the portable interfaces
to these classes. These classes have names that start with CHtmlSys:
CHtmlSysFont, CHtmlSysWin, and so on.
<p>
These classes are not typical C++ classes that define methods and
member variables. Instead, these classes are designed as abstract
interfaces -- the methods defined in these classes do not have
corresponding implementations, but are pure virtual methods that must
be overridden and defined in subclasses.
<p>
This is where the new system-specific code for your platform
needs to be written. For your system, you must define a concrete
subclass of each of the CHtmlSysXxx classes. Each of these concrete
subclasses must provide implementations for all of the methods in its
CHtmlSysXxx abstract base class.
<p>
The reason that the CHtmlSysXxx classes are designed as abstract
interfaces is so that you can use a third-party class framework to
build your version of HTML TADS, if you want. If your system (or
compiler) has an application framework, there's probably a class in
the framework that corresponds roughly to each of the CHtmlSysXxx
interfaces. To use these interfaces with your framework, you can use
multiple inheritance.
<p>
A word on multiple inheritance: A lot of people dislike multiple
inheritance, or have heard that it's a bad thing, or feel that C++'s
implementation of multiple inheritance is flawed; but this is a case
where it's actually quite useful and reasonably straightforward to
use. Since the CHtmlSysXxx classes are abstract, and because they
are stand-alone classes without any base classes, they can be "mixed
in" to other classes without much chance of an inheritance conflict,
and without placing any requirements on the design of the rest of
your class hierarchy. In particular, you won't need to use
C++'s "virtual" inheritance feature, which is probably where most
people's misgivings about C++ multiple inheritance come from.
<p>
If you're using a framework, you should find the framework class that
corresponds to each of the CHtmlSysXxx interfaces. Then, you should
create a subclass of your framework class that inherits from both the
framework class and the CHtmlSysXxx interface. For example, suppose
that your framework has a class called TWindow that defines the basic
window type. (If there's a framework subclass of TWindow that would
be more appropriate, such as TScrollingWindow, you should use that as
the base class. You don't have to use the bare window class just
because CHtmlSysWin defines the interface to a window -- make your
framework usage decisions just as though the CHtmlSysXxx interfaces
were not involved.) You'd make a TWindow subclass that also inherits
from CHtmlSysXxx:
<p>
<pre>
class CHtmlSysWin_mac: public TWindow, public CHtmlSysWin
{
...
};
</pre>
<p>
Your framework will probably require that you provide implementations
for some methods inherited from TWindow; you should define these as
you would for any other application.
<p>
In addition, you must provide implementations for all of the
functions in CHtmlSysWin. The htmlsys.h header file provides
comments that document the functions that these methods are meant to
provide.
<p>
Here's a summary of the classes in htmlsys.h that you will need
to implement.
<ul>
<li><b>CHtmlSysFont</b>: system font object. This provides an
portable interface to a font.
<li><b>CHtmlSysFrame</b>: system application frame object. This
object provides a logical container for the HTML display; this object
doesn't have to correspond to anything that's actually displayed, but
rather is a programmatic object that the TADS interpreter uses to
perform operations involving the display. When your application
starts up, you will need to create exactly one object that implements
this interface. The main purpose of this object is to route the
TADS interpreter engine's input and output functions to the main HTML
display window.
<p>Pay careful attention to the comments in htmlsys.h
regarding <tt>CHtmlSysFrame::set_frame_obj()</tt>.
<p>This interface is probably the most flexible (and thus ambiguous)
in terms of how you will go about implementing it, because it doesn't
correspond directly to any display element. In my Windows implementation,
this interface is implemented by a system-specific window object that
serves as the top-level frame window. Since this frame window contains
the main game HTML window, it can easily route the CHtmlSysFrame
functions to the main HTML window. Depending on your implementation
design, it may be more appropriate to implement this interface in
something like an "Application" object, or even in a completely
abstract singleton object that you create purely for this interface.
<li><b>CHtmlSysWin</b>: system window object. This is the interface
that HTML TADS uses to control the display. You will generally create
one of these objects to serve as the main game window; additionally,
the formatter may create additional CHtmlSysWin objects to display
banner windows.
<li><b>CHtmlSysImageJpeg</b>: system JPEG image resource object.
You must implement interface to provide a display object for JPEG
images. Note that there is a corresponding portable class, CHtmlJpeg,
which handles the details of loading a JPEG image from a file; you
won't need to port CHtmlJpeg. You will need to port CHtmlSysImageJpeg,
which is responsible for converting the portable data representation
that CHtmlJpeg uses into a suitable system-specific object that you
can display on your system.
<li><b>CHtmlSysImagePng</b>: system PNG image object. This is the
PNG image equivalent of CHtmlSysImageJpeg. The corresponding
portable class, CHtmlPng, handles the details of reading a PNG file;
you must implement CHtmlSysImagePng to convert the portable representation
used in CHtmlPng into a system-specific display object.
<li><b>CHtmlSysImageMng</b>: system MNG image object. This is the
MNG image class.
</ul>
<p>
Note that there also a few classes defined in htmlsys.h that you <i>won't</i>
have to implement. Some of these are portable classes that are used
simply to parameterize some of the methods of the other classes;
they're defined here because their main function is to work with
these classes. Others are base classes for more specialized
interfaces, so don't need to be implemented directly.
<ul>
<li><b>CHtmlFontDesc</b>: font description. This is a portable
class that's used by the portable code to describe a font to the
system code; this class is used to parameterize certain methods
in system objects.
<li><b>CHtmlFontMetrics</b>: font metrics. This class is used
as a portable representation of certain information about a font,
and is used to parameterize system object methods.
<li><b>CHtmlSysResource</b>: system resource object. This object
provides an interface to system-specific display objects that come
from external resources, such as JPEG images. This is a base
class for more specific interfaces, so you won't need to implement
this interface directly.
<li><b>CHtmlSysImage</b>: system image resource object. This is
a subclass of CHtmlSysResource that serves as the base class for
the image interfaces. You won't need to implement this interface
directly; it's a base class for more specific interfaces.
</ul>
<h3>System Object Creation</h3>
<p>
Since your system code will be providing implementations of these
interfaces in subclasses, the portable code has no way of knowing
what the final subclasses are called. Thus, the portable code can't
ever create a system object directly; instead, your system code
creates all of the system objects.
<p> Your system code will create some system objects automatically.
For example, it will create the CHtmlSysFrame object when the
application starts running (the main application entrypoint is itself
always system-specific), and it will create the main HTML window
(which provides a CHtmlSysWin interface) during initialization as
well.
<p>
After startup, the portable
code will call methods in existing system objects to create additional
system objects. For example, when the formatter needs to create a
new banner subwindow, it will call the main HTML window's
<tt>create_banner_subwin()</tt> method; this method, which is
implemented by your system code, will create an appropriate final
subclass of CHtmlSysWin -- specialized for your system -- and return
a pointer to it.
<h3>The TADS Win32 Framework</h3>
<p>
Rather than using an existing class framework to develop the Win32
version of HTML TADS, I developed my own framework. Although I
designed and implemented this framework specifically for this project,
I designed it to operate as a general-purpose Win32 framework.
Note that I could just as well have used one of the commercially
available third-party C++ frameworks for Windows (such as MFC, the
class library Microsoft includes with Visual C++), but I chose to
develop my own framework instead for a number of reasons; one of the
main reasons is that I wanted to avoid inadvertantly introducing any
framework dependencies in the portable design that might have resulted
from developing HTML TADS around an existing framework.
<p>
All of the classes with names starting with CTads (such as CTadsWin
and CTadsStatusline) belong to the Windows framework.
<p>
If you're using an existing framework to port HTML TADS to your
system, you won't need to be concerned at all with the CTadsXxx
classes. You don't need to port those classes, because you will
simply replace them with the corresponding classes from your
framework. In fact, you don't even need to replace the CTadsXxx
classes exactly; if your framework is laid out differently from the
CTads framework, you should follow the organization that you'd
normally follow when developing an application with your framework
and ignore the CTadsXxx organization. Remember, your job is to
provide implementations of the abstract interfaces defined in
htmlsys.h -- nothing from the CTads framework is needed by the
portable code.
<p>
If you're not using an existing class framework, you can use the
CTadsXxx classes as a starting point. These classes, though, are
completely Win32-specific, so they're filled with Win32 API calls.
In addition, these classes are not even designed to be called from
portable code, so the interfaces these classes expose are themselves
closely coupled to the Win32 API; for example, many of the member
variables and method parameters use Win32 system datatypes.
<h3>html_os.h</h3>
<p>
The normal TADS OS layer has some additional definitions in a header
file, os.h. This file has some configuration information needed by
the portable code, such as the native C types to use for certain
abstract TADS types.
<p>
HTML TADS has a corresponding header file, html_os.h. This file is
in the portable directory, but provides platform-specific
definitions. You need to edit this file to provide a set of
definitions for your platform. You should add a section, enclosed in
an appropriate #ifdef for your system, that includes a system-specific
file that you create. For Win32, this included file is called hos_w32.h;
you should create a file appropriate for your system.
<p>
You should refer to the hos_w32.h to find the set of macros and
other definitions that you need to include in your platform-specific
header file. Fortunately, this file is considerably simpler than
os.h from TADS; one reason is that HTML TADS uses some of the TADS OS
layer directly, reducing the amount of new OS layer that needs to be
built, and another reason is that C++ is somewhat more standardized
than C was in the days when I started TADS.
<p>
Note that html_os.h acts only as a "switchboard" for including
the appropriate platform-specific file. Please observe this
convention, since it will keep the code (both in html_os.h and
in your own system-specific files) easier to read by keeping
each platform's code in its own set of files, rather than concatenated
together into a huge impenetrable set of #ifdef's. For the Win32
definitions, look in hos_w32.h and hos_w32.cpp in the win32
subdirectory.
<h3>os_get_sysinfo()</h3>
Your system code must define this function:
<p>
<pre>
int os_get_sysinfo(int code, void *param, long *result);
</pre>
Refer to the base TADS header file osifc.h for a full description
of this function. This is one of the few TADS OS-layer functions
that you must define in your system-specific code. The reason this
function is part of your system-specific code rather than part of
the portable HTML TADS definitions (as are most of the other TADS
OS-layer functions) is that this function returns the specific
capabilities of your version of HTML TADS. Since each port of
HTML TADS may vary in capabilities, HTML TADS cannot at the portable
level know which capabilities are implemented for each platform.
For example, some ports of HTML TADS may support MIDI files but
not WAV files. This function allows the system-specific code
to provide the correct information.
<h3>os_dbg_sys_msg()</h3>
Your system code must define this function:
<p>
<pre>
void os_dbg_sys_msg(const textchar_t *msg);
</pre>
<p>
This routine displays internal debugging messages on the system console.
You can provide an empty implementation for this function if you wish;
its only function is to help you debug HTML TADS by providing a place
for the system to display internal diagnostic information. When you
compile the system without TADSHTML_DEBUG defined, this function is
not used at all.
<h3>Main entrypoint</h3>
<p>
Once you've provided implementations for the CHtmlSysXxx interfaces,
you're nearly done. The only thing left is that your system code has
control over starting up the application.
<p>
The main entrypoint is system-specific, because each GUI system has
its own way of invoking an application and passing start-up paramters
to it. There's no CHtmlSysXxx or other portable interface defined for
the main entrypoint; this is a totally system-specific function, so
you must provide a main entrypoint as appropriate for your operating
system.
<p> Your main entrypoint will undoubtedly have to do some
system-specific work to get the application initialized; you should
follow the normal application initialization protocol for your
system. Among other things, you'll want to parse the command line or
read the start-up parameters, or whatever the equivalent is on your
system.
<p> In addition, your main entrypoint is required to do a few
specific things to get HTML TADS started. You can refer to the
implementation of <tt>run_game()</tt> in the Windows code (in htmlw32.cpp)
for an example of the start-up code. Here's an outline of the steps
you need to perform:
<ul>
<li>Call the function <tt>CHtmlResType::add_basic_types()</tt> (which
takes no arguments and returns no value). This function initializes
the table of built-in media types (JPEG, PNG, MNG, MIDI, WAV, MPEG Audio,
Ogg Vorbis Audio). The media type table is dynamic, so that new media
types can be added at run-time; because of this, the table must be
initialized with the built-in types at some point during startup. (In
the future, it may be possible to add types to the table by looking
for external plug-in objects in dynamic-link libraries; no system does
this yet, but the table is dynamic to allow for this future
enhancement.)
<li>Create a parser and a formatter object. You should create a
new CHtmlParser object and start it in literal mode, and you should
create a new CHtmlFormatterInput object connected to the parser:
<p>
<pre>
parser = new CHtmlParser(TRUE);
formatter = new CHtmlFormatterInput(parser);
</pre>