Example #1
0
/*
** Create a string to hold the given URI.  Memory to hold the string
** is obtained from HtmlAlloc() and must be freed by the calling
** function.
*/
static char *BuildUri(HtmlUri *p){
  int n = 1;
  char *z;
  if( p->zScheme )    n += strlen(p->zScheme)+1;
  if( p->zAuthority ) n += strlen(p->zAuthority)+2;
  if( p->zPath )      n += strlen(p->zPath)+1;
  if( p->zQuery )     n += strlen(p->zQuery)+1;
  if( p->zFragment )  n += strlen(p->zFragment)+1;
  z = HtmlAlloc( n );
  if( z==0 ) return 0;
  n = 0;
  if( p->zScheme ){
    sprintf(z, "%s:", p->zScheme);
    n = strlen(z);
  }
  if( p->zAuthority ){
    sprintf(&z[n], "//%s", p->zAuthority);
    n += strlen(&z[n]);
  }
  if( p->zPath ){
    sprintf(&z[n], "%s", p->zPath);
    n += strlen(&z[n]);
  }
  if( p->zQuery ){
    sprintf(&z[n], "?%s", p->zQuery);
    n += strlen(&z[n]);
  }
  if( p->zFragment ){
    sprintf(&z[n], "#%s", p->zFragment);
  }else{
    z[n] = 0;
  }
  return z;
}
Example #2
0
/*
 *---------------------------------------------------------------------------
 *
 * allocFontEntry --
 *
 *     Allocate enough space for a Tcl_HashEntry and an HtmlFontKey key.
 *
 * Results:
 *     Pointer to allocated TclHashEntry structure.
 *
 * Side effects:
 *     None.
 *
 *---------------------------------------------------------------------------
 */
