/* ** 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); } }
/* ** Pop one margin off of the given margin stack. */ static void HtmlPopOneMargin(HtmlMargin **ppMargin){ if( *ppMargin ){ HtmlMargin *pOld = *ppMargin; *ppMargin = pOld->pNext; HtmlFree(pOld); } }
/* ** 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); } }
/* *--------------------------------------------------------------------------- * * HtmlImageServerShutdown -- * * Shutdown and delete the image-server for html widget pTree. This * function frees all resources allocated by HtmlImageServerInit(). * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void HtmlImageServerShutdown (HtmlTree *pTree) { HtmlImageServer *p = pTree->pImageServer; #ifndef NDEBUG Tcl_HashSearch search; Tcl_HashEntry *pEntry = Tcl_FirstHashEntry(&p->aImage, &search); assert(!pEntry); #endif HtmlFree(p); pTree->pImageServer = 0; }
/* ** 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); }
/* ** 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; }
/* ** 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); }
Tk_Image HtmlImageImage(HtmlImage2 *pImage) { assert(pImage && (pImage->isValid == 1 || pImage->isValid == 0)); if (!pImage->isValid) { /* pImage->image is invalid. This happens if the underlying Tk * image, or the image that this is a scaled copy of, is changed * or deleted. It also happens the first time this function is * called after a call to HtmlImageScale(). */ Tk_PhotoHandle photo; Tk_PhotoImageBlock block; Tcl_Interp *interp = pImage->pImageServer->pTree->interp; HtmlImage2 *pUnscaled = pImage->pUnscaled; if (pUnscaled->pixmap) { Tcl_Obj *apObj[4]; int rc; /*printf("TODO: BAD. Have to recreate image to make scaled copy.\n");*/ apObj[0] = pUnscaled->pImageName; apObj[1] = Tcl_NewStringObj("configure", -1); apObj[2] = Tcl_NewStringObj("-data", -1); apObj[3] = pUnscaled->pCompressed; Tcl_IncrRefCount(apObj[1]); Tcl_IncrRefCount(apObj[2]); Tcl_IncrRefCount(apObj[3]); pUnscaled->nIgnoreChange++; rc = Tcl_EvalObjv(interp, 4, apObj, TCL_EVAL_GLOBAL); pUnscaled->nIgnoreChange--; assert(rc==TCL_OK); Tcl_IncrRefCount(apObj[3]); Tcl_DecrRefCount(apObj[2]); Tcl_DecrRefCount(apObj[1]); } assert(pUnscaled); if (!pImage->pImageName) { /* If pImageName is still NULL, then create a new photo * image to write the scaled data to. Todo: Is it possible * to do this without invoking a script, creating the Tcl * command etc.? */ Tk_Window win = pImage->pImageServer->pTree->tkwin; Tcl_Interp *interp = pImage->pImageServer->pTree->interp; const char *z; Tcl_Eval(interp, "image create photo"); pImage->pImageName = Tcl_GetObjResult(interp); Tcl_IncrRefCount(pImage->pImageName); assert(0 == pImage->pDelete); assert(0 == pImage->image); z = Tcl_GetString(pImage->pImageName); pImage->image = Tk_GetImage(interp, win, z, imageChanged, pImage); } assert(pImage->image); CHECK_INTEGER_PLAUSIBILITY(pImage->width); CHECK_INTEGER_PLAUSIBILITY(pImage->height); CHECK_INTEGER_PLAUSIBILITY(pUnscaled->width); CHECK_INTEGER_PLAUSIBILITY(pUnscaled->height); /* Write the scaled data into image pImage->image */ photo = Tk_FindPhoto(interp, Tcl_GetString(pUnscaled->pImageName)); if (photo) { Tk_PhotoGetImage(photo, &block); } if (photo && block.pixelPtr) { int x, y; /* Iterator variables */ int w, h; /* Width and height of unscaled image */ int sw, sh; /* Width and height of scaled image */ Tk_PhotoHandle s_photo; Tk_PhotoImageBlock s_block; sw = pImage->width; sh = pImage->height; w = pUnscaled->width; h = pUnscaled->height; s_photo = Tk_FindPhoto(interp, Tcl_GetString(pImage->pImageName)); s_block.pixelPtr = (unsigned char *)HtmlAlloc("temp", sw * sh * 4); s_block.width = sw; s_block.height = sh; s_block.pitch = sw * 4; s_block.pixelSize = 4; s_block.offset[0] = 0; s_block.offset[1] = 1; s_block.offset[2] = 2; s_block.offset[3] = 3; for (x=0; x<sw; x++) { int orig_x = ((x * w) / sw); for (y=0; y<sh; y++) { unsigned char *zOrig; unsigned char *zScale; int orig_y = ((y * h) / sh); zOrig = &block.pixelPtr[ orig_x * block.pixelSize + orig_y * block.pitch]; zScale = &s_block.pixelPtr[ x * s_block.pixelSize + y * s_block.pitch]; zScale[0] = zOrig[block.offset[0]]; zScale[1] = zOrig[block.offset[1]]; zScale[2] = zOrig[block.offset[2]]; zScale[3] = zOrig[block.offset[3]]; } } photoputblock(interp, s_photo, &s_block, 0, 0, sw, sh, 0); HtmlFree(s_block.pixelPtr); } else { return HtmlImageImage(pImage->pUnscaled); } pImage->isValid = 1; if (pUnscaled->pixmap) { Tcl_Obj *apObj[4]; apObj[0] = Tcl_NewStringObj("image", -1); apObj[1] = Tcl_NewStringObj("create", -1); apObj[2] = Tcl_NewStringObj("photo", -1); apObj[3] = pUnscaled->pImageName; Tcl_IncrRefCount(apObj[0]); Tcl_IncrRefCount(apObj[1]); Tcl_IncrRefCount(apObj[2]); pUnscaled->nIgnoreChange++; Tcl_EvalObjv(interp, 4, apObj, TCL_EVAL_GLOBAL); pUnscaled->nIgnoreChange--; Tcl_DecrRefCount(apObj[2]); Tcl_DecrRefCount(apObj[1]); Tcl_IncrRefCount(apObj[0]); } } return pImage->image; }
static void freeCaseInsensitiveEntry(Tcl_HashEntry *hPtr) { HtmlFree(hPtr); }
/* ** 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); } 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(&zBuf[i+1], &zBuf[i+3]); 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(&zBuf[j+1], &zBuf[i+4]); }else{ zBuf[j+1] = 0; } i = j-1; if( i<-1 ) i = -1; continue; } } 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; }
/* ** 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; }
static void freeValuesEntry(Tcl_HashEntry *hPtr) { HtmlFree(hPtr); }
/* ** 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; char **argv; char *zBuf; if( Tcl_SplitList(htmlPtr->interp, zArgs, &argc, &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; }
/* ** 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; }
/* 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; }
/* *--------------------------------------------------------------------------- * * HtmlImageTile -- * * Results: * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tk_Image HtmlImageTile( HtmlImage2 *pImage, /* Image object */ int *pW, int *pH ) { HtmlTree *pTree = pImage->pImageServer->pTree; Tcl_Interp *interp = pTree->interp; Tcl_Obj *pTileName; /* Name of tile image at the script level */ Tk_PhotoHandle tilephoto; /* Photo of tile */ Tk_PhotoImageBlock tileblock; /* Block of tile image */ int iTileWidth; int iTileHeight; Tk_PhotoHandle origphoto; Tk_PhotoImageBlock origblock; int x; int y; /* The tile has already been generated. Return it. */ if (pImage->pTileName) { goto return_tile; } /* The image is too big to bother with a tile. Return the original. */ if (!tilesize(pImage, &iTileWidth, &iTileHeight)) { goto return_original; } /* Retrieve the block for the original image */ origphoto = Tk_FindPhoto(interp, Tcl_GetString(pImage->pImageName)); if (!origphoto) goto return_original; Tk_PhotoGetImage(origphoto, &origblock); if (!origblock.pixelPtr) goto return_original; /* Create the tile image. Surely there is a way to do this without * invoking a script, but I haven't found it yet. */ Tcl_Eval(interp, "image create photo"); pTileName = Tcl_GetObjResult(interp); Tcl_IncrRefCount(pTileName); tilephoto = Tk_FindPhoto(interp, Tcl_GetString(pTileName)); Tk_PhotoGetImage(tilephoto, &tileblock); pImage->pTileName = pTileName; pImage->tile = Tk_GetImage( interp, pTree->tkwin, Tcl_GetString(pTileName), imageChanged, 0 ); /* Allocate a block to write the tile data into. */ tileblock.pixelPtr = (unsigned char *)HtmlAlloc( "temp", iTileWidth * iTileHeight * 4 ); tileblock.width = iTileWidth; tileblock.height = iTileHeight; tileblock.pitch = iTileWidth * 4; tileblock.pixelSize = 4; tileblock.offset[0] = 0; tileblock.offset[1] = 1; tileblock.offset[2] = 2; tileblock.offset[3] = 3; for (x = 0; x < iTileWidth; x++) { for (y = 0; y < iTileHeight; y++) { unsigned char *zOrig; unsigned char *zScale; zOrig = &origblock.pixelPtr[ (x % pImage->width) *origblock.pixelSize + (y % pImage->height) * origblock.pitch ]; zScale = &tileblock.pixelPtr[x * 4 + y * tileblock.pitch]; zScale[0] = zOrig[origblock.offset[0]]; zScale[1] = zOrig[origblock.offset[1]]; zScale[2] = zOrig[origblock.offset[2]]; zScale[3] = zOrig[origblock.offset[3]]; } } photoputblock(interp,tilephoto,&tileblock,0,0,iTileWidth,iTileHeight,0); HtmlFree(tileblock.pixelPtr); pImage->iTileWidth = iTileWidth; pImage->iTileHeight = iTileHeight; return_tile: *pW = pImage->iTileWidth; *pH = pImage->iTileHeight; return pImage->tile; return_original: HtmlImageSize(pImage, pW, pH); return HtmlImageImage(pImage); }
/* ** 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; }
/* *--------------------------------------------------------------------------- * * HtmlImageServerGet -- * * Retrieve an HtmlImage2 object for the image at URL zUrl from * an image-server. The caller should match this call with a single * HtmlImageFree() when the image object is no longer required. * * If the image is not already in the cache, the Tcl script * configured as the widget -imagecmd is invoked. If this command * raises an error or returns an invalid result, then this function * returns NULL. A Tcl back-ground error is propagated in this case * also. * * Results: * Pointer to HtmlImage2 object containing the image from zUrl, or * NULL, if zUrl was invalid for some reason. * * Side effects: * May invoke -imagecmd script. * *--------------------------------------------------------------------------- */ HtmlImage2 * HtmlImageServerGet (HtmlImageServer *p, const char *zUrl) { Tcl_Obj *pImageCmd = p->pTree->options.imagecmd; Tcl_Interp *interp = p->pTree->interp; Tcl_HashEntry *pEntry = 0; HtmlImage2 *pImage = 0; /* Try to find the requested image in the hash table. */ if (pImageCmd) { int new_entry; pEntry = Tcl_CreateHashEntry(&p->aImage, zUrl, &new_entry); if (new_entry) { Tcl_Obj *pEval; Tcl_Obj *pResult; int rc; int nObj; Tcl_Obj **apObj = 0; Tk_Image img; /* The image could not be found in the hash table and an * -imagecmd callback is configured. The callback script * must be executed to obtain an image. Build up a script * in pEval and execute it. Put the result in variable pResult. */ pEval = Tcl_DuplicateObj(pImageCmd); Tcl_IncrRefCount(pEval); Tcl_ListObjAppendElement(interp, pEval, Tcl_NewStringObj(zUrl, -1)); rc = Tcl_EvalObjEx(interp, pEval, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL); Tcl_DecrRefCount(pEval); if (rc != TCL_OK) { goto image_get_out; } pResult = Tcl_GetObjResult(interp); /* Read the result into array apObj. If the result was * not a valid Tcl list, return NULL and raise a background * error about the badly formed list. */ rc = Tcl_ListObjGetElements(interp, pResult, &nObj, &apObj); if (rc != TCL_OK) { goto image_get_out; } if (nObj==0) { Tcl_DeleteHashEntry(pEntry); goto image_unavailable; } pImage = HtmlNew(HtmlImage2); if (nObj == 1 || nObj == 2) { img = Tk_GetImage( interp, p->pTree->tkwin, Tcl_GetString(apObj[0]), imageChanged, pImage ); } if ((nObj != 1 && nObj != 2) || !img) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "-imagecmd returned bad value", 0); HtmlFree(pImage); pImage = 0; goto image_get_out; } Tcl_SetHashValue(pEntry, (ClientData)pImage); Tcl_IncrRefCount(apObj[0]); pImage->pImageName = apObj[0]; if (nObj == 2) { Tcl_IncrRefCount(apObj[1]); pImage->pDelete = apObj[1]; } pImage->pImageServer = p; pImage->zUrl = Tcl_GetHashKey(&p->aImage, pEntry); pImage->image = img; Tk_SizeOfImage(pImage->image, &pImage->width, &pImage->height); pImage->isValid = 1; HtmlImagePixmap(pImage); } } image_get_out: pImage = (HtmlImage2 *)(pEntry ? Tcl_GetHashValue(pEntry) : 0); HtmlImageRef(pImage); if (!pImage && pImageCmd) { Tcl_BackgroundError(interp); Tcl_ResetResult(interp); assert(pEntry); Tcl_DeleteHashEntry(pEntry); } image_unavailable: return pImage; }
Tcl_Obj *HtmlXImageToImage( HtmlTree *pTree, XImage *pXImage, int w, int h ) { Tcl_Interp *interp = pTree->interp; Tcl_Obj *pImage; Tk_PhotoHandle photo; Tk_PhotoImageBlock block; int x; int y; unsigned long redmask, redshift; unsigned long greenmask, greenshift; unsigned long bluemask, blueshift; Visual *pVisual; Tcl_Eval(interp, "image create photo"); pImage = Tcl_GetObjResult(interp); Tcl_IncrRefCount(pImage); block.pixelPtr = (unsigned char *)HtmlAlloc("temp", w * h * 4); block.width = w; block.height = h; block.pitch = w*4; block.pixelSize = 4; block.offset[0] = 0; block.offset[1] = 1; block.offset[2] = 2; block.offset[3] = 3; pVisual = Tk_Visual(pTree->tkwin); redmask = pVisual->red_mask; bluemask = pVisual->blue_mask; greenmask = pVisual->green_mask; for (redshift=0; !((redmask>>redshift)&0x000000001); redshift++); for (greenshift=0; !((greenmask>>greenshift)&0x00000001); greenshift++); for (blueshift=0; !((bluemask>>blueshift)&0x00000001); blueshift++); for (x=0; x<w; x++) { for (y=0; y<h; y++) { unsigned char *pOut; unsigned long pixel = XGetPixel(pXImage, x, y); pOut = &block.pixelPtr[x*block.pixelSize + y*block.pitch]; pOut[0] = (pixel&redmask)>>redshift; pOut[1] = (pixel&greenmask)>>greenshift; pOut[2] = (pixel&bluemask)>>blueshift; pOut[3] = 0xFF; } } photo = Tk_FindPhoto(interp, Tcl_GetString(pImage)); photoputblock(interp, photo, &block, 0, 0, w, h, 0); HtmlFree(block.pixelPtr); return pImage; }
void HtmlImageFree (HtmlImage2 *pImage) { if (!pImage) { return; } assert(pImage->nRef > 0); pImage->nRef--; if ( pImage->nRef == 0 && (pImage->pUnscaled || !pImage->pImageServer->isSuspendGC) ) { /* The reference count for this structure has reached zero. * Really delete it. The assert() says that an original image * cannot be deleted before all of it's scaled copies. */ assert(pImage->pUnscaled || 0 == pImage->pNext); freeImageCompressed(pImage); freeTile(pImage); if (pImage->pixmap) { HtmlTree *pTree = pImage->pImageServer->pTree; Tk_FreePixmap(Tk_Display(pTree->tkwin), pImage->pixmap); pImage->pixmap = 0; } if (pImage->image) { Tk_FreeImage(pImage->image); } if (pImage->pImageName) { Tcl_Interp *interp = pImage->pImageServer->pTree->interp; Tcl_Obj *pEval; if (!pImage->pDelete) { pEval = Tcl_NewStringObj("image delete", -1); Tcl_IncrRefCount(pEval); } else { pEval = pImage->pDelete; } Tcl_ListObjAppendElement(interp, pEval, pImage->pImageName); Tcl_EvalObjEx(interp, pEval, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); Tcl_DecrRefCount(pEval); Tcl_DecrRefCount(pImage->pImageName); } if (pImage->pUnscaled) { HtmlImage2 *pIter; for ( pIter = pImage->pUnscaled; pIter->pNext != pImage; pIter = pIter->pNext ) { assert(pIter->pNext); } pIter->pNext = pIter->pNext->pNext; HtmlImageFree(pImage->pUnscaled); } else { const char *zKey = pImage->zUrl; Tcl_HashTable *paImage = &pImage->pImageServer->aImage; Tcl_HashEntry *pEntry = Tcl_FindHashEntry(paImage, zKey); assert(pEntry); Tcl_DeleteHashEntry(pEntry); } HtmlFree(pImage); Tcl_CancelIdleCall(asyncPixmapify, (ClientData)pImage); } }
/* ** 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; }