1 /***************************************************************************
2  begin       : Sat Feb 20 2010
3  copyright   : (C) 2010 by Martin Preuss
4  email       : martin@libchipcard.de
5 
6  ***************************************************************************
7  *          Please see toplevel file COPYING for license details           *
8  ***************************************************************************/
9 
10 
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
14 
15 #define DISABLE_DEBUGLOG
16 
17 
18 #include "g_box_p.h"
19 #include "g_generic_l.h"
20 #include "g_table_l.h"
21 #include "g_unorderedlist_l.h"
22 #include "htmlctx_l.h"
23 #include "o_box_l.h"
24 #include "o_word_l.h"
25 #include "o_grid_l.h"
26 #include "o_image_be.h"
27 
28 #include <gwenhywfar/misc.h>
29 #include <gwenhywfar/debug.h>
30 
31 #include <ctype.h>
32 
33 
34 
35 
HtmlGroup_Box_new(const char * groupName,HTML_GROUP * parent,GWEN_XML_CONTEXT * ctx)36 HTML_GROUP *HtmlGroup_Box_new(const char *groupName,
37                               HTML_GROUP *parent,
38                               GWEN_XML_CONTEXT *ctx)
39 {
40   HTML_GROUP *g;
41 
42   /* create base group */
43   g=HtmlGroup_Generic_new(groupName, parent, ctx);
44   assert(g);
45 
46   /* set virtual functions */
47   HtmlGroup_SetStartTagFn(g, HtmlGroup_Box_StartTag);
48   HtmlGroup_SetAddDataFn(g, HtmlGroup_Box_AddData);
49 
50   return g;
51 }
52 
53 
54 
HtmlGroup_Box_StartTag(HTML_GROUP * g,const char * tagName)55 int HtmlGroup_Box_StartTag(HTML_GROUP *g, const char *tagName)
56 {
57   HTML_GROUP *gNew=NULL;
58   GWEN_XML_CONTEXT *ctx;
59   GWEN_DB_NODE *dbAttribs;
60 
61   assert(g);
62 
63   ctx=HtmlGroup_GetXmlContext(g);
64   dbAttribs=HtmlCtx_GetCurrentAttributes(ctx);
65 
66   if (strcasecmp(tagName, "b")==0) {
67     /* Create new parser group with new properties but use the same object */
68     HTML_PROPS *pr;
69     HTML_FONT *fnt;
70 
71     gNew=HtmlGroup_Box_new(tagName, g, ctx);
72     pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
73     fnt=HtmlProps_GetFont(pr);
74     fnt=HtmlCtx_GetFont(ctx,
75                         HtmlFont_GetFontName(fnt),
76                         HtmlFont_GetFontSize(fnt),
77                         HtmlFont_GetFontFlags(fnt) | HTML_FONT_FLAGS_STRONG);
78     if (fnt) {
79       HtmlProps_SetFont(pr, fnt);
80       //HtmlFont_free(fnt);
81     }
82     HtmlGroup_SetProperties(gNew, pr);
83     HtmlProps_free(pr);
84     HtmlGroup_SetObject(gNew, HtmlGroup_GetObject(g));
85   }
86   else if (strcasecmp(tagName, "i")==0) {
87     /* Create new parser group with new properties but use the same object */
88     HTML_PROPS *pr;
89     HTML_FONT *fnt;
90 
91     gNew=HtmlGroup_Box_new(tagName, g, ctx);
92     pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
93     fnt=HtmlProps_GetFont(pr);
94     fnt=HtmlCtx_GetFont(ctx,
95                         HtmlFont_GetFontName(fnt),
96                         HtmlFont_GetFontSize(fnt),
97                         HtmlFont_GetFontFlags(fnt) | HTML_FONT_FLAGS_ITALIC);
98     if (fnt) {
99       HtmlProps_SetFont(pr, fnt);
100       //HtmlFont_free(fnt);
101     }
102     HtmlGroup_SetProperties(gNew, pr);
103     HtmlProps_free(pr);
104     HtmlGroup_SetObject(gNew, HtmlGroup_GetObject(g));
105   }
106   else if (strcasecmp(tagName, "u")==0) {
107     /* Create new parser group with new properties but use the same object */
108     HTML_PROPS *pr;
109     HTML_FONT *fnt;
110 
111     gNew=HtmlGroup_Box_new(tagName, g, ctx);
112     pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
113     fnt=HtmlProps_GetFont(pr);
114     fnt=HtmlCtx_GetFont(ctx,
115                         HtmlFont_GetFontName(fnt),
116                         HtmlFont_GetFontSize(fnt),
117                         HtmlFont_GetFontFlags(fnt) | HTML_FONT_FLAGS_UNDERLINE);
118     if (fnt) {
119       HtmlProps_SetFont(pr, fnt);
120       //HtmlFont_free(fnt);
121     }
122     HtmlGroup_SetProperties(gNew, pr);
123     HtmlProps_free(pr);
124     HtmlGroup_SetObject(gNew, HtmlGroup_GetObject(g));
125   }
126   else if (strcasecmp(tagName, "p")==0) {
127     HTML_OBJECT *o;
128 
129     gNew=HtmlGroup_Box_new(tagName, g, ctx);
130     HtmlGroup_SetProperties(gNew, HtmlGroup_GetProperties(g));
131     o=HtmlObject_Box_new(ctx);
132     HtmlObject_AddFlags(o,
133                         HTML_OBJECT_FLAGS_START_ON_NEWLINE |
134                         HTML_OBJECT_FLAGS_END_WITH_NEWLINE);
135     if (dbAttribs) {
136       const char *s;
137 
138       s=GWEN_DB_GetCharValue(dbAttribs, "align", 0, "left");
139       if (s) {
140         if (strcasecmp(s, "right")==0)
141           HtmlObject_AddFlags(o, HTML_OBJECT_FLAGS_JUSTIFY_RIGHT);
142         else if (strcasecmp(s, "center")==0)
143           HtmlObject_AddFlags(o, HTML_OBJECT_FLAGS_JUSTIFY_HCENTER);
144       }
145     }
146     HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
147     HtmlObject_SetProperties(o, HtmlGroup_GetProperties(g));
148     HtmlGroup_SetObject(gNew, o);
149   }
150   else if (strcasecmp(tagName, "right")==0) {
151     HTML_OBJECT *o;
152 
153     gNew=HtmlGroup_Box_new(tagName, g, ctx);
154     HtmlGroup_SetProperties(gNew, HtmlGroup_GetProperties(g));
155     o=HtmlObject_Box_new(ctx);
156     HtmlObject_AddFlags(o,
157                         HTML_OBJECT_FLAGS_START_ON_NEWLINE |
158                         HTML_OBJECT_FLAGS_END_WITH_NEWLINE |
159                         HTML_OBJECT_FLAGS_JUSTIFY_RIGHT);
160     HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
161     HtmlObject_SetProperties(o, HtmlGroup_GetProperties(g));
162     HtmlGroup_SetObject(gNew, o);
163   }
164   else if (strcasecmp(tagName, "br")==0) {
165     HTML_OBJECT *o;
166 
167     /* just create and add a control object */
168     o=HtmlObject_new(ctx, HtmlObjectType_Control);
169     HtmlObject_AddFlags(o, HTML_OBJECT_FLAGS_END_WITH_NEWLINE);
170     HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
171     HtmlObject_SetProperties(o, HtmlGroup_GetProperties(g));
172   }
173   else if (strcasecmp(tagName, "img")==0) {
174     HTML_OBJECT *o;
175     GWEN_DB_NODE *dbAttribs;
176 
177     o=HtmlObject_Image_new(ctx);
178     HtmlObject_AddFlags(o,
179                         HTML_OBJECT_FLAGS_START_ON_NEWLINE |
180                         HTML_OBJECT_FLAGS_END_WITH_NEWLINE);
181     dbAttribs=HtmlCtx_GetCurrentAttributes(ctx);
182     if (dbAttribs) {
183       const char *s;
184       int w;
185       int h;
186 
187       w=GWEN_DB_GetIntValue(dbAttribs, "width", 0, -1);
188       h=GWEN_DB_GetIntValue(dbAttribs, "height", 0, -1);
189 
190       /* preset */
191       if (w!=-1)
192         HtmlObject_Image_SetScaledWidth(o, w);
193       if (h!=-1)
194         HtmlObject_Image_SetScaledHeight(o, w);
195 
196       s=GWEN_DB_GetCharValue(dbAttribs, "src", 0, NULL);
197       if (s && *s) {
198         HTML_IMAGE *img;
199 
200         img=HtmlCtx_GetImage(ctx, s);
201         if (img) {
202           HtmlObject_Image_SetImage(o, img);
203           /* adjust scaled width and height if not set by attributes */
204           if (w==-1)
205             HtmlObject_Image_SetScaledWidth(o, HtmlImage_GetWidth(img));
206           if (h==-1)
207             HtmlObject_Image_SetScaledHeight(o, HtmlImage_GetHeight(img));
208         }
209         else {
210           DBG_ERROR(GWEN_LOGDOMAIN, "Image [%s] not found", s);
211         }
212       }
213       else {
214         DBG_ERROR(GWEN_LOGDOMAIN, "Missing image name in IMG element");
215       }
216     }
217 
218     HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
219     HtmlObject_SetProperties(o, HtmlGroup_GetProperties(g));
220   }
221   else if (strcasecmp(tagName, "table")==0) {
222     HTML_OBJECT *o;
223 
224     gNew=HtmlGroup_Table_new(tagName, g, ctx);
225     HtmlGroup_SetProperties(gNew, HtmlGroup_GetProperties(g));
226     o=HtmlObject_Grid_new(ctx);
227     HtmlObject_SetProperties(o, HtmlGroup_GetProperties(g));
228     HtmlGroup_SetObject(gNew, o);
229     HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
230   }
231   else if (strcasecmp(tagName, "ul")==0) {
232     HTML_OBJECT *o;
233 
234     gNew=HtmlGroup_UnorderedList_new(tagName, g, ctx);
235     HtmlGroup_SetProperties(gNew, HtmlGroup_GetProperties(g));
236     o=HtmlObject_Grid_new(ctx);
237     HtmlObject_Grid_SetColumns(o, 2);
238     HtmlObject_SetProperties(o, HtmlGroup_GetProperties(g));
239     HtmlGroup_SetObject(gNew, o);
240     HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
241   }
242   else if (strcasecmp(tagName, "font")==0) {
243     /* Create new parser group with new properties but use the same object */
244     HTML_PROPS *pr;
245     GWEN_DB_NODE *dbAttribs;
246 
247     gNew=HtmlGroup_Box_new(tagName, g, ctx);
248     pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
249 
250     dbAttribs=HtmlCtx_GetCurrentAttributes(ctx);
251     if (dbAttribs) {
252       HTML_FONT *fnt;
253       const char *s;
254       const char *fontName;
255       int fontSize;
256       uint32_t fontFlags;
257 
258       fnt=HtmlProps_GetFont(pr);
259       fontName=GWEN_DB_GetCharValue(dbAttribs, "face", 0, NULL);
260       if (fontName==NULL)
261         fontName=HtmlFont_GetFontName(fnt);
262       fontFlags=HtmlFont_GetFontFlags(fnt);
263       fontSize=HtmlFont_GetFontSize(fnt);
264       s=GWEN_DB_GetCharValue(dbAttribs, "size", 0, NULL);
265       if (s && *s) {
266         if (*s=='+') {
267           int i;
268 
269           sscanf(s, "%d", &i);
270           fontSize+=i*4;
271         }
272         else if (*s=='-') {
273           int i;
274 
275           sscanf(s, "%d", &i);
276           fontSize+=i*4;
277         }
278         else
279           sscanf(s, "%d", &fontSize);
280       }
281 
282       s=GWEN_DB_GetCharValue(dbAttribs, "color", 0, NULL);
283       if (s && *s) {
284         uint32_t color;
285 
286         color=HtmlCtx_GetColorFromName(ctx, s);
287         HtmlProps_SetForegroundColor(pr, color);
288       }
289 
290       fnt=HtmlCtx_GetFont(ctx, fontName, fontSize, fontFlags);
291       if (fnt) {
292         HtmlProps_SetFont(pr, fnt);
293         //HtmlFont_free(fnt);
294       }
295     }
296 
297     HtmlGroup_SetProperties(gNew, pr);
298     HtmlProps_free(pr);
299     HtmlGroup_SetObject(gNew, HtmlGroup_GetObject(g));
300   }
301   else if (strcasecmp(tagName, "h1")==0) {
302     /* Create new parser group with new properties but use the same object */
303     HTML_PROPS *pr;
304     HTML_FONT *fnt;
305     HTML_OBJECT *o;
306 
307     gNew=HtmlGroup_Box_new(tagName, g, ctx);
308     pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
309     fnt=HtmlProps_GetFont(pr);
310     fnt=HtmlCtx_GetFont(ctx,
311                         HtmlFont_GetFontName(fnt),
312                         HtmlFont_GetFontSize(fnt)*1.8,
313                         HtmlFont_GetFontFlags(fnt) | HTML_FONT_FLAGS_STRONG);
314     if (fnt) {
315       HtmlProps_SetFont(pr, fnt);
316       //HtmlFont_free(fnt);
317     }
318     HtmlGroup_SetProperties(gNew, pr);
319 
320     o=HtmlObject_Box_new(ctx);
321     HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
322     HtmlObject_AddFlags(o,
323                         HTML_OBJECT_FLAGS_START_ON_NEWLINE |
324                         HTML_OBJECT_FLAGS_END_WITH_NEWLINE);
325     HtmlObject_SetProperties(o, pr);
326     HtmlGroup_SetObject(gNew, o);
327     HtmlProps_free(pr);
328   }
329   else if (strcasecmp(tagName, "h2")==0) {
330     /* Create new parser group with new properties but use the same object */
331     HTML_PROPS *pr;
332     HTML_FONT *fnt;
333     HTML_OBJECT *o;
334 
335     gNew=HtmlGroup_Box_new(tagName, g, ctx);
336     pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
337     fnt=HtmlProps_GetFont(pr);
338     fnt=HtmlCtx_GetFont(ctx,
339                         HtmlFont_GetFontName(fnt),
340                         HtmlFont_GetFontSize(fnt)*1.5,
341                         HtmlFont_GetFontFlags(fnt) | HTML_FONT_FLAGS_STRONG);
342     if (fnt) {
343       HtmlProps_SetFont(pr, fnt);
344       //HtmlFont_free(fnt);
345     }
346     HtmlGroup_SetProperties(gNew, pr);
347 
348     o=HtmlObject_Box_new(ctx);
349     HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
350     HtmlObject_AddFlags(o,
351                         HTML_OBJECT_FLAGS_START_ON_NEWLINE |
352                         HTML_OBJECT_FLAGS_END_WITH_NEWLINE);
353     HtmlObject_SetProperties(o, pr);
354     HtmlGroup_SetObject(gNew, o);
355     HtmlProps_free(pr);
356   }
357   else if (strcasecmp(tagName, "h3")==0) {
358     /* Create new parser group with new properties but use the same object */
359     HTML_PROPS *pr;
360     HTML_FONT *fnt;
361     HTML_OBJECT *o;
362 
363     gNew=HtmlGroup_Box_new(tagName, g, ctx);
364     pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
365     fnt=HtmlProps_GetFont(pr);
366     fnt=HtmlCtx_GetFont(ctx,
367                         HtmlFont_GetFontName(fnt),
368                         HtmlFont_GetFontSize(fnt),
369                         HtmlFont_GetFontFlags(fnt) | HTML_FONT_FLAGS_STRONG);
370     if (fnt) {
371       HtmlProps_SetFont(pr, fnt);
372       //HtmlFont_free(fnt);
373     }
374     HtmlGroup_SetProperties(gNew, pr);
375 
376     o=HtmlObject_Box_new(ctx);
377     HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
378     HtmlObject_AddFlags(o,
379                         HTML_OBJECT_FLAGS_START_ON_NEWLINE |
380                         HTML_OBJECT_FLAGS_END_WITH_NEWLINE);
381     HtmlObject_SetProperties(o, pr);
382     HtmlGroup_SetObject(gNew, o);
383     HtmlProps_free(pr);
384   }
385   else if (strcasecmp(tagName, "h4")==0) {
386     /* Create new parser group with new properties but use the same object */
387     HTML_PROPS *pr;
388     HTML_FONT *fnt;
389     HTML_OBJECT *o;
390 
391     gNew=HtmlGroup_Box_new(tagName, g, ctx);
392     pr=HtmlProps_dup(HtmlGroup_GetProperties(g));
393     fnt=HtmlProps_GetFont(pr);
394     fnt=HtmlCtx_GetFont(ctx,
395                         HtmlFont_GetFontName(fnt),
396                         HtmlFont_GetFontSize(fnt),
397                         HtmlFont_GetFontFlags(fnt) | HTML_FONT_FLAGS_ITALIC);
398     if (fnt) {
399       HtmlProps_SetFont(pr, fnt);
400       //HtmlFont_free(fnt);
401     }
402     HtmlGroup_SetProperties(gNew, pr);
403 
404     o=HtmlObject_Box_new(ctx);
405     HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
406     HtmlObject_AddFlags(o,
407                         HTML_OBJECT_FLAGS_START_ON_NEWLINE |
408                         HTML_OBJECT_FLAGS_END_WITH_NEWLINE);
409     HtmlObject_SetProperties(o, pr);
410     HtmlGroup_SetObject(gNew, o);
411     HtmlProps_free(pr);
412   }
413   else if (strcasecmp(tagName, "html")==0 ||
414            strcasecmp(tagName, "body")==0) {
415   }
416   else {
417     DBG_WARN(GWEN_LOGDOMAIN,
418              "Unknown group [%s], handling as normal box", tagName);
419     gNew=HtmlGroup_Box_new(tagName, g, ctx);
420     HtmlGroup_SetProperties(gNew, HtmlGroup_GetProperties(g));
421     HtmlGroup_SetObject(gNew, HtmlGroup_GetObject(g));
422   }
423 
424   if (gNew) {
425     HtmlCtx_SetCurrentGroup(ctx, gNew);
426     GWEN_XmlCtx_IncDepth(ctx);
427   }
428 
429   return 0;
430 }
431 
432 
433 
HtmlGroup_Box_AddData(HTML_GROUP * g,const char * data)434 int HtmlGroup_Box_AddData(HTML_GROUP *g, const char *data)
435 {
436   GWEN_XML_CONTEXT *ctx;
437   GWEN_BUFFER *buf;
438   int rv;
439   uint8_t *s;
440   HTML_OBJECT *o;
441 
442   assert(g);
443 
444   ctx=HtmlGroup_GetXmlContext(g);
445   if (data && *data) {
446     buf=GWEN_Buffer_new(0, strlen(data), 0, 1);
447     rv=HtmlCtx_SanitizeData(ctx, data, buf);
448     if (rv<0) {
449       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
450       GWEN_Buffer_free(buf);
451       return rv;
452     }
453     if (GWEN_Buffer_GetUsedBytes(buf)) {
454       s=(uint8_t *)GWEN_Buffer_GetStart(buf);
455 
456       while (*s) {
457         uint8_t *t;
458         uint8_t c;
459 
460         /* find begin of word */
461         while (*s && isspace(*s))
462           s++;
463 
464         /* find end of word */
465         t=s;
466         while (*t && !isspace(*t))
467           t++;
468         c=*t;
469         *t=0;
470         o=HtmlObject_Word_new(ctx, (const char *) s);
471         HtmlObject_SetProperties(o, HtmlGroup_GetProperties(g));
472         HtmlObject_Tree_AddChild(HtmlGroup_GetObject(g), o);
473         *t=c;
474         s=t;
475       }
476     }
477     GWEN_Buffer_free(buf);
478   }
479 
480   return 0;
481 }
482 
483 
484 
485