/* ** 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; } } }
/* ** 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; }
/* ** 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 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; }
/* ** 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; }
/* ** 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 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; } }
/* ** 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; const 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 = 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; }
/* ** 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; }