Annotation of libwww/Library/src/HTStyle.c, revision 2.24

2.10      frystyk     1: /*                                                                   HTStyle.c
                      2: **     STYLE IMPLEMENTATION FOR HYPERTEXT
                      3: **
2.14      frystyk     4: **     (c) COPYRIGHT MIT 1995.
2.10      frystyk     5: **     Please first read the full copyright statement in the file COPYRIGH.
2.24    ! frystyk     6: **     @(#) $Id: HTStyle.c,v 2.23 1996/04/12 17:48:56 frystyk Exp $
1.1       timbl       7: **
                      8: **     Styles allow the translation between a logical property
                      9: **     of a piece of text and its physical representation.
                     10: **
                     11: **     A StyleSheet is a collection of styles, defining the
                     12: **     translation necessary to
                     13: **     represent a document. It is a linked list of styles.
                     14: */
2.11      roeber     15: 
2.12      frystyk    16: /* Library include files */
2.24    ! frystyk    17: #include "wwwsys.h"
2.12      frystyk    18: #include "HTUtils.h"
                     19: #include "HTString.h"
1.1       timbl      20: #include "HTStyle.h"
                     21: 
2.7       timbl      22: 
                     23: /*     Local definition of style
                     24: **     -------------------------
                     25: */
                     26: /*      The Style Structure
                     27: **      -------------------
                     28: */
                     29: 
2.13      frystyk    30: typedef double HTCoord;
2.7       timbl      31: typedef int HTColor;
                     32: 
                     33: typedef struct {
                     34:     short               kind;           /* only NX_LEFTTAB implemented*/
                     35:     HTCoord             position;       /* x coordinate for stop */
                     36: } HTTabStop;
                     37: 
                     38: 
                     39: struct _HTStyle {
                     40: 
                     41: /*      Style management information
                     42: */
                     43:     struct _HTStyle     *next;          /* Link for putting into stylesheet */
                     44:     char *              name;           /* Style name */
                     45:     char *              SGMLTag;        /* Tag name to start */
                     46: 
                     47: 
                     48: /*      Character attributes    (a la NXRun)
                     49: */
                     50:     HTFont              font;           /* Font id */
                     51:     HTCoord             fontSize;       /* The size of font, not independent */
                     52:     HTColor             color;  /* text gray of current run */
                     53:     int                 superscript;    /* superscript (-sub) in points */
                     54: 
                     55:     HTAnchor            *anchor;        /* Anchor id if any, else zero */
                     56: 
                     57: /*      Paragraph Attribtes     (a la NXTextStyle)
                     58: */
                     59:     HTCoord             indent1st;      /* how far first line in paragraph is
                     60:                                  * indented */
                     61:     HTCoord             leftIndent;     /* how far second line is indented */
                     62:     HTCoord             rightIndent;    /* (Missing from NeXT version */
                     63:     short               alignment;      /* quad justification */
                     64:     HTCoord             lineHt;         /* line height */
                     65:     HTCoord             descentLine;    /* descender bottom from baseline */
                     66:     HTTabStop           *tabs;          /* array of tab stops, 0 terminated */
                     67: 
                     68:     BOOL                wordWrap;       /* Yes means wrap at space not char */
                     69:     BOOL                freeFormat;     /* Yes means \n is just white space */
                     70:     HTCoord             spaceBefore;    /* Omissions from NXTextStyle */
                     71:     HTCoord             spaceAfter;
                     72:     int                 paraFlags;      /* Paragraph flags, bits as follows: */
                     73: 
                     74: #define PARA_KEEP       1       /* Do not break page within this paragraph */
                     75: #define PARA_WITH_NEXT  2       /* Do not break page after this paragraph */
                     76: 
                     77: #define HT_JUSTIFY 0            /* For alignment */
                     78: #define HT_LEFT 1
                     79: #define HT_RIGHT 2
                     80: #define HT_CENTER 3
                     81: };
                     82: 
                     83: 
1.1       timbl      84: /*     Create a new style
                     85: */
2.18      frystyk    86: PUBLIC HTStyle* HTStyleNew (void)
1.1       timbl      87: {
2.20      frystyk    88:     HTStyle *style;
                     89:     if ((style = (HTStyle  *) HT_CALLOC(1, sizeof(HTStyle))) == NULL)
                     90:         HT_OUTOFMEM("HTStyleNew");
2.15      frystyk    91:     return style;
1.1       timbl      92: }
                     93: 
                     94: /*     Create a new style with a name
                     95: */
2.22      frystyk    96: PUBLIC HTStyle* HTStyleNewNamed  (const char *name)
1.1       timbl      97: {
                     98:     HTStyle * self = HTStyleNew();
                     99:     StrAllocCopy(self->name, name);
                    100:     return self;
                    101: }
                    102: 
                    103: 
                    104: /*     Free a style
                    105: */
