summaryrefslogtreecommitdiffstats
path: root/tkhtml1/src
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2019-01-07 19:38:48 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2019-01-07 19:38:48 (GMT)
commitf946ccfb35b2c144c4bb456d5fe9b48c1b8ae524 (patch)
tree2d357dd61ade976b7beb5bfe9085027d3478bfb3 /tkhtml1/src
parent917eac6db5489b4256a4ba42d89df60e80906894 (diff)
parentd24f03b3877861780be79b1a620adae80b942c3c (diff)
downloadblt-f946ccfb35b2c144c4bb456d5fe9b48c1b8ae524.zip
blt-f946ccfb35b2c144c4bb456d5fe9b48c1b8ae524.tar.gz
blt-f946ccfb35b2c144c4bb456d5fe9b48c1b8ae524.tar.bz2
Merge commit 'd24f03b3877861780be79b1a620adae80b942c3c' as 'tkhtml1'
Diffstat (limited to 'tkhtml1/src')
-rw-r--r--tkhtml1/src/html.h1011
-rw-r--r--tkhtml1/src/htmlcmd.c735
-rw-r--r--tkhtml1/src/htmlcmd.h498
-rw-r--r--tkhtml1/src/htmldraw.c877
-rw-r--r--tkhtml1/src/htmldraw.h483
-rw-r--r--tkhtml1/src/htmlexts.c110
-rw-r--r--tkhtml1/src/htmlexts.h438
-rw-r--r--tkhtml1/src/htmlform.c606
-rw-r--r--tkhtml1/src/htmlform.h484
-rw-r--r--tkhtml1/src/htmlimage.c225
-rw-r--r--tkhtml1/src/htmlimage.h467
-rw-r--r--tkhtml1/src/htmlindex.c505
-rw-r--r--tkhtml1/src/htmlindex.h450
-rw-r--r--tkhtml1/src/htmllayout.c1170
-rw-r--r--tkhtml1/src/htmllayout.h565
-rw-r--r--tkhtml1/src/htmlparse.c1181
-rw-r--r--tkhtml1/src/htmlparse.h488
-rw-r--r--tkhtml1/src/htmlsizer.c1176
-rw-r--r--tkhtml1/src/htmlsizer.h636
-rw-r--r--tkhtml1/src/htmltable.c1175
-rw-r--r--tkhtml1/src/htmltable.h543
-rw-r--r--tkhtml1/src/htmltest.c122
-rw-r--r--tkhtml1/src/htmltest.h44
-rw-r--r--tkhtml1/src/htmltokens.c318
-rw-r--r--tkhtml1/src/htmltokens.h590
-rw-r--r--tkhtml1/src/htmlurl.c402
-rw-r--r--tkhtml1/src/htmlurl.h457
-rw-r--r--tkhtml1/src/htmlwidget.c2043
-rw-r--r--tkhtml1/src/htmlwidget.h562
-rw-r--r--tkhtml1/src/tokenlist.txt116
30 files changed, 18477 insertions, 0 deletions
diff --git a/tkhtml1/src/html.h b/tkhtml1/src/html.h
new file mode 100644
index 0000000..55f44cd
--- /dev/null
+++ b/tkhtml1/src/html.h
@@ -0,0 +1,1011 @@
+/*
+** Structures and typedefs used by the HTML widget
+** $Revision$
+**
+** Copyright (C) 1997-2000 D. Richard Hipp
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** drh@acm.org
+** http://www.hwaci.com/drh/
+*/
+
+/*
+** Debug must be turned on for testing to work.
+*/
+#define DEBUG 1
+
+/*
+** Sanity checking macros.
+*/
+#ifdef DEBUG
+#define HtmlAssert(X) \
+ if(!(X)){ \
+ fprintf(stderr,"Assertion failed on line %d of %s\n",__LINE__,__FILE__); \
+ }
+#define HtmlCantHappen \
+ fprintf(stderr,"Can't happen on line %d of %s\n",__LINE__,__FILE__);
+#else
+#define HtmlAssert(X)
+#define HtmlCantHappen
+#endif
+
+/*
+** The TRACE macro is used to print internal information about the
+** HTML layout engine during testing and debugging. The amount of
+** information printed is governed by a global variable named
+** HtmlTraceMask. If bits in the first argument to the TRACE macro
+** match any bits in HtmlTraceMask variable, then the trace message
+** is printed.
+**
+** All of this is completely disabled, of course, if the DEBUG macro
+** is not defined.
+*/
+#ifdef DEBUG
+# define TRACE_INDENT printf("%*s",HtmlDepth-3,"")
+# define TRACE(Flag, Args) \
+ if( (Flag)&HtmlTraceMask ){ \
+ TRACE_INDENT; printf Args; fflush(stdout); \
+ }
+# define TRACE_PUSH(Flag) if( (Flag)&HtmlTraceMask ){ HtmlDepth+=3; }
+# define TRACE_POP(Flag) if( (Flag)&HtmlTraceMask ){ HtmlDepth-=3; }
+#else
+# define TRACE_INDENT
+# define TRACE(Flag, Args)
+# define TRACE_PUSH(Flag)
+# define TRACE_POP(Flag)
+#endif
+
+/*
+** Bitmasks for the HtmlTraceMask global variable
+*/
+#define HtmlTrace_Table1 0x00000001
+#define HtmlTrace_Table2 0x00000002
+#define HtmlTrace_Table3 0x00000004
+#define HtmlTrace_Table4 0x00000008
+#define HtmlTrace_Table5 0x00000010
+#define HtmlTrace_Table6 0x00000020
+#define HtmlTrace_GetLine 0x00000100
+#define HtmlTrace_GetLine2 0x00000200
+#define HtmlTrace_FixLine 0x00000400
+#define HtmlTrace_BreakMarkup 0x00001000
+#define HtmlTrace_Style 0x00002000
+#define HtmlTrace_Input1 0x00004000
+
+
+/*
+** Macros to allocate and free memory.
+*/
+/*#define HtmlAlloc(A) ((void*)Tcl_Alloc(A))*/
+void* HtmlAlloc(size_t);
+#define HtmlFree(A) Tcl_Free((char*)(A))
+#define HtmlRealloc(A,B) ((void*)Tcl_Realloc((A),(B)))
+
+/*
+** Various data types. This code is designed to run on a modern
+** cached architecture where the CPU runs a lot faster than the
+** memory bus. Hence we try to pack as much data into as small a space
+** as possible so that it is more likely to fit in cache. The
+** extra CPU instruction or two needed to unpack the data is not
+** normally an issue since we expect the speed of the memory bus
+** to be the limiting factor.
+*/
+typedef unsigned char Html_u8; /* 8-bit unsigned integer */
+typedef short Html_16; /* 16-bit signed integer */
+typedef unsigned short Html_u16; /* 16-bit unsigned integer */
+typedef int Html_32; /* 32-bit signed integer */
+
+/*
+** An instance of the following structure is used to record style
+** information on each Html element.
+*/
+struct HtmlStyle {
+ unsigned int font : 6; /* Font to use for display */
+ unsigned int color : 4; /* Foreground color */
+ signed int subscript : 4; /* Positive for <sup>, negative for <sub> */
+ unsigned int align : 2; /* Horizontal alignment */
+ unsigned int bgcolor : 4; /* Background color */
+ unsigned int flags : 12; /* the STY_ flags below */
+}
+
+/*
+** We allow 8 different font families: Normal, Bold, Italic and
+** Bold-Italic in either variable or constant width.
+** Within each family there can be up to 7 font sizes from 1
+** (the smallest) up to 7 (the largest). Hence, the widget can use
+** a maximum of 56 fonts. The ".font" field of the style is an integer
+** between 0 and 55 which indicates which font to use.
+*/
+#define N_FONT_FAMILY 8
+#define N_FONT_SIZE 7
+#define N_FONT (N_FONT_FAMILY*N_FONT_SIZE)
+#define NormalFont(X) (X)
+#define BoldFont(X) ((X)+N_FONT_SIZE)
+#define ItalicFont(X) ((X)+2*N_FONT_SIZE)
+#define CWFont(X) ((X)+4*N_FONT_SIZE)
+#define FontSize(X) ((X)%N_FONT_SIZE)
+#define FontFamily(X) (((X)/N_FONT_SIZE)*N_FONT_SIZE)
+#define FONT_Any -1
+#define FONT_Default 3
+#define FontSwitch(Size, Bold, Italic, Cw) \
+ ((Size)+(Bold+(Italic)*2+(Cw)*4)*N_FONT_SIZE)
+
+/*
+** Macros for manipulating the fontValid bitmap of an HtmlWidget structure.
+*/
+#define FontIsValid(H,I) (((H)->fontValid[(I)>>3] & (1<<((I)&3)))!=0)
+#define FontSetValid(H,I) ((H)->fontValid[(I)>>3] |= (1<<((I)&3)))
+#define FontClearValid(H,I) ((H)->fontValid[(I)>>3] &= ~(1<<((I)&3)))
+
+/*
+** Information about available colors.
+**
+** The widget will use at most N_COLOR colors. 4 of these colors
+** are predefined. The rest are user selectable by options to
+** various markups. (Ex: <font color=red>)
+**
+** All colors are stored in the apColor[] array of the main widget
+** structure. The ".color" field of the HtmlStyle is an integer
+** between 0 and N_COLOR-1 which indicates which of these colors
+** to use.
+*/
+#define N_COLOR 16 /* Total number of colors */
+#define COLOR_Normal 0 /* Index for normal color (black) */
+#define COLOR_Unvisited 1 /* Index for unvisited hyperlinks */
+#define COLOR_Visited 2 /* Color for visited hyperlinks */
+#define COLOR_Selection 3 /* Background color for the selection */
+#define COLOR_Background 4 /* Default background color */
+#define N_PREDEFINED_COLOR 5 /* Number of predefined colors */
+
+/*
+** The "align" field of the style determines how text is justified
+** horizontally. ALIGN_None means that the alignment is not specified.
+** (It should probably default to ALIGN_Left in this case.)
+*/
+#define ALIGN_Left 1
+#define ALIGN_Right 2
+#define ALIGN_Center 3
+#define ALIGN_None 0
+
+/*
+** Possible value of the "flags" field of HtmlStyle are shown below.
+**
+** STY_Preformatted If set, the current text occurred within
+** <pre>..</pre>
+**
+** STY_StrikeThru Draw a solid line thru the middle of this text.
+**
+** STY_Underline This text should drawn with an underline.
+**
+** STY_NoBreak This text occurs within <nobr>..</nobr>
+**
+** STY_Anchor This text occurs within <a href=X>..</a>.
+**
+** STY_DT This text occurs within <dt>..</dt>.
+**
+** STY_Invisible This text should not appear in the main HTML
+** window. (For example, it might be within
+** <title>..</title> or <marquee>..</marquee>.)
+*/
+#define STY_Preformatted 0x001
+#define STY_StrikeThru 0x002
+#define STY_Underline 0x004
+#define STY_NoBreak 0x008
+#define STY_Anchor 0x010
+#define STY_DT 0x020
+#define STY_Invisible 0x040
+#define STY_FontMask (STY_StrikeThru|STY_Underline)
+
+/*
+** The first thing done with input HTML text is to parse it into
+** HtmlElements. All sizing and layout is done using these elements,
+** so this is a very important structure.
+**
+** Elements are designed so that the common ones (Text and Space)
+** require as little storage as possible, in order to increase
+** the chance of memory cache hits. (Turns out I didn't do a
+** very good job of this. This widget is a pig for memory. But
+** the speed is good, so I'm not going to change it right now...)
+**
+** Some elements require more memory than Text and Space (ex: <IMG>).
+** An HtmlElement is therefore represented as a union of many other
+** structures all of different sizes. That way we can have a pointer
+** to a generic element without having to worry about how big that
+** element is. The ".base.type" field (which is found in all elements)
+** will tell us what type of element we are dealing with.
+**
+** NOTE: This trick will only work on compilers that align all elements
+** of a union to the lowest memory address in that union. This is true
+** for every C compiler I've ever seen, but isn't guarenteed for ANSI-C.
+*/
+union HtmlElement {
+ HtmlElement *pNext;
+ HtmlBaseElement base;
+ HtmlTextElement text;
+ HtmlSpaceElement space;
+ HtmlMarkupElement markup;
+ HtmlCell cell;
+ HtmlTable table;
+ HtmlRef ref;
+ HtmlLi li;
+ HtmlListStart list;
+ HtmlImageMarkup image;
+ HtmlInput input;
+ HtmlForm form;
+ HtmlHr hr;
+ HtmlAnchor anchor;
+ HtmlScript script;
+ HtmlBlock block;
+};
+
+/*
+** Every element contains at least this much information:
+*/
+struct HtmlBaseElement {
+ HtmlElement *pNext; /* Next input token in a list of them all */
+ HtmlElement *pPrev; /* Previous token in a list of them all */
+ HtmlStyle style; /* The rendering style for this token */
+ Html_u8 type; /* The token type. */
+ Html_u8 flags; /* The HTML_ flags below */
+ Html_16 count; /* Various uses, depending on "type" */
+};
+
+/*
+** Bitmasks for the "flags" field of the HtmlBaseElement
+*/
+#define HTML_Visible 0x01 /* This element produces "ink" */
+#define HTML_NewLine 0x02 /* type==Html_Space and ends with newline */
+#define HTML_Selected 0x04 /* Some or all of this Html_Block is selected */
+ /* Used by Html_Block elements only. */
+
+/*
+** Each text element holds additional information as show here. Notice
+** that extra space is allocated so that zText[] will be large enough
+** to hold the complete text of the element. X and y coordinates are
+** relative to the virtual canvas. The y coordinate refers to the
+** baseline.
+*/
+struct HtmlTextElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_32 y; /* y coordinate where text should be rendered */
+ Html_16 x; /* x coordinate where text should be rendered */
+ Html_16 w; /* width of this token in pixels */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_u8 spaceWidth; /* Width of one space in the current font */
+ char zText[1]; /* Text for this element. Null terminated */
+};
+
+/*
+** Each space element is represented like this:
+*/
+struct HtmlSpaceElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_16 w; /* Width of a single space in current font */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+};
+
+/*
+** Most markup uses this structure. Some markup extends this structure
+** with additional information, but most use it as a base, at the very
+** least.
+**
+** If the markup doesn't have arguments (the "count" field of
+** HtmlBaseElement is 0) then the extra "argv" field of this structure
+** is not allocated and should not be used.
+*/
+struct HtmlMarkupElement {
+ HtmlBaseElement base;
+ char **argv;
+};
+
+/* Each <td> or <th> markup is represented by an instance of the
+** following structure.
+**
+** Drawing for a cell is a sunken 3D border with the border width given
+** by the borderWidth field in the associated <table> structure.
+*/
+struct HtmlCell {
+ HtmlMarkupElement markup;
+ Html_16 rowspan; /* Number of rows spanned by this cell */
+ Html_16 colspan; /* Number of columns spanned by this cell */
+ Html_16 x; /* X coordinate of left edge of border */
+ Html_16 w; /* Width of the border */
+ Html_32 y; /* Y coordinate of top of border indentation */
+ Html_32 h; /* Height of the border */
+ HtmlElement *pTable; /* Pointer back to the <table> */
+ HtmlElement *pEnd; /* Element that ends this cell */
+};
+
+/*
+** The maximum number of columns allowed in a table. Any columns beyond
+** this number are ignored.
+*/
+#define HTML_MAX_COLUMNS 40
+
+/*
+** This structure is used for each <table> element.
+**
+** In the minW[] and maxW[] arrays, the [0] element is the overall
+** minimum and maximum width, including cell padding, spacing and
+** the "hspace". All other elements are the minimum and maximum
+** width for the contents of individual cells without any spacing or
+** padding.
+*/
+struct HtmlTable {
+ HtmlMarkupElement markup;
+ Html_u8 borderWidth; /* Width of the border */
+ Html_u8 nCol; /* Number of columns */
+ Html_u16 nRow; /* Number of rows */
+ Html_32 y; /* top edge of table border */
+ Html_32 h; /* height of the table border */
+ Html_16 x; /* left edge of table border */
+ Html_16 w; /* width of the table border */
+ int minW[HTML_MAX_COLUMNS+1]; /* minimum width of each column */
+ int maxW[HTML_MAX_COLUMNS+1]; /* maximum width of each column */
+};
+
+/* This structure is used for </table>, </td>, <tr>, </tr>
+** and </th> elements. It points back to the <table> element
+** that began the table. It is also used by </a> to point back
+** to the original <a>. I'll probably think of other uses before
+** all is said and done...
+*/
+struct HtmlRef {
+ HtmlMarkupElement markup;
+ HtmlElement *pOther; /* Pointer to some other Html element */
+};
+
+/*
+** An instance of the following structure is used to represent
+** each <LI> markup.
+*/
+struct HtmlLi {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* What type of list is this? */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_16 cnt; /* Value for this element (if inside <OL>) */
+ Html_16 x; /* X coordinate of the bullet */
+ Html_32 y; /* Y coordinate of the bullet */
+};
+
+/*
+** The .type field of an HtmlLi or HtmlListStart structure can take on
+** any of the following values to indicate what type of bullet to draw.
+** The value in HtmlLi will take precedence over the value in HtmlListStart
+** if the two values differ.
+*/
+#define LI_TYPE_Undefined 0 /* If in HtmlLi, use the HtmlListStart value */
+#define LI_TYPE_Bullet1 1 /* A solid circle */
+#define LI_TYPE_Bullet2 2 /* A hollow circle */
+#define LI_TYPE_Bullet3 3 /* A hollow square */
+#define LI_TYPE_Enum_1 4 /* Arabic numbers */
+#define LI_TYPE_Enum_A 5 /* A, B, C, ... */
+#define LI_TYPE_Enum_a 6 /* a, b, c, ... */
+#define LI_TYPE_Enum_I 7 /* Capitalized roman numerals */
+#define LI_TYPE_Enum_i 8 /* Lower-case roman numerals */
+
+/*
+** An instance of this structure is used for <UL> or <OL>
+** markup.
+*/
+struct HtmlListStart {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* One of the LI_TYPE_ defines above */
+ Html_u8 compact; /* True if the COMPACT flag is present */
+ Html_u16 cnt; /* Next value for <OL> */
+ Html_u16 width; /* How much space to allow for indentation */
+ HtmlElement *pPrev; /* Next higher level list, or NULL */
+};
+
+/*
+** Information about each image on the HTML widget is held in an
+** instance of the following structure. A pointer to this structure
+** is the clientData for the image change callback. All image structures
+** are held on a list attached to the main widget structure.
+**
+** This structure is NOT an element. The <IMG> element is represented
+** by an HtmlImageMarkup structure below. There is one HtmlImageMarkup
+** for each <IMG> in the source HTML. There is one of these structures
+** for each unique image loaded. (If two <IMG> specify the same image,
+** there are still two HtmlImageMarkup structures but only one
+** HtmlImage structure that is shared between them.)
+*/
+struct HtmlImage {
+ HtmlWidget *htmlPtr; /* The owner of this image */
+ Tk_Image image; /* The Tk image token */
+ Html_32 w; /* Requested width of this image (0 if none) */
+ Html_32 h; /* Requested height of this image (0 if none) */
+ char *zUrl; /* The URL for this image. */
+ char *zWidth, *zHeight; /* Width and height in the <img> markup. */
+ HtmlImage *pNext; /* Next image on the list */
+ HtmlElement *pList; /* List of all <IMG> markups that use this
+ ** same image */
+};
+
+/* Each <img> markup is represented by an instance of the
+** following structure.
+**
+** If pImage==0, then we use the alternative text in zAlt.
+*/
+struct HtmlImageMarkup {
+ HtmlMarkupElement markup;
+ Html_u8 align; /* Alignment. See IMAGE_ALIGN_ defines below */
+ Html_u8 textAscent; /* Ascent of text font in force at the <IMG> */
+ Html_u8 textDescent; /* Descent of text font in force at the <IMG> */
+ Html_u8 redrawNeeded; /* Need to redraw this image because the image
+ ** content changed. */
+ Html_16 h; /* Actual height of the image */
+ Html_16 w; /* Actual width of the image */
+ Html_16 ascent; /* How far image extends above "y" */
+ Html_16 descent; /* How far image extends below "y" */
+ Html_16 x; /* X coordinate of left edge of the image */
+ Html_32 y; /* Y coordinate of image baseline */
+ char *zAlt; /* Alternative text */
+ HtmlImage *pImage; /* Corresponding HtmlImage structure */
+ HtmlElement *pNext; /* Next markup using the same HtmlImage structure */
+};
+
+/*
+** Allowed alignments for images. These represent the allowed arguments
+** to the "align=" field of the <IMG> markup.
+*/
+#define IMAGE_ALIGN_Bottom 0
+#define IMAGE_ALIGN_Middle 1
+#define IMAGE_ALIGN_Top 2
+#define IMAGE_ALIGN_TextTop 3
+#define IMAGE_ALIGN_AbsMiddle 4
+#define IMAGE_ALIGN_AbsBottom 5
+#define IMAGE_ALIGN_Left 6
+#define IMAGE_ALIGN_Right 7
+
+/*
+** All kinds of form markup, including <INPUT>, <TEXTAREA> and <SELECT>
+** are represented by instances of the following structure.
+**
+** (later...) We also use this for the <APPLET> markup. That way,
+** the window we create for an <APPLET> responds to the HtmlMapControls()
+** and HtmlUnmapControls() function calls. For an <APPLET>, the
+** pForm field is NULL. (Later still...) <EMBED> works just like
+** <APPLET> so it uses this structure too.
+*/
+struct HtmlInput {
+ HtmlMarkupElement markup;
+ HtmlElement *pForm; /* The <FORM> to which this belongs */
+ HtmlElement *pNext; /* Next element in a list of all input elements */
+ Tk_Window tkwin; /* The window that implements this control */
+ HtmlWidget *htmlPtr; /* The whole widget. Needed by geometry callbacks */
+ HtmlElement *pEnd; /* End tag for <TEXTAREA>, etc. */
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 padLeft; /* Extra padding on left side of the control */
+ Html_u8 align; /* One of the IMAGE_ALIGN_xxx types */
+ Html_u8 textAscent; /* Ascent for the current font */
+ Html_u8 textDescent; /* descent for the current font */
+ Html_u8 type; /* What type of input is this? */
+ Html_u8 sized; /* True if this input has been sized already */
+ Html_u16 cnt; /* Used to derive widget name. 0 if no widget */
+};
+
+/*
+** An input control can be one of the following types. See the
+** comment about <APPLET> on the HtmlInput structure insight into
+** INPUT_TYPE_Applet.
+*/
+#define INPUT_TYPE_Unknown 0
+#define INPUT_TYPE_Checkbox 1
+#define INPUT_TYPE_File 2
+#define INPUT_TYPE_Hidden 3
+#define INPUT_TYPE_Image 4
+#define INPUT_TYPE_Password 5
+#define INPUT_TYPE_Radio 6
+#define INPUT_TYPE_Reset 7
+#define INPUT_TYPE_Select 8
+#define INPUT_TYPE_Submit 9
+#define INPUT_TYPE_Text 10
+#define INPUT_TYPE_TextArea 11
+#define INPUT_TYPE_Applet 12
+
+/*
+** There can be multiple <FORM> entries on a single HTML page.
+** Each one must be given a unique number for identification purposes,
+** and so we can generate unique state variable names for radiobuttons,
+** checkbuttons, and entry boxes.
+*/
+struct HtmlForm {
+ HtmlMarkupElement markup;
+ Html_u16 id; /* Unique number assigned to this form */
+};
+
+/*
+** Information used by a <HR> markup
+*/
+struct HtmlHr {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 is3D; /* Is it drawn 3D? */
+};
+
+/*
+** Information used by a <A> markup
+*/
+struct HtmlAnchor {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Top edge for this element */
+};
+
+/*
+** Information about the <SCRIPT> markup. The parser treats <SCRIPT>
+** specially. All text between <SCRIPT> and </SCRIPT> is captured and
+** is pointed to by the zScript field of this structure.
+**
+** Note that zScript is not null-terminated. Instead, zScript just
+** points to a spot in the zText field of the HtmlWidget structure.
+** The nScript field determines how long the script is.
+*/
+struct HtmlScript {
+ HtmlMarkupElement markup;
+ char *zScript; /* Complete text of this script */
+ int nScript; /* Number of characters of text */
+}
+
+/*
+** A block is a single unit of display information. This can be
+** one or more text elements, or the border of table, or an
+** image, etc.
+**
+** Blocks are used to improve display speed and to improve the
+** speed of linear searchs through the token list. A single
+** block will typically contain enough information to display
+** a dozen or more Text and Space elements all with a single
+** call to Tk_DrawChars(). The blocks are linked together on
+** their own list, so we can search them much faster then elements
+** (since there are fewer of them.)
+**
+** Of course, you can construct pathological HTML that has as
+** many Blocks as it has normal tokens. But you haven't lost
+** anything. Using blocks just speeds things up in the common
+** case.
+**
+** Much of the information needed for display is held in the
+** original HtmlElement structures. "base.pNext" points to the first
+** structure in the list which can be used to find the "style"
+** "x" and "y".
+**
+** If n==0, then "base.pNext" might point to a special HtmlElement that
+** defines some other kind of drawing, like <LI> or <IMG> or <INPUT>.
+*/
+struct HtmlBlock {
+ HtmlBaseElement base; /* Superclass. Must be first */
+ char *z; /* Space to hold text when n>0 */
+ int top, bottom; /* Extremes of y coordinates */
+ Html_u16 left, right; /* Left and right boundry of this object */
+ Html_u16 n; /* Number of characters in z[] */
+ HtmlBlock *pPrev, *pNext; /* Linked list of all Blocks */
+};
+
+/*
+** Linux doesn't have a stricmp() function.
+*/
+#ifndef HAVE_STRICMP
+# define stricmp strcasecmp
+# define strnicmp strncasecmp
+#endif
+
+/*
+** A stack of these structures is used to keep track of nested font and
+** style changes. This allows us to easily revert to the previous style
+** when we encounter and end-tag like </em> or </h3>.
+**
+** This stack is used to keep track of the current style while walking
+** the list of elements. After all elements have been assigned a style,
+** the information in this stack is no longer used.
+*/
+struct HtmlStyleStack {
+ HtmlStyleStack *pNext; /* Next style on the stack */
+ int type; /* A markup that ends this style. Ex: Html_EndEM */
+ HtmlStyle style; /* The currently active style. */
+}
+
+/*
+** A stack of the following structures is used to remember the
+** left and right margins within a layout context.
+*/
+struct HtmlMargin {
+ int indent; /* Size of the current margin */
+ int bottom; /* Y value at which this margin expires */
+ int tag; /* Markup that will cancel this margin */
+ HtmlMargin *pNext; /* Previous margin */
+};
+
+/*
+** How much space (in pixels) used for a single level of indentation due
+** to a <UL> or <DL> or <BLOCKQUOTE>, etc.
+*/
+#define HTML_INDENT 36
+
+/*
+** A layout context holds all state information used by the layout
+** engine.
+*/
+struct HtmlLayoutContext {
+ HtmlWidget *htmlPtr; /* The html widget undergoing layout */
+ HtmlElement *pStart; /* Start of elements to layout */
+ HtmlElement *pEnd; /* Stop when reaching this element */
+ int headRoom; /* Extra space wanted above this line */
+ int top; /* Absolute top of drawing area */
+ int bottom; /* Bottom of previous line */
+ int left, right; /* Left and right extremes of drawing area */
+ int pageWidth; /* Width of the layout field, including
+ ** the margins */
+ int maxX, maxY; /* Maximum X and Y values of paint */
+ HtmlMargin *leftMargin; /* Stack of left margins */
+ HtmlMargin *rightMargin; /* Stack of right margins */
+};
+
+/*
+** With 28 different fonts and 16 colors, we could in principle have
+** as many as 448 different GCs. But in practice, a single page of
+** HTML will typically have much less than this. So we won't try to
+** keep all GCs on hand. Instead, We'll keep around the most recently
+** used GCs and allocate new ones as necessary.
+**
+** The following structure is used to build a cache of GCs in the
+** main widget structure.
+*/
+#define N_CACHE_GC 16
+struct GcCache {
+ GC gc; /* The graphics context */
+ Html_u8 font; /* Font used for this context */
+ Html_u8 color; /* Color used for this context */
+ Html_u8 index; /* Index used for LRU replacement */
+};
+
+/*
+** An HtmlIndex is a reference to a particular character within a
+** particular Text or Space token.
+*/
+struct HtmlIndex {
+ HtmlElement *p; /* The token containing the character */
+ int i; /* Index of the character */
+};
+
+/*
+** A single instance of the following structure (together with various
+** other structures to which this structure points) contains complete
+** state information for a single HTML widget. The clientData for
+** the widget command is a pointer to this structure.
+**
+** The HTML widget is really a mega-widget. It consists of two nested
+** windows. The outer window (tkwin) contains the focus highlight border,
+** the 3D border and the padding between the border and the text. All
+** text that results from the HTML is drawn into the clipping window
+** (clipwin). The clipping window is a child of the main
+** window and has the name "x". We have to use a clipping window so
+** that subwindows required by <FORM> will be clipped properly and won't
+** overlap with the borders.
+**
+** Two primary coordinate systems are used in this widget.
+**
+** Window coordinates In this system, (0,0) is the upper left-hand
+** corner of the clipping window. This coordinates
+** apply only to objects which is visible on screen.
+**
+** Virtual canvas The virtual canvas is an imaginary canvas holding
+** the entire document. Typically, part of the
+** virtual canvas will show thru the clipping
+** window to become visible. The mapping from
+** window to virtual canvas coordinates is
+** governed by the "xOffset" and "yOffset" fields
+** of the widget structure.
+**
+**
+*/
+struct HtmlWidget {
+ Tk_Window tkwin; /* The main window for this widget */
+ Tk_Window clipwin; /* The clipping window in which all text is
+ ** rendered. */
+ char *zClipwin; /* Name of the clipping window. */
+ Display *display; /* The X11 Server that contains tkwin */
+ Tcl_Interp *interp; /* The interpreter in which the widget lives */
+ char *zCmdName; /* Name of the command */
+ HtmlElement *pFirst; /* First HTML token on a list of them all */
+ HtmlElement *pLast; /* Last HTML token on the list */
+ int nToken; /* Number of HTML tokens on the list.
+ * Html_Block tokens don't count. */
+ HtmlElement *lastSized; /* Last HTML element that has been sized */
+ HtmlElement *nextPlaced; /* Next HTML element that needs to be
+ * positioned on canvas. */
+ HtmlBlock *firstBlock; /* List of all HtmlBlock tokens */
+ HtmlBlock *lastBlock; /* Last HtmlBlock in the list */
+ HtmlElement *firstInput; /* First <INPUT> element */
+ HtmlElement *lastInput; /* Last <INPUT> element */
+ int nInput; /* The number of <INPUT> elements */
+ int nForm; /* The number of <FORM> elements */
+ int varId; /* Used to construct a unique name for a
+ ** global array used by <INPUT> elements */
+
+ /*
+ * Information about the selected region of text
+ */
+ HtmlIndex selBegin; /* Start of the selection */
+ HtmlIndex selEnd; /* End of the selection */
+ HtmlBlock *pSelStartBlock; /* Block in which selection starts */
+ Html_16 selStartIndex; /* Index in pSelStartBlock of first selected
+ * character */
+ Html_16 selEndIndex; /* Index of last selecte char in pSelEndBlock */
+ HtmlBlock *pSelEndBlock; /* Block in which selection ends */
+
+ /*
+ * Information about the insertion cursor
+ */
+ int insOnTime; /* How long the cursor states one (millisec) */
+ int insOffTime; /* How long it is off (milliseconds) */
+ int insStatus; /* Is it visible? */
+ Tcl_TimerToken insTimer; /* Timer used to flash the insertion cursor */
+ HtmlIndex ins; /* The insertion cursor position */
+ HtmlBlock *pInsBlock; /* The HtmlBlock containing the cursor */
+ int insIndex; /* Index in pInsBlock of the cursor */
+
+ /*
+ * The following fields hold state information used by
+ * the tokenizer.
+ */
+ char *zText; /* Complete text of the unparsed HTML */
+ int nText; /* Number of characters in zText */
+ int nAlloc; /* Space allocated for zText */
+ int nComplete; /* How much of zText has actually been
+ * converted into tokens */
+ int iCol; /* The column in which zText[nComplete]
+ * occurs. Used to resolve tabs in input */
+ int iPlaintext; /* If not zero, this is the token type that
+ * caused us to go into plaintext mode. One
+ * of Html_PLAINTEXT, Html_LISTING or
+ * Html_XMP */
+ HtmlScript *pScript; /* <SCRIPT> currently being parsed */
+ char *zHandler[Html_TypeCount]; /* If not NULL, this is a TCL routine that
+ * is used to process tokens of the given
+ * type */
+ /*
+ * These fields hold state information used by the HtmlAddStyle routine.
+ * We have to store this state information here since HtmlAddStyle
+ * operates incrementally. This information must be carried from
+ * one incremental execution to the next.
+ */
+ HtmlStyleStack *styleStack; /* The style stack */
+ int paraAlignment; /* Justification associated with <p> */
+ int rowAlignment; /* Justification associated with <tr> */
+ int anchorFlags; /* Style flags associated with <A>...</A> */
+ int inDt; /* Style flags associated with <DT>...</DT> */
+ int inTr; /* True if within <tr>..</tr> */
+ int inTd; /* True if within <td>..</td> or <th>..</th> */
+ HtmlElement *anchorStart; /* Most recent <a href=...> */
+ HtmlElement *formStart; /* Most recent <form> */
+ HtmlElement *formElemStart; /* Most recent <textarea> or <select> */
+ HtmlElement *innerList; /* The inner most <OL> or <UL> */
+
+ /*
+ * These fields are used to hold the state of the layout engine.
+ * Because the layout is incremental, this state must be held for
+ * the life of the widget.
+ */
+ HtmlLayoutContext layoutContext;
+
+ /*
+ * Information used when displaying the widget:
+ */
+ Tk_3DBorder border; /* Background color */
+ int borderWidth; /* Width of the border. */
+ int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ int inset; /* Total width of highlight and 3-D border */
+ Tk_Font aFont[N_FONT]; /* Information about all screen fonts */
+ char fontValid[(N_FONT+7)/8]; /* If bit N%8 of work N/8 of this field is 0
+ * if aFont[N] needs to be reallocated before
+ * being used. */
+ XColor *apColor[N_COLOR]; /* Information about all colors */
+ int colorUsed; /* bit N is 1 if color N is in use. Only
+ ** applies to colors that aren't predefined */
+ int iDark[N_COLOR]; /* Dark 3D shadow of color K is iDark[K] */
+ int iLight[N_COLOR]; /* Light 3D shadow of color K is iLight[K] */
+ XColor *fgColor; /* Color of normal text. apColor[0] */
+ XColor *newLinkColor; /* Color of unvisitied links. apColor[1] */
+ XColor *oldLinkColor; /* Color of visitied links. apColor[2] */
+ XColor *selectionColor; /* Background color for selections */
+ GcCache aGcCache[N_CACHE_GC]; /* A cache of GCs for general use */
+ int lastGC; /* Index of recently used GC */
+ HtmlImage *imageList; /* A list of all images */
+ int width, height; /* User-requested size of the usable drawing
+ * area, in pixels. Borders and padding
+ * make the actual window a little larger */
+ int realWidth, realHeight; /* The actual physical size of tkwin as
+ * reported in the most recent ConfigureNotify
+ * event. */
+ int padx, pady; /* Separation between the edge of the window
+ * and rendered HTML. */
+ int underlineLinks; /* TRUE if we should underline hyperlinks */
+
+ /* Information about the selection
+ */
+ int exportSelection; /* True if the selection is automatically
+ * exported to the clipboard */
+
+ /* Callback commands. The HTML parser will invoke callbacks from time
+ ** to time to find out information it needs to complete formatting of
+ ** the document. The following fields define the callback commands.
+ */
+ char *zIsVisited; /* Command to tell if a hyperlink has already
+ ** been visited */
+ char *zGetImage; /* Command to get an image from a URL */
+ char *zFrameCommand; /* Command for handling <frameset> markup */
+ char *zAppletCommand; /* Command to process applets */
+ char *zResolverCommand; /* Command to resolve URIs */
+ char *zFormCommand; /* When user presses Submit */
+ char *zHyperlinkCommand; /* Invoked when a hyperlink is clicked */
+ char *zFontCommand; /* Invoked to find font names */
+ char *zScriptCommand; /* Invoked for each <SCRIPT> markup */
+
+ /*
+ * Miscellaneous information:
+ */
+ int tableRelief; /* 3d effects on <TABLE> */
+ int ruleRelief; /* 3d effects on <HR> */
+ char *zBase; /* The base URI */
+ char *zBaseHref; /* zBase as modified by <BASE HREF=..> markup */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ char *takeFocus; /* Value of -takefocus option; not used in
+ * the C code, but used by keyboard traversal
+ * scripts. Malloc'ed, but may be NULL. */
+ char *yScrollCmd; /* Command prefix for communicating with
+ * vertical scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ char *xScrollCmd; /* Command prefix for communicating with
+ * horizontal scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ int xOffset, yOffset; /* Current scroll position. These form the
+ * coordinate in the virtual canvas that
+ * corresponds to (0,0) on the physical screen
+ * in window tkwin */
+ int maxX, maxY; /* Maximum extent of any "paint" that appears
+ * on the virtual canvas. Used to compute
+ * scrollbar positions. */
+ int dirtyLeft, dirtyTop; /* Top left corner of region to redraw. These
+ * are physical screen coordinates relative to
+ * clipwin, not tkwin. */
+ int dirtyRight, dirtyBottom; /* Bottom right corner of region to redraw */
+ int locked; /* Number of locks on this structure. Don't
+ ** delete until it reaches zero. */
+ int flags; /* Various flags; see below for
+ * definitions. */
+}
+
+/*
+ * Flag bits "flags" field of the Html widget:
+ *
+ * REDRAW_PENDING A DoWhenIdle handler has already been queued to
+ * call HtmlRedrawCallback() function.
+ *
+ * GOT_FOCUS This widget currently has input focus.
+ *
+ * HSCROLL Horizontal scrollbar position needs to be
+ * recomputed.
+ *
+ * VSCROLL Vertical scrollbar position needs to be
+ * recomputed.
+ *
+ * RELAYOUT We need to reposition every element on the
+ * virtual canvas. (This happens, for example,
+ * when the size of the widget changes and we
+ * need to recompute the line breaks.)
+ *
+ * RESIZE_ELEMENTS We need to recompute the size of every element.
+ * This happens, for example, when the fonts
+ * change.
+ *
+ * REDRAW_FOCUS We need to repaint the focus highlight border.
+ *
+ * REDRAW_TEXT Everything in the clipping window needs to be redrawn.
+ *
+ * REDRAW_BORDER Everything outside the clipping window needs
+ * to be redrawn.
+ *
+ * RESIZE_CLIPWIN The size and position of the clipping window
+ * needs to be adjusted using Tk_MoveResizeWindow().
+ *
+ * STYLER_RUNNING There is a call to HtmlAddStyle() in process.
+ * Used to prevent a recursive call to HtmlAddStyle().
+ *
+ * INSERT_FLASHING True if there is a timer callback pending that will
+ * toggle the state of the insertion cursor.
+ *
+ * REDRAW_IMAGES One or more HtmlImageMarkup structures have
+ * their redrawNeeded flag set.
+ */
+
+#define REDRAW_PENDING 0x000001
+#define GOT_FOCUS 0x000002
+#define HSCROLL 0x000004
+#define VSCROLL 0x000008
+#define RELAYOUT 0x000010
+#define RESIZE_ELEMENTS 0x000020
+#define REDRAW_FOCUS 0x000040
+#define REDRAW_TEXT 0x000080
+#define REDRAW_BORDER 0x000100
+#define EXTEND_LAYOUT 0x000200
+#define RESIZE_CLIPWIN 0x000400
+#define STYLER_RUNNING 0x000800
+#define INSERT_FLASHING 0x001000
+#define REDRAW_IMAGES 0x002000
+
+/*
+** Macros to set, clear or test bits of the "flags" field.
+*/
+#define HtmlHasFlag(A,F) (((A)->flags&(F))==(F))
+#define HtmlHasAnyFlag(A,F) (((A)->flags&(F))!=0)
+#define HtmlSetFlag(A,F) ((A)->flags|=(F))
+#define HtmlClearFlag(A,F) ((A)->flags&=~(F))
+
+/*
+** No coordinate is every as big as this number
+*/
+#define LARGE_NUMBER 100000000
+
+/*
+** Default values for configuration options
+*/
+#define DEF_HTML_BG_COLOR DEF_FRAME_BG_COLOR
+#define DEF_HTML_BG_MONO DEF_FRAME_BG_MONO
+#define DEF_HTML_BORDER_WIDTH "2"
+#define DEF_HTML_CALLBACK ""
+#define DEF_HTML_CURSOR DEF_FRAME_CURSOR
+#define DEF_HTML_EXPORT_SEL "yes"
+#define DEF_HTML_FG DEF_BUTTON_FG
+#define DEF_HTML_HEIGHT "400"
+#define DEF_HTML_HIGHLIGHT_BG DEF_BUTTON_HIGHLIGHT_BG
+#define DEF_HTML_HIGHLIGHT DEF_BUTTON_HIGHLIGHT
+#define DEF_HTML_HIGHLIGHT_WIDTH "0"
+#define DEF_HTML_INSERT_OFF_TIME "300"
+#define DEF_HTML_INSERT_ON_TIME "600"
+#define DEF_HTML_PADX "5"
+#define DEF_HTML_PADY "5"
+#define DEF_HTML_RELIEF "raised"
+#define DEF_HTML_SCROLL_COMMAND ""
+#define DEF_HTML_SELECTION_COLOR "skyblue"
+#define DEF_HTML_TAKE_FOCUS "0"
+#define DEF_HTML_UNVISITED "blue1"
+#define DEF_HTML_VISITED "blue3"
+#define DEF_HTML_WIDTH "600"
+
+#ifdef NAVIGATOR_TABLES
+
+#define DEF_HTML_TABLE_BORDER "0"
+#define DEF_HTML_TABLE_CELLPADDING "2"
+#define DEF_HTML_TABLE_CELLSPACING "5"
+#define DEF_HTML_TABLE_BORDER_LIGHT_COLOR "gray80"
+#define DEF_HTML_TABLE_BORDER_DARK_COLOR "gray40"
+
+#endif /* NAVIGATOR_TABLES */
diff --git a/tkhtml1/src/htmlcmd.c b/tkhtml1/src/htmlcmd.c
new file mode 100644
index 0000000..5f5fe73
--- /dev/null
+++ b/tkhtml1/src/htmlcmd.c
@@ -0,0 +1,735 @@
+/*
+** Routines to implement the HTML widget commands
+**
+** Copyright (C) 1997-2000 D. Richard Hipp
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** drh@acm.org
+** http://www.hwaci.com/drh/
+*/
+#include <tk.h>
+#include <stdlib.h>
+#include <string.h>
+#include "htmlcmd.h"
+
+/*
+** WIDGET resolve ?URI ...?
+**
+** Call the TCL command specified by the -resolvercommand option
+** to resolve the URL.
+*/
+int HtmlResolveCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ return HtmlCallResolver(htmlPtr, (char**)argv+2);
+}
+
+/*
+** WIDGET cget CONFIG-OPTION
+**
+** Retrieve the value of a configuration option
+*/
+int HtmlCgetCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ TestPoint(0);
+ return Tk_ConfigureValue(interp, htmlPtr->tkwin, HtmlConfigSpec(),
+ (char *) htmlPtr, argv[2], 0);
+}
+
+/*
+** WIDGET clear
+**
+** Erase all HTML from this widget and clear the screen. This is
+** typically done before loading a new document.
+*/
+int HtmlClearCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ HtmlClear(htmlPtr);
+ htmlPtr->flags |= REDRAW_TEXT | VSCROLL | HSCROLL;
+ HtmlScheduleRedraw(htmlPtr);
+ TestPoint(0);
+ return TCL_OK;
+}
+
+/*
+** WIDGET configure ?OPTIONS?
+**
+** The standard Tk configure command.
+*/
+int HtmlConfigCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ if (argc == 2) {
+ TestPoint(0);
+ return Tk_ConfigureInfo(interp, htmlPtr->tkwin, HtmlConfigSpec(),
+ (char *) htmlPtr, (char *) NULL, 0);
+ } else if (argc == 3) {
+ TestPoint(0);
+ return Tk_ConfigureInfo(interp, htmlPtr->tkwin, HtmlConfigSpec(),
+ (char *) htmlPtr, argv[2], 0);
+ } else {
+ TestPoint(0);
+ return ConfigureHtmlWidget(interp, htmlPtr, argc-2, argv+2,
+ TK_CONFIG_ARGV_ONLY, 0);
+ }
+}
+
+/*
+** WIDGET href X Y
+**
+** Returns the URL on the hyperlink that is beneath the position X,Y.
+** Returns {} if there is no hyperlink beneath X,Y.
+*/
+int HtmlHrefCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ int x, y;
+ char *z;
+
+ if( Tcl_GetInt(interp, argv[2], &x) != TCL_OK
+ || Tcl_GetInt(interp, argv[3], &y) != TCL_OK
+ ){
+ TestPoint(0);
+ return TCL_ERROR;
+ }
+ z = HtmlGetHref(htmlPtr, x + htmlPtr->xOffset, y + htmlPtr->yOffset);
+ if( z ){
+ HtmlLock(htmlPtr);
+ z = HtmlResolveUri(htmlPtr, z);
+ if( !HtmlUnlock(htmlPtr) ){
+ Tcl_SetResult(interp, z, TCL_DYNAMIC);
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+** WIDGET names
+**
+** Returns a list of names associated with <a name=...> tags.
+*/
+int HtmlNamesCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ HtmlElement *p;
+ char *z;
+ TestPoint(0);
+ for(p=htmlPtr->pFirst; p; p=p->pNext){
+ if( p->base.type!=Html_A ) continue;
+ z = HtmlMarkupArg(p,"name",0);
+ if( z ){
+ Tcl_AppendElement(interp,z);
+ }else{
+ z = HtmlMarkupArg(p,"id",0);
+ if( z ){
+ Tcl_AppendElement(interp,z);
+ }
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+** WIDGET parse HTML
+**
+** Appends the given HTML text to the end of any HTML text that may have
+** been inserted by prior calls to this command. Then it runs the
+** tokenizer, parser and layout engine as far as possible with the
+** text that is available. The display is updated appropriately.
+*/
+int HtmlParseCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ HtmlElement *endPtr;
+ endPtr = htmlPtr->pLast;
+ HtmlLock(htmlPtr);
+ HtmlTokenizerAppend(htmlPtr, argv[2]);
+ if( HtmlIsDead(htmlPtr) ){
+ return TCL_OK;
+ }
+ if( endPtr ){
+ if( endPtr->pNext ){
+ HtmlAddStyle(htmlPtr, endPtr->pNext);
+ }
+ }else if( htmlPtr->pFirst ){
+ htmlPtr->paraAlignment = ALIGN_None;
+ htmlPtr->rowAlignment = ALIGN_None;
+ htmlPtr->anchorFlags = 0;
+ htmlPtr->inDt = 0;
+ htmlPtr->anchorStart = 0;
+ htmlPtr->formStart = 0;
+ htmlPtr->innerList = 0;
+ HtmlAddStyle(htmlPtr, htmlPtr->pFirst);
+ TestPoint(0);
+ }
+ if( !HtmlUnlock(htmlPtr) ){
+ htmlPtr->flags |= EXTEND_LAYOUT;
+ HtmlScheduleRedraw(htmlPtr);
+ TestPoint(0);
+ }
+ return TCL_OK;
+}
+
+/*
+** WIDGET xview ?SCROLL-OPTIONS...?
+**
+** Implements horizontal scrolling in the usual Tk way.
+*/
+int HtmlXviewCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ if( argc==2 ){
+ HtmlComputeHorizontalPosition(htmlPtr,(char*)Tcl_GetStringResult(interp));
+ TestPoint(0);
+ }else{
+ int count;
+ double fraction;
+ int maxX = htmlPtr->maxX;
+ int w = HtmlUsableWidth(htmlPtr);
+ int offset = htmlPtr->xOffset;
+ int type = Tk_GetScrollInfo(interp,argc,(const char**)argv,&fraction,&count);
+ switch( type ){
+ case TK_SCROLL_ERROR:
+ TestPoint(0);
+ return TCL_ERROR;
+ case TK_SCROLL_MOVETO:
+ offset = fraction * maxX;
+ TestPoint(0);
+ break;
+ case TK_SCROLL_PAGES:
+ offset += (count * w * 9)/10;
+ TestPoint(0);
+ break;
+ case TK_SCROLL_UNITS:
+ offset += (count * w)/10;
+ TestPoint(0);
+ break;
+ }
+ if( offset + w > maxX ){
+ offset = maxX - w;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ if( offset < 0 ){
+ offset = 0;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ HtmlHorizontalScroll(htmlPtr, offset);
+ }
+ return TCL_OK;
+}
+
+/*
+** WIDGET yview ?SCROLL-OPTIONS...?
+**
+** Implements vertical scrolling in the usual Tk way, but with one
+** enhancement. If the argument is a single word, the widget looks
+** for a <a name=...> tag with that word as the "name" and scrolls
+** to the position of that tag.
+*/
+int HtmlYviewCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ if( argc==2 ){
+ HtmlComputeVerticalPosition(htmlPtr,(char*)Tcl_GetStringResult(interp));
+ TestPoint(0);
+ }else if( argc==3 ){
+ char *z;
+ HtmlElement *p;
+ for(p=htmlPtr->pFirst; p; p=p->pNext){
+ if( p->base.type!=Html_A ) continue;
+ z = HtmlMarkupArg(p,"name",0);
+ if( z==0 ){
+ TestPoint(0);
+ continue;
+ }
+ if( strcmp(z,argv[2])!=0 ){
+ TestPoint(0);
+ continue;
+ }
+ HtmlVerticalScroll(htmlPtr, p->anchor.y);
+ TestPoint(0);
+ break;
+ }
+ } else if( argc==4 && !strncmp(argv[2],"text",4)) {
+ HtmlElement *p;
+ int i;
+
+ HtmlLock(htmlPtr);
+ if( HtmlGetIndex(htmlPtr, argv[3], &p, &i)!=0 ){
+ if( !HtmlUnlock(htmlPtr) ){
+ Tcl_AppendResult(interp,"malformed index: \"", argv[3], "\"", 0);
+ }
+ TestPoint(0);
+ return TCL_ERROR;
+ }
+ if( !HtmlUnlock(htmlPtr) && p ){
+ if( p->base.type==Html_Text ) {
+ int offset = p->text.y-20;
+ if (offset<0)
+ offset = 0;
+ HtmlVerticalScroll(htmlPtr, offset);
+ }
+ TestPoint(0);
+ }
+ }
+ else{
+ int count;
+ double fraction;
+ int maxY = htmlPtr->maxY;
+ int h = HtmlUsableHeight(htmlPtr);
+ int offset = htmlPtr->yOffset;
+ int type = Tk_GetScrollInfo(interp,argc,(const char**)argv,&fraction,&count);
+ switch( type ){
+ case TK_SCROLL_ERROR:
+ TestPoint(0);
+ return TCL_ERROR;
+ case TK_SCROLL_MOVETO:
+ offset = fraction * maxY;
+ TestPoint(0);
+ break;
+ case TK_SCROLL_PAGES:
+ offset += (count * h * 9)/10;
+ TestPoint(0);
+ break;
+ case TK_SCROLL_UNITS:
+ offset += (count * h)/10;
+ TestPoint(0);
+ break;
+ }
+ if( offset + h > maxY ){
+ offset = maxY - h;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ if( offset < 0 ){
+ offset = 0;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ HtmlVerticalScroll(htmlPtr, offset);
+ }
+ return TCL_OK;
+}
+
+/*
+** WIDGET token handler TAG ?SCRIPT?
+*/
+int HtmlTokenHandlerCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ int type = HtmlNameToType(argv[3]);
+ if( type==Html_Unknown ){
+ Tcl_AppendResult(interp,"unknown tag: \"", argv[3], "\"", 0);
+ return TCL_ERROR;
+ }
+ if( argc==4 ){
+ if( htmlPtr->zHandler[type]!=0 ){
+ Tcl_SetResult(interp,htmlPtr->zHandler[type],NULL);
+ }
+ }else{
+ if( htmlPtr->zHandler[type]!=0 ){
+ HtmlFree(htmlPtr->zHandler[type]);
+ }
+ htmlPtr->zHandler[type] = HtmlAlloc( strlen(argv[4]) + 1 );
+ if( htmlPtr->zHandler[type] ){
+ strcpy(htmlPtr->zHandler[type],argv[4]);
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+** WIDGET index INDEX
+*/
+int HtmlIndexCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ HtmlElement *p;
+ int i;
+
+ HtmlLock(htmlPtr);
+ if( HtmlGetIndex(htmlPtr, argv[2], &p, &i)!=0 ){
+ if( !HtmlUnlock(htmlPtr) ){
+ Tcl_AppendResult(interp,"malformed index: \"", argv[2], "\"", 0);
+ }
+ TestPoint(0);
+ return TCL_ERROR;
+ }
+ if( !HtmlUnlock(htmlPtr) && p ){
+ sprintf((char*)Tcl_GetStringResult(interp), "%d.%d", HtmlTokenNumber(p), i);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ return TCL_OK;
+}
+
+/* The pSelStartBlock and pSelEndBlock values have been changed.
+** This routine's job is to loop over all HtmlBlocks and either
+** set or clear the HTML_Selected bits in the .base.flags field
+** as appropriate. For every HtmlBlock where the bit changes,
+** mark that block for redrawing.
+*/
+static void UpdateSelection(HtmlWidget *htmlPtr){
+ int selected = 0;
+ HtmlIndex tempIndex;
+ HtmlBlock *pTempBlock;
+ int temp;
+ HtmlBlock *p;
+
+ for(p=htmlPtr->firstBlock; p; p=p->pNext){
+ if( p==htmlPtr->pSelStartBlock ){
+ selected = 1;
+ HtmlRedrawBlock(htmlPtr, p);
+ TestPoint(0);
+ }else if( !selected && p==htmlPtr->pSelEndBlock ){
+ selected = 1;
+ tempIndex = htmlPtr->selBegin;
+ htmlPtr->selBegin = htmlPtr->selEnd;
+ htmlPtr->selEnd = tempIndex;
+ pTempBlock = htmlPtr->pSelStartBlock;
+ htmlPtr->pSelStartBlock = htmlPtr->pSelEndBlock;
+ htmlPtr->pSelEndBlock = pTempBlock;
+ temp = htmlPtr->selStartIndex;
+ htmlPtr->selStartIndex = htmlPtr->selEndIndex;
+ htmlPtr->selEndIndex = temp;
+ HtmlRedrawBlock(htmlPtr, p);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ if( p->base.flags & HTML_Selected ){
+ if( !selected ){
+ p->base.flags &= ~HTML_Selected;
+ HtmlRedrawBlock(htmlPtr,p);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ }else{
+ if( selected ){
+ p->base.flags |= HTML_Selected;
+ HtmlRedrawBlock(htmlPtr,p);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ }
+ if( p==htmlPtr->pSelEndBlock ){
+ selected = 0;
+ HtmlRedrawBlock(htmlPtr, p);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ }
+}
+
+/* Given the selection end-points in htmlPtr->selBegin
+** and htmlPtr->selEnd, recompute pSelBeginBlock and
+** pSelEndBlock, then call UpdateSelection to update the
+** display.
+**
+** This routine should be called whenever the selection
+** changes or whenever the set of HtmlBlock structures
+** change.
+*/
+void HtmlUpdateSelection(HtmlWidget *htmlPtr, int forceUpdate){
+ HtmlBlock *pBlock;
+ int index;
+ int needUpdate = forceUpdate;
+ int temp;
+
+ if( htmlPtr->selEnd.p==0 ){
+ htmlPtr->selBegin.p = 0;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ HtmlIndexToBlockIndex(htmlPtr, htmlPtr->selBegin, &pBlock, &index);
+ if( needUpdate || pBlock != htmlPtr->pSelStartBlock ){
+ needUpdate = 1;
+ HtmlRedrawBlock(htmlPtr, htmlPtr->pSelStartBlock);
+ htmlPtr->pSelStartBlock = pBlock;
+ htmlPtr->selStartIndex = index;
+ TestPoint(0);
+ }else if( index != htmlPtr->selStartIndex ){
+ HtmlRedrawBlock(htmlPtr, pBlock);
+ htmlPtr->selStartIndex = index;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ if( htmlPtr->selBegin.p==0 ){
+ htmlPtr->selEnd.p = 0;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ HtmlIndexToBlockIndex(htmlPtr, htmlPtr->selEnd, &pBlock, &index);
+ if( needUpdate || pBlock != htmlPtr->pSelEndBlock ){
+ needUpdate = 1;
+ HtmlRedrawBlock(htmlPtr, htmlPtr->pSelEndBlock);
+ htmlPtr->pSelEndBlock = pBlock;
+ htmlPtr->selEndIndex = index;
+ TestPoint(0);
+ }else if( index != htmlPtr->selEndIndex ){
+ HtmlRedrawBlock(htmlPtr, pBlock);
+ htmlPtr->selEndIndex = index;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ if( htmlPtr->pSelStartBlock
+ && htmlPtr->pSelStartBlock==htmlPtr->pSelEndBlock
+ && htmlPtr->selStartIndex > htmlPtr->selEndIndex
+ ){
+ temp = htmlPtr->selStartIndex;
+ htmlPtr->selStartIndex = htmlPtr->selEndIndex;
+ htmlPtr->selEndIndex = temp;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ if( needUpdate ){
+ UpdateSelection(htmlPtr);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+}
+
+/*
+** WIDGET selection set INDEX INDEX
+*/
+int HtmlSelectionSetCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ HtmlIndex selBegin, selEnd;
+
+ HtmlLock(htmlPtr);
+ if( HtmlGetIndex(htmlPtr, argv[3], &selBegin.p, &selBegin.i) ){
+ if( !HtmlUnlock(htmlPtr) ){
+ Tcl_AppendResult(interp,"malformed index: \"", argv[3], "\"", 0);
+ }
+ TestPoint(0);
+ return TCL_ERROR;
+ }
+ if( HtmlIsDead(htmlPtr) ) return TCL_OK;
+ if( HtmlGetIndex(htmlPtr, argv[4], &selEnd.p, &selEnd.i) ){
+ if( !HtmlUnlock(htmlPtr) ){
+ Tcl_AppendResult(interp,"malformed index: \"", argv[4], "\"", 0);
+ }
+ TestPoint(0);
+ return TCL_ERROR;
+ }
+ if( HtmlUnlock(htmlPtr) ) return TCL_OK;
+ htmlPtr->selBegin = selBegin;
+ htmlPtr->selEnd = selEnd;
+ HtmlUpdateSelection(htmlPtr,0);
+ TestPoint(0);
+ return TCL_OK;
+}
+
+/*
+** WIDGET selection clear
+*/
+int HtmlSelectionClearCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ htmlPtr->pSelStartBlock = 0;
+ htmlPtr->pSelEndBlock = 0;
+ htmlPtr->selBegin.p = 0;
+ htmlPtr->selEnd.p = 0;
+ UpdateSelection(htmlPtr);
+ TestPoint(0);
+ return TCL_OK;
+}
+
+/*
+** Recompute the position of the insertion cursor based on the
+** position in htmlPtr->ins.
+*/
+void HtmlUpdateInsert(HtmlWidget *htmlPtr){
+ HtmlIndexToBlockIndex(htmlPtr, htmlPtr->ins,
+ &htmlPtr->pInsBlock, &htmlPtr->insIndex);
+ HtmlRedrawBlock(htmlPtr, htmlPtr->pInsBlock);
+ if( htmlPtr->insTimer==0 ){
+ htmlPtr->insStatus = 0;
+ HtmlFlashCursor(htmlPtr);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+}
+
+/*
+** WIDGET insert INDEX
+*/
+int HtmlInsertCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ HtmlIndex ins;
+ if( argv[2][0]==0 ){
+ HtmlRedrawBlock(htmlPtr, htmlPtr->pInsBlock);
+ htmlPtr->insStatus = 0;
+ htmlPtr->pInsBlock = 0;
+ htmlPtr->ins.p = 0;
+ TestPoint(0);
+ }else{
+ HtmlLock(htmlPtr);
+ if( HtmlGetIndex(htmlPtr, argv[2], &ins.p, &ins.i) ){
+ if( !HtmlUnlock(htmlPtr) ){
+ Tcl_AppendResult(interp,"malformed index: \"", argv[2], "\"", 0);
+ }
+ TestPoint(0);
+ return TCL_ERROR;
+ }
+ if( HtmlUnlock(htmlPtr) ) return TCL_OK;
+ HtmlRedrawBlock(htmlPtr, htmlPtr->pInsBlock);
+ htmlPtr->ins = ins;
+ HtmlUpdateInsert(htmlPtr);
+ TestPoint(0);
+ }
+ return TCL_OK;
+}
+
+/*
+** WIDGET token list START END
+*/
+int HtmlTokenListCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ HtmlElement *pStart, *pEnd;
+ int i;
+
+ if( HtmlGetIndex(htmlPtr, argv[3], &pStart, &i)!=0 ){
+ Tcl_AppendResult(interp,"malformed index: \"", argv[3], "\"", 0);
+ return TCL_ERROR;
+ }
+ if( HtmlGetIndex(htmlPtr, argv[4], &pEnd, &i)!=0 ){
+ Tcl_AppendResult(interp,"malformed index: \"", argv[4], "\"", 0);
+ return TCL_ERROR;
+ }
+ if( pStart ){
+ HtmlTclizeList(interp,pStart,pEnd ? pEnd->base.pNext : 0);
+ }
+ return TCL_OK;
+}
+
+void* HtmlAlloc(size_t A)
+{
+ void* ptr = Tcl_Alloc(A);
+ if (ptr)
+ memset(ptr,0,A);
+ return ptr;
+}
+
+#ifdef DEBUG
+/*
+** WIDGET debug dump START END
+*/
+int HtmlDebugDumpCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ HtmlElement *pStart, *pEnd;
+ int i;
+
+ if( HtmlGetIndex(htmlPtr, argv[3], &pStart, &i)!=0 ){
+ Tcl_AppendResult(interp,"malformed index: \"", argv[3], "\"", 0);
+ return TCL_ERROR;
+ }
+ if( HtmlGetIndex(htmlPtr, argv[4], &pEnd, &i)!=0 ){
+ Tcl_AppendResult(interp,"malformed index: \"", argv[4], "\"", 0);
+ return TCL_ERROR;
+ }
+ if( pStart ){
+ HtmlPrintList(pStart,pEnd ? pEnd->base.pNext : 0);
+ }
+ return TCL_OK;
+}
+
+/*
+** WIDGET debug testpt FILENAME
+*/
+int HtmlDebugTestPtCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ HtmlTestPointDump(argv[3]);
+ return TCL_OK;
+}
+#endif
diff --git a/tkhtml1/src/htmlcmd.h b/tkhtml1/src/htmlcmd.h
new file mode 100644
index 0000000..9417a00
--- /dev/null
+++ b/tkhtml1/src/htmlcmd.h
@@ -0,0 +1,498 @@
+/* This file was automatically generated. Do not edit! */
+void HtmlTestPointDump(const char *filename);
+typedef struct HtmlWidget HtmlWidget;
+#define DEBUG 1
+#if defined(DEBUG)
+int HtmlDebugTestPtCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+#endif
+typedef union HtmlElement HtmlElement;
+#if defined(DEBUG)
+void HtmlPrintList(HtmlElement *p,HtmlElement *pEnd);
+int HtmlDebugDumpCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+#endif
+void HtmlTclizeList(Tcl_Interp *interp,HtmlElement *p,HtmlElement *pEnd);
+int HtmlTokenListCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlInsertCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+void HtmlFlashCursor(ClientData clientData);
+void HtmlUpdateInsert(HtmlWidget *htmlPtr);
+int HtmlSelectionClearCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlSelectionSetCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+typedef struct HtmlIndex HtmlIndex;
+struct HtmlIndex {
+ HtmlElement *p; /* The token containing the character */
+ int i; /* Index of the character */
+};
+typedef struct HtmlBlock HtmlBlock;
+void HtmlIndexToBlockIndex(HtmlWidget *htmlPtr,HtmlIndex sIndex,HtmlBlock **ppBlock,int *piIndex);
+void HtmlUpdateSelection(HtmlWidget *htmlPtr,int forceUpdate);
+#define HTML_Selected 0x04 /* Some or all of this Html_Block is selected */
+void HtmlRedrawBlock(HtmlWidget *htmlPtr,HtmlBlock *p);
+typedef struct HtmlBaseElement HtmlBaseElement;
+typedef struct HtmlStyle HtmlStyle;
+struct HtmlStyle {
+ unsigned int font : 6; /* Font to use for display */
+ unsigned int color : 4; /* Foreground color */
+ signed int subscript : 4; /* Positive for <sup>, negative for <sub> */
+ unsigned int align : 2; /* Horizontal alignment */
+ unsigned int bgcolor : 4; /* Background color */
+ unsigned int flags : 12; /* the STY_ flags below */
+};
+typedef unsigned char Html_u8;
+typedef short Html_16;
+struct HtmlBaseElement {
+ HtmlElement *pNext; /* Next input token in a list of them all */
+ HtmlElement *pPrev; /* Previous token in a list of them all */
+ HtmlStyle style; /* The rendering style for this token */
+ Html_u8 type; /* The token type. */
+ Html_u8 flags; /* The HTML_ flags below */
+ Html_16 count; /* Various uses, depending on "type" */
+};
+typedef unsigned short Html_u16;
+struct HtmlBlock {
+ HtmlBaseElement base; /* Superclass. Must be first */
+ char *z; /* Space to hold text when n>0 */
+ int top, bottom; /* Extremes of y coordinates */
+ Html_u16 left, right; /* Left and right boundry of this object */
+ Html_u16 n; /* Number of characters in z[] */
+ HtmlBlock *pPrev, *pNext; /* Linked list of all Blocks */
+};
+int HtmlTokenNumber(HtmlElement *p);
+int HtmlIndexCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+/*#define HtmlAlloc(A) ((void*)Tcl_Alloc(A))*/
+void* HtmlAlloc(size_t);
+#define HtmlFree(A) Tcl_Free((char*)(A))
+#define Html_Unknown 3
+int HtmlNameToType(const char *zType);
+int HtmlTokenHandlerCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlUsableHeight(HtmlWidget *htmlPtr);
+#define Html_Text 1
+int HtmlGetIndex(HtmlWidget *htmlPtr,const char *zIndex,HtmlElement **ppToken,int *pIndex);
+void HtmlVerticalScroll(HtmlWidget *htmlPtr,int yOffset);
+void HtmlComputeVerticalPosition(HtmlWidget *htmlPtr,char *buf);
+int HtmlYviewCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+void HtmlHorizontalScroll(HtmlWidget *htmlPtr,int xOffset);
+int HtmlUsableWidth(HtmlWidget *htmlPtr);
+void HtmlComputeHorizontalPosition(HtmlWidget *htmlPtr,char *buf);
+int HtmlXviewCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+#define EXTEND_LAYOUT 0x000200
+#define ALIGN_None 0
+void HtmlAddStyle(HtmlWidget *htmlPtr,HtmlElement *p);
+int HtmlIsDead(HtmlWidget *htmlPtr);
+void HtmlTokenizerAppend(HtmlWidget *htmlPtr,const char *zText);
+int HtmlParseCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+char *HtmlMarkupArg(HtmlElement *p,const char *tag,char *zDefault);
+#define Html_A 5
+typedef struct HtmlTextElement HtmlTextElement;
+typedef int Html_32;
+struct HtmlTextElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_32 y; /* y coordinate where text should be rendered */
+ Html_16 x; /* x coordinate where text should be rendered */
+ Html_16 w; /* width of this token in pixels */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_u8 spaceWidth; /* Width of one space in the current font */
+ char zText[1]; /* Text for this element. Null terminated */
+};
+typedef struct HtmlSpaceElement HtmlSpaceElement;
+struct HtmlSpaceElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_16 w; /* Width of a single space in current font */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+};
+typedef struct HtmlMarkupElement HtmlMarkupElement;
+struct HtmlMarkupElement {
+ HtmlBaseElement base;
+ char **argv;
+};
+typedef struct HtmlCell HtmlCell;
+struct HtmlCell {
+ HtmlMarkupElement markup;
+ Html_16 rowspan; /* Number of rows spanned by this cell */
+ Html_16 colspan; /* Number of columns spanned by this cell */
+ Html_16 x; /* X coordinate of left edge of border */
+ Html_16 w; /* Width of the border */
+ Html_32 y; /* Y coordinate of top of border indentation */
+ Html_32 h; /* Height of the border */
+ HtmlElement *pTable; /* Pointer back to the <table> */
+ HtmlElement *pEnd; /* Element that ends this cell */
+};
+typedef struct HtmlTable HtmlTable;
+#define HTML_MAX_COLUMNS 40
+struct HtmlTable {
+ HtmlMarkupElement markup;
+ Html_u8 borderWidth; /* Width of the border */
+ Html_u8 nCol; /* Number of columns */
+ Html_u16 nRow; /* Number of rows */
+ Html_32 y; /* top edge of table border */
+ Html_32 h; /* height of the table border */
+ Html_16 x; /* left edge of table border */
+ Html_16 w; /* width of the table border */
+ int minW[HTML_MAX_COLUMNS+1]; /* minimum width of each column */
+ int maxW[HTML_MAX_COLUMNS+1]; /* maximum width of each column */
+};
+typedef struct HtmlRef HtmlRef;
+struct HtmlRef {
+ HtmlMarkupElement markup;
+ HtmlElement *pOther; /* Pointer to some other Html element */
+};
+typedef struct HtmlLi HtmlLi;
+struct HtmlLi {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* What type of list is this? */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_16 cnt; /* Value for this element (if inside <OL>) */
+ Html_16 x; /* X coordinate of the bullet */
+ Html_32 y; /* Y coordinate of the bullet */
+};
+typedef struct HtmlListStart HtmlListStart;
+struct HtmlListStart {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* One of the LI_TYPE_ defines above */
+ Html_u8 compact; /* True if the COMPACT flag is present */
+ Html_u16 cnt; /* Next value for <OL> */
+ Html_u16 width; /* How much space to allow for indentation */
+ HtmlElement *pPrev; /* Next higher level list, or NULL */
+};
+typedef struct HtmlImageMarkup HtmlImageMarkup;
+typedef struct HtmlImage HtmlImage;
+struct HtmlImageMarkup {
+ HtmlMarkupElement markup;
+ Html_u8 align; /* Alignment. See IMAGE_ALIGN_ defines below */
+ Html_u8 textAscent; /* Ascent of text font in force at the <IMG> */
+ Html_u8 textDescent; /* Descent of text font in force at the <IMG> */
+ Html_u8 redrawNeeded; /* Need to redraw this image because the image
+ ** content changed. */
+ Html_16 h; /* Actual height of the image */
+ Html_16 w; /* Actual width of the image */
+ Html_16 ascent; /* How far image extends above "y" */
+ Html_16 descent; /* How far image extends below "y" */
+ Html_16 x; /* X coordinate of left edge of the image */
+ Html_32 y; /* Y coordinate of image baseline */
+ char *zAlt; /* Alternative text */
+ HtmlImage *pImage; /* Corresponding HtmlImage structure */
+ HtmlElement *pNext; /* Next markup using the same HtmlImage structure */
+};
+typedef struct HtmlInput HtmlInput;
+struct HtmlInput {
+ HtmlMarkupElement markup;
+ HtmlElement *pForm; /* The <FORM> to which this belongs */
+ HtmlElement *pNext; /* Next element in a list of all input elements */
+ Tk_Window tkwin; /* The window that implements this control */
+ HtmlWidget *htmlPtr; /* The whole widget. Needed by geometry callbacks */
+ HtmlElement *pEnd; /* End tag for <TEXTAREA>, etc. */
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 padLeft; /* Extra padding on left side of the control */
+ Html_u8 align; /* One of the IMAGE_ALIGN_xxx types */
+ Html_u8 textAscent; /* Ascent for the current font */
+ Html_u8 textDescent; /* descent for the current font */
+ Html_u8 type; /* What type of input is this? */
+ Html_u8 sized; /* True if this input has been sized already */
+ Html_u16 cnt; /* Used to derive widget name. 0 if no widget */
+};
+typedef struct HtmlForm HtmlForm;
+struct HtmlForm {
+ HtmlMarkupElement markup;
+ Html_u16 id; /* Unique number assigned to this form */
+};
+typedef struct HtmlHr HtmlHr;
+struct HtmlHr {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 is3D; /* Is it drawn 3D? */
+};
+typedef struct HtmlAnchor HtmlAnchor;
+struct HtmlAnchor {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Top edge for this element */
+};
+typedef struct HtmlScript HtmlScript;
+struct HtmlScript {
+ HtmlMarkupElement markup;
+ char *zScript; /* Complete text of this script */
+ int nScript; /* Number of characters of text */
+};
+union HtmlElement {
+ HtmlElement *pNext;
+ HtmlBaseElement base;
+ HtmlTextElement text;
+ HtmlSpaceElement space;
+ HtmlMarkupElement markup;
+ HtmlCell cell;
+ HtmlTable table;
+ HtmlRef ref;
+ HtmlLi li;
+ HtmlListStart list;
+ HtmlImageMarkup image;
+ HtmlInput input;
+ HtmlForm form;
+ HtmlHr hr;
+ HtmlAnchor anchor;
+ HtmlScript script;
+ HtmlBlock block;
+};
+int HtmlNamesCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlUnlock(HtmlWidget *htmlPtr);
+char *HtmlResolveUri(HtmlWidget *htmlPtr,char *zUri);
+void HtmlLock(HtmlWidget *htmlPtr);
+char *HtmlGetHref(HtmlWidget *htmlPtr,int x,int y);
+int HtmlHrefCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int ConfigureHtmlWidget(Tcl_Interp *interp,HtmlWidget *htmlPtr,int argc,const char **argv,int flags,int realign);
+int HtmlConfigCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+void HtmlScheduleRedraw(HtmlWidget *htmlPtr);
+#define HSCROLL 0x000004
+#define VSCROLL 0x000008
+#define REDRAW_TEXT 0x000080
+void HtmlClear(HtmlWidget *htmlPtr);
+int HtmlClearCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+Tk_ConfigSpec *HtmlConfigSpec(void);
+#if defined(COVERAGE_TEST)
+extern int HtmlTPArray[2000];
+# define TestPoint(X) {extern int HtmlTPArray[]; HtmlTPArray[X]++;}
+#endif
+#if !(defined(COVERAGE_TEST))
+# define TestPoint(X)
+#endif
+int HtmlCgetCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlCallResolver(HtmlWidget *htmlPtr,char **azSeries);
+#define Html_TypeCount 151
+typedef struct HtmlStyleStack HtmlStyleStack;
+typedef struct HtmlLayoutContext HtmlLayoutContext;
+typedef struct HtmlMargin HtmlMargin;
+struct HtmlLayoutContext {
+ HtmlWidget *htmlPtr; /* The html widget undergoing layout */
+ HtmlElement *pStart; /* Start of elements to layout */
+ HtmlElement *pEnd; /* Stop when reaching this element */
+ int headRoom; /* Extra space wanted above this line */
+ int top; /* Absolute top of drawing area */
+ int bottom; /* Bottom of previous line */
+ int left, right; /* Left and right extremes of drawing area */
+ int pageWidth; /* Width of the layout field, including
+ ** the margins */
+ int maxX, maxY; /* Maximum X and Y values of paint */
+ HtmlMargin *leftMargin; /* Stack of left margins */
+ HtmlMargin *rightMargin; /* Stack of right margins */
+};
+#define N_FONT_FAMILY 8
+#define N_FONT_SIZE 7
+#define N_FONT (N_FONT_FAMILY*N_FONT_SIZE)
+#define N_COLOR 16 /* Total number of colors */
+typedef struct GcCache GcCache;
+struct GcCache {
+ GC gc; /* The graphics context */
+ Html_u8 font; /* Font used for this context */
+ Html_u8 color; /* Color used for this context */
+ Html_u8 index; /* Index used for LRU replacement */
+};
+#define N_CACHE_GC 16
+struct HtmlWidget {
+ Tk_Window tkwin; /* The main window for this widget */
+ Tk_Window clipwin; /* The clipping window in which all text is
+ ** rendered. */
+ char *zClipwin; /* Name of the clipping window. */
+ Display *display; /* The X11 Server that contains tkwin */
+ Tcl_Interp *interp; /* The interpreter in which the widget lives */
+ char *zCmdName; /* Name of the command */
+ HtmlElement *pFirst; /* First HTML token on a list of them all */
+ HtmlElement *pLast; /* Last HTML token on the list */
+ int nToken; /* Number of HTML tokens on the list.
+ * Html_Block tokens don't count. */
+ HtmlElement *lastSized; /* Last HTML element that has been sized */
+ HtmlElement *nextPlaced; /* Next HTML element that needs to be
+ * positioned on canvas. */
+ HtmlBlock *firstBlock; /* List of all HtmlBlock tokens */
+ HtmlBlock *lastBlock; /* Last HtmlBlock in the list */
+ HtmlElement *firstInput; /* First <INPUT> element */
+ HtmlElement *lastInput; /* Last <INPUT> element */
+ int nInput; /* The number of <INPUT> elements */
+ int nForm; /* The number of <FORM> elements */
+ int varId; /* Used to construct a unique name for a
+ ** global array used by <INPUT> elements */
+
+ /*
+ * Information about the selected region of text
+ */
+ HtmlIndex selBegin; /* Start of the selection */
+ HtmlIndex selEnd; /* End of the selection */
+ HtmlBlock *pSelStartBlock; /* Block in which selection starts */
+ Html_16 selStartIndex; /* Index in pSelStartBlock of first selected
+ * character */
+ Html_16 selEndIndex; /* Index of last selecte char in pSelEndBlock */
+ HtmlBlock *pSelEndBlock; /* Block in which selection ends */
+
+ /*
+ * Information about the insertion cursor
+ */
+ int insOnTime; /* How long the cursor states one (millisec) */
+ int insOffTime; /* How long it is off (milliseconds) */
+ int insStatus; /* Is it visible? */
+ Tcl_TimerToken insTimer; /* Timer used to flash the insertion cursor */
+ HtmlIndex ins; /* The insertion cursor position */
+ HtmlBlock *pInsBlock; /* The HtmlBlock containing the cursor */
+ int insIndex; /* Index in pInsBlock of the cursor */
+
+ /*
+ * The following fields hold state information used by
+ * the tokenizer.
+ */
+ char *zText; /* Complete text of the unparsed HTML */
+ int nText; /* Number of characters in zText */
+ int nAlloc; /* Space allocated for zText */
+ int nComplete; /* How much of zText has actually been
+ * converted into tokens */
+ int iCol; /* The column in which zText[nComplete]
+ * occurs. Used to resolve tabs in input */
+ int iPlaintext; /* If not zero, this is the token type that
+ * caused us to go into plaintext mode. One
+ * of Html_PLAINTEXT, Html_LISTING or
+ * Html_XMP */
+ HtmlScript *pScript; /* <SCRIPT> currently being parsed */
+ char *zHandler[Html_TypeCount]; /* If not NULL, this is a TCL routine that
+ * is used to process tokens of the given
+ * type */
+ /*
+ * These fields hold state information used by the HtmlAddStyle routine.
+ * We have to store this state information here since HtmlAddStyle
+ * operates incrementally. This information must be carried from
+ * one incremental execution to the next.
+ */
+ HtmlStyleStack *styleStack; /* The style stack */
+ int paraAlignment; /* Justification associated with <p> */
+ int rowAlignment; /* Justification associated with <tr> */
+ int anchorFlags; /* Style flags associated with <A>...</A> */
+ int inDt; /* Style flags associated with <DT>...</DT> */
+ int inTr; /* True if within <tr>..</tr> */
+ int inTd; /* True if within <td>..</td> or <th>..</th> */
+ HtmlElement *anchorStart; /* Most recent <a href=...> */
+ HtmlElement *formStart; /* Most recent <form> */
+ HtmlElement *formElemStart; /* Most recent <textarea> or <select> */
+ HtmlElement *innerList; /* The inner most <OL> or <UL> */
+
+ /*
+ * These fields are used to hold the state of the layout engine.
+ * Because the layout is incremental, this state must be held for
+ * the life of the widget.
+ */
+ HtmlLayoutContext layoutContext;
+
+ /*
+ * Information used when displaying the widget:
+ */
+ Tk_3DBorder border; /* Background color */
+ int borderWidth; /* Width of the border. */
+ int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ int inset; /* Total width of highlight and 3-D border */
+ Tk_Font aFont[N_FONT]; /* Information about all screen fonts */
+ char fontValid[(N_FONT+7)/8]; /* If bit N%8 of work N/8 of this field is 0
+ * if aFont[N] needs to be reallocated before
+ * being used. */
+ XColor *apColor[N_COLOR]; /* Information about all colors */
+ int colorUsed; /* bit N is 1 if color N is in use. Only
+ ** applies to colors that aren't predefined */
+ int iDark[N_COLOR]; /* Dark 3D shadow of color K is iDark[K] */
+ int iLight[N_COLOR]; /* Light 3D shadow of color K is iLight[K] */
+ XColor *fgColor; /* Color of normal text. apColor[0] */
+ XColor *newLinkColor; /* Color of unvisitied links. apColor[1] */
+ XColor *oldLinkColor; /* Color of visitied links. apColor[2] */
+ XColor *selectionColor; /* Background color for selections */
+ GcCache aGcCache[N_CACHE_GC]; /* A cache of GCs for general use */
+ int lastGC; /* Index of recently used GC */
+ HtmlImage *imageList; /* A list of all images */
+ int width, height; /* User-requested size of the usable drawing
+ * area, in pixels. Borders and padding
+ * make the actual window a little larger */
+ int realWidth, realHeight; /* The actual physical size of tkwin as
+ * reported in the most recent ConfigureNotify
+ * event. */
+ int padx, pady; /* Separation between the edge of the window
+ * and rendered HTML. */
+ int underlineLinks; /* TRUE if we should underline hyperlinks */
+
+ /* Information about the selection
+ */
+ int exportSelection; /* True if the selection is automatically
+ * exported to the clipboard */
+
+ /* Callback commands. The HTML parser will invoke callbacks from time
+ ** to time to find out information it needs to complete formatting of
+ ** the document. The following fields define the callback commands.
+ */
+ char *zIsVisited; /* Command to tell if a hyperlink has already
+ ** been visited */
+ char *zGetImage; /* Command to get an image from a URL */
+ char *zFrameCommand; /* Command for handling <frameset> markup */
+ char *zAppletCommand; /* Command to process applets */
+ char *zResolverCommand; /* Command to resolve URIs */
+ char *zFormCommand; /* When user presses Submit */
+ char *zHyperlinkCommand; /* Invoked when a hyperlink is clicked */
+ char *zFontCommand; /* Invoked to find font names */
+ char *zScriptCommand; /* Invoked for each <SCRIPT> markup */
+
+ /*
+ * Miscellaneous information:
+ */
+ int tableRelief; /* 3d effects on <TABLE> */
+ int ruleRelief; /* 3d effects on <HR> */
+ char *zBase; /* The base URI */
+ char *zBaseHref; /* zBase as modified by <BASE HREF=..> markup */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ char *takeFocus; /* Value of -takefocus option; not used in
+ * the C code, but used by keyboard traversal
+ * scripts. Malloc'ed, but may be NULL. */
+ char *yScrollCmd; /* Command prefix for communicating with
+ * vertical scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ char *xScrollCmd; /* Command prefix for communicating with
+ * horizontal scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ int xOffset, yOffset; /* Current scroll position. These form the
+ * coordinate in the virtual canvas that
+ * corresponds to (0,0) on the physical screen
+ * in window tkwin */
+ int maxX, maxY; /* Maximum extent of any "paint" that appears
+ * on the virtual canvas. Used to compute
+ * scrollbar positions. */
+ int dirtyLeft, dirtyTop; /* Top left corner of region to redraw. These
+ * are physical screen coordinates relative to
+ * clipwin, not tkwin. */
+ int dirtyRight, dirtyBottom; /* Bottom right corner of region to redraw */
+ int locked; /* Number of locks on this structure. Don't
+ ** delete until it reaches zero. */
+ int flags; /* Various flags; see below for
+ * definitions. */
+};
+int HtmlResolveCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+struct HtmlImage {
+ HtmlWidget *htmlPtr; /* The owner of this image */
+ Tk_Image image; /* The Tk image token */
+ Html_32 w; /* Requested width of this image (0 if none) */
+ Html_32 h; /* Requested height of this image (0 if none) */
+ char *zUrl; /* The URL for this image. */
+ char *zWidth, *zHeight; /* Width and height in the <img> markup. */
+ HtmlImage *pNext; /* Next image on the list */
+ HtmlElement *pList; /* List of all <IMG> markups that use this
+ ** same image */
+};
+struct HtmlStyleStack {
+ HtmlStyleStack *pNext; /* Next style on the stack */
+ int type; /* A markup that ends this style. Ex: Html_EndEM */
+ HtmlStyle style; /* The currently active style. */
+};
+struct HtmlMargin {
+ int indent; /* Size of the current margin */
+ int bottom; /* Y value at which this margin expires */
+ int tag; /* Markup that will cancel this margin */
+ HtmlMargin *pNext; /* Previous margin */
+};
diff --git a/tkhtml1/src/htmldraw.c b/tkhtml1/src/htmldraw.c
new file mode 100644
index 0000000..42f2f80
--- /dev/null
+++ b/tkhtml1/src/htmldraw.c
@@ -0,0 +1,877 @@
+/*
+** Routines used to render HTML onto the screen for the Tk HTML widget.
+**
+** Copyright (C) 1997-2000 D. Richard Hipp
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** drh@acm.org
+** http://www.hwaci.com/drh/
+*/
+#include <tk.h>
+#include <string.h>
+#include <stdlib.h>
+#include "htmldraw.h"
+/*
+#ifdef USE_TK_STUBS
+# include <tkIntXlibDecls.h>
+#endif
+*/
+#define USE_TK_DRAWCHARS 1
+
+/*
+** Allocate a new HtmlBlock structure.
+*/
+static HtmlBlock *AllocBlock(void){
+ HtmlBlock *pNew;
+
+ pNew = HtmlAlloc( sizeof(HtmlBlock) );
+ if( pNew ){
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->base.type = Html_Block;
+ }
+ return pNew;
+}
+
+/*
+** Free an HtmlBlock structure. Assume that it is already unlinked
+** from the element list and the block list.
+*/
+static void FreeBlock(HtmlBlock *pBlock){
+ if( pBlock ){
+ if( pBlock->z ){
+ HtmlFree(pBlock->z);
+ }
+ HtmlFree(pBlock);
+ }
+}
+
+/*
+** Destroy the given Block after first unlinking it from the
+** element list. Note that this unlinks the block from the
+** element list only -- not from the block list.
+*/
+static void UnlinkAndFreeBlock(HtmlWidget *htmlPtr, HtmlBlock *pBlock){
+ if( pBlock->base.pNext ){
+ pBlock->base.pNext->base.pPrev = pBlock->base.pPrev;
+ TestPoint(0);
+ }else{
+ htmlPtr->pLast = pBlock->base.pPrev;
+ TestPoint(0);
+ }
+ if( pBlock->base.pPrev ){
+ pBlock->base.pPrev->base.pNext = pBlock->base.pNext;
+ TestPoint(0);
+ }else{
+ htmlPtr->pFirst = pBlock->base.pNext;
+ TestPoint(0);
+ }
+ pBlock->base.pPrev = pBlock->base.pNext = 0;
+ FreeBlock(pBlock);
+}
+
+/*
+** Append a block to the block list and insert the block into the
+** element list immediately prior to the element given.
+*/
+static void AppendBlock(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ HtmlElement *pToken, /* The token that comes after pBlock */
+ HtmlBlock *pBlock /* The block to be appended */
+){
+ pBlock->base.pPrev = pToken->base.pPrev;
+ pBlock->base.pNext = pToken;
+ pBlock->pPrev = htmlPtr->lastBlock;
+ pBlock->pNext = 0;
+ if( htmlPtr->lastBlock ){
+ htmlPtr->lastBlock->pNext = pBlock;
+ TestPoint(0);
+ }else{
+ htmlPtr->firstBlock = pBlock;
+ TestPoint(0);
+ }
+ htmlPtr->lastBlock = pBlock;
+ if( pToken->base.pPrev ){
+ pToken->base.pPrev->base.pNext = (HtmlElement*)pBlock;
+ TestPoint(0);
+ }else{
+ htmlPtr->pFirst = (HtmlElement*)pBlock;
+ TestPoint(0);
+ }
+ pToken->base.pPrev = (HtmlElement*)pBlock;
+}
+
+/*
+** Print an ordered list index into the given buffer. Use numbering
+** like this:
+**
+** A B C ... Y Z AA BB CC ... ZZ
+**
+** Revert to decimal for indices greater than 52.
+*/
+static void GetLetterIndex(char *zBuf, int index, int isUpper){
+ int seed;
+ if( index<1 || index>52 ){
+ sprintf(zBuf,"%d",index);
+ TestPoint(0);
+ return;
+ }
+ if( isUpper ){
+ seed = 'A';
+ TestPoint(0);
+ }else{
+ seed = 'a';
+ TestPoint(0);
+ }
+ index--;
+ if( index<26 ){
+ zBuf[0] = seed + index;
+ zBuf[1] = 0;
+ TestPoint(0);
+ }else{
+ index -= 26;
+ zBuf[0] = seed + index;
+ zBuf[1] = seed + index;
+ zBuf[2] = 0;
+ TestPoint(0);
+ }
+ strcat(zBuf,".");
+}
+
+/*
+** Print an ordered list index into the given buffer. Use roman
+** numerals. For indices greater than a few thousand, revert to
+** decimal.
+*/
+static void GetRomanIndex(char *zBuf, int index, int isUpper){
+ int i = 0;
+ int j;
+ static struct {
+ int value;
+ char *name;
+ } values[] = {
+ { 1000, "m" },
+ { 999, "im" },
+ { 990, "xm" },
+ { 900, "cm" },
+ { 500, "d" },
+ { 499, "id" },
+ { 490, "xd" },
+ { 400, "cd" },
+ { 100, "c" },
+ { 99, "ic" },
+ { 90, "xc" },
+ { 50, "l" },
+ { 49, "il" },
+ { 40, "xl" },
+ { 10, "x" },
+ { 9, "ix" },
+ { 5, "v" },
+ { 4, "iv" },
+ { 1, "i" },
+ };
+ if( index<1 || index>=5000 ){
+ sprintf(zBuf,"%d",index);
+ TestPoint(0);
+ return;
+ }
+ for(j=0; index>0 && j<sizeof(values)/sizeof(values[0]); j++){
+ int k;
+ while( index >= values[j].value ){
+ for(k=0; values[j].name[k]; k++){
+ zBuf[i++] = values[j].name[k];
+ TestPoint(0);
+ }
+ index -= values[j].value;
+ TestPoint(0);
+ }
+ }
+ zBuf[i] = 0;
+ if( isUpper ){
+ for(i=0; zBuf[i]; i++){
+ zBuf[i] += 'A' - 'a';
+ TestPoint(0);
+ }
+ }else{
+ TestPoint(0);
+ }
+ strcat(zBuf,".");
+}
+
+/* Draw the selection background for the given block
+*/
+static void DrawSelectionBackground(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ HtmlBlock *pBlock, /* The block whose background is drawn */
+ Drawable drawable, /* Draw the background on this drawable */
+ int x, int y /* Virtual coords of top-left of drawable */
+){
+ int xLeft, xRight; /* Left and right bounds of box to draw */
+ int yTop, yBottom; /* Top and bottom of box */
+ HtmlElement *p = 0; /* First element of the block */
+ Tk_Font font; /* Font */
+ GC gc; /* GC for drawing */
+ XRectangle xrec; /* Size of a filled rectangle to be drawn */
+
+ if( pBlock==0 || (pBlock->base.flags & HTML_Selected)==0 ){
+ TestPoint(0);
+ return;
+ }
+ xLeft = pBlock->left - x;
+ if( pBlock==htmlPtr->pSelStartBlock && htmlPtr->selStartIndex>0 ){
+ if( htmlPtr->selStartIndex >= pBlock->n ){ TestPoint(0); return; }
+ p = pBlock->base.pNext;
+ font = HtmlGetFont(htmlPtr, p->base.style.font);
+ if( font==0 ) return;
+ if( p->base.type==Html_Text ){
+ xLeft = p->text.x - x + Tk_TextWidth(font, pBlock->z,
+ htmlPtr->selStartIndex);
+ }
+ }
+ xRight = pBlock->right - x;
+ if( pBlock==htmlPtr->pSelEndBlock && htmlPtr->selEndIndex<pBlock->n ){
+ if( p==0 ){
+ p = pBlock->base.pNext;
+ font = HtmlGetFont(htmlPtr, p->base.style.font);
+ if( font==0 ) return;
+ }
+ if( p->base.type==Html_Text ){
+ xRight = p->text.x - x + Tk_TextWidth(font, pBlock->z,
+ htmlPtr->selEndIndex);
+ }
+ }
+ yTop = pBlock->top - y;
+ yBottom = pBlock->bottom - y;
+ gc = HtmlGetGC(htmlPtr, COLOR_Selection, FONT_Any);
+ xrec.x = xLeft;
+ xrec.y = yTop;
+ xrec.width = xRight - xLeft;
+ xrec.height = yBottom - yTop;
+ XFillRectangles(htmlPtr->display, drawable, gc, &xrec, 1);
+}
+
+/*
+** Draw a rectangle. The rectangle will have a 3-D appearance if
+** flat==0 and a flat appearance if flat==1.
+**
+** We don't use Tk_Draw3DRectangle() because it doesn't work well
+** when the background color is close to pure white or pure black.
+*/
+static void HtmlDrawRect(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Drawable drawable, /* Draw it here */
+ HtmlElement *src, /* Element associated with drawing */
+ int x, int y, int w, int h, /* Coordinates of the rectangle */
+ int depth, /* Width of the relief, or the flat line */
+ int relief /* The relief. TK_RELIEF_FLAT omits 3d */
+){
+ if( depth>0 ){
+ int i;
+ GC gcLight, gcDark;
+ XRectangle xrec[1];
+ if( relief!=TK_RELIEF_FLAT ){
+ int iLight, iDark;
+ iLight = HtmlGetLightShadowColor(htmlPtr, src->base.style.bgcolor);
+ gcLight = HtmlGetGC(htmlPtr, iLight, FONT_Any);
+ iDark = HtmlGetDarkShadowColor(htmlPtr, src->base.style.bgcolor);
+ gcDark = HtmlGetGC(htmlPtr, iDark, FONT_Any);
+ if( relief==TK_RELIEF_SUNKEN ){
+ GC gcTemp = gcLight;
+ gcLight = gcDark;
+ gcDark = gcTemp;
+ }
+ }else{
+ gcLight = HtmlGetGC(htmlPtr, src->base.style.color, FONT_Any);
+ gcDark = gcLight;
+ }
+ xrec[0].x = x;
+ xrec[0].y = y;
+ xrec[0].width = depth;
+ xrec[0].height = h;
+ XFillRectangles(htmlPtr->display, drawable, gcLight, xrec, 1);
+ xrec[0].x = x+w-depth;
+ XFillRectangles(htmlPtr->display, drawable, gcDark, xrec, 1);
+ for(i=0; i<depth && i<h/2; i++){
+ XDrawLine(htmlPtr->display, drawable, gcLight, x+i, y+i, x+w-i-1, y+i);
+ XDrawLine(htmlPtr->display, drawable, gcDark, x+i, y+h-i-1,
+ x+w-i-1, y+h-i-1);
+ }
+ }
+ if( h>depth*2 && w>depth*2 ){
+ GC gcBg;
+ XRectangle xrec[1];
+ gcBg = HtmlGetGC(htmlPtr, src->base.style.bgcolor, FONT_Any);
+ xrec[0].x = x + depth;
+ xrec[0].y = y + depth;
+ xrec[0].width = w - depth*2;
+ xrec[0].height = h - depth*2;
+ XFillRectangles(htmlPtr->display, drawable, gcBg, xrec, 1);
+ }
+}
+
+/*
+** Display a single HtmlBlock. This is where all the drawing
+** happens.
+*/
+void HtmlBlockDraw(
+ HtmlWidget *htmlPtr, /* The main HTML widget */
+ HtmlBlock *pBlock, /* Block which needs to be drawn */
+ Drawable drawable, /* Draw the line on this */
+ int drawableLeft, /* Virtual coordinate of left edge of drawable */
+ int drawableTop, /* Virtual coordinate of top edge of drawable */
+ int drawableWidth, /* Width of the drawable */
+ int drawableHeight /* Height of the drawable */
+){
+ Tk_Font font; /* Font to use to render text */
+ GC gc; /* A graphics context */
+ HtmlElement *src; /* HtmlElement holding style information */
+ HtmlElement *pTable; /* The table (when drawing part of a table) */
+ int x, y; /* Where to draw */
+
+ if( pBlock==0 ){ TestPoint(0); return; }
+ src = pBlock->base.pNext;
+ while( src && (src->base.flags & HTML_Visible)==0 ){
+ src = src->base.pNext;
+ TestPoint(0);
+ }
+ if( src==0 ){ TestPoint(0); return; }
+ if( pBlock->n>0 ){
+ /* We must be dealing with plain old text */
+ if( src->base.type==Html_Text ){
+ x = src->text.x;
+ y = src->text.y;
+ TestPoint(0);
+ }else{
+ CANT_HAPPEN;
+ return;
+ }
+ if( pBlock->base.flags & HTML_Selected ){
+ HtmlLock(htmlPtr);
+ DrawSelectionBackground(htmlPtr, pBlock, drawable,
+ drawableLeft, drawableTop);
+ if( HtmlUnlock(htmlPtr) ) return;
+ }
+ gc = HtmlGetGC(htmlPtr, src->base.style.color, src->base.style.font);
+ font = HtmlGetFont(htmlPtr, src->base.style.font);
+ if( font==0 ) return;
+ Tk_DrawChars(htmlPtr->display,
+ drawable,
+ gc, font,
+ pBlock->z, pBlock->n,
+ x - drawableLeft, y - drawableTop);
+ if( src->base.style.flags & STY_Underline ){
+ Tk_UnderlineChars(htmlPtr->display, drawable, gc, font, pBlock->z,
+ x - drawableLeft, y-drawableTop, 0, pBlock->n);
+ }
+ if( src->base.style.flags & STY_StrikeThru ){
+ XRectangle xrec;
+ xrec.x = pBlock->left - drawableLeft;
+ xrec.y = (pBlock->top + pBlock->bottom)/2 - drawableTop;
+ xrec.width = pBlock->right - pBlock->left;
+ xrec.height = 1 + (pBlock->bottom - pBlock->top > 15);
+ XFillRectangles(htmlPtr->display, drawable, gc, &xrec, 1);
+ }
+ if( pBlock==htmlPtr->pInsBlock && htmlPtr->insStatus>0 ){
+ int x;
+ XRectangle xrec;
+ if( htmlPtr->insIndex < pBlock->n ){
+ x = src->text.x - drawableLeft;
+ x += Tk_TextWidth(font, pBlock->z, htmlPtr->insIndex);
+ }else{
+ x = pBlock->right - drawableLeft;
+ }
+ if( x>0 ){ TestPoint(0); x--; }
+ xrec.x = x;
+ xrec.y = pBlock->top - drawableTop;
+ xrec.width = 2;
+ xrec.height = pBlock->bottom - pBlock->top;
+ XFillRectangles(htmlPtr->display, drawable, gc, &xrec, 1);
+ }
+ }else{
+ /* We are dealing with a single HtmlElement which contains something
+ ** other than plain text. */
+ int top=0;
+ int btm=0;
+ int cntr;
+ int cnt, w;
+ char zBuf[30];
+ switch( src->base.type ){
+ case Html_LI:
+ x = src->li.x;
+ y = src->li.y;
+ cntr = (top+btm)/2;
+ switch( src->li.type ){
+ case LI_TYPE_Enum_1:
+ sprintf(zBuf,"%d.",src->li.cnt);
+ TestPoint(0);
+ break;
+ case LI_TYPE_Enum_A:
+ GetLetterIndex(zBuf,src->li.cnt,1);
+ TestPoint(0);
+ break;
+ case LI_TYPE_Enum_a:
+ GetLetterIndex(zBuf,src->li.cnt,0);
+ TestPoint(0);
+ break;
+ case LI_TYPE_Enum_I:
+ GetRomanIndex(zBuf,src->li.cnt,1);
+ TestPoint(0);
+ break;
+ case LI_TYPE_Enum_i:
+ GetRomanIndex(zBuf,src->li.cnt,0);
+ TestPoint(0);
+ break;
+ default:
+ zBuf[0] = 0;
+ TestPoint(0);
+ break;
+ }
+ gc = HtmlGetGC(htmlPtr, src->base.style.color, src->base.style.font);
+ switch( src->li.type ){
+ case LI_TYPE_Undefined:
+ case LI_TYPE_Bullet1:
+ XFillArc(htmlPtr->display,
+ drawable,
+ gc,
+ x - 7 - drawableLeft, y - 8 - drawableTop, 7, 7,
+ 0, 360*64);
+ TestPoint(0);
+ break;
+
+ case LI_TYPE_Bullet2:
+ XDrawArc(htmlPtr->display,
+ drawable,
+ gc,
+ x - 7 - drawableLeft, y - 8 - drawableTop, 7, 7,
+ 0, 360*64);
+ TestPoint(0);
+ break;
+
+ case LI_TYPE_Bullet3:
+ XDrawRectangle(htmlPtr->display,
+ drawable,
+ gc,
+ x - 7 - drawableLeft, y - 8 - drawableTop, 7, 7);
+ TestPoint(0);
+ break;
+
+ case LI_TYPE_Enum_1:
+ case LI_TYPE_Enum_A:
+ case LI_TYPE_Enum_a:
+ case LI_TYPE_Enum_I:
+ case LI_TYPE_Enum_i:
+ cnt = strlen(zBuf);
+ font = HtmlGetFont(htmlPtr, src->base.style.font);
+ if( font==0 ) return;
+ w = Tk_TextWidth(font, zBuf, cnt);
+ Tk_DrawChars(htmlPtr->display,
+ drawable,
+ gc, font,
+ zBuf, cnt,
+ x - w - drawableLeft, y - drawableTop);
+ TestPoint(0);
+ break;
+ }
+ break;
+ case Html_HR: {
+ int relief = htmlPtr->ruleRelief;
+ switch( relief ){
+ case TK_RELIEF_RAISED:
+ case TK_RELIEF_SUNKEN:
+ break;
+ default:
+ relief = TK_RELIEF_FLAT;
+ break;
+ }
+ HtmlDrawRect(htmlPtr, drawable, src,
+ src->hr.x - drawableLeft,
+ src->hr.y - drawableTop,
+ src->hr.w,
+ src->hr.h,
+ 1, relief);
+ break;
+ }
+ case Html_TABLE: {
+ int relief = htmlPtr->tableRelief;
+ switch( relief ){
+ case TK_RELIEF_RAISED:
+ case TK_RELIEF_SUNKEN:
+ break;
+ default:
+ relief = TK_RELIEF_FLAT;
+ break;
+ }
+ HtmlDrawRect(htmlPtr, drawable, src,
+ src->table.x - drawableLeft,
+ src->table.y - drawableTop,
+ src->table.w,
+ src->table.h,
+ src->table.borderWidth,
+ relief);
+ break;
+ }
+ case Html_TH:
+ case Html_TD: {
+ int depth, relief;
+ pTable = src->cell.pTable;
+ depth = pTable && pTable->table.borderWidth>0;
+ switch( htmlPtr->tableRelief ){
+ case TK_RELIEF_RAISED: relief = TK_RELIEF_SUNKEN; break;
+ case TK_RELIEF_SUNKEN: relief = TK_RELIEF_RAISED; break;
+ default: relief = TK_RELIEF_FLAT; break;
+ }
+ HtmlDrawRect(htmlPtr, drawable, src,
+ src->cell.x - drawableLeft,
+ src->cell.y - drawableTop,
+ src->cell.w,
+ src->cell.h,
+ depth,
+ relief);
+ break;
+ }
+ case Html_IMG:
+ if( src->image.pImage ){
+ HtmlDrawImage(src, drawable, drawableLeft, drawableTop,
+ drawableLeft + drawableWidth,
+ drawableTop + drawableHeight);
+ }else if( src->image.zAlt ){
+ gc = HtmlGetGC(htmlPtr, src->base.style.color, src->base.style.font);
+ font = HtmlGetFont(htmlPtr, src->base.style.font);
+ if( font==0 ) return;
+ Tk_DrawChars(htmlPtr->display,
+ drawable,
+ gc, font,
+ src->image.zAlt, strlen(src->image.zAlt),
+ src->image.x - drawableLeft,
+ src->image.y - drawableTop);
+ TestPoint(0);
+ }
+ break;
+ default:
+ TestPoint(0);
+ break;
+ }
+ }
+}
+
+/*
+** Draw all or part of an image.
+*/
+void HtmlDrawImage(
+ HtmlElement *pElem, /* The <IMG> to be drawn */
+ Drawable drawable, /* Draw it here */
+ int drawableLeft, /* left edge of the drawable */
+ int drawableTop, /* Virtual canvas coordinate for top of drawable */
+ int drawableRight, /* right edge of the drawable */
+ int drawableBottom /* bottom edge of the drawable */
+){
+ int imageTop; /* virtual canvas coordinate for top of image */
+ int x, y; /* where to place image on the drawable */
+ int imageX, imageY; /* \__ Subset of image that fits */
+ int imageW, imageH; /* / on the drawable */
+
+ imageTop = pElem->image.y - pElem->image.ascent;
+ y = imageTop - drawableTop;
+ if( imageTop + pElem->image.h > drawableBottom ){
+ imageH = drawableBottom - imageTop;
+ TestPoint(0);
+ }else{
+ imageH = pElem->image.h;
+ TestPoint(0);
+ }
+ if( y<0 ){
+ imageY = -y;
+ imageH += y;
+ y = 0;
+ TestPoint(0);
+ }else{
+ imageY = 0;
+ TestPoint(0);
+ }
+ x = pElem->image.x - drawableLeft;
+ if( pElem->image.x + pElem->image.w > drawableRight ){
+ imageW = drawableRight - pElem->image.x;
+ TestPoint(0);
+ }else{
+ imageW = pElem->image.w;
+ TestPoint(0);
+ }
+ if( x<0 ){
+ imageX = -x;
+ imageW += x;
+ x = 0;
+ TestPoint(0);
+ }else{
+ imageX = 0;
+ TestPoint(0);
+ }
+ Tk_RedrawImage(pElem->image.pImage->image, imageX, imageY, imageW, imageH,
+ drawable, x, y);
+ pElem->image.redrawNeeded = 0;
+}
+
+/*
+** Recompute the following fields of the given block structure:
+**
+** base.count The number of elements described by this
+** block structure.
+**
+** n The number of characters of text output
+** associated with this block. If the block
+** renders something other than text (ex: <IMG>)
+** then set n to 0.
+**
+** z Pointer to malloced memory containing the
+** text associated with this block. NULL if
+** n is 0.
+**
+** Return a pointer to the first HtmlElement not covered by the
+** block.
+*/
+static HtmlElement *FillOutBlock(HtmlWidget *htmlPtr, HtmlBlock *p){
+ HtmlElement *pElem;
+ int go;
+ int n;
+ int x, y;
+ int i;
+ HtmlStyle style;
+ int firstSelected; /* First selected character in this block */
+ int lastSelected; /* Last selected character in this block */
+ char zBuf[400];
+
+ /*
+ ** Reset n and z
+ */
+ if( p->n ){
+ p->n = 0;
+ }
+ if( p->z ){
+ HtmlFree(p->z);
+ }
+ firstSelected = 1000000;
+ lastSelected = -1;
+
+ /*
+ ** Skip over HtmlElements that aren't directly displayed.
+ */
+ pElem = p->base.pNext;
+ p->base.count = 0;
+ while( pElem && (pElem->base.flags & HTML_Visible)==0 ){
+ HtmlElement *pNext = pElem->pNext;
+ if( pElem->base.type==Html_Block ){
+ UnlinkAndFreeBlock(htmlPtr, &pElem->block);
+ TestPoint(0);
+ }else{
+ p->base.count++;
+ TestPoint(0);
+ }
+ pElem = pNext;
+ }
+ if( pElem==0 ){ TestPoint(0); return 0; }
+
+ /*
+ ** Handle "special" elements.
+ */
+ if( pElem->base.type!=Html_Text ){
+ switch( pElem->base.type ){
+ case Html_HR:
+ p->top = pElem->hr.y - pElem->hr.h;
+ p->bottom = pElem->hr.y;
+ p->left = pElem->hr.x;
+ p->right = pElem->hr.x + pElem->hr.w;
+ TestPoint(0);
+ break;
+ case Html_LI:
+ p->top = pElem->li.y - pElem->li.ascent;
+ p->bottom = pElem->li.y + pElem->li.descent;
+ p->left = pElem->li.x - 10;
+ p->right = pElem->li.x + 10;
+ TestPoint(0);
+ break;
+ case Html_TD:
+ case Html_TH:
+ p->top = pElem->cell.y;
+ p->bottom = pElem->cell.y + pElem->cell.h;
+ p->left = pElem->cell.x;
+ p->right = pElem->cell.x + pElem->cell.w;
+ TestPoint(0);
+ break;
+ case Html_TABLE:
+ p->top = pElem->table.y;
+ p->bottom = pElem->table.y + pElem->table.h;
+ p->left = pElem->table.x;
+ p->right = pElem->table.x + pElem->table.w;
+ TestPoint(0);
+ break;
+ case Html_IMG:
+ p->top = pElem->image.y - pElem->image.ascent;
+ p->bottom = pElem->image.y + pElem->image.descent;
+ p->left = pElem->image.x;
+ p->right = pElem->image.x + pElem->image.w;
+ TestPoint(0);
+ break;
+ }
+ p->base.count++;
+ TestPoint(0);
+ return pElem->pNext;
+ }
+
+ /*
+ ** If we get this far, we must be dealing with text.
+ */
+ n = 0;
+ x = pElem->text.x;
+ y = pElem->text.y;
+ p->top = y - pElem->text.ascent;
+ p->bottom = y + pElem->text.descent;
+ p->left = x;
+ style = pElem->base.style;
+ go = 1;
+ while( pElem ){
+ HtmlElement *pNext = pElem->pNext;
+ switch( pElem->base.type ){
+ case Html_Text:
+ if( pElem->base.style.flags & STY_Invisible ){
+ TestPoint(0);
+ break;
+ }
+ if( pElem->text.spaceWidth <=0 ){
+ CANT_HAPPEN;
+ break;
+ }
+ if( y != pElem->text.y
+ || style.font != pElem->base.style.font
+ || style.color != pElem->base.style.color
+ || (style.flags & STY_FontMask)
+ != (pElem->base.style.flags & STY_FontMask)
+ ){
+ go = 0;
+ TestPoint(0);
+ }else{
+ int sw = pElem->text.spaceWidth;
+ int nSpace = (pElem->text.x - x) / sw;
+ if( nSpace * sw + x != pElem->text.x ){
+ go = 0;
+ TestPoint(0);
+ }else if( n + nSpace + pElem->base.count >= sizeof(zBuf) ){
+ go = 0;
+ TestPoint(0);
+ }else{
+ for(i=0; i<nSpace; i++){
+ zBuf[n++] = ' ';
+ TestPoint(0);
+ }
+ strcpy(&zBuf[n], pElem->text.zText);
+ n += pElem->base.count;
+ x = pElem->text.x + pElem->text.w;
+ }
+ }
+ break;
+
+ case Html_Space:
+ if( pElem->base.style.font != style.font ){
+ pElem = pElem->pNext;
+ go = 0;
+ }else if( (style.flags & STY_Preformatted)!=0
+ && (pElem->base.flags & HTML_NewLine)!=0 ){
+ pElem = pElem->pNext;
+ go = 0;
+ }
+ break;
+
+ case Html_Block:
+ UnlinkAndFreeBlock(htmlPtr,&pElem->block);
+ break;
+
+ case Html_A:
+ case Html_EndA:
+ go = 0;
+ break;
+
+ default:
+ if( pElem->base.flags & HTML_Visible ) go = 0;
+ TestPoint(0);
+ break;
+ }
+ if( go==0 ) break;
+ p->base.count++;
+ pElem = pNext;
+ }
+ p->right = x;
+
+ while( n>0 && zBuf[n-1]==' ' ){ TestPoint(0); n--; }
+ p->z = HtmlAlloc( n );
+ strncpy(p->z, zBuf, n);
+ p->n = n;
+ return pElem;
+}
+
+/*
+** Scan ahead looking for a place to put a block. Return a pointer
+** to the element which should come immediately after the block.
+**
+** if pCnt!=0, then put the number of elements skipped in *pCnt.
+*/
+static HtmlElement *FindStartOfNextBlock(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ HtmlElement *p, /* First candid for the start of a block */
+ int *pCnt /* Write number of elements skipped here */
+){
+ int cnt = 0;
+
+ while( p && (p->base.flags & HTML_Visible)==0 ){
+ HtmlElement *pNext = p->pNext;
+ if( p->base.type==Html_Block ){
+ UnlinkAndFreeBlock(htmlPtr, &p->block);
+ }else{
+ cnt++;
+ }
+ p = pNext;
+ }
+ if( pCnt ){ *pCnt = cnt; }
+ return p;
+}
+
+
+/*
+** Add additional blocks to the block list in order to cover
+** all elements on the element list.
+**
+** If any old blocks are found on the element list, they must
+** be left over from a prior rendering. Unlink and delete them.
+*/
+void HtmlFormBlocks(HtmlWidget *htmlPtr){
+ HtmlElement *pElem;
+
+ if( htmlPtr->lastBlock ){
+ pElem = FillOutBlock(htmlPtr, htmlPtr->lastBlock);
+ }else{
+ pElem = htmlPtr->pFirst;
+ }
+ while( pElem ){
+ int cnt;
+ pElem = FindStartOfNextBlock(htmlPtr, pElem, &cnt);
+ if( pElem ){
+ HtmlBlock *pNew = AllocBlock();
+ if( htmlPtr->lastBlock ){
+ htmlPtr->lastBlock->base.count += cnt;
+ }
+ AppendBlock(htmlPtr, pElem, pNew);
+ pElem = FillOutBlock(htmlPtr, pNew);
+ }
+ }
+}
diff --git a/tkhtml1/src/htmldraw.h b/tkhtml1/src/htmldraw.h
new file mode 100644
index 0000000..7976f89
--- /dev/null
+++ b/tkhtml1/src/htmldraw.h
@@ -0,0 +1,483 @@
+/* This file was automatically generated. Do not edit! */
+typedef struct HtmlWidget HtmlWidget;
+void HtmlFormBlocks(HtmlWidget *htmlPtr);
+#define Html_EndA 6
+#define Html_A 5
+#define HTML_NewLine 0x02 /* type==Html_Space and ends with newline */
+#define STY_Preformatted 0x001
+#define Html_Space 2
+#define STY_StrikeThru 0x002
+#define STY_Underline 0x004
+#define STY_FontMask (STY_StrikeThru|STY_Underline)
+#define STY_Invisible 0x040
+typedef struct HtmlStyle HtmlStyle;
+struct HtmlStyle {
+ unsigned int font : 6; /* Font to use for display */
+ unsigned int color : 4; /* Foreground color */
+ signed int subscript : 4; /* Positive for <sup>, negative for <sub> */
+ unsigned int align : 2; /* Horizontal alignment */
+ unsigned int bgcolor : 4; /* Background color */
+ unsigned int flags : 12; /* the STY_ flags below */
+};
+typedef union HtmlElement HtmlElement;
+void HtmlDrawImage(HtmlElement *pElem,Drawable drawable,int drawableLeft,int drawableTop,int drawableRight,int drawableBottom);
+#define Html_IMG 76
+#define Html_TD 131
+#define Html_TH 135
+#define Html_TABLE 129
+#define Html_HR 70
+#define LI_TYPE_Bullet3 3 /* A hollow square */
+#define LI_TYPE_Bullet2 2 /* A hollow circle */
+#define LI_TYPE_Bullet1 1 /* A solid circle */
+#define LI_TYPE_Undefined 0 /* If in HtmlLi, use the HtmlListStart value */
+#define LI_TYPE_Enum_i 8 /* Lower-case roman numerals */
+#define LI_TYPE_Enum_I 7 /* Capitalized roman numerals */
+#define LI_TYPE_Enum_a 6 /* a, b, c, ... */
+#define LI_TYPE_Enum_A 5 /* A, B, C, ... */
+#define LI_TYPE_Enum_1 4 /* Arabic numbers */
+#define Html_LI 81
+int HtmlUnlock(HtmlWidget *htmlPtr);
+void HtmlLock(HtmlWidget *htmlPtr);
+void HtmlTPCantHappen(const char *zFile,int line);
+#if defined(COVERAGE_TEST)
+# define CANT_HAPPEN HtmlTPCantHappen(__FILE__,__LINE__)
+#endif
+#if !(defined(COVERAGE_TEST))
+# define CANT_HAPPEN
+#endif
+#define HTML_Visible 0x01 /* This element produces "ink" */
+typedef struct HtmlBlock HtmlBlock;
+void HtmlBlockDraw(HtmlWidget *htmlPtr,HtmlBlock *pBlock,Drawable drawable,int drawableLeft,int drawableTop,int drawableWidth,int drawableHeight);
+int HtmlGetDarkShadowColor(HtmlWidget *htmlPtr,int iBgColor);
+int HtmlGetLightShadowColor(HtmlWidget *htmlPtr,int iBgColor);
+#define FONT_Any -1
+#define COLOR_Selection 3 /* Background color for the selection */
+GC HtmlGetGC(HtmlWidget *htmlPtr,int color,int font);
+#define Html_Text 1
+Tk_Font HtmlGetFont(HtmlWidget *htmlPtr,int iFont);
+#define HTML_Selected 0x04 /* Some or all of this Html_Block is selected */
+typedef struct HtmlBaseElement HtmlBaseElement;
+typedef unsigned char Html_u8;
+typedef short Html_16;
+struct HtmlBaseElement {
+ HtmlElement *pNext; /* Next input token in a list of them all */
+ HtmlElement *pPrev; /* Previous token in a list of them all */
+ HtmlStyle style; /* The rendering style for this token */
+ Html_u8 type; /* The token type. */
+ Html_u8 flags; /* The HTML_ flags below */
+ Html_16 count; /* Various uses, depending on "type" */
+};
+typedef struct HtmlTextElement HtmlTextElement;
+typedef int Html_32;
+struct HtmlTextElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_32 y; /* y coordinate where text should be rendered */
+ Html_16 x; /* x coordinate where text should be rendered */
+ Html_16 w; /* width of this token in pixels */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_u8 spaceWidth; /* Width of one space in the current font */
+ char zText[1]; /* Text for this element. Null terminated */
+};
+typedef struct HtmlSpaceElement HtmlSpaceElement;
+struct HtmlSpaceElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_16 w; /* Width of a single space in current font */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+};
+typedef struct HtmlMarkupElement HtmlMarkupElement;
+struct HtmlMarkupElement {
+ HtmlBaseElement base;
+ char **argv;
+};
+typedef struct HtmlCell HtmlCell;
+struct HtmlCell {
+ HtmlMarkupElement markup;
+ Html_16 rowspan; /* Number of rows spanned by this cell */
+ Html_16 colspan; /* Number of columns spanned by this cell */
+ Html_16 x; /* X coordinate of left edge of border */
+ Html_16 w; /* Width of the border */
+ Html_32 y; /* Y coordinate of top of border indentation */
+ Html_32 h; /* Height of the border */
+ HtmlElement *pTable; /* Pointer back to the <table> */
+ HtmlElement *pEnd; /* Element that ends this cell */
+};
+typedef struct HtmlTable HtmlTable;
+typedef unsigned short Html_u16;
+#define HTML_MAX_COLUMNS 40
+struct HtmlTable {
+ HtmlMarkupElement markup;
+ Html_u8 borderWidth; /* Width of the border */
+ Html_u8 nCol; /* Number of columns */
+ Html_u16 nRow; /* Number of rows */
+ Html_32 y; /* top edge of table border */
+ Html_32 h; /* height of the table border */
+ Html_16 x; /* left edge of table border */
+ Html_16 w; /* width of the table border */
+ int minW[HTML_MAX_COLUMNS+1]; /* minimum width of each column */
+ int maxW[HTML_MAX_COLUMNS+1]; /* maximum width of each column */
+};
+typedef struct HtmlRef HtmlRef;
+struct HtmlRef {
+ HtmlMarkupElement markup;
+ HtmlElement *pOther; /* Pointer to some other Html element */
+};
+typedef struct HtmlLi HtmlLi;
+struct HtmlLi {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* What type of list is this? */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_16 cnt; /* Value for this element (if inside <OL>) */
+ Html_16 x; /* X coordinate of the bullet */
+ Html_32 y; /* Y coordinate of the bullet */
+};
+typedef struct HtmlListStart HtmlListStart;
+struct HtmlListStart {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* One of the LI_TYPE_ defines above */
+ Html_u8 compact; /* True if the COMPACT flag is present */
+ Html_u16 cnt; /* Next value for <OL> */
+ Html_u16 width; /* How much space to allow for indentation */
+ HtmlElement *pPrev; /* Next higher level list, or NULL */
+};
+typedef struct HtmlImageMarkup HtmlImageMarkup;
+typedef struct HtmlImage HtmlImage;
+struct HtmlImageMarkup {
+ HtmlMarkupElement markup;
+ Html_u8 align; /* Alignment. See IMAGE_ALIGN_ defines below */
+ Html_u8 textAscent; /* Ascent of text font in force at the <IMG> */
+ Html_u8 textDescent; /* Descent of text font in force at the <IMG> */
+ Html_u8 redrawNeeded; /* Need to redraw this image because the image
+ ** content changed. */
+ Html_16 h; /* Actual height of the image */
+ Html_16 w; /* Actual width of the image */
+ Html_16 ascent; /* How far image extends above "y" */
+ Html_16 descent; /* How far image extends below "y" */
+ Html_16 x; /* X coordinate of left edge of the image */
+ Html_32 y; /* Y coordinate of image baseline */
+ char *zAlt; /* Alternative text */
+ HtmlImage *pImage; /* Corresponding HtmlImage structure */
+ HtmlElement *pNext; /* Next markup using the same HtmlImage structure */
+};
+typedef struct HtmlInput HtmlInput;
+struct HtmlInput {
+ HtmlMarkupElement markup;
+ HtmlElement *pForm; /* The <FORM> to which this belongs */
+ HtmlElement *pNext; /* Next element in a list of all input elements */
+ Tk_Window tkwin; /* The window that implements this control */
+ HtmlWidget *htmlPtr; /* The whole widget. Needed by geometry callbacks */
+ HtmlElement *pEnd; /* End tag for <TEXTAREA>, etc. */
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 padLeft; /* Extra padding on left side of the control */
+ Html_u8 align; /* One of the IMAGE_ALIGN_xxx types */
+ Html_u8 textAscent; /* Ascent for the current font */
+ Html_u8 textDescent; /* descent for the current font */
+ Html_u8 type; /* What type of input is this? */
+ Html_u8 sized; /* True if this input has been sized already */
+ Html_u16 cnt; /* Used to derive widget name. 0 if no widget */
+};
+typedef struct HtmlForm HtmlForm;
+struct HtmlForm {
+ HtmlMarkupElement markup;
+ Html_u16 id; /* Unique number assigned to this form */
+};
+typedef struct HtmlHr HtmlHr;
+struct HtmlHr {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 is3D; /* Is it drawn 3D? */
+};
+typedef struct HtmlAnchor HtmlAnchor;
+struct HtmlAnchor {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Top edge for this element */
+};
+typedef struct HtmlScript HtmlScript;
+struct HtmlScript {
+ HtmlMarkupElement markup;
+ char *zScript; /* Complete text of this script */
+ int nScript; /* Number of characters of text */
+};
+struct HtmlBlock {
+ HtmlBaseElement base; /* Superclass. Must be first */
+ char *z; /* Space to hold text when n>0 */
+ int top, bottom; /* Extremes of y coordinates */
+ Html_u16 left, right; /* Left and right boundry of this object */
+ Html_u16 n; /* Number of characters in z[] */
+ HtmlBlock *pPrev, *pNext; /* Linked list of all Blocks */
+};
+union HtmlElement {
+ HtmlElement *pNext;
+ HtmlBaseElement base;
+ HtmlTextElement text;
+ HtmlSpaceElement space;
+ HtmlMarkupElement markup;
+ HtmlCell cell;
+ HtmlTable table;
+ HtmlRef ref;
+ HtmlLi li;
+ HtmlListStart list;
+ HtmlImageMarkup image;
+ HtmlInput input;
+ HtmlForm form;
+ HtmlHr hr;
+ HtmlAnchor anchor;
+ HtmlScript script;
+ HtmlBlock block;
+};
+#if defined(COVERAGE_TEST)
+extern int HtmlTPArray[2000];
+# define TestPoint(X) {extern int HtmlTPArray[]; HtmlTPArray[X]++;}
+#endif
+#if !(defined(COVERAGE_TEST))
+# define TestPoint(X)
+#endif
+typedef struct HtmlIndex HtmlIndex;
+struct HtmlIndex {
+ HtmlElement *p; /* The token containing the character */
+ int i; /* Index of the character */
+};
+#define Html_TypeCount 151
+typedef struct HtmlStyleStack HtmlStyleStack;
+typedef struct HtmlLayoutContext HtmlLayoutContext;
+typedef struct HtmlMargin HtmlMargin;
+struct HtmlLayoutContext {
+ HtmlWidget *htmlPtr; /* The html widget undergoing layout */
+ HtmlElement *pStart; /* Start of elements to layout */
+ HtmlElement *pEnd; /* Stop when reaching this element */
+ int headRoom; /* Extra space wanted above this line */
+ int top; /* Absolute top of drawing area */
+ int bottom; /* Bottom of previous line */
+ int left, right; /* Left and right extremes of drawing area */
+ int pageWidth; /* Width of the layout field, including
+ ** the margins */
+ int maxX, maxY; /* Maximum X and Y values of paint */
+ HtmlMargin *leftMargin; /* Stack of left margins */
+ HtmlMargin *rightMargin; /* Stack of right margins */
+};
+#define N_FONT_FAMILY 8
+#define N_FONT_SIZE 7
+#define N_FONT (N_FONT_FAMILY*N_FONT_SIZE)
+#define N_COLOR 16 /* Total number of colors */
+typedef struct GcCache GcCache;
+struct GcCache {
+ GC gc; /* The graphics context */
+ Html_u8 font; /* Font used for this context */
+ Html_u8 color; /* Color used for this context */
+ Html_u8 index; /* Index used for LRU replacement */
+};
+#define N_CACHE_GC 16
+struct HtmlWidget {
+ Tk_Window tkwin; /* The main window for this widget */
+ Tk_Window clipwin; /* The clipping window in which all text is
+ ** rendered. */
+ char *zClipwin; /* Name of the clipping window. */
+ Display *display; /* The X11 Server that contains tkwin */
+ Tcl_Interp *interp; /* The interpreter in which the widget lives */
+ char *zCmdName; /* Name of the command */
+ HtmlElement *pFirst; /* First HTML token on a list of them all */
+ HtmlElement *pLast; /* Last HTML token on the list */
+ int nToken; /* Number of HTML tokens on the list.
+ * Html_Block tokens don't count. */
+ HtmlElement *lastSized; /* Last HTML element that has been sized */
+ HtmlElement *nextPlaced; /* Next HTML element that needs to be
+ * positioned on canvas. */
+ HtmlBlock *firstBlock; /* List of all HtmlBlock tokens */
+ HtmlBlock *lastBlock; /* Last HtmlBlock in the list */
+ HtmlElement *firstInput; /* First <INPUT> element */
+ HtmlElement *lastInput; /* Last <INPUT> element */
+ int nInput; /* The number of <INPUT> elements */
+ int nForm; /* The number of <FORM> elements */
+ int varId; /* Used to construct a unique name for a
+ ** global array used by <INPUT> elements */
+
+ /*
+ * Information about the selected region of text
+ */
+ HtmlIndex selBegin; /* Start of the selection */
+ HtmlIndex selEnd; /* End of the selection */
+ HtmlBlock *pSelStartBlock; /* Block in which selection starts */
+ Html_16 selStartIndex; /* Index in pSelStartBlock of first selected
+ * character */
+ Html_16 selEndIndex; /* Index of last selecte char in pSelEndBlock */
+ HtmlBlock *pSelEndBlock; /* Block in which selection ends */
+
+ /*
+ * Information about the insertion cursor
+ */
+ int insOnTime; /* How long the cursor states one (millisec) */
+ int insOffTime; /* How long it is off (milliseconds) */
+ int insStatus; /* Is it visible? */
+ Tcl_TimerToken insTimer; /* Timer used to flash the insertion cursor */
+ HtmlIndex ins; /* The insertion cursor position */
+ HtmlBlock *pInsBlock; /* The HtmlBlock containing the cursor */
+ int insIndex; /* Index in pInsBlock of the cursor */
+
+ /*
+ * The following fields hold state information used by
+ * the tokenizer.
+ */
+ char *zText; /* Complete text of the unparsed HTML */
+ int nText; /* Number of characters in zText */
+ int nAlloc; /* Space allocated for zText */
+ int nComplete; /* How much of zText has actually been
+ * converted into tokens */
+ int iCol; /* The column in which zText[nComplete]
+ * occurs. Used to resolve tabs in input */
+ int iPlaintext; /* If not zero, this is the token type that
+ * caused us to go into plaintext mode. One
+ * of Html_PLAINTEXT, Html_LISTING or
+ * Html_XMP */
+ HtmlScript *pScript; /* <SCRIPT> currently being parsed */
+ char *zHandler[Html_TypeCount]; /* If not NULL, this is a TCL routine that
+ * is used to process tokens of the given
+ * type */
+ /*
+ * These fields hold state information used by the HtmlAddStyle routine.
+ * We have to store this state information here since HtmlAddStyle
+ * operates incrementally. This information must be carried from
+ * one incremental execution to the next.
+ */
+ HtmlStyleStack *styleStack; /* The style stack */
+ int paraAlignment; /* Justification associated with <p> */
+ int rowAlignment; /* Justification associated with <tr> */
+ int anchorFlags; /* Style flags associated with <A>...</A> */
+ int inDt; /* Style flags associated with <DT>...</DT> */
+ int inTr; /* True if within <tr>..</tr> */
+ int inTd; /* True if within <td>..</td> or <th>..</th> */
+ HtmlElement *anchorStart; /* Most recent <a href=...> */
+ HtmlElement *formStart; /* Most recent <form> */
+ HtmlElement *formElemStart; /* Most recent <textarea> or <select> */
+ HtmlElement *innerList; /* The inner most <OL> or <UL> */
+
+ /*
+ * These fields are used to hold the state of the layout engine.
+ * Because the layout is incremental, this state must be held for
+ * the life of the widget.
+ */
+ HtmlLayoutContext layoutContext;
+
+ /*
+ * Information used when displaying the widget:
+ */
+ Tk_3DBorder border; /* Background color */
+ int borderWidth; /* Width of the border. */
+ int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ int inset; /* Total width of highlight and 3-D border */
+ Tk_Font aFont[N_FONT]; /* Information about all screen fonts */
+ char fontValid[(N_FONT+7)/8]; /* If bit N%8 of work N/8 of this field is 0
+ * if aFont[N] needs to be reallocated before
+ * being used. */
+ XColor *apColor[N_COLOR]; /* Information about all colors */
+ int colorUsed; /* bit N is 1 if color N is in use. Only
+ ** applies to colors that aren't predefined */
+ int iDark[N_COLOR]; /* Dark 3D shadow of color K is iDark[K] */
+ int iLight[N_COLOR]; /* Light 3D shadow of color K is iLight[K] */
+ XColor *fgColor; /* Color of normal text. apColor[0] */
+ XColor *newLinkColor; /* Color of unvisitied links. apColor[1] */
+ XColor *oldLinkColor; /* Color of visitied links. apColor[2] */
+ XColor *selectionColor; /* Background color for selections */
+ GcCache aGcCache[N_CACHE_GC]; /* A cache of GCs for general use */
+ int lastGC; /* Index of recently used GC */
+ HtmlImage *imageList; /* A list of all images */
+ int width, height; /* User-requested size of the usable drawing
+ * area, in pixels. Borders and padding
+ * make the actual window a little larger */
+ int realWidth, realHeight; /* The actual physical size of tkwin as
+ * reported in the most recent ConfigureNotify
+ * event. */
+ int padx, pady; /* Separation between the edge of the window
+ * and rendered HTML. */
+ int underlineLinks; /* TRUE if we should underline hyperlinks */
+
+ /* Information about the selection
+ */
+ int exportSelection; /* True if the selection is automatically
+ * exported to the clipboard */
+
+ /* Callback commands. The HTML parser will invoke callbacks from time
+ ** to time to find out information it needs to complete formatting of
+ ** the document. The following fields define the callback commands.
+ */
+ char *zIsVisited; /* Command to tell if a hyperlink has already
+ ** been visited */
+ char *zGetImage; /* Command to get an image from a URL */
+ char *zFrameCommand; /* Command for handling <frameset> markup */
+ char *zAppletCommand; /* Command to process applets */
+ char *zResolverCommand; /* Command to resolve URIs */
+ char *zFormCommand; /* When user presses Submit */
+ char *zHyperlinkCommand; /* Invoked when a hyperlink is clicked */
+ char *zFontCommand; /* Invoked to find font names */
+ char *zScriptCommand; /* Invoked for each <SCRIPT> markup */
+
+ /*
+ * Miscellaneous information:
+ */
+ int tableRelief; /* 3d effects on <TABLE> */
+ int ruleRelief; /* 3d effects on <HR> */
+ char *zBase; /* The base URI */
+ char *zBaseHref; /* zBase as modified by <BASE HREF=..> markup */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ char *takeFocus; /* Value of -takefocus option; not used in
+ * the C code, but used by keyboard traversal
+ * scripts. Malloc'ed, but may be NULL. */
+ char *yScrollCmd; /* Command prefix for communicating with
+ * vertical scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ char *xScrollCmd; /* Command prefix for communicating with
+ * horizontal scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ int xOffset, yOffset; /* Current scroll position. These form the
+ * coordinate in the virtual canvas that
+ * corresponds to (0,0) on the physical screen
+ * in window tkwin */
+ int maxX, maxY; /* Maximum extent of any "paint" that appears
+ * on the virtual canvas. Used to compute
+ * scrollbar positions. */
+ int dirtyLeft, dirtyTop; /* Top left corner of region to redraw. These
+ * are physical screen coordinates relative to
+ * clipwin, not tkwin. */
+ int dirtyRight, dirtyBottom; /* Bottom right corner of region to redraw */
+ int locked; /* Number of locks on this structure. Don't
+ ** delete until it reaches zero. */
+ int flags; /* Various flags; see below for
+ * definitions. */
+};
+#define HtmlFree(A) Tcl_Free((char*)(A))
+#define Html_Block 4
+/*#define HtmlAlloc(A) ((void*)Tcl_Alloc(A))*/
+void* HtmlAlloc(size_t);
+struct HtmlImage {
+ HtmlWidget *htmlPtr; /* The owner of this image */
+ Tk_Image image; /* The Tk image token */
+ Html_32 w; /* Requested width of this image (0 if none) */
+ Html_32 h; /* Requested height of this image (0 if none) */
+ char *zUrl; /* The URL for this image. */
+ char *zWidth, *zHeight; /* Width and height in the <img> markup. */
+ HtmlImage *pNext; /* Next image on the list */
+ HtmlElement *pList; /* List of all <IMG> markups that use this
+ ** same image */
+};
+struct HtmlStyleStack {
+ HtmlStyleStack *pNext; /* Next style on the stack */
+ int type; /* A markup that ends this style. Ex: Html_EndEM */
+ HtmlStyle style; /* The currently active style. */
+};
+struct HtmlMargin {
+ int indent; /* Size of the current margin */
+ int bottom; /* Y value at which this margin expires */
+ int tag; /* Markup that will cancel this margin */
+ HtmlMargin *pNext; /* Previous margin */
+};
diff --git a/tkhtml1/src/htmlexts.c b/tkhtml1/src/htmlexts.c
new file mode 100644
index 0000000..9496972
--- /dev/null
+++ b/tkhtml1/src/htmlexts.c
@@ -0,0 +1,110 @@
+/*
+** The extra routines for the HTML widget for Tcl/Tk
+**
+** Copyright (C) 1997-2000 Peter MacDonald and BrowseX Systems Inc.
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** peter@browsex.com
+** http://browsex.com
+*/
+
+#include <tk.h>
+#include <string.h>
+#include <stdlib.h>
+#include "htmlexts.h"
+
+void HtmlTclizeAscii(Tcl_Interp *interp, HtmlIndex *s, HtmlIndex *e);
+
+/*
+** WIDGET text ascii START END
+*/
+int HtmlTextAsciiCmd(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ Tcl_Interp *interp, /* The interpreter */
+ int argc, /* Number of arguments */
+ const char **argv /* List of all arguments */
+){
+ HtmlIndex iStart, iEnd;
+ char *cb, *ce;
+ if (argc<=3) cb="begin"; else cb=(char*)argv[3];
+ if (argc<=4) ce=cb; else ce=(char*)argv[4];
+
+ if( HtmlGetIndex(htmlPtr, cb, &iStart.p, &iStart.i)!=0 ){
+ Tcl_AppendResult(interp,"malformed index: \"", cb, "\"", 0);
+ return TCL_ERROR;
+ }
+ if( HtmlGetIndex(htmlPtr, ce, &iEnd.p, &iEnd.i)!=0 ){
+ Tcl_AppendResult(interp,"malformed index: \"", ce, "\"", 0);
+ return TCL_ERROR;
+ }
+ if (iEnd.p && iStart.p) {
+ if ((!iEnd.i) && (!strchr(ce,'.'))) {
+ iEnd.p=iEnd.p->pNext;
+ }
+ HtmlTclizeAscii(interp,&iStart,&iEnd);
+ }
+ return TCL_OK;
+}
+
+/*
+** Return all tokens between the two elements as a Text.
+*/
+void HtmlTclizeAscii(Tcl_Interp *interp, HtmlIndex *s, HtmlIndex *e){
+ int j, nsub=0;
+ HtmlElement* p=s->p;
+ Tcl_DString str;
+ if (p && p->base.type==Html_Text) {
+ nsub=s->i;
+ }
+ Tcl_DStringInit(&str);
+ while( p) {
+ switch( p->base.type ){
+ case Html_Block:
+ break;
+ case Html_Text:
+ j=strlen(p->text.zText);
+ if (j<nsub) nsub=j;
+ if (p==e->p) {
+ j= (e->i-nsub+1);
+ }
+ Tcl_DStringAppend(&str, p->text.zText+nsub,j-nsub);
+ nsub=0;
+ break;
+ case Html_Space:
+ for (j=0; j< p->base.count; j++) {
+ if (nsub-->0) continue;
+ Tcl_DStringAppend(&str, " ", 1);
+ }
+ if ((p->base.flags & HTML_NewLine)!=0)
+ Tcl_DStringAppend(&str, "\n",1);
+ nsub=0;
+ break;
+ case Html_P:
+ case Html_BR:
+ Tcl_DStringAppend(&str, "\n",1);
+ break;
+ case Html_Unknown:
+ break;
+ default:
+ break;
+ }
+ if (p==e->p) break;
+ p = p->pNext;
+ }
+ Tcl_DStringResult(interp, &str);
+}
diff --git a/tkhtml1/src/htmlexts.h b/tkhtml1/src/htmlexts.h
new file mode 100644
index 0000000..e94edde
--- /dev/null
+++ b/tkhtml1/src/htmlexts.h
@@ -0,0 +1,438 @@
+/* This file was automatically generated. Do not edit! */
+#define Html_Unknown 3
+#define Html_BR 24
+#define Html_P 104
+#define HTML_NewLine 0x02 /* type==Html_Space and ends with newline */
+#define Html_Space 2
+#define Html_Block 4
+#define Html_Text 1
+typedef union HtmlElement HtmlElement;
+typedef struct HtmlBaseElement HtmlBaseElement;
+typedef struct HtmlStyle HtmlStyle;
+struct HtmlStyle {
+ unsigned int font : 6; /* Font to use for display */
+ unsigned int color : 4; /* Foreground color */
+ signed int subscript : 4; /* Positive for <sup>, negative for <sub> */
+ unsigned int align : 2; /* Horizontal alignment */
+ unsigned int bgcolor : 4; /* Background color */
+ unsigned int flags : 12; /* the STY_ flags below */
+};
+typedef unsigned char Html_u8;
+typedef short Html_16;
+struct HtmlBaseElement {
+ HtmlElement *pNext; /* Next input token in a list of them all */
+ HtmlElement *pPrev; /* Previous token in a list of them all */
+ HtmlStyle style; /* The rendering style for this token */
+ Html_u8 type; /* The token type. */
+ Html_u8 flags; /* The HTML_ flags below */
+ Html_16 count; /* Various uses, depending on "type" */
+};
+typedef struct HtmlTextElement HtmlTextElement;
+typedef int Html_32;
+struct HtmlTextElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_32 y; /* y coordinate where text should be rendered */
+ Html_16 x; /* x coordinate where text should be rendered */
+ Html_16 w; /* width of this token in pixels */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_u8 spaceWidth; /* Width of one space in the current font */
+ char zText[1]; /* Text for this element. Null terminated */
+};
+typedef struct HtmlSpaceElement HtmlSpaceElement;
+struct HtmlSpaceElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_16 w; /* Width of a single space in current font */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+};
+typedef struct HtmlMarkupElement HtmlMarkupElement;
+struct HtmlMarkupElement {
+ HtmlBaseElement base;
+ char **argv;
+};
+typedef struct HtmlCell HtmlCell;
+struct HtmlCell {
+ HtmlMarkupElement markup;
+ Html_16 rowspan; /* Number of rows spanned by this cell */
+ Html_16 colspan; /* Number of columns spanned by this cell */
+ Html_16 x; /* X coordinate of left edge of border */
+ Html_16 w; /* Width of the border */
+ Html_32 y; /* Y coordinate of top of border indentation */
+ Html_32 h; /* Height of the border */
+ HtmlElement *pTable; /* Pointer back to the <table> */
+ HtmlElement *pEnd; /* Element that ends this cell */
+};
+typedef struct HtmlTable HtmlTable;
+typedef unsigned short Html_u16;
+#define HTML_MAX_COLUMNS 40
+struct HtmlTable {
+ HtmlMarkupElement markup;
+ Html_u8 borderWidth; /* Width of the border */
+ Html_u8 nCol; /* Number of columns */
+ Html_u16 nRow; /* Number of rows */
+ Html_32 y; /* top edge of table border */
+ Html_32 h; /* height of the table border */
+ Html_16 x; /* left edge of table border */
+ Html_16 w; /* width of the table border */
+ int minW[HTML_MAX_COLUMNS+1]; /* minimum width of each column */
+ int maxW[HTML_MAX_COLUMNS+1]; /* maximum width of each column */
+};
+typedef struct HtmlRef HtmlRef;
+struct HtmlRef {
+ HtmlMarkupElement markup;
+ HtmlElement *pOther; /* Pointer to some other Html element */
+};
+typedef struct HtmlLi HtmlLi;
+struct HtmlLi {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* What type of list is this? */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_16 cnt; /* Value for this element (if inside <OL>) */
+ Html_16 x; /* X coordinate of the bullet */
+ Html_32 y; /* Y coordinate of the bullet */
+};
+typedef struct HtmlListStart HtmlListStart;
+struct HtmlListStart {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* One of the LI_TYPE_ defines above */
+ Html_u8 compact; /* True if the COMPACT flag is present */
+ Html_u16 cnt; /* Next value for <OL> */
+ Html_u16 width; /* How much space to allow for indentation */
+ HtmlElement *pPrev; /* Next higher level list, or NULL */
+};
+typedef struct HtmlImageMarkup HtmlImageMarkup;
+typedef struct HtmlImage HtmlImage;
+struct HtmlImageMarkup {
+ HtmlMarkupElement markup;
+ Html_u8 align; /* Alignment. See IMAGE_ALIGN_ defines below */
+ Html_u8 textAscent; /* Ascent of text font in force at the <IMG> */
+ Html_u8 textDescent; /* Descent of text font in force at the <IMG> */
+ Html_u8 redrawNeeded; /* Need to redraw this image because the image
+ ** content changed. */
+ Html_16 h; /* Actual height of the image */
+ Html_16 w; /* Actual width of the image */
+ Html_16 ascent; /* How far image extends above "y" */
+ Html_16 descent; /* How far image extends below "y" */
+ Html_16 x; /* X coordinate of left edge of the image */
+ Html_32 y; /* Y coordinate of image baseline */
+ char *zAlt; /* Alternative text */
+ HtmlImage *pImage; /* Corresponding HtmlImage structure */
+ HtmlElement *pNext; /* Next markup using the same HtmlImage structure */
+};
+typedef struct HtmlInput HtmlInput;
+typedef struct HtmlWidget HtmlWidget;
+struct HtmlInput {
+ HtmlMarkupElement markup;
+ HtmlElement *pForm; /* The <FORM> to which this belongs */
+ HtmlElement *pNext; /* Next element in a list of all input elements */
+ Tk_Window tkwin; /* The window that implements this control */
+ HtmlWidget *htmlPtr; /* The whole widget. Needed by geometry callbacks */
+ HtmlElement *pEnd; /* End tag for <TEXTAREA>, etc. */
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 padLeft; /* Extra padding on left side of the control */
+ Html_u8 align; /* One of the IMAGE_ALIGN_xxx types */
+ Html_u8 textAscent; /* Ascent for the current font */
+ Html_u8 textDescent; /* descent for the current font */
+ Html_u8 type; /* What type of input is this? */
+ Html_u8 sized; /* True if this input has been sized already */
+ Html_u16 cnt; /* Used to derive widget name. 0 if no widget */
+};
+typedef struct HtmlForm HtmlForm;
+struct HtmlForm {
+ HtmlMarkupElement markup;
+ Html_u16 id; /* Unique number assigned to this form */
+};
+typedef struct HtmlHr HtmlHr;
+struct HtmlHr {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 is3D; /* Is it drawn 3D? */
+};
+typedef struct HtmlAnchor HtmlAnchor;
+struct HtmlAnchor {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Top edge for this element */
+};
+typedef struct HtmlScript HtmlScript;
+struct HtmlScript {
+ HtmlMarkupElement markup;
+ char *zScript; /* Complete text of this script */
+ int nScript; /* Number of characters of text */
+};
+typedef struct HtmlBlock HtmlBlock;
+struct HtmlBlock {
+ HtmlBaseElement base; /* Superclass. Must be first */
+ char *z; /* Space to hold text when n>0 */
+ int top, bottom; /* Extremes of y coordinates */
+ Html_u16 left, right; /* Left and right boundry of this object */
+ Html_u16 n; /* Number of characters in z[] */
+ HtmlBlock *pPrev, *pNext; /* Linked list of all Blocks */
+};
+union HtmlElement {
+ HtmlElement *pNext;
+ HtmlBaseElement base;
+ HtmlTextElement text;
+ HtmlSpaceElement space;
+ HtmlMarkupElement markup;
+ HtmlCell cell;
+ HtmlTable table;
+ HtmlRef ref;
+ HtmlLi li;
+ HtmlListStart list;
+ HtmlImageMarkup image;
+ HtmlInput input;
+ HtmlForm form;
+ HtmlHr hr;
+ HtmlAnchor anchor;
+ HtmlScript script;
+ HtmlBlock block;
+};
+int HtmlGetIndex(HtmlWidget *htmlPtr,const char *zIndex,HtmlElement **ppToken,int *pIndex);
+typedef struct HtmlIndex HtmlIndex;
+struct HtmlIndex {
+ HtmlElement *p; /* The token containing the character */
+ int i; /* Index of the character */
+};
+#define Html_TypeCount 151
+typedef struct HtmlStyleStack HtmlStyleStack;
+typedef struct HtmlLayoutContext HtmlLayoutContext;
+typedef struct HtmlMargin HtmlMargin;
+struct HtmlLayoutContext {
+ HtmlWidget *htmlPtr; /* The html widget undergoing layout */
+ HtmlElement *pStart; /* Start of elements to layout */
+ HtmlElement *pEnd; /* Stop when reaching this element */
+ int headRoom; /* Extra space wanted above this line */
+ int top; /* Absolute top of drawing area */
+ int bottom; /* Bottom of previous line */
+ int left, right; /* Left and right extremes of drawing area */
+ int pageWidth; /* Width of the layout field, including
+ ** the margins */
+ int maxX, maxY; /* Maximum X and Y values of paint */
+ HtmlMargin *leftMargin; /* Stack of left margins */
+ HtmlMargin *rightMargin; /* Stack of right margins */
+};
+#define N_FONT_FAMILY 8
+#define N_FONT_SIZE 7
+#define N_FONT (N_FONT_FAMILY*N_FONT_SIZE)
+#define N_COLOR 16 /* Total number of colors */
+typedef struct GcCache GcCache;
+struct GcCache {
+ GC gc; /* The graphics context */
+ Html_u8 font; /* Font used for this context */
+ Html_u8 color; /* Color used for this context */
+ Html_u8 index; /* Index used for LRU replacement */
+};
+#define N_CACHE_GC 16
+struct HtmlWidget {
+ Tk_Window tkwin; /* The main window for this widget */
+ Tk_Window clipwin; /* The clipping window in which all text is
+ ** rendered. */
+ char *zClipwin; /* Name of the clipping window. */
+ Display *display; /* The X11 Server that contains tkwin */
+ Tcl_Interp *interp; /* The interpreter in which the widget lives */
+ char *zCmdName; /* Name of the command */
+ HtmlElement *pFirst; /* First HTML token on a list of them all */
+ HtmlElement *pLast; /* Last HTML token on the list */
+ int nToken; /* Number of HTML tokens on the list.
+ * Html_Block tokens don't count. */
+ HtmlElement *lastSized; /* Last HTML element that has been sized */
+ HtmlElement *nextPlaced; /* Next HTML element that needs to be
+ * positioned on canvas. */
+ HtmlBlock *firstBlock; /* List of all HtmlBlock tokens */
+ HtmlBlock *lastBlock; /* Last HtmlBlock in the list */
+ HtmlElement *firstInput; /* First <INPUT> element */
+ HtmlElement *lastInput; /* Last <INPUT> element */
+ int nInput; /* The number of <INPUT> elements */
+ int nForm; /* The number of <FORM> elements */
+ int varId; /* Used to construct a unique name for a
+ ** global array used by <INPUT> elements */
+
+ /*
+ * Information about the selected region of text
+ */
+ HtmlIndex selBegin; /* Start of the selection */
+ HtmlIndex selEnd; /* End of the selection */
+ HtmlBlock *pSelStartBlock; /* Block in which selection starts */
+ Html_16 selStartIndex; /* Index in pSelStartBlock of first selected
+ * character */
+ Html_16 selEndIndex; /* Index of last selecte char in pSelEndBlock */
+ HtmlBlock *pSelEndBlock; /* Block in which selection ends */
+
+ /*
+ * Information about the insertion cursor
+ */
+ int insOnTime; /* How long the cursor states one (millisec) */
+ int insOffTime; /* How long it is off (milliseconds) */
+ int insStatus; /* Is it visible? */
+ Tcl_TimerToken insTimer; /* Timer used to flash the insertion cursor */
+ HtmlIndex ins; /* The insertion cursor position */
+ HtmlBlock *pInsBlock; /* The HtmlBlock containing the cursor */
+ int insIndex; /* Index in pInsBlock of the cursor */
+
+ /*
+ * The following fields hold state information used by
+ * the tokenizer.
+ */
+ char *zText; /* Complete text of the unparsed HTML */
+ int nText; /* Number of characters in zText */
+ int nAlloc; /* Space allocated for zText */
+ int nComplete; /* How much of zText has actually been
+ * converted into tokens */
+ int iCol; /* The column in which zText[nComplete]
+ * occurs. Used to resolve tabs in input */
+ int iPlaintext; /* If not zero, this is the token type that
+ * caused us to go into plaintext mode. One
+ * of Html_PLAINTEXT, Html_LISTING or
+ * Html_XMP */
+ HtmlScript *pScript; /* <SCRIPT> currently being parsed */
+ char *zHandler[Html_TypeCount]; /* If not NULL, this is a TCL routine that
+ * is used to process tokens of the given
+ * type */
+ /*
+ * These fields hold state information used by the HtmlAddStyle routine.
+ * We have to store this state information here since HtmlAddStyle
+ * operates incrementally. This information must be carried from
+ * one incremental execution to the next.
+ */
+ HtmlStyleStack *styleStack; /* The style stack */
+ int paraAlignment; /* Justification associated with <p> */
+ int rowAlignment; /* Justification associated with <tr> */
+ int anchorFlags; /* Style flags associated with <A>...</A> */
+ int inDt; /* Style flags associated with <DT>...</DT> */
+ int inTr; /* True if within <tr>..</tr> */
+ int inTd; /* True if within <td>..</td> or <th>..</th> */
+ HtmlElement *anchorStart; /* Most recent <a href=...> */
+ HtmlElement *formStart; /* Most recent <form> */
+ HtmlElement *formElemStart; /* Most recent <textarea> or <select> */
+ HtmlElement *innerList; /* The inner most <OL> or <UL> */
+
+ /*
+ * These fields are used to hold the state of the layout engine.
+ * Because the layout is incremental, this state must be held for
+ * the life of the widget.
+ */
+ HtmlLayoutContext layoutContext;
+
+ /*
+ * Information used when displaying the widget:
+ */
+ Tk_3DBorder border; /* Background color */
+ int borderWidth; /* Width of the border. */
+ int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ int inset; /* Total width of highlight and 3-D border */
+ Tk_Font aFont[N_FONT]; /* Information about all screen fonts */
+ char fontValid[(N_FONT+7)/8]; /* If bit N%8 of work N/8 of this field is 0
+ * if aFont[N] needs to be reallocated before
+ * being used. */
+ XColor *apColor[N_COLOR]; /* Information about all colors */
+ int colorUsed; /* bit N is 1 if color N is in use. Only
+ ** applies to colors that aren't predefined */
+ int iDark[N_COLOR]; /* Dark 3D shadow of color K is iDark[K] */
+ int iLight[N_COLOR]; /* Light 3D shadow of color K is iLight[K] */
+ XColor *fgColor; /* Color of normal text. apColor[0] */
+ XColor *newLinkColor; /* Color of unvisitied links. apColor[1] */
+ XColor *oldLinkColor; /* Color of visitied links. apColor[2] */
+ XColor *selectionColor; /* Background color for selections */
+ GcCache aGcCache[N_CACHE_GC]; /* A cache of GCs for general use */
+ int lastGC; /* Index of recently used GC */
+ HtmlImage *imageList; /* A list of all images */
+ int width, height; /* User-requested size of the usable drawing
+ * area, in pixels. Borders and padding
+ * make the actual window a little larger */
+ int realWidth, realHeight; /* The actual physical size of tkwin as
+ * reported in the most recent ConfigureNotify
+ * event. */
+ int padx, pady; /* Separation between the edge of the window
+ * and rendered HTML. */
+ int underlineLinks; /* TRUE if we should underline hyperlinks */
+
+ /* Information about the selection
+ */
+ int exportSelection; /* True if the selection is automatically
+ * exported to the clipboard */
+
+ /* Callback commands. The HTML parser will invoke callbacks from time
+ ** to time to find out information it needs to complete formatting of
+ ** the document. The following fields define the callback commands.
+ */
+ char *zIsVisited; /* Command to tell if a hyperlink has already
+ ** been visited */
+ char *zGetImage; /* Command to get an image from a URL */
+ char *zFrameCommand; /* Command for handling <frameset> markup */
+ char *zAppletCommand; /* Command to process applets */
+ char *zResolverCommand; /* Command to resolve URIs */
+ char *zFormCommand; /* When user presses Submit */
+ char *zHyperlinkCommand; /* Invoked when a hyperlink is clicked */
+ char *zFontCommand; /* Invoked to find font names */
+ char *zScriptCommand; /* Invoked for each <SCRIPT> markup */
+
+ /*
+ * Miscellaneous information:
+ */
+ int tableRelief; /* 3d effects on <TABLE> */
+ int ruleRelief; /* 3d effects on <HR> */
+ char *zBase; /* The base URI */
+ char *zBaseHref; /* zBase as modified by <BASE HREF=..> markup */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ char *takeFocus; /* Value of -takefocus option; not used in
+ * the C code, but used by keyboard traversal
+ * scripts. Malloc'ed, but may be NULL. */
+ char *yScrollCmd; /* Command prefix for communicating with
+ * vertical scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ char *xScrollCmd; /* Command prefix for communicating with
+ * horizontal scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ int xOffset, yOffset; /* Current scroll position. These form the
+ * coordinate in the virtual canvas that
+ * corresponds to (0,0) on the physical screen
+ * in window tkwin */
+ int maxX, maxY; /* Maximum extent of any "paint" that appears
+ * on the virtual canvas. Used to compute
+ * scrollbar positions. */
+ int dirtyLeft, dirtyTop; /* Top left corner of region to redraw. These
+ * are physical screen coordinates relative to
+ * clipwin, not tkwin. */
+ int dirtyRight, dirtyBottom; /* Bottom right corner of region to redraw */
+ int locked; /* Number of locks on this structure. Don't
+ ** delete until it reaches zero. */
+ int flags; /* Various flags; see below for
+ * definitions. */
+};
+int HtmlTextAsciiCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+void HtmlTclizeAscii(Tcl_Interp *interp,HtmlIndex *s,HtmlIndex *e);
+void HtmlTclizeAscii(Tcl_Interp *interp,HtmlIndex *s,HtmlIndex *e);
+struct HtmlImage {
+ HtmlWidget *htmlPtr; /* The owner of this image */
+ Tk_Image image; /* The Tk image token */
+ Html_32 w; /* Requested width of this image (0 if none) */
+ Html_32 h; /* Requested height of this image (0 if none) */
+ char *zUrl; /* The URL for this image. */
+ char *zWidth, *zHeight; /* Width and height in the <img> markup. */
+ HtmlImage *pNext; /* Next image on the list */
+ HtmlElement *pList; /* List of all <IMG> markups that use this
+ ** same image */
+};
+struct HtmlStyleStack {
+ HtmlStyleStack *pNext; /* Next style on the stack */
+ int type; /* A markup that ends this style. Ex: Html_EndEM */
+ HtmlStyle style; /* The currently active style. */
+};
+struct HtmlMargin {
+ int indent; /* Size of the current margin */
+ int bottom; /* Y value at which this margin expires */
+ int tag; /* Markup that will cancel this margin */
+ HtmlMargin *pNext; /* Previous margin */
+};
diff --git a/tkhtml1/src/htmlform.c b/tkhtml1/src/htmlform.c
new file mode 100644
index 0000000..210ae62
--- /dev/null
+++ b/tkhtml1/src/htmlform.c
@@ -0,0 +1,606 @@
+/*
+** Routines used for processing HTML makeup for forms.
+**
+** Copyright (C) 1997-2000 D. Richard Hipp
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** drh@acm.org
+** http://www.hwaci.com/drh/
+*/
+#include <tk.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "htmlform.h"
+
+/*
+** Unmap any input control that is currently mapped.
+*/
+void HtmlUnmapControls(HtmlWidget *htmlPtr){
+ HtmlElement *p;
+
+ for(p=htmlPtr->firstInput; p; p=p->input.pNext){
+ if( p->input.tkwin!=0 && Tk_IsMapped(p->input.tkwin) ){
+ Tk_UnmapWindow(p->input.tkwin);
+ }
+ }
+}
+
+/*
+** Map any control that should be visible according to the
+** current scroll position. At the same time, if any controls that
+** should not be visible are mapped, unmap them. After this routine
+** finishes, all <INPUT> controls should be in their proper places
+** regardless of where they might have been before.
+**
+** Return the number of controls that are currently visible.
+*/
+int HtmlMapControls(HtmlWidget *htmlPtr){
+ HtmlElement *p; /* For looping over all controls */
+ int x, y, w, h; /* Part of the virtual canvas that is visible */
+ int cnt = 0; /* Number of visible controls */
+
+ x = htmlPtr->xOffset;
+ y = htmlPtr->yOffset;
+ w = Tk_Width(htmlPtr->clipwin);
+ h = Tk_Height(htmlPtr->clipwin);
+ for(p=htmlPtr->firstInput; p; p=p->input.pNext){
+ if( p->input.tkwin==0 ) continue;
+ if( p->input.y < y+h
+ && p->input.y + p->input.h > y
+ && p->input.x < x+w
+ && p->input.x + p->input.w > x
+ ){
+ /* The control should be visible. Make is so if it isn't already */
+ Tk_MoveResizeWindow(p->input.tkwin,
+ p->input.x - x, p->input.y - y,
+ p->input.w, p->input.h);
+ if( !Tk_IsMapped(p->input.tkwin) ){
+ Tk_MapWindow(p->input.tkwin);
+ }
+ cnt++;
+ }else{
+ /* This control should not be visible. Unmap it. */
+ if( Tk_IsMapped(p->input.tkwin) ){
+ Tk_UnmapWindow(p->input.tkwin);
+ }
+ }
+ }
+ return cnt;
+}
+
+/*
+** Delete all input controls. This happens when the HTML widget
+** is cleared.
+**
+** When the TCL "exit" command is invoked, the order of operations
+** here is very touchy.
+*/
+void HtmlDeleteControls(HtmlWidget *htmlPtr){
+ HtmlElement *p; /* For looping over all controls */
+ Tcl_Interp *interp; /* The interpreter */
+
+ interp = htmlPtr->interp;
+ p = htmlPtr->firstInput;
+ htmlPtr->firstInput = 0;
+ htmlPtr->lastInput = 0;
+ htmlPtr->nInput = 0;
+ if( p==0 || htmlPtr->tkwin==0 ) return;
+ HtmlLock(htmlPtr);
+ for(; p; p=p->input.pNext){
+ if( p->input.pForm && p->input.pForm->form.id>0
+ && htmlPtr->zFormCommand && htmlPtr->zFormCommand[0]
+ && !Tcl_InterpDeleted(interp) && htmlPtr->clipwin ){
+ Tcl_DString cmd;
+ int result;
+ char zBuf[60];
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, htmlPtr->zFormCommand, -1);
+ sprintf(zBuf," %d flush", p->input.pForm->form.id);
+ Tcl_DStringAppend(&cmd, zBuf, -1);
+ result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if( !Tcl_InterpDeleted(interp) ){
+ if( result != TCL_OK ){
+ Tcl_AddErrorInfo(htmlPtr->interp,
+ "\n (-formcommand flush callback executed by html widget)");
+ Tcl_BackgroundError(htmlPtr->interp);
+ TestPoint(0);
+ }
+ Tcl_ResetResult(htmlPtr->interp);
+ }
+ p->input.pForm->form.id = 0;
+ }
+ if( p->input.tkwin ){
+ if( htmlPtr->clipwin!=0 ) Tk_DestroyWindow(p->input.tkwin);
+ p->input.tkwin = 0;
+ }
+ p->input.sized = 0;
+ }
+ HtmlUnlock(htmlPtr);
+}
+
+/*
+** Return an appropriate type value for the given <INPUT> markup.
+*/
+static int InputType(HtmlElement *p){
+ int type = INPUT_TYPE_Unknown;
+ char *z;
+ int i;
+ static struct {
+ char *zName;
+ int type;
+ } types[] = {
+ { "checkbox", INPUT_TYPE_Checkbox },
+ { "file", INPUT_TYPE_File },
+ { "hidden", INPUT_TYPE_Hidden },
+ { "image", INPUT_TYPE_Image },
+ { "password", INPUT_TYPE_Password },
+ { "radio", INPUT_TYPE_Radio },
+ { "reset", INPUT_TYPE_Reset },
+ { "submit", INPUT_TYPE_Submit },
+ { "text", INPUT_TYPE_Text },
+ };
+
+ switch( p->base.type ){
+ case Html_INPUT:
+ z = HtmlMarkupArg(p, "type", "text");
+ if( z==0 ){ TestPoint(0); break; }
+ for(i=0; i<sizeof(types)/sizeof(types[0]); i++){
+ if( stricmp(types[i].zName,z)==0 ){
+ type = types[i].type;
+ TestPoint(0);
+ break;
+ }
+ TestPoint(0);
+ }
+ break;
+ case Html_SELECT:
+ type = INPUT_TYPE_Select;
+ TestPoint(0);
+ break;
+ case Html_TEXTAREA:
+ type = INPUT_TYPE_TextArea;
+ TestPoint(0);
+ break;
+ case Html_APPLET:
+ case Html_IFRAME:
+ case Html_EMBED:
+ type = INPUT_TYPE_Applet;
+ TestPoint(0);
+ break;
+ default:
+ CANT_HAPPEN;
+ break;
+ }
+ return type;
+}
+
+/*
+** Create the window name for a child widget. Space to hold the name
+** is obtained from HtmlAlloc() and must be freed by the calling function.
+*/
+static char *MakeWindowName(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ HtmlElement *pElem /* The input that needs a child widget */
+){
+ int n;
+ char *zBuf;
+
+ n = strlen(Tk_PathName(htmlPtr->clipwin));
+ zBuf = HtmlAlloc( n + 20 );
+ sprintf(zBuf,"%s.x%d",Tk_PathName(htmlPtr->clipwin), pElem->input.cnt);
+ return zBuf;
+}
+
+/*
+** A Input element is the input. Mark this element as being
+** empty. It has no widget and doesn't appear on the screen.
+**
+** This is called for HIDDEN inputs or when the -formcommand
+** callback doesn't create the widget.
+*/
+static void EmptyInput(HtmlElement *pElem){
+ pElem->input.tkwin = 0;
+ pElem->input.w = 0;
+ pElem->input.h = 0;
+ pElem->base.flags &= !HTML_Visible;
+ pElem->base.style.flags |= STY_Invisible;
+ pElem->input.sized = 1;
+}
+
+/*
+** This routine is called when one of the child windows for a form
+** wants to change its size.
+*/
+static void HtmlInputRequestProc(ClientData clientData, Tk_Window tkwin){
+ HtmlElement *pElem = (HtmlElement*)clientData;
+ if( pElem->base.type!=Html_INPUT ){ CANT_HAPPEN; return; }
+ if( pElem->input.tkwin!=tkwin ){ CANT_HAPPEN; return; }
+ pElem->input.w = Tk_ReqWidth(tkwin);
+ pElem->input.h = Tk_ReqHeight(tkwin);
+ if( pElem->input.htmlPtr && pElem->input.htmlPtr->tkwin!=0 ){
+ pElem->input.htmlPtr->flags |= RELAYOUT;
+ HtmlScheduleRedraw(pElem->input.htmlPtr);
+ }
+}
+
+/*
+** This routine is called when another entity takes over geometry
+** management for a widget corresponding to an input element.
+*/
+static void HtmlInputLostSlaveProc(ClientData clientData, Tk_Window tkwin){
+ HtmlElement *pElem = (HtmlElement*)clientData;
+ if( pElem->base.type!=Html_INPUT ){ CANT_HAPPEN; return; }
+ if( pElem->input.tkwin!=tkwin ){ CANT_HAPPEN; return; }
+ EmptyInput(pElem);
+ if( pElem->input.htmlPtr && pElem->input.htmlPtr->tkwin!=0 ){
+ pElem->input.htmlPtr->flags |= RELAYOUT;
+ HtmlScheduleRedraw(pElem->input.htmlPtr);
+ }
+}
+
+/*
+** This routine catches DestroyNotify events on a INPUT window so
+** that we will know the window is been deleted.
+*/
+static void HtmlInputEventProc(ClientData clientData, XEvent *eventPtr){
+ HtmlElement *pElem = (HtmlElement*)clientData;
+ /* if( pElem->base.type!=Html_INPUT ){ CANT_HAPPEN; return; } */
+ if( eventPtr->type==DestroyNotify ){
+ EmptyInput(pElem);
+ if( pElem->input.htmlPtr && pElem->input.htmlPtr->tkwin!=0 ){
+ pElem->input.htmlPtr->flags |= RELAYOUT;
+ HtmlScheduleRedraw(pElem->input.htmlPtr);
+ }
+ }
+}
+
+/*
+** The geometry manager for the HTML widget
+*/
+static Tk_GeomMgr htmlGeomType = {
+ "html", /* Name */
+ HtmlInputRequestProc, /* Called when widget changes size */
+ HtmlInputLostSlaveProc, /* Called when someone else takes over management */
+};
+
+/*
+** zWin is the name of a child widget that is used to implement an
+** input element. Query Tk for information about this widget (such
+** as its size) and put that information in the pElem structure
+** that represents the input.
+*/
+static void SizeAndLink(HtmlWidget *htmlPtr, char *zWin, HtmlElement *pElem){
+ pElem->input.tkwin = Tk_NameToWindow(htmlPtr->interp, zWin, htmlPtr->clipwin);
+ if( pElem->input.tkwin==0 ){
+ Tcl_ResetResult(htmlPtr->interp);
+ EmptyInput(pElem);
+ }else if( pElem->input.type==INPUT_TYPE_Hidden ){
+ pElem->input.w = 0;
+ pElem->input.h = 0;
+ pElem->base.flags &= !HTML_Visible;
+ pElem->base.style.flags |= STY_Invisible;
+ }else{
+ pElem->input.w = Tk_ReqWidth(pElem->input.tkwin);
+ pElem->input.h = Tk_ReqHeight(pElem->input.tkwin);
+ pElem->base.flags |= HTML_Visible;
+ pElem->input.htmlPtr = htmlPtr;
+ Tk_ManageGeometry(pElem->input.tkwin, &htmlGeomType, pElem);
+ Tk_CreateEventHandler(pElem->input.tkwin, StructureNotifyMask,
+ HtmlInputEventProc, pElem);
+ }
+ pElem->input.pNext = 0;
+ if( htmlPtr->firstInput==0 ){
+ htmlPtr->firstInput = pElem;
+ }else{
+ htmlPtr->lastInput->input.pNext = pElem;
+ }
+ htmlPtr->lastInput = pElem;
+ pElem->input.sized = 1;
+}
+
+/* Append all text and space tokens between pStart and pEnd to
+** the given Tcl_DString.
+*/
+static void HtmlAppendText(
+ Tcl_DString *str, /* Append the text here */
+ HtmlElement *pFirst, /* The first token */
+ HtmlElement *pEnd /* The last token */
+){
+ while( pFirst && pFirst!=pEnd ){
+ switch( pFirst->base.type ){
+ case Html_Text: {
+ Tcl_DStringAppend(str, pFirst->text.zText, -1);
+ break;
+ }
+ case Html_Space: {
+ if( pFirst->base.flags & HTML_NewLine ){
+ Tcl_DStringAppend(str, "\n", 1);
+ }else{
+ int cnt;
+ static char zSpaces[] = " ";
+ cnt = pFirst->base.count;
+ while( cnt>sizeof(zSpaces)-1 ){
+ Tcl_DStringAppend(str, zSpaces, sizeof(zSpaces)-1);
+ cnt -= sizeof(zSpaces)-1;
+ }
+ if( cnt>0 ){
+ Tcl_DStringAppend(str, zSpaces, cnt);
+ }
+ }
+ break;
+ }
+ default:
+ /* Do nothing */
+ break;
+ }
+ pFirst = pFirst->pNext;
+ }
+}
+
+/*
+** The "p" argument points to a <select>. This routine scans all
+** subsequent elements (up to the next </select>) looking for
+** <option> tags. For each option tag, it appends three elements
+** to the "str" DString:
+**
+** * 1 or 0 to indicated whether or not the element is
+** selected.
+**
+** * The value returned if this element is selected.
+**
+** * The text displayed for this element.
+*/
+static void AddSelectOptions(
+ Tcl_DString *str, /* Add text here */
+ HtmlElement *p, /* The <SELECT> markup */
+ HtmlElement *pEnd /* The </SELECT> markup */
+){
+ while( p && p!=pEnd && p->base.type!=Html_EndSELECT ){
+ if( p->base.type==Html_OPTION ){
+ char *zValue;
+ Tcl_DStringStartSublist(str);
+ if( HtmlMarkupArg(p, "selected", 0)==0 ){
+ Tcl_DStringAppend(str, "0 ", 2);
+ }else{
+ Tcl_DStringAppend(str, "1 ", 2);
+ }
+ zValue = HtmlMarkupArg(p, "value", "");
+ Tcl_DStringAppendElement(str, zValue);
+ Tcl_DStringStartSublist(str);
+ p = p->pNext;
+ while( p && p!=pEnd && p->base.type!=Html_EndOPTION
+ && p->base.type!=Html_OPTION && p->base.type!=Html_EndSELECT ){
+ if( p->base.type==Html_Text ){
+ Tcl_DStringAppend(str, p->text.zText, -1);
+ }else if( p->base.type==Html_Space ){
+ Tcl_DStringAppend(str, " ", 1);
+ }
+ p = p->pNext;
+ }
+ Tcl_DStringEndSublist(str);
+ Tcl_DStringEndSublist(str);
+ }else{
+ p = p->pNext;
+ }
+ }
+}
+
+/*
+** This routine implements the Sizer() function for <INPUT>,
+** <SELECT> and <TEXTAREA> markup.
+**
+** A side effect of sizing these markups is that widgets are
+** created to represent the corresponding input controls.
+**
+** The function normally returns 0. But if it is dealing with
+** a <SELECT> or <TEXTAREA> that is incomplete, 1 is returned.
+** In that case, the sizer will be called again at some point in
+** the future when more information is available.
+*/
+int HtmlControlSize(HtmlWidget *htmlPtr, HtmlElement *pElem){
+ char *zWin; /* Name of child widget that implements this input */
+ int incomplete = 0; /* True if data is incomplete */
+ Tcl_DString cmd; /* The complete -formcommand callback */
+
+ if( pElem->input.sized ) return 0;
+ pElem->input.type = InputType(pElem);
+ switch( pElem->input.type ){
+ case INPUT_TYPE_Checkbox:
+ case INPUT_TYPE_Hidden:
+ case INPUT_TYPE_Image:
+ case INPUT_TYPE_Radio:
+ case INPUT_TYPE_Reset:
+ case INPUT_TYPE_Submit:
+ case INPUT_TYPE_Text:
+ case INPUT_TYPE_Password:
+ case INPUT_TYPE_File: {
+ int result;
+ char zToken[50];
+
+ if( pElem->input.pForm==0 || htmlPtr->zFormCommand==0
+ || htmlPtr->zFormCommand[0]==0 ){
+ EmptyInput(pElem);
+ break;
+ }
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, htmlPtr->zFormCommand, -1);
+ sprintf(zToken," %d input ",pElem->input.pForm->form.id);
+ Tcl_DStringAppend(&cmd, zToken, -1);
+ pElem->input.cnt = ++htmlPtr->nInput;
+ zWin = MakeWindowName(htmlPtr, pElem);
+ Tcl_DStringAppend(&cmd, zWin, -1);
+ Tcl_DStringStartSublist(&cmd);
+ HtmlAppendArglist(&cmd, pElem);
+ Tcl_DStringEndSublist(&cmd);
+ HtmlLock(htmlPtr);
+ result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if( !HtmlUnlock(htmlPtr) ){
+ SizeAndLink(htmlPtr, zWin, pElem);
+ }
+ HtmlFree(zWin);
+ break;
+ }
+ case INPUT_TYPE_Select: {
+ int result;
+ char zToken[50];
+
+ if( pElem->input.pForm==0 || htmlPtr->zFormCommand==0
+ || htmlPtr->zFormCommand[0]==0 ){
+ EmptyInput(pElem);
+ break;
+ }
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, htmlPtr->zFormCommand, -1);
+ sprintf(zToken," %d select ",pElem->input.pForm->form.id);
+ Tcl_DStringAppend(&cmd, zToken, -1);
+ pElem->input.cnt = ++htmlPtr->nInput;
+ zWin = MakeWindowName(htmlPtr, pElem);
+ Tcl_DStringAppend(&cmd, zWin, -1);
+ Tcl_DStringStartSublist(&cmd);
+ HtmlAppendArglist(&cmd, pElem);
+ Tcl_DStringEndSublist(&cmd);
+ Tcl_DStringStartSublist(&cmd);
+ AddSelectOptions(&cmd, pElem, pElem->input.pEnd);
+ Tcl_DStringEndSublist(&cmd);
+ HtmlLock(htmlPtr);
+ result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if( !HtmlUnlock(htmlPtr) ){
+ SizeAndLink(htmlPtr, zWin, pElem);
+ }
+ HtmlFree(zWin);
+ break;
+ }
+ case INPUT_TYPE_TextArea: {
+ int result;
+ char zToken[50];
+
+ if( pElem->input.pForm==0 || htmlPtr->zFormCommand==0
+ || htmlPtr->zFormCommand[0]==0 ){
+ EmptyInput(pElem);
+ break;
+ }
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, htmlPtr->zFormCommand, -1);
+ sprintf(zToken," %d textarea ",pElem->input.pForm->form.id);
+ Tcl_DStringAppend(&cmd, zToken, -1);
+ pElem->input.cnt = ++htmlPtr->nInput;
+ zWin = MakeWindowName(htmlPtr, pElem);
+ Tcl_DStringAppend(&cmd, zWin, -1);
+ Tcl_DStringStartSublist(&cmd);
+ HtmlAppendArglist(&cmd, pElem);
+ Tcl_DStringEndSublist(&cmd);
+ Tcl_DStringStartSublist(&cmd);
+ HtmlAppendText(&cmd, pElem, pElem->input.pEnd);
+ Tcl_DStringEndSublist(&cmd);
+ HtmlLock(htmlPtr);
+ result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if( !HtmlUnlock(htmlPtr) ){
+ SizeAndLink(htmlPtr, zWin, pElem);
+ }
+ HtmlFree(zWin);
+ break;
+ }
+ case INPUT_TYPE_Applet: {
+ int result;
+
+ if( htmlPtr->zAppletCommand==0 || htmlPtr->zAppletCommand[0]==0 ){
+ EmptyInput(pElem);
+ break;
+ }
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, htmlPtr->zAppletCommand, -1);
+ Tcl_DStringAppend(&cmd, " ", 1);
+ pElem->input.cnt = ++htmlPtr->nInput;
+ zWin = MakeWindowName(htmlPtr, pElem);
+ Tcl_DStringAppend(&cmd, zWin, -1);
+ Tcl_DStringStartSublist(&cmd);
+ HtmlAppendArglist(&cmd, pElem);
+ Tcl_DStringEndSublist(&cmd);
+ HtmlLock(htmlPtr);
+ result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if( !HtmlUnlock(htmlPtr) ){
+ SizeAndLink(htmlPtr, zWin, pElem);
+ }
+ HtmlFree(zWin);
+ break;
+ }
+ default: {
+ CANT_HAPPEN;
+ pElem->base.flags &= ~HTML_Visible;
+ pElem->base.style.flags |= STY_Invisible;
+ pElem->input.tkwin = 0;
+ break;
+ }
+ }
+ return incomplete;
+}
+
+#if 0
+/*
+** The following array determines which characters can be put directly
+** in a query string and which must be escaped.
+*/
+static char needEscape[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1,
+};
+#define NeedToEscape(C) ((C)>0 && (C)<127 && needEscape[(int)(C)])
+
+/*
+** Append to the given DString, an encoded version of the given
+** text.
+*/
+static void EncodeText(Tcl_DString *str, char *z){
+ int i;
+ while( *z ){
+ for(i=0; z[i] && !NeedToEscape(z[i]); i++){ TestPoint(0); }
+ if( i>0 ){ TestPoint(0); Tcl_DStringAppend(str, z, i); }
+ z += i;
+ while( *z && NeedToEscape(*z) ){
+ if( *z==' ' ){
+ Tcl_DStringAppend(str,"+",1);
+ TestPoint(0);
+ }else if( *z=='\n' ){
+ Tcl_DStringAppend(str, "%0D%0A", 6);
+ TestPoint(0);
+ }else if( *z=='\r' ){
+ /* Ignore it... */
+ TestPoint(0);
+ }else{
+ char zBuf[5];
+ sprintf(zBuf,"%%%02X",0xff & *z);
+ Tcl_DStringAppend(str, zBuf, 3);
+ TestPoint(0);
+ }
+ z++;
+ }
+ }
+}
+#endif
diff --git a/tkhtml1/src/htmlform.h b/tkhtml1/src/htmlform.h
new file mode 100644
index 0000000..82fbd7e
--- /dev/null
+++ b/tkhtml1/src/htmlform.h
@@ -0,0 +1,484 @@
+/* This file was automatically generated. Do not edit! */
+#define HtmlFree(A) Tcl_Free((char*)(A))
+typedef union HtmlElement HtmlElement;
+void HtmlAppendArglist(Tcl_DString *str,HtmlElement *pElem);
+typedef struct HtmlWidget HtmlWidget;
+int HtmlControlSize(HtmlWidget *htmlPtr,HtmlElement *pElem);
+#define Html_EndOPTION 103
+#define Html_OPTION 102
+#define Html_EndSELECT 117
+#define HTML_NewLine 0x02 /* type==Html_Space and ends with newline */
+#define Html_Space 2
+#define Html_Text 1
+void HtmlScheduleRedraw(HtmlWidget *htmlPtr);
+#define RELAYOUT 0x000010
+#define STY_Invisible 0x040
+#define HTML_Visible 0x01 /* This element produces "ink" */
+/*#define HtmlAlloc(A) ((void*)Tcl_Alloc(A))*/
+void* HtmlAlloc(size_t);
+void HtmlTPCantHappen(const char *zFile,int line);
+#if defined(COVERAGE_TEST)
+# define CANT_HAPPEN HtmlTPCantHappen(__FILE__,__LINE__)
+#endif
+#if !(defined(COVERAGE_TEST))
+# define CANT_HAPPEN
+#endif
+#define INPUT_TYPE_Applet 12
+#define Html_EMBED 49
+#define Html_IFRAME 75
+#define Html_APPLET 9
+#define INPUT_TYPE_TextArea 11
+#define Html_TEXTAREA 133
+#define INPUT_TYPE_Select 8
+#define Html_SELECT 116
+#if !defined(HAVE_STRICMP)
+# define stricmp strcasecmp
+#endif
+char *HtmlMarkupArg(HtmlElement *p,const char *tag,char *zDefault);
+#define Html_INPUT 77
+#define INPUT_TYPE_Text 10
+#define INPUT_TYPE_Submit 9
+#define INPUT_TYPE_Reset 7
+#define INPUT_TYPE_Radio 6
+#define INPUT_TYPE_Password 5
+#define INPUT_TYPE_Image 4
+#define INPUT_TYPE_Hidden 3
+#define INPUT_TYPE_File 2
+#define INPUT_TYPE_Checkbox 1
+#define INPUT_TYPE_Unknown 0
+int HtmlUnlock(HtmlWidget *htmlPtr);
+#if defined(COVERAGE_TEST)
+extern int HtmlTPArray[2000];
+# define TestPoint(X) {extern int HtmlTPArray[]; HtmlTPArray[X]++;}
+#endif
+#if !(defined(COVERAGE_TEST))
+# define TestPoint(X)
+#endif
+void HtmlLock(HtmlWidget *htmlPtr);
+void HtmlDeleteControls(HtmlWidget *htmlPtr);
+int HtmlMapControls(HtmlWidget *htmlPtr);
+typedef struct HtmlBaseElement HtmlBaseElement;
+typedef struct HtmlStyle HtmlStyle;
+struct HtmlStyle {
+ unsigned int font : 6; /* Font to use for display */
+ unsigned int color : 4; /* Foreground color */
+ signed int subscript : 4; /* Positive for <sup>, negative for <sub> */
+ unsigned int align : 2; /* Horizontal alignment */
+ unsigned int bgcolor : 4; /* Background color */
+ unsigned int flags : 12; /* the STY_ flags below */
+};
+typedef unsigned char Html_u8;
+typedef short Html_16;
+struct HtmlBaseElement {
+ HtmlElement *pNext; /* Next input token in a list of them all */
+ HtmlElement *pPrev; /* Previous token in a list of them all */
+ HtmlStyle style; /* The rendering style for this token */
+ Html_u8 type; /* The token type. */
+ Html_u8 flags; /* The HTML_ flags below */
+ Html_16 count; /* Various uses, depending on "type" */
+};
+typedef struct HtmlTextElement HtmlTextElement;
+typedef int Html_32;
+struct HtmlTextElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_32 y; /* y coordinate where text should be rendered */
+ Html_16 x; /* x coordinate where text should be rendered */
+ Html_16 w; /* width of this token in pixels */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_u8 spaceWidth; /* Width of one space in the current font */
+ char zText[1]; /* Text for this element. Null terminated */
+};
+typedef struct HtmlSpaceElement HtmlSpaceElement;
+struct HtmlSpaceElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_16 w; /* Width of a single space in current font */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+};
+typedef struct HtmlMarkupElement HtmlMarkupElement;
+struct HtmlMarkupElement {
+ HtmlBaseElement base;
+ char **argv;
+};
+typedef struct HtmlCell HtmlCell;
+struct HtmlCell {
+ HtmlMarkupElement markup;
+ Html_16 rowspan; /* Number of rows spanned by this cell */
+ Html_16 colspan; /* Number of columns spanned by this cell */
+ Html_16 x; /* X coordinate of left edge of border */
+ Html_16 w; /* Width of the border */
+ Html_32 y; /* Y coordinate of top of border indentation */
+ Html_32 h; /* Height of the border */
+ HtmlElement *pTable; /* Pointer back to the <table> */
+ HtmlElement *pEnd; /* Element that ends this cell */
+};
+typedef struct HtmlTable HtmlTable;
+typedef unsigned short Html_u16;
+#define HTML_MAX_COLUMNS 40
+struct HtmlTable {
+ HtmlMarkupElement markup;
+ Html_u8 borderWidth; /* Width of the border */
+ Html_u8 nCol; /* Number of columns */
+ Html_u16 nRow; /* Number of rows */
+ Html_32 y; /* top edge of table border */
+ Html_32 h; /* height of the table border */
+ Html_16 x; /* left edge of table border */
+ Html_16 w; /* width of the table border */
+ int minW[HTML_MAX_COLUMNS+1]; /* minimum width of each column */
+ int maxW[HTML_MAX_COLUMNS+1]; /* maximum width of each column */
+};
+typedef struct HtmlRef HtmlRef;
+struct HtmlRef {
+ HtmlMarkupElement markup;
+ HtmlElement *pOther; /* Pointer to some other Html element */
+};
+typedef struct HtmlLi HtmlLi;
+struct HtmlLi {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* What type of list is this? */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_16 cnt; /* Value for this element (if inside <OL>) */
+ Html_16 x; /* X coordinate of the bullet */
+ Html_32 y; /* Y coordinate of the bullet */
+};
+typedef struct HtmlListStart HtmlListStart;
+struct HtmlListStart {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* One of the LI_TYPE_ defines above */
+ Html_u8 compact; /* True if the COMPACT flag is present */
+ Html_u16 cnt; /* Next value for <OL> */
+ Html_u16 width; /* How much space to allow for indentation */
+ HtmlElement *pPrev; /* Next higher level list, or NULL */
+};
+typedef struct HtmlImageMarkup HtmlImageMarkup;
+typedef struct HtmlImage HtmlImage;
+struct HtmlImageMarkup {
+ HtmlMarkupElement markup;
+ Html_u8 align; /* Alignment. See IMAGE_ALIGN_ defines below */
+ Html_u8 textAscent; /* Ascent of text font in force at the <IMG> */
+ Html_u8 textDescent; /* Descent of text font in force at the <IMG> */
+ Html_u8 redrawNeeded; /* Need to redraw this image because the image
+ ** content changed. */
+ Html_16 h; /* Actual height of the image */
+ Html_16 w; /* Actual width of the image */
+ Html_16 ascent; /* How far image extends above "y" */
+ Html_16 descent; /* How far image extends below "y" */
+ Html_16 x; /* X coordinate of left edge of the image */
+ Html_32 y; /* Y coordinate of image baseline */
+ char *zAlt; /* Alternative text */
+ HtmlImage *pImage; /* Corresponding HtmlImage structure */
+ HtmlElement *pNext; /* Next markup using the same HtmlImage structure */
+};
+typedef struct HtmlInput HtmlInput;
+struct HtmlInput {
+ HtmlMarkupElement markup;
+ HtmlElement *pForm; /* The <FORM> to which this belongs */
+ HtmlElement *pNext; /* Next element in a list of all input elements */
+ Tk_Window tkwin; /* The window that implements this control */
+ HtmlWidget *htmlPtr; /* The whole widget. Needed by geometry callbacks */
+ HtmlElement *pEnd; /* End tag for <TEXTAREA>, etc. */
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 padLeft; /* Extra padding on left side of the control */
+ Html_u8 align; /* One of the IMAGE_ALIGN_xxx types */
+ Html_u8 textAscent; /* Ascent for the current font */
+ Html_u8 textDescent; /* descent for the current font */
+ Html_u8 type; /* What type of input is this? */
+ Html_u8 sized; /* True if this input has been sized already */
+ Html_u16 cnt; /* Used to derive widget name. 0 if no widget */
+};
+typedef struct HtmlForm HtmlForm;
+struct HtmlForm {
+ HtmlMarkupElement markup;
+ Html_u16 id; /* Unique number assigned to this form */
+};
+typedef struct HtmlHr HtmlHr;
+struct HtmlHr {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 is3D; /* Is it drawn 3D? */
+};
+typedef struct HtmlAnchor HtmlAnchor;
+struct HtmlAnchor {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Top edge for this element */
+};
+typedef struct HtmlScript HtmlScript;
+struct HtmlScript {
+ HtmlMarkupElement markup;
+ char *zScript; /* Complete text of this script */
+ int nScript; /* Number of characters of text */
+};
+typedef struct HtmlBlock HtmlBlock;
+struct HtmlBlock {
+ HtmlBaseElement base; /* Superclass. Must be first */
+ char *z; /* Space to hold text when n>0 */
+ int top, bottom; /* Extremes of y coordinates */
+ Html_u16 left, right; /* Left and right boundry of this object */
+ Html_u16 n; /* Number of characters in z[] */
+ HtmlBlock *pPrev, *pNext; /* Linked list of all Blocks */
+};
+union HtmlElement {
+ HtmlElement *pNext;
+ HtmlBaseElement base;
+ HtmlTextElement text;
+ HtmlSpaceElement space;
+ HtmlMarkupElement markup;
+ HtmlCell cell;
+ HtmlTable table;
+ HtmlRef ref;
+ HtmlLi li;
+ HtmlListStart list;
+ HtmlImageMarkup image;
+ HtmlInput input;
+ HtmlForm form;
+ HtmlHr hr;
+ HtmlAnchor anchor;
+ HtmlScript script;
+ HtmlBlock block;
+};
+typedef struct HtmlIndex HtmlIndex;
+struct HtmlIndex {
+ HtmlElement *p; /* The token containing the character */
+ int i; /* Index of the character */
+};
+#define Html_TypeCount 151
+typedef struct HtmlStyleStack HtmlStyleStack;
+typedef struct HtmlLayoutContext HtmlLayoutContext;
+typedef struct HtmlMargin HtmlMargin;
+struct HtmlLayoutContext {
+ HtmlWidget *htmlPtr; /* The html widget undergoing layout */
+ HtmlElement *pStart; /* Start of elements to layout */
+ HtmlElement *pEnd; /* Stop when reaching this element */
+ int headRoom; /* Extra space wanted above this line */
+ int top; /* Absolute top of drawing area */
+ int bottom; /* Bottom of previous line */
+ int left, right; /* Left and right extremes of drawing area */
+ int pageWidth; /* Width of the layout field, including
+ ** the margins */
+ int maxX, maxY; /* Maximum X and Y values of paint */
+ HtmlMargin *leftMargin; /* Stack of left margins */
+ HtmlMargin *rightMargin; /* Stack of right margins */
+};
+#define N_FONT_FAMILY 8
+#define N_FONT_SIZE 7
+#define N_FONT (N_FONT_FAMILY*N_FONT_SIZE)
+#define N_COLOR 16 /* Total number of colors */
+typedef struct GcCache GcCache;
+struct GcCache {
+ GC gc; /* The graphics context */
+ Html_u8 font; /* Font used for this context */
+ Html_u8 color; /* Color used for this context */
+ Html_u8 index; /* Index used for LRU replacement */
+};
+#define N_CACHE_GC 16
+struct HtmlWidget {
+ Tk_Window tkwin; /* The main window for this widget */
+ Tk_Window clipwin; /* The clipping window in which all text is
+ ** rendered. */
+ char *zClipwin; /* Name of the clipping window. */
+ Display *display; /* The X11 Server that contains tkwin */
+ Tcl_Interp *interp; /* The interpreter in which the widget lives */
+ char *zCmdName; /* Name of the command */
+ HtmlElement *pFirst; /* First HTML token on a list of them all */
+ HtmlElement *pLast; /* Last HTML token on the list */
+ int nToken; /* Number of HTML tokens on the list.
+ * Html_Block tokens don't count. */
+ HtmlElement *lastSized; /* Last HTML element that has been sized */
+ HtmlElement *nextPlaced; /* Next HTML element that needs to be
+ * positioned on canvas. */
+ HtmlBlock *firstBlock; /* List of all HtmlBlock tokens */
+ HtmlBlock *lastBlock; /* Last HtmlBlock in the list */
+ HtmlElement *firstInput; /* First <INPUT> element */
+ HtmlElement *lastInput; /* Last <INPUT> element */
+ int nInput; /* The number of <INPUT> elements */
+ int nForm; /* The number of <FORM> elements */
+ int varId; /* Used to construct a unique name for a
+ ** global array used by <INPUT> elements */
+
+ /*
+ * Information about the selected region of text
+ */
+ HtmlIndex selBegin; /* Start of the selection */
+ HtmlIndex selEnd; /* End of the selection */
+ HtmlBlock *pSelStartBlock; /* Block in which selection starts */
+ Html_16 selStartIndex; /* Index in pSelStartBlock of first selected
+ * character */
+ Html_16 selEndIndex; /* Index of last selecte char in pSelEndBlock */
+ HtmlBlock *pSelEndBlock; /* Block in which selection ends */
+
+ /*
+ * Information about the insertion cursor
+ */
+ int insOnTime; /* How long the cursor states one (millisec) */
+ int insOffTime; /* How long it is off (milliseconds) */
+ int insStatus; /* Is it visible? */
+ Tcl_TimerToken insTimer; /* Timer used to flash the insertion cursor */
+ HtmlIndex ins; /* The insertion cursor position */
+ HtmlBlock *pInsBlock; /* The HtmlBlock containing the cursor */
+ int insIndex; /* Index in pInsBlock of the cursor */
+
+ /*
+ * The following fields hold state information used by
+ * the tokenizer.
+ */
+ char *zText; /* Complete text of the unparsed HTML */
+ int nText; /* Number of characters in zText */
+ int nAlloc; /* Space allocated for zText */
+ int nComplete; /* How much of zText has actually been
+ * converted into tokens */
+ int iCol; /* The column in which zText[nComplete]
+ * occurs. Used to resolve tabs in input */
+ int iPlaintext; /* If not zero, this is the token type that
+ * caused us to go into plaintext mode. One
+ * of Html_PLAINTEXT, Html_LISTING or
+ * Html_XMP */
+ HtmlScript *pScript; /* <SCRIPT> currently being parsed */
+ char *zHandler[Html_TypeCount]; /* If not NULL, this is a TCL routine that
+ * is used to process tokens of the given
+ * type */
+ /*
+ * These fields hold state information used by the HtmlAddStyle routine.
+ * We have to store this state information here since HtmlAddStyle
+ * operates incrementally. This information must be carried from
+ * one incremental execution to the next.
+ */
+ HtmlStyleStack *styleStack; /* The style stack */
+ int paraAlignment; /* Justification associated with <p> */
+ int rowAlignment; /* Justification associated with <tr> */
+ int anchorFlags; /* Style flags associated with <A>...</A> */
+ int inDt; /* Style flags associated with <DT>...</DT> */
+ int inTr; /* True if within <tr>..</tr> */
+ int inTd; /* True if within <td>..</td> or <th>..</th> */
+ HtmlElement *anchorStart; /* Most recent <a href=...> */
+ HtmlElement *formStart; /* Most recent <form> */
+ HtmlElement *formElemStart; /* Most recent <textarea> or <select> */
+ HtmlElement *innerList; /* The inner most <OL> or <UL> */
+
+ /*
+ * These fields are used to hold the state of the layout engine.
+ * Because the layout is incremental, this state must be held for
+ * the life of the widget.
+ */
+ HtmlLayoutContext layoutContext;
+
+ /*
+ * Information used when displaying the widget:
+ */
+ Tk_3DBorder border; /* Background color */
+ int borderWidth; /* Width of the border. */
+ int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ int inset; /* Total width of highlight and 3-D border */
+ Tk_Font aFont[N_FONT]; /* Information about all screen fonts */
+ char fontValid[(N_FONT+7)/8]; /* If bit N%8 of work N/8 of this field is 0
+ * if aFont[N] needs to be reallocated before
+ * being used. */
+ XColor *apColor[N_COLOR]; /* Information about all colors */
+ int colorUsed; /* bit N is 1 if color N is in use. Only
+ ** applies to colors that aren't predefined */
+ int iDark[N_COLOR]; /* Dark 3D shadow of color K is iDark[K] */
+ int iLight[N_COLOR]; /* Light 3D shadow of color K is iLight[K] */
+ XColor *fgColor; /* Color of normal text. apColor[0] */
+ XColor *newLinkColor; /* Color of unvisitied links. apColor[1] */
+ XColor *oldLinkColor; /* Color of visitied links. apColor[2] */
+ XColor *selectionColor; /* Background color for selections */
+ GcCache aGcCache[N_CACHE_GC]; /* A cache of GCs for general use */
+ int lastGC; /* Index of recently used GC */
+ HtmlImage *imageList; /* A list of all images */
+ int width, height; /* User-requested size of the usable drawing
+ * area, in pixels. Borders and padding
+ * make the actual window a little larger */
+ int realWidth, realHeight; /* The actual physical size of tkwin as
+ * reported in the most recent ConfigureNotify
+ * event. */
+ int padx, pady; /* Separation between the edge of the window
+ * and rendered HTML. */
+ int underlineLinks; /* TRUE if we should underline hyperlinks */
+
+ /* Information about the selection
+ */
+ int exportSelection; /* True if the selection is automatically
+ * exported to the clipboard */
+
+ /* Callback commands. The HTML parser will invoke callbacks from time
+ ** to time to find out information it needs to complete formatting of
+ ** the document. The following fields define the callback commands.
+ */
+ char *zIsVisited; /* Command to tell if a hyperlink has already
+ ** been visited */
+ char *zGetImage; /* Command to get an image from a URL */
+ char *zFrameCommand; /* Command for handling <frameset> markup */
+ char *zAppletCommand; /* Command to process applets */
+ char *zResolverCommand; /* Command to resolve URIs */
+ char *zFormCommand; /* When user presses Submit */
+ char *zHyperlinkCommand; /* Invoked when a hyperlink is clicked */
+ char *zFontCommand; /* Invoked to find font names */
+ char *zScriptCommand; /* Invoked for each <SCRIPT> markup */
+
+ /*
+ * Miscellaneous information:
+ */
+ int tableRelief; /* 3d effects on <TABLE> */
+ int ruleRelief; /* 3d effects on <HR> */
+ char *zBase; /* The base URI */
+ char *zBaseHref; /* zBase as modified by <BASE HREF=..> markup */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ char *takeFocus; /* Value of -takefocus option; not used in
+ * the C code, but used by keyboard traversal
+ * scripts. Malloc'ed, but may be NULL. */
+ char *yScrollCmd; /* Command prefix for communicating with
+ * vertical scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ char *xScrollCmd; /* Command prefix for communicating with
+ * horizontal scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ int xOffset, yOffset; /* Current scroll position. These form the
+ * coordinate in the virtual canvas that
+ * corresponds to (0,0) on the physical screen
+ * in window tkwin */
+ int maxX, maxY; /* Maximum extent of any "paint" that appears
+ * on the virtual canvas. Used to compute
+ * scrollbar positions. */
+ int dirtyLeft, dirtyTop; /* Top left corner of region to redraw. These
+ * are physical screen coordinates relative to
+ * clipwin, not tkwin. */
+ int dirtyRight, dirtyBottom; /* Bottom right corner of region to redraw */
+ int locked; /* Number of locks on this structure. Don't
+ ** delete until it reaches zero. */
+ int flags; /* Various flags; see below for
+ * definitions. */
+};
+void HtmlUnmapControls(HtmlWidget *htmlPtr);
+struct HtmlImage {
+ HtmlWidget *htmlPtr; /* The owner of this image */
+ Tk_Image image; /* The Tk image token */
+ Html_32 w; /* Requested width of this image (0 if none) */
+ Html_32 h; /* Requested height of this image (0 if none) */
+ char *zUrl; /* The URL for this image. */
+ char *zWidth, *zHeight; /* Width and height in the <img> markup. */
+ HtmlImage *pNext; /* Next image on the list */
+ HtmlElement *pList; /* List of all <IMG> markups that use this
+ ** same image */
+};
+struct HtmlStyleStack {
+ HtmlStyleStack *pNext; /* Next style on the stack */
+ int type; /* A markup that ends this style. Ex: Html_EndEM */
+ HtmlStyle style; /* The currently active style. */
+};
+struct HtmlMargin {
+ int indent; /* Size of the current margin */
+ int bottom; /* Y value at which this margin expires */
+ int tag; /* Markup that will cancel this margin */
+ HtmlMargin *pNext; /* Previous margin */
+};
diff --git a/tkhtml1/src/htmlimage.c b/tkhtml1/src/htmlimage.c
new file mode 100644
index 0000000..962ac5c
--- /dev/null
+++ b/tkhtml1/src/htmlimage.c
@@ -0,0 +1,225 @@
+/*
+** Routines used for processing <IMG> markup
+**
+** Copyright (C) 1997-2000 D. Richard Hipp
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** drh@acm.org
+** http://www.hwaci.com/drh/
+*/
+#include <tk.h>
+#include <string.h>
+#include <stdlib.h>
+#include "htmlimage.h"
+
+/*
+** Find the alignment for an image
+*/
+int HtmlGetImageAlignment(HtmlElement *p){
+ char *z;
+ int i;
+ int result;
+
+ static struct {
+ char *zName;
+ int iValue;
+ } aligns[] = {
+ { "bottom", IMAGE_ALIGN_Bottom },
+ { "baseline", IMAGE_ALIGN_Bottom },
+ { "middle", IMAGE_ALIGN_Middle },
+ { "top", IMAGE_ALIGN_Top },
+ { "absbottom", IMAGE_ALIGN_AbsBottom },
+ { "absmiddle", IMAGE_ALIGN_AbsMiddle },
+ { "texttop", IMAGE_ALIGN_TextTop },
+ { "left", IMAGE_ALIGN_Left },
+ { "right", IMAGE_ALIGN_Right },
+ };
+
+ z = HtmlMarkupArg(p, "align", 0);
+ result = IMAGE_ALIGN_Bottom;
+ if( z ){
+ for(i=0; i<sizeof(aligns)/sizeof(aligns[0]); i++){
+ if( stricmp(aligns[i].zName,z)==0 ){
+ result = aligns[i].iValue;
+ TestPoint(0);
+ break;
+ }else{
+ TestPoint(0);
+ }
+ }
+ }else{
+ TestPoint(0);
+ }
+ return result;
+}
+
+/*
+** This routine is called when an image changes. If the size of the
+** images changes, then we need to completely redo the layout. If
+** only the appearance changes, then this works like an expose event.
+*/
+static void ImageChangeProc(
+ ClientData clientData, /* Pointer to an HtmlImage structure */
+ int x, /* Left edge of region that changed */
+ int y, /* Top edge of region that changed */
+ int w, /* Width of region that changes. Maybe 0 */
+ int h, /* Height of region that changed. Maybe 0 */
+ int newWidth, /* New width of the image */
+ int newHeight /* New height of the image */
+){
+ HtmlImage *pImage;
+ HtmlWidget *htmlPtr;
+ HtmlElement *pElem;
+
+ pImage = (HtmlImage*)clientData;
+ htmlPtr = pImage->htmlPtr;
+ if( pImage->w!=newWidth || pImage->h!=newHeight ){
+ /* We have to completely redo the layout after adjusting the size
+ ** of the images */
+ for(pElem = pImage->pList; pElem; pElem = pElem->image.pNext){
+ pElem->image.w = newWidth;
+ pElem->image.h = newHeight;
+ TestPoint(0);
+ }
+ htmlPtr->flags |= RELAYOUT;
+ pImage->w = newWidth;
+ pImage->h = newHeight;
+ HtmlRedrawEverything(htmlPtr);
+ }else{
+ for(pElem = pImage->pList; pElem; pElem = pElem->image.pNext){
+ pElem->image.redrawNeeded = 1;
+ }
+ htmlPtr->flags |= REDRAW_IMAGES;
+ HtmlScheduleRedraw(htmlPtr);
+ }
+}
+
+/*
+** Append all the arguments of the given markup to the given
+** DString.
+**
+** Example: If the markup is <IMG SRC=image.gif ALT="hello!">
+** then the following text is appended to the DString:
+**
+** "src image.gif alt hello!"
+**
+** Notice how all attribute names are converted to lower case.
+** This conversion happens in the parser.
+*/
+void HtmlAppendArglist(Tcl_DString *str, HtmlElement *pElem){
+ int i;
+ for(i=0; i+1<pElem->base.count; i+=2){
+ char *z = pElem->markup.argv[i+1];
+ Tcl_DStringAppendElement(str, pElem->markup.argv[i]);
+ Tcl_DStringAppendElement(str, z);
+ }
+}
+
+/*
+** Given an <IMG> markup, find or create an appropriate HtmlImage
+** structure and return a pointer to that structure. NULL might
+** be returned.
+**
+** This routine may invoke a callback procedure which could delete
+** the HTML widget. Use HtmlLock() if necessary to preserve the
+** widget structure.
+*/
+HtmlImage *HtmlGetImage(HtmlWidget *htmlPtr, HtmlElement *p){
+ char *zWidth;
+ char *zHeight;
+ char *zSrc;
+ char *zImageName;
+ HtmlImage *pImage;
+ int result;
+ Tcl_DString cmd;
+ int lenSrc, lenW, lenH; /* Lengths of various strings */
+
+ if( p->base.type!=Html_IMG ){ CANT_HAPPEN; return 0; }
+ if( htmlPtr->zGetImage==0 || htmlPtr->zGetImage[0]==0 ){
+ TestPoint(0);
+ return 0;
+ }
+ zSrc = HtmlMarkupArg(p, "src", 0);
+ if( zSrc==0 ){
+ return 0;
+ }
+ HtmlLock(htmlPtr);
+ zSrc = HtmlResolveUri(htmlPtr, zSrc);
+ if( HtmlUnlock(htmlPtr) || zSrc==0 ) return 0;
+ zWidth = HtmlMarkupArg(p, "width", "");
+ zHeight = HtmlMarkupArg(p, "height", "");
+ for(pImage=htmlPtr->imageList; pImage; pImage=pImage->pNext){
+ if( strcmp(pImage->zUrl,zSrc)==0
+ && strcmp(pImage->zWidth, zWidth)==0
+ && strcmp(pImage->zHeight, zHeight)==0 ){
+ HtmlFree(zSrc);
+ return pImage;
+ }
+ }
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, htmlPtr->zGetImage, -1);
+ Tcl_DStringAppendElement(&cmd,zSrc);
+ Tcl_DStringAppendElement(&cmd,zWidth);
+ Tcl_DStringAppendElement(&cmd,zHeight);
+ Tcl_DStringStartSublist(&cmd);
+ HtmlAppendArglist(&cmd, p);
+ Tcl_DStringEndSublist(&cmd);
+ HtmlLock(htmlPtr);
+ result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if( HtmlUnlock(htmlPtr) ){
+ HtmlFree(zSrc);
+ }
+ zImageName = (char*)Tcl_GetStringResult(htmlPtr->interp);
+ lenSrc = strlen(zSrc);
+ lenW = strlen(zWidth);
+ lenH = strlen(zHeight);
+ pImage = HtmlAlloc( sizeof(HtmlImage) + lenSrc + lenW + lenH + 3 );
+ memset(pImage,0,sizeof(HtmlImage));
+ pImage->htmlPtr = htmlPtr;
+ pImage->zUrl = (char*)&pImage[1];
+ strcpy(pImage->zUrl,zSrc);
+ HtmlFree(zSrc);
+ pImage->zWidth = &pImage->zUrl[lenSrc+1];
+ strcpy(pImage->zWidth, zWidth);
+ pImage->zHeight = &pImage->zWidth[lenW+1];
+ strcpy(pImage->zHeight, zHeight);
+ pImage->w = 0;
+ pImage->h = 0;
+ if( result==TCL_OK ){
+ pImage->image = Tk_GetImage(htmlPtr->interp, htmlPtr->clipwin,
+ zImageName, ImageChangeProc, pImage);
+ TestPoint(0);
+ }else{
+ Tcl_AddErrorInfo(htmlPtr->interp,
+ "\n (\"-imagecommand\" command executed by html widget)");
+ Tcl_BackgroundError(htmlPtr->interp);
+ pImage->image = 0;
+ TestPoint(0);
+ }
+ if( pImage->image==0 ){
+ HtmlFree((char*)pImage);
+ TestPoint(0);
+ return 0;
+ }
+ pImage->pNext = htmlPtr->imageList;
+ htmlPtr->imageList = pImage;
+ TestPoint(0);
+ Tcl_ResetResult(htmlPtr->interp);
+ return pImage;
+}
diff --git a/tkhtml1/src/htmlimage.h b/tkhtml1/src/htmlimage.h
new file mode 100644
index 0000000..e7cb81f
--- /dev/null
+++ b/tkhtml1/src/htmlimage.h
@@ -0,0 +1,467 @@
+/* This file was automatically generated. Do not edit! */
+/*#define HtmlAlloc(A) ((void*)Tcl_Alloc(A))*/
+void* HtmlAlloc(size_t);
+#define HtmlFree(A) Tcl_Free((char*)(A))
+typedef struct HtmlWidget HtmlWidget;
+int HtmlUnlock(HtmlWidget *htmlPtr);
+char *HtmlResolveUri(HtmlWidget *htmlPtr,char *zUri);
+void HtmlLock(HtmlWidget *htmlPtr);
+void HtmlTPCantHappen(const char *zFile,int line);
+#if defined(COVERAGE_TEST)
+# define CANT_HAPPEN HtmlTPCantHappen(__FILE__,__LINE__)
+#endif
+#if !(defined(COVERAGE_TEST))
+# define CANT_HAPPEN
+#endif
+#define Html_IMG 76
+typedef struct HtmlImage HtmlImage;
+typedef union HtmlElement HtmlElement;
+HtmlImage *HtmlGetImage(HtmlWidget *htmlPtr,HtmlElement *p);
+void HtmlAppendArglist(Tcl_DString *str,HtmlElement *pElem);
+void HtmlScheduleRedraw(HtmlWidget *htmlPtr);
+#define REDRAW_IMAGES 0x002000
+void HtmlRedrawEverything(HtmlWidget *htmlPtr);
+#define RELAYOUT 0x000010
+typedef struct HtmlBlock HtmlBlock;
+typedef struct HtmlIndex HtmlIndex;
+struct HtmlIndex {
+ HtmlElement *p; /* The token containing the character */
+ int i; /* Index of the character */
+};
+typedef short Html_16;
+typedef struct HtmlScript HtmlScript;
+#define Html_TypeCount 151
+typedef struct HtmlStyleStack HtmlStyleStack;
+typedef struct HtmlLayoutContext HtmlLayoutContext;
+typedef struct HtmlMargin HtmlMargin;
+struct HtmlLayoutContext {
+ HtmlWidget *htmlPtr; /* The html widget undergoing layout */
+ HtmlElement *pStart; /* Start of elements to layout */
+ HtmlElement *pEnd; /* Stop when reaching this element */
+ int headRoom; /* Extra space wanted above this line */
+ int top; /* Absolute top of drawing area */
+ int bottom; /* Bottom of previous line */
+ int left, right; /* Left and right extremes of drawing area */
+ int pageWidth; /* Width of the layout field, including
+ ** the margins */
+ int maxX, maxY; /* Maximum X and Y values of paint */
+ HtmlMargin *leftMargin; /* Stack of left margins */
+ HtmlMargin *rightMargin; /* Stack of right margins */
+};
+#define N_FONT_FAMILY 8
+#define N_FONT_SIZE 7
+#define N_FONT (N_FONT_FAMILY*N_FONT_SIZE)
+#define N_COLOR 16 /* Total number of colors */
+typedef struct GcCache GcCache;
+typedef unsigned char Html_u8;
+struct GcCache {
+ GC gc; /* The graphics context */
+ Html_u8 font; /* Font used for this context */
+ Html_u8 color; /* Color used for this context */
+ Html_u8 index; /* Index used for LRU replacement */
+};
+#define N_CACHE_GC 16
+struct HtmlWidget {
+ Tk_Window tkwin; /* The main window for this widget */
+ Tk_Window clipwin; /* The clipping window in which all text is
+ ** rendered. */
+ char *zClipwin; /* Name of the clipping window. */
+ Display *display; /* The X11 Server that contains tkwin */
+ Tcl_Interp *interp; /* The interpreter in which the widget lives */
+ char *zCmdName; /* Name of the command */
+ HtmlElement *pFirst; /* First HTML token on a list of them all */
+ HtmlElement *pLast; /* Last HTML token on the list */
+ int nToken; /* Number of HTML tokens on the list.
+ * Html_Block tokens don't count. */
+ HtmlElement *lastSized; /* Last HTML element that has been sized */
+ HtmlElement *nextPlaced; /* Next HTML element that needs to be
+ * positioned on canvas. */
+ HtmlBlock *firstBlock; /* List of all HtmlBlock tokens */
+ HtmlBlock *lastBlock; /* Last HtmlBlock in the list */
+ HtmlElement *firstInput; /* First <INPUT> element */
+ HtmlElement *lastInput; /* Last <INPUT> element */
+ int nInput; /* The number of <INPUT> elements */
+ int nForm; /* The number of <FORM> elements */
+ int varId; /* Used to construct a unique name for a
+ ** global array used by <INPUT> elements */
+
+ /*
+ * Information about the selected region of text
+ */
+ HtmlIndex selBegin; /* Start of the selection */
+ HtmlIndex selEnd; /* End of the selection */
+ HtmlBlock *pSelStartBlock; /* Block in which selection starts */
+ Html_16 selStartIndex; /* Index in pSelStartBlock of first selected
+ * character */
+ Html_16 selEndIndex; /* Index of last selecte char in pSelEndBlock */
+ HtmlBlock *pSelEndBlock; /* Block in which selection ends */
+
+ /*
+ * Information about the insertion cursor
+ */
+ int insOnTime; /* How long the cursor states one (millisec) */
+ int insOffTime; /* How long it is off (milliseconds) */
+ int insStatus; /* Is it visible? */
+ Tcl_TimerToken insTimer; /* Timer used to flash the insertion cursor */
+ HtmlIndex ins; /* The insertion cursor position */
+ HtmlBlock *pInsBlock; /* The HtmlBlock containing the cursor */
+ int insIndex; /* Index in pInsBlock of the cursor */
+
+ /*
+ * The following fields hold state information used by
+ * the tokenizer.
+ */
+ char *zText; /* Complete text of the unparsed HTML */
+ int nText; /* Number of characters in zText */
+ int nAlloc; /* Space allocated for zText */
+ int nComplete; /* How much of zText has actually been
+ * converted into tokens */
+ int iCol; /* The column in which zText[nComplete]
+ * occurs. Used to resolve tabs in input */
+ int iPlaintext; /* If not zero, this is the token type that
+ * caused us to go into plaintext mode. One
+ * of Html_PLAINTEXT, Html_LISTING or
+ * Html_XMP */
+ HtmlScript *pScript; /* <SCRIPT> currently being parsed */
+ char *zHandler[Html_TypeCount]; /* If not NULL, this is a TCL routine that
+ * is used to process tokens of the given
+ * type */
+ /*
+ * These fields hold state information used by the HtmlAddStyle routine.
+ * We have to store this state information here since HtmlAddStyle
+ * operates incrementally. This information must be carried from
+ * one incremental execution to the next.
+ */
+ HtmlStyleStack *styleStack; /* The style stack */
+ int paraAlignment; /* Justification associated with <p> */
+ int rowAlignment; /* Justification associated with <tr> */
+ int anchorFlags; /* Style flags associated with <A>...</A> */
+ int inDt; /* Style flags associated with <DT>...</DT> */
+ int inTr; /* True if within <tr>..</tr> */
+ int inTd; /* True if within <td>..</td> or <th>..</th> */
+ HtmlElement *anchorStart; /* Most recent <a href=...> */
+ HtmlElement *formStart; /* Most recent <form> */
+ HtmlElement *formElemStart; /* Most recent <textarea> or <select> */
+ HtmlElement *innerList; /* The inner most <OL> or <UL> */
+
+ /*
+ * These fields are used to hold the state of the layout engine.
+ * Because the layout is incremental, this state must be held for
+ * the life of the widget.
+ */
+ HtmlLayoutContext layoutContext;
+
+ /*
+ * Information used when displaying the widget:
+ */
+ Tk_3DBorder border; /* Background color */
+ int borderWidth; /* Width of the border. */
+ int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ int inset; /* Total width of highlight and 3-D border */
+ Tk_Font aFont[N_FONT]; /* Information about all screen fonts */
+ char fontValid[(N_FONT+7)/8]; /* If bit N%8 of work N/8 of this field is 0
+ * if aFont[N] needs to be reallocated before
+ * being used. */
+ XColor *apColor[N_COLOR]; /* Information about all colors */
+ int colorUsed; /* bit N is 1 if color N is in use. Only
+ ** applies to colors that aren't predefined */
+ int iDark[N_COLOR]; /* Dark 3D shadow of color K is iDark[K] */
+ int iLight[N_COLOR]; /* Light 3D shadow of color K is iLight[K] */
+ XColor *fgColor; /* Color of normal text. apColor[0] */
+ XColor *newLinkColor; /* Color of unvisitied links. apColor[1] */
+ XColor *oldLinkColor; /* Color of visitied links. apColor[2] */
+ XColor *selectionColor; /* Background color for selections */
+ GcCache aGcCache[N_CACHE_GC]; /* A cache of GCs for general use */
+ int lastGC; /* Index of recently used GC */
+ HtmlImage *imageList; /* A list of all images */
+ int width, height; /* User-requested size of the usable drawing
+ * area, in pixels. Borders and padding
+ * make the actual window a little larger */
+ int realWidth, realHeight; /* The actual physical size of tkwin as
+ * reported in the most recent ConfigureNotify
+ * event. */
+ int padx, pady; /* Separation between the edge of the window
+ * and rendered HTML. */
+ int underlineLinks; /* TRUE if we should underline hyperlinks */
+
+ /* Information about the selection
+ */
+ int exportSelection; /* True if the selection is automatically
+ * exported to the clipboard */
+
+ /* Callback commands. The HTML parser will invoke callbacks from time
+ ** to time to find out information it needs to complete formatting of
+ ** the document. The following fields define the callback commands.
+ */
+ char *zIsVisited; /* Command to tell if a hyperlink has already
+ ** been visited */
+ char *zGetImage; /* Command to get an image from a URL */
+ char *zFrameCommand; /* Command for handling <frameset> markup */
+ char *zAppletCommand; /* Command to process applets */
+ char *zResolverCommand; /* Command to resolve URIs */
+ char *zFormCommand; /* When user presses Submit */
+ char *zHyperlinkCommand; /* Invoked when a hyperlink is clicked */
+ char *zFontCommand; /* Invoked to find font names */
+ char *zScriptCommand; /* Invoked for each <SCRIPT> markup */
+
+ /*
+ * Miscellaneous information:
+ */
+ int tableRelief; /* 3d effects on <TABLE> */
+ int ruleRelief; /* 3d effects on <HR> */
+ char *zBase; /* The base URI */
+ char *zBaseHref; /* zBase as modified by <BASE HREF=..> markup */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ char *takeFocus; /* Value of -takefocus option; not used in
+ * the C code, but used by keyboard traversal
+ * scripts. Malloc'ed, but may be NULL. */
+ char *yScrollCmd; /* Command prefix for communicating with
+ * vertical scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ char *xScrollCmd; /* Command prefix for communicating with
+ * horizontal scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ int xOffset, yOffset; /* Current scroll position. These form the
+ * coordinate in the virtual canvas that
+ * corresponds to (0,0) on the physical screen
+ * in window tkwin */
+ int maxX, maxY; /* Maximum extent of any "paint" that appears
+ * on the virtual canvas. Used to compute
+ * scrollbar positions. */
+ int dirtyLeft, dirtyTop; /* Top left corner of region to redraw. These
+ * are physical screen coordinates relative to
+ * clipwin, not tkwin. */
+ int dirtyRight, dirtyBottom; /* Bottom right corner of region to redraw */
+ int locked; /* Number of locks on this structure. Don't
+ ** delete until it reaches zero. */
+ int flags; /* Various flags; see below for
+ * definitions. */
+};
+typedef int Html_32;
+struct HtmlImage {
+ HtmlWidget *htmlPtr; /* The owner of this image */
+ Tk_Image image; /* The Tk image token */
+ Html_32 w; /* Requested width of this image (0 if none) */
+ Html_32 h; /* Requested height of this image (0 if none) */
+ char *zUrl; /* The URL for this image. */
+ char *zWidth, *zHeight; /* Width and height in the <img> markup. */
+ HtmlImage *pNext; /* Next image on the list */
+ HtmlElement *pList; /* List of all <IMG> markups that use this
+ ** same image */
+};
+#if defined(COVERAGE_TEST)
+extern int HtmlTPArray[2000];
+# define TestPoint(X) {extern int HtmlTPArray[]; HtmlTPArray[X]++;}
+#endif
+#if !(defined(COVERAGE_TEST))
+# define TestPoint(X)
+#endif
+#if !defined(HAVE_STRICMP)
+# define stricmp strcasecmp
+#endif
+char *HtmlMarkupArg(HtmlElement *p,const char *tag,char *zDefault);
+#define IMAGE_ALIGN_Right 7
+#define IMAGE_ALIGN_Left 6
+#define IMAGE_ALIGN_TextTop 3
+#define IMAGE_ALIGN_AbsMiddle 4
+#define IMAGE_ALIGN_AbsBottom 5
+#define IMAGE_ALIGN_Top 2
+#define IMAGE_ALIGN_Middle 1
+#define IMAGE_ALIGN_Bottom 0
+typedef struct HtmlBaseElement HtmlBaseElement;
+typedef struct HtmlStyle HtmlStyle;
+struct HtmlStyle {
+ unsigned int font : 6; /* Font to use for display */
+ unsigned int color : 4; /* Foreground color */
+ signed int subscript : 4; /* Positive for <sup>, negative for <sub> */
+ unsigned int align : 2; /* Horizontal alignment */
+ unsigned int bgcolor : 4; /* Background color */
+ unsigned int flags : 12; /* the STY_ flags below */
+};
+struct HtmlBaseElement {
+ HtmlElement *pNext; /* Next input token in a list of them all */
+ HtmlElement *pPrev; /* Previous token in a list of them all */
+ HtmlStyle style; /* The rendering style for this token */
+ Html_u8 type; /* The token type. */
+ Html_u8 flags; /* The HTML_ flags below */
+ Html_16 count; /* Various uses, depending on "type" */
+};
+typedef struct HtmlTextElement HtmlTextElement;
+struct HtmlTextElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_32 y; /* y coordinate where text should be rendered */
+ Html_16 x; /* x coordinate where text should be rendered */
+ Html_16 w; /* width of this token in pixels */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_u8 spaceWidth; /* Width of one space in the current font */
+ char zText[1]; /* Text for this element. Null terminated */
+};
+typedef struct HtmlSpaceElement HtmlSpaceElement;
+struct HtmlSpaceElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_16 w; /* Width of a single space in current font */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+};
+typedef struct HtmlMarkupElement HtmlMarkupElement;
+struct HtmlMarkupElement {
+ HtmlBaseElement base;
+ char **argv;
+};
+typedef struct HtmlCell HtmlCell;
+struct HtmlCell {
+ HtmlMarkupElement markup;
+ Html_16 rowspan; /* Number of rows spanned by this cell */
+ Html_16 colspan; /* Number of columns spanned by this cell */
+ Html_16 x; /* X coordinate of left edge of border */
+ Html_16 w; /* Width of the border */
+ Html_32 y; /* Y coordinate of top of border indentation */
+ Html_32 h; /* Height of the border */
+ HtmlElement *pTable; /* Pointer back to the <table> */
+ HtmlElement *pEnd; /* Element that ends this cell */
+};
+typedef struct HtmlTable HtmlTable;
+typedef unsigned short Html_u16;
+#define HTML_MAX_COLUMNS 40
+struct HtmlTable {
+ HtmlMarkupElement markup;
+ Html_u8 borderWidth; /* Width of the border */
+ Html_u8 nCol; /* Number of columns */
+ Html_u16 nRow; /* Number of rows */
+ Html_32 y; /* top edge of table border */
+ Html_32 h; /* height of the table border */
+ Html_16 x; /* left edge of table border */
+ Html_16 w; /* width of the table border */
+ int minW[HTML_MAX_COLUMNS+1]; /* minimum width of each column */
+ int maxW[HTML_MAX_COLUMNS+1]; /* maximum width of each column */
+};
+typedef struct HtmlRef HtmlRef;
+struct HtmlRef {
+ HtmlMarkupElement markup;
+ HtmlElement *pOther; /* Pointer to some other Html element */
+};
+typedef struct HtmlLi HtmlLi;
+struct HtmlLi {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* What type of list is this? */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_16 cnt; /* Value for this element (if inside <OL>) */
+ Html_16 x; /* X coordinate of the bullet */
+ Html_32 y; /* Y coordinate of the bullet */
+};
+typedef struct HtmlListStart HtmlListStart;
+struct HtmlListStart {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* One of the LI_TYPE_ defines above */
+ Html_u8 compact; /* True if the COMPACT flag is present */
+ Html_u16 cnt; /* Next value for <OL> */
+ Html_u16 width; /* How much space to allow for indentation */
+ HtmlElement *pPrev; /* Next higher level list, or NULL */
+};
+typedef struct HtmlImageMarkup HtmlImageMarkup;
+struct HtmlImageMarkup {
+ HtmlMarkupElement markup;
+ Html_u8 align; /* Alignment. See IMAGE_ALIGN_ defines below */
+ Html_u8 textAscent; /* Ascent of text font in force at the <IMG> */
+ Html_u8 textDescent; /* Descent of text font in force at the <IMG> */
+ Html_u8 redrawNeeded; /* Need to redraw this image because the image
+ ** content changed. */
+ Html_16 h; /* Actual height of the image */
+ Html_16 w; /* Actual width of the image */
+ Html_16 ascent; /* How far image extends above "y" */
+ Html_16 descent; /* How far image extends below "y" */
+ Html_16 x; /* X coordinate of left edge of the image */
+ Html_32 y; /* Y coordinate of image baseline */
+ char *zAlt; /* Alternative text */
+ HtmlImage *pImage; /* Corresponding HtmlImage structure */
+ HtmlElement *pNext; /* Next markup using the same HtmlImage structure */
+};
+typedef struct HtmlInput HtmlInput;
+struct HtmlInput {
+ HtmlMarkupElement markup;
+ HtmlElement *pForm; /* The <FORM> to which this belongs */
+ HtmlElement *pNext; /* Next element in a list of all input elements */
+ Tk_Window tkwin; /* The window that implements this control */
+ HtmlWidget *htmlPtr; /* The whole widget. Needed by geometry callbacks */
+ HtmlElement *pEnd; /* End tag for <TEXTAREA>, etc. */
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 padLeft; /* Extra padding on left side of the control */
+ Html_u8 align; /* One of the IMAGE_ALIGN_xxx types */
+ Html_u8 textAscent; /* Ascent for the current font */
+ Html_u8 textDescent; /* descent for the current font */
+ Html_u8 type; /* What type of input is this? */
+ Html_u8 sized; /* True if this input has been sized already */
+ Html_u16 cnt; /* Used to derive widget name. 0 if no widget */
+};
+typedef struct HtmlForm HtmlForm;
+struct HtmlForm {
+ HtmlMarkupElement markup;
+ Html_u16 id; /* Unique number assigned to this form */
+};
+typedef struct HtmlHr HtmlHr;
+struct HtmlHr {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 is3D; /* Is it drawn 3D? */
+};
+typedef struct HtmlAnchor HtmlAnchor;
+struct HtmlAnchor {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Top edge for this element */
+};
+struct HtmlScript {
+ HtmlMarkupElement markup;
+ char *zScript; /* Complete text of this script */
+ int nScript; /* Number of characters of text */
+};
+struct HtmlBlock {
+ HtmlBaseElement base; /* Superclass. Must be first */
+ char *z; /* Space to hold text when n>0 */
+ int top, bottom; /* Extremes of y coordinates */
+ Html_u16 left, right; /* Left and right boundry of this object */
+ Html_u16 n; /* Number of characters in z[] */
+ HtmlBlock *pPrev, *pNext; /* Linked list of all Blocks */
+};
+union HtmlElement {
+ HtmlElement *pNext;
+ HtmlBaseElement base;
+ HtmlTextElement text;
+ HtmlSpaceElement space;
+ HtmlMarkupElement markup;
+ HtmlCell cell;
+ HtmlTable table;
+ HtmlRef ref;
+ HtmlLi li;
+ HtmlListStart list;
+ HtmlImageMarkup image;
+ HtmlInput input;
+ HtmlForm form;
+ HtmlHr hr;
+ HtmlAnchor anchor;
+ HtmlScript script;
+ HtmlBlock block;
+};
+int HtmlGetImageAlignment(HtmlElement *p);
+struct HtmlStyleStack {
+ HtmlStyleStack *pNext; /* Next style on the stack */
+ int type; /* A markup that ends this style. Ex: Html_EndEM */
+ HtmlStyle style; /* The currently active style. */
+};
+struct HtmlMargin {
+ int indent; /* Size of the current margin */
+ int bottom; /* Y value at which this margin expires */
+ int tag; /* Markup that will cancel this margin */
+ HtmlMargin *pNext; /* Previous margin */
+};
diff --git a/tkhtml1/src/htmlindex.c b/tkhtml1/src/htmlindex.c
new file mode 100644
index 0000000..7b488a1
--- /dev/null
+++ b/tkhtml1/src/htmlindex.c
@@ -0,0 +1,505 @@
+/*
+** Routines that deal with indexes
+**
+** Copyright (C) 1997-2000 D. Richard Hipp
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** drh@acm.org
+** http://www.hwaci.com/drh/
+*/
+#include <ctype.h>
+#include <tk.h>
+#include <string.h>
+#include "htmlindex.h"
+
+/*
+** Return a pointer to the Nth HtmlElement in the list. If there
+** is no Nth element, return 0 if flag==0 and return either the first
+** or last element (whichever is closest) if flag!=0
+*/
+HtmlElement *HtmlTokenByIndex(HtmlWidget *htmlPtr, int N, int flag){
+ HtmlElement *p;
+ int n;
+
+ if( N > htmlPtr->nToken/2 ){
+ /* Start at the end and work back toward the beginning */
+ for(p=htmlPtr->pLast, n=htmlPtr->nToken; p; p=p->base.pPrev){
+ if( p->base.type!=Html_Block ){
+ if( n==N ){ TestPoint(0); break; }
+ n--;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ }
+ }else{
+ /* Start at the beginning and work forward */
+ for(p=htmlPtr->pFirst; p; p = p->base.pNext){
+ if( p->base.type!=Html_Block ){
+ N--;
+ if( N<=0 ){ TestPoint(0); break; }
+ }else{
+ TestPoint(0);
+ }
+ }
+ }
+ return p;
+}
+
+/*
+** Return the token number for the given HtmlElement
+*/
+int HtmlTokenNumber(HtmlElement *p){
+ int n = 0;
+
+ while( p ){
+ if( p->base.type!=Html_Block ){
+ TestPoint(0);
+ n++;
+ }else{
+ TestPoint(0);
+ }
+ p = p->base.pPrev;
+ }
+ return n;
+}
+
+/*
+** Find the maximum index for the given token
+*/
+static void maxIndex(HtmlElement *p, int *pIndex){
+ if( p==0 ){
+ *pIndex = 0;
+ TestPoint(0);
+ }else{
+ switch( p->base.type ){
+ case Html_Text:
+ *pIndex = p->base.count-1;
+ TestPoint(0);
+ break;
+ case Html_Space:
+ if( p->base.style.flags & STY_Preformatted ){
+ *pIndex = p->base.count-1;
+ TestPoint(0);
+ }else{
+ *pIndex = 0;
+ TestPoint(0);
+ }
+ break;
+ default:
+ *pIndex = 0;
+ TestPoint(0);
+ break;
+ }
+ }
+}
+
+/*
+** Given a Block and an x coordinate, find the Index of the character
+** that is closest to the given x coordinate.
+**
+** The x-coordinate might specify a point to the left of the block,
+** in which case the procedure returns the first token and a character
+** index of 0. Or the x-coordinate might specify a point to the right
+** of the block, in which case the last token is returned with an index
+** equal to its last character.
+*/
+static void FindIndexInBlock(
+ HtmlWidget *htmlPtr, /* The widget */
+ HtmlBlock *pBlock, /* The block */
+ int x, /* The x coordinate */
+ HtmlElement **ppToken, /* Write the closest token here */
+ int *pIndex /* Write the charater index in ppToken here */
+){
+ HtmlElement *p;
+ Tk_Font font;
+ int len;
+ int n;
+
+ p = pBlock->base.pNext;
+ HtmlLock(htmlPtr);
+ font = HtmlGetFont(htmlPtr, p->base.style.font);
+ if( HtmlUnlock(htmlPtr) ){
+ *ppToken = p;
+ *pIndex = 0;
+ return;
+ }
+ if( x <= pBlock->left ){
+ *ppToken = p;
+ *pIndex = 0;
+ TestPoint(0);
+ return;
+ }else if( x>= pBlock->right ){
+ *ppToken = p;
+ *pIndex = 0;
+ while( p && p->base.type!=Html_Block ){
+ *ppToken = p;
+ p = p->base.pNext;
+ TestPoint(0);
+ }
+ p = *ppToken;
+ if( p && p->base.type==Html_Text ){
+ *pIndex = p->base.count - 1;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ return;
+ }
+ if( pBlock->n==0 ){
+ *ppToken = p;
+ *pIndex = 0;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ n = Tk_MeasureChars(font, pBlock->z, pBlock->n, x - pBlock->left, 0, &len);
+ *pIndex = 0;
+ *ppToken = 0;
+ while( p && n>=0 ){
+ switch( p->base.type ){
+ case Html_Text:
+ if( n<p->base.count ){
+ *pIndex = n;
+ TestPoint(0);
+ }else{
+ *pIndex = p->base.count - 1;
+ TestPoint(0);
+ }
+ *ppToken = p;
+ n -= p->base.count;
+ break;
+ case Html_Space:
+ if( p->base.style.flags & STY_Preformatted ){
+ if( n<p->base.count ){
+ *pIndex = n;
+ TestPoint(0);
+ }else{
+ *pIndex = p->base.count - 1;
+ TestPoint(0);
+ }
+ *ppToken = p;
+ n -= p->base.count;
+ }else{
+ *pIndex = 0;
+ *ppToken = p;
+ n--;
+ TestPoint(0);
+ }
+ break;
+ default:
+ TestPoint(0);
+ break;
+ }
+ if( p ){
+ p = p->base.pNext;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ }
+}
+
+/*
+** Convert an Element-based index into a Block-based index.
+**
+** In other words, given a pointer to an element and an index
+** of a particular character within that element, compute a
+** pointer to the HtmlBlock used to display that character and
+** the index in the HtmlBlock of the character.
+*/
+void HtmlIndexToBlockIndex(
+ HtmlWidget *htmlPtr, /* The widget */
+ HtmlIndex sIndex, /* The index to be translated */
+ HtmlBlock **ppBlock, /* Write the corresponding block here */
+ int *piIndex /* Write the block index here */
+){
+ int n = sIndex.i;
+ HtmlElement *p;
+
+ if( sIndex.p==0 ){
+ *ppBlock = 0;
+ *piIndex = 0;
+ TestPoint(0);
+ return;
+ }
+ p = sIndex.p->base.pPrev;
+ while( p && p->base.type!=Html_Block ){
+ switch( p->base.type ){
+ case Html_Text:
+ n += p->base.count;
+ TestPoint(0);
+ break;
+ case Html_Space:
+ if( p->base.style.flags & STY_Preformatted ){
+ n += p->base.count;
+ TestPoint(0);
+ }else{
+ n++;
+ TestPoint(0);
+ }
+ break;
+ default:
+ TestPoint(0);
+ break;
+ }
+ p = p->base.pPrev;
+ }
+ if( p ){
+ *ppBlock = &p->block;
+ *piIndex = n;
+ TestPoint(0);
+ return;
+ }
+ for(p=sIndex.p; p && p->base.type!=Html_Block; p=p->base.pNext){
+ TestPoint(0);
+ }
+ *ppBlock = &p->block;
+ *piIndex = 0;
+}
+
+
+
+/*
+** Given a base index name (without any modifiers) return a pointer
+** to the token described, and the character within that token.
+**
+** Valid input forms include:
+**
+** N.M Token number N (with numbering starting at 1) and
+** character number M (with numbering starting at 0).
+**
+** end The end of all text
+**
+** N.last Last character of token number N.
+**
+** sel.first First character of the selection.
+**
+** sel.last Last character of the selection.
+**
+** ins The character holding the insertion cursor.
+**
+** @X,Y The character a location X,Y of the clipping window.
+**
+** Zero is returned if we are successful and non-zero if there is
+** any kind of error.
+**
+** If the given token doesn't exist (for example if there are only 10
+** tokens and 11.5 is requested) then *ppToken is left pointing to NULL.
+** But the function still returns 0 for success.
+*/
+static int DecodeBaseIndex(
+ HtmlWidget *htmlPtr, /* The HTML widget we are dealing with */
+ const char *zBase, /* The base index string */
+ HtmlElement **ppToken, /* Write the pointer to the token here */
+ int *pIndex /* Write the character offset here */
+){
+ int x, y;
+ int n;
+ int i;
+ HtmlElement *p;
+ HtmlBlock *pBlock;
+ HtmlBlock *pNearby;
+ int dist = 1000000;
+ int rc = 0;
+
+ while( isspace(*zBase) ){ TestPoint(0); zBase++; }
+ switch( *zBase ){
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ n = sscanf(zBase,"%d.%d",&x,&y);
+ if( n>0 ){
+ p = *ppToken = HtmlTokenByIndex(htmlPtr, x, 0);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ if( n==2 ){
+ *pIndex = y;
+ TestPoint(0);
+ }else{
+ for(i=1; isdigit(zBase[i]); i++){ TestPoint(0); }
+ if( zBase[i]==0 ){
+ *pIndex = 0;
+ TestPoint(0);
+ }else if( strcmp(&zBase[i],".last")==0 ){
+ maxIndex(p,pIndex);
+ TestPoint(0);
+ }else{
+ rc = 1;
+ TestPoint(0);
+ }
+ }
+ break;
+ case 'e':
+ if( strcmp(zBase,"end")==0 ){
+ p = *ppToken = htmlPtr->pLast;
+ maxIndex(p,pIndex);
+ TestPoint(0);
+ }else{
+ rc = 1;
+ TestPoint(0);
+ }
+ break;
+ case 's':
+ if( strcmp(zBase,"sel.first")==0 ){
+ *ppToken = htmlPtr->selBegin.p;
+ *pIndex = htmlPtr->selBegin.i;
+ TestPoint(0);
+ }else if( strcmp(zBase,"sel.last")==0 ){
+ *ppToken = htmlPtr->selEnd.p;
+ *pIndex = htmlPtr->selEnd.i;
+ TestPoint(0);
+ }else{
+ rc = 1;
+ TestPoint(0);
+ }
+ break;
+ case 'i':
+ if( strcmp(zBase,"insert")==0 ){
+ *ppToken = htmlPtr->ins.p;
+ *pIndex = htmlPtr->ins.i;
+ TestPoint(0);
+ }else{
+ rc = 1;
+ TestPoint(0);
+ }
+ break;
+ case '@':
+ n = sscanf(zBase,"@%d,%d",&x,&y);
+ if( n!=2 ){
+ rc = 1;
+ TestPoint(0);
+ break;
+ }
+ x += htmlPtr->xOffset;
+ y += htmlPtr->yOffset;
+ pNearby = 0;
+ *ppToken = htmlPtr->pLast;
+ *pIndex = 0;
+ for(pBlock=htmlPtr->firstBlock; pBlock; pBlock=pBlock->pNext){
+ int dotest;
+ if( pBlock->n==0 ){
+ switch( pBlock->base.pNext->base.type ){
+ case Html_LI:
+ case Html_IMG:
+ case Html_INPUT:
+ case Html_TEXTAREA:
+ case Html_SELECT:
+ dotest = 1;
+ TestPoint(0);
+ break;
+ default:
+ dotest = 0;
+ TestPoint(0);
+ break;
+ }
+ }else{
+ dotest = 1;
+ TestPoint(0);
+ }
+ if (dotest){
+ if( pBlock->top <= y && pBlock->bottom >= y ){
+ if( pBlock->left > x ){
+ if( pBlock->left - x < dist ){
+ dist = pBlock->left - x;
+ pNearby = pBlock;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ }else if( pBlock->right < x ){
+ if( x - pBlock->right < dist ){
+ dist = x - pBlock->right;
+ pNearby = pBlock;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ }else{
+ HtmlLock(htmlPtr);
+ FindIndexInBlock(htmlPtr, pBlock, x, ppToken, pIndex);
+ if( HtmlUnlock(htmlPtr) ) return 1;
+ TestPoint(0);
+ break;
+ }
+ }else{
+ int distY;
+ int distX;
+
+ if( pBlock->bottom < y ){
+ distY = y - pBlock->bottom;
+ TestPoint(0);
+ }else{
+ distY = pBlock->top - y;
+ TestPoint(0);
+ }
+ if( pBlock->left > x ){
+ distX = pBlock->left - x;
+ TestPoint(0);
+ }else if( pBlock->right < x ){
+ distX = x - pBlock->right;
+ TestPoint(0);
+ }else{
+ distX = 0;
+ TestPoint(0);
+ }
+ if( distX + 4*distY < dist ){
+ dist = distX + 4*distY;
+ pNearby = pBlock;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ }
+ }
+ }
+ if( pBlock==0 ){
+ if( pNearby ){
+ HtmlLock(htmlPtr);
+ FindIndexInBlock(htmlPtr, pNearby, x, ppToken, pIndex);
+ if( HtmlUnlock(htmlPtr) ) return 1;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ }else{
+ TestPoint(0);
+ }
+ break;
+ default:
+ rc = 1;
+ TestPoint(0);
+ break;
+ }
+ return rc;
+}
+
+/*
+** This routine decodes a complete index specification. A complete
+** index consists of the base specification followed by modifiers.
+*/
+int HtmlGetIndex(
+ HtmlWidget *htmlPtr, /* The widget */
+ const char *zIndex, /* Complete text of the index spec */
+ HtmlElement **ppToken, /* Write the pointer to the token here */
+ int *pIndex /* Write the character offset here */
+){
+ TestPoint(0);
+ return DecodeBaseIndex(htmlPtr, zIndex, ppToken, pIndex);
+}
diff --git a/tkhtml1/src/htmlindex.h b/tkhtml1/src/htmlindex.h
new file mode 100644
index 0000000..37a5fee
--- /dev/null
+++ b/tkhtml1/src/htmlindex.h
@@ -0,0 +1,450 @@
+/* This file was automatically generated. Do not edit! */
+typedef struct HtmlWidget HtmlWidget;
+typedef union HtmlElement HtmlElement;
+int HtmlGetIndex(HtmlWidget *htmlPtr,const char *zIndex,HtmlElement **ppToken,int *pIndex);
+#define Html_SELECT 116
+#define Html_TEXTAREA 133
+#define Html_INPUT 77
+#define Html_IMG 76
+#define Html_LI 81
+typedef struct HtmlIndex HtmlIndex;
+struct HtmlIndex {
+ HtmlElement *p; /* The token containing the character */
+ int i; /* Index of the character */
+};
+typedef struct HtmlBlock HtmlBlock;
+void HtmlIndexToBlockIndex(HtmlWidget *htmlPtr,HtmlIndex sIndex,HtmlBlock **ppBlock,int *piIndex);
+int HtmlUnlock(HtmlWidget *htmlPtr);
+Tk_Font HtmlGetFont(HtmlWidget *htmlPtr,int iFont);
+void HtmlLock(HtmlWidget *htmlPtr);
+typedef struct HtmlBaseElement HtmlBaseElement;
+typedef struct HtmlStyle HtmlStyle;
+struct HtmlStyle {
+ unsigned int font : 6; /* Font to use for display */
+ unsigned int color : 4; /* Foreground color */
+ signed int subscript : 4; /* Positive for <sup>, negative for <sub> */
+ unsigned int align : 2; /* Horizontal alignment */
+ unsigned int bgcolor : 4; /* Background color */
+ unsigned int flags : 12; /* the STY_ flags below */
+};
+typedef unsigned char Html_u8;
+typedef short Html_16;
+struct HtmlBaseElement {
+ HtmlElement *pNext; /* Next input token in a list of them all */
+ HtmlElement *pPrev; /* Previous token in a list of them all */
+ HtmlStyle style; /* The rendering style for this token */
+ Html_u8 type; /* The token type. */
+ Html_u8 flags; /* The HTML_ flags below */
+ Html_16 count; /* Various uses, depending on "type" */
+};
+typedef unsigned short Html_u16;
+struct HtmlBlock {
+ HtmlBaseElement base; /* Superclass. Must be first */
+ char *z; /* Space to hold text when n>0 */
+ int top, bottom; /* Extremes of y coordinates */
+ Html_u16 left, right; /* Left and right boundry of this object */
+ Html_u16 n; /* Number of characters in z[] */
+ HtmlBlock *pPrev, *pNext; /* Linked list of all Blocks */
+};
+#define STY_Preformatted 0x001
+#define Html_Space 2
+#define Html_Text 1
+int HtmlTokenNumber(HtmlElement *p);
+#if defined(COVERAGE_TEST)
+extern int HtmlTPArray[2000];
+# define TestPoint(X) {extern int HtmlTPArray[]; HtmlTPArray[X]++;}
+#endif
+#if !(defined(COVERAGE_TEST))
+# define TestPoint(X)
+#endif
+#define Html_Block 4
+typedef struct HtmlScript HtmlScript;
+#define Html_TypeCount 151
+typedef struct HtmlStyleStack HtmlStyleStack;
+typedef struct HtmlLayoutContext HtmlLayoutContext;
+typedef struct HtmlMargin HtmlMargin;
+struct HtmlLayoutContext {
+ HtmlWidget *htmlPtr; /* The html widget undergoing layout */
+ HtmlElement *pStart; /* Start of elements to layout */
+ HtmlElement *pEnd; /* Stop when reaching this element */
+ int headRoom; /* Extra space wanted above this line */
+ int top; /* Absolute top of drawing area */
+ int bottom; /* Bottom of previous line */
+ int left, right; /* Left and right extremes of drawing area */
+ int pageWidth; /* Width of the layout field, including
+ ** the margins */
+ int maxX, maxY; /* Maximum X and Y values of paint */
+ HtmlMargin *leftMargin; /* Stack of left margins */
+ HtmlMargin *rightMargin; /* Stack of right margins */
+};
+#define N_FONT_FAMILY 8
+#define N_FONT_SIZE 7
+#define N_FONT (N_FONT_FAMILY*N_FONT_SIZE)
+#define N_COLOR 16 /* Total number of colors */
+typedef struct GcCache GcCache;
+struct GcCache {
+ GC gc; /* The graphics context */
+ Html_u8 font; /* Font used for this context */
+ Html_u8 color; /* Color used for this context */
+ Html_u8 index; /* Index used for LRU replacement */
+};
+#define N_CACHE_GC 16
+typedef struct HtmlImage HtmlImage;
+struct HtmlWidget {
+ Tk_Window tkwin; /* The main window for this widget */
+ Tk_Window clipwin; /* The clipping window in which all text is
+ ** rendered. */
+ char *zClipwin; /* Name of the clipping window. */
+ Display *display; /* The X11 Server that contains tkwin */
+ Tcl_Interp *interp; /* The interpreter in which the widget lives */
+ char *zCmdName; /* Name of the command */
+ HtmlElement *pFirst; /* First HTML token on a list of them all */
+ HtmlElement *pLast; /* Last HTML token on the list */
+ int nToken; /* Number of HTML tokens on the list.
+ * Html_Block tokens don't count. */
+ HtmlElement *lastSized; /* Last HTML element that has been sized */
+ HtmlElement *nextPlaced; /* Next HTML element that needs to be
+ * positioned on canvas. */
+ HtmlBlock *firstBlock; /* List of all HtmlBlock tokens */
+ HtmlBlock *lastBlock; /* Last HtmlBlock in the list */
+ HtmlElement *firstInput; /* First <INPUT> element */
+ HtmlElement *lastInput; /* Last <INPUT> element */
+ int nInput; /* The number of <INPUT> elements */
+ int nForm; /* The number of <FORM> elements */
+ int varId; /* Used to construct a unique name for a
+ ** global array used by <INPUT> elements */
+
+ /*
+ * Information about the selected region of text
+ */
+ HtmlIndex selBegin; /* Start of the selection */
+ HtmlIndex selEnd; /* End of the selection */
+ HtmlBlock *pSelStartBlock; /* Block in which selection starts */
+ Html_16 selStartIndex; /* Index in pSelStartBlock of first selected
+ * character */
+ Html_16 selEndIndex; /* Index of last selecte char in pSelEndBlock */
+ HtmlBlock *pSelEndBlock; /* Block in which selection ends */
+
+ /*
+ * Information about the insertion cursor
+ */
+ int insOnTime; /* How long the cursor states one (millisec) */
+ int insOffTime; /* How long it is off (milliseconds) */
+ int insStatus; /* Is it visible? */
+ Tcl_TimerToken insTimer; /* Timer used to flash the insertion cursor */
+ HtmlIndex ins; /* The insertion cursor position */
+ HtmlBlock *pInsBlock; /* The HtmlBlock containing the cursor */
+ int insIndex; /* Index in pInsBlock of the cursor */
+
+ /*
+ * The following fields hold state information used by
+ * the tokenizer.
+ */
+ char *zText; /* Complete text of the unparsed HTML */
+ int nText; /* Number of characters in zText */
+ int nAlloc; /* Space allocated for zText */
+ int nComplete; /* How much of zText has actually been
+ * converted into tokens */
+ int iCol; /* The column in which zText[nComplete]
+ * occurs. Used to resolve tabs in input */
+ int iPlaintext; /* If not zero, this is the token type that
+ * caused us to go into plaintext mode. One
+ * of Html_PLAINTEXT, Html_LISTING or
+ * Html_XMP */
+ HtmlScript *pScript; /* <SCRIPT> currently being parsed */
+ char *zHandler[Html_TypeCount]; /* If not NULL, this is a TCL routine that
+ * is used to process tokens of the given
+ * type */
+ /*
+ * These fields hold state information used by the HtmlAddStyle routine.
+ * We have to store this state information here since HtmlAddStyle
+ * operates incrementally. This information must be carried from
+ * one incremental execution to the next.
+ */
+ HtmlStyleStack *styleStack; /* The style stack */
+ int paraAlignment; /* Justification associated with <p> */
+ int rowAlignment; /* Justification associated with <tr> */
+ int anchorFlags; /* Style flags associated with <A>...</A> */
+ int inDt; /* Style flags associated with <DT>...</DT> */
+ int inTr; /* True if within <tr>..</tr> */
+ int inTd; /* True if within <td>..</td> or <th>..</th> */
+ HtmlElement *anchorStart; /* Most recent <a href=...> */
+ HtmlElement *formStart; /* Most recent <form> */
+ HtmlElement *formElemStart; /* Most recent <textarea> or <select> */
+ HtmlElement *innerList; /* The inner most <OL> or <UL> */
+
+ /*
+ * These fields are used to hold the state of the layout engine.
+ * Because the layout is incremental, this state must be held for
+ * the life of the widget.
+ */
+ HtmlLayoutContext layoutContext;
+
+ /*
+ * Information used when displaying the widget:
+ */
+ Tk_3DBorder border; /* Background color */
+ int borderWidth; /* Width of the border. */
+ int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ int inset; /* Total width of highlight and 3-D border */
+ Tk_Font aFont[N_FONT]; /* Information about all screen fonts */
+ char fontValid[(N_FONT+7)/8]; /* If bit N%8 of work N/8 of this field is 0
+ * if aFont[N] needs to be reallocated before
+ * being used. */
+ XColor *apColor[N_COLOR]; /* Information about all colors */
+ int colorUsed; /* bit N is 1 if color N is in use. Only
+ ** applies to colors that aren't predefined */
+ int iDark[N_COLOR]; /* Dark 3D shadow of color K is iDark[K] */
+ int iLight[N_COLOR]; /* Light 3D shadow of color K is iLight[K] */
+ XColor *fgColor; /* Color of normal text. apColor[0] */
+ XColor *newLinkColor; /* Color of unvisitied links. apColor[1] */
+ XColor *oldLinkColor; /* Color of visitied links. apColor[2] */
+ XColor *selectionColor; /* Background color for selections */
+ GcCache aGcCache[N_CACHE_GC]; /* A cache of GCs for general use */
+ int lastGC; /* Index of recently used GC */
+ HtmlImage *imageList; /* A list of all images */
+ int width, height; /* User-requested size of the usable drawing
+ * area, in pixels. Borders and padding
+ * make the actual window a little larger */
+ int realWidth, realHeight; /* The actual physical size of tkwin as
+ * reported in the most recent ConfigureNotify
+ * event. */
+ int padx, pady; /* Separation between the edge of the window
+ * and rendered HTML. */
+ int underlineLinks; /* TRUE if we should underline hyperlinks */
+
+ /* Information about the selection
+ */
+ int exportSelection; /* True if the selection is automatically
+ * exported to the clipboard */
+
+ /* Callback commands. The HTML parser will invoke callbacks from time
+ ** to time to find out information it needs to complete formatting of
+ ** the document. The following fields define the callback commands.
+ */
+ char *zIsVisited; /* Command to tell if a hyperlink has already
+ ** been visited */
+ char *zGetImage; /* Command to get an image from a URL */
+ char *zFrameCommand; /* Command for handling <frameset> markup */
+ char *zAppletCommand; /* Command to process applets */
+ char *zResolverCommand; /* Command to resolve URIs */
+ char *zFormCommand; /* When user presses Submit */
+ char *zHyperlinkCommand; /* Invoked when a hyperlink is clicked */
+ char *zFontCommand; /* Invoked to find font names */
+ char *zScriptCommand; /* Invoked for each <SCRIPT> markup */
+
+ /*
+ * Miscellaneous information:
+ */
+ int tableRelief; /* 3d effects on <TABLE> */
+ int ruleRelief; /* 3d effects on <HR> */
+ char *zBase; /* The base URI */
+ char *zBaseHref; /* zBase as modified by <BASE HREF=..> markup */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ char *takeFocus; /* Value of -takefocus option; not used in
+ * the C code, but used by keyboard traversal
+ * scripts. Malloc'ed, but may be NULL. */
+ char *yScrollCmd; /* Command prefix for communicating with
+ * vertical scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ char *xScrollCmd; /* Command prefix for communicating with
+ * horizontal scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ int xOffset, yOffset; /* Current scroll position. These form the
+ * coordinate in the virtual canvas that
+ * corresponds to (0,0) on the physical screen
+ * in window tkwin */
+ int maxX, maxY; /* Maximum extent of any "paint" that appears
+ * on the virtual canvas. Used to compute
+ * scrollbar positions. */
+ int dirtyLeft, dirtyTop; /* Top left corner of region to redraw. These
+ * are physical screen coordinates relative to
+ * clipwin, not tkwin. */
+ int dirtyRight, dirtyBottom; /* Bottom right corner of region to redraw */
+ int locked; /* Number of locks on this structure. Don't
+ ** delete until it reaches zero. */
+ int flags; /* Various flags; see below for
+ * definitions. */
+};
+HtmlElement *HtmlTokenByIndex(HtmlWidget *htmlPtr,int N,int flag);
+typedef struct HtmlTextElement HtmlTextElement;
+typedef int Html_32;
+struct HtmlTextElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_32 y; /* y coordinate where text should be rendered */
+ Html_16 x; /* x coordinate where text should be rendered */
+ Html_16 w; /* width of this token in pixels */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_u8 spaceWidth; /* Width of one space in the current font */
+ char zText[1]; /* Text for this element. Null terminated */
+};
+typedef struct HtmlSpaceElement HtmlSpaceElement;
+struct HtmlSpaceElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_16 w; /* Width of a single space in current font */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+};
+typedef struct HtmlMarkupElement HtmlMarkupElement;
+struct HtmlMarkupElement {
+ HtmlBaseElement base;
+ char **argv;
+};
+typedef struct HtmlCell HtmlCell;
+struct HtmlCell {
+ HtmlMarkupElement markup;
+ Html_16 rowspan; /* Number of rows spanned by this cell */
+ Html_16 colspan; /* Number of columns spanned by this cell */
+ Html_16 x; /* X coordinate of left edge of border */
+ Html_16 w; /* Width of the border */
+ Html_32 y; /* Y coordinate of top of border indentation */
+ Html_32 h; /* Height of the border */
+ HtmlElement *pTable; /* Pointer back to the <table> */
+ HtmlElement *pEnd; /* Element that ends this cell */
+};
+typedef struct HtmlTable HtmlTable;
+#define HTML_MAX_COLUMNS 40
+struct HtmlTable {
+ HtmlMarkupElement markup;
+ Html_u8 borderWidth; /* Width of the border */
+ Html_u8 nCol; /* Number of columns */
+ Html_u16 nRow; /* Number of rows */
+ Html_32 y; /* top edge of table border */
+ Html_32 h; /* height of the table border */
+ Html_16 x; /* left edge of table border */
+ Html_16 w; /* width of the table border */
+ int minW[HTML_MAX_COLUMNS+1]; /* minimum width of each column */
+ int maxW[HTML_MAX_COLUMNS+1]; /* maximum width of each column */
+};
+typedef struct HtmlRef HtmlRef;
+struct HtmlRef {
+ HtmlMarkupElement markup;
+ HtmlElement *pOther; /* Pointer to some other Html element */
+};
+typedef struct HtmlLi HtmlLi;
+struct HtmlLi {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* What type of list is this? */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_16 cnt; /* Value for this element (if inside <OL>) */
+ Html_16 x; /* X coordinate of the bullet */
+ Html_32 y; /* Y coordinate of the bullet */
+};
+typedef struct HtmlListStart HtmlListStart;
+struct HtmlListStart {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* One of the LI_TYPE_ defines above */
+ Html_u8 compact; /* True if the COMPACT flag is present */
+ Html_u16 cnt; /* Next value for <OL> */
+ Html_u16 width; /* How much space to allow for indentation */
+ HtmlElement *pPrev; /* Next higher level list, or NULL */
+};
+typedef struct HtmlImageMarkup HtmlImageMarkup;
+struct HtmlImageMarkup {
+ HtmlMarkupElement markup;
+ Html_u8 align; /* Alignment. See IMAGE_ALIGN_ defines below */
+ Html_u8 textAscent; /* Ascent of text font in force at the <IMG> */
+ Html_u8 textDescent; /* Descent of text font in force at the <IMG> */
+ Html_u8 redrawNeeded; /* Need to redraw this image because the image
+ ** content changed. */
+ Html_16 h; /* Actual height of the image */
+ Html_16 w; /* Actual width of the image */
+ Html_16 ascent; /* How far image extends above "y" */
+ Html_16 descent; /* How far image extends below "y" */
+ Html_16 x; /* X coordinate of left edge of the image */
+ Html_32 y; /* Y coordinate of image baseline */
+ char *zAlt; /* Alternative text */
+ HtmlImage *pImage; /* Corresponding HtmlImage structure */
+ HtmlElement *pNext; /* Next markup using the same HtmlImage structure */
+};
+typedef struct HtmlInput HtmlInput;
+struct HtmlInput {
+ HtmlMarkupElement markup;
+ HtmlElement *pForm; /* The <FORM> to which this belongs */
+ HtmlElement *pNext; /* Next element in a list of all input elements */
+ Tk_Window tkwin; /* The window that implements this control */
+ HtmlWidget *htmlPtr; /* The whole widget. Needed by geometry callbacks */
+ HtmlElement *pEnd; /* End tag for <TEXTAREA>, etc. */
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 padLeft; /* Extra padding on left side of the control */
+ Html_u8 align; /* One of the IMAGE_ALIGN_xxx types */
+ Html_u8 textAscent; /* Ascent for the current font */
+ Html_u8 textDescent; /* descent for the current font */
+ Html_u8 type; /* What type of input is this? */
+ Html_u8 sized; /* True if this input has been sized already */
+ Html_u16 cnt; /* Used to derive widget name. 0 if no widget */
+};
+typedef struct HtmlForm HtmlForm;
+struct HtmlForm {
+ HtmlMarkupElement markup;
+ Html_u16 id; /* Unique number assigned to this form */
+};
+typedef struct HtmlHr HtmlHr;
+struct HtmlHr {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 is3D; /* Is it drawn 3D? */
+};
+typedef struct HtmlAnchor HtmlAnchor;
+struct HtmlAnchor {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Top edge for this element */
+};
+struct HtmlScript {
+ HtmlMarkupElement markup;
+ char *zScript; /* Complete text of this script */
+ int nScript; /* Number of characters of text */
+};
+union HtmlElement {
+ HtmlElement *pNext;
+ HtmlBaseElement base;
+ HtmlTextElement text;
+ HtmlSpaceElement space;
+ HtmlMarkupElement markup;
+ HtmlCell cell;
+ HtmlTable table;
+ HtmlRef ref;
+ HtmlLi li;
+ HtmlListStart list;
+ HtmlImageMarkup image;
+ HtmlInput input;
+ HtmlForm form;
+ HtmlHr hr;
+ HtmlAnchor anchor;
+ HtmlScript script;
+ HtmlBlock block;
+};
+struct HtmlImage {
+ HtmlWidget *htmlPtr; /* The owner of this image */
+ Tk_Image image; /* The Tk image token */
+ Html_32 w; /* Requested width of this image (0 if none) */
+ Html_32 h; /* Requested height of this image (0 if none) */
+ char *zUrl; /* The URL for this image. */
+ char *zWidth, *zHeight; /* Width and height in the <img> markup. */
+ HtmlImage *pNext; /* Next image on the list */
+ HtmlElement *pList; /* List of all <IMG> markups that use this
+ ** same image */
+};
+struct HtmlStyleStack {
+ HtmlStyleStack *pNext; /* Next style on the stack */
+ int type; /* A markup that ends this style. Ex: Html_EndEM */
+ HtmlStyle style; /* The currently active style. */
+};
+struct HtmlMargin {
+ int indent; /* Size of the current margin */
+ int bottom; /* Y value at which this margin expires */
+ int tag; /* Markup that will cancel this margin */
+ HtmlMargin *pNext; /* Previous margin */
+};
diff --git a/tkhtml1/src/htmllayout.c b/tkhtml1/src/htmllayout.c
new file mode 100644
index 0000000..e511e53
--- /dev/null
+++ b/tkhtml1/src/htmllayout.c
@@ -0,0 +1,1170 @@
+/*
+** This file contains the code used to position elements of the
+** HTML file on the screen.
+**
+** Copyright (C) 1997-2000 D. Richard Hipp
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** drh@acm.org
+** http://www.hwaci.com/drh/
+*/
+#include <tk.h>
+#include <stdlib.h>
+#include <string.h>
+#include "htmllayout.h"
+
+
+/*
+** Push a new margin onto the given margin stack.
+**
+** If the "bottom" parameter is non-negative, then this margin will
+** automatically expire for all text that is placed below the y-coordinate
+** given by "bottom". This feature is used for <IMG ALIGN=left>
+** and <IMG ALIGN=right> kinds of markup. It allows text to flow around
+** an image.
+**
+** If "bottom" is negative, then the margin stays in force until
+** it is explicitly canceled by a call to HtmlPopMargin().
+*/
+void HtmlPushMargin(
+ HtmlMargin **ppMargin, /* The margin stack onto which to push */
+ int indent, /* The indentation for the new margin */
+ int bottom, /* The margin expires at this Y coordinate */
+ int tag /* Markup that will cancel this margin */
+){
+ HtmlMargin *pNew = HtmlAlloc( sizeof(HtmlMargin) );
+ pNew->pNext = *ppMargin;
+ if( pNew->pNext ){
+ pNew->indent = indent + pNew->pNext->indent;
+ TestPoint(0);
+ }else{
+ pNew->indent = indent;
+ TestPoint(0);
+ }
+ pNew->bottom = bottom;
+ pNew->tag = tag;
+ *ppMargin = pNew;
+}
+
+/*
+** Pop one margin off of the given margin stack.
+*/
+static void HtmlPopOneMargin(HtmlMargin **ppMargin){
+ if( *ppMargin ){
+ HtmlMargin *pOld = *ppMargin;
+ *ppMargin = pOld->pNext;
+ HtmlFree(pOld);
+ }
+}
+
+/*
+** Pop as many margins as necessary until the margin that was
+** created with "tag" is popped off. Update the layout context
+** to move past obsticles, if necessary.
+**
+** If there are some margins on the stack that contain non-negative
+** bottom fields, that means there are some obsticles that we have
+** not yet cleared. If these margins get popped off the stack,
+** then we have to be careful to advance the pLC->bottom value so
+** that the next line of text will clear the obsticle.
+*/
+static void HtmlPopMargin(
+ HtmlMargin **ppMargin, /* The margin stack to be popped */
+ int tag, /* The tag we want to pop */
+ HtmlLayoutContext *pLC /* Update this layout context */
+){
+ int bottom = -1;
+ int oldTag;
+ HtmlMargin *pM;
+
+ for(pM=*ppMargin; pM && pM->tag!=tag; pM=pM->pNext){}
+ if( pM==0 ){
+ /* No matching margin is found. Do nothing. */
+ return;
+ }
+ while( (pM=*ppMargin)!=0 ){
+ if( pM->bottom>bottom ){
+ bottom = pM->bottom;
+ }
+ oldTag = pM->tag;
+ HtmlPopOneMargin(ppMargin);
+ if( oldTag==tag ) break;
+ }
+ if( pLC && pLC->bottom<bottom ){
+ pLC->headRoom += bottom - pLC->bottom;
+ pLC->bottom = bottom;
+ }
+}
+
+/*
+** Pop all expired margins from the stack.
+**
+** An expired margin is one with a non-negative bottom parameter
+** that is less than the value "y". "y" is the Y-coordinate of
+** the top edge the next line of text to by positioned. What this
+** function does is check to see if we have cleared any obsticles
+** (an obsticle is an <IMG ALIGN=left> or <IMG ALIGN=right>) and
+** expands the margins if we have.
+*/
+static void PopExpiredMargins(HtmlMargin **ppMarginStack, int y){
+ while( *ppMarginStack && (**ppMarginStack).bottom>=0 &&
+ (**ppMarginStack).bottom <= y ){
+ HtmlPopOneMargin(ppMarginStack);
+ }
+}
+
+/*
+** Clear a margin stack to reclaim memory. This routine just blindly
+** pops everything off the stack. Typically used when the screen is
+** cleared or the widget is deleted, etc.
+*/
+void HtmlClearMarginStack(HtmlMargin **ppMargin){
+ while( *ppMargin ){
+ HtmlPopOneMargin(ppMargin);
+ }
+}
+
+/*
+** This routine gathers as many tokens as will fit on one line.
+**
+** The candidate tokens begin with pStart and go thru the end of
+** the list or to pEnd, whichever comes first. The first token
+** at the start of the next line is returned. NULL is returned if
+** we exhaust data.
+**
+** "width" is the maximum allowed width of the line. The actual
+** width is returned in *actualWidth. The actual width does not
+** include any trailing spaces. Sometimes the actual width will
+** be greater than the maximum width. This will happen, for example,
+** for text enclosed in <pre>..</pre> that has lines longer than
+** the width of the page.
+**
+** If the list begins with text, at least one token is returned,
+** even if that one token is longer than the allowed line length.
+** But if the list begins with some kind of break markup (possibly
+** preceded by white space) then the returned list may be empty.
+**
+** The "x" coordinates of all elements are set assuming that the line
+** begins at 0. The calling routine should adjust these coordinates
+** to position the line horizontally. (The FixLine() procedure does
+** this.) Note that the "x" coordinate of <li> elements will be negative.
+** Text within <dt>..</dt> might also have a negative "x" coordinate.
+** But in no case will the x coordinate every be less than "minX".
+*/
+static HtmlElement *GetLine(
+ HtmlLayoutContext *pLC, /* The complete layout context. */
+ HtmlElement *pStart, /* First token on new line */
+ HtmlElement *pEnd, /* End of line. Might be NULL */
+ int width, /* How much space is on this line */
+ int minX, /* The minimum value of the X coordinate */
+ int *actualWidth /* Return space actually required */
+){
+ int x; /* Current X coordinate */
+ int spaceWanted = 0; /* Add this much space before next token */
+ HtmlElement *p; /* For looping over tokens */
+ HtmlElement *lastBreak = 0; /* Last line-break opportunity */
+ int isEmpty = 1; /* True if link contains nothing */
+ int origin; /* Initial value of "x" */
+
+ *actualWidth = 0;
+ p = pStart;
+ while( p && p!=pEnd && (p->base.style.flags & STY_Invisible)!=0 ){
+ p = p->pNext;
+ }
+ if( p && p->base.style.flags & STY_DT ){
+ origin = -HTML_INDENT;
+ }else{
+ origin = 0;
+ }
+ x = origin;
+ if( x<minX ){ x = minX; }
+ if( p && p!=pEnd && p->base.type==Html_LI ){
+ p->li.x = x - HTML_INDENT/3;
+ if( p->li.x - (HTML_INDENT*2)/3<minX ){
+ x += minX - p->li.x + (HTML_INDENT*2)/3;
+ p->li.x = minX + (HTML_INDENT*2)/3;
+ }
+ isEmpty = 0;
+ *actualWidth = 1;
+ p = p->pNext;
+ while( p && (p->base.type==Html_Space || p->base.type==Html_P) ){
+ p = p->pNext;
+ }
+ }
+ for(; p && p!=pEnd; p=p->pNext){
+ if( p->base.style.flags & STY_Invisible ){
+ continue;
+ }
+ switch( p->base.type ){
+ case Html_Text:
+ p->text.x = x + spaceWanted;
+ if( (p->base.style.flags & STY_Preformatted) == 0 ){
+ if( lastBreak && x + spaceWanted + p->text.w > width ){
+ TestPoint(0);
+ return lastBreak;
+ }
+ }
+ TRACE(HtmlTrace_GetLine2, ("Place token %s at x=%d w=%d\n",
+ HtmlTokenName(p), p->text.x, p->text.w));
+ x += p->text.w + spaceWanted;
+ isEmpty = 0;
+ spaceWanted = 0;
+ break;
+
+ case Html_Space:
+ if( p->base.style.flags & STY_Preformatted ){
+ if( p->base.flags & HTML_NewLine ){
+ *actualWidth = x<=0 ? 1 : x;
+ TestPoint(0);
+ return p->pNext;
+ }
+ x += p->space.w * p->base.count;
+ TestPoint(0);
+ }else{
+ int w;
+ if( (p->base.style.flags & STY_NoBreak)==0 ){
+ lastBreak = p->pNext;
+ *actualWidth = x<=0 && !isEmpty ? 1 : x;
+ }
+ w = p->space.w;
+ if( spaceWanted < w && x>origin ){
+ spaceWanted = w;
+ }
+ }
+ break;
+
+ case Html_IMG:
+ switch( p->image.align ){
+ case IMAGE_ALIGN_Left:
+ case IMAGE_ALIGN_Right:
+ *actualWidth = x<=0 && !isEmpty ? 1 : x;
+ return p;
+ default:
+ break;
+ }
+ p->image.x = x + spaceWanted;
+ if( (p->base.style.flags & STY_Preformatted) == 0 ){
+ if( lastBreak && x + spaceWanted + p->image.w > width ){
+ TestPoint(0);
+ return lastBreak;
+ }
+ }
+ TRACE(HtmlTrace_GetLine2, ("Place in-line image %s at x=%d w=%d\n",
+ HtmlTokenName(p), p->image.x, p->image.w));
+ x += p->image.w + spaceWanted;
+ if( (p->base.style.flags & STY_NoBreak)==0 ){
+ lastBreak = p->pNext;
+ *actualWidth = x<=0 && !isEmpty ? 1 : x;
+ }
+ spaceWanted = 0;
+ isEmpty = 0;
+ break;
+
+ case Html_APPLET:
+ case Html_EMBED:
+ case Html_INPUT:
+ case Html_SELECT:
+ case Html_TEXTAREA:
+ p->input.x = x + spaceWanted + p->input.padLeft;
+ if( (p->base.style.flags & STY_Preformatted) == 0 ){
+ if( lastBreak && x + spaceWanted + p->input.w > width ){
+ TestPoint(0);
+ return lastBreak;
+ }
+ }
+ TRACE(HtmlTrace_GetLine2, ("Place token %s at x=%d w=%d\n",
+ HtmlTokenName(p), p->input.x, p->input.w));
+ x = p->input.x + p->input.w;
+ if( (p->base.style.flags & STY_NoBreak)==0 ){
+ lastBreak = p->pNext;
+ *actualWidth = x<=0 && !isEmpty ? 1 : x;
+ }
+ spaceWanted = 0;
+ isEmpty = 0;
+ break;
+
+ case Html_EndTEXTAREA:
+ if( p->ref.pOther ){
+ /* HtmlResetTextarea(pLC->htmlPtr, p->ref.pOther); */
+ }
+ break;
+
+ case Html_DD:
+ if( p->ref.pOther==0 ) break;
+ if( p->ref.pOther->list.compact==0 || x + spaceWanted >= 0 ){
+ *actualWidth = x<=0 && !isEmpty ? 1 : x;
+ return p;
+ }
+ x = 0;
+ spaceWanted = 0;
+ break;
+
+ case Html_WBR:
+ *actualWidth = x<=0 && !isEmpty ? 1 : x;
+ if( x + spaceWanted >= width ){
+ return p->pNext;
+ }else{
+ lastBreak = p->pNext;
+ }
+ break;
+
+ case Html_ADDRESS:
+ case Html_EndADDRESS:
+ case Html_BLOCKQUOTE:
+ case Html_EndBLOCKQUOTE:
+ case Html_BODY:
+ case Html_EndBODY:
+ case Html_BR:
+ case Html_CAPTION:
+ case Html_EndCAPTION:
+ case Html_CENTER:
+ case Html_EndCENTER:
+ case Html_EndDD:
+ case Html_DIV:
+ case Html_EndDIV:
+ case Html_DL:
+ case Html_EndDL:
+ case Html_DT:
+ case Html_H1:
+ case Html_EndH1:
+ case Html_H2:
+ case Html_EndH2:
+ case Html_H3:
+ case Html_EndH3:
+ case Html_H4:
+ case Html_EndH4:
+ case Html_H5:
+ case Html_EndH5:
+ case Html_H6:
+ case Html_EndH6:
+ case Html_EndHTML:
+ case Html_HR:
+ case Html_LI:
+ case Html_LISTING:
+ case Html_EndLISTING:
+ case Html_MENU:
+ case Html_EndMENU:
+ case Html_OL:
+ case Html_EndOL:
+ case Html_P:
+ case Html_EndP:
+ case Html_PRE:
+ case Html_EndPRE:
+ case Html_TABLE:
+ case Html_EndTABLE:
+ case Html_TD:
+ case Html_EndTD:
+ case Html_TH:
+ case Html_EndTH:
+ case Html_TR:
+ case Html_EndTR:
+ case Html_UL:
+ case Html_EndUL:
+ *actualWidth = x<=0 && !isEmpty ? 1 : x;
+ return p;
+
+ default:
+ break;
+ }
+ }
+ *actualWidth = x<=0 && !isEmpty ? 1 : x;
+ return p;
+}
+
+/*
+** Set the y coordinate for every anchor in the given list
+*/
+static void FixAnchors(HtmlElement *p, HtmlElement *pEnd, int y){
+ while( p && p!=pEnd ){
+ if( p->base.type==Html_A ){
+ p->anchor.y = y;
+ }
+ p = p->pNext;
+ }
+}
+
+/*
+** This routine computes the X and Y coordinates for all elements of
+** a line that has been gathered using GetLine() above. It also figures
+** the ascent and descent for in-line images.
+**
+** The value returned is the Y coordinate of the bottom edge of the
+** new line. The X coordinates are computed by adding the left margin
+** plus any extra space needed for centering or right-justification.
+*/
+static int FixLine(
+ HtmlElement *pStart, /* Start of tokens for this line */
+ HtmlElement *pEnd, /* First token past end of this line. Maybe NULL */
+ int bottom, /* Put the top of this line here */
+ int width, /* This is the space available to the line */
+ int actualWidth, /* This is the actual width needed by the line */
+ int leftMargin, /* The current left margin */
+ int *maxX /* Write maximum X coordinate of ink here */
+){
+ int dx; /* Amount by which to increase all X coordinates */
+ int maxAscent; /* Maximum height above baseline */
+ int maxTextAscent; /* Maximum height above baseline for text */
+ int maxDescent; /* Maximum depth below baseline */
+ int ascent, descent; /* Computed ascent and descent for one element */
+ HtmlElement *p; /* For looping */
+ int y; /* Y coordinate of the baseline */
+ int dy2center; /* Distance from baseline to text font center */
+ int max = 0;
+
+ if( actualWidth>0 ){
+ for(p=pStart; p && p!=pEnd && p->base.type!=Html_Text; p=p->pNext){}
+ if( p==pEnd || p==0 ) p = pStart;
+ if( p->base.style.align == ALIGN_Center ){
+ dx = leftMargin + (width - actualWidth)/2;
+ }else if( p->base.style.align == ALIGN_Right ){
+ dx = leftMargin + (width - actualWidth);
+ }else{
+ dx = leftMargin;
+ }
+ if( dx<0 ) dx = 0;
+ maxAscent = maxTextAscent = 0;
+ for(p=pStart; p && p!=pEnd; p=p->pNext){
+ int ss;
+ if( p->base.style.flags & STY_Invisible ){
+ continue;
+ }
+ switch( p->base.type ){
+ case Html_Text:
+ p->text.x += dx;
+ max = p->text.x + p->text.w;
+ ss = p->base.style.subscript;
+ if( ss > 0 ){
+ int ascent = p->text.ascent;
+ int delta = (ascent + p->text.descent)*ss/2;
+ ascent += delta;
+ p->text.y = -delta;
+ if( ascent > maxAscent ){ TestPoint(0); maxAscent = ascent; }
+ if( ascent > maxTextAscent ){ TestPoint(0); maxTextAscent = ascent;}
+ }else if( ss < 0 ){
+ int descent = p->text.descent;
+ int delta = (descent + p->text.ascent)*(-ss)/2;
+ descent += delta;
+ p->text.y = delta;
+ }else{
+ p->text.y = 0;
+ if( p->text.ascent > maxAscent ){
+ maxAscent = p->text.ascent;
+ }
+ if( p->text.ascent > maxTextAscent ){
+ maxTextAscent = p->text.ascent;
+ }
+ }
+ break;
+ case Html_Space:
+ if( p->space.ascent > maxAscent ){
+ maxAscent = p->space.ascent;
+ }
+ break;
+ case Html_LI:
+ p->li.x += dx;
+ if( p->li.x > max ){
+ max = p->li.x;
+ }
+ break;
+ case Html_IMG:
+ p->image.x += dx;
+ max = p->image.x + p->image.w;
+ switch( p->image.align ){
+ case IMAGE_ALIGN_Middle:
+ p->image.descent = p->image.h/2;
+ p->image.ascent = p->image.h - p->image.descent;
+ if( p->image.ascent > maxAscent ){
+ maxAscent = p->image.ascent;
+ }
+ break;
+ case IMAGE_ALIGN_AbsMiddle:
+ dy2center = (p->image.textDescent - p->image.textAscent)/2;
+ p->image.descent = p->image.h/2 + dy2center;
+ p->image.ascent = p->image.h - p->image.descent;
+ if( p->image.ascent > maxAscent ){
+ maxAscent = p->image.ascent;
+ }
+ break;
+ case IMAGE_ALIGN_Bottom:
+ p->image.descent = 0;
+ p->image.ascent = p->image.h;
+ if( p->image.ascent > maxAscent ){
+ maxAscent = p->image.ascent;
+ }
+ break;
+ case IMAGE_ALIGN_AbsBottom:
+ p->image.descent = p->image.textDescent;
+ p->image.ascent = p->image.h - p->image.descent;
+ if( p->image.ascent > maxAscent ){
+ maxAscent = p->image.ascent;
+ }
+ break;
+ default:
+ TestPoint(0);
+ break;
+ }
+ break;
+ case Html_TEXTAREA:
+ case Html_INPUT:
+ case Html_SELECT:
+ case Html_EMBED:
+ case Html_APPLET:
+ p->input.x += dx;
+ max = p->input.x + p->input.w;
+ dy2center = (p->input.textDescent - p->input.textAscent)/2;
+ p->input.y = dy2center - p->input.h/2;
+ ascent = -p->input.y;
+ if( ascent > maxAscent ){
+ maxAscent = ascent;
+ }
+ break;
+ default:
+ /* Shouldn't happen */
+ break;
+ }
+ }
+ *maxX = max;
+ y = maxAscent + bottom;
+ maxDescent = 0;
+ for(p=pStart; p && p!=pEnd; p=p->pNext){
+ if( p->base.style.flags & STY_Invisible ){
+ TestPoint(0);
+ continue;
+ }
+ switch( p->base.type ){
+ case Html_Text:
+ p->text.y += y;
+ if( p->text.descent > maxDescent ){
+ maxDescent = p->text.descent;
+ }
+ break;
+ case Html_LI:
+ p->li.y = y;
+ if( p->li.descent > maxDescent ){
+ maxDescent = p->li.descent;
+ }
+ break;
+ case Html_IMG:
+ p->image.y = y;
+ switch( p->image.align ){
+ case IMAGE_ALIGN_Top:
+ p->image.ascent = maxAscent;
+ p->image.descent = p->image.h - maxAscent;
+ TestPoint(0);
+ break;
+ case IMAGE_ALIGN_TextTop:
+ p->image.ascent = maxTextAscent;
+ p->image.descent = p->image.h - maxTextAscent;
+ TestPoint(0);
+ break;
+ default:
+ TestPoint(0);
+ break;
+ }
+ if( p->image.descent > maxDescent ){
+ maxDescent = p->image.descent;
+ }
+ break;
+ case Html_INPUT:
+ case Html_SELECT:
+ case Html_TEXTAREA:
+ case Html_APPLET:
+ case Html_EMBED:
+ descent = p->input.y + p->input.h;
+ p->input.y += y;
+ if( descent > maxDescent ){
+ maxDescent = descent;
+ }
+ break;
+ default:
+ /* Shouldn't happen */
+ break;
+ }
+ }
+ TRACE(HtmlTrace_FixLine,
+ ("Setting baseline to %d. bottom=%d ascent=%d descent=%d dx=%d\n",
+ y, bottom, maxAscent, maxDescent, dx));
+ }else{
+ maxDescent = 0;
+ y = bottom;
+ }
+ return y + maxDescent;
+}
+
+/*
+** Increase the headroom to create a paragraph break at the current token
+*/
+static void Paragraph(
+ HtmlLayoutContext *pLC,
+ HtmlElement *p
+){
+ int headroom;
+
+ if( p==0 ){ TestPoint(0); return; }
+ if( p->base.type==Html_Text ){
+ headroom = p->text.ascent + p->text.descent;
+ TestPoint(0);
+ }else if( p->pNext && p->pNext->base.type==Html_Text ){
+ headroom = p->pNext->text.ascent + p->pNext->text.descent;
+ TestPoint(0);
+ }else{
+ Tk_FontMetrics fontMetrics;
+ Tk_Font font;
+ font = HtmlGetFont(pLC->htmlPtr, p->base.style.font);
+ if( font==0 ) return;
+ Tk_GetFontMetrics(font, &fontMetrics);
+ headroom = fontMetrics.descent + fontMetrics.ascent;
+ TestPoint(0);
+ }
+ if( pLC->headRoom < headroom && pLC->bottom > pLC->top ){
+ pLC->headRoom = headroom;
+ }
+}
+
+/*
+** Compute the current margins for layout. Three values are returned:
+**
+** *pY The top edge of the area in which we can put ink. This
+** takes into account any requested headroom.
+**
+** *pX The left edge of the inkable area. The takes into account
+** any margin requests active at vertical position specified
+** in pLC->bottom.
+**
+** *pW The width of the inkable area. This takes into account
+** an margin requests that are active at the vertical position
+** pLC->bottom.
+**
+*/
+void HtmlComputeMargins(
+ HtmlLayoutContext *pLC, /* The current layout context */
+ int *pX, /* Put the left edge here */
+ int *pY, /* Put the top edge here */
+ int *pW /* Put the width here */
+){
+ int x, y, w;
+
+ y = pLC->bottom + pLC->headRoom;
+ PopExpiredMargins(&pLC->leftMargin, pLC->bottom);
+ PopExpiredMargins(&pLC->rightMargin, pLC->bottom);
+ w = pLC->pageWidth - pLC->right;
+ if( pLC->leftMargin ){
+ x = pLC->leftMargin->indent + pLC->left;
+ TestPoint(0);
+ }else{
+ x = pLC->left;
+ TestPoint(0);
+ }
+ w -= x;
+ if( pLC->rightMargin ){
+ w -= pLC->rightMargin->indent;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ *pX = x;
+ *pY = y;
+ *pW = w;
+}
+
+
+/*
+** Clear a wrap-around obstacle. The second option determines the
+** precise behavior.
+**
+** CLEAR_Left Clear all obstacles on the left.
+**
+** CLEAR_Right Clear all obstacles on the right.
+**
+** CLEAR_Both Clear all obstacles on both sides.
+**
+** CLEAR_First Clear only the first obsticle on either side.
+*/
+#define CLEAR_Left 0
+#define CLEAR_Right 1
+#define CLEAR_Both 2
+#define CLEAR_First 3
+static void ClearObstacle(HtmlLayoutContext *pLC, int mode){
+ int newBottom = pLC->bottom;
+
+ PopExpiredMargins(&pLC->leftMargin, pLC->bottom);
+ PopExpiredMargins(&pLC->rightMargin, pLC->bottom);
+ switch( mode ){
+ case CLEAR_Both:
+ ClearObstacle(pLC,CLEAR_Left);
+ ClearObstacle(pLC,CLEAR_Right);
+ TestPoint(0);
+ break;
+
+ case CLEAR_Left:
+ while( pLC->leftMargin && pLC->leftMargin->bottom>=0 ){
+ newBottom = pLC->leftMargin->bottom;
+ HtmlPopOneMargin(&pLC->leftMargin);
+ TestPoint(0);
+ }
+ if( newBottom > pLC->bottom + pLC->headRoom ){
+ pLC->headRoom = 0;
+ TestPoint(0);
+ }else{
+ pLC->headRoom = newBottom - pLC->bottom;
+ TestPoint(0);
+ }
+ pLC->bottom = newBottom;
+ PopExpiredMargins(&pLC->rightMargin, pLC->bottom);
+ break;
+
+ case CLEAR_Right:
+ while( pLC->rightMargin && pLC->rightMargin->bottom>=0 ){
+ newBottom = pLC->rightMargin->bottom;
+ HtmlPopOneMargin(&pLC->rightMargin);
+ TestPoint(0);
+ }
+ if( newBottom > pLC->bottom + pLC->headRoom ){
+ pLC->headRoom = 0;
+ TestPoint(0);
+ }else{
+ pLC->headRoom = newBottom - pLC->bottom;
+ TestPoint(0);
+ }
+ pLC->bottom = newBottom;
+ PopExpiredMargins(&pLC->leftMargin, pLC->bottom);
+ break;
+
+ case CLEAR_First:
+ if( pLC->leftMargin && pLC->leftMargin->bottom>=0 ){
+ if( pLC->rightMargin
+ && pLC->rightMargin->bottom < pLC->leftMargin->bottom
+ ){
+ newBottom = pLC->rightMargin->bottom;
+ HtmlPopOneMargin(&pLC->rightMargin);
+ TestPoint(0);
+ }else{
+ newBottom = pLC->leftMargin->bottom;
+ HtmlPopOneMargin(&pLC->leftMargin);
+ TestPoint(0);
+ }
+ }else if( pLC->rightMargin && pLC->rightMargin->bottom>=0 ){
+ newBottom = pLC->rightMargin->bottom;
+ HtmlPopOneMargin(&pLC->rightMargin);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ if( newBottom > pLC->bottom + pLC->headRoom ){
+ pLC->headRoom = 0;
+ TestPoint(0);
+ }else{
+ pLC->headRoom = newBottom - pLC->bottom;
+ TestPoint(0);
+ }
+ pLC->bottom = newBottom;
+ break;
+ }
+}
+
+/*
+** Break markup is any kind of markup that might force a line-break. This
+** routine handles a single element of break markup and returns a pointer
+** to the first element past that markup. If p doesn't point to break
+** markup, then p is returned. If p is an incomplete table (a <TABLE>
+** that lacks a </TABLE>), then NULL is returned.
+*/
+static HtmlElement *DoBreakMarkup(
+ HtmlLayoutContext *pLC,
+ HtmlElement *p
+){
+ HtmlElement *pNext = p->pNext;
+ char *z;
+ int x, y, w;
+
+ switch( p->base.type ){
+ case Html_A:
+ p->anchor.y = pLC->bottom;
+ TestPoint(0);
+ break;
+
+ case Html_BLOCKQUOTE:
+ HtmlPushMargin(&pLC->leftMargin, HTML_INDENT, -1, Html_EndBLOCKQUOTE);
+ HtmlPushMargin(&pLC->rightMargin, HTML_INDENT, -1, Html_EndBLOCKQUOTE);
+ Paragraph(pLC, p);
+ TestPoint(0);
+ break;
+ case Html_EndBLOCKQUOTE:
+ HtmlPopMargin(&pLC->leftMargin, Html_EndBLOCKQUOTE, pLC);
+ HtmlPopMargin(&pLC->rightMargin, Html_EndBLOCKQUOTE, pLC);
+ Paragraph(pLC, p);
+ TestPoint(0);
+ break;
+
+ case Html_IMG:
+ switch( p->image.align ){
+ case IMAGE_ALIGN_Left:
+ HtmlComputeMargins(pLC, &x, &y, &w);
+ p->image.x = x;
+ p->image.y = y;
+ p->image.ascent = 0;
+ p->image.descent = p->image.h;
+ HtmlPushMargin(&pLC->leftMargin, p->image.w + 2, y + p->image.h, 0);
+ SETMAX( pLC->maxY, y + p->image.h );
+ SETMAX( pLC->maxX, x + p->image.w );
+ break;
+ case IMAGE_ALIGN_Right:
+ HtmlComputeMargins(pLC, &x, &y, &w);
+ p->image.x = x + w - p->image.w;
+ p->image.y = y;
+ p->image.ascent = 0;
+ p->image.descent = p->image.h;
+ HtmlPushMargin(&pLC->rightMargin, p->image.w + 2, y + p->image.h, 0);
+ SETMAX( pLC->maxY, y + p->image.h );
+ SETMAX( pLC->maxX, x + p->image.w );
+ break;
+ default:
+ TestPoint(0);
+ pNext = p;
+ break;
+ }
+ break;
+
+
+ case Html_PRE:
+ /* Skip space tokens thru the next newline. */
+ while( pNext->base.type==Html_Space ){
+ HtmlElement *pThis = pNext;
+ pNext = pNext->pNext;
+ if( pThis->base.flags & HTML_NewLine ){ TestPoint(0); break; }
+ }
+ Paragraph(pLC,p);
+ break;
+
+ case Html_UL:
+ case Html_MENU:
+ case Html_DIR:
+ case Html_OL:
+ if( p->list.compact==0 ){
+ Paragraph(pLC,p);
+ }
+ HtmlPushMargin(&pLC->leftMargin, HTML_INDENT, -1, p->base.type+1);
+ break;
+
+ case Html_EndOL:
+ case Html_EndUL:
+ case Html_EndMENU:
+ case Html_EndDIR:
+ if( p->ref.pOther ){
+ HtmlPopMargin(&pLC->leftMargin, p->base.type, pLC);
+ if( !p->ref.pOther->list.compact ){
+ Paragraph(pLC,p);
+ }
+ }
+ break;
+
+ case Html_DL:
+ Paragraph(pLC,p);
+ HtmlPushMargin(&pLC->leftMargin, HTML_INDENT, -1, Html_EndDL);
+ TestPoint(0);
+ break;
+
+ case Html_EndDL:
+ HtmlPopMargin(&pLC->leftMargin, Html_EndDL, pLC);
+ Paragraph(pLC,p);
+ TestPoint(0);
+ break;
+
+ case Html_HR: {
+ int zl, wd;
+
+ p->hr.is3D = HtmlMarkupArg(p, "noshade", 0)==0;
+ z = HtmlMarkupArg(p, "size", 0);
+ if( z ){
+ p->hr.h = atoi(z);
+ }else{
+ p->hr.h = 0;
+ }
+ if( p->hr.h<1 ){
+ int relief = pLC->htmlPtr->ruleRelief;
+ if( p->hr.is3D
+ && (relief==TK_RELIEF_SUNKEN || relief==TK_RELIEF_RAISED) ){
+ p->hr.h = 3;
+ }else{
+ p->hr.h = 2;
+ }
+ }
+ HtmlComputeMargins(pLC, &x, &y, &w);
+ p->hr.y = y;
+ y += p->hr.h + 1;
+ p->hr.x = x;
+ z = HtmlMarkupArg(p, "width", "100%");
+ zl = strlen(z);
+ if( zl>0 && z[zl-1]=='%' ){
+ wd = (atoi(z)*w)/100;
+ }else{
+ wd = atoi(z);
+ }
+ if( wd>w ) wd = w;
+ p->hr.w = wd;
+ switch( p->base.style.align ){
+ case ALIGN_Center:
+ case ALIGN_None:
+ p->hr.x += (w - wd)/2;
+ TestPoint(0);
+ break;
+ case ALIGN_Right:
+ p->hr.x += (w - wd);
+ TestPoint(0);
+ break;
+ default:
+ TestPoint(0);
+ break;
+ }
+ SETMAX( pLC->maxY, y);
+ SETMAX( pLC->maxX, wd + p->hr.x );
+ pLC->bottom = y;
+ pLC->headRoom = 0;
+ break;
+ }
+
+ case Html_ADDRESS:
+ case Html_EndADDRESS:
+ case Html_CENTER:
+ case Html_EndCENTER:
+ case Html_DIV:
+ case Html_EndDIV:
+ case Html_H1:
+ case Html_EndH1:
+ case Html_H2:
+ case Html_EndH2:
+ case Html_H3:
+ case Html_EndH3:
+ case Html_H4:
+ case Html_EndH4:
+ case Html_H5:
+ case Html_EndH5:
+ case Html_H6:
+ case Html_EndH6:
+ case Html_P:
+ case Html_EndP:
+ case Html_EndPRE:
+ Paragraph(pLC, p);
+ TestPoint(0);
+ break;
+
+ case Html_TABLE:
+ pNext = HtmlTableLayout(pLC, p);
+ TestPoint(0);
+ break;
+
+ case Html_BR:
+ z = HtmlMarkupArg(p, "clear",0);
+ if( z ){
+ if( stricmp(z,"left")==0 ){
+ ClearObstacle(pLC, CLEAR_Left);
+ TestPoint(0);
+ }else if( stricmp(z,"right")==0 ){
+ ClearObstacle(pLC, CLEAR_Right);
+ TestPoint(0);
+ }else{
+ ClearObstacle(pLC, CLEAR_Both);
+ TestPoint(0);
+ }
+ }else{
+ TestPoint(0);
+ }
+ break;
+
+ /* All of the following tags need to be handed to the GetLine() routine */
+ case Html_Text:
+ case Html_Space:
+ case Html_LI:
+ case Html_INPUT:
+ case Html_SELECT:
+ case Html_TEXTAREA:
+ case Html_APPLET:
+ case Html_EMBED:
+ pNext = p;
+ TestPoint(0);
+ break;
+
+ default:
+ TestPoint(0);
+ break;
+ }
+ return pNext;
+}
+
+/*
+** Return TRUE (non-zero) if we are currently wrapping text around
+** one or more images.
+*/
+static int InWrapAround(HtmlLayoutContext *pLC){
+ if( pLC->leftMargin && pLC->leftMargin->bottom >= 0 ){
+ TestPoint(0);
+ return 1;
+ }
+ if( pLC->rightMargin && pLC->rightMargin->bottom >= 0 ){
+ TestPoint(0);
+ return 1;
+ }
+ TestPoint(0);
+ return 0;
+}
+
+/*
+** Move past obsticles until a linewidth of reqWidth is obtained,
+** or until all obsticles are cleared.
+*/
+void HtmlWidenLine(
+ HtmlLayoutContext *pLC, /* The layout context */
+ int reqWidth, /* Requested line width */
+ int *pX, int *pY, int *pW /* The margins. See HtmllComputeMargins() */
+){
+ HtmlComputeMargins(pLC, pX, pY, pW);
+ if( *pW<reqWidth && InWrapAround(pLC) ){
+ ClearObstacle(pLC, CLEAR_First);
+ HtmlComputeMargins(pLC, pX, pY, pW);
+ }
+}
+
+#ifdef TABLE_TRIM_BLANK
+int HtmlLineWasBlank = 0;
+#endif /* TABLE_TRIM_BLANK */
+
+/*
+** Do as much layout as possible on the block of text defined by
+** the HtmlLayoutContext.
+*/
+void HtmlLayoutBlock(HtmlLayoutContext *pLC){
+ HtmlElement *p, *pNext;
+
+ for(p=pLC->pStart; p && p!=pLC->pEnd; p=pNext){
+ int lineWidth;
+ int actualWidth;
+ int y = 0;
+ int leftMargin;
+ int maxX = 0;
+
+ /* Do as much break markup as we can. */
+ while( p && p!=pLC->pEnd ){
+ HtmlLock(pLC->htmlPtr);
+ pNext = DoBreakMarkup(pLC, p);
+ if( HtmlUnlock(pLC->htmlPtr) ) return;
+ if( pNext==p ){ TestPoint(0); break; }
+ if( pNext ){
+ TRACE(HtmlTrace_BreakMarkup,
+ ("Processed token %s as break markup\n", HtmlTokenName(p)));
+ pLC->pStart = p;
+ }
+ p = pNext;
+ TestPoint(0);
+ }
+ if( p==0 || p==pLC->pEnd ){ TestPoint(0); break; }
+
+#ifdef TABLE_TRIM_BLANK
+ HtmlLineWasBlank = 0;
+#endif /* TABLE_TRIM_BLANK */
+
+ /* We might try several times to layout a single line... */
+ while( 1 ){
+
+ /* Compute margins */
+ HtmlComputeMargins(pLC, &leftMargin, &y, &lineWidth);
+
+ /* Layout a single line of text */
+ pNext = GetLine(pLC, p, pLC->pEnd, lineWidth, pLC->left-leftMargin,
+ &actualWidth);
+ TRACE(HtmlTrace_GetLine,
+ ("GetLine page=%d left=%d right=%d available=%d used=%d\n",
+ pLC->pageWidth, pLC->left, pLC->right, lineWidth, actualWidth));
+ FixAnchors(p,pNext,pLC->bottom);
+
+ /* Move down and repeat the layout if we exceeded the available
+ ** line length and it is possible to increase the line length by
+ ** moving past some obsticle.
+ */
+ if( actualWidth > lineWidth && InWrapAround(pLC) ){
+ ClearObstacle(pLC, CLEAR_First);
+ TestPoint(0);
+ continue;
+ }
+
+ /* Lock the line into place and exit the loop */
+ y = FixLine(p, pNext, y, lineWidth, actualWidth, leftMargin, &maxX);
+ TestPoint(0);
+ break;
+ }
+
+#ifdef TABLE_TRIM_BLANK
+ /*
+ * I noticed that a newline following break markup would result
+ * in a blank line being drawn. So if an "empty" line was found
+ * I subtract any whitespace caused by break markup.
+ */
+ if (actualWidth <= 0)
+ {
+ HtmlLineWasBlank = 1;
+ }
+#endif /* TABLE_TRIM_BLANK */
+
+ /* If a line was completed, advance to the next line */
+ if( pNext && actualWidth>0 && y > pLC->bottom ){
+ pLC->bottom = y;
+ pLC->headRoom = 0;
+ pLC->pStart = pNext;
+ }
+ if( y > pLC->maxY ){
+ pLC->maxY = y;
+ }
+ if( maxX > pLC->maxX ){
+ pLC->maxX = maxX;
+ }
+ }
+}
+
+/*
+** Advance the layout as far as possible
+*/
+void HtmlLayout(HtmlWidget *htmlPtr){
+ HtmlLayoutContext *pLC;
+ int btm;
+
+ if( htmlPtr->pFirst==0 ) return;
+ HtmlLock(htmlPtr);
+ HtmlSizer(htmlPtr);
+ if( HtmlUnlock(htmlPtr) ) return;
+ pLC = &htmlPtr->layoutContext;
+ pLC->htmlPtr = htmlPtr;
+ pLC->pageWidth = htmlPtr->realWidth - 2*(htmlPtr->inset + htmlPtr->padx);
+ pLC->left = 0;
+ pLC->right = 0;
+ pLC->pStart = htmlPtr->nextPlaced;
+ if( pLC->pStart==0 ){
+ pLC->pStart = htmlPtr->pFirst;
+ }
+ if( pLC->pStart ){
+ pLC->maxX = htmlPtr->maxX;
+ pLC->maxY = htmlPtr->maxY;
+ btm = pLC->bottom;
+ HtmlLock(htmlPtr);
+ HtmlLayoutBlock(pLC);
+ if( HtmlUnlock(htmlPtr) ) return;
+ htmlPtr->maxX = pLC->maxX;
+ htmlPtr->maxY = pLC->maxY;
+ htmlPtr->nextPlaced = pLC->pStart;
+ htmlPtr->flags |= HSCROLL | VSCROLL;
+ HtmlRedrawText(htmlPtr, btm);
+ }
+}
diff --git a/tkhtml1/src/htmllayout.h b/tkhtml1/src/htmllayout.h
new file mode 100644
index 0000000..0d5805b
--- /dev/null
+++ b/tkhtml1/src/htmllayout.h
@@ -0,0 +1,565 @@
+/* This file was automatically generated. Do not edit! */
+typedef struct HtmlWidget HtmlWidget;
+void HtmlRedrawText(HtmlWidget *htmlPtr,int y);
+#define VSCROLL 0x000008
+#define HSCROLL 0x000004
+void HtmlSizer(HtmlWidget *htmlPtr);
+typedef union HtmlElement HtmlElement;
+typedef struct HtmlBlock HtmlBlock;
+typedef struct HtmlIndex HtmlIndex;
+struct HtmlIndex {
+ HtmlElement *p; /* The token containing the character */
+ int i; /* Index of the character */
+};
+typedef short Html_16;
+typedef struct HtmlScript HtmlScript;
+#define Html_TypeCount 151
+typedef struct HtmlStyleStack HtmlStyleStack;
+typedef struct HtmlLayoutContext HtmlLayoutContext;
+typedef struct HtmlMargin HtmlMargin;
+struct HtmlLayoutContext {
+ HtmlWidget *htmlPtr; /* The html widget undergoing layout */
+ HtmlElement *pStart; /* Start of elements to layout */
+ HtmlElement *pEnd; /* Stop when reaching this element */
+ int headRoom; /* Extra space wanted above this line */
+ int top; /* Absolute top of drawing area */
+ int bottom; /* Bottom of previous line */
+ int left, right; /* Left and right extremes of drawing area */
+ int pageWidth; /* Width of the layout field, including
+ ** the margins */
+ int maxX, maxY; /* Maximum X and Y values of paint */
+ HtmlMargin *leftMargin; /* Stack of left margins */
+ HtmlMargin *rightMargin; /* Stack of right margins */
+};
+#define N_FONT_FAMILY 8
+#define N_FONT_SIZE 7
+#define N_FONT (N_FONT_FAMILY*N_FONT_SIZE)
+#define N_COLOR 16 /* Total number of colors */
+typedef struct GcCache GcCache;
+typedef unsigned char Html_u8;
+struct GcCache {
+ GC gc; /* The graphics context */
+ Html_u8 font; /* Font used for this context */
+ Html_u8 color; /* Color used for this context */
+ Html_u8 index; /* Index used for LRU replacement */
+};
+#define N_CACHE_GC 16
+typedef struct HtmlImage HtmlImage;
+struct HtmlWidget {
+ Tk_Window tkwin; /* The main window for this widget */
+ Tk_Window clipwin; /* The clipping window in which all text is
+ ** rendered. */
+ char *zClipwin; /* Name of the clipping window. */
+ Display *display; /* The X11 Server that contains tkwin */
+ Tcl_Interp *interp; /* The interpreter in which the widget lives */
+ char *zCmdName; /* Name of the command */
+ HtmlElement *pFirst; /* First HTML token on a list of them all */
+ HtmlElement *pLast; /* Last HTML token on the list */
+ int nToken; /* Number of HTML tokens on the list.
+ * Html_Block tokens don't count. */
+ HtmlElement *lastSized; /* Last HTML element that has been sized */
+ HtmlElement *nextPlaced; /* Next HTML element that needs to be
+ * positioned on canvas. */
+ HtmlBlock *firstBlock; /* List of all HtmlBlock tokens */
+ HtmlBlock *lastBlock; /* Last HtmlBlock in the list */
+ HtmlElement *firstInput; /* First <INPUT> element */
+ HtmlElement *lastInput; /* Last <INPUT> element */
+ int nInput; /* The number of <INPUT> elements */
+ int nForm; /* The number of <FORM> elements */
+ int varId; /* Used to construct a unique name for a
+ ** global array used by <INPUT> elements */
+
+ /*
+ * Information about the selected region of text
+ */
+ HtmlIndex selBegin; /* Start of the selection */
+ HtmlIndex selEnd; /* End of the selection */
+ HtmlBlock *pSelStartBlock; /* Block in which selection starts */
+ Html_16 selStartIndex; /* Index in pSelStartBlock of first selected
+ * character */
+ Html_16 selEndIndex; /* Index of last selecte char in pSelEndBlock */
+ HtmlBlock *pSelEndBlock; /* Block in which selection ends */
+
+ /*
+ * Information about the insertion cursor
+ */
+ int insOnTime; /* How long the cursor states one (millisec) */
+ int insOffTime; /* How long it is off (milliseconds) */
+ int insStatus; /* Is it visible? */
+ Tcl_TimerToken insTimer; /* Timer used to flash the insertion cursor */
+ HtmlIndex ins; /* The insertion cursor position */
+ HtmlBlock *pInsBlock; /* The HtmlBlock containing the cursor */
+ int insIndex; /* Index in pInsBlock of the cursor */
+
+ /*
+ * The following fields hold state information used by
+ * the tokenizer.
+ */
+ char *zText; /* Complete text of the unparsed HTML */
+ int nText; /* Number of characters in zText */
+ int nAlloc; /* Space allocated for zText */
+ int nComplete; /* How much of zText has actually been
+ * converted into tokens */
+ int iCol; /* The column in which zText[nComplete]
+ * occurs. Used to resolve tabs in input */
+ int iPlaintext; /* If not zero, this is the token type that
+ * caused us to go into plaintext mode. One
+ * of Html_PLAINTEXT, Html_LISTING or
+ * Html_XMP */
+ HtmlScript *pScript; /* <SCRIPT> currently being parsed */
+ char *zHandler[Html_TypeCount]; /* If not NULL, this is a TCL routine that
+ * is used to process tokens of the given
+ * type */
+ /*
+ * These fields hold state information used by the HtmlAddStyle routine.
+ * We have to store this state information here since HtmlAddStyle
+ * operates incrementally. This information must be carried from
+ * one incremental execution to the next.
+ */
+ HtmlStyleStack *styleStack; /* The style stack */
+ int paraAlignment; /* Justification associated with <p> */
+ int rowAlignment; /* Justification associated with <tr> */
+ int anchorFlags; /* Style flags associated with <A>...</A> */
+ int inDt; /* Style flags associated with <DT>...</DT> */
+ int inTr; /* True if within <tr>..</tr> */
+ int inTd; /* True if within <td>..</td> or <th>..</th> */
+ HtmlElement *anchorStart; /* Most recent <a href=...> */
+ HtmlElement *formStart; /* Most recent <form> */
+ HtmlElement *formElemStart; /* Most recent <textarea> or <select> */
+ HtmlElement *innerList; /* The inner most <OL> or <UL> */
+
+ /*
+ * These fields are used to hold the state of the layout engine.
+ * Because the layout is incremental, this state must be held for
+ * the life of the widget.
+ */
+ HtmlLayoutContext layoutContext;
+
+ /*
+ * Information used when displaying the widget:
+ */
+ Tk_3DBorder border; /* Background color */
+ int borderWidth; /* Width of the border. */
+ int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ int inset; /* Total width of highlight and 3-D border */
+ Tk_Font aFont[N_FONT]; /* Information about all screen fonts */
+ char fontValid[(N_FONT+7)/8]; /* If bit N%8 of work N/8 of this field is 0
+ * if aFont[N] needs to be reallocated before
+ * being used. */
+ XColor *apColor[N_COLOR]; /* Information about all colors */
+ int colorUsed; /* bit N is 1 if color N is in use. Only
+ ** applies to colors that aren't predefined */
+ int iDark[N_COLOR]; /* Dark 3D shadow of color K is iDark[K] */
+ int iLight[N_COLOR]; /* Light 3D shadow of color K is iLight[K] */
+ XColor *fgColor; /* Color of normal text. apColor[0] */
+ XColor *newLinkColor; /* Color of unvisitied links. apColor[1] */
+ XColor *oldLinkColor; /* Color of visitied links. apColor[2] */
+ XColor *selectionColor; /* Background color for selections */
+ GcCache aGcCache[N_CACHE_GC]; /* A cache of GCs for general use */
+ int lastGC; /* Index of recently used GC */
+ HtmlImage *imageList; /* A list of all images */
+ int width, height; /* User-requested size of the usable drawing
+ * area, in pixels. Borders and padding
+ * make the actual window a little larger */
+ int realWidth, realHeight; /* The actual physical size of tkwin as
+ * reported in the most recent ConfigureNotify
+ * event. */
+ int padx, pady; /* Separation between the edge of the window
+ * and rendered HTML. */
+ int underlineLinks; /* TRUE if we should underline hyperlinks */
+
+ /* Information about the selection
+ */
+ int exportSelection; /* True if the selection is automatically
+ * exported to the clipboard */
+
+ /* Callback commands. The HTML parser will invoke callbacks from time
+ ** to time to find out information it needs to complete formatting of
+ ** the document. The following fields define the callback commands.
+ */
+ char *zIsVisited; /* Command to tell if a hyperlink has already
+ ** been visited */
+ char *zGetImage; /* Command to get an image from a URL */
+ char *zFrameCommand; /* Command for handling <frameset> markup */
+ char *zAppletCommand; /* Command to process applets */
+ char *zResolverCommand; /* Command to resolve URIs */
+ char *zFormCommand; /* When user presses Submit */
+ char *zHyperlinkCommand; /* Invoked when a hyperlink is clicked */
+ char *zFontCommand; /* Invoked to find font names */
+ char *zScriptCommand; /* Invoked for each <SCRIPT> markup */
+
+ /*
+ * Miscellaneous information:
+ */
+ int tableRelief; /* 3d effects on <TABLE> */
+ int ruleRelief; /* 3d effects on <HR> */
+ char *zBase; /* The base URI */
+ char *zBaseHref; /* zBase as modified by <BASE HREF=..> markup */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ char *takeFocus; /* Value of -takefocus option; not used in
+ * the C code, but used by keyboard traversal
+ * scripts. Malloc'ed, but may be NULL. */
+ char *yScrollCmd; /* Command prefix for communicating with
+ * vertical scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ char *xScrollCmd; /* Command prefix for communicating with
+ * horizontal scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ int xOffset, yOffset; /* Current scroll position. These form the
+ * coordinate in the virtual canvas that
+ * corresponds to (0,0) on the physical screen
+ * in window tkwin */
+ int maxX, maxY; /* Maximum extent of any "paint" that appears
+ * on the virtual canvas. Used to compute
+ * scrollbar positions. */
+ int dirtyLeft, dirtyTop; /* Top left corner of region to redraw. These
+ * are physical screen coordinates relative to
+ * clipwin, not tkwin. */
+ int dirtyRight, dirtyBottom; /* Bottom right corner of region to redraw */
+ int locked; /* Number of locks on this structure. Don't
+ ** delete until it reaches zero. */
+ int flags; /* Various flags; see below for
+ * definitions. */
+};
+void HtmlLayout(HtmlWidget *htmlPtr);
+#define HtmlTrace_GetLine 0x00000100
+#define HtmlTrace_BreakMarkup 0x00001000
+int HtmlUnlock(HtmlWidget *htmlPtr);
+void HtmlLock(HtmlWidget *htmlPtr);
+void HtmlLayoutBlock(HtmlLayoutContext *pLC);
+#if defined(TABLE_TRIM_BLANK)
+extern int HtmlLineWasBlank;
+#endif
+void HtmlWidenLine(HtmlLayoutContext *pLC,int reqWidth,int *pX,int *pY,int *pW);
+#if !defined(HAVE_STRICMP)
+# define stricmp strcasecmp
+#endif
+HtmlElement *HtmlTableLayout(HtmlLayoutContext *pLC,HtmlElement *pTable);
+#define ALIGN_None 0
+char *HtmlMarkupArg(HtmlElement *p,const char *tag,char *zDefault);
+#define Html_EndDIR 40
+#define Html_DIR 39
+#define SETMAX(A,B) if( (A)<(B) ){ (A) = (B); }
+void HtmlComputeMargins(HtmlLayoutContext *pLC,int *pX,int *pY,int *pW);
+Tk_Font HtmlGetFont(HtmlWidget *htmlPtr,int iFont);
+#define HtmlTrace_FixLine 0x00000400
+#define IMAGE_ALIGN_TextTop 3
+#define IMAGE_ALIGN_Top 2
+#define IMAGE_ALIGN_AbsBottom 5
+#define IMAGE_ALIGN_Bottom 0
+#define IMAGE_ALIGN_AbsMiddle 4
+#define IMAGE_ALIGN_Middle 1
+#define ALIGN_Right 2
+#define ALIGN_Center 3
+#define Html_A 5
+#define Html_EndUL 146
+#define Html_UL 145
+#define Html_EndTR 140
+#define Html_TR 139
+#define Html_EndTH 136
+#define Html_TH 135
+#define Html_EndTD 132
+#define Html_TD 131
+#define Html_EndTABLE 130
+#define Html_TABLE 129
+#define Html_EndPRE 110
+#define Html_PRE 109
+#define Html_EndP 105
+#define Html_EndOL 101
+#define Html_OL 100
+#define Html_EndMENU 91
+#define Html_MENU 90
+#define Html_EndLISTING 85
+#define Html_LISTING 84
+#define Html_HR 70
+#define Html_EndHTML 72
+#define Html_EndH6 69
+#define Html_H6 68
+#define Html_EndH5 67
+#define Html_H5 66
+#define Html_EndH4 65
+#define Html_H4 64
+#define Html_EndH3 63
+#define Html_H3 62
+#define Html_EndH2 61
+#define Html_H2 60
+#define Html_EndH1 59
+#define Html_H1 58
+#define Html_DT 45
+#define Html_EndDL 44
+#define Html_DL 43
+#define Html_EndDIV 42
+#define Html_DIV 41
+#define Html_EndDD 36
+#define Html_EndCENTER 28
+#define Html_CENTER 27
+#define Html_EndCAPTION 26
+#define Html_CAPTION 25
+#define Html_BR 24
+#define Html_EndBODY 23
+#define Html_BODY 22
+#define Html_EndBLOCKQUOTE 21
+#define Html_BLOCKQUOTE 20
+#define Html_EndADDRESS 8
+#define Html_ADDRESS 7
+#define Html_WBR 149
+#define Html_DD 35
+#define Html_EndTEXTAREA 134
+#define Html_TEXTAREA 133
+#define Html_SELECT 116
+#define Html_INPUT 77
+#define Html_EMBED 49
+#define Html_APPLET 9
+#define IMAGE_ALIGN_Right 7
+#define IMAGE_ALIGN_Left 6
+#define Html_IMG 76
+#define STY_NoBreak 0x008
+#define HTML_NewLine 0x02 /* type==Html_Space and ends with newline */
+char *HtmlTokenName(HtmlElement *p);
+#define HtmlTrace_GetLine2 0x00000200
+extern int HtmlTraceMask;
+#define DEBUG 1
+#if defined(DEBUG)
+extern int HtmlDepth;
+# define TRACE_INDENT printf("%*s",HtmlDepth-3,"")
+#endif
+#if !(defined(DEBUG))
+# define TRACE_INDENT
+#endif
+#if defined(DEBUG)
+# define TRACE(Flag, Args) \
+ if( (Flag)&HtmlTraceMask ){ \
+ TRACE_INDENT; printf Args; fflush(stdout); \
+ }
+#endif
+#if !(defined(DEBUG))
+# define TRACE(Flag, Args)
+#endif
+#define STY_Preformatted 0x001
+#define Html_Text 1
+#define Html_P 104
+#define Html_Space 2
+#define Html_LI 81
+#define HTML_INDENT 36
+#define STY_DT 0x020
+#define STY_Invisible 0x040
+typedef struct HtmlBaseElement HtmlBaseElement;
+typedef struct HtmlStyle HtmlStyle;
+struct HtmlStyle {
+ unsigned int font : 6; /* Font to use for display */
+ unsigned int color : 4; /* Foreground color */
+ signed int subscript : 4; /* Positive for <sup>, negative for <sub> */
+ unsigned int align : 2; /* Horizontal alignment */
+ unsigned int bgcolor : 4; /* Background color */
+ unsigned int flags : 12; /* the STY_ flags below */
+};
+struct HtmlBaseElement {
+ HtmlElement *pNext; /* Next input token in a list of them all */
+ HtmlElement *pPrev; /* Previous token in a list of them all */
+ HtmlStyle style; /* The rendering style for this token */
+ Html_u8 type; /* The token type. */
+ Html_u8 flags; /* The HTML_ flags below */
+ Html_16 count; /* Various uses, depending on "type" */
+};
+typedef struct HtmlTextElement HtmlTextElement;
+typedef int Html_32;
+struct HtmlTextElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_32 y; /* y coordinate where text should be rendered */
+ Html_16 x; /* x coordinate where text should be rendered */
+ Html_16 w; /* width of this token in pixels */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_u8 spaceWidth; /* Width of one space in the current font */
+ char zText[1]; /* Text for this element. Null terminated */
+};
+typedef struct HtmlSpaceElement HtmlSpaceElement;
+struct HtmlSpaceElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_16 w; /* Width of a single space in current font */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+};
+typedef struct HtmlMarkupElement HtmlMarkupElement;
+struct HtmlMarkupElement {
+ HtmlBaseElement base;
+ char **argv;
+};
+typedef struct HtmlCell HtmlCell;
+struct HtmlCell {
+ HtmlMarkupElement markup;
+ Html_16 rowspan; /* Number of rows spanned by this cell */
+ Html_16 colspan; /* Number of columns spanned by this cell */
+ Html_16 x; /* X coordinate of left edge of border */
+ Html_16 w; /* Width of the border */
+ Html_32 y; /* Y coordinate of top of border indentation */
+ Html_32 h; /* Height of the border */
+ HtmlElement *pTable; /* Pointer back to the <table> */
+ HtmlElement *pEnd; /* Element that ends this cell */
+};
+typedef struct HtmlTable HtmlTable;
+typedef unsigned short Html_u16;
+#define HTML_MAX_COLUMNS 40
+struct HtmlTable {
+ HtmlMarkupElement markup;
+ Html_u8 borderWidth; /* Width of the border */
+ Html_u8 nCol; /* Number of columns */
+ Html_u16 nRow; /* Number of rows */
+ Html_32 y; /* top edge of table border */
+ Html_32 h; /* height of the table border */
+ Html_16 x; /* left edge of table border */
+ Html_16 w; /* width of the table border */
+ int minW[HTML_MAX_COLUMNS+1]; /* minimum width of each column */
+ int maxW[HTML_MAX_COLUMNS+1]; /* maximum width of each column */
+};
+typedef struct HtmlRef HtmlRef;
+struct HtmlRef {
+ HtmlMarkupElement markup;
+ HtmlElement *pOther; /* Pointer to some other Html element */
+};
+typedef struct HtmlLi HtmlLi;
+struct HtmlLi {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* What type of list is this? */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_16 cnt; /* Value for this element (if inside <OL>) */
+ Html_16 x; /* X coordinate of the bullet */
+ Html_32 y; /* Y coordinate of the bullet */
+};
+typedef struct HtmlListStart HtmlListStart;
+struct HtmlListStart {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* One of the LI_TYPE_ defines above */
+ Html_u8 compact; /* True if the COMPACT flag is present */
+ Html_u16 cnt; /* Next value for <OL> */
+ Html_u16 width; /* How much space to allow for indentation */
+ HtmlElement *pPrev; /* Next higher level list, or NULL */
+};
+typedef struct HtmlImageMarkup HtmlImageMarkup;
+struct HtmlImageMarkup {
+ HtmlMarkupElement markup;
+ Html_u8 align; /* Alignment. See IMAGE_ALIGN_ defines below */
+ Html_u8 textAscent; /* Ascent of text font in force at the <IMG> */
+ Html_u8 textDescent; /* Descent of text font in force at the <IMG> */
+ Html_u8 redrawNeeded; /* Need to redraw this image because the image
+ ** content changed. */
+ Html_16 h; /* Actual height of the image */
+ Html_16 w; /* Actual width of the image */
+ Html_16 ascent; /* How far image extends above "y" */
+ Html_16 descent; /* How far image extends below "y" */
+ Html_16 x; /* X coordinate of left edge of the image */
+ Html_32 y; /* Y coordinate of image baseline */
+ char *zAlt; /* Alternative text */
+ HtmlImage *pImage; /* Corresponding HtmlImage structure */
+ HtmlElement *pNext; /* Next markup using the same HtmlImage structure */
+};
+typedef struct HtmlInput HtmlInput;
+struct HtmlInput {
+ HtmlMarkupElement markup;
+ HtmlElement *pForm; /* The <FORM> to which this belongs */
+ HtmlElement *pNext; /* Next element in a list of all input elements */
+ Tk_Window tkwin; /* The window that implements this control */
+ HtmlWidget *htmlPtr; /* The whole widget. Needed by geometry callbacks */
+ HtmlElement *pEnd; /* End tag for <TEXTAREA>, etc. */
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 padLeft; /* Extra padding on left side of the control */
+ Html_u8 align; /* One of the IMAGE_ALIGN_xxx types */
+ Html_u8 textAscent; /* Ascent for the current font */
+ Html_u8 textDescent; /* descent for the current font */
+ Html_u8 type; /* What type of input is this? */
+ Html_u8 sized; /* True if this input has been sized already */
+ Html_u16 cnt; /* Used to derive widget name. 0 if no widget */
+};
+typedef struct HtmlForm HtmlForm;
+struct HtmlForm {
+ HtmlMarkupElement markup;
+ Html_u16 id; /* Unique number assigned to this form */
+};
+typedef struct HtmlHr HtmlHr;
+struct HtmlHr {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 is3D; /* Is it drawn 3D? */
+};
+typedef struct HtmlAnchor HtmlAnchor;
+struct HtmlAnchor {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Top edge for this element */
+};
+struct HtmlScript {
+ HtmlMarkupElement markup;
+ char *zScript; /* Complete text of this script */
+ int nScript; /* Number of characters of text */
+};
+struct HtmlBlock {
+ HtmlBaseElement base; /* Superclass. Must be first */
+ char *z; /* Space to hold text when n>0 */
+ int top, bottom; /* Extremes of y coordinates */
+ Html_u16 left, right; /* Left and right boundry of this object */
+ Html_u16 n; /* Number of characters in z[] */
+ HtmlBlock *pPrev, *pNext; /* Linked list of all Blocks */
+};
+union HtmlElement {
+ HtmlElement *pNext;
+ HtmlBaseElement base;
+ HtmlTextElement text;
+ HtmlSpaceElement space;
+ HtmlMarkupElement markup;
+ HtmlCell cell;
+ HtmlTable table;
+ HtmlRef ref;
+ HtmlLi li;
+ HtmlListStart list;
+ HtmlImageMarkup image;
+ HtmlInput input;
+ HtmlForm form;
+ HtmlHr hr;
+ HtmlAnchor anchor;
+ HtmlScript script;
+ HtmlBlock block;
+};
+void HtmlClearMarginStack(HtmlMargin **ppMargin);
+#define HtmlFree(A) Tcl_Free((char*)(A))
+#if defined(COVERAGE_TEST)
+extern int HtmlTPArray[2000];
+# define TestPoint(X) {extern int HtmlTPArray[]; HtmlTPArray[X]++;}
+#endif
+#if !(defined(COVERAGE_TEST))
+# define TestPoint(X)
+#endif
+/*#define HtmlAlloc(A) ((void*)Tcl_Alloc(A))*/
+void* HtmlAlloc(size_t);
+struct HtmlMargin {
+ int indent; /* Size of the current margin */
+ int bottom; /* Y value at which this margin expires */
+ int tag; /* Markup that will cancel this margin */
+ HtmlMargin *pNext; /* Previous margin */
+};
+void HtmlPushMargin(HtmlMargin **ppMargin,int indent,int bottom,int tag);
+struct HtmlImage {
+ HtmlWidget *htmlPtr; /* The owner of this image */
+ Tk_Image image; /* The Tk image token */
+ Html_32 w; /* Requested width of this image (0 if none) */
+ Html_32 h; /* Requested height of this image (0 if none) */
+ char *zUrl; /* The URL for this image. */
+ char *zWidth, *zHeight; /* Width and height in the <img> markup. */
+ HtmlImage *pNext; /* Next image on the list */
+ HtmlElement *pList; /* List of all <IMG> markups that use this
+ ** same image */
+};
+struct HtmlStyleStack {
+ HtmlStyleStack *pNext; /* Next style on the stack */
+ int type; /* A markup that ends this style. Ex: Html_EndEM */
+ HtmlStyle style; /* The currently active style. */
+};
diff --git a/tkhtml1/src/htmlparse.c b/tkhtml1/src/htmlparse.c
new file mode 100644
index 0000000..4511005
--- /dev/null
+++ b/tkhtml1/src/htmlparse.c
@@ -0,0 +1,1181 @@
+/*
+** A tokenizer that converts raw HTML into a linked list of HTML elements.
+**
+** Copyright (C) 1997-2000 D. Richard Hipp
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** drh@acm.org
+** http://www.hwaci.com/drh/
+*/
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <tk.h>
+#include "htmlparse.h"
+
+/****************** Begin Escape Sequence Translator *************/
+/*
+** The next section of code implements routines used to translate
+** the '&' escape sequences of SGML to individual characters.
+** Examples:
+**
+** &amp; &
+** &lt; <
+** &gt; >
+** &nbsp; nonbreakable space
+*/
+
+/* Each escape sequence is recorded as an instance of the following
+** structure
+*/
+struct sgEsc {
+ char *zName; /* The name of this escape sequence. ex: "amp" */
+ char value[8]; /* The value for this sequence. ex: "&" */
+ struct sgEsc *pNext; /* Next sequence with the same hash on zName */
+};
+
+/* The following is a table of all escape sequences. Add new sequences
+** by adding entries to this table.
+*/
+static struct sgEsc esc_sequences[] = {
+ { "quot", "\"", 0 },
+ { "amp", "&", 0 },
+ { "lt", "<", 0 },
+ { "gt", ">", 0 },
+ { "nbsp", " ", 0 },
+ { "iexcl", "\241", 0 },
+ { "cent", "\242", 0 },
+ { "pound", "\243", 0 },
+ { "curren", "\244", 0 },
+ { "yen", "\245", 0 },
+ { "brvbar", "\246", 0 },
+ { "sect", "\247", 0 },
+ { "uml", "\250", 0 },
+ { "copy", "\251", 0 },
+ { "ordf", "\252", 0 },
+ { "laquo", "\253", 0 },
+ { "not", "\254", 0 },
+ { "shy", "\255", 0 },
+ { "reg", "\256", 0 },
+ { "macr", "\257", 0 },
+ { "deg", "\260", 0 },
+ { "plusmn", "\261", 0 },
+ { "sup2", "\262", 0 },
+ { "sup3", "\263", 0 },
+ { "acute", "\264", 0 },
+ { "micro", "\265", 0 },
+ { "para", "\266", 0 },
+ { "middot", "\267", 0 },
+ { "cedil", "\270", 0 },
+ { "sup1", "\271", 0 },
+ { "ordm", "\272", 0 },
+ { "raquo", "\273", 0 },
+ { "frac14", "\274", 0 },
+ { "frac12", "\275", 0 },
+ { "frac34", "\276", 0 },
+ { "iquest", "\277", 0 },
+ { "Agrave", "\300", 0 },
+ { "Aacute", "\301", 0 },
+ { "Acirc", "\302", 0 },
+ { "Atilde", "\303", 0 },
+ { "Auml", "\304", 0 },
+ { "Aring", "\305", 0 },
+ { "AElig", "\306", 0 },
+ { "Ccedil", "\307", 0 },
+ { "Egrave", "\310", 0 },
+ { "Eacute", "\311", 0 },
+ { "Ecirc", "\312", 0 },
+ { "Euml", "\313", 0 },
+ { "Igrave", "\314", 0 },
+ { "Iacute", "\315", 0 },
+ { "Icirc", "\316", 0 },
+ { "Iuml", "\317", 0 },
+ { "ETH", "\320", 0 },
+ { "Ntilde", "\321", 0 },
+ { "Ograve", "\322", 0 },
+ { "Oacute", "\323", 0 },
+ { "Ocirc", "\324", 0 },
+ { "Otilde", "\325", 0 },
+ { "Ouml", "\326", 0 },
+ { "times", "\327", 0 },
+ { "Oslash", "\330", 0 },
+ { "Ugrave", "\331", 0 },
+ { "Uacute", "\332", 0 },
+ { "Ucirc", "\333", 0 },
+ { "Uuml", "\334", 0 },
+ { "Yacute", "\335", 0 },
+ { "THORN", "\336", 0 },
+ { "szlig", "\337", 0 },
+ { "agrave", "\340", 0 },
+ { "aacute", "\341", 0 },
+ { "acirc", "\342", 0 },
+ { "atilde", "\343", 0 },
+ { "auml", "\344", 0 },
+ { "aring", "\345", 0 },
+ { "aelig", "\346", 0 },
+ { "ccedil", "\347", 0 },
+ { "egrave", "\350", 0 },
+ { "eacute", "\351", 0 },
+ { "ecirc", "\352", 0 },
+ { "euml", "\353", 0 },
+ { "igrave", "\354", 0 },
+ { "iacute", "\355", 0 },
+ { "icirc", "\356", 0 },
+ { "iuml", "\357", 0 },
+ { "eth", "\360", 0 },
+ { "ntilde", "\361", 0 },
+ { "ograve", "\362", 0 },
+ { "oacute", "\363", 0 },
+ { "ocirc", "\364", 0 },
+ { "otilde", "\365", 0 },
+ { "ouml", "\366", 0 },
+ { "divide", "\367", 0 },
+ { "oslash", "\370", 0 },
+ { "ugrave", "\371", 0 },
+ { "uacute", "\372", 0 },
+ { "ucirc", "\373", 0 },
+ { "uuml", "\374", 0 },
+ { "yacute", "\375", 0 },
+ { "thorn", "\376", 0 },
+ { "yuml", "\377", 0 },
+};
+
+/* The size of the handler hash table. For best results this should
+** be a prime number which is about the same size as the number of
+** escape sequences known to the system. */
+#define ESC_HASH_SIZE (sizeof(esc_sequences)/sizeof(esc_sequences[0])+7)
+
+/* The hash table
+**
+** If the name of an escape sequences hashes to the value H, then
+** apEscHash[H] will point to a linked list of Esc structures, one of
+** which will be the Esc structure for that escape sequence.
+*/
+static struct sgEsc *apEscHash[ESC_HASH_SIZE];
+
+/* Hash a escape sequence name. The value returned is an integer
+** between 0 and ESC_HASH_SIZE-1, inclusive.
+*/
+static int EscHash(const char *zName){
+ int h = 0; /* The hash value to be returned */
+ char c; /* The next character in the name being hashed */
+
+ while( (c=*zName)!=0 ){
+ h = h<<5 ^ h ^ c;
+ zName++;
+ TestPoint(0);
+ }
+ if( h<0 ){
+ h = -h;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ return h % ESC_HASH_SIZE;
+}
+
+#ifdef TEST
+/*
+** Compute the longest and average collision chain length for the
+** escape sequence hash table
+*/
+static void EscHashStats(void){
+ int i;
+ int sum = 0;
+ int max = 0;
+ int cnt;
+ int notempty = 0;
+ struct sgEsc *p;
+
+ for(i=0; i<sizeof(esc_sequences)/sizeof(esc_sequences[0]); i++){
+ cnt = 0;
+ p = apEscHash[i];
+ if( p ) notempty++;
+ while( p ){
+ cnt++;
+ p = p->pNext;
+ }
+ sum += cnt;
+ if( cnt>max ) max = cnt;
+ }
+ printf("Longest chain=%d avg=%g slots=%d empty=%d (%g%%)\n",
+ max,(double)sum/(double)notempty, i, i-notempty,
+ 100.0*(i-notempty)/(double)i);
+}
+#endif
+
+/* Initialize the escape sequence hash table
+*/
+static void EscInit(void){
+ int i; /* For looping thru the list of escape sequences */
+ int h; /* The hash on a sequence */
+
+ for(i=0; i<sizeof(esc_sequences)/sizeof(esc_sequences[i]); i++){
+/* #ifdef TCL_UTF_MAX */
+#if 0
+ {
+ int c = esc_sequences[i].value[0];
+ Tcl_UniCharToUtf(c, esc_sequences[i].value);
+ }
+#endif
+ h = EscHash(esc_sequences[i].zName);
+ esc_sequences[i].pNext = apEscHash[h];
+ apEscHash[h] = &esc_sequences[i];
+ TestPoint(0);
+ }
+#ifdef TEST
+ EscHashStats();
+#endif
+}
+
+/*
+** This table translates the non-standard microsoft characters between
+** 0x80 and 0x9f into plain ASCII so that the characters will be visible
+** on Unix systems. Care is taken to translate the characters
+** into values less than 0x80, to avoid UTF-8 problems.
+*/
+#ifndef __WIN32__
+static char acMsChar[] = {
+ /* 0x80 */ 'C',
+ /* 0x81 */ ' ',
+ /* 0x82 */ ',',
+ /* 0x83 */ 'f',
+ /* 0x84 */ '"',
+ /* 0x85 */ '.',
+ /* 0x86 */ '*',
+ /* 0x87 */ '*',
+ /* 0x88 */ '^',
+ /* 0x89 */ '%',
+ /* 0x8a */ 'S',
+ /* 0x8b */ '<',
+ /* 0x8c */ 'O',
+ /* 0x8d */ ' ',
+ /* 0x8e */ 'Z',
+ /* 0x8f */ ' ',
+ /* 0x90 */ ' ',
+ /* 0x91 */ '\'',
+ /* 0x92 */ '\'',
+ /* 0x93 */ '"',
+ /* 0x94 */ '"',
+ /* 0x95 */ '*',
+ /* 0x96 */ '-',
+ /* 0x97 */ '-',
+ /* 0x98 */ '~',
+ /* 0x99 */ '@',
+ /* 0x9a */ 's',
+ /* 0x9b */ '>',
+ /* 0x9c */ 'o',
+ /* 0x9d */ ' ',
+ /* 0x9e */ 'z',
+ /* 0x9f */ 'Y',
+};
+#endif
+
+/* Translate escape sequences in the string "z". "z" is overwritten
+** with the translated sequence.
+**
+** Unrecognized escape sequences are unaltered.
+**
+** Example:
+**
+** input = "AT&amp;T &gt MCI"
+** output = "AT&T > MCI"
+*/
+LOCAL void HtmlTranslateEscapes(char *z){
+ int from; /* Read characters from this position in z[] */
+ int to; /* Write characters into this position in z[] */
+ int h; /* A hash on the escape sequence */
+ struct sgEsc *p; /* For looping down the escape sequence collision chain */
+ static int isInit = 0; /* True after initialization */
+
+ from = to = 0;
+ if( !isInit ){
+ EscInit();
+ isInit = 1;
+ }
+ while( z[from] ){
+ if( z[from]=='&' ){
+ if( z[from+1]=='#' ){
+ int i = from + 2;
+ int v = 0;
+ while( isdigit(z[i]) ){
+ v = v*10 + z[i] - '0';
+ i++;
+ }
+ if( z[i]==';' ){ i++; }
+
+ /* On Unix systems, translate the non-standard microsoft
+ ** characters in the range of 0x80 to 0x9f into something
+ ** we can see.
+ */
+#ifndef __WIN32__
+ if( v>=0x80 && v<0xa0 ){
+ v = acMsChar[v&0x1f];
+ }
+#endif
+ /* Put the character in the output stream in place of
+ ** the "&#000;". How we do this depends on whether or
+ ** not we are using UTF-8.
+ */
+#ifdef TCL_UTF_MAX
+ {
+ int j, n;
+ char value[8];
+ n = Tcl_UniCharToUtf(v,value);
+ for(j=0; j<n; j++){
+ z[to++] = value[j];
+ }
+ }
+#else
+ z[to++] = v;
+#endif
+ from = i;
+ }else{
+ int i = from+1;
+ int c;
+ while( z[i] && isalnum(z[i]) ){ TestPoint(0); i++; }
+ c = z[i];
+ z[i] = 0;
+ h = EscHash(&z[from+1]);
+ p = apEscHash[h];
+ while( p && strcmp(p->zName,&z[from+1])!=0 ){
+ p = p->pNext;
+ }
+ z[i] = c;
+ if( p ){
+ int j;
+ for(j=0; p->value[j]; j++){
+ z[to++] = p->value[j];
+ }
+ from = i;
+ if( c==';' ){
+ from++;
+ }
+ }else{
+ z[to++] = z[from++];
+ }
+ }
+
+ /* On UNIX systems, look for the non-standard microsoft characters
+ ** between 0x80 and 0x9f and translate them into printable ASCII
+ ** codes. Separate algorithms are required to do this for plain
+ ** ascii and for utf-8.
+ */
+#ifndef __WIN32__
+#ifdef TCL_UTF_MAX
+ }else if( (z[from]&0x80)!=0 ){
+ Tcl_UniChar c;
+ int n;
+ n = Tcl_UtfToUniChar(&z[from], &c);
+ if( c>=0x80 && c<0xa0 ){
+ z[to++] = acMsChar[c & 0x1f];
+ from += n;
+ }else{
+ while( n-- ) z[to++] = z[from++];
+ }
+#else /* if !defined(TCL_UTF_MAX) */
+ }else if( ((unsigned char)z[from])>=0x80 && ((unsigned char)z[from])<0xa0 ){
+ z[to++] = acMsChar[z[from++]&0x1f];
+#endif /* TCL_UTF_MAX */
+#endif /* __WIN32__ */
+ }else{
+ z[to++] = z[from++];
+ TestPoint(0);
+ }
+ }
+ z[to] = 0;
+}
+/******************* End Escape Sequence Translator ***************/
+
+/******************* Begin HTML tokenizer code *******************/
+/*
+** The following variable becomes TRUE when the markup hash table
+** (stored in HtmlMarkupMap[]) is initialized.
+*/
+static int isInit = 0;
+
+/* The hash table for HTML markup names.
+**
+** If an HTML markup name hashes to H, then apMap[H] will point to
+** a linked list of sgMap structure, one of which will describe the
+** the particular markup (if it exists.)
+*/
+static HtmlTokenMap *apMap[HTML_MARKUP_HASH_SIZE];
+
+/* Hash a markup name
+**
+** HTML markup is case insensitive, so this function will give the
+** same hash regardless of the case of the markup name.
+**
+** The value returned is an integer between 0 and HTML_MARKUP_HASH_SIZE-1,
+** inclusive.
+*/
+static int HtmlHash(const char *zName){
+ int h = 0;
+ char c;
+ while( (c=*zName)!=0 ){
+ if( isupper(c) ){
+ c = tolower(c);
+ }
+ h = h<<5 ^ h ^ c;
+ zName++;
+ }
+ if( h<0 ){
+ h = -h;
+ }
+ return h % HTML_MARKUP_HASH_SIZE;
+}
+
+#ifdef TEST
+/*
+** Compute the longest and average collision chain length for the
+** markup hash table
+*/
+static void HtmlHashStats(void){
+ int i;
+ int sum = 0;
+ int max = 0;
+ int cnt;
+ int notempty = 0;
+ struct sgMap *p;
+
+ for(i=0; i<HTML_MARKUP_COUNT; i++){
+ cnt = 0;
+ p = apMap[i];
+ if( p ) notempty++;
+ while( p ){
+ cnt++;
+ p = p->pCollide;
+ }
+ sum += cnt;
+ if( cnt>max ) max = cnt;
+
+ }
+ printf("longest chain=%d avg=%g slots=%d empty=%d (%g%%)\n",
+ max, (double)sum/(double)notempty, i, i-notempty,
+ 100.0*(i-notempty)/(double)i);
+}
+#endif
+
+/* Initialize the escape sequence hash table
+*/
+static void HtmlHashInit(void){
+ int i; /* For looping thru the list of markup names */
+ int h; /* The hash on a markup name */
+
+ for(i=0; i<HTML_MARKUP_COUNT; i++){
+ h = HtmlHash(HtmlMarkupMap[i].zName);
+ HtmlMarkupMap[i].pCollide = apMap[h];
+ apMap[h] = &HtmlMarkupMap[i];
+ }
+#ifdef TEST
+ HtmlHashStats();
+#endif
+}
+
+/*
+** Append the given HtmlElement to the tokenizers list of elements
+*/
+static void AppendElement(HtmlWidget *p, HtmlElement *pElem){
+ pElem->base.pNext = 0;
+ pElem->base.pPrev = p->pLast;
+ if( p->pFirst==0 ){
+ p->pFirst = pElem;
+ }else{
+ p->pLast->base.pNext = pElem;
+ }
+ p->pLast = pElem;
+ p->nToken++;
+}
+
+/*
+** Compute the new column index following the given character.
+*/
+static int NextColumn(int iCol, char c){
+ switch( c ){
+ case '\n': return 0;
+ case '\t': return (iCol | 7) + 1;
+ default: return iCol+1;
+ }
+ /* NOT REACHED */
+}
+
+/*
+** Convert a string to all lower-case letters.
+*/
+static void ToLower(char *z){
+ while( *z ){
+ if( isupper(*z) ) *z = tolower(*z);
+ z++;
+ }
+}
+
+/* Process as much of the input HTML as possible. Construct new
+** HtmlElement structures and appended them to the list. Return
+** the number of characters actually processed.
+**
+** This routine may invoke a callback procedure which could delete
+** the HTML widget.
+**
+** This routine is not reentrant for the same HTML widget. To
+** prevent reentrancy (during a callback), the p->iCol field is
+** set to a negative number. This is a flag to future invocations
+** not to reentry this routine. The p->iCol field is restored
+** before exiting, of course.
+*/
+static int Tokenize(
+ HtmlWidget *p /* The HTML widget doing the parsing */
+){
+ char *z; /* The input HTML text */
+ int c; /* The next character of input */
+ int n; /* Number of characters processed so far */
+ int iCol; /* Column of input */
+ int i, j; /* Loop counters */
+ int h; /* Result from HtmlHash() */
+ int nByte; /* Space allocated for a single HtmlElement */
+ HtmlElement *pElem; /* A new HTML element */
+ int selfClose; /* True for content free elements. Ex: <br/> */
+ int argc; /* The number of arguments on a markup */
+ HtmlTokenMap *pMap; /* For searching the markup name hash table */
+ char *zBuf; /* For handing out buffer space */
+# define mxARG 200 /* Maximum number of parameters in a single markup */
+ char *argv[mxARG]; /* Pointers to each markup argument. */
+ int arglen[mxARG]; /* Length of each markup argument */
+
+ iCol = p->iCol;
+ n = p->nComplete;
+ z = p->zText;
+ if( iCol<0 ){ TestPoint(0); return n; } /* Prevents recursion */
+ p->iCol = -1;
+ while( (c=z[n])!=0 ){
+ if( p->pScript ){
+ /* We are in the middle of <SCRIPT>...</SCRIPT>. Just look for
+ ** the </SCRIPT> markup. (later:) Treat <STYLE>...</STYLE> the
+ ** same way. */
+ HtmlScript *pScript = p->pScript;
+ char *zEnd;
+ int nEnd;
+ if( pScript->markup.base.type==Html_SCRIPT ){
+ zEnd = "</script>";
+ nEnd = 9;
+ }else{
+ zEnd = "</style>";
+ nEnd = 8;
+ }
+ if( pScript->zScript==0 ){
+ pScript->zScript = &z[n];
+ pScript->nScript = 0;
+ }
+ for(i=n+pScript->nScript; z[i]; i++){
+ if( z[i]=='<' && z[i+1]=='/' && strnicmp(&z[i],zEnd,nEnd)==0 ){
+ pScript->nScript = i - n;
+ p->pScript = 0;
+ n = i+nEnd;
+ break;
+ }
+ }
+ if( p->pScript ){
+ pScript->nScript = i - n;
+ }
+ continue;
+ }else if( isspace(c) ){
+ /* White space */
+ for(i=0; (c=z[n+i])!=0 && isspace(c) && c!='\n' && c!='\r'; i++){}
+ if( c=='\r' && z[n+i+1]=='\n' ){ i++; }
+ pElem = HtmlAlloc( sizeof(HtmlSpaceElement) );
+ if( pElem==0 ){ goto incomplete; }
+ pElem->base.type = Html_Space;
+ if( c=='\n' || c=='\r' ){
+ pElem->base.flags = HTML_NewLine;
+ pElem->base.count = 1;
+ i++;
+ iCol = 0;
+ TestPoint(0);
+ }else{
+ int iColStart = iCol;
+ pElem->base.flags = 0;
+ for(j=0; j<i; j++){
+ iCol = NextColumn(iCol, z[n+j]);
+ TestPoint(0);
+ }
+ pElem->base.count = iCol - iColStart;
+ }
+ AppendElement(p,pElem);
+ n += i;
+ }else if( c!='<' || p->iPlaintext!=0 ||
+ (!isalpha(z[n+1]) && z[n+1]!='/' && z[n+1]!='!' && z[n+1]!='?') ){
+ /* Ordinary text */
+ for(i=1; (c=z[n+i])!=0 && !isspace(c) && c!='<'; i++){}
+ if( c==0 ){ TestPoint(0); goto incomplete; }
+ if( p->iPlaintext!=0 && z[n]=='<' ){
+ switch( p->iPlaintext ){
+ case Html_LISTING:
+ if( i>=10 && strnicmp(&z[n],"</listing>",10)==0 ){
+ p->iPlaintext = 0;
+ goto doMarkup;
+ }
+ break;
+ case Html_XMP:
+ if( i>=6 && strnicmp(&z[n],"</xmp>",6)==0 ){
+ p->iPlaintext = 0;
+ goto doMarkup;
+ }
+ break;
+ case Html_TEXTAREA:
+ if( i>=11 && strnicmp(&z[n],"</textarea>",11)==0 ){
+ p->iPlaintext = 0;
+ goto doMarkup;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ nByte = sizeof(HtmlTextElement) + i;
+ pElem = HtmlAlloc( nByte );
+ if( pElem==0 ){ goto incomplete; }
+ memset(pElem,0,nByte);
+ pElem->base.type = Html_Text;
+ sprintf(pElem->text.zText,"%.*s",i,&z[n]);
+ AppendElement(p,pElem);
+ if( p->iPlaintext==0 || p->iPlaintext==Html_TEXTAREA ){
+ HtmlTranslateEscapes(pElem->text.zText);
+ }
+ pElem->base.count = strlen(pElem->text.zText);
+ n += i;
+ iCol += i;
+ }else if( strncmp(&z[n],"<!--",4)==0 ){
+ /* An HTML comment. Just skip it. */
+ for(i=4; z[n+i]; i++){
+ if( z[n+i]=='-' && strncmp(&z[n+i],"-->",3)==0 ){ break; }
+ }
+ if( z[n+i]==0 ){ TestPoint(0); goto incomplete; }
+ for(j=0; j<i+3; j++){
+ iCol = NextColumn(iCol, z[n+j]);
+ }
+ n += i + 3;
+ }else{
+ /* Markup.
+ **
+ ** First get the name of the markup
+ */
+doMarkup:
+ argc = 1;
+ argv[0] = &z[n+1];
+ for(i=1; (c=z[n+i])!=0 && !isspace(c) && c!='>' && (i<2 || c!='/'); i++){}
+ arglen[0] = i - 1;
+ if( c==0 ){ goto incomplete; }
+
+ /*
+ ** Now parse up the arguments
+ */
+ while( isspace(z[n+i]) ){ i++; }
+ while( (c=z[n+i])!=0 && c!='>' && (c!='/' || z[n+i+1]!='>') ){
+ if( argc>mxARG-3 ){
+ argc = mxARG-3;
+ }
+ argv[argc] = &z[n+i];
+ j = 0;
+ while( (c=z[n+i+j])!=0 && !isspace(c) && c!='>'
+ && c!='=' && (c!='/' || z[n+i+j+1]!='>') ){
+ j++;
+ }
+ arglen[argc] = j;
+ if( c==0 ){ goto incomplete; }
+ i += j;
+ while( isspace(c) ){
+ i++;
+ c = z[n+i];
+ }
+ if( c==0 ){ goto incomplete; }
+ argc++;
+ if( c!='=' ){
+ argv[argc] = "";
+ arglen[argc] = 0;
+ argc++;
+ continue;
+ }
+ i++;
+ c = z[n+i];
+ while( isspace(c) ){
+ i++;
+ c = z[n+i];
+ }
+ if( c==0 ){ goto incomplete; }
+ if( c=='\'' || c=='"' ){
+ int cQuote = c;
+ i++;
+ argv[argc] = &z[n+i];
+ for(j=0; (c=z[n+i+j])!=0 && c!=cQuote; j++){}
+ if( c==0 ){ goto incomplete; }
+ arglen[argc] = j;
+ i += j+1;
+ TestPoint(0);
+ }else{
+ argv[argc] = &z[n+i];
+ for(j=0; (c=z[n+i+j])!=0 && !isspace(c) && c!='>'; j++){}
+ if( c==0 ){ goto incomplete; }
+ arglen[argc] = j;
+ i += j;
+ }
+ argc++;
+ while( isspace(z[n+i]) ){ i++; }
+ }
+ if( c=='/' ){
+ i++;
+ c = z[n+i];
+ selfClose = 1;
+ }else{
+ selfClose = 0;
+ }
+ if( c==0 ){ goto incomplete; }
+ for(j=0; j<i+1; j++){
+ iCol = NextColumn(iCol, z[n+j]);
+ }
+ n += i + 1;
+
+ /* Lookup the markup name in the hash table
+ */
+ if( !isInit ){
+ HtmlHashInit();
+ isInit = 1;
+ }
+ c = argv[0][arglen[0]];
+ argv[0][arglen[0]] = 0;
+ h = HtmlHash(argv[0]);
+ for(pMap = apMap[h]; pMap; pMap=pMap->pCollide){
+ if( stricmp(pMap->zName,argv[0])==0 ){ break; }
+ TestPoint(0);
+ }
+ argv[0][arglen[0]] = c;
+ if( pMap==0 ){ continue; } /* Ignore unknown markup */
+
+makeMarkupEntry:
+ /* Construct a HtmlMarkup entry for this markup.
+ */
+ if( pMap->extra ){
+ nByte = pMap->extra;
+ }else if( argc==1 ){
+ nByte = sizeof(HtmlBaseElement);
+ }else{
+ nByte = sizeof(HtmlMarkupElement);
+ }
+ if( argc>1 ){
+ nByte += sizeof(char*) * argc;
+ for(j=1; j<argc; j++){
+ nByte += arglen[j] + 1;
+ }
+ }
+ pElem = HtmlAlloc( nByte );
+ if( pElem==0 ){ goto incomplete; }
+ memset(pElem,0,nByte);
+ pElem->base.type = pMap->type;
+ pElem->base.count = argc - 1;
+ if( argc>1 ){
+ if( pMap->extra ){
+ pElem->markup.argv = (char**)&((char*)pElem)[pMap->extra];
+ }else{
+ pElem->markup.argv = (char**)&((HtmlMarkupElement*)pElem)[1];
+ }
+ zBuf = (char*)&pElem->markup.argv[argc];
+ for(j=1; j<argc; j++){
+ pElem->markup.argv[j-1] = zBuf;
+ zBuf += arglen[j] + 1;
+ sprintf(pElem->markup.argv[j-1],"%.*s",arglen[j],argv[j]);
+ HtmlTranslateEscapes(pElem->markup.argv[j-1]);
+ if( (j&1)==1 ){
+ ToLower(pElem->markup.argv[j-1]);
+ }
+ }
+ pElem->markup.argv[argc-1] = 0;
+ }
+
+ /* The new markup has now be constructed in pElem. But before
+ ** appending to the list, check to see if there is a special
+ ** handler for this markup type.
+ */
+ if( p->zHandler[pMap->type] ){
+ Tcl_DString str;
+ Tcl_DStringInit(&str);
+ Tcl_DStringAppend(&str, p->zHandler[pMap->type], -1);
+ Tcl_DStringAppendElement(&str, pMap->zName);
+ Tcl_DStringStartSublist(&str);
+ for(j=0; j<argc-1; j++){
+ Tcl_DStringAppendElement(&str, pElem->markup.argv[j]);
+ }
+ Tcl_DStringEndSublist(&str);
+ HtmlFree(pElem);
+ HtmlLock(p);
+ Tcl_GlobalEval(p->interp, Tcl_DStringValue(&str));
+ Tcl_DStringFree(&str);
+ if( HtmlUnlock(p) ){ return 0; }
+
+ /* Tricky, tricky. The callback might have caused the p->zText
+ ** pointer to change, so renew our copy of that pointer. The
+ ** callback might also have cleared or destroyed the widget.
+ ** If so, abort this routine.
+ */
+ z = p->zText;
+ if( z==0 || p->tkwin==0 ){
+ n = 0;
+ iCol = 0;
+ goto incomplete;
+ }
+ continue;
+ }
+
+ /* No special handler for this markup. Just append it to the
+ ** list of all tokens.
+ */
+ AppendElement(p,pElem);
+ switch( pMap->type ){
+ case Html_PLAINTEXT:
+ case Html_LISTING:
+ case Html_XMP:
+ case Html_TEXTAREA:
+ p->iPlaintext = pMap->type;
+ break;
+ case Html_STYLE:
+ case Html_SCRIPT:
+ p->pScript = (HtmlScript*)pElem;
+ break;
+ default:
+ break;
+ }
+
+ /* If this is self-closing markup (ex: <br/> or <img/>) then
+ ** synthesize a closing token.
+ */
+ if( selfClose && argv[0][0]!='/'
+ && strcmp(&pMap[1].zName[1],pMap->zName)==0 ){
+ selfClose = 0;
+ pMap++;
+ argc = 1;
+ goto makeMarkupEntry;
+ }
+ }
+ }
+incomplete:
+ p->iCol = iCol;
+ return n;
+}
+/************************** End HTML Tokenizer Code ***************************/
+
+/*
+** Append text to the tokenizer engine.
+**
+** This routine (actually the Tokenize() subroutine that is called
+** by this routine) may invoke a callback procedure which could delete
+** the HTML widget.
+*/
+void HtmlTokenizerAppend(HtmlWidget *htmlPtr, const char *zText){
+ int len = strlen(zText);
+ if( htmlPtr->nText==0 ){
+ htmlPtr->nAlloc = len + 100;
+ htmlPtr->zText = HtmlAlloc( htmlPtr->nAlloc );
+ TestPoint(0);
+ }else if( htmlPtr->nText + len >= htmlPtr->nAlloc ){
+ htmlPtr->nAlloc += len + 100;
+ htmlPtr->zText = HtmlRealloc( htmlPtr->zText, htmlPtr->nAlloc );
+ TestPoint(0);
+ }
+ if( htmlPtr->zText==0 ){
+ htmlPtr->nText = 0;
+ UNTESTED;
+ return;
+ }
+ strcpy(&htmlPtr->zText[htmlPtr->nText], zText);
+ htmlPtr->nText += len;
+ htmlPtr->nComplete = Tokenize(htmlPtr);
+}
+
+/*
+** This routine takes a text representation of a token, converts
+** it into an HtmlElement structure and inserts it immediately
+** prior to pToken. If pToken==0, then the newly created HtmlElement
+** is appended.
+**
+** This routine does nothing to resize, restyle, relayout or redisplay
+** the HTML. That is the calling routines responsibility.
+**
+** Return 0 if successful. Return non-zero if zType is not a known
+** markup name.
+*/
+int HtmlInsertToken(
+ HtmlWidget *htmlPtr, /* The widget into which the token is inserted */
+ HtmlElement *pToken, /* Insert before this. Append if pToken==0 */
+ char *zType, /* Type of markup. Ex: "/a" or "table" */
+ char *zArgs /* List of arguments */
+){
+ HtmlTokenMap *pMap; /* For searching the markup name hash table */
+ int h; /* The hash on zType */
+ HtmlElement *pElem; /* The new element */
+ int nByte; /* How many bytes to allocate */
+ int i; /* Loop counter */
+
+ if( !isInit ){
+ HtmlHashInit();
+ isInit = 1;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ h = HtmlHash(zType);
+ for(pMap = apMap[h]; pMap; pMap=pMap->pCollide){
+ if( stricmp(pMap->zName,zType)==0 ){ TestPoint(0); break; }
+ TestPoint(0);
+ }
+ if( pMap==0 ){ TestPoint(0); return 1; }
+
+ if( zArgs==0 || *zArgs==0 ){
+ /* Special case of no arguments. This is a lot easier... */
+ nByte = pMap->extra ? pMap->extra : sizeof(HtmlBaseElement);
+ nByte += strlen(zType);
+ pElem = HtmlAlloc( nByte );
+ if( pElem==0 ){ TestPoint(0); return 1; }
+ memset(pElem,0,nByte);
+ pElem->base.type = pMap->type;
+ TestPoint(0);
+ }else{
+ /* The general case. There are arguments that need to be parsed
+ ** up. This is slower, but we gotta do it.
+ */
+ int argc;
+ const char **argv;
+ char *zBuf;
+
+ if( Tcl_SplitList(htmlPtr->interp, zArgs, &argc, (const char***)&argv)!=TCL_OK ){
+ TestPoint(0);
+ return 1;
+ }
+ if( pMap->extra ){
+ nByte = pMap->extra;
+ TestPoint(0);
+ }else{
+ nByte = sizeof(HtmlMarkupElement);
+ TestPoint(0);
+ }
+ nByte += sizeof(char*)*(argc+1) + strlen(zArgs) + argc + 2;
+ pElem = HtmlAlloc( nByte );
+ if( pElem==0 ){
+ HtmlFree(argv);
+ TestPoint(0);
+ return 1;
+ }
+ memset(pElem,0,nByte);
+ pElem->base.type = pMap->type;
+ pElem->base.count = argc;
+ if( pMap->extra ){
+ pElem->markup.argv = (char**)&((char*)pElem)[pMap->extra];
+ TestPoint(0);
+ }else{
+ pElem->markup.argv = (char**)&((HtmlMarkupElement*)pElem)[1];
+ TestPoint(0);
+ }
+ zBuf = (char*)&pElem->markup.argv[argc];
+ for(i=1; i<argc; i++){
+ pElem->markup.argv[i-1] = zBuf;
+ zBuf += strlen(argv[i]) + 1;
+ strcpy(pElem->markup.argv[i-1],argv[i]);
+ TestPoint(0);
+ }
+ pElem->markup.argv[argc-1] = 0;
+ HtmlFree(argv);
+ TestPoint(0);
+ }
+ if( pToken ){
+ pElem->base.pNext = pToken;
+ pElem->base.pPrev = pToken->base.pPrev;
+ if( pToken->base.pPrev ){
+ pToken->base.pPrev->pNext = pElem;
+ TestPoint(0);
+ }else{
+ htmlPtr->pFirst = pElem;
+ TestPoint(0);
+ }
+ pToken->base.pPrev = pElem;
+ htmlPtr->nToken++;
+ }else{
+ AppendElement(htmlPtr,pElem);
+ TestPoint(0);
+ }
+ return 0;
+}
+
+/*
+** Convert a markup name into a type integer
+*/
+int HtmlNameToType(const char *zType){
+ HtmlTokenMap *pMap; /* For searching the markup name hash table */
+ int h; /* The hash on zType */
+
+ if( !isInit ){
+ HtmlHashInit();
+ isInit = 1;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ h = HtmlHash(zType);
+ for(pMap = apMap[h]; pMap; pMap=pMap->pCollide){
+ if( stricmp(pMap->zName,zType)==0 ){ TestPoint(0); break; }
+ TestPoint(0);
+ }
+ return pMap ? pMap->type : Html_Unknown;
+}
+
+/*
+** Convert a type into a symbolic name
+*/
+const char *HtmlTypeToName(int type){
+ if( type>=Html_A && type<=Html_EndXMP ){
+ HtmlTokenMap *pMap = apMap[type - Html_A];
+ TestPoint(0);
+ return pMap->zName;
+ }else{
+ TestPoint(0);
+ return "???";
+ }
+}
+
+/*
+** For debugging purposes, print information about a token
+*/
+char *HtmlTokenName(HtmlElement *p){
+#ifdef DEBUG
+ static char zBuf[200];
+ int j;
+ char *zName;
+
+ if( p==0 ) return "NULL";
+ switch( p->base.type ){
+ case Html_Text:
+ sprintf(zBuf,"\"%.*s\"",p->base.count,p->text.zText);
+ break;
+ case Html_Space:
+ if( p->base.flags & HTML_NewLine ){
+ sprintf(zBuf,"\"\\n\"");
+ }else{
+ sprintf(zBuf,"\" \"");
+ }
+ break;
+ case Html_Block:
+ if( p->block.n>0 ){
+ int n = p->block.n;
+ if( n>150 ) n = 150;
+ sprintf(zBuf,"<Block z=\"%.*s\">", n, p->block.z);
+ }else{
+ sprintf(zBuf,"<Block>");
+ }
+ break;
+ default:
+ if( p->base.type >= HtmlMarkupMap[0].type
+ && p->base.type <= HtmlMarkupMap[HTML_MARKUP_COUNT-1].type ){
+ zName = HtmlMarkupMap[p->base.type - HtmlMarkupMap[0].type].zName;
+ }else{
+ zName = "Unknown";
+ }
+ sprintf(zBuf,"<%s",zName);
+ for(j=1; j<p->base.count; j += 2){
+ sprintf(&zBuf[strlen(zBuf)]," %s=%s",
+ p->markup.argv[j-1],p->markup.argv[j]);
+ }
+ strcat(zBuf,">");
+ break;
+ }
+ return zBuf;
+#else
+ return 0;
+#endif
+}
+
+/*
+** Return all tokens between the two elements as a Tcl list.
+*/
+void HtmlTclizeList(Tcl_Interp *interp, HtmlElement *p, HtmlElement *pEnd){
+ Tcl_DString str;
+ int i;
+ char *zName;
+ char zLine[100];
+
+ Tcl_DStringInit(&str);
+ while( p && p!=pEnd ){
+ switch( p->base.type ){
+ case Html_Block:
+ break;
+ case Html_Text:
+ Tcl_DStringStartSublist(&str);
+ Tcl_DStringAppendElement(&str,"Text");
+ Tcl_DStringAppendElement(&str, p->text.zText);
+ Tcl_DStringEndSublist(&str);
+ break;
+ case Html_Space:
+ sprintf(zLine,"Space %d %d",
+ p->base.count, (p->base.flags & HTML_NewLine)!=0);
+ Tcl_DStringAppendElement(&str,zLine);
+ break;
+ case Html_Unknown:
+ Tcl_DStringAppendElement(&str,"Unknown");
+ break;
+ default:
+ Tcl_DStringStartSublist(&str);
+ Tcl_DStringAppendElement(&str,"Markup");
+ if( p->base.type >= HtmlMarkupMap[0].type
+ && p->base.type <= HtmlMarkupMap[HTML_MARKUP_COUNT-1].type ){
+ zName = HtmlMarkupMap[p->base.type - HtmlMarkupMap[0].type].zName;
+ }else{
+ zName = "Unknown";
+ }
+ Tcl_DStringAppendElement(&str, zName);
+ for(i=0; i<p->base.count; i++){
+ Tcl_DStringAppendElement(&str, p->markup.argv[i]);
+ }
+ Tcl_DStringEndSublist(&str);
+ break;
+ }
+ p = p->pNext;
+ }
+ Tcl_DStringResult(interp, &str);
+}
+
+/*
+** Print a list of tokens
+*/
+#ifdef DEBUG
+void HtmlPrintList(HtmlElement *p, HtmlElement *pEnd){
+ while( p && p!=pEnd ){
+ if( p->base.type==Html_Block ){
+ char *z = p->block.z;
+ int n = p->block.n;
+ if( n==0 || z==0 ){
+ n = 1;
+ z = "";
+ }
+ printf("Block 0x%08x flags=%02x cnt=%d x=%d..%d y=%d..%d z=\"%.*s\"\n",
+ (int)p, p->base.flags, p->base.count, p->block.left, p->block.right,
+ p->block.top, p->block.bottom, n, z);
+ }else{
+ printf("Token 0x%08x font=%2d color=%2d align=%d flags=0x%04x name=%s\n",
+ (int)p, p->base.style.font, p->base.style.color,
+ p->base.style.align, p->base.style.flags, HtmlTokenName(p));
+ }
+ p = p->pNext;
+ }
+}
+#endif
diff --git a/tkhtml1/src/htmlparse.h b/tkhtml1/src/htmlparse.h
new file mode 100644
index 0000000..b5cd34d
--- /dev/null
+++ b/tkhtml1/src/htmlparse.h
@@ -0,0 +1,488 @@
+/* This file was automatically generated. Do not edit! */
+typedef union HtmlElement HtmlElement;
+#define DEBUG 1
+#if defined(DEBUG)
+void HtmlPrintList(HtmlElement *p,HtmlElement *pEnd);
+#endif
+void HtmlTclizeList(Tcl_Interp *interp,HtmlElement *p,HtmlElement *pEnd);
+#define Html_Block 4
+char *HtmlTokenName(HtmlElement *p);
+#define Html_EndXMP 151
+#define Html_A 5
+const char *HtmlTypeToName(int type);
+#define Html_Unknown 3
+int HtmlNameToType(const char *zType);
+typedef struct HtmlWidget HtmlWidget;
+int HtmlInsertToken(HtmlWidget *htmlPtr,HtmlElement *pToken,char *zType,char *zArgs);
+void HtmlTPUntested(const char *zFile,int line);
+#if defined(COVERAGE_TEST)
+# define UNTESTED HtmlTPUntested(__FILE__,__LINE__)
+#endif
+#if !(defined(COVERAGE_TEST))
+# define UNTESTED
+#endif
+#define HtmlRealloc(A,B) ((void*)Tcl_Realloc((A),(B)))
+void HtmlTokenizerAppend(HtmlWidget *htmlPtr,const char *zText);
+#define Html_STYLE 124
+#define Html_PLAINTEXT 108
+int HtmlUnlock(HtmlWidget *htmlPtr);
+void HtmlLock(HtmlWidget *htmlPtr);
+#define HtmlFree(A) Tcl_Free((char*)(A))
+typedef struct HtmlMarkupElement HtmlMarkupElement;
+typedef struct HtmlBaseElement HtmlBaseElement;
+typedef struct HtmlStyle HtmlStyle;
+struct HtmlStyle {
+ unsigned int font : 6; /* Font to use for display */
+ unsigned int color : 4; /* Foreground color */
+ signed int subscript : 4; /* Positive for <sup>, negative for <sub> */
+ unsigned int align : 2; /* Horizontal alignment */
+ unsigned int bgcolor : 4; /* Background color */
+ unsigned int flags : 12; /* the STY_ flags below */
+};
+typedef unsigned char Html_u8;
+typedef short Html_16;
+struct HtmlBaseElement {
+ HtmlElement *pNext; /* Next input token in a list of them all */
+ HtmlElement *pPrev; /* Previous token in a list of them all */
+ HtmlStyle style; /* The rendering style for this token */
+ Html_u8 type; /* The token type. */
+ Html_u8 flags; /* The HTML_ flags below */
+ Html_16 count; /* Various uses, depending on "type" */
+};
+struct HtmlMarkupElement {
+ HtmlBaseElement base;
+ char **argv;
+};
+#if !defined(HAVE_STRICMP)
+# define stricmp strcasecmp
+#endif
+#define Html_Text 1
+typedef struct HtmlTextElement HtmlTextElement;
+typedef int Html_32;
+struct HtmlTextElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_32 y; /* y coordinate where text should be rendered */
+ Html_16 x; /* x coordinate where text should be rendered */
+ Html_16 w; /* width of this token in pixels */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_u8 spaceWidth; /* Width of one space in the current font */
+ char zText[1]; /* Text for this element. Null terminated */
+};
+#define Html_TEXTAREA 133
+#define Html_XMP 150
+#define Html_LISTING 84
+#define HTML_NewLine 0x02 /* type==Html_Space and ends with newline */
+#define Html_Space 2
+typedef struct HtmlSpaceElement HtmlSpaceElement;
+struct HtmlSpaceElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_16 w; /* Width of a single space in current font */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+};
+/*#define HtmlAlloc(A) ((void*)Tcl_Alloc(A))*/
+void* HtmlAlloc(size_t);
+#if !defined(HAVE_STRICMP)
+# define strnicmp strncasecmp
+#endif
+#define Html_SCRIPT 115
+typedef struct HtmlScript HtmlScript;
+struct HtmlScript {
+ HtmlMarkupElement markup;
+ char *zScript; /* Complete text of this script */
+ int nScript; /* Number of characters of text */
+};
+typedef struct HtmlCell HtmlCell;
+struct HtmlCell {
+ HtmlMarkupElement markup;
+ Html_16 rowspan; /* Number of rows spanned by this cell */
+ Html_16 colspan; /* Number of columns spanned by this cell */
+ Html_16 x; /* X coordinate of left edge of border */
+ Html_16 w; /* Width of the border */
+ Html_32 y; /* Y coordinate of top of border indentation */
+ Html_32 h; /* Height of the border */
+ HtmlElement *pTable; /* Pointer back to the <table> */
+ HtmlElement *pEnd; /* Element that ends this cell */
+};
+typedef struct HtmlTable HtmlTable;
+typedef unsigned short Html_u16;
+#define HTML_MAX_COLUMNS 40
+struct HtmlTable {
+ HtmlMarkupElement markup;
+ Html_u8 borderWidth; /* Width of the border */
+ Html_u8 nCol; /* Number of columns */
+ Html_u16 nRow; /* Number of rows */
+ Html_32 y; /* top edge of table border */
+ Html_32 h; /* height of the table border */
+ Html_16 x; /* left edge of table border */
+ Html_16 w; /* width of the table border */
+ int minW[HTML_MAX_COLUMNS+1]; /* minimum width of each column */
+ int maxW[HTML_MAX_COLUMNS+1]; /* maximum width of each column */
+};
+typedef struct HtmlRef HtmlRef;
+struct HtmlRef {
+ HtmlMarkupElement markup;
+ HtmlElement *pOther; /* Pointer to some other Html element */
+};
+typedef struct HtmlLi HtmlLi;
+struct HtmlLi {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* What type of list is this? */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_16 cnt; /* Value for this element (if inside <OL>) */
+ Html_16 x; /* X coordinate of the bullet */
+ Html_32 y; /* Y coordinate of the bullet */
+};
+typedef struct HtmlListStart HtmlListStart;
+struct HtmlListStart {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* One of the LI_TYPE_ defines above */
+ Html_u8 compact; /* True if the COMPACT flag is present */
+ Html_u16 cnt; /* Next value for <OL> */
+ Html_u16 width; /* How much space to allow for indentation */
+ HtmlElement *pPrev; /* Next higher level list, or NULL */
+};
+typedef struct HtmlImageMarkup HtmlImageMarkup;
+typedef struct HtmlImage HtmlImage;
+struct HtmlImageMarkup {
+ HtmlMarkupElement markup;
+ Html_u8 align; /* Alignment. See IMAGE_ALIGN_ defines below */
+ Html_u8 textAscent; /* Ascent of text font in force at the <IMG> */
+ Html_u8 textDescent; /* Descent of text font in force at the <IMG> */
+ Html_u8 redrawNeeded; /* Need to redraw this image because the image
+ ** content changed. */
+ Html_16 h; /* Actual height of the image */
+ Html_16 w; /* Actual width of the image */
+ Html_16 ascent; /* How far image extends above "y" */
+ Html_16 descent; /* How far image extends below "y" */
+ Html_16 x; /* X coordinate of left edge of the image */
+ Html_32 y; /* Y coordinate of image baseline */
+ char *zAlt; /* Alternative text */
+ HtmlImage *pImage; /* Corresponding HtmlImage structure */
+ HtmlElement *pNext; /* Next markup using the same HtmlImage structure */
+};
+typedef struct HtmlInput HtmlInput;
+struct HtmlInput {
+ HtmlMarkupElement markup;
+ HtmlElement *pForm; /* The <FORM> to which this belongs */
+ HtmlElement *pNext; /* Next element in a list of all input elements */
+ Tk_Window tkwin; /* The window that implements this control */
+ HtmlWidget *htmlPtr; /* The whole widget. Needed by geometry callbacks */
+ HtmlElement *pEnd; /* End tag for <TEXTAREA>, etc. */
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 padLeft; /* Extra padding on left side of the control */
+ Html_u8 align; /* One of the IMAGE_ALIGN_xxx types */
+ Html_u8 textAscent; /* Ascent for the current font */
+ Html_u8 textDescent; /* descent for the current font */
+ Html_u8 type; /* What type of input is this? */
+ Html_u8 sized; /* True if this input has been sized already */
+ Html_u16 cnt; /* Used to derive widget name. 0 if no widget */
+};
+typedef struct HtmlForm HtmlForm;
+struct HtmlForm {
+ HtmlMarkupElement markup;
+ Html_u16 id; /* Unique number assigned to this form */
+};
+typedef struct HtmlHr HtmlHr;
+struct HtmlHr {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 is3D; /* Is it drawn 3D? */
+};
+typedef struct HtmlAnchor HtmlAnchor;
+struct HtmlAnchor {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Top edge for this element */
+};
+typedef struct HtmlBlock HtmlBlock;
+struct HtmlBlock {
+ HtmlBaseElement base; /* Superclass. Must be first */
+ char *z; /* Space to hold text when n>0 */
+ int top, bottom; /* Extremes of y coordinates */
+ Html_u16 left, right; /* Left and right boundry of this object */
+ Html_u16 n; /* Number of characters in z[] */
+ HtmlBlock *pPrev, *pNext; /* Linked list of all Blocks */
+};
+union HtmlElement {
+ HtmlElement *pNext;
+ HtmlBaseElement base;
+ HtmlTextElement text;
+ HtmlSpaceElement space;
+ HtmlMarkupElement markup;
+ HtmlCell cell;
+ HtmlTable table;
+ HtmlRef ref;
+ HtmlLi li;
+ HtmlListStart list;
+ HtmlImageMarkup image;
+ HtmlInput input;
+ HtmlForm form;
+ HtmlHr hr;
+ HtmlAnchor anchor;
+ HtmlScript script;
+ HtmlBlock block;
+};
+typedef struct HtmlIndex HtmlIndex;
+struct HtmlIndex {
+ HtmlElement *p; /* The token containing the character */
+ int i; /* Index of the character */
+};
+#define Html_TypeCount 151
+typedef struct HtmlStyleStack HtmlStyleStack;
+typedef struct HtmlLayoutContext HtmlLayoutContext;
+typedef struct HtmlMargin HtmlMargin;
+struct HtmlLayoutContext {
+ HtmlWidget *htmlPtr; /* The html widget undergoing layout */
+ HtmlElement *pStart; /* Start of elements to layout */
+ HtmlElement *pEnd; /* Stop when reaching this element */
+ int headRoom; /* Extra space wanted above this line */
+ int top; /* Absolute top of drawing area */
+ int bottom; /* Bottom of previous line */
+ int left, right; /* Left and right extremes of drawing area */
+ int pageWidth; /* Width of the layout field, including
+ ** the margins */
+ int maxX, maxY; /* Maximum X and Y values of paint */
+ HtmlMargin *leftMargin; /* Stack of left margins */
+ HtmlMargin *rightMargin; /* Stack of right margins */
+};
+#define N_FONT_FAMILY 8
+#define N_FONT_SIZE 7
+#define N_FONT (N_FONT_FAMILY*N_FONT_SIZE)
+#define N_COLOR 16 /* Total number of colors */
+typedef struct GcCache GcCache;
+struct GcCache {
+ GC gc; /* The graphics context */
+ Html_u8 font; /* Font used for this context */
+ Html_u8 color; /* Color used for this context */
+ Html_u8 index; /* Index used for LRU replacement */
+};
+#define N_CACHE_GC 16
+struct HtmlWidget {
+ Tk_Window tkwin; /* The main window for this widget */
+ Tk_Window clipwin; /* The clipping window in which all text is
+ ** rendered. */
+ char *zClipwin; /* Name of the clipping window. */
+ Display *display; /* The X11 Server that contains tkwin */
+ Tcl_Interp *interp; /* The interpreter in which the widget lives */
+ char *zCmdName; /* Name of the command */
+ HtmlElement *pFirst; /* First HTML token on a list of them all */
+ HtmlElement *pLast; /* Last HTML token on the list */
+ int nToken; /* Number of HTML tokens on the list.
+ * Html_Block tokens don't count. */
+ HtmlElement *lastSized; /* Last HTML element that has been sized */
+ HtmlElement *nextPlaced; /* Next HTML element that needs to be
+ * positioned on canvas. */
+ HtmlBlock *firstBlock; /* List of all HtmlBlock tokens */
+ HtmlBlock *lastBlock; /* Last HtmlBlock in the list */
+ HtmlElement *firstInput; /* First <INPUT> element */
+ HtmlElement *lastInput; /* Last <INPUT> element */
+ int nInput; /* The number of <INPUT> elements */
+ int nForm; /* The number of <FORM> elements */
+ int varId; /* Used to construct a unique name for a
+ ** global array used by <INPUT> elements */
+
+ /*
+ * Information about the selected region of text
+ */
+ HtmlIndex selBegin; /* Start of the selection */
+ HtmlIndex selEnd; /* End of the selection */
+ HtmlBlock *pSelStartBlock; /* Block in which selection starts */
+ Html_16 selStartIndex; /* Index in pSelStartBlock of first selected
+ * character */
+ Html_16 selEndIndex; /* Index of last selecte char in pSelEndBlock */
+ HtmlBlock *pSelEndBlock; /* Block in which selection ends */
+
+ /*
+ * Information about the insertion cursor
+ */
+ int insOnTime; /* How long the cursor states one (millisec) */
+ int insOffTime; /* How long it is off (milliseconds) */
+ int insStatus; /* Is it visible? */
+ Tcl_TimerToken insTimer; /* Timer used to flash the insertion cursor */
+ HtmlIndex ins; /* The insertion cursor position */
+ HtmlBlock *pInsBlock; /* The HtmlBlock containing the cursor */
+ int insIndex; /* Index in pInsBlock of the cursor */
+
+ /*
+ * The following fields hold state information used by
+ * the tokenizer.
+ */
+ char *zText; /* Complete text of the unparsed HTML */
+ int nText; /* Number of characters in zText */
+ int nAlloc; /* Space allocated for zText */
+ int nComplete; /* How much of zText has actually been
+ * converted into tokens */
+ int iCol; /* The column in which zText[nComplete]
+ * occurs. Used to resolve tabs in input */
+ int iPlaintext; /* If not zero, this is the token type that
+ * caused us to go into plaintext mode. One
+ * of Html_PLAINTEXT, Html_LISTING or
+ * Html_XMP */
+ HtmlScript *pScript; /* <SCRIPT> currently being parsed */
+ char *zHandler[Html_TypeCount]; /* If not NULL, this is a TCL routine that
+ * is used to process tokens of the given
+ * type */
+ /*
+ * These fields hold state information used by the HtmlAddStyle routine.
+ * We have to store this state information here since HtmlAddStyle
+ * operates incrementally. This information must be carried from
+ * one incremental execution to the next.
+ */
+ HtmlStyleStack *styleStack; /* The style stack */
+ int paraAlignment; /* Justification associated with <p> */
+ int rowAlignment; /* Justification associated with <tr> */
+ int anchorFlags; /* Style flags associated with <A>...</A> */
+ int inDt; /* Style flags associated with <DT>...</DT> */
+ int inTr; /* True if within <tr>..</tr> */
+ int inTd; /* True if within <td>..</td> or <th>..</th> */
+ HtmlElement *anchorStart; /* Most recent <a href=...> */
+ HtmlElement *formStart; /* Most recent <form> */
+ HtmlElement *formElemStart; /* Most recent <textarea> or <select> */
+ HtmlElement *innerList; /* The inner most <OL> or <UL> */
+
+ /*
+ * These fields are used to hold the state of the layout engine.
+ * Because the layout is incremental, this state must be held for
+ * the life of the widget.
+ */
+ HtmlLayoutContext layoutContext;
+
+ /*
+ * Information used when displaying the widget:
+ */
+ Tk_3DBorder border; /* Background color */
+ int borderWidth; /* Width of the border. */
+ int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ int inset; /* Total width of highlight and 3-D border */
+ Tk_Font aFont[N_FONT]; /* Information about all screen fonts */
+ char fontValid[(N_FONT+7)/8]; /* If bit N%8 of work N/8 of this field is 0
+ * if aFont[N] needs to be reallocated before
+ * being used. */
+ XColor *apColor[N_COLOR]; /* Information about all colors */
+ int colorUsed; /* bit N is 1 if color N is in use. Only
+ ** applies to colors that aren't predefined */
+ int iDark[N_COLOR]; /* Dark 3D shadow of color K is iDark[K] */
+ int iLight[N_COLOR]; /* Light 3D shadow of color K is iLight[K] */
+ XColor *fgColor; /* Color of normal text. apColor[0] */
+ XColor *newLinkColor; /* Color of unvisitied links. apColor[1] */
+ XColor *oldLinkColor; /* Color of visitied links. apColor[2] */
+ XColor *selectionColor; /* Background color for selections */
+ GcCache aGcCache[N_CACHE_GC]; /* A cache of GCs for general use */
+ int lastGC; /* Index of recently used GC */
+ HtmlImage *imageList; /* A list of all images */
+ int width, height; /* User-requested size of the usable drawing
+ * area, in pixels. Borders and padding
+ * make the actual window a little larger */
+ int realWidth, realHeight; /* The actual physical size of tkwin as
+ * reported in the most recent ConfigureNotify
+ * event. */
+ int padx, pady; /* Separation between the edge of the window
+ * and rendered HTML. */
+ int underlineLinks; /* TRUE if we should underline hyperlinks */
+
+ /* Information about the selection
+ */
+ int exportSelection; /* True if the selection is automatically
+ * exported to the clipboard */
+
+ /* Callback commands. The HTML parser will invoke callbacks from time
+ ** to time to find out information it needs to complete formatting of
+ ** the document. The following fields define the callback commands.
+ */
+ char *zIsVisited; /* Command to tell if a hyperlink has already
+ ** been visited */
+ char *zGetImage; /* Command to get an image from a URL */
+ char *zFrameCommand; /* Command for handling <frameset> markup */
+ char *zAppletCommand; /* Command to process applets */
+ char *zResolverCommand; /* Command to resolve URIs */
+ char *zFormCommand; /* When user presses Submit */
+ char *zHyperlinkCommand; /* Invoked when a hyperlink is clicked */
+ char *zFontCommand; /* Invoked to find font names */
+ char *zScriptCommand; /* Invoked for each <SCRIPT> markup */
+
+ /*
+ * Miscellaneous information:
+ */
+ int tableRelief; /* 3d effects on <TABLE> */
+ int ruleRelief; /* 3d effects on <HR> */
+ char *zBase; /* The base URI */
+ char *zBaseHref; /* zBase as modified by <BASE HREF=..> markup */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ char *takeFocus; /* Value of -takefocus option; not used in
+ * the C code, but used by keyboard traversal
+ * scripts. Malloc'ed, but may be NULL. */
+ char *yScrollCmd; /* Command prefix for communicating with
+ * vertical scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ char *xScrollCmd; /* Command prefix for communicating with
+ * horizontal scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ int xOffset, yOffset; /* Current scroll position. These form the
+ * coordinate in the virtual canvas that
+ * corresponds to (0,0) on the physical screen
+ * in window tkwin */
+ int maxX, maxY; /* Maximum extent of any "paint" that appears
+ * on the virtual canvas. Used to compute
+ * scrollbar positions. */
+ int dirtyLeft, dirtyTop; /* Top left corner of region to redraw. These
+ * are physical screen coordinates relative to
+ * clipwin, not tkwin. */
+ int dirtyRight, dirtyBottom; /* Bottom right corner of region to redraw */
+ int locked; /* Number of locks on this structure. Don't
+ ** delete until it reaches zero. */
+ int flags; /* Various flags; see below for
+ * definitions. */
+};
+typedef struct HtmlTokenMap HtmlTokenMap;
+struct HtmlTokenMap {
+ char *zName; /* Name of a markup */
+ Html_16 type; /* Markup type code */
+ Html_16 extra; /* Extra space needed above HtmlBaseElement */
+ HtmlTokenMap *pCollide; /* Hash table collision chain */
+};
+extern HtmlTokenMap HtmlMarkupMap[];
+#define HTML_MARKUP_COUNT 147
+#define HTML_MARKUP_HASH_SIZE 163
+#define LOCAL static
+LOCAL void HtmlTranslateEscapes(char *z);
+#if defined(COVERAGE_TEST)
+extern int HtmlTPArray[2000];
+# define TestPoint(X) {extern int HtmlTPArray[]; HtmlTPArray[X]++;}
+#endif
+#if !(defined(COVERAGE_TEST))
+# define TestPoint(X)
+#endif
+struct HtmlImage {
+ HtmlWidget *htmlPtr; /* The owner of this image */
+ Tk_Image image; /* The Tk image token */
+ Html_32 w; /* Requested width of this image (0 if none) */
+ Html_32 h; /* Requested height of this image (0 if none) */
+ char *zUrl; /* The URL for this image. */
+ char *zWidth, *zHeight; /* Width and height in the <img> markup. */
+ HtmlImage *pNext; /* Next image on the list */
+ HtmlElement *pList; /* List of all <IMG> markups that use this
+ ** same image */
+};
+struct HtmlStyleStack {
+ HtmlStyleStack *pNext; /* Next style on the stack */
+ int type; /* A markup that ends this style. Ex: Html_EndEM */
+ HtmlStyle style; /* The currently active style. */
+};
+struct HtmlMargin {
+ int indent; /* Size of the current margin */
+ int bottom; /* Y value at which this margin expires */
+ int tag; /* Markup that will cancel this margin */
+ HtmlMargin *pNext; /* Previous margin */
+};
diff --git a/tkhtml1/src/htmlsizer.c b/tkhtml1/src/htmlsizer.c
new file mode 100644
index 0000000..68d8dc9
--- /dev/null
+++ b/tkhtml1/src/htmlsizer.c
@@ -0,0 +1,1176 @@
+/*
+** Routines used to compute the style and size of individual elements.
+**
+** Copyright (C) 1997-2000 D. Richard Hipp
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** drh@acm.org
+** http://www.hwaci.com/drh/
+*/
+#include <tk.h>
+#include <string.h>
+#include <stdlib.h>
+#include "htmlsizer.h"
+
+/*
+** Get the current rendering style. In other words, get the style
+** that is currently on the top of the style stack.
+*/
+static HtmlStyle GetCurrentStyle(HtmlWidget *htmlPtr){
+ HtmlStyle style;
+ if( htmlPtr->styleStack ){
+ style = htmlPtr->styleStack->style;
+ }else{
+ style.font = NormalFont(2);
+ style.color = COLOR_Normal;
+ style.bgcolor = COLOR_Background;
+ style.subscript = 0;
+ style.align = ALIGN_Left;
+ style.flags = 0;
+ }
+ return style;
+}
+
+/*
+** Push a new rendering style onto the stack.
+*/
+static void PushStyleStack(
+ HtmlWidget *htmlPtr, /* Widget on which to push the style */
+ int tag, /* Tag for this style. Normally the end-tag such
+ ** as </h3> or </em>. */
+ HtmlStyle style /* The style to push */
+){
+ HtmlStyleStack *p;
+
+ p = HtmlAlloc(sizeof(*p));
+ p->pNext = htmlPtr->styleStack;
+ p->type = tag;
+ p->style = style;
+ htmlPtr->styleStack = p;
+}
+
+/*
+** Pop a rendering style off of the stack.
+**
+** The top-most style on the stack should have a tag equal to "tag".
+** If not, then we have an HTML coding error. Perhaps something
+** like this: "Some text <em>Enphasized</i> more text". It is an
+** interesting problem to figure out how to respond sanely to this
+** kind of error. Our solution it to keep popping the stack until
+** we find the correct tag, or until the stack is empty.
+*/
+HtmlStyle HtmlPopStyleStack(HtmlWidget *htmlPtr, int tag){
+ int type;
+ HtmlStyleStack *p;
+ static Html_u8 priority[Html_TypeCount+1];
+
+ if( priority[Html_TABLE]==0 ){
+ int i;
+ for(i=0; i<=Html_TypeCount; i++) priority[i] = 1;
+ priority[Html_TD] = 2;
+ priority[Html_EndTD] = 2;
+ priority[Html_TH] = 2;
+ priority[Html_EndTH] = 2;
+ priority[Html_TR] = 3;
+ priority[Html_EndTR] = 3;
+ priority[Html_TABLE] = 4;
+ priority[Html_EndTABLE] = 4;
+ }
+ if( tag<=0 || tag>Html_TypeCount ){
+ CANT_HAPPEN;
+ return GetCurrentStyle(htmlPtr);
+ }
+ while( (p=htmlPtr->styleStack)!=0 ){
+ type = p->type;
+ if( type<=0 || type>Html_TypeCount ){
+ CANT_HAPPEN;
+ return GetCurrentStyle(htmlPtr);
+ }
+ if( type!=tag && priority[type]>priority[tag] ){
+ return GetCurrentStyle(htmlPtr);
+ }
+ htmlPtr->styleStack = p->pNext;
+ HtmlFree(p);
+ if( type==tag ){ break; }
+ }
+ return GetCurrentStyle(htmlPtr);
+}
+
+/*
+** Change the font size on the given style by the delta-amount given
+*/
+static void ScaleFont(HtmlStyle *pStyle, int delta){
+ int size = FontSize(pStyle->font) + delta;
+ if( size<0 ){
+ delta -= size;
+ }else if( size>6 ){
+ delta -= size-6;
+ }
+ pStyle->font += delta;
+}
+
+/*
+** Lookup an argument in the given markup with the name given.
+** Return a pointer to its value, or the given default
+** value if it doesn't appear.
+*/
+char *HtmlMarkupArg(HtmlElement *p, const char *tag, char *zDefault){
+ int i;
+ if( !HtmlIsMarkup(p) ){ TestPoint(0); return 0; }
+ for(i=0; i<p->base.count; i+=2){
+ if( strcmp(p->markup.argv[i],tag)==0 ){
+ return p->markup.argv[i+1];
+ }
+ }
+ return zDefault;
+}
+
+/*
+** Return an alignment or justification flag associated with the
+** given markup. The given default value is returned if no alignment is
+** specified.
+*/
+static int GetAlignment(HtmlElement *p, int dflt){
+ char *z = HtmlMarkupArg(p,"align",0);
+ int rc = dflt;
+ if( z ){
+ if( stricmp(z,"left")==0 ){
+ rc = ALIGN_Left;
+ }else if( stricmp(z,"right")==0 ){
+ rc = ALIGN_Right;
+ }else if( stricmp(z,"center")==0 ){
+ rc = ALIGN_Center;
+ }
+ }
+ return rc;
+}
+
+/*
+** The "type" argument to the given element might describe the type
+** for an ordered list. Return the corresponding LI_TYPE_* entry
+** if this is the case, or the default value if it isn't.
+*/
+static int GetOrderedListType(HtmlElement *p, int dflt){
+ char *z;
+
+ z = HtmlMarkupArg(p,"type",0);
+ if( z ){
+ switch( *z ){
+ case 'A': TestPoint(0); dflt = LI_TYPE_Enum_A; break;
+ case 'a': TestPoint(0); dflt = LI_TYPE_Enum_a; break;
+ case '1': TestPoint(0); dflt = LI_TYPE_Enum_1; break;
+ case 'I': TestPoint(0); dflt = LI_TYPE_Enum_I; break;
+ case 'i': TestPoint(0); dflt = LI_TYPE_Enum_i; break;
+ default: TestPoint(0); break;
+ }
+ }else{
+ TestPoint(0);
+ }
+ return dflt;
+}
+
+/*
+** The "type" argument to the given element might describe a type
+** for an unordered list. Return the corresponding LI_TYPE entry
+** if this is the case, or the default value if it isn't.
+*/
+static int GetUnorderedListType(HtmlElement *p, int dflt){
+ char *z;
+
+ z = HtmlMarkupArg(p,"type",0);
+ if( z ){
+ if( stricmp(z,"disc")==0 ){
+ dflt = LI_TYPE_Bullet1;
+ }else if( stricmp(z,"circle")==0 ){
+ dflt = LI_TYPE_Bullet2;
+ }else if( stricmp(z,"square")==0 ){
+ dflt = LI_TYPE_Bullet3;
+ }
+ }
+ return dflt;
+}
+
+/*
+** Add the STY_Invisible style to every token between pFirst and pLast.
+*/
+static void MakeInvisible(HtmlElement *pFirst, HtmlElement *pLast){
+ if( pFirst==0 ) return;
+ pFirst = pFirst->pNext;
+ while( pFirst && pFirst!=pLast ){
+ pFirst->base.style.flags |= STY_Invisible;
+ pFirst=pFirst->pNext;
+ }
+}
+
+
+
+/*
+** For the markup <a href=XXX>, find out if the URL has been visited
+** before or not. Return COLOR_Visited or COLOR_Unvisited, as
+** appropriate.
+**
+** This routine may invoke a callback procedure which could delete
+** the HTML widget. The calling function should call HtmlLock()
+** if it needs the widget structure to be preserved.
+*/
+static int GetLinkColor(HtmlWidget *htmlPtr, char *zURL){
+ char *zCmd;
+ int result;
+ int isVisited;
+
+ if( htmlPtr->tkwin==0 ){
+ TestPoint(0);
+ return COLOR_Normal;
+ }
+ if( htmlPtr->zIsVisited==0 || htmlPtr->zIsVisited[0]==0 ){
+ TestPoint(0);
+ return COLOR_Unvisited;
+ }
+ zCmd = HtmlAlloc( strlen(htmlPtr->zIsVisited) + strlen(zURL) + 10 );
+ if( zCmd==0 ){
+ TestPoint(0);
+ return COLOR_Unvisited;
+ }
+ sprintf(zCmd,"%s {%s}",htmlPtr->zIsVisited, zURL);
+ HtmlLock(htmlPtr);
+ result = Tcl_GlobalEval(htmlPtr->interp,zCmd);
+ HtmlFree(zCmd);
+ if( HtmlUnlock(htmlPtr) ){
+ return COLOR_Unvisited;
+ }
+ if( result!=TCL_OK ){
+ TestPoint(0);
+ goto errorOut;
+ }
+ result = Tcl_GetBoolean(htmlPtr->interp, Tcl_GetStringResult(htmlPtr->interp), &isVisited);
+ if( result!=TCL_OK ){
+ TestPoint(0);
+ goto errorOut;
+ }
+ TestPoint(0);
+ return isVisited ? COLOR_Visited : COLOR_Unvisited;
+
+ errorOut:
+ Tcl_AddErrorInfo(htmlPtr->interp,
+ "\n (\"-isvisitedcommand\" command executed by html widget)");
+ Tcl_BackgroundError(htmlPtr->interp);
+ TestPoint(0);
+ return COLOR_Unvisited;
+}
+
+/*
+** This routine adds information to the input texts that doesn't change
+** when the display is resized or when new fonts are selected, etc.
+** Mostly this means adding style attributes. But other constant
+** information (such as numbering on <li> and images used for <IMG>)
+** is also obtained. The key is that this routine is only called
+** once, where the sizer and layout routines can be called many times.
+**
+** This routine is called whenever the list of elements grows. The
+** style stack is stored as part of the HTML widget so that we can
+** always continue where we left off the last time.
+**
+** In addition to adding style, this routine will invoke callbacks
+** needed to acquire information about a markup. The htmlPtr->zIsVisitied
+** callback is called for each <a> and the htmlPtr->zGetImage is called
+** for each <IMG> or for each <LI> that has a SRC= field.
+**
+** This routine may invoke a callback procedure which could delete
+** the HTML widget.
+**
+** When a markup is inserted or deleted from the token list, the
+** style routine must be completely rerun from the beginning. So
+** what we said above, that this routine is only run once, is not
+** strictly true.
+*/
+void HtmlAddStyle(HtmlWidget *htmlPtr, HtmlElement *p){
+ HtmlStyle style; /* Current style */
+ int size; /* A new font size */
+ int i; /* Loop counter */
+ int paraAlign; /* Current paragraph alignment */
+ int rowAlign; /* Current table row alignment */
+ int anchorFlags; /* Flags associated with <a> tag */
+ int inDt; /* True if within <dt>..</dt> */
+ HtmlStyle nextStyle; /* Style for next token if useNextStyle==1 */
+ int useNextStyle = 0; /* True if nextStyle is valid */
+ char *z; /* A tag parameter's value */
+
+ /* The size of header fonts relative to the current font size */
+ static int header_sizes[] = {+2, +1, 1, 1, -1, -1};
+
+ /* Don't allow recursion */
+ if( htmlPtr->flags & STYLER_RUNNING ){ TestPoint(0); return; }
+ htmlPtr->flags |= STYLER_RUNNING;
+
+ /* Load the style state out of the htmlPtr structure and into local
+ ** variables. This is purely a matter of convenience... */
+ style = GetCurrentStyle(htmlPtr);
+ paraAlign = htmlPtr->paraAlignment;
+ rowAlign = htmlPtr->rowAlignment;
+ anchorFlags = htmlPtr->anchorFlags;
+ inDt = htmlPtr->inDt;
+
+ /* Loop over tokens */
+ while( p ){
+ switch( p->base.type ){
+ case Html_A:
+ if( htmlPtr->anchorStart ){
+ style = HtmlPopStyleStack(htmlPtr, Html_EndA);
+ htmlPtr->anchorStart = 0;
+ anchorFlags = 0;
+ }
+ z = HtmlMarkupArg(p,"href",0);
+ if( z ){
+ HtmlLock(htmlPtr);
+ style.color = GetLinkColor(htmlPtr, z);
+ if( htmlPtr->underlineLinks ){
+ style.flags |= STY_Underline;
+ }
+ if( HtmlUnlock(htmlPtr) ) return;
+ anchorFlags |= STY_Anchor;
+ PushStyleStack(htmlPtr, Html_EndA, style);
+ htmlPtr->anchorStart = p;
+ }
+ break;
+ case Html_EndA:
+ if( htmlPtr->anchorStart ){
+ p->ref.pOther = htmlPtr->anchorStart;
+ style = HtmlPopStyleStack(htmlPtr, Html_EndA);
+ htmlPtr->anchorStart = 0;
+ anchorFlags = 0;
+ }
+ break;
+ case Html_ADDRESS:
+ case Html_EndADDRESS:
+ case Html_BLOCKQUOTE:
+ case Html_EndBLOCKQUOTE:
+ paraAlign = ALIGN_None;
+ TestPoint(0);
+ break;
+ case Html_APPLET:
+ if( htmlPtr->zAppletCommand && *htmlPtr->zAppletCommand ){
+ nextStyle = style;
+ nextStyle.flags |= STY_Invisible;
+ PushStyleStack(htmlPtr, Html_EndAPPLET, nextStyle);
+ useNextStyle = 1;
+ }else{
+ PushStyleStack(htmlPtr, Html_EndAPPLET, style);
+ }
+ TestPoint(0);
+ break;
+ case Html_B:
+ style.font = BoldFont( FontSize(style.font) );
+ PushStyleStack(htmlPtr, Html_EndB, style);
+ TestPoint(0);
+ break;
+ case Html_EndAPPLET:
+ case Html_EndB:
+ case Html_EndBIG:
+ case Html_EndCENTER:
+ case Html_EndCITE:
+ case Html_EndCODE:
+ case Html_EndCOMMENT:
+ case Html_EndEM:
+ case Html_EndFONT:
+ case Html_EndI:
+ case Html_EndKBD:
+ case Html_EndMARQUEE:
+ case Html_EndNOBR:
+ case Html_EndNOFRAME:
+ case Html_EndNOSCRIPT:
+ case Html_EndS:
+ case Html_EndSAMP:
+ case Html_EndSMALL:
+ case Html_EndSTRIKE:
+ case Html_EndSTRONG:
+ case Html_EndSUB:
+ case Html_EndSUP:
+ case Html_EndTITLE:
+ case Html_EndTT:
+ case Html_EndU:
+ case Html_EndVAR:
+ style = HtmlPopStyleStack(htmlPtr, p->base.type);
+ TestPoint(0);
+ break;
+ case Html_BASE:
+ z = HtmlMarkupArg(p,"href",0);
+ if( z ){
+ HtmlLock(htmlPtr);
+ z = HtmlResolveUri(htmlPtr, z);
+ if( HtmlUnlock(htmlPtr) ) return;
+ if( z!=0 ){
+ if( htmlPtr->zBaseHref ){
+ HtmlFree(htmlPtr->zBaseHref);
+ }
+ htmlPtr->zBaseHref = z;
+ }
+ }
+ break;
+ case Html_EndDIV:
+ paraAlign = ALIGN_None;
+ style = HtmlPopStyleStack(htmlPtr, p->base.type);
+ TestPoint(0);
+ break;
+ case Html_EndBASEFONT:
+ style = HtmlPopStyleStack(htmlPtr, Html_EndBASEFONT);
+ style.font = FontFamily(style.font) + 2;
+ TestPoint(0);
+ break;
+ case Html_BIG:
+ ScaleFont(&style,1);
+ PushStyleStack(htmlPtr, Html_EndBIG, style);
+ TestPoint(0);
+ break;
+ case Html_CAPTION:
+ paraAlign = GetAlignment(p, paraAlign);
+ TestPoint(0);
+ break;
+ case Html_EndCAPTION:
+ paraAlign = ALIGN_None;
+ TestPoint(0);
+ break;
+ case Html_CENTER:
+ paraAlign = ALIGN_None;
+ style.align = ALIGN_Center;
+ PushStyleStack(htmlPtr, Html_EndCENTER, style);
+ TestPoint(0);
+ break;
+ case Html_CITE:
+ PushStyleStack(htmlPtr, Html_EndCITE, style);
+ TestPoint(0);
+ break;
+ case Html_CODE:
+ style.font = CWFont( FontSize(style.font) );
+ PushStyleStack(htmlPtr, Html_EndCODE, style);
+ TestPoint(0);
+ break;
+ case Html_COMMENT:
+ style.flags |= STY_Invisible;
+ PushStyleStack(htmlPtr, Html_EndCOMMENT, style);
+ TestPoint(0);
+ break;
+ case Html_DD:
+ if( htmlPtr->innerList && htmlPtr->innerList->base.type==Html_DL ){
+ p->ref.pOther = htmlPtr->innerList;
+ TestPoint(0);
+ }else{
+ p->ref.pOther = 0;
+ TestPoint(0);
+ }
+ inDt = 0;
+ break;
+ case Html_DIR:
+ case Html_MENU:
+ case Html_UL:
+ p->list.pPrev = htmlPtr->innerList;
+ p->list.cnt = 0;
+ htmlPtr->innerList = p;
+ if( p->list.pPrev==0 ){
+ p->list.type = LI_TYPE_Bullet1;
+ p->list.compact = HtmlMarkupArg(p,"compact",0)!=0;
+ TestPoint(0);
+ }else if( p->list.pPrev->list.pPrev==0 ){
+ p->list.type = LI_TYPE_Bullet2;
+ p->list.compact = 1;
+ TestPoint(0);
+ }else{
+ p->list.type = LI_TYPE_Bullet3;
+ p->list.compact = 1;
+ TestPoint(0);
+ }
+ p->list.type = GetUnorderedListType(p,p->list.type);
+ break;
+ case Html_EndDL:
+ inDt = 0;
+ TestPoint(0);
+ /* Fall thru into the next case */
+ case Html_EndDIR:
+ case Html_EndMENU:
+ case Html_EndOL:
+ case Html_EndUL:
+ p->ref.pOther = htmlPtr->innerList;
+ if( htmlPtr->innerList ){
+ htmlPtr->innerList = htmlPtr->innerList->list.pPrev;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ break;
+ case Html_DIV:
+ paraAlign = ALIGN_None;
+ style.align = GetAlignment(p, style.align);
+ PushStyleStack(htmlPtr, Html_EndDIV, style);
+ TestPoint(0);
+ break;
+ case Html_DT:
+ if( htmlPtr->innerList && htmlPtr->innerList->base.type==Html_DL ){
+ p->ref.pOther = htmlPtr->innerList;
+ TestPoint(0);
+ }else{
+ p->ref.pOther = 0;
+ TestPoint(0);
+ }
+ inDt = STY_DT;
+ break;
+ case Html_EndDD:
+ case Html_EndDT:
+ inDt = 0;
+ TestPoint(0);
+ break;
+ case Html_DL:
+ p->list.pPrev = htmlPtr->innerList;
+ p->list.cnt = 0;
+ htmlPtr->innerList = p;
+ p->list.compact = HtmlMarkupArg(p,"compact",0)!=0;
+ inDt = 0;
+ TestPoint(0);
+ break;
+ case Html_EM:
+ style.font = ItalicFont( FontSize(style.font) );
+ PushStyleStack(htmlPtr, Html_EndEM, style);
+ TestPoint(0);
+ break;
+ case Html_EMBED:
+ break;
+ case Html_BASEFONT:
+ case Html_FONT:
+ z = HtmlMarkupArg(p,"size",0);
+ if( z ){
+ if( *z=='-' ){
+ size = FontSize(style.font) - atoi(&z[1]);
+ }else if( *z=='+' ){
+ size = FontSize(style.font) + atoi(&z[1]);
+ }else{
+ size = atoi(z);
+ }
+ if( size <= 0 ){
+ size = 1;
+ }
+ if( size >= N_FONT_SIZE ){
+ size = N_FONT_SIZE - 1;
+ }
+ style.font = FontFamily(style.font) + size - 1;
+ }
+ z = HtmlMarkupArg(p,"color",0);
+ if( z ){
+ style.color = HtmlGetColorByName(htmlPtr, z);
+ }
+ PushStyleStack(htmlPtr,
+ p->base.type==Html_FONT ? Html_EndFONT : Html_EndBASEFONT, style);
+ break;
+ case Html_FORM: {
+ char *zUrl;
+ char *zMethod;
+ Tcl_DString cmd; /* -formcommand callback */
+ int result;
+ char zToken[50];
+
+ htmlPtr->formStart = 0;
+ p->form.id = 0;
+ if( htmlPtr->zFormCommand==0 || htmlPtr->zFormCommand[0]==0 ){
+ TestPoint(0);
+ break;
+ }
+ zUrl = HtmlMarkupArg(p,"action",0);
+ if( zUrl==0 ){
+ TestPoint(0);
+ break;
+ }
+ HtmlLock(htmlPtr);
+ zUrl = HtmlResolveUri(htmlPtr, zUrl);
+ if( HtmlUnlock(htmlPtr) ) return;
+ if( zUrl==0 ) break;
+ zMethod = HtmlMarkupArg(p,"method","GET");
+ sprintf(zToken," %d form ", ++htmlPtr->nForm);
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, htmlPtr->zFormCommand, -1);
+ Tcl_DStringAppend(&cmd, zToken, -1);
+ Tcl_DStringAppendElement(&cmd, zUrl);
+ HtmlFree(zUrl);
+ Tcl_DStringAppendElement(&cmd, zMethod);
+ Tcl_DStringStartSublist(&cmd);
+ HtmlAppendArglist(&cmd, p);
+ Tcl_DStringEndSublist(&cmd);
+ HtmlLock(htmlPtr);
+ result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if( HtmlUnlock(htmlPtr) ) return;
+ if( result==TCL_OK ){
+ htmlPtr->formStart = p;
+ p->form.id = htmlPtr->nForm;
+ }
+ Tcl_ResetResult(htmlPtr->interp);
+ break;
+ }
+ case Html_EndFORM:
+ p->ref.pOther = htmlPtr->formStart;
+ htmlPtr->formStart = 0;
+ TestPoint(0);
+ break;
+ case Html_H1:
+ case Html_H2:
+ case Html_H3:
+ case Html_H4:
+ case Html_H5:
+ case Html_H6:
+ paraAlign = ALIGN_None;
+ i = (p->base.type - Html_H1)/2 + 1;
+ if( i>=1 && i<=6 ){
+ ScaleFont(&style,header_sizes[i-1]);
+ }
+ style.font = BoldFont( FontSize(style.font) );
+ style.align = GetAlignment(p, style.align);
+ PushStyleStack(htmlPtr, Html_EndH1, style);
+ break;
+ case Html_EndH1:
+ case Html_EndH2:
+ case Html_EndH3:
+ case Html_EndH4:
+ case Html_EndH5:
+ case Html_EndH6:
+ paraAlign = ALIGN_None;
+ style = HtmlPopStyleStack(htmlPtr, Html_EndH1);
+ TestPoint(0);
+ break;
+ case Html_HR:
+ nextStyle = style;
+ style.align = GetAlignment(p, ALIGN_None);
+ useNextStyle = 1;
+ break;
+ case Html_I:
+ style.font = ItalicFont( FontSize(style.font) );
+ PushStyleStack(htmlPtr, Html_EndI, style);
+ TestPoint(0);
+ break;
+ case Html_IMG:
+ HtmlLock(htmlPtr);
+ p->image.pImage = HtmlGetImage(htmlPtr, p);
+ if( HtmlUnlock(htmlPtr) ) return;
+ TestPoint(0);
+ break;
+ case Html_INPUT:
+ p->input.pForm = htmlPtr->formStart;
+ TestPoint(0);
+ break;
+ case Html_KBD:
+ style.font = CWFont( FontSize(style.font) );
+ PushStyleStack(htmlPtr, Html_EndKBD, style);
+ TestPoint(0);
+ break;
+ case Html_LI:
+ if( htmlPtr->innerList ){
+ p->li.type = htmlPtr->innerList->list.type;
+ if( htmlPtr->innerList->base.type==Html_OL ){
+ z = HtmlMarkupArg(p, "value", 0);
+ if( z ){
+ int n = atoi(z);
+ if( n>0 ){
+ p->li.cnt = n;
+ htmlPtr->innerList->list.cnt = n+1;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ }else{
+ p->li.cnt = htmlPtr->innerList->list.cnt++;
+ TestPoint(0);
+ }
+ p->li.type = GetOrderedListType(p,p->li.type);
+ }else{
+ p->li.type = GetUnorderedListType(p,p->li.type);
+ TestPoint(0);
+ }
+ }else{
+ p->base.flags &= ~HTML_Visible;
+ TestPoint(0);
+ }
+ break;
+ case Html_MARQUEE:
+ style.flags |= STY_Invisible;
+ PushStyleStack(htmlPtr, Html_EndMARQUEE, style);
+ TestPoint(0);
+ break;
+ case Html_NOBR:
+ style.flags |= STY_NoBreak;
+ PushStyleStack(htmlPtr, Html_EndNOBR, style);
+ TestPoint(0);
+ break;
+ case Html_NOFRAME:
+ if( htmlPtr->zFrameCommand && *htmlPtr->zFrameCommand ){
+ nextStyle = style;
+ nextStyle.flags |= STY_Invisible;
+ PushStyleStack(htmlPtr, Html_EndNOFRAME, nextStyle);
+ useNextStyle = 1;
+ }else{
+ PushStyleStack(htmlPtr, Html_EndNOFRAME, style);
+ }
+ TestPoint(0);
+ break;
+ case Html_NOSCRIPT:
+ if( htmlPtr->zScriptCommand && *htmlPtr->zScriptCommand ){
+ nextStyle = style;
+ nextStyle.flags |= STY_Invisible;
+ PushStyleStack(htmlPtr, Html_EndNOSCRIPT, nextStyle);
+ useNextStyle = 1;
+ }else{
+ PushStyleStack(htmlPtr, Html_EndNOSCRIPT, style);
+ }
+ TestPoint(0);
+ break;
+ case Html_OL:
+ p->list.pPrev = htmlPtr->innerList;
+ p->list.type = GetOrderedListType(p,LI_TYPE_Enum_1);
+ p->list.cnt = 1;
+ z = HtmlMarkupArg(p,"start",0);
+ if( z ){
+ int n = atoi(z);
+ if( n>0 ){
+ p->list.cnt = n;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ }else{
+ TestPoint(0);
+ }
+ p->list.compact = htmlPtr->innerList!=0 ||
+ HtmlMarkupArg(p,"compact",0)!=0;
+ htmlPtr->innerList = p;
+ break;
+ case Html_P:
+ paraAlign = GetAlignment(p, ALIGN_None);
+ TestPoint(0);
+ break;
+ case Html_EndP:
+ paraAlign = ALIGN_None;
+ TestPoint(0);
+ break;
+ case Html_PRE:
+ case Html_LISTING:
+ case Html_XMP:
+ case Html_PLAINTEXT:
+ paraAlign = ALIGN_None;
+ style.font = CWFont( FontSize(style.font) );
+ style.flags |= STY_Preformatted;
+ PushStyleStack(htmlPtr, Html_EndPRE, style);
+ TestPoint(0);
+ break;
+ case Html_EndPRE:
+ case Html_EndLISTING:
+ case Html_EndXMP:
+ style = HtmlPopStyleStack(htmlPtr, Html_EndPRE);
+ TestPoint(0);
+ break;
+ case Html_S:
+ style.flags |= STY_StrikeThru;
+ PushStyleStack(htmlPtr, Html_EndS, style);
+ TestPoint(0);
+ break;
+ case Html_SCRIPT:
+ if( htmlPtr->zScriptCommand && *htmlPtr->zScriptCommand ){
+ Tcl_DString cmd;
+ int result;
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, htmlPtr->zScriptCommand, -1);
+ Tcl_DStringStartSublist(&cmd);
+ HtmlAppendArglist(&cmd, p);
+ Tcl_DStringEndSublist(&cmd);
+ Tcl_DStringStartSublist(&cmd);
+ Tcl_DStringAppend(&cmd, p->script.zScript, p->script.nScript);
+ Tcl_DStringEndSublist(&cmd);
+ HtmlLock(htmlPtr);
+ result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if( HtmlUnlock(htmlPtr) ) return;
+ Tcl_ResetResult(htmlPtr->interp);
+ }
+ nextStyle = style;
+ style.flags |= STY_Invisible;
+ useNextStyle = 1;
+ break;
+ case Html_SELECT:
+ p->input.pForm = htmlPtr->formStart;
+ nextStyle.flags |= STY_Invisible;
+ useNextStyle = 1;
+ PushStyleStack(htmlPtr, Html_EndSELECT, style);
+ htmlPtr->formElemStart = p;
+ break;
+ case Html_EndSELECT:
+ style = HtmlPopStyleStack(htmlPtr, Html_EndSELECT);
+ if( htmlPtr->formElemStart
+ && htmlPtr->formElemStart->base.type==Html_SELECT ){
+ p->ref.pOther = htmlPtr->formElemStart;
+ MakeInvisible(p->ref.pOther, p);
+ }else{
+ p->ref.pOther = 0;
+ }
+ htmlPtr->formElemStart = 0;
+ break;
+ case Html_STRIKE:
+ style.flags |= STY_StrikeThru;
+ PushStyleStack(htmlPtr, Html_EndSTRIKE, style);
+ TestPoint(0);
+ break;
+ case Html_STYLE:
+ /* Ignore style sheets */
+ break;
+ case Html_SAMP:
+ style.font = CWFont( FontSize(style.font) );
+ PushStyleStack(htmlPtr, Html_EndSAMP, style);
+ TestPoint(0);
+ break;
+ case Html_SMALL:
+ ScaleFont(&style,-1);
+ PushStyleStack(htmlPtr, Html_EndSMALL, style);
+ TestPoint(0);
+ break;
+ case Html_STRONG:
+ style.font = BoldFont( FontSize(style.font) );
+ PushStyleStack(htmlPtr, Html_EndSTRONG, style);
+ TestPoint(0);
+ break;
+ case Html_SUB:
+ ScaleFont(&style,-1);
+ if( style.subscript > -6 ){
+ style.subscript--;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ PushStyleStack(htmlPtr, Html_EndSUB, style);
+ break;
+ case Html_SUP:
+ ScaleFont(&style,-1);
+ if( style.subscript < 6 ){
+ style.subscript++;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ PushStyleStack(htmlPtr, Html_EndSUP, style);
+ break;
+ case Html_TABLE:
+ paraAlign = ALIGN_None;
+ nextStyle = style;
+ nextStyle.align = ALIGN_Left;
+ z = HtmlMarkupArg(p, "bgcolor", 0);
+ if( z ){
+ nextStyle.bgcolor = HtmlGetColorByName(htmlPtr, z);
+ style.bgcolor = nextStyle.bgcolor;
+/* }else{
+ nextStyle.bgcolor = COLOR_Background; */
+ }
+ PushStyleStack(htmlPtr, Html_EndTABLE, nextStyle);
+ useNextStyle = 1;
+ htmlPtr->inTd = 0;
+ htmlPtr->inTr = 0;
+ TestPoint(0);
+ break;
+ case Html_EndTABLE:
+ paraAlign = ALIGN_None;
+ if( htmlPtr->inTd ){
+ style = HtmlPopStyleStack(htmlPtr, Html_EndTD);
+ htmlPtr->inTd = 0;
+ }
+ if( htmlPtr->inTr ){
+ style = HtmlPopStyleStack(htmlPtr, Html_EndTR);
+ htmlPtr->inTr = 0;
+ }
+ style = HtmlPopStyleStack(htmlPtr, p->base.type);
+ TestPoint(0);
+ break;
+ case Html_TD:
+ if( htmlPtr->inTd ){
+ style = HtmlPopStyleStack(htmlPtr, Html_EndTD);
+ }
+ htmlPtr->inTd = 1;
+ paraAlign = GetAlignment(p, rowAlign);
+ if( (z = HtmlMarkupArg(p, "bgcolor", 0))!=0 ){
+ style.bgcolor = HtmlGetColorByName(htmlPtr, z);
+ }
+ PushStyleStack(htmlPtr, Html_EndTD, style);
+ TestPoint(0);
+ break;
+ case Html_TEXTAREA:
+ p->input.pForm = htmlPtr->formStart;
+ nextStyle = style;
+ nextStyle.flags |= STY_Invisible;
+ PushStyleStack(htmlPtr, Html_EndTEXTAREA, nextStyle);
+ htmlPtr->formElemStart = p;
+ useNextStyle = 1;
+ TestPoint(0);
+ break;
+ case Html_EndTEXTAREA:
+ style = HtmlPopStyleStack(htmlPtr, Html_EndTEXTAREA);
+ if( htmlPtr->formElemStart
+ && htmlPtr->formElemStart->base.type==Html_TEXTAREA ){
+ p->ref.pOther = htmlPtr->formElemStart;
+ }else{
+ p->ref.pOther = 0;
+ }
+ htmlPtr->formElemStart = 0;
+ break;
+ case Html_TH:
+ /* paraAlign = GetAlignment(p, rowAlign); */
+ if( htmlPtr->inTd ){
+ style = HtmlPopStyleStack(htmlPtr, Html_EndTD);
+ }
+ paraAlign = GetAlignment(p, ALIGN_Center);
+ style.font = BoldFont( FontSize(style.font) );
+ if( (z = HtmlMarkupArg(p, "bgcolor", 0))!=0 ){
+ style.bgcolor = HtmlGetColorByName(htmlPtr, z);
+ }
+ PushStyleStack(htmlPtr, Html_EndTD, style);
+ htmlPtr->inTd = 1;
+ TestPoint(0);
+ break;
+ case Html_TR:
+ if( htmlPtr->inTd ){
+ style = HtmlPopStyleStack(htmlPtr, Html_EndTD);
+ htmlPtr->inTd = 0;
+ }
+ if( htmlPtr->inTr ){
+ style = HtmlPopStyleStack(htmlPtr, Html_EndTR);
+ }
+ rowAlign = GetAlignment(p, ALIGN_None);
+ if( (z = HtmlMarkupArg(p, "bgcolor", 0))!=0 ){
+ style.bgcolor = HtmlGetColorByName(htmlPtr, z);
+ }
+ PushStyleStack(htmlPtr, Html_EndTR, style);
+ htmlPtr->inTr = 1;
+ TestPoint(0);
+ break;
+ case Html_EndTR:
+ if( htmlPtr->inTd ){
+ style = HtmlPopStyleStack(htmlPtr, Html_EndTD);
+ htmlPtr->inTd = 0;
+ }
+ style = HtmlPopStyleStack(htmlPtr, Html_EndTR);
+ htmlPtr->inTr = 0;
+ paraAlign = ALIGN_None;
+ rowAlign = ALIGN_None;
+ TestPoint(0);
+ break;
+ case Html_EndTD:
+ case Html_EndTH:
+ style = HtmlPopStyleStack(htmlPtr, Html_EndTD);
+ htmlPtr->inTd = 0;
+ paraAlign = ALIGN_None;
+ rowAlign = ALIGN_None;
+ TestPoint(0);
+ break;
+ case Html_TITLE:
+ style.flags |= STY_Invisible;
+ PushStyleStack(htmlPtr, Html_EndTITLE, style);
+ TestPoint(0);
+ break;
+ case Html_TT:
+ style.font = CWFont( FontSize(style.font) );
+ PushStyleStack(htmlPtr, Html_EndTT, style);
+ TestPoint(0);
+ break;
+ case Html_U:
+ style.flags |= STY_Underline;
+ PushStyleStack(htmlPtr, Html_EndU, style);
+ break;
+ case Html_VAR:
+ style.font = ItalicFont( FontSize(style.font) );
+ PushStyleStack(htmlPtr, Html_EndVAR, style);
+ TestPoint(0);
+ break;
+ default:
+ TestPoint(0);
+ break;
+ }
+ p->base.style = style;
+ p->base.style.flags |= anchorFlags | inDt;
+ if( paraAlign!=ALIGN_None ){
+ p->base.style.align = paraAlign;
+ }
+ if( useNextStyle ){
+ style = nextStyle;
+ useNextStyle = 0;
+ }
+ TRACE(HtmlTrace_Style,
+ ("Style of 0x%08x font=%02d color=%02d bg=%02d "
+ "align=%d flags=0x%04x token=%s\n",
+ (int)p, p->base.style.font, p->base.style.color, p->base.style.bgcolor,
+ p->base.style.align, p->base.style.flags, HtmlTokenName(p)));
+ p = p->pNext;
+ }
+
+ /* Copy state information back into the htmlPtr structure for
+ ** safe keeping. */
+ htmlPtr->paraAlignment = paraAlign;
+ htmlPtr->rowAlignment = rowAlign;
+ htmlPtr->anchorFlags = anchorFlags;
+ htmlPtr->inDt = inDt;
+ htmlPtr->flags &= ~STYLER_RUNNING;
+}
+
+/*
+** Compute the size of all elements in the widget. Assume that a
+** style has already been assigned to all elements.
+**
+** Some of the elements might have already been sized. Refer to the
+** htmlPtr->lastSized and only compute sizes for elements that follow
+** this one. If htmlPtr->lastSized==0, then size everything.
+**
+** This routine only computes the sizes of individual elements. The
+** size of aggregate elements (like tables) are computed separately.
+**
+** The HTML_Visible flag is also set on every element that results
+** in ink on the page.
+**
+** This routine may invoke a callback procedure which could delete
+** the HTML widget.
+*/
+void HtmlSizer(HtmlWidget *htmlPtr){
+ HtmlElement *p;
+ int iFont = -1;
+ Tk_Font font;
+ int spaceWidth = 0;
+ Tk_FontMetrics fontMetrics;
+ char *z;
+ int stop = 0;
+
+ if( htmlPtr->pFirst==0 ){ TestPoint(0); return; }
+ if( htmlPtr->lastSized==0 ){
+ p = htmlPtr->pFirst;
+ TestPoint(0);
+ }else{
+ p = htmlPtr->lastSized->pNext;
+ TestPoint(0);
+ }
+ for(; !stop && p; p=p->pNext){
+ if( p->base.style.flags & STY_Invisible ){
+ p->base.flags &= ~HTML_Visible;
+ TestPoint(0);
+ continue;
+ }
+ if( iFont != p->base.style.font ){
+ iFont = p->base.style.font;
+ HtmlLock(htmlPtr);
+ font = HtmlGetFont(htmlPtr, iFont);
+ if( HtmlUnlock(htmlPtr) ) break;
+ Tk_GetFontMetrics(font, &fontMetrics);
+ spaceWidth = 0;
+ }
+ switch( p->base.type ){
+ case Html_Text:
+ p->text.w = Tk_TextWidth(font, p->text.zText, p->base.count);
+ p->base.flags |= HTML_Visible;
+ p->text.descent = fontMetrics.descent;
+ p->text.ascent = fontMetrics.ascent;
+ if( spaceWidth==0 ){
+ spaceWidth = Tk_TextWidth(font, " ", 1);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ p->text.spaceWidth = spaceWidth;
+ break;
+ case Html_Space:
+ if( spaceWidth==0 ){
+ spaceWidth = Tk_TextWidth(font, " ", 1);
+ }
+ p->space.w = spaceWidth;
+ p->space.descent = fontMetrics.descent;
+ p->space.ascent = fontMetrics.ascent;
+ p->base.flags &= ~HTML_Visible;
+ break;
+ case Html_TD:
+ case Html_TH:
+ z = HtmlMarkupArg(p, "rowspan","1");
+ p->cell.rowspan = atoi(z);
+ z = HtmlMarkupArg(p, "colspan","1");
+ p->cell.colspan = atoi(z);
+ p->base.flags |= HTML_Visible;
+ TestPoint(0);
+ break;
+ case Html_LI:
+ p->li.descent = fontMetrics.descent;
+ p->li.ascent = fontMetrics.ascent;
+ p->base.flags |= HTML_Visible;
+ TestPoint(0);
+ break;
+ case Html_IMG:
+ p->base.flags |= HTML_Visible;
+ p->image.redrawNeeded = 0;
+ p->image.textAscent = fontMetrics.ascent;
+ p->image.textDescent = fontMetrics.descent;
+ p->image.align = HtmlGetImageAlignment(p);
+ if( p->image.pImage==0 ){
+ p->image.ascent = fontMetrics.ascent;
+ p->image.descent = fontMetrics.descent;
+ p->image.zAlt = HtmlMarkupArg(p, "alt", "<image>");
+ p->image.w = Tk_TextWidth(font, p->image.zAlt, strlen(p->image.zAlt));
+ }else{
+ int w, h;
+ p->image.pNext = p->image.pImage->pList;
+ p->image.pImage->pList = p;
+ Tk_SizeOfImage(p->image.pImage->image, &w, &h);
+ p->image.h = h;
+ p->image.w = w;
+ p->image.ascent = h/2;
+ p->image.descent = h - p->image.ascent;
+ }
+ if( (z = HtmlMarkupArg(p, "width", 0))!=0 ){
+ int w = atoi(z);
+ if( w>0 ) p->image.w = w;
+ }
+ if( (z = HtmlMarkupArg(p, "height", 0))!=0 ){
+ int h = atoi(z);
+ if( h>0 ) p->image.h = h;
+ }
+ break;
+ case Html_HR:
+ case Html_TABLE:
+ p->base.flags |= HTML_Visible;
+ TestPoint(0);
+ break;
+ case Html_APPLET:
+ case Html_EMBED:
+ case Html_INPUT:
+ p->input.textAscent = fontMetrics.ascent;
+ p->input.textDescent = fontMetrics.descent;
+ stop = HtmlControlSize(htmlPtr, p);
+ break;
+ case Html_SELECT:
+ case Html_TEXTAREA:
+ p->input.textAscent = fontMetrics.ascent;
+ p->input.textDescent = fontMetrics.descent;
+ break;
+ case Html_EndSELECT:
+ case Html_EndTEXTAREA:
+ if( p->ref.pOther ){
+ p->ref.pOther->input.pEnd = p;
+ stop = HtmlControlSize(htmlPtr, p->ref.pOther);
+ }
+ break;
+ default:
+ p->base.flags &= ~HTML_Visible;
+ break;
+ }
+ }
+ if( p ){
+ htmlPtr->lastSized = p;
+ }else{
+ htmlPtr->lastSized = htmlPtr->pLast;
+ }
+}
diff --git a/tkhtml1/src/htmlsizer.h b/tkhtml1/src/htmlsizer.h
new file mode 100644
index 0000000..c5c3081
--- /dev/null
+++ b/tkhtml1/src/htmlsizer.h
@@ -0,0 +1,636 @@
+/* This file was automatically generated. Do not edit! */
+typedef struct HtmlWidget HtmlWidget;
+typedef union HtmlElement HtmlElement;
+int HtmlControlSize(HtmlWidget *htmlPtr,HtmlElement *pElem);
+int HtmlGetImageAlignment(HtmlElement *p);
+#define Html_Space 2
+#define Html_Text 1
+Tk_Font HtmlGetFont(HtmlWidget *htmlPtr,int iFont);
+void HtmlSizer(HtmlWidget *htmlPtr);
+char *HtmlTokenName(HtmlElement *p);
+#define HtmlTrace_Style 0x00002000
+extern int HtmlTraceMask;
+#define DEBUG 1
+#if defined(DEBUG)
+extern int HtmlDepth;
+# define TRACE_INDENT printf("%*s",HtmlDepth-3,"")
+#endif
+#if !(defined(DEBUG))
+# define TRACE_INDENT
+#endif
+#if defined(DEBUG)
+# define TRACE(Flag, Args) \
+ if( (Flag)&HtmlTraceMask ){ \
+ TRACE_INDENT; printf Args; fflush(stdout); \
+ }
+#endif
+#if !(defined(DEBUG))
+# define TRACE(Flag, Args)
+#endif
+#define Html_VAR 147
+#define Html_U 143
+#define Html_TT 141
+#define Html_TITLE 137
+#define Html_EndTEXTAREA 134
+#define Html_TEXTAREA 133
+#define Html_SUP 127
+#define Html_SUB 125
+#define Html_STRONG 122
+#define Html_SMALL 118
+#define Html_SAMP 113
+#define Html_STYLE 124
+#define Html_STRIKE 120
+#define Html_EndSELECT 117
+#define Html_SELECT 116
+#define Html_SCRIPT 115
+#define STY_StrikeThru 0x002
+#define Html_S 111
+#define Html_EndXMP 151
+#define Html_EndLISTING 85
+#define Html_EndPRE 110
+#define STY_Preformatted 0x001
+#define Html_PLAINTEXT 108
+#define Html_XMP 150
+#define Html_LISTING 84
+#define Html_PRE 109
+#define Html_EndP 105
+#define Html_P 104
+#define Html_NOSCRIPT 98
+#define Html_NOFRAME 96
+#define STY_NoBreak 0x008
+#define Html_NOBR 94
+#define Html_MARQUEE 88
+#define HTML_Visible 0x01 /* This element produces "ink" */
+#define Html_OL 100
+#define Html_LI 81
+#define Html_KBD 79
+#define Html_INPUT 77
+typedef struct HtmlImage HtmlImage;
+HtmlImage *HtmlGetImage(HtmlWidget *htmlPtr,HtmlElement *p);
+#define Html_IMG 76
+#define Html_I 73
+#define Html_HR 70
+#define Html_EndH6 69
+#define Html_EndH5 67
+#define Html_EndH4 65
+#define Html_EndH3 63
+#define Html_EndH2 61
+#define Html_EndH1 59
+#define Html_H6 68
+#define Html_H5 66
+#define Html_H4 64
+#define Html_H3 62
+#define Html_H2 60
+#define Html_H1 58
+#define Html_EndFORM 53
+void HtmlAppendArglist(Tcl_DString *str,HtmlElement *pElem);
+#define Html_FORM 52
+int HtmlGetColorByName(HtmlWidget *htmlPtr,char *zColor);
+#define N_FONT_SIZE 7
+#define Html_FONT 50
+#define Html_BASEFONT 15
+#define Html_EMBED 49
+#define ItalicFont(X) ((X)+2*N_FONT_SIZE)
+#define Html_EM 47
+#define Html_EndDT 46
+#define Html_EndDD 36
+#define STY_DT 0x020
+#define Html_DT 45
+#define Html_DIV 41
+#define Html_EndUL 146
+#define Html_EndOL 101
+#define Html_EndMENU 91
+#define Html_EndDIR 40
+#define Html_EndDL 44
+#define Html_UL 145
+#define Html_MENU 90
+#define Html_DIR 39
+#define Html_DL 43
+#define Html_DD 35
+#define Html_COMMENT 33
+#define CWFont(X) ((X)+4*N_FONT_SIZE)
+#define Html_CODE 31
+#define Html_CITE 29
+#define Html_CENTER 27
+#define Html_EndCAPTION 26
+#define Html_CAPTION 25
+#define Html_BIG 18
+#define FontFamily(X) (((X)/N_FONT_SIZE)*N_FONT_SIZE)
+#define Html_EndBASEFONT 16
+#define Html_EndDIV 42
+char *HtmlResolveUri(HtmlWidget *htmlPtr,char *zUri);
+#define Html_BASE 14
+#define Html_EndVAR 148
+#define Html_EndU 144
+#define Html_EndTT 142
+#define Html_EndTITLE 138
+#define Html_EndSUP 128
+#define Html_EndSUB 126
+#define Html_EndSTRONG 123
+#define Html_EndSTRIKE 121
+#define Html_EndSMALL 119
+#define Html_EndSAMP 114
+#define Html_EndS 112
+#define Html_EndNOSCRIPT 99
+#define Html_EndNOFRAME 97
+#define Html_EndNOBR 95
+#define Html_EndMARQUEE 89
+#define Html_EndKBD 80
+#define Html_EndI 74
+#define Html_EndFONT 51
+#define Html_EndEM 48
+#define Html_EndCOMMENT 34
+#define Html_EndCODE 32
+#define Html_EndCITE 30
+#define Html_EndCENTER 28
+#define Html_EndBIG 19
+#define Html_EndB 13
+#define BoldFont(X) ((X)+N_FONT_SIZE)
+#define Html_B 12
+#define Html_EndAPPLET 10
+#define Html_APPLET 9
+#define ALIGN_None 0
+#define Html_EndBLOCKQUOTE 21
+#define Html_BLOCKQUOTE 20
+#define Html_EndADDRESS 8
+#define Html_ADDRESS 7
+#define STY_Anchor 0x010
+#define STY_Underline 0x004
+#define Html_EndA 6
+#define Html_A 5
+#define STYLER_RUNNING 0x000800
+void HtmlAddStyle(HtmlWidget *htmlPtr,HtmlElement *p);
+#define COLOR_Visited 2 /* Color for visited hyperlinks */
+int HtmlUnlock(HtmlWidget *htmlPtr);
+void HtmlLock(HtmlWidget *htmlPtr);
+#define COLOR_Unvisited 1 /* Index for unvisited hyperlinks */
+#define STY_Invisible 0x040
+#define LI_TYPE_Bullet3 3 /* A hollow square */
+#define LI_TYPE_Bullet2 2 /* A hollow circle */
+#define LI_TYPE_Bullet1 1 /* A solid circle */
+#define LI_TYPE_Enum_i 8 /* Lower-case roman numerals */
+#define LI_TYPE_Enum_I 7 /* Capitalized roman numerals */
+#define LI_TYPE_Enum_1 4 /* Arabic numbers */
+#define LI_TYPE_Enum_a 6 /* a, b, c, ... */
+#define LI_TYPE_Enum_A 5 /* A, B, C, ... */
+#define ALIGN_Center 3
+#define ALIGN_Right 2
+#if !defined(HAVE_STRICMP)
+# define stricmp strcasecmp
+#endif
+#if defined(COVERAGE_TEST)
+extern int HtmlTPArray[2000];
+# define TestPoint(X) {extern int HtmlTPArray[]; HtmlTPArray[X]++;}
+#endif
+#if !(defined(COVERAGE_TEST))
+# define TestPoint(X)
+#endif
+#define Html_Block 4
+#define HtmlIsMarkup(X) ((X)->base.type>Html_Block)
+typedef struct HtmlBaseElement HtmlBaseElement;
+typedef struct HtmlStyle HtmlStyle;
+struct HtmlStyle {
+ unsigned int font : 6; /* Font to use for display */
+ unsigned int color : 4; /* Foreground color */
+ signed int subscript : 4; /* Positive for <sup>, negative for <sub> */
+ unsigned int align : 2; /* Horizontal alignment */
+ unsigned int bgcolor : 4; /* Background color */
+ unsigned int flags : 12; /* the STY_ flags below */
+};
+typedef unsigned char Html_u8;
+typedef short Html_16;
+struct HtmlBaseElement {
+ HtmlElement *pNext; /* Next input token in a list of them all */
+ HtmlElement *pPrev; /* Previous token in a list of them all */
+ HtmlStyle style; /* The rendering style for this token */
+ Html_u8 type; /* The token type. */
+ Html_u8 flags; /* The HTML_ flags below */
+ Html_16 count; /* Various uses, depending on "type" */
+};
+typedef struct HtmlTextElement HtmlTextElement;
+typedef int Html_32;
+struct HtmlTextElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_32 y; /* y coordinate where text should be rendered */
+ Html_16 x; /* x coordinate where text should be rendered */
+ Html_16 w; /* width of this token in pixels */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_u8 spaceWidth; /* Width of one space in the current font */
+ char zText[1]; /* Text for this element. Null terminated */
+};
+typedef struct HtmlSpaceElement HtmlSpaceElement;
+struct HtmlSpaceElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_16 w; /* Width of a single space in current font */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+};
+typedef struct HtmlMarkupElement HtmlMarkupElement;
+struct HtmlMarkupElement {
+ HtmlBaseElement base;
+ char **argv;
+};
+typedef struct HtmlCell HtmlCell;
+struct HtmlCell {
+ HtmlMarkupElement markup;
+ Html_16 rowspan; /* Number of rows spanned by this cell */
+ Html_16 colspan; /* Number of columns spanned by this cell */
+ Html_16 x; /* X coordinate of left edge of border */
+ Html_16 w; /* Width of the border */
+ Html_32 y; /* Y coordinate of top of border indentation */
+ Html_32 h; /* Height of the border */
+ HtmlElement *pTable; /* Pointer back to the <table> */
+ HtmlElement *pEnd; /* Element that ends this cell */
+};
+typedef struct HtmlTable HtmlTable;
+typedef unsigned short Html_u16;
+#define HTML_MAX_COLUMNS 40
+struct HtmlTable {
+ HtmlMarkupElement markup;
+ Html_u8 borderWidth; /* Width of the border */
+ Html_u8 nCol; /* Number of columns */
+ Html_u16 nRow; /* Number of rows */
+ Html_32 y; /* top edge of table border */
+ Html_32 h; /* height of the table border */
+ Html_16 x; /* left edge of table border */
+ Html_16 w; /* width of the table border */
+ int minW[HTML_MAX_COLUMNS+1]; /* minimum width of each column */
+ int maxW[HTML_MAX_COLUMNS+1]; /* maximum width of each column */
+};
+typedef struct HtmlRef HtmlRef;
+struct HtmlRef {
+ HtmlMarkupElement markup;
+ HtmlElement *pOther; /* Pointer to some other Html element */
+};
+typedef struct HtmlLi HtmlLi;
+struct HtmlLi {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* What type of list is this? */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_16 cnt; /* Value for this element (if inside <OL>) */
+ Html_16 x; /* X coordinate of the bullet */
+ Html_32 y; /* Y coordinate of the bullet */
+};
+typedef struct HtmlListStart HtmlListStart;
+struct HtmlListStart {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* One of the LI_TYPE_ defines above */
+ Html_u8 compact; /* True if the COMPACT flag is present */
+ Html_u16 cnt; /* Next value for <OL> */
+ Html_u16 width; /* How much space to allow for indentation */
+ HtmlElement *pPrev; /* Next higher level list, or NULL */
+};
+typedef struct HtmlImageMarkup HtmlImageMarkup;
+struct HtmlImageMarkup {
+ HtmlMarkupElement markup;
+ Html_u8 align; /* Alignment. See IMAGE_ALIGN_ defines below */
+ Html_u8 textAscent; /* Ascent of text font in force at the <IMG> */
+ Html_u8 textDescent; /* Descent of text font in force at the <IMG> */
+ Html_u8 redrawNeeded; /* Need to redraw this image because the image
+ ** content changed. */
+ Html_16 h; /* Actual height of the image */
+ Html_16 w; /* Actual width of the image */
+ Html_16 ascent; /* How far image extends above "y" */
+ Html_16 descent; /* How far image extends below "y" */
+ Html_16 x; /* X coordinate of left edge of the image */
+ Html_32 y; /* Y coordinate of image baseline */
+ char *zAlt; /* Alternative text */
+ HtmlImage *pImage; /* Corresponding HtmlImage structure */
+ HtmlElement *pNext; /* Next markup using the same HtmlImage structure */
+};
+typedef struct HtmlInput HtmlInput;
+struct HtmlInput {
+ HtmlMarkupElement markup;
+ HtmlElement *pForm; /* The <FORM> to which this belongs */
+ HtmlElement *pNext; /* Next element in a list of all input elements */
+ Tk_Window tkwin; /* The window that implements this control */
+ HtmlWidget *htmlPtr; /* The whole widget. Needed by geometry callbacks */
+ HtmlElement *pEnd; /* End tag for <TEXTAREA>, etc. */
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 padLeft; /* Extra padding on left side of the control */
+ Html_u8 align; /* One of the IMAGE_ALIGN_xxx types */
+ Html_u8 textAscent; /* Ascent for the current font */
+ Html_u8 textDescent; /* descent for the current font */
+ Html_u8 type; /* What type of input is this? */
+ Html_u8 sized; /* True if this input has been sized already */
+ Html_u16 cnt; /* Used to derive widget name. 0 if no widget */
+};
+typedef struct HtmlForm HtmlForm;
+struct HtmlForm {
+ HtmlMarkupElement markup;
+ Html_u16 id; /* Unique number assigned to this form */
+};
+typedef struct HtmlHr HtmlHr;
+struct HtmlHr {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 is3D; /* Is it drawn 3D? */
+};
+typedef struct HtmlAnchor HtmlAnchor;
+struct HtmlAnchor {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Top edge for this element */
+};
+typedef struct HtmlScript HtmlScript;
+struct HtmlScript {
+ HtmlMarkupElement markup;
+ char *zScript; /* Complete text of this script */
+ int nScript; /* Number of characters of text */
+};
+typedef struct HtmlBlock HtmlBlock;
+struct HtmlBlock {
+ HtmlBaseElement base; /* Superclass. Must be first */
+ char *z; /* Space to hold text when n>0 */
+ int top, bottom; /* Extremes of y coordinates */
+ Html_u16 left, right; /* Left and right boundry of this object */
+ Html_u16 n; /* Number of characters in z[] */
+ HtmlBlock *pPrev, *pNext; /* Linked list of all Blocks */
+};
+union HtmlElement {
+ HtmlElement *pNext;
+ HtmlBaseElement base;
+ HtmlTextElement text;
+ HtmlSpaceElement space;
+ HtmlMarkupElement markup;
+ HtmlCell cell;
+ HtmlTable table;
+ HtmlRef ref;
+ HtmlLi li;
+ HtmlListStart list;
+ HtmlImageMarkup image;
+ HtmlInput input;
+ HtmlForm form;
+ HtmlHr hr;
+ HtmlAnchor anchor;
+ HtmlScript script;
+ HtmlBlock block;
+};
+char *HtmlMarkupArg(HtmlElement *p,const char *tag,char *zDefault);
+#define FontSize(X) ((X)%N_FONT_SIZE)
+#define HtmlFree(A) Tcl_Free((char*)(A))
+void HtmlTPCantHappen(const char *zFile,int line);
+#if defined(COVERAGE_TEST)
+# define CANT_HAPPEN HtmlTPCantHappen(__FILE__,__LINE__)
+#endif
+#if !(defined(COVERAGE_TEST))
+# define CANT_HAPPEN
+#endif
+#define Html_EndTABLE 130
+#define Html_EndTR 140
+#define Html_TR 139
+#define Html_EndTH 136
+#define Html_TH 135
+#define Html_EndTD 132
+#define Html_TD 131
+#define Html_TABLE 129
+#define Html_TypeCount 151
+HtmlStyle HtmlPopStyleStack(HtmlWidget *htmlPtr,int tag);
+/*#define HtmlAlloc(A) ((void*)Tcl_Alloc(A))*/
+void* HtmlAlloc(size_t);
+typedef struct HtmlStyleStack HtmlStyleStack;
+struct HtmlStyleStack {
+ HtmlStyleStack *pNext; /* Next style on the stack */
+ int type; /* A markup that ends this style. Ex: Html_EndEM */
+ HtmlStyle style; /* The currently active style. */
+};
+#define ALIGN_Left 1
+#define COLOR_Background 4 /* Default background color */
+#define COLOR_Normal 0 /* Index for normal color (black) */
+#define NormalFont(X) (X)
+typedef struct HtmlIndex HtmlIndex;
+struct HtmlIndex {
+ HtmlElement *p; /* The token containing the character */
+ int i; /* Index of the character */
+};
+typedef struct HtmlLayoutContext HtmlLayoutContext;
+typedef struct HtmlMargin HtmlMargin;
+struct HtmlLayoutContext {
+ HtmlWidget *htmlPtr; /* The html widget undergoing layout */
+ HtmlElement *pStart; /* Start of elements to layout */
+ HtmlElement *pEnd; /* Stop when reaching this element */
+ int headRoom; /* Extra space wanted above this line */
+ int top; /* Absolute top of drawing area */
+ int bottom; /* Bottom of previous line */
+ int left, right; /* Left and right extremes of drawing area */
+ int pageWidth; /* Width of the layout field, including
+ ** the margins */
+ int maxX, maxY; /* Maximum X and Y values of paint */
+ HtmlMargin *leftMargin; /* Stack of left margins */
+ HtmlMargin *rightMargin; /* Stack of right margins */
+};
+#define N_FONT_FAMILY 8
+#define N_FONT (N_FONT_FAMILY*N_FONT_SIZE)
+#define N_COLOR 16 /* Total number of colors */
+typedef struct GcCache GcCache;
+struct GcCache {
+ GC gc; /* The graphics context */
+ Html_u8 font; /* Font used for this context */
+ Html_u8 color; /* Color used for this context */
+ Html_u8 index; /* Index used for LRU replacement */
+};
+#define N_CACHE_GC 16
+struct HtmlWidget {
+ Tk_Window tkwin; /* The main window for this widget */
+ Tk_Window clipwin; /* The clipping window in which all text is
+ ** rendered. */
+ char *zClipwin; /* Name of the clipping window. */
+ Display *display; /* The X11 Server that contains tkwin */
+ Tcl_Interp *interp; /* The interpreter in which the widget lives */
+ char *zCmdName; /* Name of the command */
+ HtmlElement *pFirst; /* First HTML token on a list of them all */
+ HtmlElement *pLast; /* Last HTML token on the list */
+ int nToken; /* Number of HTML tokens on the list.
+ * Html_Block tokens don't count. */
+ HtmlElement *lastSized; /* Last HTML element that has been sized */
+ HtmlElement *nextPlaced; /* Next HTML element that needs to be
+ * positioned on canvas. */
+ HtmlBlock *firstBlock; /* List of all HtmlBlock tokens */
+ HtmlBlock *lastBlock; /* Last HtmlBlock in the list */
+ HtmlElement *firstInput; /* First <INPUT> element */
+ HtmlElement *lastInput; /* Last <INPUT> element */
+ int nInput; /* The number of <INPUT> elements */
+ int nForm; /* The number of <FORM> elements */
+ int varId; /* Used to construct a unique name for a
+ ** global array used by <INPUT> elements */
+
+ /*
+ * Information about the selected region of text
+ */
+ HtmlIndex selBegin; /* Start of the selection */
+ HtmlIndex selEnd; /* End of the selection */
+ HtmlBlock *pSelStartBlock; /* Block in which selection starts */
+ Html_16 selStartIndex; /* Index in pSelStartBlock of first selected
+ * character */
+ Html_16 selEndIndex; /* Index of last selecte char in pSelEndBlock */
+ HtmlBlock *pSelEndBlock; /* Block in which selection ends */
+
+ /*
+ * Information about the insertion cursor
+ */
+ int insOnTime; /* How long the cursor states one (millisec) */
+ int insOffTime; /* How long it is off (milliseconds) */
+ int insStatus; /* Is it visible? */
+ Tcl_TimerToken insTimer; /* Timer used to flash the insertion cursor */
+ HtmlIndex ins; /* The insertion cursor position */
+ HtmlBlock *pInsBlock; /* The HtmlBlock containing the cursor */
+ int insIndex; /* Index in pInsBlock of the cursor */
+
+ /*
+ * The following fields hold state information used by
+ * the tokenizer.
+ */
+ char *zText; /* Complete text of the unparsed HTML */
+ int nText; /* Number of characters in zText */
+ int nAlloc; /* Space allocated for zText */
+ int nComplete; /* How much of zText has actually been
+ * converted into tokens */
+ int iCol; /* The column in which zText[nComplete]
+ * occurs. Used to resolve tabs in input */
+ int iPlaintext; /* If not zero, this is the token type that
+ * caused us to go into plaintext mode. One
+ * of Html_PLAINTEXT, Html_LISTING or
+ * Html_XMP */
+ HtmlScript *pScript; /* <SCRIPT> currently being parsed */
+ char *zHandler[Html_TypeCount]; /* If not NULL, this is a TCL routine that
+ * is used to process tokens of the given
+ * type */
+ /*
+ * These fields hold state information used by the HtmlAddStyle routine.
+ * We have to store this state information here since HtmlAddStyle
+ * operates incrementally. This information must be carried from
+ * one incremental execution to the next.
+ */
+ HtmlStyleStack *styleStack; /* The style stack */
+ int paraAlignment; /* Justification associated with <p> */
+ int rowAlignment; /* Justification associated with <tr> */
+ int anchorFlags; /* Style flags associated with <A>...</A> */
+ int inDt; /* Style flags associated with <DT>...</DT> */
+ int inTr; /* True if within <tr>..</tr> */
+ int inTd; /* True if within <td>..</td> or <th>..</th> */
+ HtmlElement *anchorStart; /* Most recent <a href=...> */
+ HtmlElement *formStart; /* Most recent <form> */
+ HtmlElement *formElemStart; /* Most recent <textarea> or <select> */
+ HtmlElement *innerList; /* The inner most <OL> or <UL> */
+
+ /*
+ * These fields are used to hold the state of the layout engine.
+ * Because the layout is incremental, this state must be held for
+ * the life of the widget.
+ */
+ HtmlLayoutContext layoutContext;
+
+ /*
+ * Information used when displaying the widget:
+ */
+ Tk_3DBorder border; /* Background color */
+ int borderWidth; /* Width of the border. */
+ int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ int inset; /* Total width of highlight and 3-D border */
+ Tk_Font aFont[N_FONT]; /* Information about all screen fonts */
+ char fontValid[(N_FONT+7)/8]; /* If bit N%8 of work N/8 of this field is 0
+ * if aFont[N] needs to be reallocated before
+ * being used. */
+ XColor *apColor[N_COLOR]; /* Information about all colors */
+ int colorUsed; /* bit N is 1 if color N is in use. Only
+ ** applies to colors that aren't predefined */
+ int iDark[N_COLOR]; /* Dark 3D shadow of color K is iDark[K] */
+ int iLight[N_COLOR]; /* Light 3D shadow of color K is iLight[K] */
+ XColor *fgColor; /* Color of normal text. apColor[0] */
+ XColor *newLinkColor; /* Color of unvisitied links. apColor[1] */
+ XColor *oldLinkColor; /* Color of visitied links. apColor[2] */
+ XColor *selectionColor; /* Background color for selections */
+ GcCache aGcCache[N_CACHE_GC]; /* A cache of GCs for general use */
+ int lastGC; /* Index of recently used GC */
+ HtmlImage *imageList; /* A list of all images */
+ int width, height; /* User-requested size of the usable drawing
+ * area, in pixels. Borders and padding
+ * make the actual window a little larger */
+ int realWidth, realHeight; /* The actual physical size of tkwin as
+ * reported in the most recent ConfigureNotify
+ * event. */
+ int padx, pady; /* Separation between the edge of the window
+ * and rendered HTML. */
+ int underlineLinks; /* TRUE if we should underline hyperlinks */
+
+ /* Information about the selection
+ */
+ int exportSelection; /* True if the selection is automatically
+ * exported to the clipboard */
+
+ /* Callback commands. The HTML parser will invoke callbacks from time
+ ** to time to find out information it needs to complete formatting of
+ ** the document. The following fields define the callback commands.
+ */
+ char *zIsVisited; /* Command to tell if a hyperlink has already
+ ** been visited */
+ char *zGetImage; /* Command to get an image from a URL */
+ char *zFrameCommand; /* Command for handling <frameset> markup */
+ char *zAppletCommand; /* Command to process applets */
+ char *zResolverCommand; /* Command to resolve URIs */
+ char *zFormCommand; /* When user presses Submit */
+ char *zHyperlinkCommand; /* Invoked when a hyperlink is clicked */
+ char *zFontCommand; /* Invoked to find font names */
+ char *zScriptCommand; /* Invoked for each <SCRIPT> markup */
+
+ /*
+ * Miscellaneous information:
+ */
+ int tableRelief; /* 3d effects on <TABLE> */
+ int ruleRelief; /* 3d effects on <HR> */
+ char *zBase; /* The base URI */
+ char *zBaseHref; /* zBase as modified by <BASE HREF=..> markup */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ char *takeFocus; /* Value of -takefocus option; not used in
+ * the C code, but used by keyboard traversal
+ * scripts. Malloc'ed, but may be NULL. */
+ char *yScrollCmd; /* Command prefix for communicating with
+ * vertical scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ char *xScrollCmd; /* Command prefix for communicating with
+ * horizontal scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ int xOffset, yOffset; /* Current scroll position. These form the
+ * coordinate in the virtual canvas that
+ * corresponds to (0,0) on the physical screen
+ * in window tkwin */
+ int maxX, maxY; /* Maximum extent of any "paint" that appears
+ * on the virtual canvas. Used to compute
+ * scrollbar positions. */
+ int dirtyLeft, dirtyTop; /* Top left corner of region to redraw. These
+ * are physical screen coordinates relative to
+ * clipwin, not tkwin. */
+ int dirtyRight, dirtyBottom; /* Bottom right corner of region to redraw */
+ int locked; /* Number of locks on this structure. Don't
+ ** delete until it reaches zero. */
+ int flags; /* Various flags; see below for
+ * definitions. */
+};
+struct HtmlImage {
+ HtmlWidget *htmlPtr; /* The owner of this image */
+ Tk_Image image; /* The Tk image token */
+ Html_32 w; /* Requested width of this image (0 if none) */
+ Html_32 h; /* Requested height of this image (0 if none) */
+ char *zUrl; /* The URL for this image. */
+ char *zWidth, *zHeight; /* Width and height in the <img> markup. */
+ HtmlImage *pNext; /* Next image on the list */
+ HtmlElement *pList; /* List of all <IMG> markups that use this
+ ** same image */
+};
+struct HtmlMargin {
+ int indent; /* Size of the current margin */
+ int bottom; /* Y value at which this margin expires */
+ int tag; /* Markup that will cancel this margin */
+ HtmlMargin *pNext; /* Previous margin */
+};
diff --git a/tkhtml1/src/htmltable.c b/tkhtml1/src/htmltable.c
new file mode 100644
index 0000000..98bbb48
--- /dev/null
+++ b/tkhtml1/src/htmltable.c
@@ -0,0 +1,1175 @@
+/*
+** Routines for doing layout of HTML tables
+**
+** Copyright (C) 1997-2000 D. Richard Hipp
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** drh@acm.org
+** http://www.hwaci.com/drh/
+*/
+#include <tk.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include "htmltable.h"
+
+/*
+** Default values for various table style parameters
+*/
+#define DFLT_BORDER 0
+#define DFLT_CELLSPACING_3D 5
+#define DFLT_CELLSPACING_FLAT 0
+#define DFLT_CELLPADDING 2
+#define DFLT_HSPACE 0
+#define DFLT_VSPACE 0
+
+#if INTERFACE
+/*
+** Set parameter A to the maximum of A and B.
+*/
+#define SETMAX(A,B) if( (A)<(B) ){ (A) = (B); }
+#define MAX(A,B) ((A)<(B)?(B):(A))
+#endif
+
+/*
+** Return the appropriate cell spacing for the given table.
+*/
+static int CellSpacing(HtmlWidget *htmlPtr, HtmlElement *pTable){
+ char *z;
+ int relief;
+ int cellSpacing;
+
+ z = HtmlMarkupArg(pTable, "cellspacing", 0);
+ if( z==0 ){
+ relief = htmlPtr->tableRelief;
+ if( relief==TK_RELIEF_RAISED || relief==TK_RELIEF_SUNKEN ){
+ cellSpacing = DFLT_CELLSPACING_3D;
+ }else{
+ cellSpacing = DFLT_CELLSPACING_FLAT;
+ }
+ }else{
+ cellSpacing = atoi(z);
+ }
+ return cellSpacing;
+}
+
+/* Forward declaration */
+static HtmlElement *MinMax(HtmlWidget*, HtmlElement *, int *, int *, int);
+
+/* pStart points to a <table>. Compute the number of columns, the
+** minimum and maximum size for each column and the overall minimum
+** and maximum size for this table and store these value in the
+** pStart structure. Return a pointer to the </table> element,
+** or to NULL if there is no </table>.
+**
+** The min and max size for column N (where the leftmost column has
+** N==1) is pStart->minW[1] and pStart->maxW[1]. The pStart->minW[0]
+** and pStart->maxW[0] entries contain the minimum and maximum widths
+** of the whole table, including any cell padding, cell spacing,
+** border width and "hspace". The values of pStart->minW[I] for I>=1
+** do not contain any cell padding, cell spacing or border width.
+** Only pStart->minW[0] contains these extra spaces.
+**
+** The back references from </table>, </tr>, </td> and </th> back to
+** the <table> markup are also filled in. And for each <td> and <th>
+** markup, the pTable and pEnd fields are set to their proper values.
+*/
+static HtmlElement *TableDimensions(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ HtmlElement *pStart, /* The <table> markup */
+ int lineWidth /* Total widget available to the table */
+){
+ HtmlElement *p; /* Element being processed */
+ HtmlElement *pNext; /* Next element to process */
+ int iCol = 0; /* Current column number. 1..N */
+ int iRow = 0; /* Current row number */
+ int inRow = 0; /* True if in between <TR> and </TR> */
+ int i, j; /* Loop counters */
+ int n; /* Number of columns */
+ int minW, maxW, requestedW; /* min, max, requested width for a cell */
+ int noWrap; /* true for NOWRAP cells */
+ int colspan; /* Column span for the current cell */
+ int rowspan; /* Row span for the current cell */
+ char *z; /* Value of a <table> parameter */
+ int cellSpacing; /* Value of CELLSPACING parameter */
+ int cellPadding; /* Value of CELLPADDING parameter */
+ int tbw; /* Width of border around whole table */
+ int cbw; /* Width of border around one cell */
+ int hspace; /* Value of HSPACE parameter */
+ int separation; /* Space between columns */
+ int margin; /* Space between left margin and 1st col */
+ int availWidth; /* Part of lineWidth still available */
+ int maxTableWidth; /* Amount of lineWidth available to table*/
+ int fromAbove[HTML_MAX_COLUMNS+1]; /* Cell above extends thru this row */
+ int min0span[HTML_MAX_COLUMNS+1]; /* Min for colspan=0 cells */
+ int max0span[HTML_MAX_COLUMNS+1]; /* Max for colspan=0 cells */
+ int reqW[HTML_MAX_COLUMNS+1]; /* Requested width for each column */
+
+ /* colMin[A][B] is the absolute minimum width of all columns between
+ ** A+1 and B+1. colMin[B][A] is the requested width of columns between
+ ** A+1 and B+1. This information is used to add in the constraints imposed
+ ** by <TD COLSPAN=N> markup where N>=2.
+ */
+ int colMin[HTML_MAX_COLUMNS+1][HTML_MAX_COLUMNS+1];
+# define ColMin(A,B) colMin[(A)-1][(B)-1]
+# define ColReq(A,B) colMin[(B)-1][(A)-1]
+
+ if( pStart==0 || pStart->base.type!=Html_TABLE ){
+ TestPoint(0);
+ return pStart;
+ }
+ TRACE_PUSH(HtmlTrace_Table1);
+ TRACE(HtmlTrace_Table1, ("Starting TableDimensions..\n"));
+ pStart->table.nCol = 0;
+ pStart->table.nRow = 0;
+ z = HtmlMarkupArg(pStart, "border", 0);
+ if( z && *z==0 ) z = "2";
+ tbw = pStart->table.borderWidth = z ? atoi(z) : DFLT_BORDER;
+ cbw = tbw>0;
+ z = HtmlMarkupArg(pStart, "cellpadding", 0);
+ cellPadding = z ? atoi(z) : DFLT_CELLPADDING;
+ cellSpacing = CellSpacing(htmlPtr, pStart);
+#ifdef DEBUG
+ /* The HtmlTrace_Table4 flag causes tables to be draw with borders
+ ** of 2, cellPadding of 5 and cell spacing of 2. This makes the
+ ** table clearly visible. Useful for debugging. */
+ if( HtmlTraceMask & HtmlTrace_Table4 ){
+ tbw = pStart->table.borderWidth = 2;
+ cbw = 1;
+ cellPadding = 5;
+ cellSpacing = 2;
+ pStart->base.style.bgcolor = COLOR_Background;
+ }
+#endif
+ separation = cellSpacing + 2*(cellPadding + cbw);
+ margin = tbw + cellSpacing + cbw + cellPadding;
+ z = HtmlMarkupArg(pStart, "hspace", 0);
+ hspace = z ? atoi(z) : DFLT_HSPACE;
+
+ for(p=pStart->pNext; p && p->base.type!=Html_EndTABLE; p=pNext){
+ pNext = p->pNext;
+ switch( p->base.type ){
+ case Html_EndTD:
+ case Html_EndTH:
+ case Html_EndTABLE:
+ p->ref.pOther = pStart;
+ TestPoint(0);
+ break;
+ case Html_EndTR:
+ p->ref.pOther = pStart;
+ inRow = 0;
+ TestPoint(0);
+ break;
+ case Html_TR:
+ p->ref.pOther = pStart;
+ iRow++;
+ pStart->table.nRow++;
+ iCol = 0;
+ inRow = 1;
+ maxTableWidth = availWidth = lineWidth - 2*margin;
+ TestPoint(0);
+ break;
+ case Html_CAPTION:
+ while( p && p->base.type!=Html_EndTABLE
+ && p->base.type!=Html_EndCAPTION ){
+ p = p->pNext;
+ TestPoint(0);
+ }
+ break;
+ case Html_TD:
+ case Html_TH:
+ if( !inRow ){
+ /* If the <TR> markup is omitted, insert it. */
+ HtmlElement *pNew = HtmlAlloc( sizeof(HtmlRef) );
+ if( pNew==0 ) break;
+ memset(pNew, 0, sizeof(HtmlRef));
+ pNew->base = p->base;
+ pNew->base.pNext = p;
+ pNew->base.type = Html_TR;
+ pNew->base.count = 0;
+ p->base.pPrev->base.pNext = pNew;
+ p->base.pPrev = pNew;
+ pNext = pNew;
+ break;
+ }
+ do{
+ iCol++;
+ }while( iCol <= pStart->table.nCol && fromAbove[iCol] > iRow );
+ p->cell.pTable = pStart;
+ colspan = p->cell.colspan;
+ if( colspan==0 ){
+ colspan = 1;
+ }
+ if( iCol + colspan - 1 > pStart->table.nCol ){
+ int nCol = iCol + colspan - 1;
+ if( nCol > HTML_MAX_COLUMNS ){
+ nCol = HTML_MAX_COLUMNS;
+ }
+ for(i=pStart->table.nCol+1; i<=nCol; i++){
+ fromAbove[i] = 0;
+ pStart->table.minW[i] = 0;
+ pStart->table.maxW[i] = 0;
+ min0span[i] = 0;
+ max0span[i] = 0;
+ reqW[i] = 0;
+ for(j=1; j<i; j++){
+ ColMin(j,i) = 0;
+ ColReq(j,i) = 0;
+ }
+ }
+ pStart->table.nCol = nCol;
+ }
+ noWrap = HtmlMarkupArg(p, "nowrap", 0)!=0;
+ pNext = MinMax(htmlPtr, p, &minW, &maxW, availWidth);
+ p->cell.pEnd = pNext;
+ if( (z = HtmlMarkupArg(p, "width", 0))!=0 ){
+ for(i=0; isdigit(z[i]); i++){}
+ if( strcmp(z,"*")==0 ){
+ requestedW = availWidth;
+ }else if( z[i]==0 ){
+ requestedW = atoi(z);
+ }else if( z[i]=='%' ){
+ /* requestedW = (atoi(z)*availWidth + 99)/100; */
+ requestedW = (atoi(z)*maxTableWidth + 99)/100;
+ }
+ }else{
+ requestedW = 0;
+ }
+ TRACE(HtmlTrace_Table1,
+ ("Row %d Column %d: min=%d max=%d req=%d stop at %s\n",
+ iRow,iCol,minW,maxW,requestedW, HtmlTokenName(p->cell.pEnd)));
+ if( noWrap ){
+ minW = maxW;
+ }
+ if( iCol + p->cell.colspan <= HTML_MAX_COLUMNS ){
+ int min = 0;
+ if( p->cell.colspan==0 ){
+ SETMAX( min0span[iCol], minW );
+ SETMAX( max0span[iCol], maxW );
+ min = min0span[iCol] + separation;
+ }else if( colspan==1 ){
+ SETMAX( pStart->table.minW[iCol], minW );
+ SETMAX( pStart->table.maxW[iCol], maxW );
+ SETMAX( reqW[iCol], requestedW );
+ min = pStart->table.minW[iCol] + separation;
+ }else{
+ int n = p->cell.colspan;
+ SETMAX( ColMin(iCol,iCol+n-1), minW);
+ SETMAX( ColReq(iCol,iCol+n-1), requestedW);
+ min = minW + separation;
+#if 0
+ maxW = (maxW + (n - 1)*(1-separation))/n;
+ for(i=iCol; i<iCol + n && i<HTML_MAX_COLUMNS; i++){
+ SETMAX( pStart->table.maxW[i], maxW );
+ }
+#endif
+ }
+ availWidth -= min;
+ }
+ rowspan = p->cell.rowspan;
+ if( rowspan==0 ){
+ rowspan = LARGE_NUMBER;
+ }
+ if( rowspan>1 ){
+ for(i=iCol; i<iCol + p->cell.colspan && i<HTML_MAX_COLUMNS; i++){
+ fromAbove[i] = iRow + rowspan;
+ }
+ }
+ if( p->cell.colspan > 1 ){
+ iCol += p->cell.colspan - 1;
+ }else if( p->cell.colspan==0 ){
+ iCol = HTML_MAX_COLUMNS + 1;
+ }
+ break;
+ }
+ }
+
+#ifdef DEBUG
+ if( HtmlTraceMask & HtmlTrace_Table6 ){
+ char *zSpace = "";
+ TRACE_INDENT;
+ for(i=1; i<=pStart->table.nCol; i++){
+ printf("%s%d:%d..%d",zSpace,i,
+ pStart->table.minW[i],pStart->table.maxW[i]);
+ if( reqW[i]>0 ){
+ printf("(w=%d)",reqW[i]);
+ }
+ zSpace = " ";
+ }
+ printf("\n");
+ for(i=1; i<pStart->table.nCol; i++){
+ for(j=i+1; j<=pStart->table.nCol; j++){
+ if( ColMin(i,j)>0 ){
+ TRACE_INDENT;
+ printf("ColMin(%d,%d) = %d\n", i, j, ColMin(i,j));
+ }
+ if( ColReq(i,j)>0 ){
+ TRACE_INDENT;
+ printf("ColReq(%d,%d) = %d\n", i, j, ColReq(i,j));
+ }
+ }
+ }
+ }
+#endif
+
+ /* Compute the min and max width of each column
+ */
+ for(i=1; i<=pStart->table.nCol; i++){
+ int sumMin, sumReq, sumMax;
+
+ /* Reduce the max[] field to N for columns that have "width=N" */
+ if( reqW[i]>0 ){
+ pStart->table.maxW[i] = MAX(pStart->table.minW[i],reqW[i]);
+ }
+
+ /* Expand the width of columns marked with "colspan=0".
+ */
+ if( min0span[i]>0 || max0span[i]>0 ){
+ int n = pStart->table.nCol - i + 1;
+ minW = (min0span[i] + (n - 1)*(1-separation))/n;
+ maxW = (max0span[i] + (n - 1)*(1-separation))/n;
+ for(j=i; j<=pStart->table.nCol; j++){
+ SETMAX( pStart->table.minW[j], minW );
+ SETMAX( pStart->table.maxW[j], maxW );
+ }
+ }
+
+ /* Expand the minW[] of columns to accomodate "colspan=N" constraints.
+ ** The minW[] is expanded up to the maxW[] first. Then all the maxW[]s
+ ** are expanded in proportion to their sizes. The same thing occurs
+ ** for reqW[]s.
+ */
+ sumReq = reqW[i];
+ sumMin = pStart->table.minW[i];
+ sumMax = pStart->table.maxW[i];
+ for(j=i-1; j>=1; j--){
+ int cmin, creq;
+ sumMin += pStart->table.minW[j];
+ sumMax += pStart->table.maxW[j];
+ sumReq += reqW[i];
+ cmin = ColMin(j,i);
+ if( cmin>sumMin ){
+ int k;
+ double scale;
+ int *tminW = pStart->table.minW;
+ int *tmaxW = pStart->table.maxW;
+ if( sumMin<sumMax ){
+ scale = (double)(cmin - sumMin)/(double)(sumMax - sumMin);
+ for(k=j; k<=i; k++){
+ sumMin -= tminW[k];
+ tminW[k] = (tmaxW[k] - tminW[k])*scale + tminW[k];
+ sumMin += tminW[k];
+ }
+ }else if( sumMin>0 ){
+ scale = (double)cmin/(double)sumMin;
+ for(k=j; k<=i; k++){
+ sumMin -= tminW[k];
+ tminW[k] = tmaxW[k] = tminW[k]*scale;
+ sumMin += tminW[k];
+ }
+ }else{
+ int unit = cmin/(i-j+1);
+ for(k=j; k<=i; k++){
+ tminW[k] = tmaxW[k] = unit;
+ sumMin += tminW[k];
+ }
+ }
+ }
+ creq = ColReq(j,i);
+ if( creq>sumReq ){
+ int k;
+ double scale;
+ int *tmaxW = pStart->table.maxW;
+ if( sumReq<sumMax ){
+ scale = (double)(creq - sumReq)/(double)(sumMax - sumReq);
+ for(k=j; k<=i; k++){
+ sumReq -= reqW[k];
+ reqW[k] = (tmaxW[k] - reqW[k])*scale + reqW[k];
+ sumReq += reqW[k];
+ }
+ }else if( sumReq>0 ){
+ scale = (double)creq/(double)sumReq;
+ for(k=j; k<=i; k++){
+ sumReq -= reqW[k];
+ reqW[k] = reqW[k]*scale;
+ sumReq += reqW[k];
+ }
+ }else{
+ int unit = creq/(i-j+1);
+ for(k=j; k<=i; k++){
+ reqW[k] = unit;
+ sumReq += reqW[k];
+ }
+ }
+ }
+ }
+ }
+
+#ifdef DEBUG
+ if( HtmlTraceMask & HtmlTrace_Table6 ){
+ char *zSpace = "";
+ TRACE_INDENT;
+ for(i=1; i<=pStart->table.nCol; i++){
+ printf("%s%d:%d..%d",zSpace,i,
+ pStart->table.minW[i],pStart->table.maxW[i]);
+ if( reqW[i]>0 ){
+ printf("(w=%d)",reqW[i]);
+ }
+ zSpace = " ";
+ }
+ printf("\n");
+ }
+#endif
+
+ /* Compute the min and max width of the whole table
+ */
+ n = pStart->table.nCol;
+ requestedW = tbw*2 + (n+1)*cellSpacing + n*2*(cellPadding + cbw);
+ pStart->table.minW[0] = requestedW;
+ pStart->table.maxW[0] = requestedW;
+ for(i=1; i<=pStart->table.nCol; i++){
+ pStart->table.minW[0] += pStart->table.minW[i];
+ pStart->table.maxW[0] += pStart->table.maxW[i];
+ requestedW += MAX(reqW[i], pStart->table.minW[i]);
+ }
+
+ /* Figure out how wide to draw the table */
+ z = HtmlMarkupArg(pStart, "width", 0);
+ if( z ){
+ int len = strlen(z);
+ int totalWidth;
+ if( len>0 && z[len-1]=='%' ){
+ totalWidth = (atoi(z) * lineWidth)/100;
+ }else{
+ totalWidth = atoi(z);
+ }
+ SETMAX( requestedW, totalWidth );
+ }
+ if( lineWidth && (requestedW > lineWidth) ){
+ TRACE(HtmlTrace_Table5,("RequestedW reduced to lineWidth: %d -> %d\n",
+ requestedW, lineWidth));
+ requestedW = lineWidth;
+ }
+ if( requestedW > pStart->table.minW[0] ){
+ float scale;
+ int *tminW = pStart->table.minW;
+ int *tmaxW = pStart->table.maxW;
+ TRACE(HtmlTrace_Table5,
+ ("Expanding table minW from %d to %d. (reqW=%d width=%s)\n",
+ tminW[0], requestedW, requestedW, z));
+ if( tmaxW[0] > tminW[0] ){
+ scale = (double)(requestedW - tminW[0]) / (double)(tmaxW[0] - tminW[0]);
+ for(i=1; i<=pStart->table.nCol; i++){
+ tminW[i] += (tmaxW[i] - tminW[i]) * scale;
+ SETMAX(tmaxW[i], tminW[i]);
+ }
+ }else if( tminW[0]>0 ){
+ scale = requestedW/(double)tminW[0];
+ for(i=1; i<=pStart->table.nCol; i++){
+ tminW[i] *= scale;
+ tmaxW[i] *= scale;
+ }
+ }else if( pStart->table.nCol>0 ){
+ int unit = (requestedW - margin)/pStart->table.nCol - separation;
+ if( unit<0 ) unit = 0;
+ for(i=1; i<=pStart->table.nCol; i++){
+ tminW[i] = tmaxW[i] = unit;
+ }
+ }else{
+ tminW[0] = tmaxW[0] = requestedW;
+ }
+ pStart->table.minW[0] = requestedW;
+ SETMAX( pStart->table.maxW[0], requestedW );
+ }
+
+#ifdef DEBUG
+ if( HtmlTraceMask & HtmlTrace_Table5 ){
+ TRACE_INDENT;
+ printf("Start with %s and ", HtmlTokenName(pStart));
+ printf("end with %s\n", HtmlTokenName(p));
+ TRACE_INDENT;
+ printf("nCol=%d minWidth=%d maxWidth=%d\n",
+ pStart->table.nCol, pStart->table.minW[0], pStart->table.maxW[0]);
+ for(i=1; i<=pStart->table.nCol; i++){
+ TRACE_INDENT;
+ printf("Column %d minWidth=%d maxWidth=%d\n",
+ i, pStart->table.minW[i], pStart->table.maxW[i]);
+ }
+ }
+#endif
+
+ TRACE(HtmlTrace_Table1,
+ ("Result of TableDimensions: min=%d max=%d nCol=%d\n",
+ pStart->table.minW[0], pStart->table.maxW[0], pStart->table.nCol));
+ TRACE_POP(HtmlTrace_Table1);
+ return p;
+}
+
+/*
+** Given a list of elements, compute the minimum and maximum width needed
+** to render the list. Stop the search at the first element seen that is
+** in the following set:
+**
+** <tr> <td> <th> </tr> </td> </th> </table>
+**
+** Return a pointer to the element that stopped the search, or to NULL
+** if we ran out of data.
+**
+** Sometimes the value returned for both min and max will be larger than
+** the true minimum and maximum. This is rare, and only occurs if the
+** element string contains figures with flow-around text.
+*/
+static HtmlElement *MinMax(
+ HtmlWidget *htmlPtr, /* The Html widget */
+ HtmlElement *p, /* Start the search here */
+ int *pMin, /* Return the minimum width here */
+ int *pMax, /* Return the maximum width here */
+ int lineWidth /* Total width available */
+){
+ int min = 0; /* Minimum width so far */
+ int max = 0; /* Maximum width so far */
+ int indent = 0; /* Amount of indentation (minimum) */
+ int obstacle = 0; /* Possible obstacles in the margin */
+ int x1 = 0; /* Length of current line assuming maximum length */
+ int x2 = 0; /* Length of current line assuming minimum length */
+ int go = 1; /* Change to 0 to stop the loop */
+ HtmlElement *pNext; /* Next element in the list */
+
+ for(p=p->pNext; go && p; p = pNext){
+ pNext = p->pNext;
+ switch( p->base.type ){
+ case Html_Text:
+ x1 += p->text.w;
+ x2 += p->text.w;
+ if( p->base.style.flags & STY_Preformatted ){
+ SETMAX( min, x1 );
+ SETMAX( max, x1 );
+ }else{
+ SETMAX( min, x2 );
+ SETMAX( max, x1 );
+ }
+ break;
+ case Html_Space:
+ if( p->base.style.flags & STY_Preformatted ){
+ if( p->base.flags & HTML_NewLine ){
+ x1 = x2 = indent;
+ }else{
+ x1 += p->space.w * p->base.count;
+ x2 += p->space.w * p->base.count;
+ }
+ }else if( p->base.style.flags & STY_NoBreak ){
+ if( x1>indent ){ x1 += p->space.w; TestPoint(0);}
+ if( x2>indent ){ x2 += p->space.w; TestPoint(0);}
+ }else{
+ if( x1>indent ){ x1 += p->space.w; TestPoint(0);}
+ x2 = indent;
+ }
+ break;
+ case Html_IMG:
+ switch( p->image.align ){
+ case IMAGE_ALIGN_Left:
+ case IMAGE_ALIGN_Right:
+ obstacle += p->image.w;
+ x1 = obstacle + indent;
+ x2 = indent;
+ SETMAX( min, x2 );
+ SETMAX( min, p->image.w );
+ SETMAX( max, x1 );
+ break;
+ default:
+ x1 += p->image.w;
+ x2 += p->image.w;
+ if( p->base.style.flags & STY_Preformatted ){
+ SETMAX( min, x1 );
+ SETMAX( max, x1 );
+ }else{
+ SETMAX( min, x2 );
+ SETMAX( max, x1 );
+ }
+ break;
+ }
+ break;
+ case Html_TABLE:
+ /* pNext = TableDimensions(htmlPtr, p, lineWidth-indent); */
+ pNext = TableDimensions(htmlPtr, p, 0);
+ x1 = p->table.maxW[0] + indent + obstacle;
+ x2 = p->table.minW[0] + indent;
+ SETMAX( max, x1 );
+ SETMAX( min, x2 );
+ x1 = indent + obstacle;
+ x2 = indent;
+ if( pNext && pNext->base.type==Html_EndTABLE ){
+ pNext = pNext->pNext;
+ }
+ break;
+ case Html_UL:
+ case Html_OL:
+ indent += HTML_INDENT;
+ x1 = indent + obstacle;
+ x2 = indent;
+ break;
+ case Html_EndUL:
+ case Html_EndOL:
+ indent -= HTML_INDENT;
+ if( indent < 0 ){ indent = 0; }
+ x1 = indent + obstacle;
+ x2 = indent;
+ break;
+ case Html_BLOCKQUOTE:
+ indent += 2*HTML_INDENT;
+ x1 = indent + obstacle;
+ x2 = indent;
+ break;
+ case Html_EndBLOCKQUOTE:
+ indent -= 2*HTML_INDENT;
+ if( indent < 0 ){ indent = 0; }
+ x1 = indent + obstacle;
+ x2 = indent;
+ break;
+ case Html_APPLET:
+ case Html_INPUT:
+ case Html_SELECT:
+ case Html_EMBED:
+ case Html_TEXTAREA:
+ x1 += p->input.w + p->input.padLeft;
+ if( p->base.style.flags & STY_Preformatted ){
+ SETMAX( min, x1 );
+ SETMAX( max, x1 );
+ x2 += p->input.w + p->input.padLeft;
+ }else{
+ SETMAX( min, indent + p->input.w );
+ SETMAX( max, x1 );
+ x2 = indent;
+ }
+ break;
+ case Html_BR:
+ case Html_P:
+ case Html_EndP:
+ case Html_DIV:
+ case Html_EndDIV:
+ case Html_H1:
+ case Html_EndH1:
+ case Html_H2:
+ case Html_EndH2:
+ case Html_H3:
+ case Html_EndH3:
+ case Html_H4:
+ case Html_EndH4:
+ case Html_H5:
+ case Html_H6:
+ x1 = indent + obstacle;
+ x2 = indent;
+ break;
+ case Html_EndTD:
+ case Html_EndTH:
+ case Html_CAPTION:
+ case Html_EndTABLE:
+ case Html_TD:
+ case Html_TR:
+ case Html_TH:
+ case Html_EndTR:
+ go = 0;
+ break;
+ default:
+ break;
+ }
+ if( !go ){ break; }
+ }
+ *pMin = min;
+ *pMax = max;
+ return p;
+}
+
+/* Vertical alignments:
+*/
+#define VAlign_Unknown 0
+#define VAlign_Top 1
+#define VAlign_Bottom 2
+#define VAlign_Center 3
+#define VAlign_Baseline 4
+
+/*
+** Return the vertical alignment specified by the given element.
+*/
+static int GetVerticalAlignment(HtmlElement *p, int dflt){
+ char *z;
+ int rc;
+ if( p==0 ) return dflt;
+ z = HtmlMarkupArg(p, "valign", 0);
+ if( z==0 ){
+ rc = dflt;
+ TestPoint(0);
+ }else if( stricmp(z,"top")==0 ){
+ rc = VAlign_Top;
+ TestPoint(0);
+ }else if( stricmp(z,"bottom")==0 ){
+ rc = VAlign_Bottom;
+ TestPoint(0);
+ }else if( stricmp(z,"center")==0 ){
+ rc = VAlign_Center;
+ TestPoint(0);
+ }else if( stricmp(z,"baseline")==0 ){
+ rc = VAlign_Baseline;
+ TestPoint(0);
+ }else{
+ rc = dflt;
+ TestPoint(0);
+ }
+ return rc;
+}
+
+/* Do all layout for a single table. Return the </table> element or
+** NULL if the table is unterminated.
+*/
+HtmlElement *HtmlTableLayout(
+ HtmlLayoutContext *pLC, /* The layout context */
+ HtmlElement *pTable /* The <table> element */
+){
+ HtmlElement *pEnd; /* The </table> element */
+ HtmlElement *p; /* For looping thru elements of the table */
+ HtmlElement *pNext; /* Next element in the loop */
+ HtmlElement *pCaption; /* Start of the caption text. The <caption> */
+ HtmlElement *pEndCaption; /* End of the caption. The </caption> */
+ int width; /* Width of the table as drawn */
+ int cellSpacing; /* Value of cellspacing= parameter to <table> */
+ int cellPadding; /* Value of cellpadding= parameter to <table> */
+ int tbw; /* Width of the 3D border around the whole table */
+ int cbw; /* Width of the 3D border around a cell */
+ int pad; /* cellPadding + borderwidth */
+ char *z; /* A string */
+ int leftMargin; /* The left edge of space available for drawing */
+ int lineWidth; /* Total horizontal space available for drawing */
+ int separation; /* Distance between content of columns (or rows) */
+ int i; /* Loop counter */
+ int n; /* Number of columns */
+ int btm; /* Bottom edge of previous row */
+ int iRow; /* Current row number */
+ int iCol; /* Current column number */
+ int colspan; /* Number of columns spanned by current cell */
+ int vspace; /* Value of the vspace= parameter to <table> */
+ int hspace; /* Value of the hspace= parameter to <table> */
+ int rowBottom; /* Bottom edge of content in the current row */
+ int defaultVAlign; /* Default vertical alignment for the current row */
+ char *zAlign; /* Value of the ALIGN= attribute of the <TABLE> */
+#define N HTML_MAX_COLUMNS+1
+ int y[N]; /* Top edge of each cell's content */
+ int x[N]; /* Left edge of each cell's content */
+ int w[N]; /* Width of each cell's content */
+ int ymax[N]; /* Bottom edge of cell's content if valign=top */
+ HtmlElement *apElem[N]; /* The <td> or <th> for each cell in a row */
+ int firstRow[N]; /* First row on which a cell appears */
+ int lastRow[N]; /* Row to which each cell span's */
+ int valign[N]; /* Vertical alignment for each cell */
+ HtmlLayoutContext savedContext; /* Saved copy of the original pLC */
+ HtmlLayoutContext cellContext; /* Used to render a single cell */
+#ifdef TABLE_TRIM_BLANK
+ extern int HtmlLineWasBlank;
+#endif /* TABLE_TRIM_BLANK */
+
+ if( pTable==0 || pTable->base.type!=Html_TABLE ){
+ TestPoint(0);
+ return pTable;
+ }
+ TRACE_PUSH(HtmlTrace_Table2);
+ TRACE(HtmlTrace_Table2, ("Starting TableLayout() at %s\n",
+ HtmlTokenName(pTable)));
+
+ /* Figure how much horizontal space is available for rendering
+ ** this table. Store the answer in lineWidth. leftMargin is
+ ** the left-most X coordinate of the table. btm stores the top-most
+ ** Y coordinate.
+ */
+ HtmlComputeMargins(pLC, &leftMargin, &btm, &lineWidth);
+ TRACE(HtmlTrace_Table2, ("...btm=%d left=%d width=%d\n",
+ btm, leftMargin, lineWidth));
+
+ /* figure out how much space the table wants for each column,
+ ** and in total.. */
+ pEnd = TableDimensions(pLC->htmlPtr, pTable, lineWidth);
+
+ /* If we don't have enough horizontal space to accomodate the minimum table
+ ** width, then try to move down past some obstruction (such as an
+ ** <IMG ALIGN=LEFT>) to give us more room.
+ */
+ if( lineWidth < pTable->table.minW[0] ){
+ HtmlWidenLine(pLC, pTable->table.minW[0], &leftMargin, &btm, &lineWidth);
+ TRACE(HtmlTrace_Table2, ("Widen to btm=%d left=%d width=%d\n",
+ btm, leftMargin, lineWidth));
+ }
+ savedContext = *pLC;
+
+ /* Figure out how wide to draw the table
+ */
+ if( lineWidth < pTable->table.minW[0] ){
+ width = pTable->table.minW[0];
+ }else if( lineWidth <= pTable->table.maxW[0] ){
+ width = lineWidth;
+ }else{
+ width = pTable->table.maxW[0];
+ }
+
+
+ /* Compute the width and left edge position of every column in
+ ** the table */
+ z = HtmlMarkupArg(pTable, "cellpadding", 0);
+ cellPadding = z ? atoi(z) : DFLT_CELLPADDING;
+ cellSpacing = CellSpacing(pLC->htmlPtr, pTable);
+ z = HtmlMarkupArg(pTable, "vspace", 0);
+ vspace = z ? atoi(z) : DFLT_VSPACE;
+ z = HtmlMarkupArg(pTable, "hspace", 0);
+ hspace = z ? atoi(z) : DFLT_HSPACE;
+#ifdef DEBUG
+ if( HtmlTraceMask & HtmlTrace_Table4 ){
+ cellPadding = 5;
+ cellSpacing = 2;
+ if( vspace<2 ) vspace = 2;
+ if( hspace<2 ) hspace = 2;
+ }
+#endif
+ tbw = pTable->table.borderWidth;
+ cbw = (tbw>0);
+ pad = cellPadding + cbw;
+ separation = cellSpacing + 2*pad;
+ x[1] = leftMargin + tbw + cellSpacing + pad;
+ n = pTable->table.nCol;
+ if( n<=0 || pTable->table.maxW[0]<=0 ){
+ /* Abort if the table has no columns at all or if the total width
+ ** of the table is zero or less. */
+ return pEnd;
+ }
+ zAlign = HtmlMarkupArg(pTable, "align", "");
+ if( width < lineWidth ){
+ int align = pTable->base.style.align;
+ if( align==ALIGN_Right || stricmp(zAlign,"right")==0 ){
+ x[1] += lineWidth - width;
+ }else if( align==ALIGN_Center && stricmp(zAlign,"left")!=0 ){
+ x[1] += (lineWidth - width)/2;
+ }
+ }
+ if( width==pTable->table.maxW[0] ){
+ w[1] = pTable->table.maxW[1];
+ for(i=2; i<=n; i++){
+ w[i] = pTable->table.maxW[i];
+ x[i] = x[i-1] + w[i-1] + separation;
+ TestPoint(0);
+ }
+ }else if( width > pTable->table.maxW[0] ){
+ int *tmaxW = pTable->table.maxW;
+ double scale = ((double)width)/ (double)tmaxW[0];
+ w[1] = tmaxW[1] * scale;
+ for(i=2; i<=n; i++){
+ w[i] = tmaxW[i] * scale;
+ x[i] = x[i-1] + w[i-1] + separation;
+ TestPoint(0);
+ }
+ }else if( width > pTable->table.minW[0] ){
+ float scale;
+ int *tminW = pTable->table.minW;
+ int *tmaxW = pTable->table.maxW;
+ scale = (double)(width - tminW[0]) / (double)(tmaxW[0] - tminW[0]);
+ w[1] = tminW[1] + (tmaxW[1] - tminW[1]) * scale;
+ for(i=2; i<=n; i++){
+ w[i] = tminW[i] + (tmaxW[i] - tminW[i]) * scale;
+ x[i] = x[i-1] + w[i-1] + separation;
+ TestPoint(0);
+ }
+ }else{
+ w[1] = pTable->table.minW[1];
+ for(i=2; i<=n; i++){
+ w[i] = pTable->table.minW[i];
+ x[i] = x[i-1] + w[i-1] + separation;
+ TestPoint(0);
+ }
+ }
+ w[n] = width - ((x[n] - x[1]) + 2*(tbw + pad + cellSpacing));
+
+ /* Add notation to the pTable structure so that we will know where
+ ** to draw the outer box around the outside of the table.
+ */
+ btm += vspace;
+ pTable->table.y = btm;
+ pTable->table.x = x[1] - (tbw + cellSpacing + pad);
+ pTable->table.w = width;
+ SETMAX(pLC->maxX, pTable->table.x + pTable->table.w);
+ btm += tbw + cellSpacing;
+
+ /* Begin rendering rows of the table */
+ for(i=1; i<=n; i++){
+ firstRow[i] = 0;
+ lastRow[i] = 0;
+ apElem[i] = 0;
+ }
+ p = pTable->pNext;
+ rowBottom = btm;
+ for(iRow=1; iRow<=pTable->table.nRow; iRow++){
+ TRACE(HtmlTrace_Table2, ("Row %d: btm=%d\n",iRow,btm));
+ /* Find the start of the next row. Keep an eye out for the caption
+ ** while we search */
+ while( p && p->base.type!=Html_TR ){
+ if( p->base.type==Html_CAPTION ){
+ pCaption = p;
+ while( p && p!=pEnd && p->base.type!=Html_EndCAPTION ){
+ p = p->pNext;
+ }
+ pEndCaption = p;
+ }
+ TRACE(HtmlTrace_Table3, ("Skipping token %s\n", HtmlTokenName(p)));
+ p = p->pNext;
+ }
+ if( p==0 ){ TestPoint(0); break; }
+
+ /* Record default vertical alignment flag for this row */
+ defaultVAlign = GetVerticalAlignment(p, VAlign_Center);
+
+ /* Find every new cell on this row */
+ for(iCol=1; iCol<=pTable->table.nCol && iCol<HTML_MAX_COLUMNS; iCol++){
+ if( lastRow[iCol]<iRow ) ymax[iCol] = 0;
+ }
+ iCol = 0;
+ for(p=p->pNext; p && p->base.type!=Html_TR && p!=pEnd; p=pNext){
+ pNext = p->pNext;
+ TRACE(HtmlTrace_Table3, ("Processing token %s\n", HtmlTokenName(p)));
+ switch( p->base.type ){
+ case Html_TD:
+ case Html_TH:
+ /* Find the column number for this cell. Be careful to skip
+ ** columns which extend down to this row from prior rows */
+ do{
+ iCol++;
+ }while( iCol <= HTML_MAX_COLUMNS && lastRow[iCol] >= iRow );
+ TRACE(HtmlTrace_Table2,
+ ("Column %d: x=%d w=%d\n",iCol,x[iCol],w[iCol]));
+ /* Process the new cell. (Cells beyond the maximum number of
+ ** cells are simply ignored.) */
+ if( iCol <= HTML_MAX_COLUMNS ){
+ apElem[iCol] = p;
+ pNext = p->cell.pEnd;
+ if( p->cell.rowspan==0 ){
+ lastRow[iCol] = pTable->table.nRow;
+ }else{
+ lastRow[iCol] = iRow + p->cell.rowspan - 1;
+ }
+ firstRow[iCol] = iRow;
+
+ /* Set vertical alignment flag for this cell */
+ valign[iCol] = GetVerticalAlignment(p, defaultVAlign);
+
+ /* Render cell contents and record the height */
+ y[iCol] = btm + pad;
+ cellContext.htmlPtr = pLC->htmlPtr;
+ cellContext.pStart = p->pNext;
+ cellContext.pEnd = pNext;
+ cellContext.headRoom = 0;
+ cellContext.top = y[iCol];
+ cellContext.bottom = y[iCol];
+ cellContext.left = x[iCol];
+ cellContext.right = 0;
+ cellContext.pageWidth = x[iCol]+w[iCol];
+ colspan = p->cell.colspan;
+ if( colspan==0 ){
+ for(i=iCol+1; i<=pTable->table.nCol; i++){
+ cellContext.pageWidth += w[i] + separation;
+ lastRow[i] = lastRow[iCol];
+ }
+ }else if( colspan>1 ){
+ for(i=iCol+1; i<iCol+colspan; i++){
+ cellContext.pageWidth += w[i] + separation;
+ lastRow[i] = lastRow[iCol];
+ }
+ }
+ cellContext.maxX = 0;
+ cellContext.maxY = 0;
+ cellContext.leftMargin = 0;
+ cellContext.rightMargin = 0;
+ HtmlLock(cellContext.htmlPtr);
+ HtmlLayoutBlock(&cellContext);
+ if( HtmlUnlock(cellContext.htmlPtr) ) return 0;
+#ifdef TABLE_TRIM_BLANK
+ /*
+ * Cancel any trailing vertical whitespace caused
+ * by break markup
+ */
+ if (HtmlLineWasBlank)
+ cellContext.maxY -= cellContext.headRoom;
+#endif /* TABLE_TRIM_BLANK */
+ ymax[iCol] = cellContext.maxY;
+ SETMAX(ymax[iCol], y[iCol]);
+ HtmlClearMarginStack(&cellContext.leftMargin);
+ HtmlClearMarginStack(&cellContext.rightMargin);
+
+ /* Set coordinates of the cell border */
+ p->cell.x = x[iCol] - pad;
+ p->cell.y = btm;
+ p->cell.w = cellContext.pageWidth + 2*pad - x[iCol];
+ TRACE(HtmlTrace_Table2,
+ ("Column %d top=%d bottom=%d h=%d left=%d w=%d\n",
+ iCol, y[iCol], ymax[iCol], ymax[iCol]-y[iCol],
+ p->cell.x, p->cell.w));
+
+ /* Advance the column counter for cells spaning multiple columns */
+ if( colspan > 1 ){
+ iCol += colspan - 1;
+ }else if( colspan==0 ){
+ iCol = HTML_MAX_COLUMNS + 1;
+ }
+ }
+ break;
+
+ case Html_CAPTION:
+ /* Gotta remember where the caption is so we can render it
+ ** at the end */
+ pCaption = p;
+ while( pNext && pNext!=pEnd && pNext->base.type!=Html_EndCAPTION ){
+ pNext = pNext->pNext;
+ }
+ pEndCaption = pNext;
+ break;
+ }
+ }
+
+ /* Figure out how high to make this row. */
+ for(iCol=1; iCol<=pTable->table.nCol; iCol++){
+ if( lastRow[iCol] == iRow || iRow==pTable->table.nRow ){
+ SETMAX( rowBottom, ymax[iCol] );
+ }
+ }
+ TRACE(HtmlTrace_Table2, ("Total row height: %d..%d -> %d\n",
+ btm,rowBottom,rowBottom-btm));
+
+ /* Position every cell whose bottom edge ends on this row */
+ for(iCol=1; iCol<=pTable->table.nCol; iCol++){
+ int dy; /* Extra space at top of cell used for vertical alignment */
+
+ /* Skip any unused cells or cells that extend down thru
+ ** subsequent rows */
+ if( apElem[iCol]==0
+ || (iRow!=pTable->table.nRow && lastRow[iCol]>iRow) ){ continue; }
+
+ /* Align the contents of the cell vertically. */
+ switch( valign[iCol] ){
+ case VAlign_Unknown:
+ case VAlign_Center:
+ dy = (rowBottom - ymax[iCol])/2;
+ break;
+ case VAlign_Top:
+ case VAlign_Baseline:
+ dy = 0;
+ break;
+ case VAlign_Bottom:
+ dy = rowBottom - ymax[iCol];
+ break;
+ }
+ if( dy ){
+ HtmlElement *pLast = apElem[iCol]->cell.pEnd;
+ TRACE(HtmlTrace_Table3, ("Delta column %d by %d\n",iCol,dy));
+ HtmlMoveVertically(apElem[iCol]->pNext, pLast, dy);
+ }
+
+ /* Record the height of the cell so that the border can be drawn */
+ apElem[iCol]->cell.h = rowBottom + pad - apElem[iCol]->cell.y;
+ apElem[iCol] = 0;
+ }
+
+ /* Update btm to the height of the row we just finished setting */
+ btm = rowBottom + pad + cellSpacing;
+ }
+
+ btm += tbw;
+ pTable->table.h = btm - pTable->table.y;
+ SETMAX( pLC->maxY, btm );
+ pLC->bottom = btm + vspace;
+
+ /* Render the caption, if there is one */
+ if( pCaption ){
+ }
+
+ /* Whenever we do any table layout, we need to recompute all the
+ ** HtmlBlocks. The following statement forces this. */
+ pLC->htmlPtr->firstBlock = pLC->htmlPtr->lastBlock = 0;
+
+ /* Adjust the context for text that wraps around the table, if
+ ** requested by an ALIGN=RIGHT or ALIGN=LEFT attribute.
+ */
+ if( stricmp(zAlign,"left")==0 ){
+ savedContext.maxX = pLC->maxX;
+ savedContext.maxY = pLC->maxY;
+ *pLC = savedContext;
+ HtmlPushMargin(&pLC->leftMargin, pTable->table.w + 2,
+ pTable->table.y + pTable->table.h + 2, 0);
+ }else if( stricmp(zAlign,"right")==0 ){
+ savedContext.maxX = pLC->maxX;
+ savedContext.maxY = pLC->maxY;
+ *pLC = savedContext;
+ HtmlPushMargin(&pLC->rightMargin, pTable->table.w + 2,
+ pTable->table.y + pTable->table.h + 2, 0);
+ }
+
+ /* All done */
+ TRACE(HtmlTrace_Table2, (
+ "Done with TableLayout(). x=%d y=%d w=%d h=%d Return %s\n",
+ pTable->table.x, pTable->table.y, pTable->table.w, pTable->table.h,
+ HtmlTokenName(pEnd)));
+ TRACE_POP(HtmlTrace_Table2);
+ return pEnd;
+}
+
+
+/*
+** Move all elements in the given list vertically by the amount dy
+*/
+void HtmlMoveVertically(
+ HtmlElement *p, /* First element to move */
+ HtmlElement *pLast, /* Last element. Do move this one */
+ int dy /* Amount by which to move */
+){
+ if( dy==0 ){ TestPoint(0); return; }
+ while( p && p!=pLast ){
+ switch( p->base.type ){
+ case Html_A:
+ p->anchor.y += dy;
+ break;
+ case Html_Text:
+ p->text.y += dy;
+ break;
+ case Html_LI:
+ p->li.y += dy;
+ break;
+ case Html_TD:
+ case Html_TH:
+ p->cell.y += dy;
+ break;
+ case Html_TABLE:
+ p->table.y += dy;
+ break;
+ case Html_IMG:
+ p->image.y += dy;
+ break;
+ case Html_INPUT:
+ case Html_SELECT:
+ case Html_APPLET:
+ case Html_EMBED:
+ case Html_TEXTAREA:
+ p->input.y += dy;
+ break;
+ default:
+ break;
+ }
+ p = p->pNext;
+ }
+}
diff --git a/tkhtml1/src/htmltable.h b/tkhtml1/src/htmltable.h
new file mode 100644
index 0000000..2e4cb03
--- /dev/null
+++ b/tkhtml1/src/htmltable.h
@@ -0,0 +1,543 @@
+/* This file was automatically generated. Do not edit! */
+#define Html_LI 81
+#define Html_A 5
+typedef struct HtmlMargin HtmlMargin;
+void HtmlPushMargin(HtmlMargin **ppMargin,int indent,int bottom,int tag);
+typedef union HtmlElement HtmlElement;
+void HtmlMoveVertically(HtmlElement *p,HtmlElement *pLast,int dy);
+void HtmlClearMarginStack(HtmlMargin **ppMargin);
+typedef struct HtmlWidget HtmlWidget;
+int HtmlUnlock(HtmlWidget *htmlPtr);
+typedef struct HtmlLayoutContext HtmlLayoutContext;
+void HtmlLayoutBlock(HtmlLayoutContext *pLC);
+void HtmlLock(HtmlWidget *htmlPtr);
+#define HtmlTrace_Table3 0x00000004
+#define ALIGN_Center 3
+#define ALIGN_Right 2
+void HtmlWidenLine(HtmlLayoutContext *pLC,int reqWidth,int *pX,int *pY,int *pW);
+void HtmlComputeMargins(HtmlLayoutContext *pLC,int *pX,int *pY,int *pW);
+#define HtmlTrace_Table2 0x00000002
+#if defined(TABLE_TRIM_BLANK)
+extern int HtmlLineWasBlank;
+#endif
+struct HtmlLayoutContext {
+ HtmlWidget *htmlPtr; /* The html widget undergoing layout */
+ HtmlElement *pStart; /* Start of elements to layout */
+ HtmlElement *pEnd; /* Stop when reaching this element */
+ int headRoom; /* Extra space wanted above this line */
+ int top; /* Absolute top of drawing area */
+ int bottom; /* Bottom of previous line */
+ int left, right; /* Left and right extremes of drawing area */
+ int pageWidth; /* Width of the layout field, including
+ ** the margins */
+ int maxX, maxY; /* Maximum X and Y values of paint */
+ HtmlMargin *leftMargin; /* Stack of left margins */
+ HtmlMargin *rightMargin; /* Stack of right margins */
+};
+HtmlElement *HtmlTableLayout(HtmlLayoutContext *pLC,HtmlElement *pTable);
+#if !defined(HAVE_STRICMP)
+# define stricmp strcasecmp
+#endif
+#define Html_H6 68
+#define Html_H5 66
+#define Html_EndH4 65
+#define Html_H4 64
+#define Html_EndH3 63
+#define Html_H3 62
+#define Html_EndH2 61
+#define Html_H2 60
+#define Html_EndH1 59
+#define Html_H1 58
+#define Html_EndDIV 42
+#define Html_DIV 41
+#define Html_EndP 105
+#define Html_P 104
+#define Html_BR 24
+#define Html_TEXTAREA 133
+#define Html_EMBED 49
+#define Html_SELECT 116
+#define Html_INPUT 77
+#define Html_APPLET 9
+#define Html_EndBLOCKQUOTE 21
+#define Html_BLOCKQUOTE 20
+#define Html_EndOL 101
+#define Html_EndUL 146
+#define HTML_INDENT 36
+#define Html_OL 100
+#define Html_UL 145
+#define IMAGE_ALIGN_Right 7
+#define IMAGE_ALIGN_Left 6
+#define Html_IMG 76
+#define STY_NoBreak 0x008
+#define HTML_NewLine 0x02 /* type==Html_Space and ends with newline */
+#define Html_Space 2
+#define STY_Preformatted 0x001
+#define Html_Text 1
+extern int HtmlTraceMask;
+#define DEBUG 1
+#if defined(DEBUG)
+extern int HtmlDepth;
+# define TRACE_POP(Flag) if( (Flag)&HtmlTraceMask ){ HtmlDepth-=3; }
+#endif
+#if !(defined(DEBUG))
+# define TRACE_POP(Flag)
+#endif
+#define HtmlTrace_Table5 0x00000010
+#if defined(DEBUG)
+# define TRACE_INDENT printf("%*s",HtmlDepth-3,"")
+#endif
+#if !(defined(DEBUG))
+# define TRACE_INDENT
+#endif
+#define HtmlTrace_Table6 0x00000020
+#define LARGE_NUMBER 100000000
+char *HtmlTokenName(HtmlElement *p);
+typedef struct HtmlRef HtmlRef;
+typedef struct HtmlMarkupElement HtmlMarkupElement;
+typedef struct HtmlBaseElement HtmlBaseElement;
+typedef struct HtmlStyle HtmlStyle;
+struct HtmlStyle {
+ unsigned int font : 6; /* Font to use for display */
+ unsigned int color : 4; /* Foreground color */
+ signed int subscript : 4; /* Positive for <sup>, negative for <sub> */
+ unsigned int align : 2; /* Horizontal alignment */
+ unsigned int bgcolor : 4; /* Background color */
+ unsigned int flags : 12; /* the STY_ flags below */
+};
+typedef unsigned char Html_u8;
+typedef short Html_16;
+struct HtmlBaseElement {
+ HtmlElement *pNext; /* Next input token in a list of them all */
+ HtmlElement *pPrev; /* Previous token in a list of them all */
+ HtmlStyle style; /* The rendering style for this token */
+ Html_u8 type; /* The token type. */
+ Html_u8 flags; /* The HTML_ flags below */
+ Html_16 count; /* Various uses, depending on "type" */
+};
+struct HtmlMarkupElement {
+ HtmlBaseElement base;
+ char **argv;
+};
+struct HtmlRef {
+ HtmlMarkupElement markup;
+ HtmlElement *pOther; /* Pointer to some other Html element */
+};
+/*#define HtmlAlloc(A) ((void*)Tcl_Alloc(A))*/
+void* HtmlAlloc(size_t);
+#define Html_TH 135
+#define Html_TD 131
+#define Html_EndCAPTION 26
+#define Html_CAPTION 25
+#define Html_TR 139
+#define Html_EndTR 140
+#define Html_EndTH 136
+#define Html_EndTD 132
+#define Html_EndTABLE 130
+#define COLOR_Background 4 /* Default background color */
+#define HtmlTrace_Table4 0x00000008
+#if defined(DEBUG)
+# define TRACE(Flag, Args) \
+ if( (Flag)&HtmlTraceMask ){ \
+ TRACE_INDENT; printf Args; fflush(stdout); \
+ }
+#endif
+#if !(defined(DEBUG))
+# define TRACE(Flag, Args)
+#endif
+#define HtmlTrace_Table1 0x00000001
+#if defined(DEBUG)
+# define TRACE_PUSH(Flag) if( (Flag)&HtmlTraceMask ){ HtmlDepth+=3; }
+#endif
+#if !(defined(DEBUG))
+# define TRACE_PUSH(Flag)
+#endif
+#if defined(COVERAGE_TEST)
+extern int HtmlTPArray[2000];
+# define TestPoint(X) {extern int HtmlTPArray[]; HtmlTPArray[X]++;}
+#endif
+#if !(defined(COVERAGE_TEST))
+# define TestPoint(X)
+#endif
+#define Html_TABLE 129
+#define HTML_MAX_COLUMNS 40
+char *HtmlMarkupArg(HtmlElement *p,const char *tag,char *zDefault);
+typedef struct HtmlTextElement HtmlTextElement;
+typedef int Html_32;
+struct HtmlTextElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_32 y; /* y coordinate where text should be rendered */
+ Html_16 x; /* x coordinate where text should be rendered */
+ Html_16 w; /* width of this token in pixels */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_u8 spaceWidth; /* Width of one space in the current font */
+ char zText[1]; /* Text for this element. Null terminated */
+};
+typedef struct HtmlSpaceElement HtmlSpaceElement;
+struct HtmlSpaceElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_16 w; /* Width of a single space in current font */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+};
+typedef struct HtmlCell HtmlCell;
+struct HtmlCell {
+ HtmlMarkupElement markup;
+ Html_16 rowspan; /* Number of rows spanned by this cell */
+ Html_16 colspan; /* Number of columns spanned by this cell */
+ Html_16 x; /* X coordinate of left edge of border */
+ Html_16 w; /* Width of the border */
+ Html_32 y; /* Y coordinate of top of border indentation */
+ Html_32 h; /* Height of the border */
+ HtmlElement *pTable; /* Pointer back to the <table> */
+ HtmlElement *pEnd; /* Element that ends this cell */
+};
+typedef struct HtmlTable HtmlTable;
+typedef unsigned short Html_u16;
+struct HtmlTable {
+ HtmlMarkupElement markup;
+ Html_u8 borderWidth; /* Width of the border */
+ Html_u8 nCol; /* Number of columns */
+ Html_u16 nRow; /* Number of rows */
+ Html_32 y; /* top edge of table border */
+ Html_32 h; /* height of the table border */
+ Html_16 x; /* left edge of table border */
+ Html_16 w; /* width of the table border */
+ int minW[HTML_MAX_COLUMNS+1]; /* minimum width of each column */
+ int maxW[HTML_MAX_COLUMNS+1]; /* maximum width of each column */
+};
+typedef struct HtmlLi HtmlLi;
+struct HtmlLi {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* What type of list is this? */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_16 cnt; /* Value for this element (if inside <OL>) */
+ Html_16 x; /* X coordinate of the bullet */
+ Html_32 y; /* Y coordinate of the bullet */
+};
+typedef struct HtmlListStart HtmlListStart;
+struct HtmlListStart {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* One of the LI_TYPE_ defines above */
+ Html_u8 compact; /* True if the COMPACT flag is present */
+ Html_u16 cnt; /* Next value for <OL> */
+ Html_u16 width; /* How much space to allow for indentation */
+ HtmlElement *pPrev; /* Next higher level list, or NULL */
+};
+typedef struct HtmlImageMarkup HtmlImageMarkup;
+typedef struct HtmlImage HtmlImage;
+struct HtmlImageMarkup {
+ HtmlMarkupElement markup;
+ Html_u8 align; /* Alignment. See IMAGE_ALIGN_ defines below */
+ Html_u8 textAscent; /* Ascent of text font in force at the <IMG> */
+ Html_u8 textDescent; /* Descent of text font in force at the <IMG> */
+ Html_u8 redrawNeeded; /* Need to redraw this image because the image
+ ** content changed. */
+ Html_16 h; /* Actual height of the image */
+ Html_16 w; /* Actual width of the image */
+ Html_16 ascent; /* How far image extends above "y" */
+ Html_16 descent; /* How far image extends below "y" */
+ Html_16 x; /* X coordinate of left edge of the image */
+ Html_32 y; /* Y coordinate of image baseline */
+ char *zAlt; /* Alternative text */
+ HtmlImage *pImage; /* Corresponding HtmlImage structure */
+ HtmlElement *pNext; /* Next markup using the same HtmlImage structure */
+};
+typedef struct HtmlInput HtmlInput;
+struct HtmlInput {
+ HtmlMarkupElement markup;
+ HtmlElement *pForm; /* The <FORM> to which this belongs */
+ HtmlElement *pNext; /* Next element in a list of all input elements */
+ Tk_Window tkwin; /* The window that implements this control */
+ HtmlWidget *htmlPtr; /* The whole widget. Needed by geometry callbacks */
+ HtmlElement *pEnd; /* End tag for <TEXTAREA>, etc. */
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 padLeft; /* Extra padding on left side of the control */
+ Html_u8 align; /* One of the IMAGE_ALIGN_xxx types */
+ Html_u8 textAscent; /* Ascent for the current font */
+ Html_u8 textDescent; /* descent for the current font */
+ Html_u8 type; /* What type of input is this? */
+ Html_u8 sized; /* True if this input has been sized already */
+ Html_u16 cnt; /* Used to derive widget name. 0 if no widget */
+};
+typedef struct HtmlForm HtmlForm;
+struct HtmlForm {
+ HtmlMarkupElement markup;
+ Html_u16 id; /* Unique number assigned to this form */
+};
+typedef struct HtmlHr HtmlHr;
+struct HtmlHr {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 is3D; /* Is it drawn 3D? */
+};
+typedef struct HtmlAnchor HtmlAnchor;
+struct HtmlAnchor {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Top edge for this element */
+};
+typedef struct HtmlScript HtmlScript;
+struct HtmlScript {
+ HtmlMarkupElement markup;
+ char *zScript; /* Complete text of this script */
+ int nScript; /* Number of characters of text */
+};
+typedef struct HtmlBlock HtmlBlock;
+struct HtmlBlock {
+ HtmlBaseElement base; /* Superclass. Must be first */
+ char *z; /* Space to hold text when n>0 */
+ int top, bottom; /* Extremes of y coordinates */
+ Html_u16 left, right; /* Left and right boundry of this object */
+ Html_u16 n; /* Number of characters in z[] */
+ HtmlBlock *pPrev, *pNext; /* Linked list of all Blocks */
+};
+union HtmlElement {
+ HtmlElement *pNext;
+ HtmlBaseElement base;
+ HtmlTextElement text;
+ HtmlSpaceElement space;
+ HtmlMarkupElement markup;
+ HtmlCell cell;
+ HtmlTable table;
+ HtmlRef ref;
+ HtmlLi li;
+ HtmlListStart list;
+ HtmlImageMarkup image;
+ HtmlInput input;
+ HtmlForm form;
+ HtmlHr hr;
+ HtmlAnchor anchor;
+ HtmlScript script;
+ HtmlBlock block;
+};
+typedef struct HtmlIndex HtmlIndex;
+struct HtmlIndex {
+ HtmlElement *p; /* The token containing the character */
+ int i; /* Index of the character */
+};
+#define Html_TypeCount 151
+typedef struct HtmlStyleStack HtmlStyleStack;
+#define N_FONT_FAMILY 8
+#define N_FONT_SIZE 7
+#define N_FONT (N_FONT_FAMILY*N_FONT_SIZE)
+#define N_COLOR 16 /* Total number of colors */
+typedef struct GcCache GcCache;
+struct GcCache {
+ GC gc; /* The graphics context */
+ Html_u8 font; /* Font used for this context */
+ Html_u8 color; /* Color used for this context */
+ Html_u8 index; /* Index used for LRU replacement */
+};
+#define N_CACHE_GC 16
+struct HtmlWidget {
+ Tk_Window tkwin; /* The main window for this widget */
+ Tk_Window clipwin; /* The clipping window in which all text is
+ ** rendered. */
+ char *zClipwin; /* Name of the clipping window. */
+ Display *display; /* The X11 Server that contains tkwin */
+ Tcl_Interp *interp; /* The interpreter in which the widget lives */
+ char *zCmdName; /* Name of the command */
+ HtmlElement *pFirst; /* First HTML token on a list of them all */
+ HtmlElement *pLast; /* Last HTML token on the list */
+ int nToken; /* Number of HTML tokens on the list.
+ * Html_Block tokens don't count. */
+ HtmlElement *lastSized; /* Last HTML element that has been sized */
+ HtmlElement *nextPlaced; /* Next HTML element that needs to be
+ * positioned on canvas. */
+ HtmlBlock *firstBlock; /* List of all HtmlBlock tokens */
+ HtmlBlock *lastBlock; /* Last HtmlBlock in the list */
+ HtmlElement *firstInput; /* First <INPUT> element */
+ HtmlElement *lastInput; /* Last <INPUT> element */
+ int nInput; /* The number of <INPUT> elements */
+ int nForm; /* The number of <FORM> elements */
+ int varId; /* Used to construct a unique name for a
+ ** global array used by <INPUT> elements */
+
+ /*
+ * Information about the selected region of text
+ */
+ HtmlIndex selBegin; /* Start of the selection */
+ HtmlIndex selEnd; /* End of the selection */
+ HtmlBlock *pSelStartBlock; /* Block in which selection starts */
+ Html_16 selStartIndex; /* Index in pSelStartBlock of first selected
+ * character */
+ Html_16 selEndIndex; /* Index of last selecte char in pSelEndBlock */
+ HtmlBlock *pSelEndBlock; /* Block in which selection ends */
+
+ /*
+ * Information about the insertion cursor
+ */
+ int insOnTime; /* How long the cursor states one (millisec) */
+ int insOffTime; /* How long it is off (milliseconds) */
+ int insStatus; /* Is it visible? */
+ Tcl_TimerToken insTimer; /* Timer used to flash the insertion cursor */
+ HtmlIndex ins; /* The insertion cursor position */
+ HtmlBlock *pInsBlock; /* The HtmlBlock containing the cursor */
+ int insIndex; /* Index in pInsBlock of the cursor */
+
+ /*
+ * The following fields hold state information used by
+ * the tokenizer.
+ */
+ char *zText; /* Complete text of the unparsed HTML */
+ int nText; /* Number of characters in zText */
+ int nAlloc; /* Space allocated for zText */
+ int nComplete; /* How much of zText has actually been
+ * converted into tokens */
+ int iCol; /* The column in which zText[nComplete]
+ * occurs. Used to resolve tabs in input */
+ int iPlaintext; /* If not zero, this is the token type that
+ * caused us to go into plaintext mode. One
+ * of Html_PLAINTEXT, Html_LISTING or
+ * Html_XMP */
+ HtmlScript *pScript; /* <SCRIPT> currently being parsed */
+ char *zHandler[Html_TypeCount]; /* If not NULL, this is a TCL routine that
+ * is used to process tokens of the given
+ * type */
+ /*
+ * These fields hold state information used by the HtmlAddStyle routine.
+ * We have to store this state information here since HtmlAddStyle
+ * operates incrementally. This information must be carried from
+ * one incremental execution to the next.
+ */
+ HtmlStyleStack *styleStack; /* The style stack */
+ int paraAlignment; /* Justification associated with <p> */
+ int rowAlignment; /* Justification associated with <tr> */
+ int anchorFlags; /* Style flags associated with <A>...</A> */
+ int inDt; /* Style flags associated with <DT>...</DT> */
+ int inTr; /* True if within <tr>..</tr> */
+ int inTd; /* True if within <td>..</td> or <th>..</th> */
+ HtmlElement *anchorStart; /* Most recent <a href=...> */
+ HtmlElement *formStart; /* Most recent <form> */
+ HtmlElement *formElemStart; /* Most recent <textarea> or <select> */
+ HtmlElement *innerList; /* The inner most <OL> or <UL> */
+
+ /*
+ * These fields are used to hold the state of the layout engine.
+ * Because the layout is incremental, this state must be held for
+ * the life of the widget.
+ */
+ HtmlLayoutContext layoutContext;
+
+ /*
+ * Information used when displaying the widget:
+ */
+ Tk_3DBorder border; /* Background color */
+ int borderWidth; /* Width of the border. */
+ int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ int inset; /* Total width of highlight and 3-D border */
+ Tk_Font aFont[N_FONT]; /* Information about all screen fonts */
+ char fontValid[(N_FONT+7)/8]; /* If bit N%8 of work N/8 of this field is 0
+ * if aFont[N] needs to be reallocated before
+ * being used. */
+ XColor *apColor[N_COLOR]; /* Information about all colors */
+ int colorUsed; /* bit N is 1 if color N is in use. Only
+ ** applies to colors that aren't predefined */
+ int iDark[N_COLOR]; /* Dark 3D shadow of color K is iDark[K] */
+ int iLight[N_COLOR]; /* Light 3D shadow of color K is iLight[K] */
+ XColor *fgColor; /* Color of normal text. apColor[0] */
+ XColor *newLinkColor; /* Color of unvisitied links. apColor[1] */
+ XColor *oldLinkColor; /* Color of visitied links. apColor[2] */
+ XColor *selectionColor; /* Background color for selections */
+ GcCache aGcCache[N_CACHE_GC]; /* A cache of GCs for general use */
+ int lastGC; /* Index of recently used GC */
+ HtmlImage *imageList; /* A list of all images */
+ int width, height; /* User-requested size of the usable drawing
+ * area, in pixels. Borders and padding
+ * make the actual window a little larger */
+ int realWidth, realHeight; /* The actual physical size of tkwin as
+ * reported in the most recent ConfigureNotify
+ * event. */
+ int padx, pady; /* Separation between the edge of the window
+ * and rendered HTML. */
+ int underlineLinks; /* TRUE if we should underline hyperlinks */
+
+ /* Information about the selection
+ */
+ int exportSelection; /* True if the selection is automatically
+ * exported to the clipboard */
+
+ /* Callback commands. The HTML parser will invoke callbacks from time
+ ** to time to find out information it needs to complete formatting of
+ ** the document. The following fields define the callback commands.
+ */
+ char *zIsVisited; /* Command to tell if a hyperlink has already
+ ** been visited */
+ char *zGetImage; /* Command to get an image from a URL */
+ char *zFrameCommand; /* Command for handling <frameset> markup */
+ char *zAppletCommand; /* Command to process applets */
+ char *zResolverCommand; /* Command to resolve URIs */
+ char *zFormCommand; /* When user presses Submit */
+ char *zHyperlinkCommand; /* Invoked when a hyperlink is clicked */
+ char *zFontCommand; /* Invoked to find font names */
+ char *zScriptCommand; /* Invoked for each <SCRIPT> markup */
+
+ /*
+ * Miscellaneous information:
+ */
+ int tableRelief; /* 3d effects on <TABLE> */
+ int ruleRelief; /* 3d effects on <HR> */
+ char *zBase; /* The base URI */
+ char *zBaseHref; /* zBase as modified by <BASE HREF=..> markup */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ char *takeFocus; /* Value of -takefocus option; not used in
+ * the C code, but used by keyboard traversal
+ * scripts. Malloc'ed, but may be NULL. */
+ char *yScrollCmd; /* Command prefix for communicating with
+ * vertical scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ char *xScrollCmd; /* Command prefix for communicating with
+ * horizontal scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ int xOffset, yOffset; /* Current scroll position. These form the
+ * coordinate in the virtual canvas that
+ * corresponds to (0,0) on the physical screen
+ * in window tkwin */
+ int maxX, maxY; /* Maximum extent of any "paint" that appears
+ * on the virtual canvas. Used to compute
+ * scrollbar positions. */
+ int dirtyLeft, dirtyTop; /* Top left corner of region to redraw. These
+ * are physical screen coordinates relative to
+ * clipwin, not tkwin. */
+ int dirtyRight, dirtyBottom; /* Bottom right corner of region to redraw */
+ int locked; /* Number of locks on this structure. Don't
+ ** delete until it reaches zero. */
+ int flags; /* Various flags; see below for
+ * definitions. */
+};
+#define MAX(A,B) ((A)<(B)?(B):(A))
+#define SETMAX(A,B) if( (A)<(B) ){ (A) = (B); }
+#define INTERFACE 0
+struct HtmlImage {
+ HtmlWidget *htmlPtr; /* The owner of this image */
+ Tk_Image image; /* The Tk image token */
+ Html_32 w; /* Requested width of this image (0 if none) */
+ Html_32 h; /* Requested height of this image (0 if none) */
+ char *zUrl; /* The URL for this image. */
+ char *zWidth, *zHeight; /* Width and height in the <img> markup. */
+ HtmlImage *pNext; /* Next image on the list */
+ HtmlElement *pList; /* List of all <IMG> markups that use this
+ ** same image */
+};
+struct HtmlStyleStack {
+ HtmlStyleStack *pNext; /* Next style on the stack */
+ int type; /* A markup that ends this style. Ex: Html_EndEM */
+ HtmlStyle style; /* The currently active style. */
+};
+struct HtmlMargin {
+ int indent; /* Size of the current margin */
+ int bottom; /* Y value at which this margin expires */
+ int tag; /* Markup that will cancel this margin */
+ HtmlMargin *pNext; /* Previous margin */
+};
diff --git a/tkhtml1/src/htmltest.c b/tkhtml1/src/htmltest.c
new file mode 100644
index 0000000..c57d98b
--- /dev/null
+++ b/tkhtml1/src/htmltest.c
@@ -0,0 +1,122 @@
+/*
+** This file contains the TestPoint routines used for profiling
+** and coverage analysis of the code.
+**
+** Copyright (C) 1997-2000 D. Richard Hipp
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** drh@acm.org
+** http://www.hwaci.com/drh/
+*/
+/*
+** A macro named "TestPoint" is defined which increments a counter
+** whenever it is encountered. This is very efficient, and should
+** not impact performance of the system. For delivery, the macro
+** can be nulled out by recompiling without the COVERAGE_TEST macro
+** defined.
+**
+** See also the "renumber.c" program which can be used
+** to assign unique numbers to all of the TestPoint(0) macros.
+*/
+#include "tcl.h"
+#include "htmltest.h"
+
+#if INTERFACE
+
+#if defined(COVERAGE_TEST)
+# define TestPoint(X) {extern int HtmlTPArray[]; HtmlTPArray[X]++;}
+# define UNTESTED HtmlTPUntested(__FILE__,__LINE__)
+# define CANT_HAPPEN HtmlTPCantHappen(__FILE__,__LINE__)
+# define HtmlVerifyLock(H) if((H)->locked==0)HtmlTPCantHappen(__FILE__,__LINE__)
+#else
+# define TestPoint(X)
+# define UNTESTED
+# define CANT_HAPPEN
+# define HtmlVerifyLock(H)
+#endif
+
+#endif /* INTERFACE */
+
+/*
+** The following global array keeps track of the number of visits to
+** each testpoint. The size of the array must be set manually to the
+** be at least one greater than the largest TestPoint number.
+*/
+#if defined(COVERAGE_TEST)
+int HtmlTPArray[2000];
+#endif
+
+/* Needed by the EslTestPointDump routine
+*/
+#include <stdio.h>
+
+/*
+** Recursion depth
+*/
+#if defined(DEBUG)
+int HtmlDepth = 0;
+#endif
+#if INTERFACE
+#if defined(DEBUG)
+#define HtmlPush HtmlDepth+=2
+#define HtmlPop HtmlDepth-=2
+#else
+#define HtmlPush
+#define HtmlPop
+#endif
+#endif
+
+/* This function is called to print the values of all elements of the
+** TP_Array to the given file. Values are printed in decimal, one per line.
+*/
+void HtmlTestPointDump(const char *filename){
+#if defined(COVERAGE_TEST)
+ FILE *fp;
+
+ fp = fopen(filename,"a");
+ if( fp ){
+ int i;
+ for(i=0; i<sizeof(HtmlTPArray)/sizeof(HtmlTPArray[0]); i++){
+ if( HtmlTPArray[i]>0 ){
+ fprintf(fp,"%d %d\n",i,HtmlTPArray[i]);
+ }
+ }
+ }
+ fclose(fp);
+#endif
+}
+
+/* This function reports an error to stderr when code that is marked
+** UNTESTED gets executed.
+*/
+void HtmlTPUntested(const char *zFile, int line){
+#ifndef USE_TCL_STUBS
+ fprintf(stderr,"Untested HTML Widget code executed in file %s line %d\n",
+ zFile,line);
+#endif
+}
+
+/* This function reports an error to stderr when safety code that should
+** never execute is called.
+*/
+void HtmlTPCantHappen(const char *zFile, int line){
+#ifndef USE_TCL_STUBS
+ fprintf(stderr,"Unplanned behavior in the HTML Widget in file %s line %d\n",
+ zFile,line);
+#endif
+}
diff --git a/tkhtml1/src/htmltest.h b/tkhtml1/src/htmltest.h
new file mode 100644
index 0000000..060508f
--- /dev/null
+++ b/tkhtml1/src/htmltest.h
@@ -0,0 +1,44 @@
+/* This file was automatically generated. Do not edit! */
+void HtmlTestPointDump(const char *filename);
+#define DEBUG 1
+#if defined(DEBUG)
+extern int HtmlDepth;
+#define HtmlPop HtmlDepth-=2
+#endif
+#if !(defined(DEBUG))
+#define HtmlPop
+#endif
+#if defined(DEBUG)
+#define HtmlPush HtmlDepth+=2
+#endif
+#if !(defined(DEBUG))
+#define HtmlPush
+#endif
+void HtmlTPCantHappen(const char *zFile,int line);
+#if defined(COVERAGE_TEST)
+# define HtmlVerifyLock(H) if((H)->locked==0)HtmlTPCantHappen(__FILE__,__LINE__)
+#endif
+#if !(defined(COVERAGE_TEST))
+# define HtmlVerifyLock(H)
+#endif
+#if defined(COVERAGE_TEST)
+# define CANT_HAPPEN HtmlTPCantHappen(__FILE__,__LINE__)
+#endif
+#if !(defined(COVERAGE_TEST))
+# define CANT_HAPPEN
+#endif
+void HtmlTPUntested(const char *zFile,int line);
+#if defined(COVERAGE_TEST)
+# define UNTESTED HtmlTPUntested(__FILE__,__LINE__)
+#endif
+#if !(defined(COVERAGE_TEST))
+# define UNTESTED
+#endif
+#if defined(COVERAGE_TEST)
+extern int HtmlTPArray[2000];
+# define TestPoint(X) {extern int HtmlTPArray[]; HtmlTPArray[X]++;}
+#endif
+#if !(defined(COVERAGE_TEST))
+# define TestPoint(X)
+#endif
+#define INTERFACE 0
diff --git a/tkhtml1/src/htmltokens.c b/tkhtml1/src/htmltokens.c
new file mode 100644
index 0000000..d8a3c99
--- /dev/null
+++ b/tkhtml1/src/htmltokens.c
@@ -0,0 +1,318 @@
+/* DO NOT EDIT
+** The code in this file was automatically generated.
+*/
+#include <tk.h>
+#include "htmltokens.h"
+#if INTERFACE
+struct HtmlTokenMap {
+ char *zName; /* Name of a markup */
+ Html_16 type; /* Markup type code */
+ Html_16 extra; /* Extra space needed above HtmlBaseElement */
+ HtmlTokenMap *pCollide; /* Hash table collision chain */
+};
+#define Html_Text 1
+#define Html_Space 2
+#define Html_Unknown 3
+#define Html_Block 4
+#define HtmlIsMarkup(X) ((X)->base.type>Html_Block)
+
+#define Html_A 5
+#define Html_EndA 6
+#define Html_ADDRESS 7
+#define Html_EndADDRESS 8
+#define Html_APPLET 9
+#define Html_EndAPPLET 10
+#define Html_AREA 11
+#define Html_B 12
+#define Html_EndB 13
+#define Html_BASE 14
+#define Html_BASEFONT 15
+#define Html_EndBASEFONT 16
+#define Html_BGSOUND 17
+#define Html_BIG 18
+#define Html_EndBIG 19
+#define Html_BLOCKQUOTE 20
+#define Html_EndBLOCKQUOTE 21
+#define Html_BODY 22
+#define Html_EndBODY 23
+#define Html_BR 24
+#define Html_CAPTION 25
+#define Html_EndCAPTION 26
+#define Html_CENTER 27
+#define Html_EndCENTER 28
+#define Html_CITE 29
+#define Html_EndCITE 30
+#define Html_CODE 31
+#define Html_EndCODE 32
+#define Html_COMMENT 33
+#define Html_EndCOMMENT 34
+#define Html_DD 35
+#define Html_EndDD 36
+#define Html_DFN 37
+#define Html_EndDFN 38
+#define Html_DIR 39
+#define Html_EndDIR 40
+#define Html_DIV 41
+#define Html_EndDIV 42
+#define Html_DL 43
+#define Html_EndDL 44
+#define Html_DT 45
+#define Html_EndDT 46
+#define Html_EM 47
+#define Html_EndEM 48
+#define Html_EMBED 49
+#define Html_FONT 50
+#define Html_EndFONT 51
+#define Html_FORM 52
+#define Html_EndFORM 53
+#define Html_FRAME 54
+#define Html_EndFRAME 55
+#define Html_FRAMESET 56
+#define Html_EndFRAMESET 57
+#define Html_H1 58
+#define Html_EndH1 59
+#define Html_H2 60
+#define Html_EndH2 61
+#define Html_H3 62
+#define Html_EndH3 63
+#define Html_H4 64
+#define Html_EndH4 65
+#define Html_H5 66
+#define Html_EndH5 67
+#define Html_H6 68
+#define Html_EndH6 69
+#define Html_HR 70
+#define Html_HTML 71
+#define Html_EndHTML 72
+#define Html_I 73
+#define Html_EndI 74
+#define Html_IFRAME 75
+#define Html_IMG 76
+#define Html_INPUT 77
+#define Html_ISINDEX 78
+#define Html_KBD 79
+#define Html_EndKBD 80
+#define Html_LI 81
+#define Html_EndLI 82
+#define Html_LINK 83
+#define Html_LISTING 84
+#define Html_EndLISTING 85
+#define Html_MAP 86
+#define Html_EndMAP 87
+#define Html_MARQUEE 88
+#define Html_EndMARQUEE 89
+#define Html_MENU 90
+#define Html_EndMENU 91
+#define Html_META 92
+#define Html_NEXTID 93
+#define Html_NOBR 94
+#define Html_EndNOBR 95
+#define Html_NOFRAME 96
+#define Html_EndNOFRAME 97
+#define Html_NOSCRIPT 98
+#define Html_EndNOSCRIPT 99
+#define Html_OL 100
+#define Html_EndOL 101
+#define Html_OPTION 102
+#define Html_EndOPTION 103
+#define Html_P 104
+#define Html_EndP 105
+#define Html_PARAM 106
+#define Html_EndPARAM 107
+#define Html_PLAINTEXT 108
+#define Html_PRE 109
+#define Html_EndPRE 110
+#define Html_S 111
+#define Html_EndS 112
+#define Html_SAMP 113
+#define Html_EndSAMP 114
+#define Html_SCRIPT 115
+#define Html_SELECT 116
+#define Html_EndSELECT 117
+#define Html_SMALL 118
+#define Html_EndSMALL 119
+#define Html_STRIKE 120
+#define Html_EndSTRIKE 121
+#define Html_STRONG 122
+#define Html_EndSTRONG 123
+#define Html_STYLE 124
+#define Html_SUB 125
+#define Html_EndSUB 126
+#define Html_SUP 127
+#define Html_EndSUP 128
+#define Html_TABLE 129
+#define Html_EndTABLE 130
+#define Html_TD 131
+#define Html_EndTD 132
+#define Html_TEXTAREA 133
+#define Html_EndTEXTAREA 134
+#define Html_TH 135
+#define Html_EndTH 136
+#define Html_TITLE 137
+#define Html_EndTITLE 138
+#define Html_TR 139
+#define Html_EndTR 140
+#define Html_TT 141
+#define Html_EndTT 142
+#define Html_U 143
+#define Html_EndU 144
+#define Html_UL 145
+#define Html_EndUL 146
+#define Html_VAR 147
+#define Html_EndVAR 148
+#define Html_WBR 149
+#define Html_XMP 150
+#define Html_EndXMP 151
+#define Html_TypeCount 151
+#define HTML_MARKUP_HASH_SIZE 163
+#define HTML_MARKUP_COUNT 147
+#endif /* INTERFACE */
+HtmlTokenMap HtmlMarkupMap[] = {
+ { "a", Html_A, sizeof(HtmlAnchor), },
+ { "/a", Html_EndA, sizeof(HtmlRef), },
+ { "address", Html_ADDRESS, 0, },
+ { "/address", Html_EndADDRESS, 0, },
+ { "applet", Html_APPLET, sizeof(HtmlInput), },
+ { "/applet", Html_EndAPPLET, 0, },
+ { "area", Html_AREA, 0, },
+ { "b", Html_B, 0, },
+ { "/b", Html_EndB, 0, },
+ { "base", Html_BASE, 0, },
+ { "basefont", Html_BASEFONT, 0, },
+ { "/basefont", Html_EndBASEFONT, 0, },
+ { "bgsound", Html_BGSOUND, 0, },
+ { "big", Html_BIG, 0, },
+ { "/big", Html_EndBIG, 0, },
+ { "blockquote", Html_BLOCKQUOTE, 0, },
+ { "/blockquote", Html_EndBLOCKQUOTE, 0, },
+ { "body", Html_BODY, 0, },
+ { "/body", Html_EndBODY, 0, },
+ { "br", Html_BR, 0, },
+ { "caption", Html_CAPTION, 0, },
+ { "/caption", Html_EndCAPTION, 0, },
+ { "center", Html_CENTER, 0, },
+ { "/center", Html_EndCENTER, 0, },
+ { "cite", Html_CITE, 0, },
+ { "/cite", Html_EndCITE, 0, },
+ { "code", Html_CODE, 0, },
+ { "/code", Html_EndCODE, 0, },
+ { "comment", Html_COMMENT, 0, },
+ { "/comment", Html_EndCOMMENT, 0, },
+ { "dd", Html_DD, sizeof(HtmlRef), },
+ { "/dd", Html_EndDD, 0, },
+ { "dfn", Html_DFN, 0, },
+ { "/dfn", Html_EndDFN, 0, },
+ { "dir", Html_DIR, sizeof(HtmlListStart), },
+ { "/dir", Html_EndDIR, sizeof(HtmlRef), },
+ { "div", Html_DIV, 0, },
+ { "/div", Html_EndDIV, 0, },
+ { "dl", Html_DL, sizeof(HtmlListStart), },
+ { "/dl", Html_EndDL, sizeof(HtmlRef), },
+ { "dt", Html_DT, sizeof(HtmlRef), },
+ { "/dt", Html_EndDT, 0, },
+ { "em", Html_EM, 0, },
+ { "/em", Html_EndEM, 0, },
+ { "embed", Html_EMBED, sizeof(HtmlInput), },
+ { "font", Html_FONT, 0, },
+ { "/font", Html_EndFONT, 0, },
+ { "form", Html_FORM, sizeof(HtmlForm), },
+ { "/form", Html_EndFORM, sizeof(HtmlRef), },
+ { "frame", Html_FRAME, 0, },
+ { "/frame", Html_EndFRAME, 0, },
+ { "frameset", Html_FRAMESET, 0, },
+ { "/frameset", Html_EndFRAMESET, 0, },
+ { "h1", Html_H1, 0, },
+ { "/h1", Html_EndH1, 0, },
+ { "h2", Html_H2, 0, },
+ { "/h2", Html_EndH2, 0, },
+ { "h3", Html_H3, 0, },
+ { "/h3", Html_EndH3, 0, },
+ { "h4", Html_H4, 0, },
+ { "/h4", Html_EndH4, 0, },
+ { "h5", Html_H5, 0, },
+ { "/h5", Html_EndH5, 0, },
+ { "h6", Html_H6, 0, },
+ { "/h6", Html_EndH6, 0, },
+ { "hr", Html_HR, sizeof(HtmlHr), },
+ { "html", Html_HTML, 0, },
+ { "/html", Html_EndHTML, 0, },
+ { "i", Html_I, 0, },
+ { "/i", Html_EndI, 0, },
+ { "iframe", Html_IFRAME, 0, },
+ { "img", Html_IMG, sizeof(HtmlImageMarkup), },
+ { "input", Html_INPUT, sizeof(HtmlInput), },
+ { "isindex", Html_ISINDEX, 0, },
+ { "kbd", Html_KBD, 0, },
+ { "/kbd", Html_EndKBD, 0, },
+ { "li", Html_LI, sizeof(HtmlLi), },
+ { "/li", Html_EndLI, 0, },
+ { "link", Html_LINK, 0, },
+ { "listing", Html_LISTING, 0, },
+ { "/listing", Html_EndLISTING, 0, },
+ { "map", Html_MAP, 0, },
+ { "/map", Html_EndMAP, 0, },
+ { "marquee", Html_MARQUEE, 0, },
+ { "/marquee", Html_EndMARQUEE, 0, },
+ { "menu", Html_MENU, sizeof(HtmlListStart), },
+ { "/menu", Html_EndMENU, sizeof(HtmlRef), },
+ { "meta", Html_META, 0, },
+ { "nextid", Html_NEXTID, 0, },
+ { "nobr", Html_NOBR, 0, },
+ { "/nobr", Html_EndNOBR, 0, },
+ { "noframe", Html_NOFRAME, 0, },
+ { "/noframe", Html_EndNOFRAME, 0, },
+ { "noscript", Html_NOSCRIPT, 0, },
+ { "/noscript", Html_EndNOSCRIPT, 0, },
+ { "ol", Html_OL, sizeof(HtmlListStart), },
+ { "/ol", Html_EndOL, sizeof(HtmlRef), },
+ { "option", Html_OPTION, 0, },
+ { "/option", Html_EndOPTION, 0, },
+ { "p", Html_P, 0, },
+ { "/p", Html_EndP, 0, },
+ { "param", Html_PARAM, 0, },
+ { "/param", Html_EndPARAM, 0, },
+ { "plaintext", Html_PLAINTEXT, 0, },
+ { "pre", Html_PRE, 0, },
+ { "/pre", Html_EndPRE, 0, },
+ { "s", Html_S, 0, },
+ { "/s", Html_EndS, 0, },
+ { "samp", Html_SAMP, 0, },
+ { "/samp", Html_EndSAMP, 0, },
+ { "script", Html_SCRIPT, sizeof(HtmlScript), },
+ { "select", Html_SELECT, sizeof(HtmlInput), },
+ { "/select", Html_EndSELECT, sizeof(HtmlRef), },
+ { "small", Html_SMALL, 0, },
+ { "/small", Html_EndSMALL, 0, },
+ { "strike", Html_STRIKE, 0, },
+ { "/strike", Html_EndSTRIKE, 0, },
+ { "strong", Html_STRONG, 0, },
+ { "/strong", Html_EndSTRONG, 0, },
+ { "style", Html_STYLE, sizeof(HtmlScript), },
+ { "sub", Html_SUB, 0, },
+ { "/sub", Html_EndSUB, 0, },
+ { "sup", Html_SUP, 0, },
+ { "/sup", Html_EndSUP, 0, },
+ { "table", Html_TABLE, sizeof(HtmlTable), },
+ { "/table", Html_EndTABLE, sizeof(HtmlRef), },
+ { "td", Html_TD, sizeof(HtmlCell), },
+ { "/td", Html_EndTD, sizeof(HtmlRef), },
+ { "textarea", Html_TEXTAREA, sizeof(HtmlInput), },
+ { "/textarea", Html_EndTEXTAREA, sizeof(HtmlRef), },
+ { "th", Html_TH, sizeof(HtmlCell), },
+ { "/th", Html_EndTH, sizeof(HtmlRef), },
+ { "title", Html_TITLE, 0, },
+ { "/title", Html_EndTITLE, 0, },
+ { "tr", Html_TR, sizeof(HtmlRef), },
+ { "/tr", Html_EndTR, sizeof(HtmlRef), },
+ { "tt", Html_TT, 0, },
+ { "/tt", Html_EndTT, 0, },
+ { "u", Html_U, 0, },
+ { "/u", Html_EndU, 0, },
+ { "ul", Html_UL, sizeof(HtmlListStart), },
+ { "/ul", Html_EndUL, sizeof(HtmlRef), },
+ { "var", Html_VAR, 0, },
+ { "/var", Html_EndVAR, 0, },
+ { "wbr", Html_WBR, 0, },
+ { "xmp", Html_XMP, 0, },
+ { "/xmp", Html_EndXMP, 0, },
+};
diff --git a/tkhtml1/src/htmltokens.h b/tkhtml1/src/htmltokens.h
new file mode 100644
index 0000000..0736806
--- /dev/null
+++ b/tkhtml1/src/htmltokens.h
@@ -0,0 +1,590 @@
+/* This file was automatically generated. Do not edit! */
+typedef struct HtmlCell HtmlCell;
+typedef struct HtmlMarkupElement HtmlMarkupElement;
+typedef struct HtmlBaseElement HtmlBaseElement;
+typedef union HtmlElement HtmlElement;
+typedef struct HtmlStyle HtmlStyle;
+struct HtmlStyle {
+ unsigned int font : 6; /* Font to use for display */
+ unsigned int color : 4; /* Foreground color */
+ signed int subscript : 4; /* Positive for <sup>, negative for <sub> */
+ unsigned int align : 2; /* Horizontal alignment */
+ unsigned int bgcolor : 4; /* Background color */
+ unsigned int flags : 12; /* the STY_ flags below */
+};
+typedef unsigned char Html_u8;
+typedef short Html_16;
+struct HtmlBaseElement {
+ HtmlElement *pNext; /* Next input token in a list of them all */
+ HtmlElement *pPrev; /* Previous token in a list of them all */
+ HtmlStyle style; /* The rendering style for this token */
+ Html_u8 type; /* The token type. */
+ Html_u8 flags; /* The HTML_ flags below */
+ Html_16 count; /* Various uses, depending on "type" */
+};
+struct HtmlMarkupElement {
+ HtmlBaseElement base;
+ char **argv;
+};
+typedef int Html_32;
+struct HtmlCell {
+ HtmlMarkupElement markup;
+ Html_16 rowspan; /* Number of rows spanned by this cell */
+ Html_16 colspan; /* Number of columns spanned by this cell */
+ Html_16 x; /* X coordinate of left edge of border */
+ Html_16 w; /* Width of the border */
+ Html_32 y; /* Y coordinate of top of border indentation */
+ Html_32 h; /* Height of the border */
+ HtmlElement *pTable; /* Pointer back to the <table> */
+ HtmlElement *pEnd; /* Element that ends this cell */
+};
+typedef struct HtmlTable HtmlTable;
+typedef unsigned short Html_u16;
+#define HTML_MAX_COLUMNS 40
+struct HtmlTable {
+ HtmlMarkupElement markup;
+ Html_u8 borderWidth; /* Width of the border */
+ Html_u8 nCol; /* Number of columns */
+ Html_u16 nRow; /* Number of rows */
+ Html_32 y; /* top edge of table border */
+ Html_32 h; /* height of the table border */
+ Html_16 x; /* left edge of table border */
+ Html_16 w; /* width of the table border */
+ int minW[HTML_MAX_COLUMNS+1]; /* minimum width of each column */
+ int maxW[HTML_MAX_COLUMNS+1]; /* maximum width of each column */
+};
+typedef struct HtmlScript HtmlScript;
+struct HtmlScript {
+ HtmlMarkupElement markup;
+ char *zScript; /* Complete text of this script */
+ int nScript; /* Number of characters of text */
+};
+typedef struct HtmlLi HtmlLi;
+struct HtmlLi {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* What type of list is this? */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_16 cnt; /* Value for this element (if inside <OL>) */
+ Html_16 x; /* X coordinate of the bullet */
+ Html_32 y; /* Y coordinate of the bullet */
+};
+typedef struct HtmlImageMarkup HtmlImageMarkup;
+typedef struct HtmlImage HtmlImage;
+struct HtmlImageMarkup {
+ HtmlMarkupElement markup;
+ Html_u8 align; /* Alignment. See IMAGE_ALIGN_ defines below */
+ Html_u8 textAscent; /* Ascent of text font in force at the <IMG> */
+ Html_u8 textDescent; /* Descent of text font in force at the <IMG> */
+ Html_u8 redrawNeeded; /* Need to redraw this image because the image
+ ** content changed. */
+ Html_16 h; /* Actual height of the image */
+ Html_16 w; /* Actual width of the image */
+ Html_16 ascent; /* How far image extends above "y" */
+ Html_16 descent; /* How far image extends below "y" */
+ Html_16 x; /* X coordinate of left edge of the image */
+ Html_32 y; /* Y coordinate of image baseline */
+ char *zAlt; /* Alternative text */
+ HtmlImage *pImage; /* Corresponding HtmlImage structure */
+ HtmlElement *pNext; /* Next markup using the same HtmlImage structure */
+};
+typedef struct HtmlHr HtmlHr;
+struct HtmlHr {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 is3D; /* Is it drawn 3D? */
+};
+typedef struct HtmlForm HtmlForm;
+struct HtmlForm {
+ HtmlMarkupElement markup;
+ Html_u16 id; /* Unique number assigned to this form */
+};
+typedef struct HtmlListStart HtmlListStart;
+struct HtmlListStart {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* One of the LI_TYPE_ defines above */
+ Html_u8 compact; /* True if the COMPACT flag is present */
+ Html_u16 cnt; /* Next value for <OL> */
+ Html_u16 width; /* How much space to allow for indentation */
+ HtmlElement *pPrev; /* Next higher level list, or NULL */
+};
+typedef struct HtmlInput HtmlInput;
+typedef struct HtmlWidget HtmlWidget;
+struct HtmlInput {
+ HtmlMarkupElement markup;
+ HtmlElement *pForm; /* The <FORM> to which this belongs */
+ HtmlElement *pNext; /* Next element in a list of all input elements */
+ Tk_Window tkwin; /* The window that implements this control */
+ HtmlWidget *htmlPtr; /* The whole widget. Needed by geometry callbacks */
+ HtmlElement *pEnd; /* End tag for <TEXTAREA>, etc. */
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 padLeft; /* Extra padding on left side of the control */
+ Html_u8 align; /* One of the IMAGE_ALIGN_xxx types */
+ Html_u8 textAscent; /* Ascent for the current font */
+ Html_u8 textDescent; /* descent for the current font */
+ Html_u8 type; /* What type of input is this? */
+ Html_u8 sized; /* True if this input has been sized already */
+ Html_u16 cnt; /* Used to derive widget name. 0 if no widget */
+};
+typedef struct HtmlRef HtmlRef;
+struct HtmlRef {
+ HtmlMarkupElement markup;
+ HtmlElement *pOther; /* Pointer to some other Html element */
+};
+typedef struct HtmlAnchor HtmlAnchor;
+struct HtmlAnchor {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Top edge for this element */
+};
+typedef struct HtmlTokenMap HtmlTokenMap;
+struct HtmlTokenMap {
+ char *zName; /* Name of a markup */
+ Html_16 type; /* Markup type code */
+ Html_16 extra; /* Extra space needed above HtmlBaseElement */
+ HtmlTokenMap *pCollide; /* Hash table collision chain */
+};
+extern HtmlTokenMap HtmlMarkupMap[];
+#define HTML_MARKUP_COUNT 147
+#define HTML_MARKUP_HASH_SIZE 163
+#define Html_TypeCount 151
+#define Html_EndXMP 151
+#define Html_XMP 150
+#define Html_WBR 149
+#define Html_EndVAR 148
+#define Html_VAR 147
+#define Html_EndUL 146
+#define Html_UL 145
+#define Html_EndU 144
+#define Html_U 143
+#define Html_EndTT 142
+#define Html_TT 141
+#define Html_EndTR 140
+#define Html_TR 139
+#define Html_EndTITLE 138
+#define Html_TITLE 137
+#define Html_EndTH 136
+#define Html_TH 135
+#define Html_EndTEXTAREA 134
+#define Html_TEXTAREA 133
+#define Html_EndTD 132
+#define Html_TD 131
+#define Html_EndTABLE 130
+#define Html_TABLE 129
+#define Html_EndSUP 128
+#define Html_SUP 127
+#define Html_EndSUB 126
+#define Html_SUB 125
+#define Html_STYLE 124
+#define Html_EndSTRONG 123
+#define Html_STRONG 122
+#define Html_EndSTRIKE 121
+#define Html_STRIKE 120
+#define Html_EndSMALL 119
+#define Html_SMALL 118
+#define Html_EndSELECT 117
+#define Html_SELECT 116
+#define Html_SCRIPT 115
+#define Html_EndSAMP 114
+#define Html_SAMP 113
+#define Html_EndS 112
+#define Html_S 111
+#define Html_EndPRE 110
+#define Html_PRE 109
+#define Html_PLAINTEXT 108
+#define Html_EndPARAM 107
+#define Html_PARAM 106
+#define Html_EndP 105
+#define Html_P 104
+#define Html_EndOPTION 103
+#define Html_OPTION 102
+#define Html_EndOL 101
+#define Html_OL 100
+#define Html_EndNOSCRIPT 99
+#define Html_NOSCRIPT 98
+#define Html_EndNOFRAME 97
+#define Html_NOFRAME 96
+#define Html_EndNOBR 95
+#define Html_NOBR 94
+#define Html_NEXTID 93
+#define Html_META 92
+#define Html_EndMENU 91
+#define Html_MENU 90
+#define Html_EndMARQUEE 89
+#define Html_MARQUEE 88
+#define Html_EndMAP 87
+#define Html_MAP 86
+#define Html_EndLISTING 85
+#define Html_LISTING 84
+#define Html_LINK 83
+#define Html_EndLI 82
+#define Html_LI 81
+#define Html_EndKBD 80
+#define Html_KBD 79
+#define Html_ISINDEX 78
+#define Html_INPUT 77
+#define Html_IMG 76
+#define Html_IFRAME 75
+#define Html_EndI 74
+#define Html_I 73
+#define Html_EndHTML 72
+#define Html_HTML 71
+#define Html_HR 70
+#define Html_EndH6 69
+#define Html_H6 68
+#define Html_EndH5 67
+#define Html_H5 66
+#define Html_EndH4 65
+#define Html_H4 64
+#define Html_EndH3 63
+#define Html_H3 62
+#define Html_EndH2 61
+#define Html_H2 60
+#define Html_EndH1 59
+#define Html_H1 58
+#define Html_EndFRAMESET 57
+#define Html_FRAMESET 56
+#define Html_EndFRAME 55
+#define Html_FRAME 54
+#define Html_EndFORM 53
+#define Html_FORM 52
+#define Html_EndFONT 51
+#define Html_FONT 50
+#define Html_EMBED 49
+#define Html_EndEM 48
+#define Html_EM 47
+#define Html_EndDT 46
+#define Html_DT 45
+#define Html_EndDL 44
+#define Html_DL 43
+#define Html_EndDIV 42
+#define Html_DIV 41
+#define Html_EndDIR 40
+#define Html_DIR 39
+#define Html_EndDFN 38
+#define Html_DFN 37
+#define Html_EndDD 36
+#define Html_DD 35
+#define Html_EndCOMMENT 34
+#define Html_COMMENT 33
+#define Html_EndCODE 32
+#define Html_CODE 31
+#define Html_EndCITE 30
+#define Html_CITE 29
+#define Html_EndCENTER 28
+#define Html_CENTER 27
+#define Html_EndCAPTION 26
+#define Html_CAPTION 25
+#define Html_BR 24
+#define Html_EndBODY 23
+#define Html_BODY 22
+#define Html_EndBLOCKQUOTE 21
+#define Html_BLOCKQUOTE 20
+#define Html_EndBIG 19
+#define Html_BIG 18
+#define Html_BGSOUND 17
+#define Html_EndBASEFONT 16
+#define Html_BASEFONT 15
+#define Html_BASE 14
+#define Html_EndB 13
+#define Html_B 12
+#define Html_AREA 11
+#define Html_EndAPPLET 10
+#define Html_APPLET 9
+#define Html_EndADDRESS 8
+#define Html_ADDRESS 7
+#define Html_EndA 6
+#define Html_A 5
+#define Html_Block 4
+#define HtmlIsMarkup(X) ((X)->base.type>Html_Block)
+#define Html_Unknown 3
+#define Html_Space 2
+#define Html_Text 1
+#define INTERFACE 0
+typedef struct HtmlTextElement HtmlTextElement;
+struct HtmlTextElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_32 y; /* y coordinate where text should be rendered */
+ Html_16 x; /* x coordinate where text should be rendered */
+ Html_16 w; /* width of this token in pixels */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_u8 spaceWidth; /* Width of one space in the current font */
+ char zText[1]; /* Text for this element. Null terminated */
+};
+typedef struct HtmlSpaceElement HtmlSpaceElement;
+struct HtmlSpaceElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_16 w; /* Width of a single space in current font */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+};
+typedef struct HtmlBlock HtmlBlock;
+struct HtmlBlock {
+ HtmlBaseElement base; /* Superclass. Must be first */
+ char *z; /* Space to hold text when n>0 */
+ int top, bottom; /* Extremes of y coordinates */
+ Html_u16 left, right; /* Left and right boundry of this object */
+ Html_u16 n; /* Number of characters in z[] */
+ HtmlBlock *pPrev, *pNext; /* Linked list of all Blocks */
+};
+union HtmlElement {
+ HtmlElement *pNext;
+ HtmlBaseElement base;
+ HtmlTextElement text;
+ HtmlSpaceElement space;
+ HtmlMarkupElement markup;
+ HtmlCell cell;
+ HtmlTable table;
+ HtmlRef ref;
+ HtmlLi li;
+ HtmlListStart list;
+ HtmlImageMarkup image;
+ HtmlInput input;
+ HtmlForm form;
+ HtmlHr hr;
+ HtmlAnchor anchor;
+ HtmlScript script;
+ HtmlBlock block;
+};
+struct HtmlImage {
+ HtmlWidget *htmlPtr; /* The owner of this image */
+ Tk_Image image; /* The Tk image token */
+ Html_32 w; /* Requested width of this image (0 if none) */
+ Html_32 h; /* Requested height of this image (0 if none) */
+ char *zUrl; /* The URL for this image. */
+ char *zWidth, *zHeight; /* Width and height in the <img> markup. */
+ HtmlImage *pNext; /* Next image on the list */
+ HtmlElement *pList; /* List of all <IMG> markups that use this
+ ** same image */
+};
+typedef struct HtmlIndex HtmlIndex;
+struct HtmlIndex {
+ HtmlElement *p; /* The token containing the character */
+ int i; /* Index of the character */
+};
+typedef struct HtmlStyleStack HtmlStyleStack;
+typedef struct HtmlLayoutContext HtmlLayoutContext;
+typedef struct HtmlMargin HtmlMargin;
+struct HtmlLayoutContext {
+ HtmlWidget *htmlPtr; /* The html widget undergoing layout */
+ HtmlElement *pStart; /* Start of elements to layout */
+ HtmlElement *pEnd; /* Stop when reaching this element */
+ int headRoom; /* Extra space wanted above this line */
+ int top; /* Absolute top of drawing area */
+ int bottom; /* Bottom of previous line */
+ int left, right; /* Left and right extremes of drawing area */
+ int pageWidth; /* Width of the layout field, including
+ ** the margins */
+ int maxX, maxY; /* Maximum X and Y values of paint */
+ HtmlMargin *leftMargin; /* Stack of left margins */
+ HtmlMargin *rightMargin; /* Stack of right margins */
+};
+#define N_FONT_FAMILY 8
+#define N_FONT_SIZE 7
+#define N_FONT (N_FONT_FAMILY*N_FONT_SIZE)
+#define N_COLOR 16 /* Total number of colors */
+typedef struct GcCache GcCache;
+struct GcCache {
+ GC gc; /* The graphics context */
+ Html_u8 font; /* Font used for this context */
+ Html_u8 color; /* Color used for this context */
+ Html_u8 index; /* Index used for LRU replacement */
+};
+#define N_CACHE_GC 16
+struct HtmlWidget {
+ Tk_Window tkwin; /* The main window for this widget */
+ Tk_Window clipwin; /* The clipping window in which all text is
+ ** rendered. */
+ char *zClipwin; /* Name of the clipping window. */
+ Display *display; /* The X11 Server that contains tkwin */
+ Tcl_Interp *interp; /* The interpreter in which the widget lives */
+ char *zCmdName; /* Name of the command */
+ HtmlElement *pFirst; /* First HTML token on a list of them all */
+ HtmlElement *pLast; /* Last HTML token on the list */
+ int nToken; /* Number of HTML tokens on the list.
+ * Html_Block tokens don't count. */
+ HtmlElement *lastSized; /* Last HTML element that has been sized */
+ HtmlElement *nextPlaced; /* Next HTML element that needs to be
+ * positioned on canvas. */
+ HtmlBlock *firstBlock; /* List of all HtmlBlock tokens */
+ HtmlBlock *lastBlock; /* Last HtmlBlock in the list */
+ HtmlElement *firstInput; /* First <INPUT> element */
+ HtmlElement *lastInput; /* Last <INPUT> element */
+ int nInput; /* The number of <INPUT> elements */
+ int nForm; /* The number of <FORM> elements */
+ int varId; /* Used to construct a unique name for a
+ ** global array used by <INPUT> elements */
+
+ /*
+ * Information about the selected region of text
+ */
+ HtmlIndex selBegin; /* Start of the selection */
+ HtmlIndex selEnd; /* End of the selection */
+ HtmlBlock *pSelStartBlock; /* Block in which selection starts */
+ Html_16 selStartIndex; /* Index in pSelStartBlock of first selected
+ * character */
+ Html_16 selEndIndex; /* Index of last selecte char in pSelEndBlock */
+ HtmlBlock *pSelEndBlock; /* Block in which selection ends */
+
+ /*
+ * Information about the insertion cursor
+ */
+ int insOnTime; /* How long the cursor states one (millisec) */
+ int insOffTime; /* How long it is off (milliseconds) */
+ int insStatus; /* Is it visible? */
+ Tcl_TimerToken insTimer; /* Timer used to flash the insertion cursor */
+ HtmlIndex ins; /* The insertion cursor position */
+ HtmlBlock *pInsBlock; /* The HtmlBlock containing the cursor */
+ int insIndex; /* Index in pInsBlock of the cursor */
+
+ /*
+ * The following fields hold state information used by
+ * the tokenizer.
+ */
+ char *zText; /* Complete text of the unparsed HTML */
+ int nText; /* Number of characters in zText */
+ int nAlloc; /* Space allocated for zText */
+ int nComplete; /* How much of zText has actually been
+ * converted into tokens */
+ int iCol; /* The column in which zText[nComplete]
+ * occurs. Used to resolve tabs in input */
+ int iPlaintext; /* If not zero, this is the token type that
+ * caused us to go into plaintext mode. One
+ * of Html_PLAINTEXT, Html_LISTING or
+ * Html_XMP */
+ HtmlScript *pScript; /* <SCRIPT> currently being parsed */
+ char *zHandler[Html_TypeCount]; /* If not NULL, this is a TCL routine that
+ * is used to process tokens of the given
+ * type */
+ /*
+ * These fields hold state information used by the HtmlAddStyle routine.
+ * We have to store this state information here since HtmlAddStyle
+ * operates incrementally. This information must be carried from
+ * one incremental execution to the next.
+ */
+ HtmlStyleStack *styleStack; /* The style stack */
+ int paraAlignment; /* Justification associated with <p> */
+ int rowAlignment; /* Justification associated with <tr> */
+ int anchorFlags; /* Style flags associated with <A>...</A> */
+ int inDt; /* Style flags associated with <DT>...</DT> */
+ int inTr; /* True if within <tr>..</tr> */
+ int inTd; /* True if within <td>..</td> or <th>..</th> */
+ HtmlElement *anchorStart; /* Most recent <a href=...> */
+ HtmlElement *formStart; /* Most recent <form> */
+ HtmlElement *formElemStart; /* Most recent <textarea> or <select> */
+ HtmlElement *innerList; /* The inner most <OL> or <UL> */
+
+ /*
+ * These fields are used to hold the state of the layout engine.
+ * Because the layout is incremental, this state must be held for
+ * the life of the widget.
+ */
+ HtmlLayoutContext layoutContext;
+
+ /*
+ * Information used when displaying the widget:
+ */
+ Tk_3DBorder border; /* Background color */
+ int borderWidth; /* Width of the border. */
+ int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ int inset; /* Total width of highlight and 3-D border */
+ Tk_Font aFont[N_FONT]; /* Information about all screen fonts */
+ char fontValid[(N_FONT+7)/8]; /* If bit N%8 of work N/8 of this field is 0
+ * if aFont[N] needs to be reallocated before
+ * being used. */
+ XColor *apColor[N_COLOR]; /* Information about all colors */
+ int colorUsed; /* bit N is 1 if color N is in use. Only
+ ** applies to colors that aren't predefined */
+ int iDark[N_COLOR]; /* Dark 3D shadow of color K is iDark[K] */
+ int iLight[N_COLOR]; /* Light 3D shadow of color K is iLight[K] */
+ XColor *fgColor; /* Color of normal text. apColor[0] */
+ XColor *newLinkColor; /* Color of unvisitied links. apColor[1] */
+ XColor *oldLinkColor; /* Color of visitied links. apColor[2] */
+ XColor *selectionColor; /* Background color for selections */
+ GcCache aGcCache[N_CACHE_GC]; /* A cache of GCs for general use */
+ int lastGC; /* Index of recently used GC */
+ HtmlImage *imageList; /* A list of all images */
+ int width, height; /* User-requested size of the usable drawing
+ * area, in pixels. Borders and padding
+ * make the actual window a little larger */
+ int realWidth, realHeight; /* The actual physical size of tkwin as
+ * reported in the most recent ConfigureNotify
+ * event. */
+ int padx, pady; /* Separation between the edge of the window
+ * and rendered HTML. */
+ int underlineLinks; /* TRUE if we should underline hyperlinks */
+
+ /* Information about the selection
+ */
+ int exportSelection; /* True if the selection is automatically
+ * exported to the clipboard */
+
+ /* Callback commands. The HTML parser will invoke callbacks from time
+ ** to time to find out information it needs to complete formatting of
+ ** the document. The following fields define the callback commands.
+ */
+ char *zIsVisited; /* Command to tell if a hyperlink has already
+ ** been visited */
+ char *zGetImage; /* Command to get an image from a URL */
+ char *zFrameCommand; /* Command for handling <frameset> markup */
+ char *zAppletCommand; /* Command to process applets */
+ char *zResolverCommand; /* Command to resolve URIs */
+ char *zFormCommand; /* When user presses Submit */
+ char *zHyperlinkCommand; /* Invoked when a hyperlink is clicked */
+ char *zFontCommand; /* Invoked to find font names */
+ char *zScriptCommand; /* Invoked for each <SCRIPT> markup */
+
+ /*
+ * Miscellaneous information:
+ */
+ int tableRelief; /* 3d effects on <TABLE> */
+ int ruleRelief; /* 3d effects on <HR> */
+ char *zBase; /* The base URI */
+ char *zBaseHref; /* zBase as modified by <BASE HREF=..> markup */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ char *takeFocus; /* Value of -takefocus option; not used in
+ * the C code, but used by keyboard traversal
+ * scripts. Malloc'ed, but may be NULL. */
+ char *yScrollCmd; /* Command prefix for communicating with
+ * vertical scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ char *xScrollCmd; /* Command prefix for communicating with
+ * horizontal scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ int xOffset, yOffset; /* Current scroll position. These form the
+ * coordinate in the virtual canvas that
+ * corresponds to (0,0) on the physical screen
+ * in window tkwin */
+ int maxX, maxY; /* Maximum extent of any "paint" that appears
+ * on the virtual canvas. Used to compute
+ * scrollbar positions. */
+ int dirtyLeft, dirtyTop; /* Top left corner of region to redraw. These
+ * are physical screen coordinates relative to
+ * clipwin, not tkwin. */
+ int dirtyRight, dirtyBottom; /* Bottom right corner of region to redraw */
+ int locked; /* Number of locks on this structure. Don't
+ ** delete until it reaches zero. */
+ int flags; /* Various flags; see below for
+ * definitions. */
+};
+struct HtmlStyleStack {
+ HtmlStyleStack *pNext; /* Next style on the stack */
+ int type; /* A markup that ends this style. Ex: Html_EndEM */
+ HtmlStyle style; /* The currently active style. */
+};
+struct HtmlMargin {
+ int indent; /* Size of the current margin */
+ int bottom; /* Y value at which this margin expires */
+ int tag; /* Markup that will cancel this margin */
+ HtmlMargin *pNext; /* Previous margin */
+};
diff --git a/tkhtml1/src/htmlurl.c b/tkhtml1/src/htmlurl.c
new file mode 100644
index 0000000..bf8808f
--- /dev/null
+++ b/tkhtml1/src/htmlurl.c
@@ -0,0 +1,402 @@
+/*
+** Routines for processing URLs.
+**
+** Copyright (C) 1997-2000 D. Richard Hipp
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** drh@acm.org
+** http://www.hwaci.com/drh/
+*/
+#include <tk.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include "htmlurl.h"
+
+#if LOCAL_INTERFACE
+/*
+** A parsed URI is held in an instance of the following structure.
+** Each component is recorded in memory obtained from HtmlAlloc().
+**
+** The examples are from the URI
+**
+** http://192.168.1.1:8080/cgi-bin/printenv?name=xyzzy&addr=none#frag
+*/
+struct HtmlUri {
+ char *zScheme; /* Ex: "http" */
+ char *zAuthority; /* Ex: "192.168.1.1:8080" */
+ char *zPath; /* Ex: "cgi-bin/printenv" */
+ char *zQuery; /* Ex: "name=xyzzy&addr=none" */
+ char *zFragment; /* Ex: "frag" */
+};
+#endif
+
+/*
+** Return the length of the next component of the URL in z[] given
+** that the component starts at z[0]. The initial sequence of the
+** component must be zInit[]. The component is terminated by any
+** character in zTerm[]. The length returned is 0 if the component
+** doesn't exist. The length includes the zInit[] string, but not
+** the termination character.
+**
+** Component zInit zTerm
+** ---------- ------- -------
+** scheme "" ":/?#"
+** authority "//" "/?#"
+** path "/" "?#"
+** query "?" "#"
+** fragment "#" ""
+*/
+static int ComponentLength(const char *z, const char *zInit, const char *zTerm){
+ int i, n;
+ for(n=0; zInit[n]; n++){
+ if( zInit[n]!=z[n] ) return 0;
+ }
+ while( z[n] ){
+ for(i=0; zTerm[i]; i++){
+ if( z[n]==zTerm[i] ) return n;
+ }
+ n++;
+ }
+ return n;
+}
+
+/*
+** Duplicate a string of length n.
+*/
+static char *StrNDup(const char *z, int n){
+ char *zResult;
+ if(!n)
+ return NULL;
+ if( n<=0 ){
+ n = strlen(z);
+ }
+ zResult = HtmlAlloc( n + 1 );
+ if( zResult ){
+ memcpy(zResult, z, n);
+ zResult[n] = 0;
+ TestPoint(0);
+ }
+ return zResult;
+}
+
+/*
+** Parse a text URI into an HtmlUri structure.
+*/
+static HtmlUri *ParseUri(const char *zUri){
+ HtmlUri *p;
+ int n;
+
+ p = HtmlAlloc( sizeof(*p) );
+ if( p==0 ) return 0;
+ memset(p, 0, sizeof(*p));
+ if( zUri==0 || zUri[0]==0 ) return p;
+ while( isspace(zUri[0]) ){ zUri++; }
+ n = ComponentLength(zUri, "", ":/?# ");
+ if( n>0 && zUri[n]==':' ){
+ p->zScheme = StrNDup(zUri, n);
+ zUri += n+1;
+ }
+ n = ComponentLength(zUri, "//", "/?# ");
+ if( n>0 ){
+ p->zAuthority = StrNDup(&zUri[2], n-2);
+ zUri += n;
+ }
+ /* allow spaces in path */
+ /* n = ComponentLength(zUri, "", "?# ");*/
+ n = ComponentLength(zUri, "", "?#");
+ if( n>0 ){
+ p->zPath = StrNDup(zUri, n);
+ zUri += n;
+ }
+ n = ComponentLength(zUri, "?", "# ");
+ if( n>0 ){
+ p->zQuery = StrNDup(&zUri[1], n-1);
+ zUri += n;
+ }
+ n = ComponentLength(zUri, "#", " ");
+ if( n>0 ){
+ p->zFragment = StrNDup(&zUri[1], n-1);
+ }
+ return p;
+}
+
+/*
+** Delete an HtmlUri structure.
+*/
+static void FreeUri(HtmlUri *p){
+ if( p==0 ) return;
+ if( p->zScheme ) HtmlFree(p->zScheme);
+ if( p->zAuthority ) HtmlFree(p->zAuthority);
+ if( p->zPath ) HtmlFree(p->zPath);
+ if( p->zQuery ) HtmlFree(p->zQuery);
+ if( p->zFragment ) HtmlFree(p->zFragment);
+ HtmlFree(p);
+}
+
+/*
+** Create a string to hold the given URI. Memory to hold the string
+** is obtained from HtmlAlloc() and must be freed by the calling
+** function.
+*/
+static char *BuildUri(HtmlUri *p){
+ int n = 1;
+ char *z;
+ if( p->zScheme ) n += strlen(p->zScheme)+1;
+ if( p->zAuthority ) n += strlen(p->zAuthority)+2;
+ if( p->zPath ) n += strlen(p->zPath)+1;
+ if( p->zQuery ) n += strlen(p->zQuery)+1;
+ if( p->zFragment ) n += strlen(p->zFragment)+1;
+ z = HtmlAlloc( n );
+ if( z==0 ) return 0;
+ n = 0;
+ if( p->zScheme ){
+ sprintf(z, "%s:", p->zScheme);
+ n = strlen(z);
+ }
+ if( p->zAuthority ){
+ sprintf(&z[n], "//%s", p->zAuthority);
+ n += strlen(&z[n]);
+ }
+ if( p->zPath ){
+ sprintf(&z[n], "%s", p->zPath);
+ n += strlen(&z[n]);
+ }
+ if( p->zQuery ){
+ sprintf(&z[n], "?%s", p->zQuery);
+ n += strlen(&z[n]);
+ }
+ if( p->zFragment ){
+ sprintf(&z[n], "#%s", p->zFragment);
+ }else{
+ z[n] = 0;
+ }
+ return z;
+}
+
+/*
+** Replace the string in *pzDest with the string in zSrc
+*/
+static void ReplaceStr(char **pzDest, const char *zSrc){
+ if( *pzDest!=0 ) HtmlFree(*pzDest);
+ if( zSrc==0 ){
+ *pzDest = 0;
+ }else{
+ *pzDest = StrNDup(zSrc, -1);
+ }
+}
+
+/*
+** Remove leading and trailing spaces from the given string. Return
+** a new string obtained from HtmlAlloc().
+*/
+static char *Trim(char *z){
+ int i;
+ char *zNew;
+ while( isspace(*z) ) z++;
+ i = strlen(z);
+ zNew = HtmlAlloc( i+1 );
+ if( zNew==0 ) return 0;
+ strcpy(zNew, z);
+ if( i>0 && isspace(zNew[i-1]) ){
+ i--;
+ zNew[i] = 0;
+ }
+ return zNew;
+}
+
+/*
+** The input azSeries[] is a sequence of URIs. This command must
+** resolve them all and put the result in the interp->result field
+** of the interpreter associated with the HTML widget. Return
+** TCL_OK on success and TCL_ERROR if there is a failure.
+**
+** This function can cause the HTML widget to be deleted or changed
+** arbitrarily.
+*/
+int HtmlCallResolver(
+ HtmlWidget *htmlPtr, /* The widget that is doing the resolving. */
+ char **azSeries /* A list of URIs. NULL terminated */
+){
+ int rc = TCL_OK; /* Return value of this function. */
+ char *z;
+
+ HtmlVerifyLock(htmlPtr);
+ if( htmlPtr->zResolverCommand && htmlPtr->zResolverCommand[0] ){
+ /*
+ ** Append the current base URI then the azSeries arguments to the
+ ** TCL command specified by the -resolvercommand optoin, then execute
+ ** the result.
+ **
+ ** The -resolvercommand could do nasty things, such as delete
+ ** the HTML widget out from under us. Be prepared for the worst.
+ */
+ Tcl_DString cmd;
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, htmlPtr->zResolverCommand, -1);
+ if( htmlPtr->zBaseHref && htmlPtr->zBaseHref[0] ){
+ z = Trim(htmlPtr->zBaseHref);
+ }else if( htmlPtr->zBase && htmlPtr->zBase[0] ){
+ z = Trim(htmlPtr->zBase);
+ }
+ else
+ z=0;
+
+ if( z ){
+ Tcl_DStringAppendElement(&cmd, z);
+ HtmlFree(z);
+ }
+ while( azSeries[0] ){
+ z = Trim(azSeries[0]);
+ if( z ){
+ Tcl_DStringAppendElement(&cmd, z);
+ HtmlFree(z);
+ }
+ azSeries++;
+ }
+ HtmlLock(htmlPtr);
+ rc = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if( HtmlUnlock(htmlPtr) ) return TCL_ERROR;
+ if( rc!=TCL_OK ){
+ Tcl_AddErrorInfo(htmlPtr->interp,
+ "\n (-resolvercommand executed by HTML widget)");
+ }
+ }else{
+ /*
+ ** No -resolvercommand has been specified. Do the default
+ ** resolver algorithm specified in section 5.2 of RFC 2396.
+ */
+ HtmlUri *base, *term;
+ if( htmlPtr->zBaseHref && htmlPtr->zBaseHref[0] ){
+ base = ParseUri(htmlPtr->zBaseHref);
+ }else{
+ base = ParseUri(htmlPtr->zBase);
+ }
+ while( azSeries[0] ){
+ term = ParseUri(azSeries[0]);
+ azSeries++;
+ if( term->zScheme==0 && term->zAuthority==0 && term->zPath==0
+ && term->zQuery==0 && term->zFragment ){
+ ReplaceStr(&base->zFragment, term->zFragment);
+ }else if( term->zScheme ){
+ HtmlUri temp;
+ temp = *term;
+ *term = *base;
+ *base = temp;
+ }else if( term->zAuthority ){
+ ReplaceStr(&base->zAuthority, term->zAuthority);
+ ReplaceStr(&base->zPath, term->zPath);
+ ReplaceStr(&base->zQuery, term->zQuery);
+ ReplaceStr(&base->zFragment, term->zFragment);
+ }else if( term->zPath && (term->zPath[0]=='/' || base->zPath==0) ){
+ ReplaceStr(&base->zPath, term->zPath);
+ ReplaceStr(&base->zQuery, term->zQuery);
+ ReplaceStr(&base->zFragment, term->zFragment);
+ }else if( term->zPath && base->zPath ){
+ char *zBuf;
+ int i, j;
+ zBuf = HtmlAlloc( strlen(base->zPath) + strlen(term->zPath) + 2 );
+ if( zBuf ){
+ sprintf(zBuf,"%s", base->zPath);
+ for(i=strlen(zBuf)-1; i>=0 && zBuf[i]!='/'; i--){ zBuf[i] = 0; }
+ strcat(zBuf, term->zPath);
+ for(i=0; zBuf[i]; i++){
+ if( zBuf[i]=='/' && zBuf[i+1]=='.' && zBuf[i+2]=='/' ){
+ // strcpy into same buf is undefined
+ // strcpy(&zBuf[i+1], &zBuf[i+3]);
+ int ll = strlen(zBuf+i+3)+1;
+ char* tmp = malloc(ll);
+ strncpy(tmp,zBuf+i+3,ll);
+ strcpy(zBuf+i+1, tmp);
+ free(tmp);
+ i--;
+ continue;
+ }
+ if( zBuf[i]=='/' && zBuf[i+1]=='.' && zBuf[i+2]==0 ){
+ zBuf[i+1] = 0;
+ continue;
+ }
+ if( i>0 && zBuf[i]=='/' && zBuf[i+1]=='.' && zBuf[i+2]=='.'
+ && (zBuf[i+3]=='/' || zBuf[i+3]==0) ){
+ for(j=i-1; j>=0 && zBuf[j]!='/'; j--){}
+ if( zBuf[i+3] ){
+ // strcpy into same buf is undefined
+ // strcpy(&zBuf[j+1], &zBuf[i+4]);
+ int ll = strlen(zBuf+i+4)+1;
+ char* tmp = malloc(ll);
+ strncpy(tmp,zBuf+i+4,ll);
+ strcpy(zBuf+j+1, tmp);
+ free(tmp);
+ }else{
+ zBuf[j+1] = 0;
+ }
+ i = j-1;
+ if( i<-1 ) i = -1;
+ continue;
+ }
+ }
+ /* look for /../ at begining */
+ if (!strncmp(zBuf,"/../",4)) {
+ // strcpy into same buf is undefined
+ // strcpy(zBuf,zBuf+3);
+ int ll = strlen(zBuf+3)+1;
+ char* tmp = malloc(ll);
+ strncpy(tmp,zBuf+3,ll);
+ strcpy(zBuf, tmp);
+ free(tmp);
+ }
+ HtmlFree(base->zPath);
+ base->zPath = zBuf;
+ }
+ ReplaceStr(&base->zQuery, term->zQuery);
+ ReplaceStr(&base->zFragment, term->zFragment);
+ }
+ FreeUri(term);
+ }
+ Tcl_SetResult(htmlPtr->interp, BuildUri(base), TCL_DYNAMIC);
+ FreeUri(base);
+ }
+ return rc;
+}
+
+/*
+** This is a convenient wrapper routine for HtmlCallResolver.
+** It makes a copy of the result into memory obtained from HtmlAlloc()
+** and invokes Tcl_ResetResult().
+*/
+char *HtmlResolveUri(HtmlWidget *htmlPtr, char *zUri){
+ char *azSeq[2];
+ char *zSrc;
+ int result;
+
+ if( zUri==0 || *zUri==0 ) return 0;
+ azSeq[0] = zUri;
+ azSeq[1] = 0;
+ HtmlLock(htmlPtr);
+ result = HtmlCallResolver(htmlPtr, azSeq);
+ if( HtmlUnlock(htmlPtr) ) return 0;
+ if( result==TCL_OK ){
+ zSrc = HtmlAlloc( strlen(Tcl_GetStringResult(htmlPtr->interp)) + 1 );
+ if( zSrc ) strcpy(zSrc, Tcl_GetStringResult(htmlPtr->interp));
+ }else{
+ zSrc = 0;
+ }
+ Tcl_ResetResult(htmlPtr->interp);
+ return zSrc;
+}
diff --git a/tkhtml1/src/htmlurl.h b/tkhtml1/src/htmlurl.h
new file mode 100644
index 0000000..871c48f
--- /dev/null
+++ b/tkhtml1/src/htmlurl.h
@@ -0,0 +1,457 @@
+/* This file was automatically generated. Do not edit! */
+typedef struct HtmlWidget HtmlWidget;
+char *HtmlResolveUri(HtmlWidget *htmlPtr,char *zUri);
+int HtmlUnlock(HtmlWidget *htmlPtr);
+void HtmlLock(HtmlWidget *htmlPtr);
+void HtmlTPCantHappen(const char *zFile,int line);
+#if defined(COVERAGE_TEST)
+# define HtmlVerifyLock(H) if((H)->locked==0)HtmlTPCantHappen(__FILE__,__LINE__)
+#endif
+#if !(defined(COVERAGE_TEST))
+# define HtmlVerifyLock(H)
+#endif
+typedef union HtmlElement HtmlElement;
+typedef struct HtmlBlock HtmlBlock;
+typedef struct HtmlIndex HtmlIndex;
+struct HtmlIndex {
+ HtmlElement *p; /* The token containing the character */
+ int i; /* Index of the character */
+};
+typedef short Html_16;
+typedef struct HtmlScript HtmlScript;
+#define Html_TypeCount 151
+typedef struct HtmlStyleStack HtmlStyleStack;
+typedef struct HtmlLayoutContext HtmlLayoutContext;
+typedef struct HtmlMargin HtmlMargin;
+struct HtmlLayoutContext {
+ HtmlWidget *htmlPtr; /* The html widget undergoing layout */
+ HtmlElement *pStart; /* Start of elements to layout */
+ HtmlElement *pEnd; /* Stop when reaching this element */
+ int headRoom; /* Extra space wanted above this line */
+ int top; /* Absolute top of drawing area */
+ int bottom; /* Bottom of previous line */
+ int left, right; /* Left and right extremes of drawing area */
+ int pageWidth; /* Width of the layout field, including
+ ** the margins */
+ int maxX, maxY; /* Maximum X and Y values of paint */
+ HtmlMargin *leftMargin; /* Stack of left margins */
+ HtmlMargin *rightMargin; /* Stack of right margins */
+};
+#define N_FONT_FAMILY 8
+#define N_FONT_SIZE 7
+#define N_FONT (N_FONT_FAMILY*N_FONT_SIZE)
+#define N_COLOR 16 /* Total number of colors */
+typedef struct GcCache GcCache;
+typedef unsigned char Html_u8;
+struct GcCache {
+ GC gc; /* The graphics context */
+ Html_u8 font; /* Font used for this context */
+ Html_u8 color; /* Color used for this context */
+ Html_u8 index; /* Index used for LRU replacement */
+};
+#define N_CACHE_GC 16
+typedef struct HtmlImage HtmlImage;
+struct HtmlWidget {
+ Tk_Window tkwin; /* The main window for this widget */
+ Tk_Window clipwin; /* The clipping window in which all text is
+ ** rendered. */
+ char *zClipwin; /* Name of the clipping window. */
+ Display *display; /* The X11 Server that contains tkwin */
+ Tcl_Interp *interp; /* The interpreter in which the widget lives */
+ char *zCmdName; /* Name of the command */
+ HtmlElement *pFirst; /* First HTML token on a list of them all */
+ HtmlElement *pLast; /* Last HTML token on the list */
+ int nToken; /* Number of HTML tokens on the list.
+ * Html_Block tokens don't count. */
+ HtmlElement *lastSized; /* Last HTML element that has been sized */
+ HtmlElement *nextPlaced; /* Next HTML element that needs to be
+ * positioned on canvas. */
+ HtmlBlock *firstBlock; /* List of all HtmlBlock tokens */
+ HtmlBlock *lastBlock; /* Last HtmlBlock in the list */
+ HtmlElement *firstInput; /* First <INPUT> element */
+ HtmlElement *lastInput; /* Last <INPUT> element */
+ int nInput; /* The number of <INPUT> elements */
+ int nForm; /* The number of <FORM> elements */
+ int varId; /* Used to construct a unique name for a
+ ** global array used by <INPUT> elements */
+
+ /*
+ * Information about the selected region of text
+ */
+ HtmlIndex selBegin; /* Start of the selection */
+ HtmlIndex selEnd; /* End of the selection */
+ HtmlBlock *pSelStartBlock; /* Block in which selection starts */
+ Html_16 selStartIndex; /* Index in pSelStartBlock of first selected
+ * character */
+ Html_16 selEndIndex; /* Index of last selecte char in pSelEndBlock */
+ HtmlBlock *pSelEndBlock; /* Block in which selection ends */
+
+ /*
+ * Information about the insertion cursor
+ */
+ int insOnTime; /* How long the cursor states one (millisec) */
+ int insOffTime; /* How long it is off (milliseconds) */
+ int insStatus; /* Is it visible? */
+ Tcl_TimerToken insTimer; /* Timer used to flash the insertion cursor */
+ HtmlIndex ins; /* The insertion cursor position */
+ HtmlBlock *pInsBlock; /* The HtmlBlock containing the cursor */
+ int insIndex; /* Index in pInsBlock of the cursor */
+
+ /*
+ * The following fields hold state information used by
+ * the tokenizer.
+ */
+ char *zText; /* Complete text of the unparsed HTML */
+ int nText; /* Number of characters in zText */
+ int nAlloc; /* Space allocated for zText */
+ int nComplete; /* How much of zText has actually been
+ * converted into tokens */
+ int iCol; /* The column in which zText[nComplete]
+ * occurs. Used to resolve tabs in input */
+ int iPlaintext; /* If not zero, this is the token type that
+ * caused us to go into plaintext mode. One
+ * of Html_PLAINTEXT, Html_LISTING or
+ * Html_XMP */
+ HtmlScript *pScript; /* <SCRIPT> currently being parsed */
+ char *zHandler[Html_TypeCount]; /* If not NULL, this is a TCL routine that
+ * is used to process tokens of the given
+ * type */
+ /*
+ * These fields hold state information used by the HtmlAddStyle routine.
+ * We have to store this state information here since HtmlAddStyle
+ * operates incrementally. This information must be carried from
+ * one incremental execution to the next.
+ */
+ HtmlStyleStack *styleStack; /* The style stack */
+ int paraAlignment; /* Justification associated with <p> */
+ int rowAlignment; /* Justification associated with <tr> */
+ int anchorFlags; /* Style flags associated with <A>...</A> */
+ int inDt; /* Style flags associated with <DT>...</DT> */
+ int inTr; /* True if within <tr>..</tr> */
+ int inTd; /* True if within <td>..</td> or <th>..</th> */
+ HtmlElement *anchorStart; /* Most recent <a href=...> */
+ HtmlElement *formStart; /* Most recent <form> */
+ HtmlElement *formElemStart; /* Most recent <textarea> or <select> */
+ HtmlElement *innerList; /* The inner most <OL> or <UL> */
+
+ /*
+ * These fields are used to hold the state of the layout engine.
+ * Because the layout is incremental, this state must be held for
+ * the life of the widget.
+ */
+ HtmlLayoutContext layoutContext;
+
+ /*
+ * Information used when displaying the widget:
+ */
+ Tk_3DBorder border; /* Background color */
+ int borderWidth; /* Width of the border. */
+ int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ int inset; /* Total width of highlight and 3-D border */
+ Tk_Font aFont[N_FONT]; /* Information about all screen fonts */
+ char fontValid[(N_FONT+7)/8]; /* If bit N%8 of work N/8 of this field is 0
+ * if aFont[N] needs to be reallocated before
+ * being used. */
+ XColor *apColor[N_COLOR]; /* Information about all colors */
+ int colorUsed; /* bit N is 1 if color N is in use. Only
+ ** applies to colors that aren't predefined */
+ int iDark[N_COLOR]; /* Dark 3D shadow of color K is iDark[K] */
+ int iLight[N_COLOR]; /* Light 3D shadow of color K is iLight[K] */
+ XColor *fgColor; /* Color of normal text. apColor[0] */
+ XColor *newLinkColor; /* Color of unvisitied links. apColor[1] */
+ XColor *oldLinkColor; /* Color of visitied links. apColor[2] */
+ XColor *selectionColor; /* Background color for selections */
+ GcCache aGcCache[N_CACHE_GC]; /* A cache of GCs for general use */
+ int lastGC; /* Index of recently used GC */
+ HtmlImage *imageList; /* A list of all images */
+ int width, height; /* User-requested size of the usable drawing
+ * area, in pixels. Borders and padding
+ * make the actual window a little larger */
+ int realWidth, realHeight; /* The actual physical size of tkwin as
+ * reported in the most recent ConfigureNotify
+ * event. */
+ int padx, pady; /* Separation between the edge of the window
+ * and rendered HTML. */
+ int underlineLinks; /* TRUE if we should underline hyperlinks */
+
+ /* Information about the selection
+ */
+ int exportSelection; /* True if the selection is automatically
+ * exported to the clipboard */
+
+ /* Callback commands. The HTML parser will invoke callbacks from time
+ ** to time to find out information it needs to complete formatting of
+ ** the document. The following fields define the callback commands.
+ */
+ char *zIsVisited; /* Command to tell if a hyperlink has already
+ ** been visited */
+ char *zGetImage; /* Command to get an image from a URL */
+ char *zFrameCommand; /* Command for handling <frameset> markup */
+ char *zAppletCommand; /* Command to process applets */
+ char *zResolverCommand; /* Command to resolve URIs */
+ char *zFormCommand; /* When user presses Submit */
+ char *zHyperlinkCommand; /* Invoked when a hyperlink is clicked */
+ char *zFontCommand; /* Invoked to find font names */
+ char *zScriptCommand; /* Invoked for each <SCRIPT> markup */
+
+ /*
+ * Miscellaneous information:
+ */
+ int tableRelief; /* 3d effects on <TABLE> */
+ int ruleRelief; /* 3d effects on <HR> */
+ char *zBase; /* The base URI */
+ char *zBaseHref; /* zBase as modified by <BASE HREF=..> markup */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ char *takeFocus; /* Value of -takefocus option; not used in
+ * the C code, but used by keyboard traversal
+ * scripts. Malloc'ed, but may be NULL. */
+ char *yScrollCmd; /* Command prefix for communicating with
+ * vertical scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ char *xScrollCmd; /* Command prefix for communicating with
+ * horizontal scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ int xOffset, yOffset; /* Current scroll position. These form the
+ * coordinate in the virtual canvas that
+ * corresponds to (0,0) on the physical screen
+ * in window tkwin */
+ int maxX, maxY; /* Maximum extent of any "paint" that appears
+ * on the virtual canvas. Used to compute
+ * scrollbar positions. */
+ int dirtyLeft, dirtyTop; /* Top left corner of region to redraw. These
+ * are physical screen coordinates relative to
+ * clipwin, not tkwin. */
+ int dirtyRight, dirtyBottom; /* Bottom right corner of region to redraw */
+ int locked; /* Number of locks on this structure. Don't
+ ** delete until it reaches zero. */
+ int flags; /* Various flags; see below for
+ * definitions. */
+};
+int HtmlCallResolver(HtmlWidget *htmlPtr,char **azSeries);
+#define HtmlFree(A) Tcl_Free((char*)(A))
+#if defined(COVERAGE_TEST)
+extern int HtmlTPArray[2000];
+# define TestPoint(X) {extern int HtmlTPArray[]; HtmlTPArray[X]++;}
+#endif
+#if !(defined(COVERAGE_TEST))
+# define TestPoint(X)
+#endif
+/*#define HtmlAlloc(A) ((void*)Tcl_Alloc(A))*/
+void* HtmlAlloc(size_t);
+typedef struct HtmlUri HtmlUri;
+struct HtmlUri {
+ char *zScheme; /* Ex: "http" */
+ char *zAuthority; /* Ex: "192.168.1.1:8080" */
+ char *zPath; /* Ex: "cgi-bin/printenv" */
+ char *zQuery; /* Ex: "name=xyzzy&addr=none" */
+ char *zFragment; /* Ex: "frag" */
+};
+#define LOCAL_INTERFACE 0
+typedef struct HtmlBaseElement HtmlBaseElement;
+typedef struct HtmlStyle HtmlStyle;
+struct HtmlStyle {
+ unsigned int font : 6; /* Font to use for display */
+ unsigned int color : 4; /* Foreground color */
+ signed int subscript : 4; /* Positive for <sup>, negative for <sub> */
+ unsigned int align : 2; /* Horizontal alignment */
+ unsigned int bgcolor : 4; /* Background color */
+ unsigned int flags : 12; /* the STY_ flags below */
+};
+struct HtmlBaseElement {
+ HtmlElement *pNext; /* Next input token in a list of them all */
+ HtmlElement *pPrev; /* Previous token in a list of them all */
+ HtmlStyle style; /* The rendering style for this token */
+ Html_u8 type; /* The token type. */
+ Html_u8 flags; /* The HTML_ flags below */
+ Html_16 count; /* Various uses, depending on "type" */
+};
+typedef struct HtmlTextElement HtmlTextElement;
+typedef int Html_32;
+struct HtmlTextElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_32 y; /* y coordinate where text should be rendered */
+ Html_16 x; /* x coordinate where text should be rendered */
+ Html_16 w; /* width of this token in pixels */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_u8 spaceWidth; /* Width of one space in the current font */
+ char zText[1]; /* Text for this element. Null terminated */
+};
+typedef struct HtmlSpaceElement HtmlSpaceElement;
+struct HtmlSpaceElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_16 w; /* Width of a single space in current font */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+};
+typedef struct HtmlMarkupElement HtmlMarkupElement;
+struct HtmlMarkupElement {
+ HtmlBaseElement base;
+ char **argv;
+};
+typedef struct HtmlCell HtmlCell;
+struct HtmlCell {
+ HtmlMarkupElement markup;
+ Html_16 rowspan; /* Number of rows spanned by this cell */
+ Html_16 colspan; /* Number of columns spanned by this cell */
+ Html_16 x; /* X coordinate of left edge of border */
+ Html_16 w; /* Width of the border */
+ Html_32 y; /* Y coordinate of top of border indentation */
+ Html_32 h; /* Height of the border */
+ HtmlElement *pTable; /* Pointer back to the <table> */
+ HtmlElement *pEnd; /* Element that ends this cell */
+};
+typedef struct HtmlTable HtmlTable;
+typedef unsigned short Html_u16;
+#define HTML_MAX_COLUMNS 40
+struct HtmlTable {
+ HtmlMarkupElement markup;
+ Html_u8 borderWidth; /* Width of the border */
+ Html_u8 nCol; /* Number of columns */
+ Html_u16 nRow; /* Number of rows */
+ Html_32 y; /* top edge of table border */
+ Html_32 h; /* height of the table border */
+ Html_16 x; /* left edge of table border */
+ Html_16 w; /* width of the table border */
+ int minW[HTML_MAX_COLUMNS+1]; /* minimum width of each column */
+ int maxW[HTML_MAX_COLUMNS+1]; /* maximum width of each column */
+};
+typedef struct HtmlRef HtmlRef;
+struct HtmlRef {
+ HtmlMarkupElement markup;
+ HtmlElement *pOther; /* Pointer to some other Html element */
+};
+typedef struct HtmlLi HtmlLi;
+struct HtmlLi {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* What type of list is this? */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_16 cnt; /* Value for this element (if inside <OL>) */
+ Html_16 x; /* X coordinate of the bullet */
+ Html_32 y; /* Y coordinate of the bullet */
+};
+typedef struct HtmlListStart HtmlListStart;
+struct HtmlListStart {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* One of the LI_TYPE_ defines above */
+ Html_u8 compact; /* True if the COMPACT flag is present */
+ Html_u16 cnt; /* Next value for <OL> */
+ Html_u16 width; /* How much space to allow for indentation */
+ HtmlElement *pPrev; /* Next higher level list, or NULL */
+};
+typedef struct HtmlImageMarkup HtmlImageMarkup;
+struct HtmlImageMarkup {
+ HtmlMarkupElement markup;
+ Html_u8 align; /* Alignment. See IMAGE_ALIGN_ defines below */
+ Html_u8 textAscent; /* Ascent of text font in force at the <IMG> */
+ Html_u8 textDescent; /* Descent of text font in force at the <IMG> */
+ Html_u8 redrawNeeded; /* Need to redraw this image because the image
+ ** content changed. */
+ Html_16 h; /* Actual height of the image */
+ Html_16 w; /* Actual width of the image */
+ Html_16 ascent; /* How far image extends above "y" */
+ Html_16 descent; /* How far image extends below "y" */
+ Html_16 x; /* X coordinate of left edge of the image */
+ Html_32 y; /* Y coordinate of image baseline */
+ char *zAlt; /* Alternative text */
+ HtmlImage *pImage; /* Corresponding HtmlImage structure */
+ HtmlElement *pNext; /* Next markup using the same HtmlImage structure */
+};
+typedef struct HtmlInput HtmlInput;
+struct HtmlInput {
+ HtmlMarkupElement markup;
+ HtmlElement *pForm; /* The <FORM> to which this belongs */
+ HtmlElement *pNext; /* Next element in a list of all input elements */
+ Tk_Window tkwin; /* The window that implements this control */
+ HtmlWidget *htmlPtr; /* The whole widget. Needed by geometry callbacks */
+ HtmlElement *pEnd; /* End tag for <TEXTAREA>, etc. */
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 padLeft; /* Extra padding on left side of the control */
+ Html_u8 align; /* One of the IMAGE_ALIGN_xxx types */
+ Html_u8 textAscent; /* Ascent for the current font */
+ Html_u8 textDescent; /* descent for the current font */
+ Html_u8 type; /* What type of input is this? */
+ Html_u8 sized; /* True if this input has been sized already */
+ Html_u16 cnt; /* Used to derive widget name. 0 if no widget */
+};
+typedef struct HtmlForm HtmlForm;
+struct HtmlForm {
+ HtmlMarkupElement markup;
+ Html_u16 id; /* Unique number assigned to this form */
+};
+typedef struct HtmlHr HtmlHr;
+struct HtmlHr {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 is3D; /* Is it drawn 3D? */
+};
+typedef struct HtmlAnchor HtmlAnchor;
+struct HtmlAnchor {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Top edge for this element */
+};
+struct HtmlScript {
+ HtmlMarkupElement markup;
+ char *zScript; /* Complete text of this script */
+ int nScript; /* Number of characters of text */
+};
+struct HtmlBlock {
+ HtmlBaseElement base; /* Superclass. Must be first */
+ char *z; /* Space to hold text when n>0 */
+ int top, bottom; /* Extremes of y coordinates */
+ Html_u16 left, right; /* Left and right boundry of this object */
+ Html_u16 n; /* Number of characters in z[] */
+ HtmlBlock *pPrev, *pNext; /* Linked list of all Blocks */
+};
+union HtmlElement {
+ HtmlElement *pNext;
+ HtmlBaseElement base;
+ HtmlTextElement text;
+ HtmlSpaceElement space;
+ HtmlMarkupElement markup;
+ HtmlCell cell;
+ HtmlTable table;
+ HtmlRef ref;
+ HtmlLi li;
+ HtmlListStart list;
+ HtmlImageMarkup image;
+ HtmlInput input;
+ HtmlForm form;
+ HtmlHr hr;
+ HtmlAnchor anchor;
+ HtmlScript script;
+ HtmlBlock block;
+};
+struct HtmlImage {
+ HtmlWidget *htmlPtr; /* The owner of this image */
+ Tk_Image image; /* The Tk image token */
+ Html_32 w; /* Requested width of this image (0 if none) */
+ Html_32 h; /* Requested height of this image (0 if none) */
+ char *zUrl; /* The URL for this image. */
+ char *zWidth, *zHeight; /* Width and height in the <img> markup. */
+ HtmlImage *pNext; /* Next image on the list */
+ HtmlElement *pList; /* List of all <IMG> markups that use this
+ ** same image */
+};
+struct HtmlStyleStack {
+ HtmlStyleStack *pNext; /* Next style on the stack */
+ int type; /* A markup that ends this style. Ex: Html_EndEM */
+ HtmlStyle style; /* The currently active style. */
+};
+struct HtmlMargin {
+ int indent; /* Size of the current margin */
+ int bottom; /* Y value at which this margin expires */
+ int tag; /* Markup that will cancel this margin */
+ HtmlMargin *pNext; /* Previous margin */
+};
diff --git a/tkhtml1/src/htmlwidget.c b/tkhtml1/src/htmlwidget.c
new file mode 100644
index 0000000..3d6e632
--- /dev/null
+++ b/tkhtml1/src/htmlwidget.c
@@ -0,0 +1,2043 @@
+/*
+** The main routine for the HTML widget for Tcl/Tk
+**
+** Copyright (C) 1997-2000 D. Richard Hipp
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** drh@acm.org
+** http://www.hwaci.com/drh/
+*/
+#include <tk.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "htmlwidget.h"
+/*
+#ifdef USE_TK_STUBS
+# include <tkIntXlibDecls.h>
+#endif
+*/
+/*
+** This global variable is used for tracing the operation of
+** the Html formatter.
+*/
+int HtmlTraceMask = 0;
+
+#ifdef __WIN32__
+# define DEF_FRAME_BG_COLOR "SystemButtonFace"
+# define DEF_FRAME_BG_MONO "White"
+# define DEF_FRAME_CURSOR ""
+# define DEF_BUTTON_FG "SystemButtonText"
+# define DEF_BUTTON_HIGHLIGHT_BG "SystemButtonFace"
+# define DEF_BUTTON_HIGHLIGHT "SystemWindowFrame"
+#else
+# define DEF_FRAME_BG_COLOR "#d9d9d9"
+# define DEF_FRAME_BG_MONO "White"
+# define DEF_FRAME_CURSOR ""
+# define DEF_BUTTON_FG "Black"
+# define DEF_BUTTON_HIGHLIGHT_BG "#d9d9d9"
+# define DEF_BUTTON_HIGHLIGHT "Black"
+#endif
+
+/*
+** Information used for argv parsing.
+*/
+static Tk_ConfigSpec configSpecs[] = {
+ {TK_CONFIG_STRING, "-appletcommand", "appletCommand", "HtmlCallback",
+ DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zAppletCommand), 0},
+ {TK_CONFIG_BORDER, "-background", "background", "Background",
+ DEF_HTML_BG_COLOR, Tk_Offset(HtmlWidget, border),
+ TK_CONFIG_COLOR_ONLY},
+ {TK_CONFIG_BORDER, "-background", "background", "Background",
+ DEF_HTML_BG_MONO, Tk_Offset(HtmlWidget, border),
+ TK_CONFIG_MONO_ONLY},
+ {TK_CONFIG_STRING, "-base", "base", "Base",
+ "", Tk_Offset(HtmlWidget, zBase), 0},
+ {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
+ (char *) NULL, 0, 0},
+ {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
+ (char *) NULL, 0, 0},
+ {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
+ DEF_HTML_BORDER_WIDTH, Tk_Offset(HtmlWidget, borderWidth), 0},
+ {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
+ DEF_HTML_CURSOR, Tk_Offset(HtmlWidget, cursor), TK_CONFIG_NULL_OK},
+ {TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection","ExportSelection",
+ DEF_HTML_EXPORT_SEL, Tk_Offset(HtmlWidget, exportSelection), 0},
+ {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
+ (char *) NULL, 0, 0},
+ {TK_CONFIG_STRING, "-fontcommand", "fontCommand", "FontCommand",
+ DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zFontCommand), 0},
+ {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
+ DEF_HTML_FG, Tk_Offset(HtmlWidget, fgColor), 0},
+ {TK_CONFIG_STRING, "-formcommand", "formlCommand", "HtmlCallback",
+ DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zFormCommand), 0},
+ {TK_CONFIG_STRING, "-framecommand", "frameCommand", "HtmlCallback",
+ DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zFrameCommand), 0},
+ {TK_CONFIG_PIXELS, "-height", "height", "Height",
+ DEF_HTML_HEIGHT, Tk_Offset(HtmlWidget, height), 0},
+ {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
+ "HighlightBackground", DEF_HTML_HIGHLIGHT_BG,
+ Tk_Offset(HtmlWidget, highlightBgColorPtr), 0},
+ {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
+ DEF_HTML_HIGHLIGHT, Tk_Offset(HtmlWidget, highlightColorPtr), 0},
+ {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
+ "HighlightThickness",
+ DEF_HTML_HIGHLIGHT_WIDTH, Tk_Offset(HtmlWidget, highlightWidth), 0},
+ {TK_CONFIG_STRING, "-hyperlinkcommand", "hyperlinkCommand", "HtmlCallback",
+ DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zHyperlinkCommand), 0},
+ {TK_CONFIG_STRING, "-imagecommand", "imageCommand", "HtmlCallback",
+ DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zGetImage), 0},
+ {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime",
+ DEF_HTML_INSERT_OFF_TIME, Tk_Offset(HtmlWidget, insOffTime), 0},
+ {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime",
+ DEF_HTML_INSERT_ON_TIME, Tk_Offset(HtmlWidget, insOnTime), 0},
+ {TK_CONFIG_STRING, "-isvisitedcommand", "isVisitedCommand", "HtmlCallback",
+ DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zIsVisited), 0},
+ {TK_CONFIG_PIXELS, "-padx", "padX", "Pad",
+ DEF_HTML_PADX, Tk_Offset(HtmlWidget, padx), 0},
+ {TK_CONFIG_PIXELS, "-pady", "padY", "Pad",
+ DEF_HTML_PADY, Tk_Offset(HtmlWidget, pady), 0},
+ {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
+ DEF_HTML_RELIEF, Tk_Offset(HtmlWidget, relief), 0},
+ {TK_CONFIG_STRING, "-resolvercommand", "resolverCommand", "HtmlCallback",
+ DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zResolverCommand), 0},
+ {TK_CONFIG_RELIEF, "-rulerelief", "ruleRelief","RuleRelief",
+ "sunken", Tk_Offset(HtmlWidget, ruleRelief), 0},
+ {TK_CONFIG_STRING, "-scriptcommand", "scriptCommand", "HtmlCallback",
+ "", Tk_Offset(HtmlWidget, zScriptCommand), 0},
+ {TK_CONFIG_COLOR, "-selectioncolor", "background", "Background",
+ DEF_HTML_SELECTION_COLOR, Tk_Offset(HtmlWidget, selectionColor), 0},
+ {TK_CONFIG_RELIEF, "-tablerelief", "tableRelief","TableRelief",
+ "raised", Tk_Offset(HtmlWidget, tableRelief), 0},
+ {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
+ DEF_HTML_TAKE_FOCUS, Tk_Offset(HtmlWidget, takeFocus),
+ TK_CONFIG_NULL_OK},
+ {TK_CONFIG_COLOR, "-unvisitedcolor", "foreground", "Foreground",
+ DEF_HTML_UNVISITED, Tk_Offset(HtmlWidget, newLinkColor), 0},
+ {TK_CONFIG_BOOLEAN, "-underlinehyperlinks", "underlineHyperlinks",
+ "UnderlineHyperlinks", "1", Tk_Offset(HtmlWidget, underlineLinks), 0},
+ {TK_CONFIG_COLOR, "-visitedcolor", "foreground", "Foreground",
+ DEF_HTML_VISITED, Tk_Offset(HtmlWidget, oldLinkColor), 0},
+ {TK_CONFIG_PIXELS, "-width", "width", "Width",
+ DEF_HTML_WIDTH, Tk_Offset(HtmlWidget, width), 0},
+ {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
+ DEF_HTML_SCROLL_COMMAND, Tk_Offset(HtmlWidget, xScrollCmd),
+ TK_CONFIG_NULL_OK},
+ {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
+ DEF_HTML_SCROLL_COMMAND, Tk_Offset(HtmlWidget, yScrollCmd),
+ TK_CONFIG_NULL_OK},
+ {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, 0}
+};
+
+/*
+** Get a copy of the config specs.
+*/
+Tk_ConfigSpec *HtmlConfigSpec(void){
+ return configSpecs;
+}
+
+/*
+** Find the width of the usable drawing area in pixels. If the window isn't
+** mapped, use the size requested by the user.
+**
+** The usable drawing area is the area available for displaying rendered
+** HTML. The usable drawing area does not include the 3D border or the
+** padx and pady boundry within the 3D border. The usable drawing area
+** is the size of the clipping window.
+*/
+int HtmlUsableWidth(HtmlWidget *htmlPtr){
+ int w;
+ Tk_Window tkwin = htmlPtr->tkwin;
+ if( tkwin && Tk_IsMapped(tkwin) ){
+ w = Tk_Width(tkwin) - 2*(htmlPtr->padx + htmlPtr->inset);
+ TestPoint(0);
+ }else{
+ w = htmlPtr->width;
+ TestPoint(0);
+ }
+ return w;
+}
+
+/*
+** Find the height of the usable drawing area in pixels. If the window isn't
+** mapped, use the size requested by the user.
+**
+** The usable drawing area is the area available for displaying rendered
+** HTML. The usable drawing area does not include the 3D border or the
+** padx and pady boundry within the 3D border. The usable drawing area
+** is the size of the clipping window.
+*/
+int HtmlUsableHeight(HtmlWidget *htmlPtr){
+ int h;
+ Tk_Window tkwin = htmlPtr->tkwin;
+ if( tkwin && Tk_IsMapped(tkwin) ){
+ h = Tk_Height(tkwin) - 2*(htmlPtr->pady + htmlPtr->inset);
+ TestPoint(0);
+ }else{
+ h = htmlPtr->height;
+ TestPoint(0);
+ }
+ return h;
+}
+
+/*
+** Compute a pair of floating point numbers that describe the current
+** vertical scroll position. The first number is the fraction of
+** the document that is off the top of the visible region and the second
+** number is the fraction that is beyond the end of the visible region.
+*/
+void HtmlComputeVerticalPosition(
+ HtmlWidget *htmlPtr,
+ char *buf /* Write the two floating point values here */
+){
+ int actual; /* Size of the viewing area */
+ double frac1, frac2;
+
+ actual = HtmlUsableHeight(htmlPtr);
+ if( htmlPtr->maxY <= 0 ){
+ frac1 = 0.0;
+ frac2 = 1.0;
+ TestPoint(0);
+ }else{
+ frac1 = (double)htmlPtr->yOffset/(double)htmlPtr->maxY;
+ if( frac1 > 1.0 ){
+ frac1 = 1.0;
+ TestPoint(0);
+ }else if( frac1 < 0.0 ){
+ frac1 = 0.0;
+ TestPoint(0);
+ }
+ frac2 = (double)(htmlPtr->yOffset+actual)/(double)htmlPtr->maxY;
+ if( frac2 > 1.0 ){
+ frac2 = 1.0;
+ TestPoint(0);
+ }else if( frac2 < 0.0 ){
+ frac2 = 0.0;
+ TestPoint(0);
+ }
+ }
+ sprintf(buf,"%g %g",frac1, frac2);
+}
+
+/*
+** Do the same thing for the horizontal direction
+*/
+void HtmlComputeHorizontalPosition(
+ HtmlWidget *htmlPtr,
+ char *buf /* Write the two floating point values here */
+){
+ int actual; /* Size of the viewing area */
+ double frac1, frac2;
+
+ actual = HtmlUsableWidth(htmlPtr);
+ if( htmlPtr->maxX <= 0 ){
+ frac1 = 0.0;
+ frac2 = 1.0;
+ TestPoint(0);
+ }else{
+ frac1 = (double)htmlPtr->xOffset/(double)htmlPtr->maxX;
+ if( frac1 > 1.0 ){
+ frac1 = 1.0;
+ TestPoint(0);
+ }else if( frac1 < 0.0 ){
+ frac1 = 0.0;
+ TestPoint(0);
+ }
+ frac2 = (double)(htmlPtr->xOffset+actual)/(double)htmlPtr->maxX;
+ if( frac2 > 1.0 ){
+ frac2 = 1.0;
+ TestPoint(0);
+ }else if( frac2 < 0.0 ){
+ frac2 = 0.0;
+ TestPoint(0);
+ }
+ }
+ sprintf(buf,"%g %g",frac1, frac2);
+}
+
+/*
+** Clear the cache of GCs
+*/
+static void ClearGcCache(HtmlWidget *htmlPtr){
+ int i;
+ for(i=0; i<N_CACHE_GC; i++){
+ if( htmlPtr->aGcCache[i].index ){
+ Tk_FreeGC(htmlPtr->display, htmlPtr->aGcCache[i].gc);
+ htmlPtr->aGcCache[i].index = 0;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ }
+}
+
+
+/*
+** This routine is called when the widget command is deleted. If the
+** widget isn't already in the process of being destroyed, this command
+** starts that process rolling.
+**
+** This routine can be called in two ways.
+**
+** (1) The window is destroyed, which causes the command to be deleted.
+** In this case, we don't have to do anything.
+**
+** (2) The command only is deleted (ex: "rename .html {}"). In that
+** case we need to destroy the window.
+*/
+static void HtmlCmdDeletedProc(ClientData clientData){
+ HtmlWidget *htmlPtr = (HtmlWidget*) clientData;
+ if (htmlPtr != NULL && htmlPtr->tkwin!=NULL ) {
+ Tk_Window tkwin = htmlPtr->tkwin;
+ htmlPtr->tkwin = NULL;
+ Tk_DestroyWindow(tkwin);
+ }
+}
+
+/*
+** Reset the main layout context in the main widget. This happens
+** before we redo the layout, or just before deleting the widget.
+*/
+static void ResetLayoutContext(HtmlWidget *htmlPtr){
+ htmlPtr->layoutContext.headRoom = 0;
+ htmlPtr->layoutContext.top = 0;
+ htmlPtr->layoutContext.bottom = 0;
+ HtmlClearMarginStack(&htmlPtr->layoutContext.leftMargin);
+ HtmlClearMarginStack(&htmlPtr->layoutContext.rightMargin);
+}
+
+/*
+** This routine is invoked in order to redraw all or part of the HTML
+** widget. This might happen because the display has changed, or in
+** response to an expose event. In all cases, though, this routine
+** is called by an idle callback.
+*/
+static void HtmlRedrawCallback(ClientData clientData){
+ HtmlWidget *htmlPtr = (HtmlWidget*)clientData;
+ Tk_Window tkwin = htmlPtr->tkwin;
+ Tk_Window clipwin = htmlPtr->clipwin;
+ Pixmap pixmap; /* The buffer on which to render HTML */
+ int x, y, w, h; /* Virtual canvas coordinates of area to draw */
+ int hw; /* highlight thickness */
+ int insetX, insetY; /* Total highlight thickness, border width and
+ ** padx/y */
+ int clipwinH, clipwinW; /* Width and height of the clipping window */
+ HtmlBlock *pBlock; /* For looping over blocks to be drawn */
+ int redoSelection = 0; /* True to recompute the selection */
+
+ /*
+ ** Don't bother doing anything if the widget is in the process of
+ ** being destroyed.
+ */
+ if( tkwin==0 ){
+ goto redrawExit;
+ }
+
+ /*
+ ** Recompute the layout, if necessary or requested.
+ **
+ ** Calling HtmlLayout() is tricky because HtmlLayout() may invoke one
+ ** or more callbacks (thru the "-imagecommand" callback, for instance)
+ ** and these callbacks could, in theory, do nasty things like delete
+ ** or unmap this widget. So we have to take precautions:
+ **
+ ** * Don't remove the REDRAW_PENDING flag until after HtmlLayout()
+ ** has been called, to prevent a recursive call to HtmlRedrawCallback().
+ **
+ ** * Call HtmlLock() on the htmlPtr structure to prevent it from
+ ** being deleted out from under us.
+ **
+ */
+ if( (htmlPtr->flags & RESIZE_ELEMENTS)!=0
+ && (htmlPtr->flags & STYLER_RUNNING)==0 ){
+ HtmlImage *pImage;
+ for(pImage=htmlPtr->imageList; pImage; pImage=pImage->pNext){
+ pImage->pList = 0;
+ }
+ htmlPtr->lastSized = 0;
+ htmlPtr->flags &= ~RESIZE_ELEMENTS;
+ htmlPtr->flags |= RELAYOUT;
+ }
+
+ /* We used to make a distinction between RELAYOUT and EXTEND_LAYOUT.
+ ** RELAYOUT would be used when the widget was resized, but the
+ ** less compute-intensive EXTEND_LAYOUT would be used when new
+ ** text was appended.
+ **
+ ** Unfortunately, EXTEND_LAYOUT has some problem that arise when
+ ** tables are used. The quick fix is to make an EXTEND_LAYOUT do
+ ** a complete RELAYOUT. Someday, we need to fix EXTEND_LAYOUT so
+ ** that it works right...
+ */
+ if( (htmlPtr->flags & (RELAYOUT|EXTEND_LAYOUT))!=0
+ && (htmlPtr->flags & STYLER_RUNNING)==0 ){
+ htmlPtr->nextPlaced = 0;
+ htmlPtr->nInput = 0;
+ htmlPtr->varId = 0;
+ htmlPtr->maxX = 0;
+ htmlPtr->maxY = 0;
+ ResetLayoutContext(htmlPtr);
+ htmlPtr->firstBlock = 0;
+ htmlPtr->lastBlock = 0;
+ redoSelection = 1;
+ htmlPtr->flags &= ~RELAYOUT;
+ htmlPtr->flags |= HSCROLL | VSCROLL | REDRAW_TEXT | EXTEND_LAYOUT;
+ }
+ if( (htmlPtr->flags & EXTEND_LAYOUT) && htmlPtr->pFirst!=0 ){
+ HtmlLock(htmlPtr);
+ HtmlLayout(htmlPtr);
+ if( HtmlUnlock(htmlPtr) ) goto redrawExit;
+ tkwin = htmlPtr->tkwin;
+ htmlPtr->flags &= ~EXTEND_LAYOUT;
+ HtmlFormBlocks(htmlPtr);
+ HtmlMapControls(htmlPtr);
+ if( redoSelection && htmlPtr->selBegin.p && htmlPtr->selEnd.p ){
+ HtmlUpdateSelection(htmlPtr,1);
+ HtmlUpdateInsert(htmlPtr);
+ }
+ }
+ htmlPtr->flags &= ~REDRAW_PENDING;
+
+ /* No need to do any actual drawing if we aren't mapped
+ */
+ if( !Tk_IsMapped(tkwin) ){
+ goto redrawExit;
+ }
+
+ /* Redraw the scrollbars. Take care here, since the scrollbar
+ ** update command could (in theory) delete the html widget, or
+ ** even the whole interpreter. Preserve critical data structures,
+ ** and check to see if we are still alive before continuing.
+ */
+ if( (htmlPtr->flags & (HSCROLL|VSCROLL)) != 0 ){
+ Tcl_Interp *interp = htmlPtr->interp;
+ int result;
+ char buf[200];
+
+ if( (htmlPtr->flags & HSCROLL)!=0 ){
+ if( htmlPtr->xScrollCmd && htmlPtr->xScrollCmd[0] ){
+ HtmlComputeHorizontalPosition(htmlPtr,buf);
+ HtmlLock(htmlPtr);
+ result = Tcl_VarEval(interp, htmlPtr->xScrollCmd, " ", buf, NULL);
+ if( HtmlUnlock(htmlPtr) ) goto redrawExit;
+ if (result != TCL_OK) {
+ Tcl_AddErrorInfo(interp,
+ "\n (horizontal scrolling command executed by html widget)");
+ Tcl_BackgroundError(interp);
+ TestPoint(0);
+ }
+ }
+ htmlPtr->flags &= ~HSCROLL;
+ }
+ if( (htmlPtr->flags & VSCROLL)!=0 && tkwin && Tk_IsMapped(tkwin) ){
+ if( htmlPtr->yScrollCmd && htmlPtr->yScrollCmd[0] ){
+ Tcl_Interp *interp = htmlPtr->interp;
+ int result;
+ char buf[200];
+ HtmlComputeVerticalPosition(htmlPtr,buf);
+ HtmlLock(htmlPtr);
+ result = Tcl_VarEval(interp, htmlPtr->yScrollCmd, " ", buf, NULL);
+ if( HtmlUnlock(htmlPtr) ) goto redrawExit;
+ if (result != TCL_OK) {
+ Tcl_AddErrorInfo(interp,
+ "\n (horizontal scrolling command executed by html widget)");
+ Tcl_BackgroundError(interp);
+ TestPoint(0);
+ }
+ }
+ htmlPtr->flags &= ~VSCROLL;
+ }
+ tkwin = htmlPtr->tkwin;
+ if( tkwin==0 || !Tk_IsMapped(tkwin) ){ goto redrawExit; }
+ if( htmlPtr->flags & REDRAW_PENDING ){ return; }
+ clipwin = htmlPtr->clipwin;
+ if( clipwin==0 ){ TestPoint(0); goto redrawExit; }
+ }
+
+ /* Redraw the focus highlight, if requested */
+ hw = htmlPtr->highlightWidth;
+ if( htmlPtr->flags & REDRAW_FOCUS ){
+ if( hw>0 ){
+ GC gc;
+ Tk_Window tkwin = htmlPtr->tkwin;
+
+ if( htmlPtr->flags & GOT_FOCUS ){
+ gc = Tk_GCForColor(htmlPtr->highlightColorPtr, Tk_WindowId(tkwin));
+ TestPoint(0);
+ }else{
+ gc = Tk_GCForColor(htmlPtr->highlightBgColorPtr, Tk_WindowId(tkwin));
+ TestPoint(0);
+ }
+ Tk_DrawFocusHighlight(tkwin, gc, hw, Tk_WindowId(tkwin));
+ }
+ htmlPtr->flags &= ~REDRAW_FOCUS;
+ }
+
+ /* Draw the borders around the parameter of the window. This is
+ ** drawn directly -- it is not double buffered.
+ */
+ if( htmlPtr->flags & REDRAW_BORDER ){
+ htmlPtr->flags &= ~REDRAW_BORDER;
+ Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), htmlPtr->border,
+ hw, /* x */
+ hw, /* y */
+ Tk_Width(tkwin) - 2*hw, /* width */
+ Tk_Height(tkwin) - 2*hw, /* height */
+ htmlPtr->borderWidth, htmlPtr->relief);
+ }
+
+ /*
+ ** If the styler is in a callback, unmap the clipping window and
+ ** abort further processing.
+ */
+ if( htmlPtr->flags & STYLER_RUNNING ){
+ if( Tk_IsMapped(clipwin) ){
+ Tk_UnmapWindow(clipwin);
+ }
+ goto earlyOut;
+ }
+
+ /*
+ ** If we don't have a clipping window, then something is seriously
+ ** wrong. We might as well give up.
+ */
+ if( clipwin==NULL ){ TestPoint(0); goto earlyOut; }
+
+ /* Resize, reposition and map the clipping window, if necessary */
+ insetX = htmlPtr->padx + htmlPtr->inset;
+ insetY = htmlPtr->pady + htmlPtr->inset;
+ if( htmlPtr->flags & RESIZE_CLIPWIN ){
+ int h, w;
+ Tk_MoveResizeWindow(clipwin, insetX, insetY,
+ htmlPtr->realWidth - 2*insetX,
+ htmlPtr->realHeight - 2*insetY);
+ if( !Tk_IsMapped(clipwin) ){
+ Tk_MapWindow(clipwin);
+ }
+ h = htmlPtr->realHeight - 2*insetY;
+ if( htmlPtr->yOffset + h > htmlPtr->maxY ){
+ htmlPtr->yOffset = htmlPtr->maxY - h;
+ }
+ if( htmlPtr->yOffset < 0 ){
+ htmlPtr->yOffset = 0;
+ }
+ w = htmlPtr->realWidth - 2*insetX;
+ if( htmlPtr->xOffset + h > htmlPtr->maxX ){
+ htmlPtr->xOffset = htmlPtr->maxX - w;
+ }
+ if( htmlPtr->xOffset < 0 ){
+ htmlPtr->xOffset = 0;
+ }
+ htmlPtr->flags &= ~RESIZE_CLIPWIN;
+ }
+ HtmlMapControls(htmlPtr);
+
+ /*
+ ** Compute the virtual canvas coordinates corresponding to the
+ ** dirty region of the clipping window.
+ */
+ clipwinW = Tk_Width(clipwin);
+ clipwinH = Tk_Height(clipwin);
+ if( htmlPtr->flags & REDRAW_TEXT ){
+ w = clipwinW;
+ h = clipwinH;
+ x = htmlPtr->xOffset;
+ y = htmlPtr->yOffset;
+ htmlPtr->dirtyLeft = 0;
+ htmlPtr->dirtyTop = 0;
+ htmlPtr->flags &= ~REDRAW_TEXT;
+ }else{
+ if( htmlPtr->dirtyLeft < 0 ){
+ htmlPtr->dirtyLeft = 0;
+ TestPoint(0);
+ }
+ if( htmlPtr->dirtyRight > clipwinW ){
+ htmlPtr->dirtyRight = clipwinW;
+ TestPoint(0);
+ }
+ if( htmlPtr->dirtyTop < 0 ){
+ htmlPtr->dirtyTop = 0;
+ TestPoint(0);
+ }
+ if( htmlPtr->dirtyBottom > clipwinH ){
+ htmlPtr->dirtyBottom = clipwinH;
+ TestPoint(0);
+ }
+ w = htmlPtr->dirtyRight - htmlPtr->dirtyLeft;
+ h = htmlPtr->dirtyBottom - htmlPtr->dirtyTop;
+ x = htmlPtr->xOffset + htmlPtr->dirtyLeft;
+ y = htmlPtr->yOffset + htmlPtr->dirtyTop;
+ }
+
+ /* Skip the rest of the drawing process if the area to be refreshed is
+ ** less than zero */
+ if( w>0 && h>0 ){
+ Display *display = htmlPtr->display;
+ int dead;
+ GC gcBg;
+ XRectangle xrec;
+ /* printf("Redraw %dx%d at %d,%d\n", w, h, x, y); */
+
+ /* Allocate and clear a pixmap upon which to draw */
+ gcBg = HtmlGetGC(htmlPtr, COLOR_Background, FONT_Any);
+ pixmap = Tk_GetPixmap(display, Tk_WindowId(clipwin),w,h,Tk_Depth(clipwin));
+ xrec.x = 0;
+ xrec.y = 0;
+ xrec.width = w;
+ xrec.height = h;
+ XFillRectangles(display, pixmap, gcBg, &xrec, 1);
+
+ /* Render all visible HTML onto the pixmap */
+ HtmlLock(htmlPtr);
+ for(pBlock=htmlPtr->firstBlock; pBlock; pBlock=pBlock->pNext){
+ if( pBlock->top <= y+h && pBlock->bottom >= y
+ && pBlock->left <= x+w && pBlock->right >= x ){
+ HtmlBlockDraw(htmlPtr,pBlock,pixmap,x,y,w,h);
+ if( htmlPtr->tkwin==0 ) break;
+ }
+ }
+ dead = HtmlUnlock(htmlPtr);
+
+ /* Finally, copy the pixmap onto the window and delete the pixmap */
+ if( !dead ){
+ XCopyArea(display, pixmap, Tk_WindowId(clipwin),
+ gcBg, 0, 0, w, h, htmlPtr->dirtyLeft, htmlPtr->dirtyTop);
+ }
+ Tk_FreePixmap(display, pixmap);
+ if( dead ) goto redrawExit;
+ /* XFlush(display); */
+ }
+
+ /* Redraw images, if requested */
+ if( htmlPtr->flags & REDRAW_IMAGES ){
+ HtmlImage *pImage;
+ HtmlElement *pElem;
+ int top, bottom, left, right; /* Coordinates of the clipping window */
+ int imageTop; /* Top edge of image */
+
+ top = htmlPtr->yOffset;
+ bottom = top + HtmlUsableHeight(htmlPtr);
+ left = htmlPtr->xOffset;
+ right = left + HtmlUsableWidth(htmlPtr);
+ for(pImage = htmlPtr->imageList; pImage; pImage=pImage->pNext){
+ for(pElem = pImage->pList; pElem; pElem=pElem->image.pNext){
+ if( pElem->image.redrawNeeded==0 ) continue;
+ imageTop = pElem->image.y - pElem->image.ascent;
+ if( imageTop > bottom
+ || imageTop + pElem->image.h < top
+ || pElem->image.x > right
+ || pElem->image.x + pElem->image.w < left ){
+ TestPoint(0);
+ continue;
+ }
+ HtmlDrawImage(pElem, Tk_WindowId(htmlPtr->clipwin),
+ left, top, right, bottom);
+ }
+ }
+ htmlPtr->flags &= ~REDRAW_IMAGES;
+ }
+
+ /* Set the dirty region to the empty set. */
+ earlyOut:
+ htmlPtr->dirtyTop = LARGE_NUMBER;
+ htmlPtr->dirtyLeft = LARGE_NUMBER;
+ htmlPtr->dirtyBottom = 0;
+ htmlPtr->dirtyRight = 0;
+ redrawExit:
+ return;
+}
+
+/*
+** Make sure that a call to the HtmlRedrawCallback() routine has been
+** queued.
+*/
+void HtmlScheduleRedraw(HtmlWidget *htmlPtr){
+ if( (htmlPtr->flags & REDRAW_PENDING)==0
+ && htmlPtr->tkwin!=0
+ && Tk_IsMapped(htmlPtr->tkwin)
+ ){
+ Tcl_DoWhenIdle(HtmlRedrawCallback, (ClientData)htmlPtr);
+ htmlPtr->flags |= REDRAW_PENDING;
+ }
+}
+
+/*
+** If any part of the screen needs to be redrawn, Then call this routine
+** with the values of a box (in window coordinates) that needs to be
+** redrawn. This routine will make sure an idle callback is scheduled
+** to do the redraw.
+**
+** The box coordinates are relative to the clipping window (clipwin),
+** not the main window (tkwin).
+*/
+void HtmlRedrawArea(
+ HtmlWidget *htmlPtr, /* The widget to be redrawn */
+ int left, int top, /* Top left corner of area to redraw */
+ int right, int bottom /* bottom right corner of area to redraw */
+){
+ if( bottom < 0 ){ TestPoint(0); return; }
+ if( top > htmlPtr->realHeight ){ TestPoint(0); return; }
+ if( right < 0 ){ TestPoint(0); return; }
+ if( left > htmlPtr->realWidth ){ TestPoint(0); return; }
+ if( htmlPtr->dirtyTop > top ){ htmlPtr->dirtyTop = top; TestPoint(0);}
+ if( htmlPtr->dirtyLeft > left ){ htmlPtr->dirtyLeft = left; TestPoint(0);}
+ if( htmlPtr->dirtyBottom < bottom ){
+ htmlPtr->dirtyBottom = bottom;
+ TestPoint(0);
+ }
+ if( htmlPtr->dirtyRight < right ){ htmlPtr->dirtyRight = right; TestPoint(0);}
+ HtmlScheduleRedraw(htmlPtr);
+ TestPoint(0);
+}
+
+/* Redraw the HtmlBlock given.
+*/
+void HtmlRedrawBlock(HtmlWidget *htmlPtr, HtmlBlock *p){
+ if( p ){
+ HtmlRedrawArea(htmlPtr,
+ p->left - htmlPtr->xOffset,
+ p->top - htmlPtr->yOffset,
+ p->right - htmlPtr->xOffset + 1,
+ p->bottom - htmlPtr->yOffset
+ );
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+}
+
+/*
+** Call this routine to force the entire widget to be redrawn.
+*/
+void HtmlRedrawEverything(HtmlWidget *htmlPtr){
+ htmlPtr->flags |= REDRAW_FOCUS | REDRAW_TEXT | REDRAW_BORDER;
+ HtmlScheduleRedraw(htmlPtr);
+ TestPoint(0);
+}
+
+/*
+** Do the redrawing right now. Don't wait.
+*/
+#if 0 /* NOT_USED */
+static void HtmlRedrawPush(HtmlWidget *htmlPtr){
+ if( htmlPtr->flags & REDRAW_PENDING ){
+ Tcl_CancelIdleCall(HtmlRedrawCallback, (ClientData)htmlPtr);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ HtmlRedrawCallback( (ClientData)htmlPtr );
+}
+#endif
+
+/*
+** Call this routine to cause all of the rendered HTML at the
+** virtual canvas coordinate of Y and beyond to be redrawn.
+*/
+void HtmlRedrawText(HtmlWidget *htmlPtr, int y){
+ int yOffset; /* Top-most visible canvas coordinate */
+ int clipHeight; /* Height of the clipping window */
+
+ yOffset = htmlPtr->yOffset;
+ clipHeight = HtmlUsableHeight(htmlPtr);
+ y -= yOffset;
+ if( y < clipHeight ){
+ HtmlRedrawArea(htmlPtr, 0, y, LARGE_NUMBER, clipHeight);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+}
+
+/*
+** Recalculate the preferred size of the html widget and pass this
+** along to the geometry manager.
+*/
+static void HtmlRecomputeGeometry(HtmlWidget *htmlPtr){
+ int w, h; /* Total width and height of the widget */
+
+ htmlPtr->inset = htmlPtr->highlightWidth + htmlPtr->borderWidth;
+ w = htmlPtr->width + 2*(htmlPtr->padx + htmlPtr->inset);
+ h = htmlPtr->height + 2*(htmlPtr->pady + htmlPtr->inset);
+ Tk_GeometryRequest(htmlPtr->tkwin, w, h);
+ Tk_SetInternalBorder(htmlPtr->tkwin, htmlPtr->inset);
+ TestPoint(0);
+}
+
+/*
+** This routine is called in order to process a "configure" subcommand
+** on the given html widget.
+*/
+int ConfigureHtmlWidget(
+ Tcl_Interp *interp, /* Write error message to this interpreter */
+ HtmlWidget *htmlPtr, /* The Html widget to be configured */
+ int argc, /* Number of configuration arguments */
+ const char **argv, /* Text of configuration arguments */
+ int flags, /* Configuration flags */
+ int realign /* Always do a redraw if set */
+){
+ int rc;
+ int i;
+ int redraw = realign; /* True if a redraw is required. */
+
+ /* Scan thru the configuration options to see if we need to redraw
+ ** the widget.
+ */
+ for(i=0; redraw==0 && i<argc; i+=2){
+ int c;
+ int n;
+ if( argv[i][0]!='-' ){
+ redraw = 1;
+ break;
+ }
+ c = argv[i][1];
+ n = strlen(argv[i]);
+ if( c=='c' && n>4 && strncmp(argv[i],"-cursor",n)==0 ){
+ /* do nothing */
+ }else
+ /* The default case */
+ {
+ redraw = 1;
+ }
+ }
+ rc = Tk_ConfigureWidget(interp, htmlPtr->tkwin, configSpecs, argc, (const char**)argv,
+ (char *) htmlPtr, flags);
+ if( rc!=TCL_OK || redraw==0 ){ TestPoint(0); return rc; }
+ memset(htmlPtr->fontValid, 0, sizeof(htmlPtr->fontValid));
+ htmlPtr->apColor[COLOR_Normal] = htmlPtr->fgColor;
+ htmlPtr->apColor[COLOR_Visited] = htmlPtr->oldLinkColor;
+ htmlPtr->apColor[COLOR_Unvisited] = htmlPtr->newLinkColor;
+ htmlPtr->apColor[COLOR_Selection] = htmlPtr->selectionColor;
+ htmlPtr->apColor[COLOR_Background] = Tk_3DBorderColor(htmlPtr->border);
+ Tk_SetBackgroundFromBorder(htmlPtr->tkwin, htmlPtr->border);
+ if( htmlPtr->highlightWidth < 0 ){ htmlPtr->highlightWidth = 0; TestPoint(0);}
+ if (htmlPtr->padx < 0) { htmlPtr->padx = 0; TestPoint(0);}
+ if (htmlPtr->pady < 0) { htmlPtr->pady = 0; TestPoint(0);}
+ if (htmlPtr->width < 100) { htmlPtr->width = 100; TestPoint(0);}
+ if (htmlPtr->height < 100) { htmlPtr->height = 100; TestPoint(0);}
+ if (htmlPtr->borderWidth < 0) {htmlPtr->borderWidth = 0; TestPoint(0);}
+ htmlPtr->flags |= RESIZE_ELEMENTS | RELAYOUT | REDRAW_BORDER | RESIZE_CLIPWIN;
+ HtmlRecomputeGeometry(htmlPtr);
+ HtmlRedrawEverything(htmlPtr);
+ ClearGcCache(htmlPtr);
+ return rc;
+}
+
+/*
+** Delete a single HtmlElement
+*/
+void HtmlDeleteElement(HtmlElement *p){
+ switch( p->base.type ){
+ case Html_Block:
+ if( p->block.z ){
+ HtmlFree(p->block.z);
+ }
+ break;
+ default:
+ break;
+ }
+ HtmlFree(p);
+}
+
+/*
+** Erase all data from the HTML widget. Bring it back to an
+** empty screen.
+**
+** This happens (for example) when the "clear" method is invoked
+** on the widget, or just before the widget is deleted.
+*/
+void HtmlClear(HtmlWidget *htmlPtr){
+ int i;
+ HtmlElement *p, *pNext;
+
+ HtmlDeleteControls(htmlPtr);
+ for(p=htmlPtr->pFirst; p; p=pNext){
+ pNext = p->pNext;
+ HtmlDeleteElement(p);
+ }
+ htmlPtr->pFirst = 0;
+ htmlPtr->pLast = 0;
+ htmlPtr->nToken = 0;
+ if( htmlPtr->zText ){
+ HtmlFree(htmlPtr->zText);
+ }
+ htmlPtr->zText = 0;
+ htmlPtr->nText = 0;
+ htmlPtr->nAlloc = 0;
+ htmlPtr->nComplete = 0;
+ htmlPtr->iPlaintext = 0;
+ for(i=N_PREDEFINED_COLOR; i<N_COLOR; i++){
+ if( htmlPtr->apColor[i] != 0 ){
+ Tk_FreeColor(htmlPtr->apColor[i]);
+ htmlPtr->apColor[i] = 0;
+ }
+ }
+ for(i=0; i<N_COLOR; i++){
+ htmlPtr->iDark[i] = 0;
+ htmlPtr->iLight[i] = 0;
+ }
+ htmlPtr->colorUsed = 0;
+ while( htmlPtr->imageList ){
+ HtmlImage *p = htmlPtr->imageList;
+ htmlPtr->imageList = p->pNext;
+ Tk_FreeImage(p->image);
+ HtmlFree(p);
+ TestPoint(0);
+ }
+ while( htmlPtr->styleStack ){
+ HtmlStyleStack *p = htmlPtr->styleStack;
+ htmlPtr->styleStack = p->pNext;
+ HtmlFree(p);
+ }
+ ClearGcCache(htmlPtr);
+ ResetLayoutContext(htmlPtr);
+ if( htmlPtr->zBaseHref ){
+ HtmlFree(htmlPtr->zBaseHref);
+ htmlPtr->zBaseHref = 0;
+ }
+ htmlPtr->lastSized = 0;
+ htmlPtr->nextPlaced = 0;
+ htmlPtr->firstBlock = 0;
+ htmlPtr->lastBlock = 0;
+ htmlPtr->nInput = 0;
+ htmlPtr->nForm = 0;
+ htmlPtr->varId = 0;
+ htmlPtr->paraAlignment = ALIGN_None;
+ htmlPtr->rowAlignment = ALIGN_None;
+ htmlPtr->anchorFlags = 0;
+ htmlPtr->inDt = 0;
+ htmlPtr->anchorStart = 0;
+ htmlPtr->formStart = 0;
+ htmlPtr->innerList = 0;
+ htmlPtr->maxX = 0;
+ htmlPtr->maxY = 0;
+ htmlPtr->xOffset = 0;
+ htmlPtr->yOffset = 0;
+ htmlPtr->pInsBlock = 0;
+ htmlPtr->ins.p = 0;
+ htmlPtr->selBegin.p = 0;
+ htmlPtr->selEnd.p = 0;
+ htmlPtr->pSelStartBlock = 0;
+ htmlPtr->pSelEndBlock = 0;
+}
+
+/*
+** This routine attempts to delete the widget structure. But it won't
+** do it if the widget structure is locked. If the widget structure is
+** locked, then when HtmlUnlock() is called and the lock count reaches
+** zero, this routine will be called to finish the job.
+*/
+static void DestroyHtmlWidget(HtmlWidget *htmlPtr){
+ int i;
+
+ if( htmlPtr->locked>0 ) return;
+ Tcl_DeleteCommand(htmlPtr->interp, htmlPtr->zCmdName);
+ Tcl_DeleteCommand(htmlPtr->interp, htmlPtr->zClipwin);
+ HtmlClear(htmlPtr);
+ Tk_FreeOptions(configSpecs, (char*) htmlPtr, htmlPtr->display, 0);
+ for(i=0; i<N_FONT; i++){
+ if( htmlPtr->aFont[i] != 0 ){
+ Tk_FreeFont(htmlPtr->aFont[i]);
+ htmlPtr->aFont[i] = 0;
+ }
+ }
+ for(i=0; i<Html_TypeCount; i++){
+ if( htmlPtr->zHandler[i] ){
+ HtmlFree(htmlPtr->zHandler[i]);
+ htmlPtr->zHandler[i] = 0;
+ }
+ }
+ if( htmlPtr->insTimer ){
+ Tcl_DeleteTimerHandler(htmlPtr->insTimer);
+ htmlPtr->insTimer = 0;
+ }
+ HtmlFree(htmlPtr->zClipwin);
+ HtmlFree(htmlPtr);
+}
+
+/*
+** Remove a lock from the HTML widget. If the widget has been
+** deleted, then delete the widget structure. Return 1 if the
+** widget has been deleted. Return 0 if it still exists.
+**
+** Normal Tk code (that is to say, code in the Tk core) uses
+** Tcl_Preserve() and Tcl_Release() to accomplish what this
+** function does. But preserving and releasing are much more
+** common in this code than in regular widgets, so this routine
+** was invented to do the same thing easier and faster.
+*/
+int HtmlUnlock(HtmlWidget *htmlPtr){
+ htmlPtr->locked--;
+ if( htmlPtr->tkwin==0 && htmlPtr->locked<=0 ){
+ Tcl_Interp *interp = htmlPtr->interp;
+ Tcl_Preserve(interp);
+ DestroyHtmlWidget(htmlPtr);
+ Tcl_Release(interp);
+ return 1;
+ }
+ return htmlPtr->tkwin==0;
+}
+
+/*
+** Lock the HTML widget. This prevents the widget structure from
+** being deleted even if the widget itself is destroyed. There must
+** be a call to HtmlUnlock() to release the structure.
+*/
+void HtmlLock(HtmlWidget *htmlPtr){
+ htmlPtr->locked++;
+}
+
+/*
+** This routine checks to see if an HTML widget has been
+** destroyed. It is always called after calling HtmlLock().
+**
+** If the widget has been destroyed, then the structure
+** is unlocked and the function returns 1. If the widget
+** has not been destroyed, then the structure is not unlocked
+** and the routine returns 0.
+**
+** This routine is intended for use in code like the following:
+**
+** HtmlLock(htmlPtr);
+** // Do something that might destroy the widget
+** if( HtmlIsDead(htmlPtr) ) return;
+** // Do something that might destroy the widget
+** if( HtmlIsDead(htmlPtr) ) return;
+** // Do something that might destroy the widget
+** if( HtmlUnlock(htmlPtr) ) return;
+*/
+int HtmlIsDead(HtmlWidget *htmlPtr){
+ if( htmlPtr->tkwin==0 ){
+ HtmlUnlock(htmlPtr);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+** Flash the insertion cursor.
+*/
+void HtmlFlashCursor(ClientData clientData){
+ HtmlWidget *htmlPtr = (HtmlWidget*)clientData;
+ if( htmlPtr->pInsBlock==0 || htmlPtr->insOnTime<=0
+ || htmlPtr->insOffTime<=0 ){
+ htmlPtr->insTimer = 0;
+ TestPoint(0);
+ return;
+ }
+ HtmlRedrawBlock(htmlPtr, htmlPtr->pInsBlock);
+ if( (htmlPtr->flags & GOT_FOCUS)==0 ){
+ htmlPtr->insStatus = 0;
+ htmlPtr->insTimer = 0;
+ TestPoint(0);
+ }else if( htmlPtr->insStatus ){
+ htmlPtr->insTimer = Tcl_CreateTimerHandler(htmlPtr->insOffTime,
+ HtmlFlashCursor, clientData);
+ htmlPtr->insStatus = 0;
+ TestPoint(0);
+ }else{
+ htmlPtr->insTimer = Tcl_CreateTimerHandler(htmlPtr->insOnTime,
+ HtmlFlashCursor, clientData);
+ htmlPtr->insStatus = 1;
+ TestPoint(0);
+ }
+}
+
+/*
+** Return a GC from the cache. As many as N_CACHE_GCs are kept valid
+** at any one time. They are replaced using an LRU algorithm.
+**
+** A value of FONT_Any (-1) for the font means "don't care".
+*/
+GC HtmlGetGC(HtmlWidget *htmlPtr, int color, int font){
+ int i, j;
+ GcCache *p = htmlPtr->aGcCache;
+ XGCValues gcValues;
+ int mask;
+ Tk_Font tkfont;
+
+ /*
+ ** Check for an existing GC.
+ */
+ if( color < 0 || color >= N_COLOR ){ color = 0; TestPoint(0); }
+ if( font < FONT_Any || font >= N_FONT ){ font = FONT_Default; TestPoint(0); }
+ for(i=0; i<N_CACHE_GC; i++, p++){
+ if( p->index==0 ){ TestPoint(0); continue; }
+ if( (font<0 || p->font==font) && p->color==color ){
+ if( p->index>1 ){
+ for(j=0; j<N_CACHE_GC; j++){
+ if( htmlPtr->aGcCache[j].index
+ && htmlPtr->aGcCache[j].index < p->index ){
+ htmlPtr->aGcCache[j].index++;
+ }
+ }
+ p->index = 1;
+ }
+ return htmlPtr->aGcCache[i].gc;
+ }
+ }
+
+ /*
+ ** No GC matches. Find a place to allocate a new GC.
+ */
+ p = htmlPtr->aGcCache;
+ for(i=0; i<N_CACHE_GC; i++, p++){
+ if( p->index==0 || p->index==N_CACHE_GC ){ TestPoint(0); break; }
+ }
+ if( p->index ){
+ Tk_FreeGC(htmlPtr->display, p->gc);
+ }
+ gcValues.foreground = htmlPtr->apColor[color]->pixel;
+ gcValues.graphics_exposures = True;
+ mask = GCForeground | GCGraphicsExposures;
+ if( font<0 ){ font = FONT_Default; TestPoint(0); }
+ tkfont = HtmlGetFont(htmlPtr, font);
+ if( tkfont ){
+ gcValues.font = Tk_FontId(tkfont);
+ mask |= GCFont;
+ }
+ p->gc = Tk_GetGC(htmlPtr->tkwin, mask, &gcValues);
+ if( p->index==0 ){ p->index = N_CACHE_GC + 1; TestPoint(0); }
+ for(j=0; j<N_CACHE_GC; j++){
+ if( htmlPtr->aGcCache[j].index && htmlPtr->aGcCache[j].index < p->index ){
+ htmlPtr->aGcCache[j].index++;
+ }
+ }
+ p->index = 1;
+ p->font = font;
+ p->color = color;
+ return p->gc;
+}
+
+/*
+** Retrieve any valid GC. The font and color don't matter since the
+** GC will only be used for copying.
+*/
+GC HtmlGetAnyGC(HtmlWidget *htmlPtr){
+ int i;
+ GcCache *p = htmlPtr->aGcCache;
+
+ for(i=0; i<N_CACHE_GC; i++, p++){
+ if( p->index ){ TestPoint(0); return p->gc; }
+ }
+ TestPoint(0);
+ return HtmlGetGC(htmlPtr, COLOR_Normal, FONT_Default);
+}
+
+/*
+** All window events (for both tkwin and clipwin) are
+** sent to this routine.
+*/
+static void HtmlEventProc(ClientData clientData, XEvent *eventPtr){
+ HtmlWidget *htmlPtr = (HtmlWidget*) clientData;
+ int redraw_needed = 0;
+ XConfigureRequestEvent *p;
+
+ switch( eventPtr->type ){
+ case GraphicsExpose:
+ case Expose:
+ if( htmlPtr->tkwin==0 ){
+ /* The widget is being deleted. Do nothing */
+ TestPoint(0);
+ }else if( eventPtr->xexpose.window!=Tk_WindowId(htmlPtr->tkwin) ){
+ /* Exposure in the clipping window */
+ HtmlRedrawArea(htmlPtr, eventPtr->xexpose.x - 1,
+ eventPtr->xexpose.y - 1,
+ eventPtr->xexpose.x + eventPtr->xexpose.width + 1,
+ eventPtr->xexpose.y + eventPtr->xexpose.height + 1);
+ TestPoint(0);
+ }else{
+ /* Exposure in the main window */
+ htmlPtr->flags |= REDRAW_BORDER;
+ HtmlScheduleRedraw(htmlPtr);
+ TestPoint(0);
+ }
+ break;
+ case DestroyNotify:
+ if( (htmlPtr->flags & REDRAW_PENDING) ){
+ Tcl_CancelIdleCall(HtmlRedrawCallback, (ClientData)htmlPtr);
+ htmlPtr->flags &= ~REDRAW_PENDING;
+ }
+ if( htmlPtr->tkwin != 0 ){
+ if( eventPtr->xany.window!=Tk_WindowId(htmlPtr->tkwin) ){
+ Tk_DestroyWindow(htmlPtr->tkwin);
+ htmlPtr->clipwin = 0;
+ break;
+ }
+ htmlPtr->tkwin = 0;
+ Tcl_DeleteCommand(htmlPtr->interp, htmlPtr->zCmdName);
+ Tcl_DeleteCommand(htmlPtr->interp, htmlPtr->zClipwin);
+ }
+ HtmlUnlock(htmlPtr);
+ break;
+ case ConfigureNotify:
+ if( htmlPtr->tkwin!=0
+ && eventPtr->xconfigure.window==Tk_WindowId(htmlPtr->tkwin)
+ ){
+ p = (XConfigureRequestEvent*)eventPtr;
+ if( p->width != htmlPtr->realWidth ){
+ redraw_needed = 1;
+ htmlPtr->realWidth = p->width;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ if( p->height != htmlPtr->realHeight ){
+ redraw_needed = 1;
+ htmlPtr->realHeight = p->height;
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ if( redraw_needed ){
+ htmlPtr->flags |= RELAYOUT | VSCROLL | HSCROLL | RESIZE_CLIPWIN;
+ HtmlRedrawEverything(htmlPtr);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ }
+ break;
+ case FocusIn:
+ if( htmlPtr->tkwin!=0
+ && eventPtr->xfocus.window==Tk_WindowId(htmlPtr->tkwin)
+ && eventPtr->xfocus.detail != NotifyInferior
+ ){
+ htmlPtr->flags |= GOT_FOCUS | REDRAW_FOCUS;
+ HtmlScheduleRedraw(htmlPtr);
+ HtmlUpdateInsert(htmlPtr);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ break;
+ case FocusOut:
+ if( htmlPtr->tkwin!=0
+ && eventPtr->xfocus.window==Tk_WindowId(htmlPtr->tkwin)
+ && eventPtr->xfocus.detail != NotifyInferior
+ ){
+ htmlPtr->flags &= ~GOT_FOCUS;
+ htmlPtr->flags |= REDRAW_FOCUS;
+ HtmlScheduleRedraw(htmlPtr);
+ TestPoint(0);
+ }else{
+ TestPoint(0);
+ }
+ break;
+ }
+}
+
+
+/*
+** The rendering and layout routines should call this routine in order to get
+** a font structure. The iFont parameter specifies which of the N_FONT
+** fonts should be obtained. The font is allocated if necessary.
+**
+** Because the -fontcommand callback can be invoked, this function can
+** (in theory) cause the HTML widget to be changed arbitrarily or even
+** deleted. Callers of this function much be prepared to be called
+** recursively and/or to have the HTML widget deleted out from under
+** them. This routine will return NULL if the HTML widget is deleted.
+*/
+Tk_Font HtmlGetFont(
+ HtmlWidget *htmlPtr, /* The HTML widget to which the font applies */
+ int iFont /* Which font to obtain */
+){
+ Tk_Font toFree = 0;
+
+ if( iFont<0 ){ iFont = 0; TestPoint(0); }
+ if( iFont>=N_FONT ){ iFont = N_FONT - 1; CANT_HAPPEN; }
+
+ /*
+ ** If the font has previously been allocated, but the "fontValid" bitmap
+ ** shows it is no longer valid, then mark it for freeing later. We use
+ ** a policy of allocate-before-free because Tk's font cache operates
+ ** much more efficiently that way.
+ */
+ if( !FontIsValid(htmlPtr, iFont) && htmlPtr->aFont[iFont]!=0 ){
+ toFree = htmlPtr->aFont[iFont];
+ htmlPtr->aFont[iFont] = 0;
+ TestPoint(0);
+ }
+
+ /*
+ ** If we need to allocate a font, first construct the font name then
+ ** allocate it.
+ */
+ if( htmlPtr->aFont[iFont]==0 ){
+ char name[200]; /* Name of the font */
+
+ name[0] = 0;
+
+ /* Run the -fontcommand if it is specified
+ */
+ if( htmlPtr->zFontCommand && htmlPtr->zFontCommand[0] ){
+ int iFam; /* The font family index. Value between 0 and 7 */
+ Tcl_DString str; /* The command we'll execute to get the font name */
+ char *zSep = ""; /* Separator between font attributes */
+ int rc; /* Return code from the font command */
+ char zBuf[100]; /* Temporary buffer */
+
+ Tcl_DStringInit(&str);
+ Tcl_DStringAppend(&str, htmlPtr->zFontCommand, -1);
+ sprintf(zBuf, " %d {", FontSize(iFont)+1);
+ Tcl_DStringAppend(&str,zBuf, -1);
+ iFam = iFont / N_FONT_SIZE ;
+ if( iFam & 1 ){
+ Tcl_DStringAppend(&str,"bold",-1);
+ zSep = " ";
+ }
+ if( iFam & 2 ){
+ Tcl_DStringAppend(&str,zSep,-1);
+ Tcl_DStringAppend(&str,"italic",-1);
+ zSep = " ";
+ }
+ if( iFam & 4 ){
+ Tcl_DStringAppend(&str,zSep,-1);
+ Tcl_DStringAppend(&str,"fixed",-1);
+ }
+ Tcl_DStringAppend(&str,"}",-1);
+ HtmlLock(htmlPtr);
+ rc = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&str));
+ Tcl_DStringFree(&str);
+ if( HtmlUnlock(htmlPtr) ){
+ return NULL;
+ }
+ if( rc!=TCL_OK ){
+ Tcl_AddErrorInfo(htmlPtr->interp,
+ "\n (-fontcommand callback of HTML widget)");
+ Tcl_BackgroundError(htmlPtr->interp);
+ }else{
+ sprintf(name,"%.100s", Tcl_GetStringResult(htmlPtr->interp));
+ }
+ Tcl_ResetResult(htmlPtr->interp);
+ }
+
+ /*
+ ** If the -fontcommand failed or returned an empty string, or if
+ ** there is no -fontcommand, then get the default font name.
+ */
+ if( name[0]==0 ){
+ char *familyStr = "";
+ int iFamily;
+ int iSize;
+ int size;
+
+ iFamily = iFont / N_FONT_SIZE;
+ iSize = iFont % N_FONT_SIZE + 1;
+ switch( iFamily ){
+ case 0: familyStr = "helvetica -%d"; break;
+ case 1: familyStr = "helvetica -%d bold"; break;
+ case 2: familyStr = "helvetica -%d italic"; break;
+ case 3: familyStr = "helvetica -%d bold italic"; break;
+ case 4: familyStr = "courier -%d"; break;
+ case 5: familyStr = "courier -%d bold"; break;
+ case 6: familyStr = "courier -%d italic"; break;
+ case 7: familyStr = "courier -%d bold italic"; break;
+ default: familyStr = "helvetica -14"; CANT_HAPPEN;
+ }
+ switch( iSize ){
+ case 1: size = 8; break;
+ case 2: size = 10; break;
+ case 3: size = 12; break;
+ case 4: size = 14; break;
+ case 5: size = 16; break;
+ case 6: size = 18; break;
+ case 7: size = 24; break;
+ default: size = 14; CANT_HAPPEN;
+ }
+ sprintf(name, familyStr, size);
+ }
+
+ /* Get the named font
+ */
+ htmlPtr->aFont[iFont] = Tk_GetFont(htmlPtr->interp, htmlPtr->tkwin, name);
+ if( htmlPtr->aFont[iFont]==0 ){
+ Tcl_AddErrorInfo(htmlPtr->interp,
+ "\n (trying to create a font named \"");
+ Tcl_AddErrorInfo(htmlPtr->interp, name);
+ Tcl_AddErrorInfo(htmlPtr->interp, "\" in the HTML widget)");
+ Tcl_BackgroundError(htmlPtr->interp);
+ htmlPtr->aFont[iFont] =
+ Tk_GetFont(htmlPtr->interp, htmlPtr->tkwin, "fixed");
+ }
+ if( htmlPtr->aFont[iFont]==0 ){
+ Tcl_AddErrorInfo(htmlPtr->interp,
+ "\n (trying to create font \"fixed\" in the HTML widget)");
+ Tcl_BackgroundError(htmlPtr->interp);
+ htmlPtr->aFont[iFont] =
+ Tk_GetFont(htmlPtr->interp, htmlPtr->tkwin, "helvetica -12");
+ }
+ FontSetValid(htmlPtr, iFont);
+ TestPoint(0);
+ }
+
+ /*
+ ** Free the expired font, if any.
+ */
+ if( toFree!=0 ){
+ Tk_FreeFont(toFree);
+ }
+ return htmlPtr->aFont[iFont];
+}
+
+/*
+** Compute the squared distance between two colors
+*/
+static float colorDistance(XColor *pA, XColor *pB){
+ float x, y, z;
+
+ x = 0.30 * (pA->red - pB->red);
+ y = 0.61 * (pA->green - pB->green);
+ z = 0.11 * (pA->blue - pB->blue);
+ TestPoint(0);
+ return x*x + y*y + z*z;
+}
+
+/*
+** This routine returns an index between 0 and N_COLOR-1 which indicates
+** which XColor structure in the apColor[] array of htmlPtr should be
+** used to describe the color specified by the given name.
+*/
+int HtmlGetColorByName(HtmlWidget *htmlPtr, char *zColor){
+ XColor *pNew;
+ int iColor;
+ Tk_Uid name;
+ int i, n;
+ char zAltColor[16];
+
+ /* Netscape accepts color names that are just HEX values, without
+ ** the # up front. This isn't valid HTML, but we support it for
+ ** compatibility.
+ */
+ n = strlen(zColor);
+
+ /* trucate any spaces on the end */
+ while (n>0 && zColor[n-1]==' ') {
+ zColor[n-1] = '\0';
+ n--;
+ }
+
+ if( n==6 || n==3 || n==9 || n==12 ){
+ for(i=0; i<n; i++){
+ if( !isxdigit(zColor[i]) ) break;
+ }
+ if( i==n ){
+ sprintf(zAltColor,"#%s",zColor);
+ }else{
+ strcpy(zAltColor, zColor);
+ }
+ name = Tk_GetUid(zAltColor);
+ }else{
+ name = Tk_GetUid(zColor);
+ }
+ pNew = Tk_GetColor(htmlPtr->interp, htmlPtr->clipwin, name);
+ if( pNew==0 ){
+ return 0; /* Color 0 is always the default */
+ }
+
+ iColor = GetColorByValue(htmlPtr, pNew);
+ Tk_FreeColor(pNew);
+ return iColor;
+}
+
+/*
+** Macros used in the computation of appropriate shadow colors.
+*/
+#define MAX_COLOR 65535
+#define MAX(A,B) ((A)<(B)?(B):(A))
+#define MIN(A,B) ((A)<(B)?(A):(B))
+
+/*
+** Check to see if the given color is too dark to be easily distinguished
+** from black.
+*/
+static int isDarkColor(XColor *p){
+ float x, y, z;
+
+ x = 0.50 * p->red;
+ y = 1.00 * p->green;
+ z = 0.28 * p->blue;
+ return (x*x + y*y + z*z)<0.05*MAX_COLOR*MAX_COLOR;
+}
+
+/*
+** Given that the background color is iBgColor, figure out an
+** appropriate color for the dark part of a 3D shadow.
+*/
+int HtmlGetDarkShadowColor(HtmlWidget *htmlPtr, int iBgColor){
+ if( htmlPtr->iDark[iBgColor]==0 ){
+ XColor *pRef, val;
+ pRef = htmlPtr->apColor[iBgColor];
+ if( isDarkColor(pRef) ){
+ int t1, t2;
+ t1 = MIN(MAX_COLOR,pRef->red*1.2);
+ t2 = (pRef->red*3 + MAX_COLOR)/4;
+ val.red = MAX(t1,t2);
+ t1 = MIN(MAX_COLOR,pRef->green*1.2);
+ t2 = (pRef->green*3 + MAX_COLOR)/4;
+ val.green = MAX(t1,t2);
+ t1 = MIN(MAX_COLOR,pRef->blue*1.2);
+ t2 = (pRef->blue*3 + MAX_COLOR)/4;
+ val.blue = MAX(t1,t2);
+ }else{
+ val.red = pRef->red*0.6;
+ val.green = pRef->green*0.6;
+ val.blue = pRef->blue*0.6;
+ }
+ htmlPtr->iDark[iBgColor] = GetColorByValue(htmlPtr, &val) + 1;
+ }
+ return htmlPtr->iDark[iBgColor] - 1;
+}
+
+/*
+** Check to see if the given color is too light to be easily distinguished
+** from white.
+*/
+static int isLightColor(XColor *p){
+ return p->green>=0.85*MAX_COLOR;
+}
+
+/*
+** Given that the background color is iBgColor, figure out an
+** appropriate color for the bright part of the 3D shadow.
+*/
+int HtmlGetLightShadowColor(HtmlWidget *htmlPtr, int iBgColor){
+ if( htmlPtr->iLight[iBgColor]==0 ){
+ XColor *pRef, val;
+ pRef = htmlPtr->apColor[iBgColor];
+ if( isLightColor(pRef) ){
+ val.red = pRef->red*0.9;
+ val.green = pRef->green*0.9;
+ val.blue = pRef->blue*0.9;
+ }else{
+ int t1, t2;
+ t1 = MIN(MAX_COLOR,pRef->green*1.4);
+ t2 = (pRef->green + MAX_COLOR)/2;
+ val.green = MAX(t1,t2);
+ t1 = MIN(MAX_COLOR,pRef->red*1.4);
+ t2 = (pRef->red + MAX_COLOR)/2;
+ val.red = MAX(t1,t2);
+ t1 = MIN(MAX_COLOR,pRef->blue*1.4);
+ t2 = (pRef->blue + MAX_COLOR)/2;
+ val.blue = MAX(t1,t2);
+ }
+ htmlPtr->iLight[iBgColor] = GetColorByValue(htmlPtr, &val) + 1;
+ }
+ return htmlPtr->iLight[iBgColor] - 1;
+}
+
+/*
+** Find a color integer for the color whose color components
+** are given by pRef.
+*/
+LOCAL int GetColorByValue(HtmlWidget *htmlPtr, XColor *pRef){
+ int i;
+ float dist;
+ float closestDist;
+ int closest;
+ /*
+ int r, g, b;
+# define COLOR_MASK 0xf800
+ */
+
+ XColor* q;
+ q = Tk_GetColorByValue(htmlPtr->clipwin, pRef);
+
+ /* Search for an exact match */
+ /*
+ r = pRef->red &= COLOR_MASK;
+ g = pRef->green &= COLOR_MASK;
+ b = pRef->blue &= COLOR_MASK;
+ */
+ for(i=0; i<N_COLOR; i++){
+ XColor *p = htmlPtr->apColor[i];
+ /*
+ if( p && (p->red & COLOR_MASK)==r && (p->green & COLOR_MASK)==g
+ && (p->blue & COLOR_MASK)==b ){
+ */
+ if (p && (q->red == p->red)
+ && (q->green == p->green)
+ && (q->blue == p->blue)) {
+ htmlPtr->colorUsed |= (1<<i);
+ Tk_FreeColor(q);
+ return i;
+ }
+ }
+ Tk_FreeColor(q);
+
+ /* No exact matches. Look for a completely unused slot */
+ for(i=N_PREDEFINED_COLOR; i<N_COLOR; i++){
+ if( htmlPtr->apColor[i]==0 ){
+ htmlPtr->apColor[i] = Tk_GetColorByValue(htmlPtr->clipwin, pRef);
+ htmlPtr->colorUsed |= (1<<i);
+ return i;
+ }
+ }
+
+ /* No empty slots. Look for a slot that contains a color that
+ ** isn't currently in use. */
+ for(i=N_PREDEFINED_COLOR; i<N_COLOR; i++){
+ if( ((htmlPtr->colorUsed >> i) & 1) == 0 ){
+ Tk_FreeColor(htmlPtr->apColor[i]);
+ htmlPtr->apColor[i] = Tk_GetColorByValue(htmlPtr->clipwin, pRef);
+ htmlPtr->colorUsed |= (1<<i);
+ return i;
+ }
+ }
+
+ /* Ok, find the existing color that is closest to the color requested
+ ** and use it. */
+ closest = 0;
+ closestDist = colorDistance(pRef, htmlPtr->apColor[0]);
+ for(i=1; i<N_COLOR; i++){
+ dist = colorDistance(pRef, htmlPtr->apColor[i]);
+ if( dist < closestDist ){
+ closestDist = dist;
+ closest = i;
+ }
+ }
+ return i;
+}
+
+/*
+** This routine searchs for a hyperlink beneath the coordinates x,y
+** and returns a pointer to the HREF for that hyperlink. The text
+** is held one of the markup.argv[] fields of the <a> markup.
+*/
+char *HtmlGetHref(HtmlWidget *htmlPtr, int x, int y){
+ HtmlBlock *pBlock;
+ HtmlElement *pElem;
+
+ for(pBlock=htmlPtr->firstBlock; pBlock; pBlock=pBlock->pNext){
+ if( pBlock->top > y || pBlock->bottom < y
+ || pBlock->left > x || pBlock->right < x
+ ){
+ TestPoint(0);
+ continue;
+ }
+ pElem = pBlock->base.pNext;
+ if( (pElem->base.style.flags & STY_Anchor)==0 ){ TestPoint(0); continue; }
+ switch( pElem->base.type ){
+ case Html_Text:
+ case Html_Space:
+ case Html_IMG:
+ while( pElem && pElem->base.type!=Html_A ){
+ pElem = pElem->base.pPrev;
+ }
+ if( pElem==0 || pElem->base.type!=Html_A ){ break; }
+ return HtmlMarkupArg(pElem,"href", 0);
+ default:
+ break;
+ }
+ }
+ TestPoint(0);
+ return 0;
+}
+
+/*
+** Change the "yOffset" field from its current value to the value given.
+** This has the effect of scrolling the widget vertically.
+*/
+void HtmlVerticalScroll(HtmlWidget *htmlPtr, int yOffset){
+ int inset; /* The 3D border plus the pady */
+ int h; /* Height of the clipping window */
+ int diff; /* Difference between old and new offset */
+ GC gc; /* Graphics context used for copying */
+ int w; /* Width of text area */
+
+ if( yOffset==htmlPtr->yOffset ){ TestPoint(0); return; }
+ inset = htmlPtr->pady + htmlPtr->inset;
+ h = htmlPtr->realHeight - 2*inset;
+ if( (htmlPtr->flags & REDRAW_TEXT)!=0
+ || (htmlPtr->dirtyTop < h && htmlPtr->dirtyBottom > 0)
+ || htmlPtr->yOffset > yOffset + (h - 30)
+ || htmlPtr->yOffset < yOffset - (h - 30)
+ ){
+ htmlPtr->yOffset = yOffset;
+ htmlPtr->flags |= VSCROLL | REDRAW_TEXT;
+ HtmlScheduleRedraw(htmlPtr);
+ TestPoint(0);
+ return;
+ }
+ diff = htmlPtr->yOffset - yOffset;
+ gc = HtmlGetAnyGC(htmlPtr);
+ w = htmlPtr->realWidth - 2*(htmlPtr->inset + htmlPtr->padx);
+ htmlPtr->flags |= VSCROLL;
+ htmlPtr->yOffset = yOffset;
+#ifndef MAC_OSX_TK
+ if( diff < 0 ){
+ XCopyArea(htmlPtr->display,
+ Tk_WindowId(htmlPtr->clipwin), /* source */
+ Tk_WindowId(htmlPtr->clipwin), /* destination */
+ gc,
+ 0, -diff, /* source X, Y */
+ w, h + diff, /* Width and height */
+ 0, 0); /* Destination X, Y */
+ HtmlRedrawArea(htmlPtr, 0, h + diff, w, h);
+ TestPoint(0);
+ }else{
+ XCopyArea(htmlPtr->display,
+ Tk_WindowId(htmlPtr->clipwin), /* source */
+ Tk_WindowId(htmlPtr->clipwin), /* destination */
+ gc,
+ 0, 0, /* source X, Y */
+ w, h - diff, /* Width and height */
+ 0, diff); /* Destination X, Y */
+ HtmlRedrawArea(htmlPtr, 0, 0, w, diff);
+ TestPoint(0);
+ }
+#else
+ HtmlRedrawArea(htmlPtr, 0, 0, w, h);
+#endif
+ /* HtmlMapControls(htmlPtr);*/
+}
+
+/*
+** Change the "xOffset" field from its current value to the value given.
+** This has the effect of scrolling the widget horizontally.
+*/
+void HtmlHorizontalScroll(HtmlWidget *htmlPtr, int xOffset){
+ if( xOffset==htmlPtr->xOffset ){ TestPoint(0); return; }
+ htmlPtr->xOffset = xOffset;
+ HtmlMapControls(htmlPtr);
+ htmlPtr->flags |= HSCROLL | REDRAW_TEXT;
+ HtmlScheduleRedraw(htmlPtr);
+ TestPoint(0);
+}
+
+/*
+** The following array defines all possible widget command. The main
+** widget command function just parses up the command line, then vectors
+** control to one of the command service routines defined in the
+** following array:
+*/
+static struct HtmlSubcommand {
+ char *zCmd1; /* First-level subcommand. Required */
+ char *zCmd2; /* Second-level subcommand. May be NULL */
+ int minArgc; /* Minimum number of arguments */
+ int maxArgc; /* Maximum number of arguments */
+ char *zHelp; /* Help string if wrong number of arguments */
+ int (*xFunc)(HtmlWidget*,Tcl_Interp*,int,const char**); /* Cmd service routine */
+} aSubcommand[] = {
+ { "cget", 0, 3, 3, "CONFIG-OPTION", HtmlCgetCmd },
+ { "clear", 0, 2, 2, 0, HtmlClearCmd },
+ { "configure", 0, 2, 0, "?ARGS...?", HtmlConfigCmd },
+ { "href", 0, 4, 4, "X Y", HtmlHrefCmd },
+ { "index", 0, 3, 3, "INDEX", HtmlIndexCmd },
+ { "insert", 0, 3, 3, "INDEX", HtmlInsertCmd },
+ { "names", 0, 2, 2, 0, HtmlNamesCmd },
+ { "parse", 0, 3, 3, "HTML-TEXT", HtmlParseCmd },
+ { "resolve", 0, 2, 0, "?URI ...?", HtmlResolveCmd },
+ { "selection", "clear", 3, 3, 0, HtmlSelectionClearCmd},
+ { 0, "set", 5, 5, "START END", HtmlSelectionSetCmd },
+ { "text", "ascii", 5, 5, "START END", HtmlTextAsciiCmd},
+ { 0, "delete", 5, 5, "START END", 0 },
+ { 0, "html", 5, 5, "START END", 0 },
+ { 0, "insert", 5, 5, "INDEX TEXT", 0 },
+ { "token", "append", 5, 5, "TAG ARGUMENTS", 0 },
+ { 0, "delete", 4, 5, "INDEX ?INDEX?", 0 },
+ { 0, "find", 4, 6, "TAG ?before|after INDEX?", 0 },
+ { 0, "get", 4, 5, "INDEX ?INDEX?", 0 },
+ { 0, "handler", 4, 5, "TAG ?SCRIPT?", HtmlTokenHandlerCmd },
+ { 0, "insert", 6, 6, "INDEX TAG ARGUMENTS", 0 },
+ { 0, "list", 5, 5, "START END", HtmlTokenListCmd },
+ { "xview", 0, 2, 5, "OPTIONS...", HtmlXviewCmd },
+ { "yview", 0, 2, 5, "OPTIONS...", HtmlYviewCmd },
+#ifdef DEBUG
+ { "debug", "dump", 5, 5, "START END", HtmlDebugDumpCmd },
+ { 0, "testpt", 4, 4, "FILENAME", HtmlDebugTestPtCmd },
+#endif
+};
+#define nSubcommand (sizeof(aSubcommand)/sizeof(aSubcommand[0]))
+
+/*
+** This routine implements the command used by individual HTML widgets.
+*/
+static int HtmlWidgetCommand(
+ ClientData clientData, /* The HTML widget data structure */
+ Tcl_Interp *interp, /* Current interpreter. */
+ int argc, /* Number of arguments. */
+ const char **argv /* Argument strings. */
+){
+ HtmlWidget *htmlPtr = (HtmlWidget*) clientData;
+ size_t length;
+ int c;
+ int i;
+ struct HtmlSubcommand *pCmd;
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " option ?arg arg ...?\"", 0);
+ TestPoint(0);
+ return TCL_ERROR;
+ }
+ c = argv[1][0];
+ length = strlen(argv[1]);
+ for(i=0, pCmd=aSubcommand; i<nSubcommand; i++, pCmd++){
+ if( pCmd->zCmd1==0 || c!=pCmd->zCmd1[0]
+ || strncmp(pCmd->zCmd1,argv[1],length)!=0 ){
+ TestPoint(0);
+ continue;
+ }
+ if( pCmd->zCmd2 ){
+ int length2;
+ int j;
+ if( argc<3 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " ", pCmd->zCmd1, " SUBCOMMAND ?OPTIONS...?", 0);
+ TestPoint(0);
+ return TCL_ERROR;
+ }
+ length2 = strlen(argv[2]);
+ for(j=i; j<nSubcommand && (j==i || pCmd->zCmd1==0); j++, pCmd++){
+ if( strncmp(pCmd->zCmd2,argv[2],length2)==0 ){
+ TestPoint(0);
+ break;
+ }
+ }
+ if( j>=nSubcommand || (j!=i && aSubcommand[j].zCmd1!=0) ){
+ Tcl_AppendResult(interp,"unknown subcommand \"", argv[2],
+ "\" -- should be one of:", 0);
+ for(j=i; j<nSubcommand && (j==i || aSubcommand[j].zCmd1==0); j++){
+ Tcl_AppendResult(interp, " ", aSubcommand[j].zCmd2, 0);
+ TestPoint(0);
+ }
+ return TCL_ERROR;
+ }
+ }
+ if( argc<pCmd->minArgc || (argc>pCmd->maxArgc && pCmd->maxArgc>0) ){
+ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+ " ", pCmd->zCmd1, 0);
+ if( pCmd->zCmd2 ){
+ Tcl_AppendResult(interp, " ", pCmd->zCmd2, 0);
+ TestPoint(0);
+ }
+ if( pCmd->zHelp ){
+ Tcl_AppendResult(interp, " ", pCmd->zHelp, 0);
+ TestPoint(0);
+ }
+ Tcl_AppendResult(interp, "\"", 0);
+ TestPoint(0);
+ return TCL_ERROR;
+ }
+ if( pCmd->xFunc==0 ){
+ Tcl_AppendResult(interp,"command not yet implemented", 0);
+ TestPoint(0);
+ return TCL_ERROR;
+ }
+ TestPoint(0);
+ return (*pCmd->xFunc)(htmlPtr, interp, argc, argv);
+ }
+ Tcl_AppendResult(interp,"unknown command \"", argv[1], "\" -- should be "
+ "one of:", 0);
+ for(i=0; i<nSubcommand; i++){
+ if( aSubcommand[i].zCmd1==0 || aSubcommand[i].zCmd1[0]=='_' ){
+ TestPoint(0);
+ continue;
+ }
+ Tcl_AppendResult(interp, " ", aSubcommand[i].zCmd1, 0);
+ TestPoint(0);
+ }
+ TestPoint(0);
+ return TCL_ERROR;
+}
+
+/*
+** The following routine implements the Tcl "html" command. This command
+** is used to create new HTML widgets only. After the widget has been
+** created, it is manipulated using the widget command defined above.
+*/
+static int HtmlCommand(
+ ClientData clientData, /* Main window */
+ Tcl_Interp *interp, /* Current interpreter. */
+ int argc, /* Number of arguments. */
+ const char **argv /* Argument strings. */
+){
+ int n, c;
+ char *z;
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " pathName ?options?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ z = (char*)argv[1];
+ n = strlen(z);
+ c = z[0];
+
+ /* If the first argument begins with ".", then it must be the
+ ** name of a new window the user wants to create.
+ */
+ if( argv[1][0]=='.' ){
+ HtmlWidget *htmlPtr;
+ Tk_Window new;
+ Tk_Window clipwin;
+ char *zClipwin;
+ Tk_Window tkwin = (Tk_Window)clientData;
+ static int varId = 1; /* Used to construct unique names */
+
+ new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
+ if (new == NULL) {
+ return TCL_ERROR;
+ }
+ zClipwin = HtmlAlloc( strlen(argv[1]) + 3 );
+ if( zClipwin==0 ){
+ Tk_DestroyWindow(new);
+ return TCL_ERROR;
+ }
+ sprintf(zClipwin,"%s.x",argv[1]);
+ clipwin = Tk_CreateWindowFromPath(interp, new, zClipwin, 0);
+ if( clipwin==0 ){
+ Tk_DestroyWindow(new);
+ HtmlFree(zClipwin);
+ return TCL_ERROR;
+ }
+
+ htmlPtr = HtmlAlloc(sizeof(HtmlWidget) + strlen(argv[1]) + 1);
+ memset(htmlPtr, 0, sizeof(HtmlWidget));
+ htmlPtr->tkwin = new;
+ htmlPtr->clipwin = clipwin;
+ htmlPtr->zClipwin = zClipwin;
+ htmlPtr->display = Tk_Display(new);
+ htmlPtr->interp = interp;
+ htmlPtr->zCmdName = (char*)&htmlPtr[1];
+ strcpy(htmlPtr->zCmdName, argv[1]);
+ htmlPtr->relief = TK_RELIEF_FLAT;
+ htmlPtr->dirtyLeft = LARGE_NUMBER;
+ htmlPtr->dirtyTop = LARGE_NUMBER;
+ htmlPtr->flags = RESIZE_CLIPWIN;
+ htmlPtr->varId = varId++;
+ Tcl_CreateCommand(interp, htmlPtr->zCmdName,
+ HtmlWidgetCommand, (ClientData)htmlPtr, HtmlCmdDeletedProc);
+ Tcl_CreateCommand(interp, htmlPtr->zClipwin,
+ HtmlWidgetCommand, (ClientData)htmlPtr, HtmlCmdDeletedProc);
+
+ Tk_SetClass(new,"Html");
+ Tk_SetClass(clipwin,"HtmlClip");
+ Tk_CreateEventHandler(htmlPtr->tkwin,
+ ExposureMask|StructureNotifyMask|FocusChangeMask,
+ HtmlEventProc, (ClientData) htmlPtr);
+ Tk_CreateEventHandler(htmlPtr->clipwin,
+ ExposureMask|StructureNotifyMask,
+ HtmlEventProc, (ClientData) htmlPtr);
+ if (ConfigureHtmlWidget(interp, htmlPtr, argc-2, argv+2, 0, 1) != TCL_OK) {
+ goto error;
+ }
+ Tcl_SetResult(interp,Tk_PathName(htmlPtr->tkwin),NULL);
+ return TCL_OK;
+
+ error:
+ Tk_DestroyWindow(htmlPtr->tkwin);
+ return TCL_ERROR;
+ }
+
+ /* html reformat $from $to $text
+ **
+ ** Convert the format of text.
+ */
+ if( c=='r' && strncmp(z,"reformat",n)==0 ){
+ if( argc!=5 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " reformat FROM TO TEXT", (char *) NULL);
+ return TCL_ERROR;
+ }
+ Tcl_AppendResult(interp, "not yet implemented", 0);
+ return TCL_ERROR;
+ }else
+
+
+ /* html urljoin $scheme $authority $path $query $fragment
+ **
+ ** Merge together the parts of a URL into a single value URL.
+ */
+ if( c=='u' && strncmp(z,"urljoin",n)==0 ){
+ if( argc!=7 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " url join SCHEME AUTHORITY PATH QUERY FRAGMENT\"", 0);
+ return TCL_ERROR;
+ }
+ Tcl_AppendResult(interp, "not yet implemented", 0);
+ return TCL_ERROR;
+ }else
+
+
+ /* html urlsplit $url
+ **
+ ** Split a URL into a list of its parts.
+ */
+ if( c=='u' && strncmp(z,"urlsplit",n)==0 ){
+ if( argc!=3 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " url split URL\"", 0);
+ return TCL_ERROR;
+ }
+ Tcl_AppendResult(interp, "not yet implemented", 0);
+ return TCL_ERROR;
+ }else
+
+ /* No match. Report an error.
+ */
+ {
+ Tcl_AppendResult(interp, "unknown command \"", z, "\": should be "
+ "a window name or one of: "
+ "reformat urljoin urlsplit", 0);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+** The following mess is used to define DLL_EXPORT. DLL_EXPORT is
+** blank except when we are building a Windows95/NT DLL from this
+** library. Some special trickery is necessary to make this wall
+** work together with makeheaders.
+*/
+#if INTERFACE
+#define DLL_EXPORT
+#endif
+#if defined(USE_TCL_STUBS) && defined(__WIN32__)
+# undef DLL_EXPORT
+# define DLL_EXPORT __declspec(dllexport)
+#endif
+
+/*
+** This routine is used to register the "html" command with the
+** Tcl interpreter. This is the only routine in this file with
+** external linkage.
+*/
+DLL_EXPORT int Tkhtml1_Init(Tcl_Interp *interp) {
+
+ if (Tcl_InitStubs(interp, TCL_PATCH_LEVEL, 0) == NULL)
+ return TCL_ERROR;
+
+ if (Tk_InitStubs(interp, TK_PATCH_LEVEL, 0) == NULL)
+ return TCL_ERROR;
+
+ Tcl_CreateCommand(interp,"html", HtmlCommand, Tk_MainWindow(interp), 0);
+
+#ifdef DEBUG
+ Tcl_LinkVar(interp, "HtmlTraceMask", (char*)&HtmlTraceMask, TCL_LINK_INT);
+#endif
+
+ if (Tcl_PkgProvide(interp, PACKAGE_NAME, PACKAGE_VERSION) != TCL_OK)
+ return TCL_ERROR;
+
+ return TCL_OK;
+}
diff --git a/tkhtml1/src/htmlwidget.h b/tkhtml1/src/htmlwidget.h
new file mode 100644
index 0000000..1c634b4
--- /dev/null
+++ b/tkhtml1/src/htmlwidget.h
@@ -0,0 +1,562 @@
+/* This file was automatically generated. Do not edit! */
+#define DLL_EXPORT
+DLL_EXPORT int Tkhtml1_Init(Tcl_Interp *interp);
+#define INTERFACE 0
+/*#define HtmlAlloc(A) ((void*)Tcl_Alloc(A))*/
+void* HtmlAlloc(size_t);
+typedef struct HtmlWidget HtmlWidget;
+#define DEBUG 1
+#if defined(DEBUG)
+int HtmlDebugTestPtCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlDebugDumpCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+#endif
+int HtmlYviewCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlXviewCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlTokenListCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlTokenHandlerCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlTextAsciiCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlSelectionSetCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlSelectionClearCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlResolveCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlParseCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlNamesCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlInsertCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlIndexCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlHrefCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlConfigCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlClearCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+int HtmlCgetCmd(HtmlWidget *htmlPtr,Tcl_Interp *interp,int argc,const char **argv);
+void HtmlHorizontalScroll(HtmlWidget *htmlPtr,int xOffset);
+void HtmlVerticalScroll(HtmlWidget *htmlPtr,int yOffset);
+typedef union HtmlElement HtmlElement;
+char *HtmlMarkupArg(HtmlElement *p,const char *tag,char *zDefault);
+#define Html_A 5
+#define Html_IMG 76
+#define Html_Space 2
+#define Html_Text 1
+#define STY_Anchor 0x010
+char *HtmlGetHref(HtmlWidget *htmlPtr,int x,int y);
+#define LOCAL static
+int HtmlGetLightShadowColor(HtmlWidget *htmlPtr,int iBgColor);
+int HtmlGetDarkShadowColor(HtmlWidget *htmlPtr,int iBgColor);
+#define MAX(A,B) ((A)<(B)?(B):(A))
+LOCAL int GetColorByValue(HtmlWidget *htmlPtr,XColor *pRef);
+int HtmlGetColorByName(HtmlWidget *htmlPtr,char *zColor);
+#define FontSetValid(H,I) ((H)->fontValid[(I)>>3] |= (1<<((I)&3)))
+#define N_FONT_SIZE 7
+#define FontSize(X) ((X)%N_FONT_SIZE)
+#define FontIsValid(H,I) (((H)->fontValid[(I)>>3] & (1<<((I)&3)))!=0)
+void HtmlTPCantHappen(const char *zFile,int line);
+#if defined(COVERAGE_TEST)
+# define CANT_HAPPEN HtmlTPCantHappen(__FILE__,__LINE__)
+#endif
+#if !(defined(COVERAGE_TEST))
+# define CANT_HAPPEN
+#endif
+GC HtmlGetAnyGC(HtmlWidget *htmlPtr);
+Tk_Font HtmlGetFont(HtmlWidget *htmlPtr,int iFont);
+#define FONT_Default 3
+typedef struct GcCache GcCache;
+typedef unsigned char Html_u8;
+struct GcCache {
+ GC gc; /* The graphics context */
+ Html_u8 font; /* Font used for this context */
+ Html_u8 color; /* Color used for this context */
+ Html_u8 index; /* Index used for LRU replacement */
+};
+void HtmlFlashCursor(ClientData clientData);
+int HtmlIsDead(HtmlWidget *htmlPtr);
+#define Html_TypeCount 151
+#define N_FONT_FAMILY 8
+#define N_FONT (N_FONT_FAMILY*N_FONT_SIZE)
+#define ALIGN_None 0
+typedef struct HtmlStyleStack HtmlStyleStack;
+typedef struct HtmlStyle HtmlStyle;
+struct HtmlStyle {
+ unsigned int font : 6; /* Font to use for display */
+ unsigned int color : 4; /* Foreground color */
+ signed int subscript : 4; /* Positive for <sup>, negative for <sub> */
+ unsigned int align : 2; /* Horizontal alignment */
+ unsigned int bgcolor : 4; /* Background color */
+ unsigned int flags : 12; /* the STY_ flags below */
+};
+struct HtmlStyleStack {
+ HtmlStyleStack *pNext; /* Next style on the stack */
+ int type; /* A markup that ends this style. Ex: Html_EndEM */
+ HtmlStyle style; /* The currently active style. */
+};
+#define N_COLOR 16 /* Total number of colors */
+#define N_PREDEFINED_COLOR 5 /* Number of predefined colors */
+void HtmlDeleteControls(HtmlWidget *htmlPtr);
+void HtmlClear(HtmlWidget *htmlPtr);
+#define HtmlFree(A) Tcl_Free((char*)(A))
+#define Html_Block 4
+void HtmlDeleteElement(HtmlElement *p);
+#define COLOR_Selection 3 /* Background color for the selection */
+#define COLOR_Unvisited 1 /* Index for unvisited hyperlinks */
+#define COLOR_Visited 2 /* Color for visited hyperlinks */
+#define COLOR_Normal 0 /* Index for normal color (black) */
+int ConfigureHtmlWidget(Tcl_Interp *interp,HtmlWidget *htmlPtr,int argc,const char **argv,int flags,int realign);
+void HtmlRedrawText(HtmlWidget *htmlPtr,int y);
+void HtmlRedrawEverything(HtmlWidget *htmlPtr);
+typedef struct HtmlBlock HtmlBlock;
+void HtmlRedrawBlock(HtmlWidget *htmlPtr,HtmlBlock *p);
+void HtmlRedrawArea(HtmlWidget *htmlPtr,int left,int top,int right,int bottom);
+void HtmlScheduleRedraw(HtmlWidget *htmlPtr);
+#define LARGE_NUMBER 100000000
+void HtmlDrawImage(HtmlElement *pElem,Drawable drawable,int drawableLeft,int drawableTop,int drawableRight,int drawableBottom);
+typedef struct HtmlBaseElement HtmlBaseElement;
+typedef short Html_16;
+struct HtmlBaseElement {
+ HtmlElement *pNext; /* Next input token in a list of them all */
+ HtmlElement *pPrev; /* Previous token in a list of them all */
+ HtmlStyle style; /* The rendering style for this token */
+ Html_u8 type; /* The token type. */
+ Html_u8 flags; /* The HTML_ flags below */
+ Html_16 count; /* Various uses, depending on "type" */
+};
+typedef struct HtmlTextElement HtmlTextElement;
+typedef int Html_32;
+struct HtmlTextElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_32 y; /* y coordinate where text should be rendered */
+ Html_16 x; /* x coordinate where text should be rendered */
+ Html_16 w; /* width of this token in pixels */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_u8 spaceWidth; /* Width of one space in the current font */
+ char zText[1]; /* Text for this element. Null terminated */
+};
+typedef struct HtmlSpaceElement HtmlSpaceElement;
+struct HtmlSpaceElement {
+ HtmlBaseElement base; /* All the base information */
+ Html_16 w; /* Width of a single space in current font */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+};
+typedef struct HtmlMarkupElement HtmlMarkupElement;
+struct HtmlMarkupElement {
+ HtmlBaseElement base;
+ char **argv;
+};
+typedef struct HtmlCell HtmlCell;
+struct HtmlCell {
+ HtmlMarkupElement markup;
+ Html_16 rowspan; /* Number of rows spanned by this cell */
+ Html_16 colspan; /* Number of columns spanned by this cell */
+ Html_16 x; /* X coordinate of left edge of border */
+ Html_16 w; /* Width of the border */
+ Html_32 y; /* Y coordinate of top of border indentation */
+ Html_32 h; /* Height of the border */
+ HtmlElement *pTable; /* Pointer back to the <table> */
+ HtmlElement *pEnd; /* Element that ends this cell */
+};
+typedef struct HtmlTable HtmlTable;
+typedef unsigned short Html_u16;
+#define HTML_MAX_COLUMNS 40
+struct HtmlTable {
+ HtmlMarkupElement markup;
+ Html_u8 borderWidth; /* Width of the border */
+ Html_u8 nCol; /* Number of columns */
+ Html_u16 nRow; /* Number of rows */
+ Html_32 y; /* top edge of table border */
+ Html_32 h; /* height of the table border */
+ Html_16 x; /* left edge of table border */
+ Html_16 w; /* width of the table border */
+ int minW[HTML_MAX_COLUMNS+1]; /* minimum width of each column */
+ int maxW[HTML_MAX_COLUMNS+1]; /* maximum width of each column */
+};
+typedef struct HtmlRef HtmlRef;
+struct HtmlRef {
+ HtmlMarkupElement markup;
+ HtmlElement *pOther; /* Pointer to some other Html element */
+};
+typedef struct HtmlLi HtmlLi;
+struct HtmlLi {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* What type of list is this? */
+ Html_u8 ascent; /* height above the baseline */
+ Html_u8 descent; /* depth below the baseline */
+ Html_16 cnt; /* Value for this element (if inside <OL>) */
+ Html_16 x; /* X coordinate of the bullet */
+ Html_32 y; /* Y coordinate of the bullet */
+};
+typedef struct HtmlListStart HtmlListStart;
+struct HtmlListStart {
+ HtmlMarkupElement markup;
+ Html_u8 type; /* One of the LI_TYPE_ defines above */
+ Html_u8 compact; /* True if the COMPACT flag is present */
+ Html_u16 cnt; /* Next value for <OL> */
+ Html_u16 width; /* How much space to allow for indentation */
+ HtmlElement *pPrev; /* Next higher level list, or NULL */
+};
+typedef struct HtmlImageMarkup HtmlImageMarkup;
+typedef struct HtmlImage HtmlImage;
+struct HtmlImageMarkup {
+ HtmlMarkupElement markup;
+ Html_u8 align; /* Alignment. See IMAGE_ALIGN_ defines below */
+ Html_u8 textAscent; /* Ascent of text font in force at the <IMG> */
+ Html_u8 textDescent; /* Descent of text font in force at the <IMG> */
+ Html_u8 redrawNeeded; /* Need to redraw this image because the image
+ ** content changed. */
+ Html_16 h; /* Actual height of the image */
+ Html_16 w; /* Actual width of the image */
+ Html_16 ascent; /* How far image extends above "y" */
+ Html_16 descent; /* How far image extends below "y" */
+ Html_16 x; /* X coordinate of left edge of the image */
+ Html_32 y; /* Y coordinate of image baseline */
+ char *zAlt; /* Alternative text */
+ HtmlImage *pImage; /* Corresponding HtmlImage structure */
+ HtmlElement *pNext; /* Next markup using the same HtmlImage structure */
+};
+typedef struct HtmlInput HtmlInput;
+struct HtmlInput {
+ HtmlMarkupElement markup;
+ HtmlElement *pForm; /* The <FORM> to which this belongs */
+ HtmlElement *pNext; /* Next element in a list of all input elements */
+ Tk_Window tkwin; /* The window that implements this control */
+ HtmlWidget *htmlPtr; /* The whole widget. Needed by geometry callbacks */
+ HtmlElement *pEnd; /* End tag for <TEXTAREA>, etc. */
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 padLeft; /* Extra padding on left side of the control */
+ Html_u8 align; /* One of the IMAGE_ALIGN_xxx types */
+ Html_u8 textAscent; /* Ascent for the current font */
+ Html_u8 textDescent; /* descent for the current font */
+ Html_u8 type; /* What type of input is this? */
+ Html_u8 sized; /* True if this input has been sized already */
+ Html_u16 cnt; /* Used to derive widget name. 0 if no widget */
+};
+typedef struct HtmlForm HtmlForm;
+struct HtmlForm {
+ HtmlMarkupElement markup;
+ Html_u16 id; /* Unique number assigned to this form */
+};
+typedef struct HtmlHr HtmlHr;
+struct HtmlHr {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Baseline for this input element */
+ Html_u16 x; /* Left edge */
+ Html_u16 w, h; /* Width and height of this control */
+ Html_u8 is3D; /* Is it drawn 3D? */
+};
+typedef struct HtmlAnchor HtmlAnchor;
+struct HtmlAnchor {
+ HtmlMarkupElement markup;
+ Html_32 y; /* Top edge for this element */
+};
+typedef struct HtmlScript HtmlScript;
+struct HtmlScript {
+ HtmlMarkupElement markup;
+ char *zScript; /* Complete text of this script */
+ int nScript; /* Number of characters of text */
+};
+struct HtmlBlock {
+ HtmlBaseElement base; /* Superclass. Must be first */
+ char *z; /* Space to hold text when n>0 */
+ int top, bottom; /* Extremes of y coordinates */
+ Html_u16 left, right; /* Left and right boundry of this object */
+ Html_u16 n; /* Number of characters in z[] */
+ HtmlBlock *pPrev, *pNext; /* Linked list of all Blocks */
+};
+union HtmlElement {
+ HtmlElement *pNext;
+ HtmlBaseElement base;
+ HtmlTextElement text;
+ HtmlSpaceElement space;
+ HtmlMarkupElement markup;
+ HtmlCell cell;
+ HtmlTable table;
+ HtmlRef ref;
+ HtmlLi li;
+ HtmlListStart list;
+ HtmlImageMarkup image;
+ HtmlInput input;
+ HtmlForm form;
+ HtmlHr hr;
+ HtmlAnchor anchor;
+ HtmlScript script;
+ HtmlBlock block;
+};
+#define REDRAW_IMAGES 0x002000
+void HtmlBlockDraw(HtmlWidget *htmlPtr,HtmlBlock *pBlock,Drawable drawable,int drawableLeft,int drawableTop,int drawableWidth,int drawableHeight);
+#define FONT_Any -1
+#define COLOR_Background 4 /* Default background color */
+GC HtmlGetGC(HtmlWidget *htmlPtr,int color,int font);
+#define RESIZE_CLIPWIN 0x000400
+#define REDRAW_BORDER 0x000100
+#define GOT_FOCUS 0x000002
+#define REDRAW_FOCUS 0x000040
+#define REDRAW_PENDING 0x000001
+void HtmlUpdateInsert(HtmlWidget *htmlPtr);
+void HtmlUpdateSelection(HtmlWidget *htmlPtr,int forceUpdate);
+int HtmlMapControls(HtmlWidget *htmlPtr);
+void HtmlFormBlocks(HtmlWidget *htmlPtr);
+int HtmlUnlock(HtmlWidget *htmlPtr);
+void HtmlLayout(HtmlWidget *htmlPtr);
+void HtmlLock(HtmlWidget *htmlPtr);
+#define REDRAW_TEXT 0x000080
+#define VSCROLL 0x000008
+#define HSCROLL 0x000004
+#define EXTEND_LAYOUT 0x000200
+#define RELAYOUT 0x000010
+struct HtmlImage {
+ HtmlWidget *htmlPtr; /* The owner of this image */
+ Tk_Image image; /* The Tk image token */
+ Html_32 w; /* Requested width of this image (0 if none) */
+ Html_32 h; /* Requested height of this image (0 if none) */
+ char *zUrl; /* The URL for this image. */
+ char *zWidth, *zHeight; /* Width and height in the <img> markup. */
+ HtmlImage *pNext; /* Next image on the list */
+ HtmlElement *pList; /* List of all <IMG> markups that use this
+ ** same image */
+};
+#define STYLER_RUNNING 0x000800
+#define RESIZE_ELEMENTS 0x000020
+typedef struct HtmlMargin HtmlMargin;
+void HtmlClearMarginStack(HtmlMargin **ppMargin);
+#define N_CACHE_GC 16
+void HtmlComputeHorizontalPosition(HtmlWidget *htmlPtr,char *buf);
+void HtmlComputeVerticalPosition(HtmlWidget *htmlPtr,char *buf);
+int HtmlUsableHeight(HtmlWidget *htmlPtr);
+#if defined(COVERAGE_TEST)
+extern int HtmlTPArray[2000];
+# define TestPoint(X) {extern int HtmlTPArray[]; HtmlTPArray[X]++;}
+#endif
+#if !(defined(COVERAGE_TEST))
+# define TestPoint(X)
+#endif
+int HtmlUsableWidth(HtmlWidget *htmlPtr);
+Tk_ConfigSpec *HtmlConfigSpec(void);
+#define DEF_HTML_SCROLL_COMMAND ""
+#define DEF_HTML_WIDTH "600"
+#define DEF_HTML_VISITED "blue3"
+#define DEF_HTML_UNVISITED "blue1"
+#define DEF_HTML_TAKE_FOCUS "0"
+#define DEF_HTML_SELECTION_COLOR "skyblue"
+#define DEF_HTML_RELIEF "raised"
+#define DEF_HTML_PADY "5"
+#define DEF_HTML_PADX "5"
+#define DEF_HTML_INSERT_ON_TIME "600"
+#define DEF_HTML_INSERT_OFF_TIME "300"
+#define DEF_HTML_HIGHLIGHT_WIDTH "0"
+#define DEF_HTML_HIGHLIGHT DEF_BUTTON_HIGHLIGHT
+#define DEF_HTML_HIGHLIGHT_BG DEF_BUTTON_HIGHLIGHT_BG
+#define DEF_HTML_HEIGHT "400"
+#define DEF_HTML_FG DEF_BUTTON_FG
+#define DEF_HTML_EXPORT_SEL "yes"
+#define DEF_HTML_CURSOR DEF_FRAME_CURSOR
+#define DEF_HTML_BORDER_WIDTH "2"
+#define DEF_HTML_BG_MONO DEF_FRAME_BG_MONO
+#define DEF_HTML_BG_COLOR DEF_FRAME_BG_COLOR
+typedef struct HtmlIndex HtmlIndex;
+struct HtmlIndex {
+ HtmlElement *p; /* The token containing the character */
+ int i; /* Index of the character */
+};
+typedef struct HtmlLayoutContext HtmlLayoutContext;
+struct HtmlLayoutContext {
+ HtmlWidget *htmlPtr; /* The html widget undergoing layout */
+ HtmlElement *pStart; /* Start of elements to layout */
+ HtmlElement *pEnd; /* Stop when reaching this element */
+ int headRoom; /* Extra space wanted above this line */
+ int top; /* Absolute top of drawing area */
+ int bottom; /* Bottom of previous line */
+ int left, right; /* Left and right extremes of drawing area */
+ int pageWidth; /* Width of the layout field, including
+ ** the margins */
+ int maxX, maxY; /* Maximum X and Y values of paint */
+ HtmlMargin *leftMargin; /* Stack of left margins */
+ HtmlMargin *rightMargin; /* Stack of right margins */
+};
+struct HtmlWidget {
+ Tk_Window tkwin; /* The main window for this widget */
+ Tk_Window clipwin; /* The clipping window in which all text is
+ ** rendered. */
+ char *zClipwin; /* Name of the clipping window. */
+ Display *display; /* The X11 Server that contains tkwin */
+ Tcl_Interp *interp; /* The interpreter in which the widget lives */
+ char *zCmdName; /* Name of the command */
+ HtmlElement *pFirst; /* First HTML token on a list of them all */
+ HtmlElement *pLast; /* Last HTML token on the list */
+ int nToken; /* Number of HTML tokens on the list.
+ * Html_Block tokens don't count. */
+ HtmlElement *lastSized; /* Last HTML element that has been sized */
+ HtmlElement *nextPlaced; /* Next HTML element that needs to be
+ * positioned on canvas. */
+ HtmlBlock *firstBlock; /* List of all HtmlBlock tokens */
+ HtmlBlock *lastBlock; /* Last HtmlBlock in the list */
+ HtmlElement *firstInput; /* First <INPUT> element */
+ HtmlElement *lastInput; /* Last <INPUT> element */
+ int nInput; /* The number of <INPUT> elements */
+ int nForm; /* The number of <FORM> elements */
+ int varId; /* Used to construct a unique name for a
+ ** global array used by <INPUT> elements */
+
+ /*
+ * Information about the selected region of text
+ */
+ HtmlIndex selBegin; /* Start of the selection */
+ HtmlIndex selEnd; /* End of the selection */
+ HtmlBlock *pSelStartBlock; /* Block in which selection starts */
+ Html_16 selStartIndex; /* Index in pSelStartBlock of first selected
+ * character */
+ Html_16 selEndIndex; /* Index of last selecte char in pSelEndBlock */
+ HtmlBlock *pSelEndBlock; /* Block in which selection ends */
+
+ /*
+ * Information about the insertion cursor
+ */
+ int insOnTime; /* How long the cursor states one (millisec) */
+ int insOffTime; /* How long it is off (milliseconds) */
+ int insStatus; /* Is it visible? */
+ Tcl_TimerToken insTimer; /* Timer used to flash the insertion cursor */
+ HtmlIndex ins; /* The insertion cursor position */
+ HtmlBlock *pInsBlock; /* The HtmlBlock containing the cursor */
+ int insIndex; /* Index in pInsBlock of the cursor */
+
+ /*
+ * The following fields hold state information used by
+ * the tokenizer.
+ */
+ char *zText; /* Complete text of the unparsed HTML */
+ int nText; /* Number of characters in zText */
+ int nAlloc; /* Space allocated for zText */
+ int nComplete; /* How much of zText has actually been
+ * converted into tokens */
+ int iCol; /* The column in which zText[nComplete]
+ * occurs. Used to resolve tabs in input */
+ int iPlaintext; /* If not zero, this is the token type that
+ * caused us to go into plaintext mode. One
+ * of Html_PLAINTEXT, Html_LISTING or
+ * Html_XMP */
+ HtmlScript *pScript; /* <SCRIPT> currently being parsed */
+ char *zHandler[Html_TypeCount]; /* If not NULL, this is a TCL routine that
+ * is used to process tokens of the given
+ * type */
+ /*
+ * These fields hold state information used by the HtmlAddStyle routine.
+ * We have to store this state information here since HtmlAddStyle
+ * operates incrementally. This information must be carried from
+ * one incremental execution to the next.
+ */
+ HtmlStyleStack *styleStack; /* The style stack */
+ int paraAlignment; /* Justification associated with <p> */
+ int rowAlignment; /* Justification associated with <tr> */
+ int anchorFlags; /* Style flags associated with <A>...</A> */
+ int inDt; /* Style flags associated with <DT>...</DT> */
+ int inTr; /* True if within <tr>..</tr> */
+ int inTd; /* True if within <td>..</td> or <th>..</th> */
+ HtmlElement *anchorStart; /* Most recent <a href=...> */
+ HtmlElement *formStart; /* Most recent <form> */
+ HtmlElement *formElemStart; /* Most recent <textarea> or <select> */
+ HtmlElement *innerList; /* The inner most <OL> or <UL> */
+
+ /*
+ * These fields are used to hold the state of the layout engine.
+ * Because the layout is incremental, this state must be held for
+ * the life of the widget.
+ */
+ HtmlLayoutContext layoutContext;
+
+ /*
+ * Information used when displaying the widget:
+ */
+ Tk_3DBorder border; /* Background color */
+ int borderWidth; /* Width of the border. */
+ int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ int inset; /* Total width of highlight and 3-D border */
+ Tk_Font aFont[N_FONT]; /* Information about all screen fonts */
+ char fontValid[(N_FONT+7)/8]; /* If bit N%8 of work N/8 of this field is 0
+ * if aFont[N] needs to be reallocated before
+ * being used. */
+ XColor *apColor[N_COLOR]; /* Information about all colors */
+ int colorUsed; /* bit N is 1 if color N is in use. Only
+ ** applies to colors that aren't predefined */
+ int iDark[N_COLOR]; /* Dark 3D shadow of color K is iDark[K] */
+ int iLight[N_COLOR]; /* Light 3D shadow of color K is iLight[K] */
+ XColor *fgColor; /* Color of normal text. apColor[0] */
+ XColor *newLinkColor; /* Color of unvisitied links. apColor[1] */
+ XColor *oldLinkColor; /* Color of visitied links. apColor[2] */
+ XColor *selectionColor; /* Background color for selections */
+ GcCache aGcCache[N_CACHE_GC]; /* A cache of GCs for general use */
+ int lastGC; /* Index of recently used GC */
+ HtmlImage *imageList; /* A list of all images */
+ int width, height; /* User-requested size of the usable drawing
+ * area, in pixels. Borders and padding
+ * make the actual window a little larger */
+ int realWidth, realHeight; /* The actual physical size of tkwin as
+ * reported in the most recent ConfigureNotify
+ * event. */
+ int padx, pady; /* Separation between the edge of the window
+ * and rendered HTML. */
+ int underlineLinks; /* TRUE if we should underline hyperlinks */
+
+ /* Information about the selection
+ */
+ int exportSelection; /* True if the selection is automatically
+ * exported to the clipboard */
+
+ /* Callback commands. The HTML parser will invoke callbacks from time
+ ** to time to find out information it needs to complete formatting of
+ ** the document. The following fields define the callback commands.
+ */
+ char *zIsVisited; /* Command to tell if a hyperlink has already
+ ** been visited */
+ char *zGetImage; /* Command to get an image from a URL */
+ char *zFrameCommand; /* Command for handling <frameset> markup */
+ char *zAppletCommand; /* Command to process applets */
+ char *zResolverCommand; /* Command to resolve URIs */
+ char *zFormCommand; /* When user presses Submit */
+ char *zHyperlinkCommand; /* Invoked when a hyperlink is clicked */
+ char *zFontCommand; /* Invoked to find font names */
+ char *zScriptCommand; /* Invoked for each <SCRIPT> markup */
+
+ /*
+ * Miscellaneous information:
+ */
+ int tableRelief; /* 3d effects on <TABLE> */
+ int ruleRelief; /* 3d effects on <HR> */
+ char *zBase; /* The base URI */
+ char *zBaseHref; /* zBase as modified by <BASE HREF=..> markup */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ char *takeFocus; /* Value of -takefocus option; not used in
+ * the C code, but used by keyboard traversal
+ * scripts. Malloc'ed, but may be NULL. */
+ char *yScrollCmd; /* Command prefix for communicating with
+ * vertical scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ char *xScrollCmd; /* Command prefix for communicating with
+ * horizontal scrollbar. NULL means no command
+ * to issue. Malloc'ed. */
+ int xOffset, yOffset; /* Current scroll position. These form the
+ * coordinate in the virtual canvas that
+ * corresponds to (0,0) on the physical screen
+ * in window tkwin */
+ int maxX, maxY; /* Maximum extent of any "paint" that appears
+ * on the virtual canvas. Used to compute
+ * scrollbar positions. */
+ int dirtyLeft, dirtyTop; /* Top left corner of region to redraw. These
+ * are physical screen coordinates relative to
+ * clipwin, not tkwin. */
+ int dirtyRight, dirtyBottom; /* Bottom right corner of region to redraw */
+ int locked; /* Number of locks on this structure. Don't
+ ** delete until it reaches zero. */
+ int flags; /* Various flags; see below for
+ * definitions. */
+};
+#define DEF_HTML_CALLBACK ""
+extern int HtmlTraceMask;
+struct HtmlMargin {
+ int indent; /* Size of the current margin */
+ int bottom; /* Y value at which this margin expires */
+ int tag; /* Markup that will cancel this margin */
+ HtmlMargin *pNext; /* Previous margin */
+};
diff --git a/tkhtml1/src/tokenlist.txt b/tkhtml1/src/tokenlist.txt
new file mode 100644
index 0000000..6b0b638
--- /dev/null
+++ b/tkhtml1/src/tokenlist.txt
@@ -0,0 +1,116 @@
+#
+# This file contains raw data used to build the "htmltokens.c" file.
+# Each line contains 2 or 3 elements. The first word on each line is
+# the name of some HTML markup. The second word is the amount of
+# space to allocate for the corresponding element. "0" appears if
+# no extra space (beyond HtmlMarkup) is required. If there is a
+# corresponding end-tag, then the third column specifies the size of
+# the end markup.
+# $Revision$
+#
+# Copyright (C) 1997-2000 D. Richard Hipp
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+# Author contact information:
+# drh@acm.org
+# http://www.hwaci.com/drh/
+
+
+# Order is not important. Comments begin with #. Spacing is ignored.
+
+a HtmlAnchor HtmlRef
+address 0 0
+applet HtmlInput 0
+area 0
+b 0 0
+base 0
+basefont 0 0
+bgsound 0
+big 0 0
+blockquote 0 0
+body 0 0
+br 0
+caption 0 0
+center 0 0
+cite 0 0
+code 0 0
+comment 0 0
+dd HtmlRef 0
+dfn 0 0
+dir HtmlListStart HtmlRef
+div 0 0
+dl HtmlListStart HtmlRef
+dt HtmlRef 0
+em 0 0
+embed HtmlInput
+font 0 0
+form HtmlForm HtmlRef
+frame 0 0
+frameset 0 0
+h1 0 0
+h2 0 0
+h3 0 0
+h4 0 0
+h5 0 0
+h6 0 0
+hr HtmlHr
+html 0 0
+i 0 0
+iframe 0
+img HtmlImageMarkup
+input HtmlInput
+isindex 0
+kbd 0 0
+li HtmlLi 0
+link 0
+listing 0 0
+map 0 0
+marquee 0 0
+menu HtmlListStart HtmlRef
+meta 0
+nextid 0
+nobr 0 0
+noframe 0 0
+noscript 0 0
+ol HtmlListStart HtmlRef
+option 0 0
+p 0 0
+param 0 0
+plaintext 0
+pre 0 0
+s 0 0
+samp 0 0
+script HtmlScript
+select HtmlInput HtmlRef
+small 0 0
+strike 0 0
+strong 0 0
+style HtmlScript
+sub 0 0
+sup 0 0
+table HtmlTable HtmlRef
+td HtmlCell HtmlRef
+textarea HtmlInput HtmlRef
+th HtmlCell HtmlRef
+title 0 0
+tr HtmlRef HtmlRef
+tt 0 0
+u 0 0
+ul HtmlListStart HtmlRef
+var 0 0
+wbr 0
+xmp 0 0