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