2.18      frystyk   106: PUBLIC HTStyle * HTStyleFree  (HTStyle *self)
1.1       timbl     107: {
2.20      frystyk   108:     if (self->name) HT_FREE(self->name);
                    109:     if (self->SGMLTag) HT_FREE(self->SGMLTag);
                    110:     HT_FREE(self);
1.1       timbl     111:     return 0;
                    112: }
                    113: 
                    114: 
                    115: #ifdef SUPPRESS  /* Only on the NeXT */
                    116: /*     Read a style from a stream      (without its name)
                    117: **     --------------------------
                    118: **
                    119: **     Reads a style with paragraph information from a stream.
                    120: **     The style name is not read or written by these routines.
                    121: */
                    122: #define NONE_STRING "(None)"
                    123: #define HTStream NXStream
                    124: 
                    125: HTStyle * HTStyleRead (HTStyle * style, HTStream * stream)
                    126: {
                    127:     char myTag[STYLE_NAME_LENGTH];
                    128:     char fontName[STYLE_NAME_LENGTH];
                    129:     NXTextStyle *p;
                    130:     int        tab;
                    131:     int gotpara;               /* flag: have we got a paragraph definition? */
                    132:        
                    133:     NXScanf(stream, "%s%s%f%d",
                    134:        myTag,
                    135:        fontName,
                    136:        &style->fontSize,
                    137:        &gotpara);
                    138:     if (gotpara) {
                    139:        if (!style->paragraph) {
2.20      frystyk   140:            if ((style->paragraph = HT_MALLOC(sizeof(*(style->paragraph)))) == NULL)
                    141:                HT_OUTOFMEM("paragraph");
1.1       timbl     142:            style->paragraph->tabs = 0;
                    143:        }
                    144:        p = style->paragraph;
                    145:        NXScanf(stream, "%f%f%f%f%hd%f%f%hd",
                    146:            &p->indent1st,
                    147:            &p->indent2nd,
                    148:            &p->lineHt,
                    149:            &p->descentLine,
                    150:            &p->alignment,
                    151:            &style->spaceBefore,
                    152:            &style->spaceAfter,
                    153:            &p->numTabs);
2.20      frystyk   154:        if (p->tabs) HT_FREE(p->tabs);
                    155:        if ((p->tabs = HT_MALLOC(p->numTabs * sizeof(p->tabs[0]))) == NULL)
                    156:            HT_OUTOFMEM("tabs");
1.1       timbl     157:        for (tab=0; tab < p->numTabs; tab++) {
                    158:            NXScanf(stream, "%hd%f",
                    159:                    &p->tabs[tab].kind,
                    160:                    &p->tabs[tab].x);
                    161:        }
                    162:     } else { /* No paragraph */
                    163:         if (style->paragraph) {
2.20      frystyk   164:            HT_FREE(style->paragraph);
1.1       timbl     165:            style->paragraph = 0;
                    166:        }
                    167:     } /* if no paragraph */
                    168:     StrAllocCopy(style->SGMLTag, myTag);
                    169:     if (strcmp(fontName, NONE_STRING)==0)
                    170:         style->font = 0;
                    171:     else
                    172:         style->font = [Font newFont:fontName size:style->fontSize];
                    173:     return 0;
                    174: 
                    175: }
                    176: 
                    177: 
                    178: /*     Write a style to a stream in a compatible way
                    179: */
                    180: HTStyle * HTStyleWrite (HTStyle * style, NXStream * stream)
                    181: {
                    182:     int tab;
                    183:     NXTextStyle *p = style->paragraph;
                    184:     NXPrintf(stream, "%s %s %f %d\n",
                    185:        style->SGMLTag,
                    186:        style->font ? [style->font name] : NONE_STRING,
                    187:        style->fontSize,
                    188:        p!=0);
                    189: 
                    190:     if (p) {
                    191:        NXPrintf(stream, "\t%f %f %f %f %d %f %f\t%d\n",
                    192:            p->indent1st,
                    193:            p->indent2nd,
                    194:            p->lineHt,
                    195:            p->descentLine,
                    196:            p->alignment,
                    197:            style->spaceBefore,
                    198:            style->spaceAfter,
                    199:            p->numTabs);
                    200:            
                    201:        for (tab=0; tab < p->numTabs; tab++)
                    202:            NXPrintf(stream, "\t%d %f\n",
                    203:                    p->tabs[tab].kind,
                    204:                    p->tabs[tab].x);
                    205:        }
                    206:     return style;
                    207: }
                    208: 
                    209: 
                    210: /*     Write a style to stdout for diagnostics
                    211: */
                    212: HTStyle * HTStyleDump (HTStyle * style)
                    213: {
                    214:     int tab;
                    215:     NXTextStyle *p = style->paragraph;
2.21      eric      216:     HTTrace("Style %d `%s' SGML:%s. Font %s %.1f point.\n",
1.1       timbl     217:        style,
                    218:        style->name,
                    219:        style->SGMLTag,
                    220:        [style->font name],
                    221:        style->fontSize);
                    222:     if (p) {
2.21      eric      223:         HTTrace(
1.1       timbl     224:        "\tIndents: first=%.0f others=%.0f, Height=%.1f Desc=%.1f\n"
                    225:        "\tAlign=%d, %d tabs. (%.0f before, %.0f after)\n",
                    226:            p->indent1st,
                    227:            p->indent2nd,
                    228:            p->lineHt,
                    229:            p->descentLine,
                    230:            p->alignment,
                    231:            p->numTabs,
                    232:            style->spaceBefore,
                    233:            style->spaceAfter);
                    234:            
                    235:        for (tab=0; tab < p->numTabs; tab++) {
2.21      eric      236:            HTTrace("\t\tTab kind=%d at %.0f\n",
1.1       timbl     237:                    p->tabs[tab].kind,
                    238:                    p->tabs[tab].x);
                    239:        }
2.21      eric      240:        HTTrace("\n");
1.1       timbl     241:     } /* if paragraph */
                    242:     return style;
                    243: }
                    244: #endif
                    245: 
                    246: 
                    247: /*                     StyleSheet Functions
                    248: **                     ====================
                    249: */
                    250: 
                    251: /*     Searching for styles:
                    252: */
