earlybrowserreborn - Rev 1

Subversion Repositories:
Rev:
/*      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 = HT_FONT;
    self->color = HT_BLACK;
    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) printf("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) printf("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) printf("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) printf("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