diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2019-01-07 20:01:09 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2019-01-07 20:01:09 (GMT) |
commit | 40254c18e6e39a5d7b83ec6bebf5506851309eb7 (patch) | |
tree | 36994c705ce8237c3fd8a74206b06d85e4176931 /tkhtml1/generic | |
parent | 1ea9e06c2ff3a6f4059d1be92dcca32157fe7c03 (diff) | |
parent | 3ce224e243300735512141a85a1ef499e44f9540 (diff) | |
download | blt-40254c18e6e39a5d7b83ec6bebf5506851309eb7.zip blt-40254c18e6e39a5d7b83ec6bebf5506851309eb7.tar.gz blt-40254c18e6e39a5d7b83ec6bebf5506851309eb7.tar.bz2 |
Merge commit '3ce224e243300735512141a85a1ef499e44f9540' as 'tkhtml1'
Diffstat (limited to 'tkhtml1/generic')
30 files changed, 18477 insertions, 0 deletions
diff --git a/tkhtml1/generic/html.h b/tkhtml1/generic/html.h new file mode 100644 index 0000000..55f44cd --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlcmd.c b/tkhtml1/generic/htmlcmd.c new file mode 100644 index 0000000..5f5fe73 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlcmd.h b/tkhtml1/generic/htmlcmd.h new file mode 100644 index 0000000..9417a00 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmldraw.c b/tkhtml1/generic/htmldraw.c new file mode 100644 index 0000000..42f2f80 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmldraw.h b/tkhtml1/generic/htmldraw.h new file mode 100644 index 0000000..7976f89 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlexts.c b/tkhtml1/generic/htmlexts.c new file mode 100644 index 0000000..9496972 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlexts.h b/tkhtml1/generic/htmlexts.h new file mode 100644 index 0000000..e94edde --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlform.c b/tkhtml1/generic/htmlform.c new file mode 100644 index 0000000..210ae62 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlform.h b/tkhtml1/generic/htmlform.h new file mode 100644 index 0000000..82fbd7e --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlimage.c b/tkhtml1/generic/htmlimage.c new file mode 100644 index 0000000..962ac5c --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlimage.h b/tkhtml1/generic/htmlimage.h new file mode 100644 index 0000000..e7cb81f --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlindex.c b/tkhtml1/generic/htmlindex.c new file mode 100644 index 0000000..7b488a1 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlindex.h b/tkhtml1/generic/htmlindex.h new file mode 100644 index 0000000..37a5fee --- /dev/null +++ b/tkhtml1/generic/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/generic/htmllayout.c b/tkhtml1/generic/htmllayout.c new file mode 100644 index 0000000..e511e53 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmllayout.h b/tkhtml1/generic/htmllayout.h new file mode 100644 index 0000000..0d5805b --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlparse.c b/tkhtml1/generic/htmlparse.c new file mode 100644 index 0000000..4511005 --- /dev/null +++ b/tkhtml1/generic/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: +** +** & & +** < < +** > > +** 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&T > 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 "�". 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/generic/htmlparse.h b/tkhtml1/generic/htmlparse.h new file mode 100644 index 0000000..b5cd34d --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlsizer.c b/tkhtml1/generic/htmlsizer.c new file mode 100644 index 0000000..68d8dc9 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlsizer.h b/tkhtml1/generic/htmlsizer.h new file mode 100644 index 0000000..c5c3081 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmltable.c b/tkhtml1/generic/htmltable.c new file mode 100644 index 0000000..98bbb48 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmltable.h b/tkhtml1/generic/htmltable.h new file mode 100644 index 0000000..2e4cb03 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmltest.c b/tkhtml1/generic/htmltest.c new file mode 100644 index 0000000..c57d98b --- /dev/null +++ b/tkhtml1/generic/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/generic/htmltest.h b/tkhtml1/generic/htmltest.h new file mode 100644 index 0000000..060508f --- /dev/null +++ b/tkhtml1/generic/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/generic/htmltokens.c b/tkhtml1/generic/htmltokens.c new file mode 100644 index 0000000..d8a3c99 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmltokens.h b/tkhtml1/generic/htmltokens.h new file mode 100644 index 0000000..0736806 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlurl.c b/tkhtml1/generic/htmlurl.c new file mode 100644 index 0000000..bf8808f --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlurl.h b/tkhtml1/generic/htmlurl.h new file mode 100644 index 0000000..871c48f --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlwidget.c b/tkhtml1/generic/htmlwidget.c new file mode 100644 index 0000000..3d6e632 --- /dev/null +++ b/tkhtml1/generic/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/generic/htmlwidget.h b/tkhtml1/generic/htmlwidget.h new file mode 100644 index 0000000..1c634b4 --- /dev/null +++ b/tkhtml1/generic/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/generic/tokenlist.txt b/tkhtml1/generic/tokenlist.txt new file mode 100644 index 0000000..6b0b638 --- /dev/null +++ b/tkhtml1/generic/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 |