1 /*
2 * $LynxId: HTStyle.c,v 1.16 2009/11/27 13:01:48 tom Exp $
3 *
4 * Style Implementation for Hypertext HTStyle.c
5 * ==================================
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 */
14
15 #include <HTUtils.h>
16 #include <HTStyle.h>
17
18 #include <LYLeaks.h>
19
20 /* Create a new style
21 */
HTStyleNew(void)22 HTStyle *HTStyleNew(void)
23 {
24 HTStyle *self = typecalloc(HTStyle);
25
26 if (self == NULL)
27 outofmem(__FILE__, "HTStyleNew");
28 return self;
29 }
30
31 /* Create a new style with a name
32 */
HTStyleNewNamed(const char * name)33 HTStyle *HTStyleNewNamed(const char *name)
34 {
35 HTStyle *self = HTStyleNew();
36
37 StrAllocCopy(self->w_name, name);
38 self->id = -1; /* <0 */
39 return self;
40 }
41
42 /* Free a style
43 */
HTStyleFree(HTStyle * self)44 HTStyle *HTStyleFree(HTStyle *self)
45 {
46 FREE(self->w_name);
47 FREE(self->w_SGMLTag);
48 FREE(self);
49 return NULL;
50 }
51
52 #ifdef SUPPRESS /* Only on the NeXT */
53 /* Read a style from a stream (without its name)
54 * --------------------------
55 *
56 * Reads a style with paragraph information from a stream.
57 * The style name is not read or written by these routines.
58 */
59 #define NONE_STRING "(None)"
60 #define HTStream NXStream
61
HTStyleRead(HTStyle * style,HTStream * stream)62 HTStyle *HTStyleRead(HTStyle *style, HTStream *stream)
63 {
64 char myTag[STYLE_NAME_LENGTH];
65 char fontName[STYLE_NAME_LENGTH];
66 NXTextStyle *p;
67 int tab;
68 int gotpara; /* flag: have we got a paragraph definition? */
69
70 NXScanf(stream, "%s%s%f%d",
71 myTag,
72 fontName,
73 &style->fontSize,
74 &gotpara);
75 if (gotpara) {
76 if (!style->paragraph) {
77 style->paragraph = malloc(sizeof(*(style->paragraph)));
78 if (!style->paragraph)
79 outofmem(__FILE__, "HTStyleRead");
80 style->paragraph->tabs = 0;
81 }
82 p = style->paragraph;
83 NXScanf(stream, "%f%f%f%f%hd%f%f%hd",
84 &p->indent1st,
85 &p->indent2nd,
86 &p->lineHt,
87 &p->descentLine,
88 &p->alignment,
89 &style->spaceBefore,
90 &style->spaceAfter,
91 &p->numTabs);
92 FREE(p->tabs);
93 p->tabs = malloc(p->numTabs * sizeof(p->tabs[0]));
94 if (!p->tabs)
95 outofmem(__FILE__, "HTStyleRead");
96 for (tab = 0; tab < p->numTabs; tab++) {
97 NXScanf(stream, "%hd%f",
98 &p->tabs[tab].kind,
99 &p->tabs[tab].x);
100 }
101 } else { /* No paragraph */
102 FREE(style->paragraph);
103 } /* if no paragraph */
104 StrAllocCopy(style->SGMLTag, myTag);
105 if (strcmp(fontName, NONE_STRING) == 0)
106 style->font = 0;
107 else
108 style->font =[Font newFont: fontName size:style->fontSize];
109 return NULL;
110 }
111
112 /* Write a style to a stream in a compatible way
113 */
HTStyleWrite(HTStyle * style,NXStream * stream)114 HTStyle *HTStyleWrite(HTStyle *style, NXStream * stream)
115 {
116 int tab;
117 NXTextStyle *p = style->paragraph;
118
119 NXPrintf(stream, "%s %s %f %d\n",
120 style->SGMLTag,
121 style->font ?[style->font name] : NONE_STRING,
122 style->fontSize,
123 p != 0);
124
125 if (p) {
126 NXPrintf(stream, "\t%f %f %f %f %d %f %f\t%d\n",
127 p->indent1st,
128 p->indent2nd,
129 p->lineHt,
130 p->descentLine,
131 p->alignment,
132 style->spaceBefore,
133 style->spaceAfter,
134 p->numTabs);
135
136 for (tab = 0; tab < p->numTabs; tab++)
137 NXPrintf(stream, "\t%d %f\n",
138 p->tabs[tab].kind,
139 p->tabs[tab].x);
140 }
141 return style;
142 }
143
144 /* Write a style to stdout for diagnostics
145 */
HTStyleDump(HTStyle * style)146 HTStyle *HTStyleDump(HTStyle *style)
147 {
148 int tab;
149 NXTextStyle *p = style->paragraph;
150
151 printf(STYLE_DUMP_FONT,
152 style,
153 style->name,
154 style->SGMLTag,
155 [style->font name],
156 style->fontSize);
157 if (p) {
158 printf(STYLE_DUMP_IDENT,
159 p->indent1st,
160 p->indent2nd,
161 p->lineHt,
162 p->descentLine);
163 printf(STYLE_DUMP_ALIGN,
164 p->alignment,
165 p->numTabs,
166 style->spaceBefore,
167 style->spaceAfter);
168
169 for (tab = 0; tab < p->numTabs; tab++) {
170 printf(STYLE_DUMP_TAB,
171 p->tabs[tab].kind,
172 p->tabs[tab].x);
173 }
174 printf("\n");
175 } /* if paragraph */
176 return style;
177 }
178 #endif /* SUPPRESS */
179
180 /* StyleSheet Functions
181 * ====================
182 */
183
184 /* Searching for styles:
185 */
HTStyleNamed(HTStyleSheet * self,const char * name)186 HTStyle *HTStyleNamed(HTStyleSheet *self, const char *name)
187 {
188 HTStyle *scan;
189
190 for (scan = self->styles; scan; scan = scan->next)
191 if (0 == strcmp(GetHTStyleName(scan), name))
192 return scan;
193 CTRACE((tfp, "StyleSheet: No style named `%s'\n", name));
194 return NULL;
195 }
196
197 #ifdef NEXT_SUPRESS /* Not in general common code */
198
HTStyleMatching(HTStyleSheet * self,HTStyle * style)199 HTStyle *HTStyleMatching(HTStyleSheet *self, HTStyle *style)
200 {
201 HTStyle *scan;
202
203 for (scan = self->styles; scan; scan = scan->next)
204 if (scan->paragraph == para)
205 return scan;
206 return NULL;
207 }
208
209 /* Find the style which best fits a given run
210 * ------------------------------------------
211 *
212 * This heuristic is used for guessing the style for a run of
213 * text which has been pasted in. In order, we try:
214 *
215 * A style whose paragraph structure is actually used by the run.
216 * A style matching in font
217 * A style matching in paragraph style exactly
218 * A style matching in paragraph to a degree
219 */
220
HTStyleForRun(HTStyleSheet * self,NXRun * run)221 HTStyle *HTStyleForRun(HTStyleSheet *self, NXRun * run)
222 {
223 HTStyle *scan;
224 HTStyle *best = 0;
225 int bestMatch = 0;
226 NXTextStyle *rp = run->paraStyle;
227
228 for (scan = self->styles; scan; scan = scan->next)
229 if (scan->paragraph == run->paraStyle)
230 return scan; /* Exact */
231
232 for (scan = self->styles; scan; scan = scan->next) {
233 NXTextStyle *sp = scan->paragraph;
234
235 if (sp) {
236 int match = 0;
237
238 if (sp->indent1st == rp->indent1st)
239 match = match + 1;
240 if (sp->indent2nd == rp->indent2nd)
241 match = match + 2;
242 if (sp->lineHt == rp->lineHt)
243 match = match + 1;
244 if (sp->numTabs == rp->numTabs)
245 match = match + 1;
246 if (sp->alignment == rp->alignment)
247 match = match + 3;
248 if (scan->font == run->font)
249 match = match + 10;
250 if (match > bestMatch) {
251 best = scan;
252 bestMatch = match;
253 }
254 }
255 }
256 CTRACE((tfp, "HTStyleForRun: Best match for style is %d out of 18\n",
257 bestMatch));
258 return best;
259 }
260 #endif /* NEXT_SUPRESS */
261
262 /* Add a style to a sheet
263 * ----------------------
264 */
HTStyleSheetAddStyle(HTStyleSheet * self,HTStyle * style)265 HTStyleSheet *HTStyleSheetAddStyle(HTStyleSheet *self, HTStyle *style)
266 {
267 style->next = 0; /* The style will go on the end */
268 if (!self->styles) {
269 self->styles = style;
270 } else {
271 HTStyle *scan;
272
273 for (scan = self->styles; scan->next; scan = scan->next) ; /* Find end */
274 scan->next = style;
275 }
276 return self;
277 }
278
279 /* Remove the given object from a style sheet if it exists
280 */
HTStyleSheetRemoveStyle(HTStyleSheet * self,HTStyle * style)281 HTStyleSheet *HTStyleSheetRemoveStyle(HTStyleSheet *self, HTStyle *style)
282 {
283 if (self->styles == style) {
284 self->styles = style->next;
285 return self;
286 } else {
287 HTStyle *scan;
288
289 for (scan = self->styles; scan; scan = scan->next) {
290 if (scan->next == style) {
291 scan->next = style->next;
292 return self;
293 }
294 }
295 }
296 return NULL;
297 }
298
299 /* Create new style sheet
300 */
301
HTStyleSheetNew(void)302 HTStyleSheet *HTStyleSheetNew(void)
303 {
304 HTStyleSheet *self = typecalloc(HTStyleSheet);
305
306 if (self == NULL)
307 outofmem(__FILE__, "HTStyleSheetNew");
308 return self;
309 }
310
311 /* Free off a style sheet pointer
312 */
HTStyleSheetFree(HTStyleSheet * self)313 HTStyleSheet *HTStyleSheetFree(HTStyleSheet *self)
314 {
315 HTStyle *style;
316
317 while ((style = self->styles) != 0) {
318 self->styles = style->next;
319 HTStyleFree(style);
320 }
321 FREE(self);
322 return NULL;
323 }
324
325 /* Read a stylesheet from a typed stream
326 * -------------------------------------
327 *
328 * Reads a style sheet from a stream. If new styles have the same names
329 * as existing styles, they replace the old ones without changing the ids.
330 */
331
332 #ifdef NEXT_SUPRESS /* Only on the NeXT */
HTStyleSheetRead(HTStyleSheet * self,NXStream * stream)333 HTStyleSheet *HTStyleSheetRead(HTStyleSheet *self, NXStream * stream)
334 {
335 int numStyles;
336 int i;
337 HTStyle *style;
338 char styleName[80];
339
340 NXScanf(stream, " %d ", &numStyles);
341 CTRACE((tfp, "Stylesheet: Reading %d styles\n", numStyles));
342 for (i = 0; i < numStyles; i++) {
343 NXScanf(stream, "%s", styleName);
344 style = HTStyleNamed(self, styleName);
345 if (!style) {
346 style = HTStyleNewNamed(styleName);
347 (void) HTStyleSheetAddStyle(self, style);
348 }
349 (void) HTStyleRead(style, stream);
350 if (TRACE)
351 HTStyleDump(style);
352 }
353 return self;
354 }
355
356 /* Write a stylesheet to a typed stream
357 * ------------------------------------
358 *
359 * Writes a style sheet to a stream.
360 */
361
HTStyleSheetWrite(HTStyleSheet * self,NXStream * stream)362 HTStyleSheet *HTStyleSheetWrite(HTStyleSheet *self, NXStream * stream)
363 {
364 int numStyles = 0;
365 HTStyle *style;
366
367 for (style = self->styles; style; style = style->next)
368 numStyles++;
369 NXPrintf(stream, "%d\n", numStyles);
370
371 CTRACE((tfp, "StyleSheet: Writing %d styles\n", numStyles));
372 for (style = self->styles; style; style = style->next) {
373 NXPrintf(stream, "%s ", style->name);
374 (void) HTStyleWrite(style, stream);
375 }
376 return self;
377 }
378 #endif /* NEXT_SUPRESS */
379