void HtmlPrintList(HtmlElement *p, HtmlElement *pEnd){ while( p && p!=pEnd ){ if( p->base.type==Html_Block ){ char *z = p->block.z; int n = p->block.n; if( n==0 || z==0 ){ n = 1; z = ""; } printf("Block 0x%08x flags=%02x cnt=%d x=%d..%d y=%d..%d z=\"%.*s\"\n", (int)p, p->base.flags, p->base.count, p->block.left, p->block.right, p->block.top, p->block.bottom, n, z); }else{ printf("Token 0x%08x font=%2d color=%2d align=%d flags=0x%04x name=%s\n", (int)p, p->base.style.font, p->base.style.color, p->base.style.align, p->base.style.flags, HtmlTokenName(p)); } p = p->pNext; } }
/* ** 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; }
/* ** This routine gathers as many tokens as will fit on one line. ** ** The candidate tokens begin with pStart and go thru the end of ** the list or to pEnd, whichever comes first. The first token ** at the start of the next line is returned. NULL is returned if ** we exhaust data. ** ** "width" is the maximum allowed width of the line. The actual ** width is returned in *actualWidth. The actual width does not ** include any trailing spaces. Sometimes the actual width will ** be greater than the maximum width. This will happen, for example, ** for text enclosed in <pre>..</pre> that has lines longer than ** the width of the page. ** ** If the list begins with text, at least one token is returned, ** even if that one token is longer than the allowed line length. ** But if the list begins with some kind of break markup (possibly ** preceded by white space) then the returned list may be empty. ** ** The "x" coordinates of all elements are set assuming that the line ** begins at 0. The calling routine should adjust these coordinates ** to position the line horizontally. (The FixLine() procedure does ** this.) Note that the "x" coordinate of <li> elements will be negative. ** Text within <dt>..</dt> might also have a negative "x" coordinate. ** But in no case will the x coordinate every be less than "minX". */ static HtmlElement *GetLine( HtmlLayoutContext *pLC, /* The complete layout context. */ HtmlElement *pStart, /* First token on new line */ HtmlElement *pEnd, /* End of line. Might be NULL */ int width, /* How much space is on this line */ int minX, /* The minimum value of the X coordinate */ int *actualWidth /* Return space actually required */ ){ int x; /* Current X coordinate */ int spaceWanted = 0; /* Add this much space before next token */ HtmlElement *p; /* For looping over tokens */ HtmlElement *lastBreak = 0; /* Last line-break opportunity */ int isEmpty = 1; /* True if link contains nothing */ int origin; /* Initial value of "x" */ *actualWidth = 0; p = pStart; while( p && p!=pEnd && (p->base.style.flags & STY_Invisible)!=0 ){ p = p->pNext; } if( p && p->base.style.flags & STY_DT ){ origin = -HTML_INDENT; }else{ origin = 0; } x = origin; if( x<minX ){ x = minX; } if( p && p!=pEnd && p->base.type==Html_LI ){ p->li.x = x - HTML_INDENT/3; if( p->li.x - (HTML_INDENT*2)/3<minX ){ x += minX - p->li.x + (HTML_INDENT*2)/3; p->li.x = minX + (HTML_INDENT*2)/3; } isEmpty = 0; *actualWidth = 1; p = p->pNext; while( p && (p->base.type==Html_Space || p->base.type==Html_P) ){ p = p->pNext; } } for(; p && p!=pEnd; p=p->pNext){ if( p->base.style.flags & STY_Invisible ){ continue; } switch( p->base.type ){ case Html_Text: p->text.x = x + spaceWanted; if( (p->base.style.flags & STY_Preformatted) == 0 ){ if( lastBreak && x + spaceWanted + p->text.w > width ){ TestPoint(0); return lastBreak; } } TRACE(HtmlTrace_GetLine2, ("Place token %s at x=%d w=%d\n", HtmlTokenName(p), p->text.x, p->text.w)); x += p->text.w + spaceWanted; isEmpty = 0; spaceWanted = 0; break; case Html_Space: if( p->base.style.flags & STY_Preformatted ){ if( p->base.flags & HTML_NewLine ){ *actualWidth = x<=0 ? 1 : x; TestPoint(0); return p->pNext; } x += p->space.w * p->base.count; TestPoint(0); }else{ int w; if( (p->base.style.flags & STY_NoBreak)==0 ){ lastBreak = p->pNext; *actualWidth = x<=0 && !isEmpty ? 1 : x; } w = p->space.w; if( spaceWanted < w && x>origin ){ spaceWanted = w; } } break; case Html_IMG: switch( p->image.align ){ case IMAGE_ALIGN_Left: case IMAGE_ALIGN_Right: *actualWidth = x<=0 && !isEmpty ? 1 : x; return p; default: break; } p->image.x = x + spaceWanted; if( (p->base.style.flags & STY_Preformatted) == 0 ){ if( lastBreak && x + spaceWanted + p->image.w > width ){ TestPoint(0); return lastBreak; } } TRACE(HtmlTrace_GetLine2, ("Place in-line image %s at x=%d w=%d\n", HtmlTokenName(p), p->image.x, p->image.w)); x += p->image.w + spaceWanted; if( (p->base.style.flags & STY_NoBreak)==0 ){ lastBreak = p->pNext; *actualWidth = x<=0 && !isEmpty ? 1 : x; } spaceWanted = 0; isEmpty = 0; break; case Html_APPLET: case Html_EMBED: case Html_INPUT: case Html_SELECT: case Html_TEXTAREA: p->input.x = x + spaceWanted + p->input.padLeft; if( (p->base.style.flags & STY_Preformatted) == 0 ){ if( lastBreak && x + spaceWanted + p->input.w > width ){ TestPoint(0); return lastBreak; } } TRACE(HtmlTrace_GetLine2, ("Place token %s at x=%d w=%d\n", HtmlTokenName(p), p->input.x, p->input.w)); x = p->input.x + p->input.w; if( (p->base.style.flags & STY_NoBreak)==0 ){ lastBreak = p->pNext; *actualWidth = x<=0 && !isEmpty ? 1 : x; } spaceWanted = 0; isEmpty = 0; break; case Html_EndTEXTAREA: if( p->ref.pOther ){ /* HtmlResetTextarea(pLC->htmlPtr, p->ref.pOther); */ } break; case Html_DD: if( p->ref.pOther==0 ) break; if( p->ref.pOther->list.compact==0 || x + spaceWanted >= 0 ){ *actualWidth = x<=0 && !isEmpty ? 1 : x; return p; } x = 0; spaceWanted = 0; break; case Html_WBR: *actualWidth = x<=0 && !isEmpty ? 1 : x; if( x + spaceWanted >= width ){ return p->pNext; }else{ lastBreak = p->pNext; } break; case Html_ADDRESS: case Html_EndADDRESS: case Html_BLOCKQUOTE: case Html_EndBLOCKQUOTE: case Html_BODY: case Html_EndBODY: case Html_BR: case Html_CAPTION: case Html_EndCAPTION: case Html_CENTER: case Html_EndCENTER: case Html_EndDD: case Html_DIV: case Html_EndDIV: case Html_DL: case Html_EndDL: case Html_DT: case Html_H1: case Html_EndH1: case Html_H2: case Html_EndH2: case Html_H3: case Html_EndH3: case Html_H4: case Html_EndH4: case Html_H5: case Html_EndH5: case Html_H6: case Html_EndH6: case Html_EndHTML: case Html_HR: case Html_LI: case Html_LISTING: case Html_EndLISTING: case Html_MENU: case Html_EndMENU: case Html_OL: case Html_EndOL: case Html_P: case Html_EndP: case Html_PRE: case Html_EndPRE: case Html_TABLE: case Html_EndTABLE: case Html_TD: case Html_EndTD: case Html_TH: case Html_EndTH: case Html_TR: case Html_EndTR: case Html_UL: case Html_EndUL: *actualWidth = x<=0 && !isEmpty ? 1 : x; return p; default: break; } } *actualWidth = x<=0 && !isEmpty ? 1 : x; return p; }
/* ** Do as much layout as possible on the block of text defined by ** the HtmlLayoutContext. */ void HtmlLayoutBlock(HtmlLayoutContext *pLC){ HtmlElement *p, *pNext; for(p=pLC->pStart; p && p!=pLC->pEnd; p=pNext){ int lineWidth; int actualWidth; int y = 0; int leftMargin; int maxX = 0; /* Do as much break markup as we can. */ while( p && p!=pLC->pEnd ){ HtmlLock(pLC->htmlPtr); pNext = DoBreakMarkup(pLC, p); if( HtmlUnlock(pLC->htmlPtr) ) return; if( pNext==p ){ TestPoint(0); break; } if( pNext ){ TRACE(HtmlTrace_BreakMarkup, ("Processed token %s as break markup\n", HtmlTokenName(p))); pLC->pStart = p; } p = pNext; TestPoint(0); } if( p==0 || p==pLC->pEnd ){ TestPoint(0); break; } #ifdef TABLE_TRIM_BLANK HtmlLineWasBlank = 0; #endif /* TABLE_TRIM_BLANK */ /* We might try several times to layout a single line... */ while( 1 ){ /* Compute margins */ HtmlComputeMargins(pLC, &leftMargin, &y, &lineWidth); /* Layout a single line of text */ pNext = GetLine(pLC, p, pLC->pEnd, lineWidth, pLC->left-leftMargin, &actualWidth); TRACE(HtmlTrace_GetLine, ("GetLine page=%d left=%d right=%d available=%d used=%d\n", pLC->pageWidth, pLC->left, pLC->right, lineWidth, actualWidth)); FixAnchors(p,pNext,pLC->bottom); /* Move down and repeat the layout if we exceeded the available ** line length and it is possible to increase the line length by ** moving past some obsticle. */ if( actualWidth > lineWidth && InWrapAround(pLC) ){ ClearObstacle(pLC, CLEAR_First); TestPoint(0); continue; } /* Lock the line into place and exit the loop */ y = FixLine(p, pNext, y, lineWidth, actualWidth, leftMargin, &maxX); TestPoint(0); break; } #ifdef TABLE_TRIM_BLANK /* * I noticed that a newline following break markup would result * in a blank line being drawn. So if an "empty" line was found * I subtract any whitespace caused by break markup. */ if (actualWidth <= 0) { HtmlLineWasBlank = 1; } #endif /* TABLE_TRIM_BLANK */ /* If a line was completed, advance to the next line */ if( pNext && actualWidth>0 && y > pLC->bottom ){ pLC->bottom = y; pLC->headRoom = 0; pLC->pStart = pNext; } if( y > pLC->maxY ){ pLC->maxY = y; } if( maxX > pLC->maxX ){ pLC->maxX = maxX; } } }