2.22      frystyk   253: HTStyle * HTStyleNamed  (HTStyleSheet *self, const char *name)
1.1       timbl     254: {
2.19      frystyk   255:     if (self && name) {                                     /* added by HWL 11/8/94 */
                    256:        HTStyle * scan;
                    257:        for (scan=self->styles; scan; scan=scan->next)
                    258:            if (!strcmp(scan->name, name)) return scan;
                    259:        if (SGML_TRACE)
2.21      eric      260:            HTTrace("StyleSheet.. No style named `%s'\n", name);
2.8       howcome   261:     }
2.9       frystyk   262:     return NULL;
1.1       timbl     263: }
                    264: 
                    265: #ifdef NEXT_SUPRESS            /* Not in general common code */
                    266: 
                    267: HTStyle * HTStyleMatching (HTStyleSheet * self, HTStyle *style)
                    268: {
                    269:     HTStyle * scan;
                    270:     for (scan=self->styles; scan; scan=scan->next)
                    271:         if (scan->paragraph == para) return scan;
                    272:     return 0;
                    273: }
                    274: 
                    275: /*     Find the style which best fits a given run
                    276: **     ------------------------------------------
                    277: **
                    278: **     This heuristic is used for guessing the style for a run of
                    279: **     text which has been pasted in. In order, we try:
                    280: **
                    281: **     A style whose paragraph structure is actually used by the run.
                    282: **     A style matching in font
                    283: **     A style matching in paragraph style exactly
                    284: **     A style matching in paragraph to a degree
                    285: */
                    286: 
                    287: HTStyle * HTStyleForRun (HTStyleSheet *self, NXRun *run)
                    288: {
                    289:     HTStyle * scan;
                    290:     HTStyle * best = 0;
                    291:     int        bestMatch = 0;
                    292:     NXTextStyle * rp = run->paraStyle;
                    293:     for (scan=self->styles; scan; scan=scan->next)
                    294:         if (scan->paragraph == run->paraStyle) return scan;    /* Exact */
                    295: 
                    296:     for (scan=self->styles; scan; scan=scan->next){
                    297:        NXTextStyle * sp = scan->paragraph;
                    298:        if (sp) {
                    299:            int match = 0;
                    300:            if (sp->indent1st ==        rp->indent1st)  match = match+1;
                    301:            if (sp->indent2nd ==        rp->indent2nd)  match = match+2;
                    302:            if (sp->lineHt ==           rp->lineHt)     match = match+1;
                    303:            if (sp->numTabs ==          rp->numTabs)    match = match+1;
                    304:            if (sp->alignment ==        rp->alignment)  match = match+3;
                    305:            if (scan->font ==           run->font)      match = match+10;
                    306:            if (match>bestMatch) {
                    307:                    best=scan;
                    308:                    bestMatch=match;
                    309:            }
                    310:        }
                    311:     }
2.21      eric      312:     if (WWWTRACE) HTTrace("HTStyleForRun: Best match for style is %d out of 18\n",
1.1       timbl     313:                         bestMatch);
                    314:     return best;
                    315: }
                    316: #endif
                    317: 
                    318: 
                    319: /*     Add a style to a sheet
                    320: **     ----------------------
                    321: */
