summaryrefslogtreecommitdiffstats
path: root/tkhtml1/src/htmllayout.c
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2019-01-07 19:38:30 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2019-01-07 19:38:30 (GMT)
commit917eac6db5489b4256a4ba42d89df60e80906894 (patch)
treefb96917e1f49ca7bcef7efc1107c1306f604a471 /tkhtml1/src/htmllayout.c
parent09e487f0e296d4f8b4d8f52913e0853cd6267ab1 (diff)
downloadblt-917eac6db5489b4256a4ba42d89df60e80906894.zip
blt-917eac6db5489b4256a4ba42d89df60e80906894.tar.gz
blt-917eac6db5489b4256a4ba42d89df60e80906894.tar.bz2
update TEA 3.13
Diffstat (limited to 'tkhtml1/src/htmllayout.c')
-rw-r--r--tkhtml1/src/htmllayout.c1170
1 files changed, 0 insertions, 1170 deletions
diff --git a/tkhtml1/src/htmllayout.c b/tkhtml1/src/htmllayout.c
deleted file mode 100644
index e511e53..0000000
--- a/tkhtml1/src/htmllayout.c
+++ /dev/null
@@ -1,1170 +0,0 @@
-/*
-** This file contains the code used to position elements of the
-** HTML file on the screen.
-**
-** 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 <stdlib.h>
-#include <string.h>
-#include "htmllayout.h"
-
-
-/*
-** 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;
-}
-
-/*
-** Pop one margin off of the given margin stack.
-*/
-static void HtmlPopOneMargin(HtmlMargin **ppMargin){
- if( *ppMargin ){
- HtmlMargin *pOld = *ppMargin;
- *ppMargin = pOld->pNext;
- HtmlFree(pOld);
- }
-}
-
-/*
-** Pop as many margins as necessary until the margin that was
-** created with "tag" is popped off. Update the layout context
-** to move past obsticles, if necessary.
-**
-** If there are some margins on the stack that contain non-negative
-** bottom fields, that means there are some obsticles that we have
-** not yet cleared. If these margins get popped off the stack,
-** then we have to be careful to advance the pLC->bottom value so
-** that the next line of text will clear the obsticle.
-*/
-static void HtmlPopMargin(
- HtmlMargin **ppMargin, /* The margin stack to be popped */
- int tag, /* The tag we want to pop */
- HtmlLayoutContext *pLC /* Update this layout context */
-){
- int bottom = -1;
- int oldTag;
- HtmlMargin *pM;
-
- for(pM=*ppMargin; pM && pM->tag!=tag; pM=pM->pNext){}
- if( pM==0 ){
- /* No matching margin is found. Do nothing. */
- return;
- }
- while( (pM=*ppMargin)!=0 ){
- if( pM->bottom>bottom ){
- bottom = pM->bottom;
- }
- oldTag = pM->tag;
- HtmlPopOneMargin(ppMargin);
- if( oldTag==tag ) break;
- }
- if( pLC && pLC->bottom<bottom ){
- pLC->headRoom += bottom - pLC->bottom;
- pLC->bottom = bottom;
- }
-}
-
-/*
-** Pop all expired margins from the stack.
-**
-** An expired margin is one with a non-negative bottom parameter
-** that is less than the value "y". "y" is the Y-coordinate of
-** the top edge the next line of text to by positioned. What this
-** function does is check to see if we have cleared any obsticles
-** (an obsticle is an <IMG ALIGN=left> or <IMG ALIGN=right>) and
-** expands the margins if we have.
-*/
-static void PopExpiredMargins(HtmlMargin **ppMarginStack, int y){
- while( *ppMarginStack && (**ppMarginStack).bottom>=0 &&
- (**ppMarginStack).bottom <= y ){
- HtmlPopOneMargin(ppMarginStack);
- }
-}
-
-/*
-** Clear a margin stack to reclaim memory. This routine just blindly
-** pops everything off the stack. Typically used when the screen is
-** cleared or the widget is deleted, etc.
-*/
-void HtmlClearMarginStack(HtmlMargin **ppMargin){
- while( *ppMargin ){
- HtmlPopOneMargin(ppMargin);
- }
-}
-
-/*
-** 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;
-}
-
-/*
-** Set the y coordinate for every anchor in the given list
-*/
-static void FixAnchors(HtmlElement *p, HtmlElement *pEnd, int y){
- while( p && p!=pEnd ){
- if( p->base.type==Html_A ){
- p->anchor.y = y;
- }
- p = p->pNext;
- }
-}
-
-/*
-** This routine computes the X and Y coordinates for all elements of
-** a line that has been gathered using GetLine() above. It also figures
-** the ascent and descent for in-line images.
-**
-** The value returned is the Y coordinate of the bottom edge of the
-** new line. The X coordinates are computed by adding the left margin
-** plus any extra space needed for centering or right-justification.
-*/
-static int FixLine(
- HtmlElement *pStart, /* Start of tokens for this line */
- HtmlElement *pEnd, /* First token past end of this line. Maybe NULL */
- int bottom, /* Put the top of this line here */
- int width, /* This is the space available to the line */
- int actualWidth, /* This is the actual width needed by the line */
- int leftMargin, /* The current left margin */
- int *maxX /* Write maximum X coordinate of ink here */
-){
- int dx; /* Amount by which to increase all X coordinates */
- int maxAscent; /* Maximum height above baseline */
- int maxTextAscent; /* Maximum height above baseline for text */
- int maxDescent; /* Maximum depth below baseline */
- int ascent, descent; /* Computed ascent and descent for one element */
- HtmlElement *p; /* For looping */
- int y; /* Y coordinate of the baseline */
- int dy2center; /* Distance from baseline to text font center */
- int max = 0;
-
- if( actualWidth>0 ){
- for(p=pStart; p && p!=pEnd && p->base.type!=Html_Text; p=p->pNext){}
- if( p==pEnd || p==0 ) p = pStart;
- if( p->base.style.align == ALIGN_Center ){
- dx = leftMargin + (width - actualWidth)/2;
- }else if( p->base.style.align == ALIGN_Right ){
- dx = leftMargin + (width - actualWidth);
- }else{
- dx = leftMargin;
- }
- if( dx<0 ) dx = 0;
- maxAscent = maxTextAscent = 0;
- for(p=pStart; p && p!=pEnd; p=p->pNext){
- int ss;
- if( p->base.style.flags & STY_Invisible ){
- continue;
- }
- switch( p->base.type ){
- case Html_Text:
- p->text.x += dx;
- max = p->text.x + p->text.w;
- ss = p->base.style.subscript;
- if( ss > 0 ){
- int ascent = p->text.ascent;
- int delta = (ascent + p->text.descent)*ss/2;
- ascent += delta;
- p->text.y = -delta;
- if( ascent > maxAscent ){ TestPoint(0); maxAscent = ascent; }
- if( ascent > maxTextAscent ){ TestPoint(0); maxTextAscent = ascent;}
- }else if( ss < 0 ){
- int descent = p->text.descent;
- int delta = (descent + p->text.ascent)*(-ss)/2;
- descent += delta;
- p->text.y = delta;
- }else{
- p->text.y = 0;
- if( p->text.ascent > maxAscent ){
- maxAscent = p->text.ascent;
- }
- if( p->text.ascent > maxTextAscent ){
- maxTextAscent = p->text.ascent;
- }
- }
- break;
- case Html_Space:
- if( p->space.ascent > maxAscent ){
- maxAscent = p->space.ascent;
- }
- break;
- case Html_LI:
- p->li.x += dx;
- if( p->li.x > max ){
- max = p->li.x;
- }
- break;
- case Html_IMG:
- p->image.x += dx;
- max = p->image.x + p->image.w;
- switch( p->image.align ){
- case IMAGE_ALIGN_Middle:
- p->image.descent = p->image.h/2;
- p->image.ascent = p->image.h - p->image.descent;
- if( p->image.ascent > maxAscent ){
- maxAscent = p->image.ascent;
- }
- break;
- case IMAGE_ALIGN_AbsMiddle:
- dy2center = (p->image.textDescent - p->image.textAscent)/2;
- p->image.descent = p->image.h/2 + dy2center;
- p->image.ascent = p->image.h - p->image.descent;
- if( p->image.ascent > maxAscent ){
- maxAscent = p->image.ascent;
- }
- break;
- case IMAGE_ALIGN_Bottom:
- p->image.descent = 0;
- p->image.ascent = p->image.h;
- if( p->image.ascent > maxAscent ){
- maxAscent = p->image.ascent;
- }
- break;
- case IMAGE_ALIGN_AbsBottom:
- p->image.descent = p->image.textDescent;
- p->image.ascent = p->image.h - p->image.descent;
- if( p->image.ascent > maxAscent ){
- maxAscent = p->image.ascent;
- }
- break;
- default:
- TestPoint(0);
- break;
- }
- break;
- case Html_TEXTAREA:
- case Html_INPUT:
- case Html_SELECT:
- case Html_EMBED:
- case Html_APPLET:
- p->input.x += dx;
- max = p->input.x + p->input.w;
- dy2center = (p->input.textDescent - p->input.textAscent)/2;
- p->input.y = dy2center - p->input.h/2;
- ascent = -p->input.y;
- if( ascent > maxAscent ){
- maxAscent = ascent;
- }
- break;
- default:
- /* Shouldn't happen */
- break;
- }
- }
- *maxX = max;
- y = maxAscent + bottom;
- maxDescent = 0;
- for(p=pStart; p && p!=pEnd; p=p->pNext){
- if( p->base.style.flags & STY_Invisible ){
- TestPoint(0);
- continue;
- }
- switch( p->base.type ){
- case Html_Text:
- p->text.y += y;
- if( p->text.descent > maxDescent ){
- maxDescent = p->text.descent;
- }
- break;
- case Html_LI:
- p->li.y = y;
- if( p->li.descent > maxDescent ){
- maxDescent = p->li.descent;
- }
- break;
- case Html_IMG:
- p->image.y = y;
- switch( p->image.align ){
- case IMAGE_ALIGN_Top:
- p->image.ascent = maxAscent;
- p->image.descent = p->image.h - maxAscent;
- TestPoint(0);
- break;
- case IMAGE_ALIGN_TextTop:
- p->image.ascent = maxTextAscent;
- p->image.descent = p->image.h - maxTextAscent;
- TestPoint(0);
- break;
- default:
- TestPoint(0);
- break;
- }
- if( p->image.descent > maxDescent ){
- maxDescent = p->image.descent;
- }
- break;
- case Html_INPUT:
- case Html_SELECT:
- case Html_TEXTAREA:
- case Html_APPLET:
- case Html_EMBED:
- descent = p->input.y + p->input.h;
- p->input.y += y;
- if( descent > maxDescent ){
- maxDescent = descent;
- }
- break;
- default:
- /* Shouldn't happen */
- break;
- }
- }
- TRACE(HtmlTrace_FixLine,
- ("Setting baseline to %d. bottom=%d ascent=%d descent=%d dx=%d\n",
- y, bottom, maxAscent, maxDescent, dx));
- }else{
- maxDescent = 0;
- y = bottom;
- }
- return y + maxDescent;
-}
-
-/*
-** Increase the headroom to create a paragraph break at the current token
-*/
-static void Paragraph(
- HtmlLayoutContext *pLC,
- HtmlElement *p
-){
- int headroom;
-
- if( p==0 ){ TestPoint(0); return; }
- if( p->base.type==Html_Text ){
- headroom = p->text.ascent + p->text.descent;
- TestPoint(0);
- }else if( p->pNext && p->pNext->base.type==Html_Text ){
- headroom = p->pNext->text.ascent + p->pNext->text.descent;
- TestPoint(0);
- }else{
- Tk_FontMetrics fontMetrics;
- Tk_Font font;
- font = HtmlGetFont(pLC->htmlPtr, p->base.style.font);
- if( font==0 ) return;
- Tk_GetFontMetrics(font, &fontMetrics);
- headroom = fontMetrics.descent + fontMetrics.ascent;
- TestPoint(0);
- }
- if( pLC->headRoom < headroom && pLC->bottom > pLC->top ){
- pLC->headRoom = headroom;
- }
-}
-
-/*
-** Compute the current margins for layout. Three values are returned:
-**
-** *pY The top edge of the area in which we can put ink. This
-** takes into account any requested headroom.
-**
-** *pX The left edge of the inkable area. The takes into account
-** any margin requests active at vertical position specified
-** in pLC->bottom.
-**
-** *pW The width of the inkable area. This takes into account
-** an margin requests that are active at the vertical position
-** pLC->bottom.
-**
-*/
-void HtmlComputeMargins(
- HtmlLayoutContext *pLC, /* The current layout context */
- int *pX, /* Put the left edge here */
- int *pY, /* Put the top edge here */
- int *pW /* Put the width here */
-){
- int x, y, w;
-
- y = pLC->bottom + pLC->headRoom;
- PopExpiredMargins(&pLC->leftMargin, pLC->bottom);
- PopExpiredMargins(&pLC->rightMargin, pLC->bottom);
- w = pLC->pageWidth - pLC->right;
- if( pLC->leftMargin ){
- x = pLC->leftMargin->indent + pLC->left;
- TestPoint(0);
- }else{
- x = pLC->left;
- TestPoint(0);
- }
- w -= x;
- if( pLC->rightMargin ){
- w -= pLC->rightMargin->indent;
- TestPoint(0);
- }else{
- TestPoint(0);
- }
- *pX = x;
- *pY = y;
- *pW = w;
-}
-
-
-/*
-** Clear a wrap-around obstacle. The second option determines the
-** precise behavior.
-**
-** CLEAR_Left Clear all obstacles on the left.
-**
-** CLEAR_Right Clear all obstacles on the right.
-**
-** CLEAR_Both Clear all obstacles on both sides.
-**
-** CLEAR_First Clear only the first obsticle on either side.
-*/
-#define CLEAR_Left 0
-#define CLEAR_Right 1
-#define CLEAR_Both 2
-#define CLEAR_First 3
-static void ClearObstacle(HtmlLayoutContext *pLC, int mode){
- int newBottom = pLC->bottom;
-
- PopExpiredMargins(&pLC->leftMargin, pLC->bottom);
- PopExpiredMargins(&pLC->rightMargin, pLC->bottom);
- switch( mode ){
- case CLEAR_Both:
- ClearObstacle(pLC,CLEAR_Left);
- ClearObstacle(pLC,CLEAR_Right);
- TestPoint(0);
- break;
-
- case CLEAR_Left:
- while( pLC->leftMargin && pLC->leftMargin->bottom>=0 ){
- newBottom = pLC->leftMargin->bottom;
- HtmlPopOneMargin(&pLC->leftMargin);
- TestPoint(0);
- }
- if( newBottom > pLC->bottom + pLC->headRoom ){
- pLC->headRoom = 0;
- TestPoint(0);
- }else{
- pLC->headRoom = newBottom - pLC->bottom;
- TestPoint(0);
- }
- pLC->bottom = newBottom;
- PopExpiredMargins(&pLC->rightMargin, pLC->bottom);
- break;
-
- case CLEAR_Right:
- while( pLC->rightMargin && pLC->rightMargin->bottom>=0 ){
- newBottom = pLC->rightMargin->bottom;
- HtmlPopOneMargin(&pLC->rightMargin);
- TestPoint(0);
- }
- if( newBottom > pLC->bottom + pLC->headRoom ){
- pLC->headRoom = 0;
- TestPoint(0);
- }else{
- pLC->headRoom = newBottom - pLC->bottom;
- TestPoint(0);
- }
- pLC->bottom = newBottom;
- PopExpiredMargins(&pLC->leftMargin, pLC->bottom);
- break;
-
- case CLEAR_First:
- if( pLC->leftMargin && pLC->leftMargin->bottom>=0 ){
- if( pLC->rightMargin
- && pLC->rightMargin->bottom < pLC->leftMargin->bottom
- ){
- newBottom = pLC->rightMargin->bottom;
- HtmlPopOneMargin(&pLC->rightMargin);
- TestPoint(0);
- }else{
- newBottom = pLC->leftMargin->bottom;
- HtmlPopOneMargin(&pLC->leftMargin);
- TestPoint(0);
- }
- }else if( pLC->rightMargin && pLC->rightMargin->bottom>=0 ){
- newBottom = pLC->rightMargin->bottom;
- HtmlPopOneMargin(&pLC->rightMargin);
- TestPoint(0);
- }else{
- TestPoint(0);
- }
- if( newBottom > pLC->bottom + pLC->headRoom ){
- pLC->headRoom = 0;
- TestPoint(0);
- }else{
- pLC->headRoom = newBottom - pLC->bottom;
- TestPoint(0);
- }
- pLC->bottom = newBottom;
- break;
- }
-}
-
-/*
-** Break markup is any kind of markup that might force a line-break. This
-** routine handles a single element of break markup and returns a pointer
-** to the first element past that markup. If p doesn't point to break
-** markup, then p is returned. If p is an incomplete table (a <TABLE>
-** that lacks a </TABLE>), then NULL is returned.
-*/
-static HtmlElement *DoBreakMarkup(
- HtmlLayoutContext *pLC,
- HtmlElement *p
-){
- HtmlElement *pNext = p->pNext;
- char *z;
- int x, y, w;
-
- switch( p->base.type ){
- case Html_A:
- p->anchor.y = pLC->bottom;
- TestPoint(0);
- break;
-
- case Html_BLOCKQUOTE:
- HtmlPushMargin(&pLC->leftMargin, HTML_INDENT, -1, Html_EndBLOCKQUOTE);
- HtmlPushMargin(&pLC->rightMargin, HTML_INDENT, -1, Html_EndBLOCKQUOTE);
- Paragraph(pLC, p);
- TestPoint(0);
- break;
- case Html_EndBLOCKQUOTE:
- HtmlPopMargin(&pLC->leftMargin, Html_EndBLOCKQUOTE, pLC);
- HtmlPopMargin(&pLC->rightMargin, Html_EndBLOCKQUOTE, pLC);
- Paragraph(pLC, p);
- TestPoint(0);
- break;
-
- case Html_IMG:
- switch( p->image.align ){
- case IMAGE_ALIGN_Left:
- HtmlComputeMargins(pLC, &x, &y, &w);
- p->image.x = x;
- p->image.y = y;
- p->image.ascent = 0;
- p->image.descent = p->image.h;
- HtmlPushMargin(&pLC->leftMargin, p->image.w + 2, y + p->image.h, 0);
- SETMAX( pLC->maxY, y + p->image.h );
- SETMAX( pLC->maxX, x + p->image.w );
- break;
- case IMAGE_ALIGN_Right:
- HtmlComputeMargins(pLC, &x, &y, &w);
- p->image.x = x + w - p->image.w;
- p->image.y = y;
- p->image.ascent = 0;
- p->image.descent = p->image.h;
- HtmlPushMargin(&pLC->rightMargin, p->image.w + 2, y + p->image.h, 0);
- SETMAX( pLC->maxY, y + p->image.h );
- SETMAX( pLC->maxX, x + p->image.w );
- break;
- default:
- TestPoint(0);
- pNext = p;
- break;
- }
- break;
-
-
- case Html_PRE:
- /* Skip space tokens thru the next newline. */
- while( pNext->base.type==Html_Space ){
- HtmlElement *pThis = pNext;
- pNext = pNext->pNext;
- if( pThis->base.flags & HTML_NewLine ){ TestPoint(0); break; }
- }
- Paragraph(pLC,p);
- break;
-
- case Html_UL:
- case Html_MENU:
- case Html_DIR:
- case Html_OL:
- if( p->list.compact==0 ){
- Paragraph(pLC,p);
- }
- HtmlPushMargin(&pLC->leftMargin, HTML_INDENT, -1, p->base.type+1);
- break;
-
- case Html_EndOL:
- case Html_EndUL:
- case Html_EndMENU:
- case Html_EndDIR:
- if( p->ref.pOther ){
- HtmlPopMargin(&pLC->leftMargin, p->base.type, pLC);
- if( !p->ref.pOther->list.compact ){
- Paragraph(pLC,p);
- }
- }
- break;
-
- case Html_DL:
- Paragraph(pLC,p);
- HtmlPushMargin(&pLC->leftMargin, HTML_INDENT, -1, Html_EndDL);
- TestPoint(0);
- break;
-
- case Html_EndDL:
- HtmlPopMargin(&pLC->leftMargin, Html_EndDL, pLC);
- Paragraph(pLC,p);
- TestPoint(0);
- break;
-
- case Html_HR: {
- int zl, wd;
-
- p->hr.is3D = HtmlMarkupArg(p, "noshade", 0)==0;
- z = HtmlMarkupArg(p, "size", 0);
- if( z ){
- p->hr.h = atoi(z);
- }else{
- p->hr.h = 0;
- }
- if( p->hr.h<1 ){
- int relief = pLC->htmlPtr->ruleRelief;
- if( p->hr.is3D
- && (relief==TK_RELIEF_SUNKEN || relief==TK_RELIEF_RAISED) ){
- p->hr.h = 3;
- }else{
- p->hr.h = 2;
- }
- }
- HtmlComputeMargins(pLC, &x, &y, &w);
- p->hr.y = y;
- y += p->hr.h + 1;
- p->hr.x = x;
- z = HtmlMarkupArg(p, "width", "100%");
- zl = strlen(z);
- if( zl>0 && z[zl-1]=='%' ){
- wd = (atoi(z)*w)/100;
- }else{
- wd = atoi(z);
- }
- if( wd>w ) wd = w;
- p->hr.w = wd;
- switch( p->base.style.align ){
- case ALIGN_Center:
- case ALIGN_None:
- p->hr.x += (w - wd)/2;
- TestPoint(0);
- break;
- case ALIGN_Right:
- p->hr.x += (w - wd);
- TestPoint(0);
- break;
- default:
- TestPoint(0);
- break;
- }
- SETMAX( pLC->maxY, y);
- SETMAX( pLC->maxX, wd + p->hr.x );
- pLC->bottom = y;
- pLC->headRoom = 0;
- break;
- }
-
- case Html_ADDRESS:
- case Html_EndADDRESS:
- case Html_CENTER:
- case Html_EndCENTER:
- case Html_DIV:
- case Html_EndDIV:
- 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_P:
- case Html_EndP:
- case Html_EndPRE:
- Paragraph(pLC, p);
- TestPoint(0);
- break;
-
- case Html_TABLE:
- pNext = HtmlTableLayout(pLC, p);
- TestPoint(0);
- break;
-
- case Html_BR:
- z = HtmlMarkupArg(p, "clear",0);
- if( z ){
- if( stricmp(z,"left")==0 ){
- ClearObstacle(pLC, CLEAR_Left);
- TestPoint(0);
- }else if( stricmp(z,"right")==0 ){
- ClearObstacle(pLC, CLEAR_Right);
- TestPoint(0);
- }else{
- ClearObstacle(pLC, CLEAR_Both);
- TestPoint(0);
- }
- }else{
- TestPoint(0);
- }
- break;
-
- /* All of the following tags need to be handed to the GetLine() routine */
- case Html_Text:
- case Html_Space:
- case Html_LI:
- case Html_INPUT:
- case Html_SELECT:
- case Html_TEXTAREA:
- case Html_APPLET:
- case Html_EMBED:
- pNext = p;
- TestPoint(0);
- break;
-
- default:
- TestPoint(0);
- break;
- }
- return pNext;
-}
-
-/*
-** Return TRUE (non-zero) if we are currently wrapping text around
-** one or more images.
-*/
-static int InWrapAround(HtmlLayoutContext *pLC){
- if( pLC->leftMargin && pLC->leftMargin->bottom >= 0 ){
- TestPoint(0);
- return 1;
- }
- if( pLC->rightMargin && pLC->rightMargin->bottom >= 0 ){
- TestPoint(0);
- return 1;
- }
- TestPoint(0);
- return 0;
-}
-
-/*
-** Move past obsticles until a linewidth of reqWidth is obtained,
-** or until all obsticles are cleared.
-*/
-void HtmlWidenLine(
- HtmlLayoutContext *pLC, /* The layout context */
- int reqWidth, /* Requested line width */
- int *pX, int *pY, int *pW /* The margins. See HtmllComputeMargins() */
-){
- HtmlComputeMargins(pLC, pX, pY, pW);
- if( *pW<reqWidth && InWrapAround(pLC) ){
- ClearObstacle(pLC, CLEAR_First);
- HtmlComputeMargins(pLC, pX, pY, pW);
- }
-}
-
-#ifdef TABLE_TRIM_BLANK
-int HtmlLineWasBlank = 0;
-#endif /* TABLE_TRIM_BLANK */
-
-/*
-** 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;
- }
- }
-}
-
-/*
-** Advance the layout as far as possible
-*/
-void HtmlLayout(HtmlWidget *htmlPtr){
- HtmlLayoutContext *pLC;
- int btm;
-
- if( htmlPtr->pFirst==0 ) return;
- HtmlLock(htmlPtr);
- HtmlSizer(htmlPtr);
- if( HtmlUnlock(htmlPtr) ) return;
- pLC = &htmlPtr->layoutContext;
- pLC->htmlPtr = htmlPtr;
- pLC->pageWidth = htmlPtr->realWidth - 2*(htmlPtr->inset + htmlPtr->padx);
- pLC->left = 0;
- pLC->right = 0;
- pLC->pStart = htmlPtr->nextPlaced;
- if( pLC->pStart==0 ){
- pLC->pStart = htmlPtr->pFirst;
- }
- if( pLC->pStart ){
- pLC->maxX = htmlPtr->maxX;
- pLC->maxY = htmlPtr->maxY;
- btm = pLC->bottom;
- HtmlLock(htmlPtr);
- HtmlLayoutBlock(pLC);
- if( HtmlUnlock(htmlPtr) ) return;
- htmlPtr->maxX = pLC->maxX;
- htmlPtr->maxY = pLC->maxY;
- htmlPtr->nextPlaced = pLC->pStart;
- htmlPtr->flags |= HSCROLL | VSCROLL;
- HtmlRedrawText(htmlPtr, btm);
- }
-}