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