static Tcl_HashEntry * 
allocFontEntry(
    Tcl_HashTable *tablePtr,    /* Hash table. */
    VOID *keyPtr                /* Key to store in the hash table entry. */
    )
{
    HtmlFontKey *pKey = (HtmlFontKey *)keyPtr;
    unsigned int size;
    Tcl_HashEntry *hPtr;
    HtmlFontKey *pStoredKey;

    assert(pKey->zFontFamily);
    size = (
        sizeof(Tcl_HashEntry) - sizeof(hPtr->key) +
        strlen(pKey->zFontFamily) + 1 +
        sizeof(HtmlFontKey)
    );
    assert(size >= sizeof(Tcl_HashEntry));

    hPtr = (Tcl_HashEntry *) HtmlAlloc("allocFontEntry()", size);
    pStoredKey = (HtmlFontKey *)(hPtr->key.string);
    pStoredKey->iFontSize = pKey->iFontSize;
    pStoredKey->isItalic = pKey->isItalic;
    pStoredKey->isBold = pKey->isBold;
    pStoredKey->zFontFamily = (char *)(&pStoredKey[1]);
    strcpy((char *)pStoredKey->zFontFamily, pKey->zFontFamily);

    return hPtr;
}
Example #3
0
/*
** Parse a text URI into an HtmlUri structure.
*/
static HtmlUri *ParseUri(const char *zUri){
  HtmlUri *p;
  int n;

  p = HtmlAlloc( sizeof(*p) );
  if( p==0 ) return 0;
  memset(p, 0, sizeof(*p));
  if( zUri==0 || zUri[0]==0 ) return p;
  while( isspace(zUri[0]) ){ zUri++; }
  n = ComponentLength(zUri, "", ":/?# ");
  if( n>0 && zUri[n]==':' ){
    p->zScheme = StrNDup(zUri, n);
    zUri += n+1;
  }
  n = ComponentLength(zUri, "//", "/?# ");
  if( n>0 ){
    p->zAuthority = StrNDup(&zUri[2], n-2);
    zUri += n;
  }
  n = ComponentLength(zUri, "", "?# ");
  if( n>0 ){
    p->zPath = StrNDup(zUri, n);
    zUri += n;
  }
  n = ComponentLength(zUri, "?", "# ");
  if( n>0 ){
    p->zQuery = StrNDup(&zUri[1], n-1);
    zUri += n;
  }
  n = ComponentLength(zUri, "#", " ");
  if( n>0 ){
    p->zFragment = StrNDup(&zUri[1], n-1);
  }
  return p;
}
Example #4
0
/*
** Allocate a new HtmlBlock structure.
*/
static HtmlBlock *AllocBlock(void){
  HtmlBlock *pNew;

  pNew = HtmlAlloc( sizeof(HtmlBlock) );
  if( pNew ){
    memset(pNew, 0, sizeof(*pNew));
    pNew->base.type = Html_Block;
  }
  return pNew;
}
Example #5
0
/*
** Create the window name for a child widget.  Space to hold the name
** is obtained from HtmlAlloc() and must be freed by the calling function.
*/
static char *MakeWindowName(
  HtmlWidget *htmlPtr,        /* The HTML widget */
  HtmlElement *pElem          /* The input that needs a child widget */
){
  int n;
  char *zBuf;

  n = strlen(Tk_PathName(htmlPtr->clipwin));
  zBuf = HtmlAlloc( n + 20 );
  sprintf(zBuf,"%s.x%d",Tk_PathName(htmlPtr->clipwin), pElem->input.cnt);
  return zBuf;
}
Example #6
0
/*
** Duplicate a string of length n.
*/
static char *StrNDup(const char *z, int n){
  char *zResult;
  if( n<=0 ){
    n = strlen(z);
  }
  zResult = HtmlAlloc( n + 1 );
  if( zResult ){
    memcpy(zResult, z, n);
    zResult[n] = 0;
    TestPoint(0);
  }
  return zResult;
}
Example #7
0
/*
** Push a new rendering style onto the stack.
*/
static void PushStyleStack(
  HtmlWidget *htmlPtr,   /* Widget on which to push the style */
  int tag,               /* Tag for this style.  Normally the end-tag such
                         ** as </h3> or </em>. */
  HtmlStyle style        /* The style to push */
){
  HtmlStyleStack *p;

  p = HtmlAlloc(sizeof(*p));
  p->pNext = htmlPtr->styleStack;
  p->type = tag;
  p->style = style;
  htmlPtr->styleStack = p;
}
Example #8
0
/*
** Remove leading and trailing spaces from the given string.  Return
** a new string obtained from HtmlAlloc().
*/
static char *Trim(char *z){
  int i;
  char *zNew;
  while( isspace(*z) ) z++;
  i = strlen(z);
  zNew = HtmlAlloc( i+1 );
  if( zNew==0 ) return 0;
  strcpy(zNew, z);
  if( i>0 && isspace(zNew[i-1]) ){
    i--;
    zNew[i] = 0;
  }
  return zNew;
}
Example #9
0
/*
** 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;
}
Example #10
0
/*
** Push a new margin onto the given margin stack.
**
** If the "bottom" parameter is non-negative, then this margin will
** automatically expire for all text that is placed below the y-coordinate
** given by "bottom".  This feature is used for <IMG ALIGN=left>
** and <IMG ALIGN=right> kinds of markup.  It allows text to flow around
** an image.
**
** If "bottom" is negative, then the margin stays in force until
** it is explicitly canceled by a call to HtmlPopMargin().
*/
void HtmlPushMargin(
  HtmlMargin **ppMargin,  /* The margin stack onto which to push */
  int indent,             /* The indentation for the new margin */
  int bottom,             /* The margin expires at this Y coordinate */
  int tag                 /* Markup that will cancel this margin */
){
  HtmlMargin *pNew = HtmlAlloc( sizeof(HtmlMargin) );
  pNew->pNext = *ppMargin;
  if( pNew->pNext ){
    pNew->indent = indent + pNew->pNext->indent;
    TestPoint(0);
  }else{
    pNew->indent = indent;
    TestPoint(0);
  }
  pNew->bottom = bottom;
  pNew->tag = tag;
  *ppMargin = pNew;
}
Example #11
0
/*
** This is a convenient wrapper routine for HtmlCallResolver.
** It makes a copy of the result into memory obtained from HtmlAlloc()
** and invokes Tcl_ResetResult().
*/
char *HtmlResolveUri(HtmlWidget *htmlPtr, char *zUri){
  char *azSeq[2];
  char *zSrc;
  int result;

  if( zUri==0 || *zUri==0 ) return 0;
  azSeq[0] = zUri;
  azSeq[1] = 0;
  HtmlLock(htmlPtr);
  result = HtmlCallResolver(htmlPtr, azSeq);
  if( HtmlUnlock(htmlPtr) ) return 0;
  if( result==TCL_OK ){
    zSrc = HtmlAlloc( strlen(htmlPtr->interp->result) + 1 );
    if( zSrc ) strcpy(zSrc, htmlPtr->interp->result);
  }else{
    zSrc = 0;
  }
  Tcl_ResetResult(htmlPtr->interp);
  return zSrc;
}
Example #12
0
/*
** Append text to the tokenizer engine.
**
** This routine (actually the Tokenize() subroutine that is called
** by this routine) may invoke a callback procedure which could delete
** the HTML widget. 
*/
void HtmlTokenizerAppend(HtmlWidget *htmlPtr, const char *zText){
  int len = strlen(zText);
  if( htmlPtr->nText==0 ){
    htmlPtr->nAlloc = len + 100;
    htmlPtr->zText = HtmlAlloc( htmlPtr->nAlloc );
    TestPoint(0);
  }else if( htmlPtr->nText + len >= htmlPtr->nAlloc ){
    htmlPtr->nAlloc += len + 100;
    htmlPtr->zText = HtmlRealloc( htmlPtr->zText, htmlPtr->nAlloc );
    TestPoint(0);
  }
  if( htmlPtr->zText==0 ){
    htmlPtr->nText = 0;
    UNTESTED;
    return;
  }
  strcpy(&htmlPtr->zText[htmlPtr->nText], zText);
  htmlPtr->nText += len;
  htmlPtr->nComplete = Tokenize(htmlPtr);
}
Example #13
0
/*
 *---------------------------------------------------------------------------
 *
 * allocCaseInsensitiveEntry --
 *
 *     Allocate enough space for a Tcl_HashEntry and associated string key.
 *
 * Results:
 *     None.
 *
 * Side effects:
 *     None.
 *
 *---------------------------------------------------------------------------
 */
