/*
* $LynxId: HTStyle.c,v 1.16 2009/11/27 13:01:48 tom Exp $
*
* 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 <HTUtils.h>
#include <HTStyle.h>
#include <LYLeaks.h>
/* Create a new style
*/
HTStyle *HTStyleNew(void)
{
HTStyle *self = typecalloc(HTStyle);
if (self == NULL)
outofmem(__FILE__, "HTStyleNew");
return self;
}
/* Create a new style with a name
*/
HTStyle *HTStyleNewNamed(const char *name)
{
HTStyle *self = HTStyleNew();
StrAllocCopy(self->w_name, name);
self->id = -1; /* <0 */
return self;
}
/* Free a style
*/
HTStyle *HTStyleFree(HTStyle *self)
{
FREE(self->w_name);
FREE(self->w_SGMLTag);
FREE(self);
return NULL;
}
#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)));
if (!style->paragraph)
outofmem(__FILE__, "HTStyleRead");
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);
FREE(p->tabs);
p->tabs = malloc(p->numTabs * sizeof(p->tabs[0]));
if (!p->tabs)
outofmem(__FILE__, "HTStyleRead");
for (tab = 0; tab < p->numTabs; tab++) {
NXScanf(stream, "%hd%f",
&p->tabs[tab].kind,
&p->tabs[tab].x);
}
} else { /* No paragraph */
FREE(style->paragraph);
} /* 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 NULL;
}
/* 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_DUMP_FONT,
style,
style->name,
style->SGMLTag,
[style->font name],
style->fontSize);
if (p) {
printf(STYLE_DUMP_IDENT,
p->indent1st,
p->indent2nd,
p->lineHt,
p->descentLine);
printf(STYLE_DUMP_ALIGN,
p->alignment,
p->numTabs,
style->spaceBefore,
style->spaceAfter);
for (tab = 0; tab < p->numTabs; tab++) {
printf(STYLE_DUMP_TAB,
p->tabs[tab].kind,
p->tabs[tab].x);
}
printf("\n");
} /* if paragraph */
return style;
}
#endif /* SUPPRESS */
/* StyleSheet Functions
* ====================
*/
/* Searching for styles:
*/
HTStyle *HTStyleNamed(HTStyleSheet *self, const char *name)
{
HTStyle *scan;
for (scan = self->styles; scan; scan = scan->next)
if (0 == strcmp(GetHTStyleName(scan), name))
return scan;
CTRACE((tfp, "StyleSheet: No style named `%s'\n", name));
return NULL;
}
#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 NULL;
}
/* 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;
}
}
}
CTRACE((tfp, "HTStyleForRun: Best match for style is %d out of 18\n",
bestMatch));
return best;
}
#endif /* NEXT_SUPRESS */
/* Add a style to a sheet
* ----------------------
*/
HTStyleSheet *HTStyleSheetAddStyle(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(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 NULL;
}
/* Create new style sheet
*/
HTStyleSheet *HTStyleSheetNew(void)
{
HTStyleSheet *self = typecalloc(HTStyleSheet);
if (self == NULL)
outofmem(__FILE__, "HTStyleSheetNew");
return self;
}
/* Free off a style sheet pointer
*/
HTStyleSheet *HTStyleSheetFree(HTStyleSheet *self)
{
HTStyle *style;
while ((style = self->styles) != 0) {
self->styles = style->next;
HTStyleFree(style);
}
FREE(self);
return NULL;
}
/* 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);
CTRACE((tfp, "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);
CTRACE((tfp, "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 /* NEXT_SUPRESS */