634 lines
11 KiB
C
634 lines
11 KiB
C
|
/*
|
||
|
* list.c
|
||
|
*
|
||
|
* libhtml - HTML->X renderer
|
||
|
*
|
||
|
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program 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 General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
*/
|
||
|
#include "port_before.h"
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <ctype.h>
|
||
|
|
||
|
#ifdef HAVE_STDLIB_H
|
||
|
#include <stdlib.h>
|
||
|
#endif
|
||
|
|
||
|
#include "port_after.h"
|
||
|
|
||
|
#include "html.h"
|
||
|
|
||
|
/*
|
||
|
* Numeric label stuff for <OL> supplied by
|
||
|
* Jake Kesinger <kesinger@math.ttu.edu>
|
||
|
*/
|
||
|
typedef enum
|
||
|
{
|
||
|
OL_NUMERIC,
|
||
|
OL_ALPHA_CAP,
|
||
|
OL_ALPHA_MINISCULE,
|
||
|
OL_ROMAN_CAP,
|
||
|
OL_ROMAN_MINISCULE
|
||
|
} OListType;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
OListType type; /* type for ol list */
|
||
|
int count; /* count for ol list */
|
||
|
int bullet_diam; /* cached bullet size */
|
||
|
GList klist; /* list of item boxes */
|
||
|
HTMLBox lbox; /* list box */
|
||
|
HTMLBox ibox; /* item box */
|
||
|
HTMLBox tbox; /* text box inside item (dd, li) */
|
||
|
} HList;
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
* Private functions
|
||
|
*
|
||
|
*/
|
||
|
static void RenderLI _ArgProto((HTMLInfo, HTMLBox, Region));
|
||
|
static void SetupList _ArgProto((HTMLInfo, HTMLBox));
|
||
|
static void RenderList _ArgProto((HTMLInfo, HTMLBox, Region));
|
||
|
static void DestroyList _ArgProto((HTMLInfo, HTMLBox));
|
||
|
static HList *CreateList _ArgProto((HTMLInfo, HTMLEnv));
|
||
|
static void OLNext _ArgProto((char *, size_t, int, OListType));
|
||
|
|
||
|
/*
|
||
|
* SetupList
|
||
|
*/
|
||
|
static void
|
||
|
SetupList(li, box)
|
||
|
HTMLInfo li;
|
||
|
HTMLBox box;
|
||
|
{
|
||
|
HList *hl = (HList *)box->closure;
|
||
|
HTMLBox c;
|
||
|
int ty = box->y;
|
||
|
|
||
|
for (c = (HTMLBox)GListGetHead(hl->klist); c != NULL;
|
||
|
c = (HTMLBox)GListGetNext(hl->klist))
|
||
|
{
|
||
|
c->x = box->x;
|
||
|
c->y = ty;
|
||
|
HTMLSetupBox(li, c);
|
||
|
ty += c->height;
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* RenderList
|
||
|
*/
|
||
|
static void
|
||
|
RenderList(li, box, r)
|
||
|
HTMLInfo li;
|
||
|
HTMLBox box;
|
||
|
Region r;
|
||
|
{
|
||
|
HList *hl = (HList *)box->closure;
|
||
|
HTMLBox c;
|
||
|
|
||
|
for (c = (HTMLBox)GListGetHead(hl->klist); c != NULL;
|
||
|
c = (HTMLBox)GListGetNext(hl->klist))
|
||
|
{
|
||
|
HTMLRenderBox(li, r, c);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
DestroyList(li, box)
|
||
|
HTMLInfo li;
|
||
|
HTMLBox box;
|
||
|
{
|
||
|
HList *ls = (HList *)box->closure;
|
||
|
HTMLBox c;
|
||
|
|
||
|
for (c = (HTMLBox)GListGetHead(ls->klist); c != NULL;
|
||
|
c = (HTMLBox)GListGetNext(ls->klist))
|
||
|
{
|
||
|
HTMLDestroyBox(li, c);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* RenderLI
|
||
|
*/
|
||
|
static void
|
||
|
RenderLI(li, box, r)
|
||
|
HTMLInfo li;
|
||
|
HTMLBox box;
|
||
|
Region r;
|
||
|
{
|
||
|
unsigned int half = box->width / 2;
|
||
|
|
||
|
XFillArc(li->dpy, li->win, li->gc,
|
||
|
box->x + half, box->y + half, half, half,
|
||
|
0, 360 * 64);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CreateList
|
||
|
*/
|
||
|
static HList *
|
||
|
CreateList(li, env)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
{
|
||
|
HList *ls;
|
||
|
|
||
|
ls = (HList *)MPCGet(li->mp, sizeof(HList));
|
||
|
ls->lbox = HTMLCreateBox(li, env);
|
||
|
ls->lbox->setup = SetupList;
|
||
|
ls->lbox->render = RenderList;
|
||
|
ls->lbox->destroy = DestroyList;
|
||
|
ls->lbox->closure = ls;
|
||
|
ls->klist = GListCreateX(li->mp);
|
||
|
|
||
|
return(ls);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
* Public functions
|
||
|
*
|
||
|
*/
|
||
|
void
|
||
|
HTMLULBegin(li, env, p)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
MLElement p;
|
||
|
{
|
||
|
HList *ls;
|
||
|
XFontStruct *font;
|
||
|
|
||
|
font = HTMLGetFont(li, env);
|
||
|
|
||
|
ls = CreateList(li, env);
|
||
|
ls->bullet_diam = font->ascent;
|
||
|
env->closure = ls;
|
||
|
env->ff = FLOW_LEFT_JUSTIFY;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
HTMLListEnd(li, env, p)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
MLElement p;
|
||
|
{
|
||
|
HList *ls = (HList *)env->closure;
|
||
|
|
||
|
HTMLEnvAddBox(li, env->penv, ls->lbox);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
HTMLOLBegin(li, env, p)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
MLElement p;
|
||
|
{
|
||
|
HList *ls;
|
||
|
char *startstr;
|
||
|
char *variantstr;
|
||
|
|
||
|
ls = CreateList(li, env);
|
||
|
env->closure = ls;
|
||
|
env->ff = FLOW_LEFT_JUSTIFY;
|
||
|
|
||
|
/*
|
||
|
* If the <ol> specifies a START or SEQNUM attribute, handle that,
|
||
|
* otherwise the default is 1
|
||
|
*/
|
||
|
if((startstr = MLFindAttribute(p, "start"))!= NULL)
|
||
|
{
|
||
|
ls->count = atoi(startstr);
|
||
|
}
|
||
|
else if((startstr = MLFindAttribute(p, "seqnum"))!= NULL)
|
||
|
{
|
||
|
ls->count = atoi(startstr);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ls->count = 1;
|
||
|
}
|
||
|
/*
|
||
|
* Now see if said <ol> has a TYPE attribute.
|
||
|
* Types are:
|
||
|
* 1 ==> std numbering
|
||
|
* aA ==>[aA]lphabetic
|
||
|
* iI ==> [rR]oman
|
||
|
*/
|
||
|
if ((variantstr = MLFindAttribute(p, "type")) != NULL)
|
||
|
{
|
||
|
if (variantstr[0] == 'a') ls->type = OL_ALPHA_MINISCULE;
|
||
|
else if (variantstr[0] == 'A') ls->type = OL_ALPHA_CAP;
|
||
|
else if (variantstr[0] == 'i') ls->type = OL_ROMAN_MINISCULE;
|
||
|
else if (variantstr[0] == 'I') ls->type = OL_ROMAN_CAP;
|
||
|
else ls->type = OL_NUMERIC;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ls->type = OL_NUMERIC;
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
HTMLLIBegin(li, env, p)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
MLElement p;
|
||
|
{
|
||
|
HTMLBox box;
|
||
|
HList *ls;
|
||
|
char buffer[BUFSIZ];
|
||
|
|
||
|
ls = (HList *)env->penv->closure;
|
||
|
ls->ibox = HTMLCreateFlowBox(li, env, HTMLGetMaxWidth(li, env->penv));
|
||
|
GListAddTail(ls->klist, ls->ibox);
|
||
|
env->closure = ls;
|
||
|
|
||
|
if (HTMLTagToID(env->penv->tag) == TAG_OL)
|
||
|
{
|
||
|
OLNext(buffer, sizeof(buffer), ls->count++, ls->type);
|
||
|
box = HTMLCreateTextBox(li, env,
|
||
|
MPStrDup(li->mp, buffer), strlen(buffer));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
box = HTMLCreateBox(li, env);
|
||
|
box->width = ls->bullet_diam;
|
||
|
box->height = ls->bullet_diam;
|
||
|
box->render = RenderLI;
|
||
|
}
|
||
|
HTMLSetB(box, BOX_FLOAT_LEFT);
|
||
|
HTMLLayoutBox(li, ls->ibox, box);
|
||
|
|
||
|
ls->tbox = HTMLCreateFlowBox(li, env,
|
||
|
HTMLGetMaxWidth(li, env->penv) - box->width);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
HTMLItemEnd(li, env, p)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
MLElement p;
|
||
|
{
|
||
|
HList *ls = (HList *)env->closure;
|
||
|
|
||
|
if (ls->tbox != NULL)
|
||
|
{
|
||
|
HTMLFinishFlowBox(li, ls->tbox);
|
||
|
HTMLLayoutBox(li, ls->ibox, ls->tbox);
|
||
|
}
|
||
|
HTMLFinishFlowBox(li, ls->ibox);
|
||
|
|
||
|
HTMLEnvAddBox(li, env->penv, ls->ibox);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
HTMLDDBegin(li, env, p)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
MLElement p;
|
||
|
{
|
||
|
HList *ls;
|
||
|
HTMLBox indent;
|
||
|
|
||
|
ls = (HList *)env->penv->closure;
|
||
|
ls->ibox = HTMLCreateFlowBox(li, env, HTMLGetMaxWidth(li, env->penv));
|
||
|
GListAddTail(ls->klist, ls->ibox);
|
||
|
env->closure = ls;
|
||
|
|
||
|
indent = HTMLCreateBox(li, env);
|
||
|
if (ResourceGetUInt(li->cres, "html.dlIndent", &(indent->width)) == NULL)
|
||
|
{
|
||
|
indent->width = 20;
|
||
|
}
|
||
|
indent->height = 1;
|
||
|
HTMLSetB(indent, BOX_FLOAT_LEFT);
|
||
|
HTMLLayoutBox(li, ls->ibox, indent);
|
||
|
|
||
|
ls->tbox = HTMLCreateFlowBox(li, env,
|
||
|
HTMLGetMaxWidth(li, env->penv) - indent->width);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
HTMLDTBegin(li, env, p)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
MLElement p;
|
||
|
{
|
||
|
HList *ls;
|
||
|
|
||
|
ls = (HList *)env->penv->closure;
|
||
|
ls->ibox = HTMLCreateFlowBox(li, env, HTMLGetMaxWidth(li, env->penv));
|
||
|
GListAddTail(ls->klist, ls->ibox);
|
||
|
env->closure = ls;
|
||
|
ls->tbox = NULL; /* this is important */
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
HTMLDLBegin(li, env, p)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
MLElement p;
|
||
|
{
|
||
|
HList *ls;
|
||
|
|
||
|
ls = CreateList(li, env);
|
||
|
env->closure = ls;
|
||
|
env->ff = FLOW_LEFT_JUSTIFY;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* OLNext
|
||
|
*/
|
||
|
static void
|
||
|
OLNext(buffer, bsize, number, oltype)
|
||
|
char *buffer;
|
||
|
size_t bsize;
|
||
|
int number;
|
||
|
OListType oltype;
|
||
|
{
|
||
|
int i;
|
||
|
char *cp;
|
||
|
|
||
|
if (oltype == OL_ALPHA_CAP)
|
||
|
{
|
||
|
number = (number-1) % 26;
|
||
|
number += 65;
|
||
|
snprintf(buffer, bsize, "%c.", (char)number);
|
||
|
}
|
||
|
else if (oltype == OL_ALPHA_MINISCULE)
|
||
|
{
|
||
|
number = (number-1) % 26;
|
||
|
number += 97;
|
||
|
snprintf(buffer, bsize, "%c.", (char)number);
|
||
|
}
|
||
|
else if ((oltype==OL_ROMAN_CAP)||(oltype==OL_ROMAN_MINISCULE))
|
||
|
{
|
||
|
/*Convert an integer to roman*/
|
||
|
i=0;
|
||
|
if (number <0)
|
||
|
{
|
||
|
buffer[i++]='-';
|
||
|
number *= -1;
|
||
|
}
|
||
|
if (number==0)
|
||
|
{
|
||
|
buffer[i++]='0';
|
||
|
}
|
||
|
while ((number > 0) && (i < BUFSIZ - 2))
|
||
|
{
|
||
|
if (number >=1000)
|
||
|
{
|
||
|
number -=1000;
|
||
|
buffer[i++]='M';
|
||
|
}
|
||
|
else if (number >=900)
|
||
|
{
|
||
|
number -=100;
|
||
|
buffer[i++]='C';
|
||
|
buffer[i++]='M';
|
||
|
}
|
||
|
else if (number >= 500)
|
||
|
{
|
||
|
number -= 500;
|
||
|
buffer[i++] ='D';
|
||
|
}
|
||
|
else if (number >= 100)
|
||
|
{
|
||
|
number -= 100;
|
||
|
buffer[i++] ='C';
|
||
|
}
|
||
|
else if (number >= 90)
|
||
|
{
|
||
|
number-= 10;
|
||
|
buffer[i++]='X';
|
||
|
buffer[i++]='C';
|
||
|
}
|
||
|
else if (number >= 50)
|
||
|
{
|
||
|
number -= 50;
|
||
|
buffer[i++] = 'L';
|
||
|
}
|
||
|
else if (number >= 40)
|
||
|
{
|
||
|
number -= 10;
|
||
|
buffer[i++]='X';
|
||
|
buffer[i++]='L';
|
||
|
}
|
||
|
else if (number >= 10)
|
||
|
{
|
||
|
number -= 10;
|
||
|
buffer[i++]='X';
|
||
|
}
|
||
|
else if (number == 9)
|
||
|
{
|
||
|
number = 0;
|
||
|
buffer[i++]='I';
|
||
|
buffer[i++]='X';
|
||
|
}
|
||
|
else if (number >= 5)
|
||
|
{
|
||
|
number -= 5;
|
||
|
buffer[i++]='V';
|
||
|
}
|
||
|
else if (number == 4)
|
||
|
{
|
||
|
number = 0;
|
||
|
buffer[i++]='I';
|
||
|
buffer[i++]='V';
|
||
|
}
|
||
|
else if (number >=1)
|
||
|
{
|
||
|
number--;
|
||
|
buffer[i++]='I';
|
||
|
}
|
||
|
}
|
||
|
buffer[i++] = '.';
|
||
|
buffer[i] = '\0';
|
||
|
/*We've done everything in caps, now convert to lowercase if
|
||
|
necessary*/
|
||
|
if (oltype == OL_ROMAN_MINISCULE)
|
||
|
{
|
||
|
for (cp = buffer; *cp != '\0'; cp++)
|
||
|
{
|
||
|
*cp = tolower(*cp);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
snprintf(buffer, sizeof(buffer), "%d.", number);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
HTMLListAccept(li, obj)
|
||
|
HTMLInfo li;
|
||
|
HTMLObject obj;
|
||
|
{
|
||
|
if (obj->type != HTML_ENV) return(false);
|
||
|
if (HTMLTagToID(obj->o.env->tag) != TAG_LI) return(false);
|
||
|
return(true);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
HTMLDLAccept(li, obj)
|
||
|
HTMLInfo li;
|
||
|
HTMLObject obj;
|
||
|
{
|
||
|
if (obj->type != HTML_ENV) return(false);
|
||
|
if (HTMLTagToID(obj->o.env->tag) != TAG_DD &&
|
||
|
HTMLTagToID(obj->o.env->tag) != TAG_DT)
|
||
|
{
|
||
|
return(false);
|
||
|
}
|
||
|
return(true);
|
||
|
}
|
||
|
|
||
|
HTMLInsertStatus
|
||
|
HTMLLIInsert(li, env, p)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
MLElement p;
|
||
|
{
|
||
|
HTMLEnv tenv;
|
||
|
|
||
|
if ((tenv = HTMLFindEnv(li, TAG_UL)) == NULL &&
|
||
|
(tenv = HTMLFindEnv(li, TAG_OL)) == NULL)
|
||
|
{
|
||
|
return(HTMLInsertReject);
|
||
|
}
|
||
|
|
||
|
if (HTMLTagToID(tenv->tag) == TAG_UL) HTMLPopEnv(li, TAG_UL);
|
||
|
else HTMLPopEnv(li, TAG_OL);
|
||
|
|
||
|
return(HTMLInsertOK);
|
||
|
}
|
||
|
|
||
|
HTMLInsertStatus
|
||
|
HTMLDDInsert(li, env, p)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
MLElement p;
|
||
|
{
|
||
|
HTMLEnv tenv;
|
||
|
|
||
|
if ((tenv = HTMLFindEnv(li, TAG_DL)) == NULL)
|
||
|
{
|
||
|
return(HTMLInsertReject);
|
||
|
}
|
||
|
|
||
|
HTMLPopEnv(li, TAG_DL);
|
||
|
|
||
|
return(HTMLInsertOK);
|
||
|
}
|
||
|
|
||
|
HTMLInsertStatus
|
||
|
HTMLDTInsert(li, env, p)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
MLElement p;
|
||
|
{
|
||
|
HTMLEnv tenv;
|
||
|
|
||
|
if ((tenv = HTMLFindEnv(li, TAG_DL)) == NULL)
|
||
|
{
|
||
|
return(HTMLInsertReject);
|
||
|
}
|
||
|
|
||
|
HTMLPopEnv(li, TAG_DL);
|
||
|
|
||
|
return(HTMLInsertOK);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* HTMLItemAddBox
|
||
|
*/
|
||
|
void
|
||
|
HTMLItemAddBox(li, env, box)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
HTMLBox box;
|
||
|
{
|
||
|
HList *ls = (HList *)env->closure;
|
||
|
|
||
|
if (ls->tbox != NULL) HTMLLayoutBox(li, ls->tbox, box);
|
||
|
else HTMLLayoutBox(li, ls->ibox, box);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* HTMLListAddBox
|
||
|
*/
|
||
|
void
|
||
|
HTMLListAddBox(li, env, box)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
HTMLBox box;
|
||
|
{
|
||
|
HList *ls = (HList *)env->closure;
|
||
|
HTMLBox parent = ls->lbox;
|
||
|
|
||
|
if (box->width > parent->width) parent->width = box->width;
|
||
|
parent->height += box->height;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* HTMLItemWidth
|
||
|
*/
|
||
|
unsigned int
|
||
|
HTMLItemWidth(li, env)
|
||
|
HTMLInfo li;
|
||
|
HTMLEnv env;
|
||
|
{
|
||
|
HList *ls = (HList *)env->closure;
|
||
|
|
||
|
if (ls->tbox != NULL) return(HTMLGetBoxWidth(li, ls->tbox));
|
||
|
else return(HTMLGetBoxWidth(li, ls->ibox));
|
||
|
}
|