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