static Tcl_HashEntry * 
allocCaseInsensitiveEntry(
    Tcl_HashTable *tablePtr,    /* Hash table. */
    VOID *keyPtr                /* Key to store in the hash table entry. */
    )
{
    const char *string = (CONST char *) keyPtr;
    char *pCsr;
    Tcl_HashEntry *hPtr;
    unsigned int size;

    size = sizeof(Tcl_HashEntry) + strlen(string) + 1 - sizeof(hPtr->key);
    if (size < sizeof(Tcl_HashEntry)) {
        size = sizeof(Tcl_HashEntry);
    }
    hPtr = (Tcl_HashEntry *) HtmlAlloc("allocCaseInsensitiveEntry()", size);
    strcpy(hPtr->key.string, string);

    for (pCsr = hPtr->key.string; *pCsr; pCsr++) {
        if( *pCsr > 0 ) *pCsr = tolower(*pCsr);
    }

    return hPtr;
}
Example #14
0
/*
 *---------------------------------------------------------------------------
 *
 * allocValuesEntry --
 *
 *     Allocate enough space for a Tcl_HashEntry and an HtmlComputedValues 
 *     key.
 *
 * Results:
 *     Pointer to allocated TclHashEntry structure.
 *
 * Side effects:
 *     None.
 *
 *---------------------------------------------------------------------------
 */