2.18      frystyk   322: HTStyleSheet * HTStyleSheetAddStyle 
                    323:   (HTStyleSheet *self, HTStyle *style)
1.1       timbl     324: {
                    325:     style->next = 0;           /* The style will go on the end */
                    326:     if (!self->styles) {
                    327:        self->styles = style;
                    328:     } else {
                    329:        HTStyle * scan;
                    330:         for(scan=self->styles; scan->next; scan=scan->next); /* Find end */
                    331:        scan->next=style;
                    332:     }
                    333:     return self;
                    334: }
                    335: 
                    336: 
                    337: /*     Remove the given object from a style sheet if it exists
                    338: */
2.18      frystyk   339: HTStyleSheet * HTStyleSheetRemoveStyle 
                    340:   (HTStyleSheet *self, HTStyle *style)
1.1       timbl     341: {
2.6       luotonen  342:     if (self->styles == style) {
1.1       timbl     343:        self->styles = style->next;
                    344:        return self;
                    345:     } else {
                    346:        HTStyle * scan;
                    347:        for(scan = self->styles; scan; scan = scan->next) {
2.6       luotonen  348:            if (scan->next == style) {
1.1       timbl     349:                scan->next = style->next;
                    350:                return self;
                    351:            }
                    352:        }
                    353:     }
                    354:     return 0;
                    355: }
                    356: 
                    357: /*     Create new style sheet
                    358: */
                    359: 
2.18      frystyk   360: HTStyleSheet * HTStyleSheetNew (void)
1.1       timbl     361: {
2.20      frystyk   362:     HTStyleSheet * style;
                    363:     if ((style = (HTStyleSheet  *) HT_CALLOC(1, sizeof(HTStyleSheet))) == NULL)
                    364:         HT_OUTOFMEM("HTStyleSheetNew");
2.15      frystyk   365:     return style;
1.1       timbl     366: }
                    367: 
                    368: 
                    369: /*     Free off a style sheet pointer
                    370: */
2.18      frystyk   371: HTStyleSheet * HTStyleSheetFree  (HTStyleSheet *self)
1.1       timbl     372: {
                    373:     HTStyle * style;
                    374:     while((style=self->styles)!=0) {
                    375:         self->styles = style->next;
                    376:        HTStyleFree(style);
                    377:     }
2.20      frystyk   378:     HT_FREE(self);
1.1       timbl     379:     return 0;
                    380: }
                    381: 
                    382: 
                    383: /*     Read a stylesheet from a typed stream
                    384: **     -------------------------------------
                    385: **
                    386: **     Reads a style sheet from a stream.  If new styles have the same names
                    387: **     as existing styles, they replace the old ones without changing the ids.
                    388: */
                    389: 
                    390: #ifdef NEXT_SUPRESS  /* Only on the NeXT */
                    391: HTStyleSheet * HTStyleSheetRead(HTStyleSheet * self, NXStream * stream)
                    392: {
                    393:     int numStyles;
                    394:     int i;
                    395:     HTStyle * style;
                    396:     char styleName[80];
                    397:     NXScanf(stream, " %d ", &numStyles);
2.21      eric      398:     if (WWWTRACE) HTTrace("Stylesheet: Reading %d styles\n", numStyles);
1.1       timbl     399:     for (i=0; i<numStyles; i++) {
                    400:         NXScanf(stream, "%s", styleName);
                    401:         style = HTStyleNamed(self, styleName);
                    402:        if (!style) {
                    403:            style = HTStyleNewNamed(styleName);
                    404:            (void) HTStyleSheetAddStyle(self, style);
                    405:        }
                    406:        (void) HTStyleRead(style, stream);
2.16      frystyk   407:        if (WWWTRACE) HTStyleDump(style);
1.1       timbl     408:     }
                    409:     return self;
                    410: }
                    411: 
                    412: /*     Write a stylesheet to a typed stream
                    413: **     ------------------------------------
                    414: **
                    415: **     Writes a style sheet to a stream.
                    416: */
                    417: 
                    418: HTStyleSheet * HTStyleSheetWrite(HTStyleSheet * self, NXStream * stream)
                    419: {
                    420:     int numStyles = 0;
                    421:     HTStyle * style;
                    422:     
                    423:     for(style=self->styles; style; style=style->next) numStyles++;
                    424:     NXPrintf(stream, "%d\n", numStyles);
                    425:     
2.21      eric      426:     if (WWWTRACE) HTTrace("StyleSheet: Writing %d styles\n", numStyles);
1.1       timbl     427:     for (style=self->styles; style; style=style->next) {
                    428:         NXPrintf(stream, "%s ", style->name);
                    429:        (void) HTStyleWrite(style, stream);
                    430:     }
                    431:     return self;
                    432: }
                    433: #endif

Webmaster