mirror of
https://github.com/NishiOwO/tkwww.git
synced 2025-04-21 16:54:40 +00:00
364 lines
8.8 KiB
C
364 lines
8.8 KiB
C
/* Style Implementation for Hypertext HTStyle.c
|
|
** ==================================
|
|
**
|
|
** Styles allow the translation between a logical property
|
|
** of a piece of text and its physical representation.
|
|
**
|
|
** A StyleSheet is a collection of styles, defining the
|
|
** translation necessary to
|
|
** represent a document. It is a linked list of styles.
|
|
*/
|
|
#include "HTStyle.h"
|
|
#include "HTUtils.h"
|
|
|
|
/* Create a new style
|
|
*/
|
|
PUBLIC HTStyle* HTStyleNew NOARGS
|
|
{
|
|
HTStyle * self = (HTStyle *)malloc(sizeof(*self));
|
|
memset(self, 0, sizeof(*self));
|
|
self->font = (HTFont) 0;
|
|
self->color = 0;
|
|
return self;
|
|
}
|
|
|
|
/* Create a new style with a name
|
|
*/
|
|
PUBLIC HTStyle* HTStyleNewNamed ARGS1 (CONST char *,name)
|
|
{
|
|
HTStyle * self = HTStyleNew();
|
|
StrAllocCopy(self->name, name);
|
|
return self;
|
|
}
|
|
|
|
|
|
/* Free a style
|
|
*/
|
|
PUBLIC HTStyle * HTStyleFree ARGS1 (HTStyle *,self)
|
|
{
|
|
if (self->name) free(self->name);
|
|
if (self->SGMLTag) free(self->SGMLTag);
|
|
free(self);
|
|
return 0;
|
|
}
|
|
|
|
|
|
#ifdef SUPPRESS /* Only on the NeXT */
|
|
/* Read a style from a stream (without its name)
|
|
** --------------------------
|
|
**
|
|
** Reads a style with paragraph information from a stream.
|
|
** The style name is not read or written by these routines.
|
|
*/
|
|
#define NONE_STRING "(None)"
|
|
#define HTStream NXStream
|
|
|
|
HTStyle * HTStyleRead (HTStyle * style, HTStream * stream)
|
|
{
|
|
char myTag[STYLE_NAME_LENGTH];
|
|
char fontName[STYLE_NAME_LENGTH];
|
|
NXTextStyle *p;
|
|
int tab;
|
|
int gotpara; /* flag: have we got a paragraph definition? */
|
|
|
|
NXScanf(stream, "%s%s%f%d",
|
|
myTag,
|
|
fontName,
|
|
&style->fontSize,
|
|
&gotpara);
|
|
if (gotpara) {
|
|
if (!style->paragraph) {
|
|
style->paragraph = malloc(sizeof(*(style->paragraph)));
|
|
style->paragraph->tabs = 0;
|
|
}
|
|
p = style->paragraph;
|
|
NXScanf(stream, "%f%f%f%f%hd%f%f%hd",
|
|
&p->indent1st,
|
|
&p->indent2nd,
|
|
&p->lineHt,
|
|
&p->descentLine,
|
|
&p->alignment,
|
|
&style->spaceBefore,
|
|
&style->spaceAfter,
|
|
&p->numTabs);
|
|
if (p->tabs) free(p->tabs);
|
|
p->tabs = malloc(p->numTabs * sizeof(p->tabs[0]));
|
|
for (tab=0; tab < p->numTabs; tab++) {
|
|
NXScanf(stream, "%hd%f",
|
|
&p->tabs[tab].kind,
|
|
&p->tabs[tab].x);
|
|
}
|
|
} else { /* No paragraph */
|
|
if (style->paragraph) {
|
|
free(style->paragraph);
|
|
style->paragraph = 0;
|
|
}
|
|
} /* if no paragraph */
|
|
StrAllocCopy(style->SGMLTag, myTag);
|
|
if (strcmp(fontName, NONE_STRING)==0)
|
|
style->font = 0;
|
|
else
|
|
style->font = [Font newFont:fontName size:style->fontSize];
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
/* Write a style to a stream in a compatible way
|
|
*/
|
|
HTStyle * HTStyleWrite (HTStyle * style, NXStream * stream)
|
|
{
|
|
int tab;
|
|
NXTextStyle *p = style->paragraph;
|
|
NXPrintf(stream, "%s %s %f %d\n",
|
|
style->SGMLTag,
|
|
style->font ? [style->font name] : NONE_STRING,
|
|
style->fontSize,
|
|
p!=0);
|
|
|
|
if (p) {
|
|
NXPrintf(stream, "\t%f %f %f %f %d %f %f\t%d\n",
|
|
p->indent1st,
|
|
p->indent2nd,
|
|
p->lineHt,
|
|
p->descentLine,
|
|
p->alignment,
|
|
style->spaceBefore,
|
|
style->spaceAfter,
|
|
p->numTabs);
|
|
|
|
for (tab=0; tab < p->numTabs; tab++)
|
|
NXPrintf(stream, "\t%d %f\n",
|
|
p->tabs[tab].kind,
|
|
p->tabs[tab].x);
|
|
}
|
|
return style;
|
|
}
|
|
|
|
|
|
/* Write a style to stdout for diagnostics
|
|
*/
|
|
HTStyle * HTStyleDump (HTStyle * style)
|
|
{
|
|
int tab;
|
|
NXTextStyle *p = style->paragraph;
|
|
printf("Style %d `%s' SGML:%s. Font %s %.1f point.\n",
|
|
style,
|
|
style->name,
|
|
style->SGMLTag,
|
|
[style->font name],
|
|
style->fontSize);
|
|
if (p) {
|
|
printf(
|
|
"\tIndents: first=%.0f others=%.0f, Height=%.1f Desc=%.1f\n"
|
|
"\tAlign=%d, %d tabs. (%.0f before, %.0f after)\n",
|
|
p->indent1st,
|
|
p->indent2nd,
|
|
p->lineHt,
|
|
p->descentLine,
|
|
p->alignment,
|
|
p->numTabs,
|
|
style->spaceBefore,
|
|
style->spaceAfter);
|
|
|
|
for (tab=0; tab < p->numTabs; tab++) {
|
|
printf("\t\tTab kind=%d at %.0f\n",
|
|
p->tabs[tab].kind,
|
|
p->tabs[tab].x);
|
|
}
|
|
printf("\n");
|
|
} /* if paragraph */
|
|
return style;
|
|
}
|
|
#endif
|
|
|
|
|
|
/* StyleSheet Functions
|
|
** ====================
|
|
*/
|
|
|
|
/* Searching for styles:
|
|
*/
|
|
HTStyle * HTStyleNamed ARGS2 (HTStyleSheet *,self, CONST char *,name)
|
|
{
|
|
HTStyle * scan;
|
|
for (scan=self->styles; scan; scan=scan->next)
|
|
if (0==strcmp(scan->name, name)) return scan;
|
|
if (TRACE) fprintf(stderr, "StyleSheet: No style named `%s'\n", name);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef NEXT_SUPRESS /* Not in general common code */
|
|
|
|
HTStyle * HTStyleMatching (HTStyleSheet * self, HTStyle *style)
|
|
{
|
|
HTStyle * scan;
|
|
for (scan=self->styles; scan; scan=scan->next)
|
|
if (scan->paragraph == para) return scan;
|
|
return 0;
|
|
}
|
|
|
|
/* Find the style which best fits a given run
|
|
** ------------------------------------------
|
|
**
|
|
** This heuristic is used for guessing the style for a run of
|
|
** text which has been pasted in. In order, we try:
|
|
**
|
|
** A style whose paragraph structure is actually used by the run.
|
|
** A style matching in font
|
|
** A style matching in paragraph style exactly
|
|
** A style matching in paragraph to a degree
|
|
*/
|
|
|
|
HTStyle * HTStyleForRun (HTStyleSheet *self, NXRun *run)
|
|
{
|
|
HTStyle * scan;
|
|
HTStyle * best = 0;
|
|
int bestMatch = 0;
|
|
NXTextStyle * rp = run->paraStyle;
|
|
for (scan=self->styles; scan; scan=scan->next)
|
|
if (scan->paragraph == run->paraStyle) return scan; /* Exact */
|
|
|
|
for (scan=self->styles; scan; scan=scan->next){
|
|
NXTextStyle * sp = scan->paragraph;
|
|
if (sp) {
|
|
int match = 0;
|
|
if (sp->indent1st == rp->indent1st) match = match+1;
|
|
if (sp->indent2nd == rp->indent2nd) match = match+2;
|
|
if (sp->lineHt == rp->lineHt) match = match+1;
|
|
if (sp->numTabs == rp->numTabs) match = match+1;
|
|
if (sp->alignment == rp->alignment) match = match+3;
|
|
if (scan->font == run->font) match = match+10;
|
|
if (match>bestMatch) {
|
|
best=scan;
|
|
bestMatch=match;
|
|
}
|
|
}
|
|
}
|
|
if (TRACE) fprintf(stderr, "HTStyleForRun: Best match for style is %d out of 18\n",
|
|
bestMatch);
|
|
return best;
|
|
}
|
|
#endif
|
|
|
|
|
|
/* Add a style to a sheet
|
|
** ----------------------
|
|
*/
|
|
HTStyleSheet * HTStyleSheetAddStyle ARGS2
|
|
(HTStyleSheet *,self, HTStyle *,style)
|
|
{
|
|
style->next = 0; /* The style will go on the end */
|
|
if (!self->styles) {
|
|
self->styles = style;
|
|
} else {
|
|
HTStyle * scan;
|
|
for(scan=self->styles; scan->next; scan=scan->next); /* Find end */
|
|
scan->next=style;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
|
|
/* Remove the given object from a style sheet if it exists
|
|
*/
|
|
HTStyleSheet * HTStyleSheetRemoveStyle ARGS2
|
|
(HTStyleSheet *,self, HTStyle *,style)
|
|
{
|
|
if (self->styles == style) {
|
|
self->styles = style->next;
|
|
return self;
|
|
} else {
|
|
HTStyle * scan;
|
|
for(scan = self->styles; scan; scan = scan->next) {
|
|
if (scan->next == style) {
|
|
scan->next = style->next;
|
|
return self;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Create new style sheet
|
|
*/
|
|
|
|
HTStyleSheet * HTStyleSheetNew NOARGS
|
|
{
|
|
HTStyleSheet * self = (HTStyleSheet *)malloc(sizeof(*self));
|
|
|
|
memset((void*)self, 0, sizeof(*self)); /* ANSI */
|
|
/* Harbison c ref man says (char*)self
|
|
but k&r ansii and abc books and Think_C say (void*) */
|
|
|
|
/* bzero(self, sizeof(*self)); */ /* BSD */
|
|
return self;
|
|
}
|
|
|
|
|
|
/* Free off a style sheet pointer
|
|
*/
|
|
HTStyleSheet * HTStyleSheetFree ARGS1 (HTStyleSheet *,self)
|
|
{
|
|
HTStyle * style;
|
|
while((style=self->styles)!=0) {
|
|
self->styles = style->next;
|
|
HTStyleFree(style);
|
|
}
|
|
free(self);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Read a stylesheet from a typed stream
|
|
** -------------------------------------
|
|
**
|
|
** Reads a style sheet from a stream. If new styles have the same names
|
|
** as existing styles, they replace the old ones without changing the ids.
|
|
*/
|
|
|
|
#ifdef NEXT_SUPRESS /* Only on the NeXT */
|
|
HTStyleSheet * HTStyleSheetRead(HTStyleSheet * self, NXStream * stream)
|
|
{
|
|
int numStyles;
|
|
int i;
|
|
HTStyle * style;
|
|
char styleName[80];
|
|
NXScanf(stream, " %d ", &numStyles);
|
|
if (TRACE) fprintf(stderr, "Stylesheet: Reading %d styles\n", numStyles);
|
|
for (i=0; i<numStyles; i++) {
|
|
NXScanf(stream, "%s", styleName);
|
|
style = HTStyleNamed(self, styleName);
|
|
if (!style) {
|
|
style = HTStyleNewNamed(styleName);
|
|
(void) HTStyleSheetAddStyle(self, style);
|
|
}
|
|
(void) HTStyleRead(style, stream);
|
|
if (TRACE) HTStyleDump(style);
|
|
}
|
|
return self;
|
|
}
|
|
|
|
/* Write a stylesheet to a typed stream
|
|
** ------------------------------------
|
|
**
|
|
** Writes a style sheet to a stream.
|
|
*/
|
|
|
|
HTStyleSheet * HTStyleSheetWrite(HTStyleSheet * self, NXStream * stream)
|
|
{
|
|
int numStyles = 0;
|
|
HTStyle * style;
|
|
|
|
for(style=self->styles; style; style=style->next) numStyles++;
|
|
NXPrintf(stream, "%d\n", numStyles);
|
|
|
|
if (TRACE) fprintf(stderr, "StyleSheet: Writing %d styles\n", numStyles);
|
|
for (style=self->styles; style; style=style->next) {
|
|
NXPrintf(stream, "%s ", style->name);
|
|
(void) HTStyleWrite(style, stream);
|
|
}
|
|
return self;
|
|
}
|
|
#endif
|