-
Notifications
You must be signed in to change notification settings - Fork 0
/
htmlfmt.h
2836 lines (2370 loc) · 97.4 KB
/
htmlfmt.h
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
/* $Header: d:/cvsroot/tads/html/htmlfmt.h,v 1.3 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
htmlfmt.h - TADS HTML formatter
Function
Takes an HTML parse tree as input, and formats the text into a
draw list. The draw list is a set of rectangular areas suitable
for display.
Notes
Modified
09/07/97 MJRoberts - Creation
*/
#ifndef HTMLFMT_H
#define HTMLFMT_H
#ifndef TADSHTML_H
#include "tadshtml.h"
#endif
#ifndef HTMLATTR_H
#include "htmlattr.h"
#endif
#ifndef HTMLURL_H
#include "htmlurl.h"
#endif
#ifndef HTMLSYS_H
#include "htmlsys.h"
#endif
/* ------------------------------------------------------------------------ */
/*
* Line break state object. This structure lets each display item keep
* track of the last location for a line break, so that when we exceed
* the available display width we can apply a line break.
*/
class CHtmlLineBreak
{
public:
CHtmlLineBreak() { clear(); }
/* clear the break position */
void clear()
{
item_ = 0;
pos_ = 0;
last_char_ = 0;
no_break_ = FALSE;
ws_start_item_ = 0;
ws_start_pos_ = 0;
brk_ws_start_item_ = 0;
brk_ws_start_pos_ = 0;
}
/*
* Set the break position. If we're currently in a run of whitespace,
* and the existing break position is in the same run of whitespace,
* we'll ignore this new break position, so that we always break at
* the start of a run of whitespace.
*/
void set_break_pos(class CHtmlDisp *item, void *pos)
{
/*
* if we're in a run of whitespace, and the current break position
* is in the same run of whitespace, ignore the new position,
* since breaking anywhere in the run of whitespace is equivalent
* to breaking at the earliest possible point in the run of
* whitespace
*/
if (ws_start_item_ != 0
&& brk_ws_start_item_ == ws_start_item_
&& brk_ws_start_pos_ == ws_start_pos_)
return;
/* note the new break position */
item_ = item;
pos_ = pos;
/* note the run of whitespace containing the break position */
brk_ws_start_item_ = ws_start_item_;
brk_ws_start_pos_ = ws_start_pos_;
}
/* note a character, for the whitespace run calculation */
void note_char(textchar_t ch, class CHtmlDisp *item, void *pos)
{
/* note the whitspace or non-whitespace, as appropriate */
if (is_space(ch))
note_ws(item, pos);
else
note_non_ws();
}
/*
* set the current whitespace position, if it's not already set - this
* can be called each time whitespace is encountered to set the start
* of a whitespace run if we're not already in a whitespace run
*/
void note_ws(class CHtmlDisp *item, void *pos)
{
/* if we're not already in a run, this is the start of a run */
if (ws_start_item_ == 0)
{
/* remember the given item and position as the start of a run */
ws_start_item_ = item;
ws_start_pos_ = pos;
}
}
/*
* clear the whitespace run start - this can be called each time a
* non-whitespace character is encountered to note that we're not in a
* run of whitespace
*/
void note_non_ws() { ws_start_item_ = 0; }
/*
* Display object containing the line break. Whenever a display
* object identifies a line break, it should store a pointer to
* itself here, so that as soon as we exceed the display width we
* can go back to the last break point.
*/
class CHtmlDisp *item_;
/*
* position pointer, for use of display object - when a display
* object finds a suitable break position, it can use this to
* identify the internal location of the break
*/
void *pos_;
/*
* The item and position of the run of whitespace containing the
* current break position. Each time we accept a new break position,
* we copy the current whitespace run start point into these members;
* this way, we can tell if a subsequent break position is part of the
* same run of whitespace by comparing these to the current whitespace
* start point.
*/
class CHtmlDisp *brk_ws_start_item_;
void *brk_ws_start_pos_;
/*
* Last character of previous item, for break purposes. Even when
* we don't find any breaks in an item, the item should set this
* variable so that the next item can determine whether it's
* possible to break between the two items. If an item doesn't
* contain text, it should set this to a character value that allows
* the next item to determine if a break is allowed between the two
* items; setting this to a space always allows a break, whereas
* setting it to an alphabetic character prevents a break it
* non-whitespace text follows.
*/
textchar_t last_char_;
/*
* No-break flag: this indicates that we have an explicitly no-break
* indication just before the current position, which means that we
* can't break to the left of the current position, even if the next
* item would normally allow a break here.
*/
int no_break_;
/*
* Display item and position giving the start of the last run of
* whitespace we encountered. We'll set these to null every time we
* encounter anything other than whitespace, and set them to the
* current item and position every time they're null and we find a
* whitespace character. The line breaking routine can use these to
* go back and remove visual trailing whitespace after breaking the
* line.
*/
class CHtmlDisp *ws_start_item_;
void *ws_start_pos_;
};
/* ------------------------------------------------------------------------ */
/*
* Table cell metrics measurement object. This object is used to
* measure the minimum and maximum widths of items in a table cell.
*/
class CHtmlTableMetrics
{
public:
/* clear metrics - set up for the start of a new cell */
void clear()
{
last_char_ = 0;
leftover_width_ = 0;
cur_line_width_ = 0;
min_width_ = max_width_ = 0;
no_break_ = FALSE;
no_break_sect_ = FALSE;
}
/*
* Add an indivisible item (i.e., an item that can't be broken up
* across lines). If this item is wider than the widest indivisible
* item so far, we'll update the minimum width to reflect this
* item's width. This does not affect the total length of the
* current line; the item must be separately added to the total line
* width if appropriate.
*/
void add_indivisible(long wid)
{
if (wid > min_width_)
min_width_ = wid;
}
/*
* Add to the size of the current line. If this makes the current
* line longer than the maximum width so far, we'll update the
* maximum width to reflect the width of this line.
*/
void add_to_cur_line(long wid)
{
cur_line_width_ += wid;
if (cur_line_width_ > max_width_)
max_width_ = cur_line_width_;
}
/*
* Clear the leftover width. This should be called any time an item
* doesn't need to use or aggregate any space into the leftover
* width. This will add any current leftover width to the current
* line and indivisible widths, and clear the leftover.
*/
void clear_leftover()
{
/* add the leftover to the indivisible width and line width */
add_indivisible(leftover_width_);
add_to_cur_line(leftover_width_);
/* forget the leftover width */
leftover_width_ = 0;
}
/*
* Start a new line. Resets the current line's width to zero.
*/
void start_new_line()
{
/*
* if there's any leftover width, add it to both the indivisible
* width and the total line width
*/
add_to_cur_line(leftover_width_);
add_indivisible(leftover_width_);
/* forget the current line width and leftover width */
cur_line_width_ = 0;
leftover_width_ = 0;
/* there is no previous character on the line */
last_char_ = 0;
/* there's no no-break flag yet */
no_break_ = FALSE;
}
/*
* Minimum width so far. This is the size of the largest single
* item that can't be broken across lines; since this item can't be
* broken, its width is the smallest we can go without clipping
* anything.
*/
long min_width_;
/*
* Maximum width so far. This is the size of the longest line.
* This is the widest that we'd have to go to avoid having to break
* up any lines.
*/
long max_width_;
/*
* Size of the current line so far. Each time we encounter a line
* break, we'll reset this to zero.
*/
long cur_line_width_;
/*
* last character of previous item, for break purposes (see the
* notes on the last_char_ member of CHtmlLineBreak for details on
* how this works)
*/
textchar_t last_char_;
/*
* Leftover width from previous item - this is the amount of space
* left over after the last break in the previous item. If we can't
* insert a break between the end of the previous item and the start
* of the current item, this leftover space must be added to the
* space at the start of the current item.
*/
long leftover_width_;
/* flag: we just passed an explicit no-break item (such as an ) */
unsigned int no_break_ : 1;
/* flag: we're in a <NOBR> section */
unsigned int no_break_sect_ : 1;
};
/* ------------------------------------------------------------------------ */
/*
* Line-start table. We need to be able to find line starts quickly,
* so that we can navigate from a screen coordinate (such as might come
* from a mouse click) to a display object. To facilitate quick
* searching by position, we keep an array of the display items that are
* first in their lines, and we keep the array in order of vertical line
* position. Since the number of lines could grow quite large, we keep
* a two-level array: the top-level array keeps pointers to the
* second-level arrays, which in turn keep pointers to the line starts.
* The second-level arrays are fixed-size, so it's a simple calculation
* to determine which second-level array contains a given index, and the
* offset of the line within the second-level array. On storing a new
* item, we ensure that the array is large enough to hold the item, so
* the caller is not responsible for doing any initialization or bounds
* checking on storing a value. However, note that we don't check items
* on retrieval to ensure that they're within bounds or have been
* initialized; the caller is responsible for checking that items
* retrieved have actually been stored.
*/
const int HTML_LINE_START_PAGESIZE = 1024; /* pointers in a 2nd-level page */
const int HTML_LINE_START_SHIFT = 10; /* log2(pagesize) */
struct CHtmlLineStartEntry
{
long ypos;
class CHtmlDisp *disp;
};
/*
* line start searcher class
*/
class CHtmlLineStartSearcher
{
public:
virtual ~CHtmlLineStartSearcher() {}
/*
* true -> the item we're seeking is between the two given items; b
* == 0 means that a is the last entry
*/
virtual int is_between(const CHtmlLineStartEntry *a,
const CHtmlLineStartEntry *b) const = 0;
/*
* true -> item is too low - we're looking for something higher
*/
virtual int is_low(const CHtmlLineStartEntry *item) const = 0;
};
class CHtmlLineStarts
{
public:
CHtmlLineStarts();
~CHtmlLineStarts();
/* add an entry at a given index with a given line start position */
void add(long index, class CHtmlDisp *item, long y);
/* get an entry at a given index */
class CHtmlDisp *get(long index) const
{
return (index >= count_ ? 0 : get_internal(index)->disp);
}
/* get the y position of a line */
long get_ypos(long index) const
{
return (index >= count_ ? 0 : get_internal(index)->ypos);
}
/* change the y position of a line */
void set_ypos(long index, long ypos)
{
if (index < count_)
get_internal(index)->ypos = ypos;
}
/* forget about all of our entries */
void clear_count() { count_ = 0; }
/* get the current count of line starts */
long get_count() const { return count_; }
/* restore the count to a setting previously noted with get_count */
void restore_count(long count) { count_ = count; }
/*
* Get the index of the entry that contains a given y offset. This
* will find the entry with the greatest y offset less than or equal
* to the given y offset.
*/
long find_by_ypos(long ypos) const;
/*
* Get the index of the entry that contains a given text offset
*/
long find_by_txtofs(unsigned long txtofs) const;
/*
* Get the index of the entry at the given debugger source file
* position. This is used only for debug source windows.
*/
long find_by_debugsrcpos(unsigned long srcfpos) const;
/*
* General finder routine, using the given searcher to determine the
* ordering. Performs a binary search of our line start array using
* the given searcher, and returns the index of the item we found.
*/
long find(const CHtmlLineStartSearcher *searcher) const;
private:
/* get the internal entry for an item */
CHtmlLineStartEntry *get_internal(long index) const
{
unsigned int page;
unsigned int offset;
calc_location(index, &page, &offset);
return *(pages_ + page) + offset;
}
/*
* calculate the second-level array containing the item, and the
* item's index within the second-level array
*/
void calc_location(long index, unsigned int *page,
unsigned int *offset) const
{
*page = (unsigned int)(index >> HTML_LINE_START_SHIFT);
*offset = (unsigned int)(index & (HTML_LINE_START_PAGESIZE - 1));
}
/* ensure that a particular page is allocated */
void ensure_page(unsigned int page);
/* the top-level array */
CHtmlLineStartEntry **pages_;
/* size of the top-level array */
size_t top_pages_allocated_;
/* number of second-level pages allocated */
size_t second_pages_allocated_;
/*
* number of items stored so far (actually, the maximum index plus
* one, since the caller may not fill in all items)
*/
long count_;
};
/* ------------------------------------------------------------------------ */
/*
* Flow-around item stack. A flow-around item is an item in the left or
* right margin that text flows around. To control the text, we
* increase the margins temporarily, until we get past the bottom of the
* object in the margin. This stack tracks the objects that we're
* currently flowing text around; there's one of these for each margin.
*/
/* flow stack item */
class CHtmlFmtFlowStkItem
{
public:
/*
* margin setting in effect before this item was pushed, stored as a
* delta from the new margin set for the item
*/
long old_margin_delta;
/* y position of bottom of this flow item */
long bottom;
/*
* table active when stack position was entered - we cannot leave this
* stack level unless this same table is active
*/
class CHtmlTagTABLE *cur_table;
};
/* flow stack */
class CHtmlFmtFlowStack
{
public:
CHtmlFmtFlowStack()
{
/* nothing on the stack yet */
sp = 0;
}
/* push the current margins */
void push(long old_margin_delta, long bottom,
class CHtmlTagTABLE *cur_table);
/* get the item at the top of the stack */
const CHtmlFmtFlowStkItem *get_top() const { return &stk[sp - 1]; }
/* determine if there's anything on the stack */
int is_empty() const { return sp == 0; }
/* pop the top item */
void pop();
/* determine if we're past the end of the item at the top of the stack */
int is_past_end(long ypos, class CHtmlTagTABLE *cur_table) const;
/*
* determine if it's legal to end this item, based on the current
* table nesting level
*/
int can_end_item(const CHtmlFmtFlowStkItem *item,
const class CHtmlTagTABLE *cur_table) const;
/* determine if it's legal to end an item given its index */
int can_end_item(int index, class CHtmlTagTABLE *cur_table) const
{ return can_end_item(get_by_index(index), cur_table); }
/* determine if we can end the top item */
int can_end_top_item(class CHtmlTagTABLE *cur_table) const
{ return !is_empty() && can_end_item(get_top(), cur_table); }
/* get the number of items on the stack */
int get_count() const { return sp; }
/*
* get an item at an index from the top - 0 is the top, 1 is the
* next item, and so on
*/
const CHtmlFmtFlowStkItem *get_by_index(int index) const
{ return &stk[sp - index - 1]; }
/* reset - discard all items */
void reset() { sp = 0; }
private:
/* stack pointer */
size_t sp;
/* stack */
CHtmlFmtFlowStkItem stk[100];
};
/*
* Table formatting environment snapshot. This records the necessary
* information to resume formatting after finishing with a floating table.
*/
class CHtmlFmtTableEnvSave
{
public:
/* left/right stack depths */
int left_count;
int right_count;
/* left/right margin settings at the current stack level */
long margin_left;
long margin_right;
/* output position and status */
CHtmlDisp *disp_tail;
CHtmlDisp *line_head;
long max_line_width;
long avail_line_width;
CHtmlPoint curpos;
int line_spacing;
long line_count;
long line_id;
long line_starts_count;
int last_was_newline : 1;
};
/* maximum table environment save depth */
const size_t CHTMLFMT_TABLE_ENV_SAVE_MAX = 20;
/* ------------------------------------------------------------------------ */
/*
* formatter heap page structure
*/
struct CHtmlFmt_heap_page_t
{
unsigned char *mem;
size_t siz;
};
/* ------------------------------------------------------------------------ */
/*
* Display item factory. Certain types of display items come in
* linkable and unlinkable varieties. When we're in a link, we need to
* create a linkable type, and at other times we need to create the
* normal unlinkable kind. To simplify and centralize these decisions,
* we maintain a display item factory that creates the appropriate types
* of objects. The current item factory should always be used when
* creating an object; it will create the appropriate type of objects
* for the current context. Note that most display items are not
* linkable at all, so there's no need to go through the factory -- it's
* only needed where both linkable and unlinkable types exist.
*/
class CHtmlFmtDispFactory
{
public:
CHtmlFmtDispFactory(class CHtmlFormatter *formatter)
{
formatter_ = formatter;
}
virtual ~CHtmlFmtDispFactory() {}
/* create a text display item */
virtual CHtmlDisp *new_disp_text(class CHtmlSysWin *win,
class CHtmlSysFont *font,
const textchar_t *txt, size_t txtlen,
unsigned long txtofs) = 0;
/* create an input-editor text display item */
virtual class CHtmlDispTextInput *new_disp_text_input(
class CHtmlSysWin *win, class CHtmlSysFont *font,
const textchar_t *txt, size_t txtlen, unsigned long txtofs) = 0;
/* create a soft-hyphen display item */
virtual class CHtmlDisp *new_disp_soft_hyphen(
class CHtmlSysWin *win, class CHtmlSysFont *font,
const textchar_t *txt, size_t txtlen, unsigned long txtofs) = 0;
/* create a non-breaking space display item */
virtual class CHtmlDisp *new_disp_nbsp(
class CHtmlSysWin *win, class CHtmlSysFont *font,
const textchar_t *txt, size_t txtlen, unsigned long txtofs) = 0;
/* create an special typographical space display item */
virtual class CHtmlDisp *new_disp_space(
class CHtmlSysWin *win, class CHtmlSysFont *font,
const textchar_t *txt, size_t txtlen, unsigned long txtofs,
int wid, int pre) = 0;
/* create a pre-formatted text display item */
virtual CHtmlDisp *new_disp_text_pre(class CHtmlSysWin *win,
class CHtmlSysFont *font,
const textchar_t *txt,
size_t txtlen,
unsigned long txtofs) = 0;
/* create a debugger-window text display item */
virtual CHtmlDisp *new_disp_text_debug(class CHtmlSysWin *win,
class CHtmlSysFont *font,
const textchar_t *txt,
size_t txtlen,
unsigned long txtofs,
unsigned long linenum) = 0;
/* create an image display item */
virtual class CHtmlDispImg *new_disp_img(
class CHtmlSysWin *win, class CHtmlResCacheObject *image,
CStringBuf *alt, HTML_Attrib_id_t align, long hspace, long vspace,
long width, int width_set, long height, int height_set,
long border, class CHtmlUrl *usemap, int ismap) = 0;
protected:
class CHtmlFormatter *formatter_;
};
/* ------------------------------------------------------------------------ */
/*
* Formatter
*/
/* maximum depth of margin stack */
const int MARGIN_STACK_DEPTH_MAX = 20;
class CHtmlFormatter
{
public:
CHtmlFormatter(class CHtmlParser *parser);
virtual ~CHtmlFormatter();
/*
* get/set T3 mode - this indicates that our caller is a T3 program,
* which changes certain parsing rules
*/
int is_t3_mode() const { return t3_mode_; }
void set_t3_mode(int f) { t3_mode_ = f; }
/*
* receive notification that the parser is about to be deleted; we
* must release any references we have to the parser or the format
* tag list (which is owned by the parser, so will be deleted when
* the parser is deleted).
*/
virtual void release_parser()
{
/* forget the parser */
parser_ = 0;
}
/* set my window and the physical margins to use */
virtual void set_win(class CHtmlSysWin *win, const CHtmlRect *r);
/*
* Receive notification that my window is being deleted. By
* default, I'll just forget the window.
*/
virtual void unset_win();
/* get my window pointer */
class CHtmlSysWin *get_win() const { return win_; }
/* invalidate the whole window area */
void inval_window();
/* get the special BODY display item */
class CHtmlDispBody *get_body_disp() const{ return body_disp_; }
/* get the resource cache (a global singleton) */
static class CHtmlResCache *get_res_cache() { return res_cache_; }
/* get the resource finder (a global singleton) */
static class CHtmlResFinder *get_res_finder() { return res_finder_; }
/* play a sound */
void play_sound(class CHtmlTagSOUND *tag,
HTML_Attrib_id_t layer,
class CHtmlResCacheObject *res,
int repeat_count, int random_start,
HTML_Attrib_id_t sequence);
/*
* Stop all sounds in the given layer. 'fade_out' gives the fade time:
* if zero, it means that we should cancel sounds immediately,
* otherwise the sounds should be faded out over the given interval in
* seconds. If 'fade_in_background' is set, the fade should happen in
* the background, so that new sounds can start playing in the layer
* concurrently with the fade; otherwise the layer should remain
* occupied until the fade is finished, at which point the next sound
* in the layer's queue can begin.
*/
virtual void cancel_sound(HTML_Attrib_id_t layer, double fade_out,
int fade_in_background, int sync);
/* terminate all active playback (such as animations) */
void cancel_playback();
/* get/set the last sound tag */
virtual class CHtmlTagSOUND *get_last_sound_tag() const = 0;
virtual void set_last_sound_tag(class CHtmlTagSOUND *tag) = 0;
/* do we allow <SOUND> tags in this window? */
virtual int allow_sound_tags() const = 0;
/*
* Flush the text buffer. By default, we do nothing, since the basic
* formatter doesn't own its own text buffer. This can be overridden
* for formatter subclasses that do own an independent text buffer.
*/
virtual void flush_txtbuf(int /*fmt*/) { }
/*
* Add an extra line's worth of vertical whitespace to the display
* height, beyond what's strictly needed for the layout. This can be
* used to provide visual feedback after a user presses Enter at the
* end of an input line. We simply add one line height worth of space
* to the display height and refigure the scrollbar positions, which
* will generally cause the display window to scroll one line.
*/
void add_line_to_disp_height();
/*
* Set the "physical" margins. The window should call this if it
* wants to specify an inset from the window coordinates, to provide
* some whitespace around the edges of the window. The bottom and
* right coordinates in the rectangle are inset amounts, so they
* will usually be small positive numbers (.right probably will
* equal .left). Note that the window generally won't need to
* change this after it's initially set up, which happens when it
* plugs in to the formatter with set_win().
*/
void set_phys_margins(const CHtmlRect *r);
/* get the physical margin settings */
CHtmlRect get_phys_margins() const { return phys_margins_; }
/* set the physical margins */
void set_phys_margins(long left, long top, long right, long bottom)
{ phys_margins_.set(left, top, right, bottom); }
/*
* Re-start rendering at the top of the document. This should be
* called whenever the current formatting becomes invalid, such as
* when the window is resized horizontally.
*
* If reset_sounds is true, we'll stop all currently playing sounds
* and start over with the <SOUND> tags that we encounter in the
* course of formatting the page. If reset_sounds is false, we'll
* leave current sounds playing and ignore all <SOUND> tags that we
* encounter. reset_sounds should be false whenever we're
* reformatting the current page (for example, after resizing the
* window or changing the default font size), and should be true
* when switching to a new page.
*/
virtual void start_at_top(int reset_sounds);
/*
* Do some more formatting. This routine does a little work and
* then returns, so that an interactive program can check for events
* and respond to user actions while formatting is in progress. A
* non-interactive program can simply call this routine repeatedly
* as long as more_to_do() returns true. An interactive program can
* monitor the progress of the formatting with getcurpos();
* normally, an interactive program will want to do formatting until
* it has enough to fill the current window (or until the formatting
* is done, whichever comes first), then process user events while
* formatting any additional text in the background, since further
* text is out of view at the moment.
*/
void do_formatting();
/* do we have more rendering left to do? */
int more_to_do();
/* get the current rendering position */
CHtmlPoint getcurpos() const { return curpos_; }
/*
* get the maximum y position so far (i.e., the display height of the
* page)
*/
unsigned long get_max_y_pos() const { return disp_max_y_pos_; }
/* get the maximum y position assigned to a layout item so far */
unsigned long get_layout_max_y_pos() const { return layout_max_y_pos_; }
/*
* Increase the page height by a given amount (which can be negative
* to decrease the position). This should be used only for temporary
* adjustments to the scrolling area during times when new text won't
* be added, since the new y position will affect future text
* formatting if not undone.
*/
void inc_max_y_pos(long amount) { disp_max_y_pos_ += amount; }
/*
* Add an item to the tail of the display list, adjust the current
* line under construction to compensate for the new item.
*/
virtual void add_disp_item(class CHtmlDisp *item);
/*
* Add a link display item. To enter a hypertext link (<A HREF>),
* create a link item and call this routine. Subsequent linkable
* items will refer back to this link object. Call end_link() when
* the matching </A> is reached.
*/
void add_disp_item_link(class CHtmlDispLink *link);
/* end the current link (opened with add_disp_item_link()) */
void end_link();
/*
* Get/set character-wrapping mode. The default is word-wrap mode;
* when character-wrap mode is off, word-wrap mode is selected.
*/
int is_char_wrap_mode() const { return char_wrap_mode_; }
void set_char_wrap_mode(int f)
{
/* remember the new wrap mode */
char_wrap_mode_ = f;
/* set the correct factory based on the new mode */
adjust_disp_factory();
}
/* get the current link item */
class CHtmlDispLink *get_cur_link() const { return cur_link_; }
/* get the current display item factory */
CHtmlFmtDispFactory *get_disp_factory() const
{ return cur_disp_factory_; }
/*
* Add an item to the tail of the display list, replacing the
* current command input display item(s), if any. This is used
* during editing of a command line to update the display after the
* user has made a change in the contents of the command line.
* Default formatters are not input-capable, so we simply add the
* display item as though it were any other display item.
* Input-capable formatter subclasses should override this to
* provide proper input editing formatting.
*/
virtual void add_disp_item_input(class CHtmlDispTextInput *item,
class CHtmlTagTextInput *);
/*
* Add a display item that floats to the left or right margin with
* text flowing around it. We can't add this type of item
* immediately; instead, we need to wait until we start a new line,
* at which point we can add the item and adjust the margins so that
* text flows around the item. This routine adds the item to an
* internal list of items to be deferred until the start of the next
* line.
*/
void add_disp_item_deferred(class CHtmlDisp *item);
/* Add an item, starting a new line with the item */
void add_disp_item_new_line(class CHtmlDisp *item);
/* Add an item, starting a new line immediately after the item. */
void add_disp_item_new_line_after(class CHtmlDisp *item);
/* Add a <DIV> */
void begin_div(class CHtmlDispDIV *div);
/* end the current <DIV> */
void end_div();
/* define a tab stop at the current position */
void set_tab(const textchar_t *tab_id, HTML_Attrib_id_t align,
textchar_t dp);
/* tab to a previously-defined tab stop */
void tab_to(class CHtmlTagTAB *tag);
/*
* Add minimum line spacing. This makes sure that we're starting a
* new line, and that the line spacing for the new line is at least
* as much as requested. If we're already on a new line and have
* provided the requested amount of inter-line spacing, this doesn't
* do anything.
*/
void add_line_spacing(int spacing);
/*
* Add vertical whitespace as needed to move past floating items in
* one or both margins. Returns true if any line spacing was added,
* false if not.
*/
int break_to_clear(int left, int right);
/* get current font */
class CHtmlSysFont *get_font() const { return curfont_; }
/* set a new font */
void set_font(class CHtmlSysFont *font) { curfont_ = font; }
/* get/set the current base font size */
int get_font_base_size() const { return font_base_size_; }
void set_font_base_size(int siz) { font_base_size_ = siz; }
/*
* Draw everything in a given area. If clip_lines is false, we'll
* draw the last line even if it doesn't fit entirely in the area,
* otherwise we'll stop when we reach a line that doesn't entirely
* fit. If clip_lines is true, we'll return in clip_y the y
* position of the first line we didn't draw.
*/
void draw(const CHtmlRect *area, int clip_lines, long *clip_y);
/*
* Invalidate links that are visible on the screen. This is used to
* quickly redraw the window's links (and only its links) for a
* short-term change in the link visibility state. This can be used
* to implement a mode where links are highlighted only if a key is
* held down.
*/
void inval_links_on_screen(const CHtmlRect *area);
/* invalidate the display area occupied by the selected text */
void inval_sel_range()
{
/* if the selection range isn't empty, invalidate it */
if (sel_start_ != sel_end_)
inval_offset_range(sel_start_, sel_end_);
}
/* get the maximum line width */
long get_max_line_width() const { return max_line_width_; }
/*
* Get the maximum line width at the outer level. If we're inside a
* table, we'll return the outermost enclosing max line width;
* otherwise, we'll return the current maximum line width. The
* outer maximum line width is useful for calculating the horizontal
* scrollbar range; the current line width is not interesting for
* scrollbars if it is ultimately wrapped within a table.
*/
long get_outer_max_line_width() const { return outer_max_line_width_; }