diff options
Diffstat (limited to 'src/htmldraw.c')
-rw-r--r-- | src/htmldraw.c | 877 |
1 files changed, 877 insertions, 0 deletions
diff --git a/src/htmldraw.c b/src/htmldraw.c new file mode 100644 index 0000000..42f2f80 --- /dev/null +++ b/src/htmldraw.c @@ -0,0 +1,877 @@ +/* +** Routines used to render HTML onto the screen for the Tk HTML widget. +** +** Copyright (C) 1997-2000 D. Richard Hipp +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. +** +** You should have received a copy of the GNU Library General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +** +** Author contact information: +** drh@acm.org +** http://www.hwaci.com/drh/ +*/ +#include <tk.h> +#include <string.h> +#include <stdlib.h> +#include "htmldraw.h" +/* +#ifdef USE_TK_STUBS +# include <tkIntXlibDecls.h> +#endif +*/ +#define USE_TK_DRAWCHARS 1 + +/* +** Allocate a new HtmlBlock structure. +*/ +static HtmlBlock *AllocBlock(void){ + HtmlBlock *pNew; + + pNew = HtmlAlloc( sizeof(HtmlBlock) ); + if( pNew ){ + memset(pNew, 0, sizeof(*pNew)); + pNew->base.type = Html_Block; + } + return pNew; +} + +/* +** Free an HtmlBlock structure. Assume that it is already unlinked +** from the element list and the block list. +*/ +static void FreeBlock(HtmlBlock *pBlock){ + if( pBlock ){ + if( pBlock->z ){ + HtmlFree(pBlock->z); + } + HtmlFree(pBlock); + } +} + +/* +** Destroy the given Block after first unlinking it from the +** element list. Note that this unlinks the block from the +** element list only -- not from the block list. +*/ +static void UnlinkAndFreeBlock(HtmlWidget *htmlPtr, HtmlBlock *pBlock){ + if( pBlock->base.pNext ){ + pBlock->base.pNext->base.pPrev = pBlock->base.pPrev; + TestPoint(0); + }else{ + htmlPtr->pLast = pBlock->base.pPrev; + TestPoint(0); + } + if( pBlock->base.pPrev ){ + pBlock->base.pPrev->base.pNext = pBlock->base.pNext; + TestPoint(0); + }else{ + htmlPtr->pFirst = pBlock->base.pNext; + TestPoint(0); + } + pBlock->base.pPrev = pBlock->base.pNext = 0; + FreeBlock(pBlock); +} + +/* +** Append a block to the block list and insert the block into the +** element list immediately prior to the element given. +*/ +static void AppendBlock( + HtmlWidget *htmlPtr, /* The HTML widget */ + HtmlElement *pToken, /* The token that comes after pBlock */ + HtmlBlock *pBlock /* The block to be appended */ +){ + pBlock->base.pPrev = pToken->base.pPrev; + pBlock->base.pNext = pToken; + pBlock->pPrev = htmlPtr->lastBlock; + pBlock->pNext = 0; + if( htmlPtr->lastBlock ){ + htmlPtr->lastBlock->pNext = pBlock; + TestPoint(0); + }else{ + htmlPtr->firstBlock = pBlock; + TestPoint(0); + } + htmlPtr->lastBlock = pBlock; + if( pToken->base.pPrev ){ + pToken->base.pPrev->base.pNext = (HtmlElement*)pBlock; + TestPoint(0); + }else{ + htmlPtr->pFirst = (HtmlElement*)pBlock; + TestPoint(0); + } + pToken->base.pPrev = (HtmlElement*)pBlock; +} + +/* +** Print an ordered list index into the given buffer. Use numbering +** like this: +** +** A B C ... Y Z AA BB CC ... ZZ +** +** Revert to decimal for indices greater than 52. +*/ +static void GetLetterIndex(char *zBuf, int index, int isUpper){ + int seed; + if( index<1 || index>52 ){ + sprintf(zBuf,"%d",index); + TestPoint(0); + return; + } + if( isUpper ){ + seed = 'A'; + TestPoint(0); + }else{ + seed = 'a'; + TestPoint(0); + } + index--; + if( index<26 ){ + zBuf[0] = seed + index; + zBuf[1] = 0; + TestPoint(0); + }else{ + index -= 26; + zBuf[0] = seed + index; + zBuf[1] = seed + index; + zBuf[2] = 0; + TestPoint(0); + } + strcat(zBuf,"."); +} + +/* +** Print an ordered list index into the given buffer. Use roman +** numerals. For indices greater than a few thousand, revert to +** decimal. +*/ +static void GetRomanIndex(char *zBuf, int index, int isUpper){ + int i = 0; + int j; + static struct { + int value; + char *name; + } values[] = { + { 1000, "m" }, + { 999, "im" }, + { 990, "xm" }, + { 900, "cm" }, + { 500, "d" }, + { 499, "id" }, + { 490, "xd" }, + { 400, "cd" }, + { 100, "c" }, + { 99, "ic" }, + { 90, "xc" }, + { 50, "l" }, + { 49, "il" }, + { 40, "xl" }, + { 10, "x" }, + { 9, "ix" }, + { 5, "v" }, + { 4, "iv" }, + { 1, "i" }, + }; + if( index<1 || index>=5000 ){ + sprintf(zBuf,"%d",index); + TestPoint(0); + return; + } + for(j=0; index>0 && j<sizeof(values)/sizeof(values[0]); j++){ + int k; + while( index >= values[j].value ){ + for(k=0; values[j].name[k]; k++){ + zBuf[i++] = values[j].name[k]; + TestPoint(0); + } + index -= values[j].value; + TestPoint(0); + } + } + zBuf[i] = 0; + if( isUpper ){ + for(i=0; zBuf[i]; i++){ + zBuf[i] += 'A' - 'a'; + TestPoint(0); + } + }else{ + TestPoint(0); + } + strcat(zBuf,"."); +} + +/* Draw the selection background for the given block +*/ +static void DrawSelectionBackground( + HtmlWidget *htmlPtr, /* The HTML widget */ + HtmlBlock *pBlock, /* The block whose background is drawn */ + Drawable drawable, /* Draw the background on this drawable */ + int x, int y /* Virtual coords of top-left of drawable */ +){ + int xLeft, xRight; /* Left and right bounds of box to draw */ + int yTop, yBottom; /* Top and bottom of box */ + HtmlElement *p = 0; /* First element of the block */ + Tk_Font font; /* Font */ + GC gc; /* GC for drawing */ + XRectangle xrec; /* Size of a filled rectangle to be drawn */ + + if( pBlock==0 || (pBlock->base.flags & HTML_Selected)==0 ){ + TestPoint(0); + return; + } + xLeft = pBlock->left - x; + if( pBlock==htmlPtr->pSelStartBlock && htmlPtr->selStartIndex>0 ){ + if( htmlPtr->selStartIndex >= pBlock->n ){ TestPoint(0); return; } + p = pBlock->base.pNext; + font = HtmlGetFont(htmlPtr, p->base.style.font); + if( font==0 ) return; + if( p->base.type==Html_Text ){ + xLeft = p->text.x - x + Tk_TextWidth(font, pBlock->z, + htmlPtr->selStartIndex); + } + } + xRight = pBlock->right - x; + if( pBlock==htmlPtr->pSelEndBlock && htmlPtr->selEndIndex<pBlock->n ){ + if( p==0 ){ + p = pBlock->base.pNext; + font = HtmlGetFont(htmlPtr, p->base.style.font); + if( font==0 ) return; + } + if( p->base.type==Html_Text ){ + xRight = p->text.x - x + Tk_TextWidth(font, pBlock->z, + htmlPtr->selEndIndex); + } + } + yTop = pBlock->top - y; + yBottom = pBlock->bottom - y; + gc = HtmlGetGC(htmlPtr, COLOR_Selection, FONT_Any); + xrec.x = xLeft; + xrec.y = yTop; + xrec.width = xRight - xLeft; + xrec.height = yBottom - yTop; + XFillRectangles(htmlPtr->display, drawable, gc, &xrec, 1); +} + +/* +** Draw a rectangle. The rectangle will have a 3-D appearance if +** flat==0 and a flat appearance if flat==1. +** +** We don't use Tk_Draw3DRectangle() because it doesn't work well +** when the background color is close to pure white or pure black. +*/ +static void HtmlDrawRect( + HtmlWidget *htmlPtr, /* The HTML widget */ + Drawable drawable, /* Draw it here */ + HtmlElement *src, /* Element associated with drawing */ + int x, int y, int w, int h, /* Coordinates of the rectangle */ + int depth, /* Width of the relief, or the flat line */ + int relief /* The relief. TK_RELIEF_FLAT omits 3d */ +){ + if( depth>0 ){ + int i; + GC gcLight, gcDark; + XRectangle xrec[1]; + if( relief!=TK_RELIEF_FLAT ){ + int iLight, iDark; + iLight = HtmlGetLightShadowColor(htmlPtr, src->base.style.bgcolor); + gcLight = HtmlGetGC(htmlPtr, iLight, FONT_Any); + iDark = HtmlGetDarkShadowColor(htmlPtr, src->base.style.bgcolor); + gcDark = HtmlGetGC(htmlPtr, iDark, FONT_Any); + if( relief==TK_RELIEF_SUNKEN ){ + GC gcTemp = gcLight; + gcLight = gcDark; + gcDark = gcTemp; + } + }else{ + gcLight = HtmlGetGC(htmlPtr, src->base.style.color, FONT_Any); + gcDark = gcLight; + } + xrec[0].x = x; + xrec[0].y = y; + xrec[0].width = depth; + xrec[0].height = h; + XFillRectangles(htmlPtr->display, drawable, gcLight, xrec, 1); + xrec[0].x = x+w-depth; + XFillRectangles(htmlPtr->display, drawable, gcDark, xrec, 1); + for(i=0; i<depth && i<h/2; i++){ + XDrawLine(htmlPtr->display, drawable, gcLight, x+i, y+i, x+w-i-1, y+i); + XDrawLine(htmlPtr->display, drawable, gcDark, x+i, y+h-i-1, + x+w-i-1, y+h-i-1); + } + } + if( h>depth*2 && w>depth*2 ){ + GC gcBg; + XRectangle xrec[1]; + gcBg = HtmlGetGC(htmlPtr, src->base.style.bgcolor, FONT_Any); + xrec[0].x = x + depth; + xrec[0].y = y + depth; + xrec[0].width = w - depth*2; + xrec[0].height = h - depth*2; + XFillRectangles(htmlPtr->display, drawable, gcBg, xrec, 1); + } +} + +/* +** Display a single HtmlBlock. This is where all the drawing +** happens. +*/ +void HtmlBlockDraw( + HtmlWidget *htmlPtr, /* The main HTML widget */ + HtmlBlock *pBlock, /* Block which needs to be drawn */ + Drawable drawable, /* Draw the line on this */ + int drawableLeft, /* Virtual coordinate of left edge of drawable */ + int drawableTop, /* Virtual coordinate of top edge of drawable */ + int drawableWidth, /* Width of the drawable */ + int drawableHeight /* Height of the drawable */ +){ + Tk_Font font; /* Font to use to render text */ + GC gc; /* A graphics context */ + HtmlElement *src; /* HtmlElement holding style information */ + HtmlElement *pTable; /* The table (when drawing part of a table) */ + int x, y; /* Where to draw */ + + if( pBlock==0 ){ TestPoint(0); return; } + src = pBlock->base.pNext; + while( src && (src->base.flags & HTML_Visible)==0 ){ + src = src->base.pNext; + TestPoint(0); + } + if( src==0 ){ TestPoint(0); return; } + if( pBlock->n>0 ){ + /* We must be dealing with plain old text */ + if( src->base.type==Html_Text ){ + x = src->text.x; + y = src->text.y; + TestPoint(0); + }else{ + CANT_HAPPEN; + return; + } + if( pBlock->base.flags & HTML_Selected ){ + HtmlLock(htmlPtr); + DrawSelectionBackground(htmlPtr, pBlock, drawable, + drawableLeft, drawableTop); + if( HtmlUnlock(htmlPtr) ) return; + } + gc = HtmlGetGC(htmlPtr, src->base.style.color, src->base.style.font); + font = HtmlGetFont(htmlPtr, src->base.style.font); + if( font==0 ) return; + Tk_DrawChars(htmlPtr->display, + drawable, + gc, font, + pBlock->z, pBlock->n, + x - drawableLeft, y - drawableTop); + if( src->base.style.flags & STY_Underline ){ + Tk_UnderlineChars(htmlPtr->display, drawable, gc, font, pBlock->z, + x - drawableLeft, y-drawableTop, 0, pBlock->n); + } + if( src->base.style.flags & STY_StrikeThru ){ + XRectangle xrec; + xrec.x = pBlock->left - drawableLeft; + xrec.y = (pBlock->top + pBlock->bottom)/2 - drawableTop; + xrec.width = pBlock->right - pBlock->left; + xrec.height = 1 + (pBlock->bottom - pBlock->top > 15); + XFillRectangles(htmlPtr->display, drawable, gc, &xrec, 1); + } + if( pBlock==htmlPtr->pInsBlock && htmlPtr->insStatus>0 ){ + int x; + XRectangle xrec; + if( htmlPtr->insIndex < pBlock->n ){ + x = src->text.x - drawableLeft; + x += Tk_TextWidth(font, pBlock->z, htmlPtr->insIndex); + }else{ + x = pBlock->right - drawableLeft; + } + if( x>0 ){ TestPoint(0); x--; } + xrec.x = x; + xrec.y = pBlock->top - drawableTop; + xrec.width = 2; + xrec.height = pBlock->bottom - pBlock->top; + XFillRectangles(htmlPtr->display, drawable, gc, &xrec, 1); + } + }else{ + /* We are dealing with a single HtmlElement which contains something + ** other than plain text. */ + int top=0; + int btm=0; + int cntr; + int cnt, w; + char zBuf[30]; + switch( src->base.type ){ + case Html_LI: + x = src->li.x; + y = src->li.y; + cntr = (top+btm)/2; + switch( src->li.type ){ + case LI_TYPE_Enum_1: + sprintf(zBuf,"%d.",src->li.cnt); + TestPoint(0); + break; + case LI_TYPE_Enum_A: + GetLetterIndex(zBuf,src->li.cnt,1); + TestPoint(0); + break; + case LI_TYPE_Enum_a: + GetLetterIndex(zBuf,src->li.cnt,0); + TestPoint(0); + break; + case LI_TYPE_Enum_I: + GetRomanIndex(zBuf,src->li.cnt,1); + TestPoint(0); + break; + case LI_TYPE_Enum_i: + GetRomanIndex(zBuf,src->li.cnt,0); + TestPoint(0); + break; + default: + zBuf[0] = 0; + TestPoint(0); + break; + } + gc = HtmlGetGC(htmlPtr, src->base.style.color, src->base.style.font); + switch( src->li.type ){ + case LI_TYPE_Undefined: + case LI_TYPE_Bullet1: + XFillArc(htmlPtr->display, + drawable, + gc, + x - 7 - drawableLeft, y - 8 - drawableTop, 7, 7, + 0, 360*64); + TestPoint(0); + break; + + case LI_TYPE_Bullet2: + XDrawArc(htmlPtr->display, + drawable, + gc, + x - 7 - drawableLeft, y - 8 - drawableTop, 7, 7, + 0, 360*64); + TestPoint(0); + break; + + case LI_TYPE_Bullet3: + XDrawRectangle(htmlPtr->display, + drawable, + gc, + x - 7 - drawableLeft, y - 8 - drawableTop, 7, 7); + TestPoint(0); + break; + + case LI_TYPE_Enum_1: + case LI_TYPE_Enum_A: + case LI_TYPE_Enum_a: + case LI_TYPE_Enum_I: + case LI_TYPE_Enum_i: + cnt = strlen(zBuf); + font = HtmlGetFont(htmlPtr, src->base.style.font); + if( font==0 ) return; + w = Tk_TextWidth(font, zBuf, cnt); + Tk_DrawChars(htmlPtr->display, + drawable, + gc, font, + zBuf, cnt, + x - w - drawableLeft, y - drawableTop); + TestPoint(0); + break; + } + break; + case Html_HR: { + int relief = htmlPtr->ruleRelief; + switch( relief ){ + case TK_RELIEF_RAISED: + case TK_RELIEF_SUNKEN: + break; + default: + relief = TK_RELIEF_FLAT; + break; + } + HtmlDrawRect(htmlPtr, drawable, src, + src->hr.x - drawableLeft, + src->hr.y - drawableTop, + src->hr.w, + src->hr.h, + 1, relief); + break; + } + case Html_TABLE: { + int relief = htmlPtr->tableRelief; + switch( relief ){ + case TK_RELIEF_RAISED: + case TK_RELIEF_SUNKEN: + break; + default: + relief = TK_RELIEF_FLAT; + break; + } + HtmlDrawRect(htmlPtr, drawable, src, + src->table.x - drawableLeft, + src->table.y - drawableTop, + src->table.w, + src->table.h, + src->table.borderWidth, + relief); + break; + } + case Html_TH: + case Html_TD: { + int depth, relief; + pTable = src->cell.pTable; + depth = pTable && pTable->table.borderWidth>0; + switch( htmlPtr->tableRelief ){ + case TK_RELIEF_RAISED: relief = TK_RELIEF_SUNKEN; break; + case TK_RELIEF_SUNKEN: relief = TK_RELIEF_RAISED; break; + default: relief = TK_RELIEF_FLAT; break; + } + HtmlDrawRect(htmlPtr, drawable, src, + src->cell.x - drawableLeft, + src->cell.y - drawableTop, + src->cell.w, + src->cell.h, + depth, + relief); + break; + } + case Html_IMG: + if( src->image.pImage ){ + HtmlDrawImage(src, drawable, drawableLeft, drawableTop, + drawableLeft + drawableWidth, + drawableTop + drawableHeight); + }else if( src->image.zAlt ){ + gc = HtmlGetGC(htmlPtr, src->base.style.color, src->base.style.font); + font = HtmlGetFont(htmlPtr, src->base.style.font); + if( font==0 ) return; + Tk_DrawChars(htmlPtr->display, + drawable, + gc, font, + src->image.zAlt, strlen(src->image.zAlt), + src->image.x - drawableLeft, + src->image.y - drawableTop); + TestPoint(0); + } + break; + default: + TestPoint(0); + break; + } + } +} + +/* +** Draw all or part of an image. +*/ +void HtmlDrawImage( + HtmlElement *pElem, /* The <IMG> to be drawn */ + Drawable drawable, /* Draw it here */ + int drawableLeft, /* left edge of the drawable */ + int drawableTop, /* Virtual canvas coordinate for top of drawable */ + int drawableRight, /* right edge of the drawable */ + int drawableBottom /* bottom edge of the drawable */ +){ + int imageTop; /* virtual canvas coordinate for top of image */ + int x, y; /* where to place image on the drawable */ + int imageX, imageY; /* \__ Subset of image that fits */ + int imageW, imageH; /* / on the drawable */ + + imageTop = pElem->image.y - pElem->image.ascent; + y = imageTop - drawableTop; + if( imageTop + pElem->image.h > drawableBottom ){ + imageH = drawableBottom - imageTop; + TestPoint(0); + }else{ + imageH = pElem->image.h; + TestPoint(0); + } + if( y<0 ){ + imageY = -y; + imageH += y; + y = 0; + TestPoint(0); + }else{ + imageY = 0; + TestPoint(0); + } + x = pElem->image.x - drawableLeft; + if( pElem->image.x + pElem->image.w > drawableRight ){ + imageW = drawableRight - pElem->image.x; + TestPoint(0); + }else{ + imageW = pElem->image.w; + TestPoint(0); + } + if( x<0 ){ + imageX = -x; + imageW += x; + x = 0; + TestPoint(0); + }else{ + imageX = 0; + TestPoint(0); + } + Tk_RedrawImage(pElem->image.pImage->image, imageX, imageY, imageW, imageH, + drawable, x, y); + pElem->image.redrawNeeded = 0; +} + +/* +** Recompute the following fields of the given block structure: +** +** base.count The number of elements described by this +** block structure. +** +** n The number of characters of text output +** associated with this block. If the block +** renders something other than text (ex: <IMG>) +** then set n to 0. +** +** z Pointer to malloced memory containing the +** text associated with this block. NULL if +** n is 0. +** +** Return a pointer to the first HtmlElement not covered by the +** block. +*/ +static HtmlElement *FillOutBlock(HtmlWidget *htmlPtr, HtmlBlock *p){ + HtmlElement *pElem; + int go; + int n; + int x, y; + int i; + HtmlStyle style; + int firstSelected; /* First selected character in this block */ + int lastSelected; /* Last selected character in this block */ + char zBuf[400]; + + /* + ** Reset n and z + */ + if( p->n ){ + p->n = 0; + } + if( p->z ){ + HtmlFree(p->z); + } + firstSelected = 1000000; + lastSelected = -1; + + /* + ** Skip over HtmlElements that aren't directly displayed. + */ + pElem = p->base.pNext; + p->base.count = 0; + while( pElem && (pElem->base.flags & HTML_Visible)==0 ){ + HtmlElement *pNext = pElem->pNext; + if( pElem->base.type==Html_Block ){ + UnlinkAndFreeBlock(htmlPtr, &pElem->block); + TestPoint(0); + }else{ + p->base.count++; + TestPoint(0); + } + pElem = pNext; + } + if( pElem==0 ){ TestPoint(0); return 0; } + + /* + ** Handle "special" elements. + */ + if( pElem->base.type!=Html_Text ){ + switch( pElem->base.type ){ + case Html_HR: + p->top = pElem->hr.y - pElem->hr.h; + p->bottom = pElem->hr.y; + p->left = pElem->hr.x; + p->right = pElem->hr.x + pElem->hr.w; + TestPoint(0); + break; + case Html_LI: + p->top = pElem->li.y - pElem->li.ascent; + p->bottom = pElem->li.y + pElem->li.descent; + p->left = pElem->li.x - 10; + p->right = pElem->li.x + 10; + TestPoint(0); + break; + case Html_TD: + case Html_TH: + p->top = pElem->cell.y; + p->bottom = pElem->cell.y + pElem->cell.h; + p->left = pElem->cell.x; + p->right = pElem->cell.x + pElem->cell.w; + TestPoint(0); + break; + case Html_TABLE: + p->top = pElem->table.y; + p->bottom = pElem->table.y + pElem->table.h; + p->left = pElem->table.x; + p->right = pElem->table.x + pElem->table.w; + TestPoint(0); + break; + case Html_IMG: + p->top = pElem->image.y - pElem->image.ascent; + p->bottom = pElem->image.y + pElem->image.descent; + p->left = pElem->image.x; + p->right = pElem->image.x + pElem->image.w; + TestPoint(0); + break; + } + p->base.count++; + TestPoint(0); + return pElem->pNext; + } + + /* + ** If we get this far, we must be dealing with text. + */ + n = 0; + x = pElem->text.x; + y = pElem->text.y; + p->top = y - pElem->text.ascent; + p->bottom = y + pElem->text.descent; + p->left = x; + style = pElem->base.style; + go = 1; + while( pElem ){ + HtmlElement *pNext = pElem->pNext; + switch( pElem->base.type ){ + case Html_Text: + if( pElem->base.style.flags & STY_Invisible ){ + TestPoint(0); + break; + } + if( pElem->text.spaceWidth <=0 ){ + CANT_HAPPEN; + break; + } + if( y != pElem->text.y + || style.font != pElem->base.style.font + || style.color != pElem->base.style.color + || (style.flags & STY_FontMask) + != (pElem->base.style.flags & STY_FontMask) + ){ + go = 0; + TestPoint(0); + }else{ + int sw = pElem->text.spaceWidth; + int nSpace = (pElem->text.x - x) / sw; + if( nSpace * sw + x != pElem->text.x ){ + go = 0; + TestPoint(0); + }else if( n + nSpace + pElem->base.count >= sizeof(zBuf) ){ + go = 0; + TestPoint(0); + }else{ + for(i=0; i<nSpace; i++){ + zBuf[n++] = ' '; + TestPoint(0); + } + strcpy(&zBuf[n], pElem->text.zText); + n += pElem->base.count; + x = pElem->text.x + pElem->text.w; + } + } + break; + + case Html_Space: + if( pElem->base.style.font != style.font ){ + pElem = pElem->pNext; + go = 0; + }else if( (style.flags & STY_Preformatted)!=0 + && (pElem->base.flags & HTML_NewLine)!=0 ){ + pElem = pElem->pNext; + go = 0; + } + break; + + case Html_Block: + UnlinkAndFreeBlock(htmlPtr,&pElem->block); + break; + + case Html_A: + case Html_EndA: + go = 0; + break; + + default: + if( pElem->base.flags & HTML_Visible ) go = 0; + TestPoint(0); + break; + } + if( go==0 ) break; + p->base.count++; + pElem = pNext; + } + p->right = x; + + while( n>0 && zBuf[n-1]==' ' ){ TestPoint(0); n--; } + p->z = HtmlAlloc( n ); + strncpy(p->z, zBuf, n); + p->n = n; + return pElem; +} + +/* +** Scan ahead looking for a place to put a block. Return a pointer +** to the element which should come immediately after the block. +** +** if pCnt!=0, then put the number of elements skipped in *pCnt. +*/ +static HtmlElement *FindStartOfNextBlock( + HtmlWidget *htmlPtr, /* The HTML widget */ + HtmlElement *p, /* First candid for the start of a block */ + int *pCnt /* Write number of elements skipped here */ +){ + int cnt = 0; + + while( p && (p->base.flags & HTML_Visible)==0 ){ + HtmlElement *pNext = p->pNext; + if( p->base.type==Html_Block ){ + UnlinkAndFreeBlock(htmlPtr, &p->block); + }else{ + cnt++; + } + p = pNext; + } + if( pCnt ){ *pCnt = cnt; } + return p; +} + + +/* +** Add additional blocks to the block list in order to cover +** all elements on the element list. +** +** If any old blocks are found on the element list, they must +** be left over from a prior rendering. Unlink and delete them. +*/ +void HtmlFormBlocks(HtmlWidget *htmlPtr){ + HtmlElement *pElem; + + if( htmlPtr->lastBlock ){ + pElem = FillOutBlock(htmlPtr, htmlPtr->lastBlock); + }else{ + pElem = htmlPtr->pFirst; + } + while( pElem ){ + int cnt; + pElem = FindStartOfNextBlock(htmlPtr, pElem, &cnt); + if( pElem ){ + HtmlBlock *pNew = AllocBlock(); + if( htmlPtr->lastBlock ){ + htmlPtr->lastBlock->base.count += cnt; + } + AppendBlock(htmlPtr, pElem, pNew); + pElem = FillOutBlock(htmlPtr, pNew); + } + } +} |