Annotation of libwww/Library/src/HTStyle.c, revision 2.18
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.
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.11 roeber 14:
2.12 frystyk 15: /* Library include files */
16: #include "tcp.h"
17: #include "HTUtils.h"
18: #include "HTString.h"
1.1 timbl 19: #include "HTStyle.h"
20:
2.7 timbl 21:
22: /* Local definition of style
23: ** -------------------------
24: */
25: /* The Style Structure
26: ** -------------------
27: */
28:
2.13 frystyk 29: typedef double HTCoord;
2.7 timbl 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: */
2.18 ! frystyk 85: PUBLIC HTStyle* HTStyleNew (void)
1.1 timbl 86: {
2.15 frystyk 87: HTStyle *style = (HTStyle *) calloc(1, sizeof(HTStyle));
88: if (!style) outofmem(__FILE__, "HTStyleNew");
89: return style;
1.1 timbl 90: }
91:
92: /* Create a new style with a name
93: */
2.18 ! frystyk 94: PUBLIC HTStyle* HTStyleNewNamed (CONST char *name)
1.1 timbl 95: {
96: HTStyle * self = HTStyleNew();
97: StrAllocCopy(self->name, name);
98: return self;
99: }
100:
101:
102: /* Free a style
103: */
2.18 ! frystyk 104: PUBLIC HTStyle * HTStyleFree (HTStyle *self)
1.1 timbl 105: {
106: if (self->name) free(self->name);
107: if (self->SGMLTag) free(self->SGMLTag);
108: free(self);
109: return 0;
110: }
111:
112:
113: #ifdef SUPPRESS /* Only on the NeXT */
114: /* Read a style from a stream (without its name)
115: ** --------------------------
116: **
117: ** Reads a style with paragraph information from a stream.
118: ** The style name is not read or written by these routines.
119: */
120: #define NONE_STRING "(None)"
121: #define HTStream NXStream
122:
123: HTStyle * HTStyleRead (HTStyle * style, HTStream * stream)
124: {
125: char myTag[STYLE_NAME_LENGTH];
126: char fontName[STYLE_NAME_LENGTH];
127: NXTextStyle *p;
128: int tab;
129: int gotpara; /* flag: have we got a paragraph definition? */
130:
131: NXScanf(stream, "%s%s%f%d",
132: myTag,
133: fontName,
134: &style->fontSize,
135: &gotpara);
136: if (gotpara) {
137: if (!style->paragraph) {
138: style->paragraph = malloc(sizeof(*(style->paragraph)));
139: style->paragraph->tabs = 0;
140: }
141: p = style->paragraph;
142: NXScanf(stream, "%f%f%f%f%hd%f%f%hd",
143: &p->indent1st,
144: &p->indent2nd,
145: &p->lineHt,
146: &p->descentLine,
147: &p->alignment,
148: &style->spaceBefore,
149: &style->spaceAfter,
150: &p->numTabs);
151: if (p->tabs) free(p->tabs);
152: p->tabs = malloc(p->numTabs * sizeof(p->tabs[0]));
153: for (tab=0; tab < p->numTabs; tab++) {
154: NXScanf(stream, "%hd%f",
155: &p->tabs[tab].kind,
156: &p->tabs[tab].x);
157: }
158: } else { /* No paragraph */
159: if (style->paragraph) {
160: free(style->paragraph);
161: style->paragraph = 0;
162: }
163: } /* if no paragraph */
164: StrAllocCopy(style->SGMLTag, myTag);
165: if (strcmp(fontName, NONE_STRING)==0)
166: style->font = 0;
167: else
168: style->font = [Font newFont:fontName size:style->fontSize];
169: return 0;
170:
171: }
172:
173:
174: /* Write a style to a stream in a compatible way
175: */
176: HTStyle * HTStyleWrite (HTStyle * style, NXStream * stream)
177: {
178: int tab;
179: NXTextStyle *p = style->paragraph;
180: NXPrintf(stream, "%s %s %f %d\n",
181: style->SGMLTag,
182: style->font ? [style->font name] : NONE_STRING,
183: style->fontSize,
184: p!=0);
185:
186: if (p) {
187: NXPrintf(stream, "\t%f %f %f %f %d %f %f\t%d\n",
188: p->indent1st,
189: p->indent2nd,
190: p->lineHt,
191: p->descentLine,
192: p->alignment,
193: style->spaceBefore,
194: style->spaceAfter,
195: p->numTabs);
196:
197: for (tab=0; tab < p->numTabs; tab++)
198: NXPrintf(stream, "\t%d %f\n",
199: p->tabs[tab].kind,
200: p->tabs[tab].x);
201: }
202: return style;
203: }
204:
205:
206: /* Write a style to stdout for diagnostics
207: */
208: HTStyle * HTStyleDump (HTStyle * style)
209: {
210: int tab;
211: NXTextStyle *p = style->paragraph;
2.17 frystyk 212: TTYPrint(TDEST, "Style %d `%s' SGML:%s. Font %s %.1f point.\n",
1.1 timbl 213: style,
214: style->name,
215: style->SGMLTag,
216: [style->font name],
217: style->fontSize);
218: if (p) {
2.17 frystyk 219: TTYPrint(TDEST,
1.1 timbl 220: "\tIndents: first=%.0f others=%.0f, Height=%.1f Desc=%.1f\n"
221: "\tAlign=%d, %d tabs. (%.0f before, %.0f after)\n",
222: p->indent1st,
223: p->indent2nd,
224: p->lineHt,
225: p->descentLine,
226: p->alignment,
227: p->numTabs,
228: style->spaceBefore,
229: style->spaceAfter);
230:
231: for (tab=0; tab < p->numTabs; tab++) {
2.17 frystyk 232: TTYPrint(TDEST, "\t\tTab kind=%d at %.0f\n",
1.1 timbl 233: p->tabs[tab].kind,
234: p->tabs[tab].x);
235: }
2.17 frystyk 236: TTYPrint(TDEST, "\n");
1.1 timbl 237: } /* if paragraph */
238: return style;
239: }
240: #endif
241:
242:
243: /* StyleSheet Functions
244: ** ====================
245: */
246:
247: /* Searching for styles:
248: */
2.18 ! frystyk 249: HTStyle * HTStyleNamed (HTStyleSheet *self, CONST char *name)
1.1 timbl 250: {
251: HTStyle * scan;
2.8 howcome 252:
253: if (!self) { /* added by HWL 11/8/94 */
2.17 frystyk 254: if (WWWTRACE) TTYPrint(TDEST, "HTStyleNamed.. Called with NULL pointer\n");
2.9 frystyk 255: return NULL;
2.8 howcome 256: }
257:
1.1 timbl 258: for (scan=self->styles; scan; scan=scan->next)
259: if (0==strcmp(scan->name, name)) return scan;
2.17 frystyk 260: if (WWWTRACE) TTYPrint(TDEST, "StyleSheet: No style named `%s'\n", name);
2.9 frystyk 261: return NULL;
1.1 timbl 262: }
263:
264: #ifdef NEXT_SUPRESS /* Not in general common code */
265:
266: HTStyle * HTStyleMatching (HTStyleSheet * self, HTStyle *style)
267: {
268: HTStyle * scan;
269: for (scan=self->styles; scan; scan=scan->next)
270: if (scan->paragraph == para) return scan;
271: return 0;
272: }
273:
274: /* Find the style which best fits a given run
275: ** ------------------------------------------
276: **
277: ** This heuristic is used for guessing the style for a run of
278: ** text which has been pasted in. In order, we try:
279: **
280: ** A style whose paragraph structure is actually used by the run.
281: ** A style matching in font
282: ** A style matching in paragraph style exactly
283: ** A style matching in paragraph to a degree
284: */
285:
286: HTStyle * HTStyleForRun (HTStyleSheet *self, NXRun *run)
287: {
288: HTStyle * scan;
289: HTStyle * best = 0;
290: int bestMatch = 0;
291: NXTextStyle * rp = run->paraStyle;
292: for (scan=self->styles; scan; scan=scan->next)
293: if (scan->paragraph == run->paraStyle) return scan; /* Exact */
294:
295: for (scan=self->styles; scan; scan=scan->next){
296: NXTextStyle * sp = scan->paragraph;
297: if (sp) {
298: int match = 0;
299: if (sp->indent1st == rp->indent1st) match = match+1;
300: if (sp->indent2nd == rp->indent2nd) match = match+2;
301: if (sp->lineHt == rp->lineHt) match = match+1;
302: if (sp->numTabs == rp->numTabs) match = match+1;
303: if (sp->alignment == rp->alignment) match = match+3;
304: if (scan->font == run->font) match = match+10;
305: if (match>bestMatch) {
306: best=scan;
307: bestMatch=match;
308: }
309: }
310: }
2.17 frystyk 311: if (WWWTRACE) TTYPrint(TDEST, "HTStyleForRun: Best match for style is %d out of 18\n",
1.1 timbl 312: bestMatch);
313: return best;
314: }
315: #endif
316:
317:
318: /* Add a style to a sheet
319: ** ----------------------
320: */
2.18 ! frystyk 321: HTStyleSheet * HTStyleSheetAddStyle
! 322: (HTStyleSheet *self, HTStyle *style)
1.1 timbl 323: {
324: style->next = 0; /* The style will go on the end */
325: if (!self->styles) {
326: self->styles = style;
327: } else {
328: HTStyle * scan;
329: for(scan=self->styles; scan->next; scan=scan->next); /* Find end */
330: scan->next=style;
331: }
332: return self;
333: }
334:
335:
336: /* Remove the given object from a style sheet if it exists
337: */
2.18 ! frystyk 338: HTStyleSheet * HTStyleSheetRemoveStyle
! 339: (HTStyleSheet *self, HTStyle *style)
1.1 timbl 340: {
2.6 luotonen 341: if (self->styles == style) {
1.1 timbl 342: self->styles = style->next;
343: return self;
344: } else {
345: HTStyle * scan;
346: for(scan = self->styles; scan; scan = scan->next) {
2.6 luotonen 347: if (scan->next == style) {
1.1 timbl 348: scan->next = style->next;
349: return self;
350: }
351: }
352: }
353: return 0;
354: }
355:
356: /* Create new style sheet
357: */
358:
2.18 ! frystyk 359: HTStyleSheet * HTStyleSheetNew (void)
1.1 timbl 360: {
2.15 frystyk 361: HTStyleSheet * style = (HTStyleSheet *) calloc(1, sizeof(HTStyleSheet));
362: if (!style) outofmem(__FILE__, "HTStyleSheetNew");
363: return style;
1.1 timbl 364: }
365:
366:
367: /* Free off a style sheet pointer
368: */
2.18 ! frystyk 369: HTStyleSheet * HTStyleSheetFree (HTStyleSheet *self)
1.1 timbl 370: {
371: HTStyle * style;
372: while((style=self->styles)!=0) {
373: self->styles = style->next;
374: HTStyleFree(style);
375: }
376: free(self);
377: return 0;
378: }
379:
380:
381: /* Read a stylesheet from a typed stream
382: ** -------------------------------------
383: **
384: ** Reads a style sheet from a stream. If new styles have the same names
385: ** as existing styles, they replace the old ones without changing the ids.
386: */
387:
388: #ifdef NEXT_SUPRESS /* Only on the NeXT */
389: HTStyleSheet * HTStyleSheetRead(HTStyleSheet * self, NXStream * stream)
390: {
391: int numStyles;
392: int i;
393: HTStyle * style;
394: char styleName[80];
395: NXScanf(stream, " %d ", &numStyles);
2.17 frystyk 396: if (WWWTRACE) TTYPrint(TDEST, "Stylesheet: Reading %d styles\n", numStyles);
1.1 timbl 397: for (i=0; i<numStyles; i++) {
398: NXScanf(stream, "%s", styleName);
399: style = HTStyleNamed(self, styleName);
400: if (!style) {
401: style = HTStyleNewNamed(styleName);
402: (void) HTStyleSheetAddStyle(self, style);
403: }
404: (void) HTStyleRead(style, stream);
2.16 frystyk 405: if (WWWTRACE) HTStyleDump(style);
1.1 timbl 406: }
407: return self;
408: }
409:
410: /* Write a stylesheet to a typed stream
411: ** ------------------------------------
412: **
413: ** Writes a style sheet to a stream.
414: */
415:
416: HTStyleSheet * HTStyleSheetWrite(HTStyleSheet * self, NXStream * stream)
417: {
418: int numStyles = 0;
419: HTStyle * style;
420:
421: for(style=self->styles; style; style=style->next) numStyles++;
422: NXPrintf(stream, "%d\n", numStyles);
423:
2.17 frystyk 424: if (WWWTRACE) TTYPrint(TDEST, "StyleSheet: Writing %d styles\n", numStyles);
1.1 timbl 425: for (style=self->styles; style; style=style->next) {
426: NXPrintf(stream, "%s ", style->name);
427: (void) HTStyleWrite(style, stream);
428: }
429: return self;
430: }
431: #endif
Webmaster