static Tcl_HashEntry * 
allocValuesEntry(
    Tcl_HashTable *tablePtr,    /* Hash table. */
    VOID *keyPtr                /* Key to store in the hash table entry. */
    )
{
    HtmlComputedValues *pKey = (HtmlComputedValues *)keyPtr;
    HtmlComputedValues *pStoredKey;
    unsigned int size;
    Tcl_HashEntry *hPtr;

    size = (
        sizeof(HtmlComputedValues) +
        sizeof(Tcl_HashEntry) - 
        sizeof(hPtr->key)
    );
    assert(size >= sizeof(Tcl_HashEntry));

    hPtr = (Tcl_HashEntry *) HtmlAlloc("allocValuesEntry()", size);
    pStoredKey = (HtmlComputedValues *)(hPtr->key.string);
    memcpy(pStoredKey, pKey, sizeof(HtmlComputedValues));

    return hPtr;
}
Example #15
0
/*
** 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;
}
Example #16
0
/*
** 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;
}
Example #17
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;
}
Example #18
0
/*
** Recompute the following fields of the given block structure:
**
**    base.count         The number of elements described by this
**                       block structure.
**
**    n                  The number of characters of text output
**                       associated with this block.  If the block
**                       renders something other than text (ex: <IMG>)
**                       then set n to 0.
**
**    z                  Pointer to malloced memory containing the
**                       text associated with this block.  NULL if
**                       n is 0.
**
** Return a pointer to the first HtmlElement not covered by the
** block.
*/
static HtmlElement *FillOutBlock(HtmlWidget *htmlPtr, HtmlBlock *p){
  HtmlElement *pElem;
  int go;
  int n;
  int x, y;
  int i;
  HtmlStyle style;
  int firstSelected;      /* First selected character in this block */
  int lastSelected;       /* Last selected character in this block */
  char zBuf[400];

  /*
  ** Reset n and z
  */
  if( p->n ){
    p->n = 0;
  }
  if( p->z ){
    HtmlFree(p->z);
  }
  firstSelected = 1000000;
  lastSelected = -1;

  /*
  ** Skip over HtmlElements that aren't directly displayed.
  */
  pElem = p->base.pNext;
  p->base.count = 0;
  while( pElem && (pElem->base.flags & HTML_Visible)==0 ){
    HtmlElement *pNext = pElem->pNext;
    if( pElem->base.type==Html_Block ){
      UnlinkAndFreeBlock(htmlPtr, &pElem->block);
      TestPoint(0);
    }else{
      p->base.count++;
      TestPoint(0);
    }
    pElem = pNext;
  }
  if( pElem==0 ){ TestPoint(0); return 0; }

  /*
  ** Handle "special" elements.
  */
  if( pElem->base.type!=Html_Text ){
    switch( pElem->base.type ){
      case Html_HR:
        p->top = pElem->hr.y - pElem->hr.h;
        p->bottom = pElem->hr.y;
        p->left = pElem->hr.x;
        p->right = pElem->hr.x + pElem->hr.w;
        TestPoint(0);
        break;
      case Html_LI:
        p->top = pElem->li.y - pElem->li.ascent;
        p->bottom = pElem->li.y + pElem->li.descent;
        p->left = pElem->li.x - 10;
        p->right = pElem->li.x + 10;
        TestPoint(0);
        break;
      case Html_TD:
      case Html_TH:
        p->top = pElem->cell.y;
        p->bottom = pElem->cell.y + pElem->cell.h;
        p->left = pElem->cell.x;
        p->right = pElem->cell.x + pElem->cell.w;
        TestPoint(0);
        break;
      case Html_TABLE:
        p->top = pElem->table.y;
        p->bottom = pElem->table.y + pElem->table.h;
        p->left = pElem->table.x;
        p->right = pElem->table.x + pElem->table.w;
        TestPoint(0);
        break;
      case Html_IMG:
        p->top = pElem->image.y - pElem->image.ascent;
        p->bottom = pElem->image.y + pElem->image.descent;
        p->left = pElem->image.x;
        p->right = pElem->image.x + pElem->image.w;
        TestPoint(0);
        break;
    }
    p->base.count++;
    TestPoint(0);
    return pElem->pNext;
  }

  /*
  ** If we get this far, we must be dealing with text.
  */
  n = 0;
  x = pElem->text.x;
  y = pElem->text.y;
  p->top = y - pElem->text.ascent;
  p->bottom = y + pElem->text.descent;
  p->left = x;
  style = pElem->base.style;
  go = 1;
  while( pElem ){
    HtmlElement *pNext = pElem->pNext;
    switch( pElem->base.type ){
      case Html_Text:
        if( pElem->base.style.flags & STY_Invisible ){
          TestPoint(0);
          break;
        }
        if( pElem->text.spaceWidth <=0 ){
          CANT_HAPPEN;
          break;
        }
        if( y != pElem->text.y 
        ||  style.font != pElem->base.style.font
        ||  style.color != pElem->base.style.color
        ||  (style.flags & STY_FontMask) 
              != (pElem->base.style.flags & STY_FontMask)
        ){
          go = 0;
          TestPoint(0);
        }else{
          int sw = pElem->text.spaceWidth;
          int nSpace = (pElem->text.x - x) / sw;
          if( nSpace * sw + x != pElem->text.x ){
            go = 0;
            TestPoint(0);
          }else if( n + nSpace + pElem->base.count >= sizeof(zBuf) ){
            go = 0;
            TestPoint(0);
          }else{
            for(i=0; i<nSpace; i++){
              zBuf[n++] = ' ';
              TestPoint(0);
            }
            strcpy(&zBuf[n], pElem->text.zText);
            n += pElem->base.count;
            x = pElem->text.x + pElem->text.w;
          }
        }
        break;

      case Html_Space:
        if( pElem->base.style.font != style.font ){
          pElem = pElem->pNext;
          go = 0;
        }else if( (style.flags & STY_Preformatted)!=0 
                  && (pElem->base.flags & HTML_NewLine)!=0 ){
          pElem = pElem->pNext;
          go = 0;
        }
        break;

      case Html_Block:
        UnlinkAndFreeBlock(htmlPtr,&pElem->block);
        break;

      case Html_A:
      case Html_EndA:
        go = 0;
        break;

      default:
        if( pElem->base.flags & HTML_Visible ) go = 0;
        TestPoint(0);
        break;
    }
    if( go==0 ) break;
    p->base.count++;
    pElem = pNext;
  }
  p->right = x;

  while( n>0 && zBuf[n-1]==' ' ){ TestPoint(0); n--; }
  p->z = HtmlAlloc( n );
  strncpy(p->z, zBuf, n);
  p->n = n;
  return pElem;
}
Example #19
0
/*
 *---------------------------------------------------------------------------
 *
 * 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);
}
Example #20
0
/* 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;
}
Example #21
0
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;
}
Example #22
0
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;
}