Annotation of libwww/Library/src/HTStyle.c, revision 2.20
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.20 ! frystyk 87: HTStyle *style;
! 88: if ((style = (HTStyle *) HT_CALLOC(1, sizeof(HTStyle))) == NULL)
! 89: HT_OUTOFMEM("HTStyleNew");
2.15 frystyk 90: return style;
1.1 timbl 91: }
92:
93: /* Create a new style with a name
94: */
2.18 frystyk 95: PUBLIC HTStyle* HTStyleNewNamed (CONST char *name)
1.1 timbl 96: {
97: HTStyle * self = HTStyleNew();
98: StrAllocCopy(self->name, name);
99: return self;
100: }
101:
102:
103: /* Free a style
104: */
2.18 frystyk 105: PUBLIC HTStyle * HTStyleFree (HTStyle *self)
1.1 timbl 106: {
2.20 ! frystyk 107: if (self->name) HT_FREE(self->name);
! 108: if (self->SGMLTag) HT_FREE(self->SGMLTag);
! 109: HT_FREE(self);
1.1 timbl 110: return 0;
111: }
112:
113:
114: #ifdef SUPPRESS /* Only on the NeXT */
115: /* Read a style from a stream (without its name)
116: ** --------------------------
117: **
118: ** Reads a style with paragraph information from a stream.
119: ** The style name is not read or written by these routines.
120: */
121: #define NONE_STRING "(None)"
122: #define HTStream NXStream
123:
124: HTStyle * HTStyleRead (HTStyle * style, HTStream * stream)
125: {
126: char myTag[STYLE_NAME_LENGTH];
127: char fontName[STYLE_NAME_LENGTH];
128: NXTextStyle *p;
129: int tab;
130: int gotpara; /* flag: have we got a paragraph definition? */
131:
132: NXScanf(stream, "%s%s%f%d",
133: myTag,
134: fontName,
135: &style->fontSize,
136: &gotpara);
137: if (gotpara) {
138: if (!style->paragraph) {
2.20 ! frystyk 139: if ((style->paragraph = HT_MALLOC(sizeof(*(style->paragraph)))) == NULL)
! 140: HT_OUTOFMEM("paragraph");
1.1 timbl 141: style->paragraph->tabs = 0;
142: }
143: p = style->paragraph;
144: NXScanf(stream, "%f%f%f%f%hd%f%f%hd",
145: &p->indent1st,
146: &p->indent2nd,
147: &p->lineHt,
148: &p->descentLine,
149: &p->alignment,
150: &style->spaceBefore,
151: &style->spaceAfter,
152: &p->numTabs);
2.20 ! frystyk 153: if (p->tabs) HT_FREE(p->tabs);
! 154: if ((p->tabs = HT_MALLOC(p->numTabs * sizeof(p->tabs[0]))) == NULL)
! 155: HT_OUTOFMEM("tabs");
1.1 timbl 156: for (tab=0; tab < p->numTabs; tab++) {
157: NXScanf(stream, "%hd%f",
158: &p->tabs[tab].kind,
159: &p->tabs[tab].x);
160: }
161: } else { /* No paragraph */
162: if (style->paragraph) {
2.20 ! frystyk 163: HT_FREE(style->paragraph);
1.1 timbl 164: style->paragraph = 0;
165: }
166: } /* if no paragraph */
167: StrAllocCopy(style->SGMLTag, myTag);
168: if (strcmp(fontName, NONE_STRING)==0)
169: style->font = 0;
170: else
171: style->font = [Font newFont:fontName size:style->fontSize];
172: return 0;
173:
174: }
175:
176:
177: /* Write a style to a stream in a compatible way
178: */
179: HTStyle * HTStyleWrite (HTStyle * style, NXStream * stream)
180: {
181: int tab;
182: NXTextStyle *p = style->paragraph;
183: NXPrintf(stream, "%s %s %f %d\n",
184: style->SGMLTag,
185: style->font ? [style->font name] : NONE_STRING,
186: style->fontSize,
187: p!=0);
188:
189: if (p) {
190: NXPrintf(stream, "\t%f %f %f %f %d %f %f\t%d\n",
191: p->indent1st,
192: p->indent2nd,
193: p->lineHt,
194: p->descentLine,
195: p->alignment,
196: style->spaceBefore,
197: style->spaceAfter,
198: p->numTabs);
199:
200: for (tab=0; tab < p->numTabs; tab++)
201: NXPrintf(stream, "\t%d %f\n",
202: p->tabs[tab].kind,
203: p->tabs[tab].x);
204: }
205: return style;
206: }
207:
208:
209: /* Write a style to stdout for diagnostics
210: */
211: HTStyle * HTStyleDump (HTStyle * style)
212: {
213: int tab;
214: NXTextStyle *p = style->paragraph;
2.17 frystyk 215: TTYPrint(TDEST, "Style %d `%s' SGML:%s. Font %s %.1f point.\n",
1.1 timbl 216: style,
217: style->name,
218: style->SGMLTag,
219: [style->font name],
220: style->fontSize);
221: if (p) {
2.17 frystyk 222: TTYPrint(TDEST,
1.1 timbl 223: "\tIndents: first=%.0f others=%.0f, Height=%.1f Desc=%.1f\n"
224: "\tAlign=%d, %d tabs. (%.0f before, %.0f after)\n",
225: p->indent1st,
226: p->indent2nd,
227: p->lineHt,
228: p->descentLine,
229: p->alignment,
230: p->numTabs,
231: style->spaceBefore,
232: style->spaceAfter);
233:
234: for (tab=0; tab < p->numTabs; tab++) {
2.17 frystyk 235: TTYPrint(TDEST, "\t\tTab kind=%d at %.0f\n",
1.1 timbl 236: p->tabs[tab].kind,
237: p->tabs[tab].x);
238: }
2.17 frystyk 239: TTYPrint(TDEST, "\n");
1.1 timbl 240: } /* if paragraph */
241: return style;
242: }
243: #endif
244:
245:
246: /* StyleSheet Functions
247: ** ====================
248: */
249:
250: /* Searching for styles:
251: */
2.18 frystyk 252: HTStyle * HTStyleNamed (HTStyleSheet *self, CONST char *name)
1.1 timbl 253: {
2.19 frystyk 254: if (self && name) { /* added by HWL 11/8/94 */
255: HTStyle * scan;
256: for (scan=self->styles; scan; scan=scan->next)
257: if (!strcmp(scan->name, name)) return scan;
258: if (SGML_TRACE)
259: TTYPrint(TDEST, "StyleSheet.. No style named `%s'\n", name);
2.8 howcome 260: }
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.20 ! frystyk 361: HTStyleSheet * style;
! 362: if ((style = (HTStyleSheet *) HT_CALLOC(1, sizeof(HTStyleSheet))) == NULL)
! 363: HT_OUTOFMEM("HTStyleSheetNew");
2.15 frystyk 364: return style;
1.1 timbl 365: }
366:
367:
368: /* Free off a style sheet pointer
369: */
2.18 frystyk 370: HTStyleSheet * HTStyleSheetFree (HTStyleSheet *self)
1.1 timbl 371: {
372: HTStyle * style;
373: while((style=self->styles)!=0) {
374: self->styles = style->next;
375: HTStyleFree(style);
376: }
2.20 ! frystyk 377: HT_FREE(self);
1.1 timbl 378: return 0;
379: }
380:
381:
382: /* Read a stylesheet from a typed stream
383: ** -------------------------------------
384: **
385: ** Reads a style sheet from a stream. If new styles have the same names
386: ** as existing styles, they replace the old ones without changing the ids.
387: */
388:
389: #ifdef NEXT_SUPRESS /* Only on the NeXT */
390: HTStyleSheet * HTStyleSheetRead(HTStyleSheet * self, NXStream * stream)
391: {
392: int numStyles;
393: int i;
394: HTStyle * style;
395: char styleName[80];
396: NXScanf(stream, " %d ", &numStyles);
2.17 frystyk 397: if (WWWTRACE) TTYPrint(TDEST, "Stylesheet: Reading %d styles\n", numStyles);
1.1 timbl 398: for (i=0; i<numStyles; i++) {
399: NXScanf(stream, "%s", styleName);
400: style = HTStyleNamed(self, styleName);
401: if (!style) {
402: style = HTStyleNewNamed(styleName);
403: (void) HTStyleSheetAddStyle(self, style);
404: }
405: (void) HTStyleRead(style, stream);
2.16 frystyk 406: if (WWWTRACE) HTStyleDump(style);
1.1 timbl 407: }
408: return self;
409: }
410:
411: /* Write a stylesheet to a typed stream
412: ** ------------------------------------
413: **
414: ** Writes a style sheet to a stream.
415: */
416:
417: HTStyleSheet * HTStyleSheetWrite(HTStyleSheet * self, NXStream * stream)
418: {
419: int numStyles = 0;
420: HTStyle * style;
421:
422: for(style=self->styles; style; style=style->next) numStyles++;
423: NXPrintf(stream, "%d\n", numStyles);
424:
2.17 frystyk 425: if (WWWTRACE) TTYPrint(TDEST, "StyleSheet: Writing %d styles\n", numStyles);
1.1 timbl 426: for (style=self->styles; style; style=style->next) {
427: NXPrintf(stream, "%s ", style->name);
428: (void) HTStyleWrite(style, stream);
429: }
430: return self;
431: }
432: #endif
Webmaster