/*
** 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
#include
#include
#include "htmldraw.h"
/*
#ifdef USE_TK_STUBS
# include
#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= 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->selEndIndexn ){
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; idisplay, 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 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: )
** 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; itext.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);
}
}
}