~ubuntu-branches/ubuntu/jaunty/texlive-bin/jaunty-security

« back to all changes in this revision

Viewing changes to build/source/texk/xdvipdfmx/src/spc_html.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Preining
  • Date: 2008-06-26 23:14:59 UTC
  • mfrom: (2.1.30 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080626231459-y02rjsrgtafu83yr
Tags: 2007.dfsg.2-3
add missing source roadmap.fig of roadmap.eps in fontinst documentation
(Closes: #482915) (urgency medium due to RC bug)
(new patch add-missing-fontinst-source)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  $Header: /home/cvsroot/dvipdfmx/src/spc_html.c,v 1.5 2005/08/14 15:50:36 chofchof Exp $
 
2
 
 
3
    This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
 
4
 
 
5
    Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
 
6
    the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
 
7
    
 
8
    Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
 
9
 
 
10
    This program is free software; you can redistribute it and/or modify
 
11
    it under the terms of the GNU General Public License as published by
 
12
    the Free Software Foundation; either version 2 of the License, or
 
13
    (at your option) any later version.
 
14
    
 
15
    This program is distributed in the hope that it will be useful,
 
16
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
    GNU General Public License for more details.
 
19
    
 
20
    You should have received a copy of the GNU General Public License
 
21
    along with this program; if not, write to the Free Software
 
22
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 
23
*/
 
24
 
 
25
#ifdef HAVE_CONFIG_H
 
26
#include "config.h"
 
27
#endif
 
28
 
 
29
#include "system.h"
 
30
#include "mem.h"
 
31
#include "error.h"
 
32
#include "dpxutil.h"
 
33
 
 
34
#include "pdfdraw.h"
 
35
#include "pdfdev.h"
 
36
#include "pdfximage.h"
 
37
 
 
38
#include "pdfdoc.h"
 
39
 
 
40
#include "specials.h"
 
41
#include "spc_util.h"
 
42
 
 
43
#include "spc_html.h"
 
44
 
 
45
 
 
46
#define  ENABLE_HTML_IMG_SUPPORT   1
 
47
#define  ENABLE_HTML_SVG_TRANSFORM 1
 
48
#define  ENABLE_HTML_SVG_OPACITY   1
 
49
 
 
50
/* _FIXME_
 
51
 * Please rewrite this or remove html special support
 
52
 */
 
53
 
 
54
#define  ANCHOR_TYPE_HREF  0
 
55
#define  ANCHOR_TYPE_NAME  1
 
56
 
 
57
struct spc_html_
 
58
{
 
59
  struct {
 
60
    long  extensions;
 
61
  } opts;
 
62
 
 
63
  pdf_obj  *link_dict;
 
64
  char     *baseurl;
 
65
  int       pending_type;
 
66
};
 
67
 
 
68
static struct spc_html_ _html_state = {
 
69
  { 0 },
 
70
  NULL, NULL, -1
 
71
};
 
72
 
 
73
 
 
74
#ifdef  ENABLE_HTML_SVG_TRANSFORM
 
75
static int cvt_a_to_tmatrix (pdf_tmatrix *M, const char *ptr, char **nextptr);
 
76
#endif /* ENABLE_HTML_SVG_TRANSFORM */
 
77
 
 
78
#define \
 
79
downcasify(s) \
 
80
if ((s)) { \
 
81
  char  *_p = (char *) (s); \
 
82
  while (*(_p) != 0) { \
 
83
    if (*(_p) >= 'A' && *(_p) <= 'Z') { \
 
84
      *(_p) = (*(_p) - 'A') + 'a'; \
 
85
    } \
 
86
    _p++; \
 
87
  } \
 
88
}
 
89
 
 
90
static int
 
91
parse_key_val (char **pp, char *endptr, char **kp, char **vp)
 
92
{
 
93
  char  *q, *p, *k, *v;
 
94
  int    n, error = 0;
 
95
 
 
96
  for (p = *pp ; p < endptr && isspace(*p); p++);
 
97
#if  0
 
98
  while (!error && p < endptr &&
 
99
         ((*p >= 'a' && *p <= 'z') ||
 
100
          (*p >= 'A' && *p <= 'Z'))
 
101
        ) {
 
102
#endif
 
103
    k = v = NULL;
 
104
    for (q = p, n = 0;
 
105
         p < endptr &&
 
106
         ((*p >= 'a' && *p <= 'z') ||
 
107
          (*p >= 'A' && *p <= 'Z') ||
 
108
          (*p >= '0' && *p <= '9') ||
 
109
           *p == '-' || *p == ':'
 
110
         ); n++, p++);
 
111
    if (n == 0) {
 
112
#if  0
 
113
      break;
 
114
#else
 
115
      *kp = *vp = NULL;
 
116
      return  -1;
 
117
#endif
 
118
    }
 
119
    k = NEW(n + 1, char);
 
120
    memcpy(k, q, n); k[n] = '\0';
 
121
    if (p + 2 >= endptr || p[0] != '=' || (p[1] != '\"' && p[1] != '\'')) {
 
122
      RELEASE(k); k = NULL;
 
123
      *pp = p;
 
124
      error = -1;
 
125
    } else {
 
126
      char  qchr = p[1];
 
127
      p += 2; /* skip '="' */
 
128
      for (q = p, n = 0; p < endptr && *p != qchr; p++, n++);
 
129
      if (p == endptr || *p != qchr)
 
130
        error = -1;
 
131
      else {
 
132
        v = NEW(n + 1, char);
 
133
        memcpy(v, q, n); v[n] = '\0';
 
134
#if  0
 
135
        pdf_add_dict(t->attr,
 
136
                     pdf_new_name(k),
 
137
                     pdf_new_string(v, n));
 
138
        RELEASE(v);
 
139
#endif
 
140
        p++;
 
141
      }
 
142
    }
 
143
#if  0
 
144
    RELEASE(k);
 
145
    if (!error)
 
146
      for ( ; p < endptr && isspace(*p); p++);
 
147
  }
 
148
#endif
 
149
 
 
150
  *kp = k; *vp = v; *pp = p;
 
151
  return  error;
 
152
}
 
153
 
 
154
#define  HTML_TAG_NAME_MAX    127
 
155
#define  HTML_TAG_TYPE_EMPTY  1
 
156
#define  HTML_TAG_TYPE_OPEN   1
 
157
#define  HTML_TAG_TYPE_CLOSE  2
 
158
 
 
159
static int
 
160
read_html_tag (char *name, pdf_obj *attr, int *type, char **pp, char *endptr)
 
161
{
 
162
  char  *p = *pp;
 
163
  int    n = 0, error = 0;
 
164
 
 
165
  for ( ; p < endptr && isspace(*p); p++);
 
166
  if (p >= endptr || *p != '<')
 
167
    return  -1;
 
168
 
 
169
  *type = HTML_TAG_TYPE_OPEN;
 
170
  for (++p; p < endptr && isspace(*p); p++);
 
171
  if (p < endptr && *p == '/') {
 
172
    *type = HTML_TAG_TYPE_CLOSE;
 
173
    for (++p; p < endptr && isspace(*p); p++);
 
174
  }
 
175
 
 
176
#define ISDELIM(c) ((c) == '>' || (c) == '/' || isspace(c))
 
177
  for (n = 0; p < endptr && n < HTML_TAG_NAME_MAX && !ISDELIM(*p); n++, p++) {
 
178
    name[n] = *p;
 
179
  } 
 
180
  name[n] = '\0';
 
181
  if (n == 0 || p == endptr || !ISDELIM(*p)) {
 
182
    *pp = p;
 
183
    return  -1;
 
184
  }
 
185
 
 
186
  for ( ; p < endptr && isspace(*p); p++);
 
187
  while (p < endptr && !error && *p != '/' && *p != '>') {
 
188
    char  *kp = NULL, *vp = NULL;
 
189
    error = parse_key_val(&p, endptr, &kp, &vp);
 
190
    if (!error) {
 
191
      downcasify(kp);
 
192
      pdf_add_dict(attr,
 
193
                   pdf_new_name(kp),
 
194
                   pdf_new_string(vp, strlen(vp) + 1)); /* include trailing NULL here!!! */
 
195
      RELEASE(kp);
 
196
      RELEASE(vp);
 
197
    }
 
198
    for ( ; p < endptr && isspace(*p); p++);
 
199
  }
 
200
  if (error) {
 
201
    *pp = p;
 
202
    return  error;
 
203
  }
 
204
 
 
205
  if (p < endptr && *p == '/') {
 
206
    *type = HTML_TAG_TYPE_EMPTY;
 
207
    for (++p; p < endptr && isspace(*p); p++);
 
208
  }
 
209
  if (p == endptr || *p != '>') {
 
210
    *pp = p;
 
211
    return  -1;
 
212
  }
 
213
  p++;
 
214
 
 
215
  downcasify(name);
 
216
  *pp = p;
 
217
  return  0;
 
218
}
 
219
 
 
220
 
 
221
static int
 
222
spc_handler_html__init (struct spc_env *spe, struct spc_arg *ap, void *dp)
 
223
{
 
224
  struct spc_html_ *sd = dp;
 
225
 
 
226
  sd->link_dict    = NULL;
 
227
  sd->baseurl      = NULL;
 
228
  sd->pending_type = -1;
 
229
 
 
230
  return  0;
 
231
}
 
232
 
 
233
static int
 
234
spc_handler_html__clean (struct spc_env *spe, struct spc_arg *ap, void *dp)
 
235
{
 
236
  struct spc_html_ *sd = dp;
 
237
 
 
238
  if (sd->baseurl)
 
239
    RELEASE(sd->baseurl);
 
240
 
 
241
  if (sd->pending_type >= 0 || sd->link_dict)
 
242
    spc_warn(spe, "Unclosed html anchor found.");
 
243
 
 
244
  if (sd->link_dict)
 
245
    pdf_release_obj(sd->link_dict);
 
246
 
 
247
  sd->pending_type = -1;
 
248
  sd->baseurl      = NULL;
 
249
  sd->link_dict    = NULL;
 
250
 
 
251
  return  0;
 
252
}
 
253
 
 
254
 
 
255
static int
 
256
spc_handler_html__bophook (struct spc_env *spe, struct spc_arg *ap, void *dp)
 
257
{
 
258
  struct spc_html_ *sd = dp;
 
259
 
 
260
  if (sd->pending_type >= 0) {
 
261
    spc_warn(spe, "...html anchor continues from previous page processed...");
 
262
  }
 
263
 
 
264
  return  0;
 
265
}
 
266
 
 
267
static int
 
268
spc_handler_html__eophook (struct spc_env *spe, struct spc_arg *ap, void *dp)
 
269
{
 
270
  struct spc_html_ *sd = dp;
 
271
 
 
272
  if (sd->pending_type >= 0) {
 
273
    spc_warn(spe, "Unclosed html anchor at end-of-page!");
 
274
  }
 
275
 
 
276
  return  0;
 
277
}
 
278
 
 
279
 
 
280
static char *
 
281
fqurl (const char *baseurl, const char *name)
 
282
{
 
283
  char  *q;
 
284
  int    len = 0;
 
285
 
 
286
  len = strlen(name);
 
287
  if (baseurl)
 
288
    len += strlen(baseurl) + 1; /* we may want to add '/' */
 
289
 
 
290
  q = NEW(len + 1, char);
 
291
  *q = '\0';
 
292
  if (baseurl && baseurl[0]) {
 
293
    char  *p;
 
294
    strcpy(q, baseurl);
 
295
    p = q + strlen(q) - 1;
 
296
    if (*p == '/')
 
297
      *p = '\0';
 
298
    if (name[0] && name[0] != '/')
 
299
      strcat(q, "/");
 
300
  }
 
301
  strcat(q, name);
 
302
 
 
303
  return  q;
 
304
}
 
305
 
 
306
static int
 
307
html_open_link (struct spc_env *spe, const char *name, struct spc_html_ *sd)
 
308
{
 
309
  pdf_obj  *color;
 
310
  char     *url;
 
311
 
 
312
  ASSERT( name );
 
313
  ASSERT( sd->link_dict == NULL ); /* Should be checked somewhere else */
 
314
 
 
315
  sd->link_dict = pdf_new_dict();
 
316
  pdf_add_dict(sd->link_dict,
 
317
               pdf_new_name("Type"),    pdf_new_name ("Annot"));
 
318
  pdf_add_dict(sd->link_dict,
 
319
               pdf_new_name("Subtype"), pdf_new_name ("Link"));
 
320
 
 
321
  color = pdf_new_array ();
 
322
  pdf_add_array(color, pdf_new_number(0.0));
 
323
  pdf_add_array(color, pdf_new_number(0.0));
 
324
  pdf_add_array(color, pdf_new_number(1.0));
 
325
  pdf_add_dict(sd->link_dict, pdf_new_name("C"), color);
 
326
 
 
327
  url = fqurl(sd->baseurl, name);
 
328
  if (url[0] == '#') {
 
329
    /* url++; causes memory leak in RELEASE(url) */
 
330
    pdf_add_dict(sd->link_dict,
 
331
                 pdf_new_name("Dest"),
 
332
                 pdf_new_string(url+1, strlen(url+1)));
 
333
  } else { /* Assume this is URL */
 
334
    pdf_obj  *action = pdf_new_dict();
 
335
    pdf_add_dict(action,
 
336
                 pdf_new_name("Type"),
 
337
                 pdf_new_name("Action"));
 
338
    pdf_add_dict(action,
 
339
                 pdf_new_name("S"),
 
340
                 pdf_new_name("URI"));
 
341
    pdf_add_dict(action,
 
342
                 pdf_new_name("URI"),
 
343
                 pdf_new_string(url, strlen(url)));
 
344
    pdf_add_dict(sd->link_dict,
 
345
                 pdf_new_name("A"),
 
346
                 pdf_link_obj(action));
 
347
    pdf_release_obj(action);
 
348
  }
 
349
  RELEASE(url);
 
350
 
 
351
  spc_begin_annot(spe, sd->link_dict);
 
352
 
 
353
  sd->pending_type = ANCHOR_TYPE_HREF;
 
354
 
 
355
  return  0;
 
356
}
 
357
 
 
358
static int
 
359
html_open_dest (struct spc_env *spe, const char *name, struct spc_html_ *sd)
 
360
{
 
361
  int        error;
 
362
  pdf_obj   *array, *page_ref;
 
363
  pdf_coord  cp;
 
364
 
 
365
  cp.x = spe->x_user; cp.y = spe->y_user;
 
366
  pdf_dev_transform(&cp, NULL);
 
367
 
 
368
  page_ref = pdf_doc_this_page_ref();
 
369
  ASSERT( page_ref ); /* Otherwise must be bug */
 
370
 
 
371
  array = pdf_new_array();
 
372
  pdf_add_array(array, page_ref);
 
373
  pdf_add_array(array, pdf_new_name("XYZ"));
 
374
  pdf_add_array(array, pdf_new_null());
 
375
  pdf_add_array(array, pdf_new_number(cp.y + 24.0));
 
376
  pdf_add_array(array, pdf_new_null());
 
377
 
 
378
  error = pdf_doc_add_names("Dests",
 
379
                            name, strlen(name),
 
380
                            array);
 
381
 
 
382
  if (error)
 
383
    spc_warn(spe, "Failed to add named destination: %s", name);
 
384
 
 
385
  sd->pending_type = ANCHOR_TYPE_NAME;
 
386
 
 
387
  return  error;
 
388
}
 
389
 
 
390
#define ANCHOR_STARTED(s) ((s)->pending_type >= 0 || (s)->link_dict)
 
391
 
 
392
static int
 
393
spc_html__anchor_open (struct spc_env *spe, pdf_obj *attr, struct spc_html_ *sd)
 
394
{
 
395
  pdf_obj *href, *name;
 
396
  int      error = 0;
 
397
 
 
398
  if (ANCHOR_STARTED(sd)) {
 
399
    spc_warn(spe, "Nested html anchors found!");
 
400
    return  -1;
 
401
  }
 
402
 
 
403
  href = pdf_lookup_dict(attr, "href");
 
404
  name = pdf_lookup_dict(attr, "name");
 
405
  if (href && name) {
 
406
    spc_warn(spe, "Sorry, you can't have both \"href\" and \"name\" in anchor tag...");
 
407
    error = -1;
 
408
  } else if (href) {
 
409
    error = html_open_link(spe, pdf_string_value(href), sd);
 
410
  } else if (name) { /* name */
 
411
    error = html_open_dest(spe, pdf_string_value(name), sd);
 
412
  } else {
 
413
    spc_warn(spe, "You should have \"href\" or \"name\" in anchor tag!");
 
414
    error = -1;
 
415
  }
 
416
 
 
417
  return  error;
 
418
}
 
419
 
 
420
static int
 
421
spc_html__anchor_close (struct spc_env *spe, pdf_obj *attr, struct spc_html_ *sd)
 
422
{
 
423
  int  error = 0;
 
424
 
 
425
  switch (sd->pending_type) {
 
426
  case  ANCHOR_TYPE_HREF:
 
427
    if (sd->link_dict) {
 
428
      spc_end_annot(spe);
 
429
      pdf_release_obj(sd->link_dict);
 
430
      sd->link_dict    = NULL;
 
431
      sd->pending_type = -1;
 
432
    } else {
 
433
      spc_warn(spe, "Closing html anchor (link) without starting!");
 
434
      error = -1;
 
435
    }
 
436
    break;
 
437
  case  ANCHOR_TYPE_NAME:
 
438
    sd->pending_type = -1;
 
439
    break;
 
440
  default:
 
441
    spc_warn(spe, "No corresponding opening tag for html anchor.");
 
442
    error = -1;
 
443
    break;
 
444
  }
 
445
 
 
446
  return  error;
 
447
}
 
448
 
 
449
static int
 
450
spc_html__base_empty (struct spc_env *spe, pdf_obj *attr, struct spc_html_ *sd)
 
451
{
 
452
  pdf_obj *href;
 
453
  char    *vp;
 
454
 
 
455
  href = pdf_lookup_dict(attr, "href");
 
456
  if (!href) {
 
457
    spc_warn(spe, "\"href\" not found for \"base\" tag!");
 
458
    return  -1;
 
459
  }
 
460
 
 
461
  vp = (char *) pdf_string_value(href);
 
462
  if (sd->baseurl) {
 
463
    spc_warn(spe, "\"baseurl\" changed: \"%s\" --> \"%s\"", sd->baseurl, vp);
 
464
    RELEASE(sd->baseurl);
 
465
  }
 
466
  sd->baseurl = NEW(strlen(vp) + 1, char);
 
467
  strcpy(sd->baseurl, vp);
 
468
 
 
469
  return  0;
 
470
}
 
471
 
 
472
 
 
473
#ifdef  ENABLE_HTML_IMG_SUPPORT
 
474
/* This isn't completed.
 
475
 * Please think about placement of images.
 
476
 */
 
477
static double
 
478
atopt (const char *a)
 
479
{
 
480
  char   *q, *p = (char *) a;
 
481
  double  v, u = 1.0;
 
482
  const char *_ukeys[] = {
 
483
#define K_UNIT__PT  0
 
484
#define K_UNIT__IN  1
 
485
#define K_UNIT__CM  2
 
486
#define K_UNIT__MM  3
 
487
#define K_UNIT__BP  4
 
488
    "pt", "in", "cm", "mm", "bp",
 
489
#define K_UNIT__PX  5
 
490
    "px",
 
491
     NULL
 
492
  };
 
493
  int     k;
 
494
 
 
495
  q = parse_float_decimal(&p, p + strlen(p));
 
496
  if (!q) {
 
497
    WARN("Invalid length value: %s (%c)", a, *p);
 
498
    return  0.0;
 
499
  }
 
500
 
 
501
  v = atof(q);
 
502
  RELEASE(q);
 
503
 
 
504
  q = parse_c_ident(&p, p + strlen(p));
 
505
  if (q) {
 
506
    for (k = 0; _ukeys[k] && strcmp(_ukeys[k], q); k++);
 
507
    switch (k) {
 
508
    case K_UNIT__PT: u *= 72.0 / 72.27; break;
 
509
    case K_UNIT__IN: u *= 72.0; break;
 
510
    case K_UNIT__CM: u *= 72.0 / 2.54 ; break;
 
511
    case K_UNIT__MM: u *= 72.0 / 25.4 ; break;
 
512
    case K_UNIT__BP: u *= 1.0 ; break;
 
513
    case K_UNIT__PX: u *= 1.0 ; break; /* 72dpi */
 
514
    default:
 
515
      WARN("Unknown unit of measure: %s", q);
 
516
      break;
 
517
    }
 
518
    RELEASE(q);
 
519
  }
 
520
 
 
521
  return  v * u;
 
522
}
 
523
 
 
524
 
 
525
#ifdef  ENABLE_HTML_SVG_OPACITY
 
526
/* Replicated from spc_tpic */
 
527
static pdf_obj *
 
528
create_xgstate (double a /* alpha */, int f_ais /* alpha is shape */)
 
529
{
 
530
  pdf_obj  *dict;
 
531
 
 
532
  dict = pdf_new_dict();
 
533
  pdf_add_dict(dict,
 
534
               pdf_new_name("Type"),
 
535
               pdf_new_name("ExtGState"));
 
536
  if (f_ais) {
 
537
    pdf_add_dict(dict,
 
538
                 pdf_new_name("AIS"),
 
539
                 pdf_new_boolean(1));
 
540
  }
 
541
  pdf_add_dict(dict,
 
542
               pdf_new_name("ca"),
 
543
               pdf_new_number(a));
 
544
 
 
545
  return  dict;
 
546
}
 
547
 
 
548
static int
 
549
check_resourcestatus (const char *category, const char *resname)
 
550
{
 
551
  pdf_obj  *dict1, *dict2;
 
552
 
 
553
  dict1 = pdf_doc_current_page_resources();
 
554
  if (!dict1)
 
555
    return  0;
 
556
 
 
557
  dict2 = pdf_lookup_dict(dict1, category);
 
558
  if (dict2 &&
 
559
      pdf_obj_typeof(dict2) == PDF_DICT) {
 
560
    if (pdf_lookup_dict(dict2, resname))
 
561
      return  1;
 
562
  }
 
563
  return  0;
 
564
}
 
565
#endif /* ENABLE_HTML_SVG_OPACITY */
 
566
 
 
567
static int
 
568
spc_html__img_empty (struct spc_env *spe, pdf_obj *attr, struct spc_html_ *sd)
 
569
{
 
570
  pdf_obj       *src, *obj;
 
571
  transform_info ti;
 
572
  int            id, error = 0;
 
573
#ifdef  ENABLE_HTML_SVG_OPACITY
 
574
  double         alpha = 1.0; /* meaning fully opaque */
 
575
#endif /* ENABLE_HTML_SVG_OPACITY */
 
576
#ifdef  ENABLE_HTML_SVG_TRANSFORM
 
577
  pdf_tmatrix    M;
 
578
 
 
579
  pdf_setmatrix(&M, 1.0, 0.0, 0.0, 1.0, spe->x_user, spe->y_user);
 
580
#endif /* ENABLE_HTML_SVG_TRANSFORM */
 
581
 
 
582
  spc_warn(spe, "html \"img\" tag found (not completed, plese don't use!).");
 
583
 
 
584
  src = pdf_lookup_dict(attr, "src");
 
585
  if (!src) {
 
586
    spc_warn(spe, "\"src\" attribute not found for \"img\" tag!");
 
587
    return  -1;
 
588
  }
 
589
 
 
590
  transform_info_clear(&ti);
 
591
  obj = pdf_lookup_dict(attr, "width");
 
592
  if (obj) {
 
593
    ti.width  = atopt(pdf_string_value(obj));
 
594
    ti.flags |= INFO_HAS_WIDTH;
 
595
  }
 
596
  obj = pdf_lookup_dict(attr, "height");
 
597
  if (obj) {
 
598
    ti.height = atopt(pdf_string_value(obj));
 
599
    ti.flags |= INFO_HAS_HEIGHT;
 
600
  }
 
601
 
 
602
#ifdef  ENABLE_HTML_SVG_OPACITY
 
603
  obj = pdf_lookup_dict(attr, "svg:opacity");
 
604
  if (obj) {
 
605
    alpha = atof(pdf_string_value(obj));
 
606
    if (alpha < 0.0 || alpha > 1.0) {
 
607
      spc_warn(spe, "Invalid opacity value: %s", pdf_string_value(obj));
 
608
      alpha = 1.0;
 
609
    }
 
610
  }
 
611
#endif /* ENABLE_HTML_SVG_OPCAITY */
 
612
 
 
613
#ifdef  ENABLE_HTML_SVG_TRANSFORM
 
614
  obj = pdf_lookup_dict(attr, "svg:transform");
 
615
  if (obj) {
 
616
    char  *p = (char *) pdf_string_value(obj);
 
617
    pdf_tmatrix  N;
 
618
    for ( ; *p && isspace(*p); p++);
 
619
    while (*p && !error) {
 
620
      pdf_setmatrix(&N, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
 
621
      error = cvt_a_to_tmatrix(&N, p, &p);
 
622
      if (!error) {
 
623
        N.f = -N.f;
 
624
        pdf_concatmatrix(&M, &N);
 
625
        for ( ; *p && isspace(*p); p++);
 
626
        if (*p == ',')
 
627
          for (++p; *p && isspace(*p); p++);
 
628
      }
 
629
    }
 
630
  }
 
631
#endif /* ENABLE_HTML_SVG_TRANSFORM */
 
632
 
 
633
  if (error) {
 
634
    spc_warn(spe, "Error in html \"img\" tag attribute.");
 
635
    return  error;
 
636
  }
 
637
 
 
638
  id = pdf_ximage_findresource(pdf_string_value(src), 0, 0);
 
639
  if (id < 0) {
 
640
    spc_warn(spe, "Could not find/load image: %s", pdf_string_value(src)); 
 
641
    error = -1;
 
642
  } else {
 
643
#if defined(ENABLE_HTML_SVG_TRANSFORM) || defined(ENABLE_HTML_SVG_OPACITY)
 
644
    {
 
645
      char     *res_name;
 
646
      pdf_rect  r;
 
647
 
 
648
      graphics_mode();
 
649
 
 
650
      pdf_dev_gsave();
 
651
 
 
652
#ifdef  ENABLE_HTML_SVG_OPACITY
 
653
      {
 
654
        pdf_obj *dict;
 
655
        int      a = round(100.0 * alpha);
 
656
        if (a != 0) {
 
657
          res_name = NEW(strlen("_Tps_a100_") + 1, char);
 
658
          sprintf(res_name, "_Tps_a%03d_", a); /* Not Tps prefix but... */
 
659
          if (!check_resourcestatus("ExtGState", res_name)) {
 
660
            dict = create_xgstate(round_at(0.01 * a, 0.01), 0);
 
661
            pdf_doc_add_page_resource("ExtGState",
 
662
                                      res_name, pdf_ref_obj(dict));
 
663
            pdf_release_obj(dict);
 
664
          }
 
665
          pdf_doc_add_page_content(" /", 2);
 
666
          pdf_doc_add_page_content(res_name, strlen(res_name));
 
667
          pdf_doc_add_page_content(" gs", 3);
 
668
          RELEASE(res_name);
 
669
        }
 
670
      }
 
671
#endif /* ENABLE_HTML_SVG_OPACITY */
 
672
 
 
673
      pdf_dev_concat(&M);
 
674
 
 
675
      pdf_ximage_scale_image(id, &M, &r, &ti);
 
676
      pdf_dev_concat(&M);
 
677
 
 
678
      pdf_dev_rectclip(r.llx, r.lly, r.urx - r.llx, r.ury - r.lly);
 
679
 
 
680
      res_name = pdf_ximage_get_resname(id);
 
681
      pdf_doc_add_page_content(" /", 2);
 
682
      pdf_doc_add_page_content(res_name, strlen(res_name));
 
683
      pdf_doc_add_page_content(" Do", 3);
 
684
 
 
685
      pdf_dev_grestore();
 
686
 
 
687
      pdf_doc_add_page_resource("XObject",
 
688
                                res_name,
 
689
                                pdf_ximage_get_reference(id));
 
690
    }
 
691
#else
 
692
    pdf_dev_put_image(id, &ti, spe->x_user, spe->y_user);
 
693
#endif /* ENABLE_HTML_SVG_XXX */
 
694
  }
 
695
 
 
696
  return  error;
 
697
}
 
698
#else
 
699
static int
 
700
spc_html__img_empty (struct spc_env *spe, pdf_obj *attr, struct spc_html_ *sd)
 
701
{
 
702
  spc_warn(spe, "IMG tag not yet supported yet...");
 
703
  return  -1;
 
704
}
 
705
#endif  /* ENABLE_HTML_IMG_SUPPORT */
 
706
 
 
707
 
 
708
static int
 
709
spc_handler_html_default (struct spc_env *spe, struct spc_arg *ap)
 
710
{
 
711
  struct spc_html_ *sd = &_html_state;
 
712
  char      name[HTML_TAG_NAME_MAX + 1];
 
713
  pdf_obj  *attr;
 
714
  int       error = 0, type = HTML_TAG_TYPE_OPEN;
 
715
 
 
716
  if (ap->curptr >= ap->endptr)
 
717
    return  0;
 
718
 
 
719
  attr  = pdf_new_dict();
 
720
  error = read_html_tag(name, attr, &type, &ap->curptr, ap->endptr);
 
721
  if (error) {
 
722
    pdf_release_obj(attr);
 
723
    return  error;
 
724
  }
 
725
  if (!strcmp(name, "a")) {
 
726
    switch (type) {
 
727
    case  HTML_TAG_TYPE_OPEN:
 
728
      error = spc_html__anchor_open (spe, attr, sd);
 
729
      break;
 
730
    case  HTML_TAG_TYPE_CLOSE:
 
731
      error = spc_html__anchor_close(spe, attr, sd);
 
732
      break;
 
733
    default:
 
734
      spc_warn(spe, "Empty html anchor tag???");
 
735
      error = -1;
 
736
      break;
 
737
    }
 
738
  } else if (!strcmp(name, "base")) {
 
739
    if (type == HTML_TAG_TYPE_CLOSE) {
 
740
      spc_warn(spe, "Close tag for \"base\"???");
 
741
      error = -1;
 
742
    } else { /* treat "open" same as "empty" */
 
743
      error = spc_html__base_empty(spe, attr, sd);
 
744
    }
 
745
  } else if (!strcmp(name, "img")) {
 
746
    if (type == HTML_TAG_TYPE_CLOSE) {
 
747
      spc_warn(spe, "Close tag for \"img\"???");
 
748
      error = -1;
 
749
    } else { /* treat "open" same as "empty" */
 
750
      error = spc_html__img_empty(spe, attr, sd);
 
751
    }
 
752
  }
 
753
  pdf_release_obj(attr);
 
754
 
 
755
  for ( ; ap->curptr < ap->endptr && isspace(ap->curptr[0]); ap->curptr++);
 
756
 
 
757
  return  error;
 
758
}
 
759
 
 
760
 
 
761
#ifdef  ENABLE_HTML_SVG_TRANSFORM
 
762
/* translate wsp* '(' wsp* number (comma-wsp number)? wsp* ')' */
 
763
static int
 
764
cvt_a_to_tmatrix (pdf_tmatrix *M, const char *ptr, char **nextptr)
 
765
{
 
766
  char        *q, *p = (char *) ptr;
 
767
  int          n;
 
768
  double       v[6];
 
769
  static const char *_tkeys[] = {
 
770
#define  K_TRNS__MATRIX     0
 
771
    "matrix",    /* a b c d e f */
 
772
#define  K_TRNS__TRANSLATE  1
 
773
    "translate", /* tx [ty] : dflt. tf = 0 */
 
774
#define  K_TRNS__SCALE      2
 
775
    "scale",     /* sx [sy] : dflt. sy = sx */
 
776
#define  K_TRNS__ROTATE     3
 
777
    "rotate",    /* ang [cx cy] : dflt. cx, cy = 0 */
 
778
#define  K_TRNS__SKEWX      4
 
779
#define  K_TRNS__SKEWY      5
 
780
    "skewX",     /* ang */
 
781
    "skewY",     /* ang */
 
782
    NULL
 
783
  };
 
784
  int          k;
 
785
 
 
786
  for ( ; *p && isspace(*p); p++);
 
787
 
 
788
  q = parse_c_ident(&p, p + strlen(p));
 
789
  if (!q)
 
790
    return -1;
 
791
  /* parsed transformation key */
 
792
  for (k = 0; _tkeys[k] && strcmp(q, _tkeys[k]); k++);
 
793
  RELEASE(q);
 
794
 
 
795
  /* handle args */
 
796
  for ( ; *p && isspace(*p); p++);
 
797
  if (*p != '(' || *(p + 1) == 0)
 
798
    return  -1;
 
799
  for (++p; *p && isspace(*p); p++);
 
800
  for (n = 0; n < 6 && *p && *p != ')'; n++) {
 
801
    q = parse_float_decimal(&p, p + strlen(p));
 
802
    if (!q)
 
803
      break;
 
804
    else {
 
805
      v[n] = atof(q);
 
806
      if (*p == ',')
 
807
        p++;
 
808
      for ( ; *p && isspace(*p); p++);
 
809
      if (*p == ',')
 
810
        for (++p; *p && isspace(*p); p++);
 
811
      RELEASE(q);
 
812
    }
 
813
  }
 
814
  if (*p != ')')
 
815
    return  -1;
 
816
  p++;
 
817
 
 
818
  switch (k) {
 
819
  case  K_TRNS__MATRIX:
 
820
    if (n != 6)
 
821
      return  -1;
 
822
    M->a = v[0]; M->c = v[1];
 
823
    M->b = v[2]; M->d = v[3];
 
824
    M->e = v[4]; M->f = v[5];
 
825
    break;
 
826
  case  K_TRNS__TRANSLATE:
 
827
    if (n != 1 && n != 2)
 
828
      return  -1;
 
829
    M->a = M->d = 1.0;
 
830
    M->c = M->b = 0.0;
 
831
    M->e = v[0]; M->f = (n == 2) ? v[1] : 0.0;
 
832
    break;
 
833
  case  K_TRNS__SCALE:
 
834
    if (n != 1 && n != 2)
 
835
      return  -1;
 
836
    M->a = v[0]; M->d = (n == 2) ? v[1] : v[0];
 
837
    M->c = M->b = 0.0;
 
838
    M->e = M->f = 0.0;
 
839
    break;
 
840
  case  K_TRNS__ROTATE:
 
841
    if (n != 1 && n != 3)
 
842
      return  -1;
 
843
    M->a = cos(v[0] * M_PI / 180.0);
 
844
    M->c = sin(v[0] * M_PI / 180.0);
 
845
    M->b = -M->c; M->d = M->a;
 
846
    M->e = (n == 3) ? v[1] : 0.0;
 
847
    M->f = (n == 3) ? v[2] : 0.0;
 
848
    break;
 
849
  case  K_TRNS__SKEWX:
 
850
    if (n != 1)
 
851
       return  -1;
 
852
    M->a = M->d = 1.0;
 
853
    M->c = 0.0;
 
854
    M->b = tan(v[0] * M_PI / 180.0);
 
855
    break;
 
856
  case  K_TRNS__SKEWY:
 
857
    if (n != 1)
 
858
       return  -1;
 
859
    M->a = M->d = 1.0;
 
860
    M->c = tan(v[0] * M_PI / 180.0);
 
861
    M->b = 0.0;
 
862
    break;
 
863
  }
 
864
 
 
865
  if (nextptr)
 
866
    *nextptr = p;
 
867
  return  0;
 
868
}    
 
869
#endif /* ENABLE_HTML_SVG_TRANSFORM */
 
870
 
 
871
int
 
872
spc_html_at_begin_document (void)
 
873
{
 
874
  struct spc_html_ *sd = &_html_state;
 
875
  return  spc_handler_html__init(NULL, NULL, sd);
 
876
}
 
877
 
 
878
int
 
879
spc_html_at_begin_page (void)
 
880
{
 
881
  struct spc_html_ *sd = &_html_state;
 
882
  return  spc_handler_html__bophook(NULL, NULL, sd);
 
883
}
 
884
 
 
885
int
 
886
spc_html_at_end_page (void)
 
887
{
 
888
  struct spc_html_ *sd = &_html_state;
 
889
  return  spc_handler_html__eophook(NULL, NULL, sd);
 
890
}
 
891
 
 
892
int
 
893
spc_html_at_end_document (void)
 
894
{
 
895
  struct spc_html_ *sd = &_html_state;
 
896
  return  spc_handler_html__clean(NULL, NULL, sd);
 
897
}
 
898
 
 
899
 
 
900
int
 
901
spc_html_check_special (const char *buffer, long size)
 
902
{
 
903
  char  *p, *endptr;
 
904
 
 
905
  p      = (char *) buffer;
 
906
  endptr = p + size;
 
907
 
 
908
  for ( ; p < endptr && isspace(*p); p++);
 
909
  size   = (long) (endptr - p);
 
910
  if (size >= strlen("html:") &&
 
911
      !memcmp(p, "html:", strlen("html:"))) {
 
912
    return  1;
 
913
  }
 
914
 
 
915
  return  0;
 
916
}
 
917
 
 
918
 
 
919
int
 
920
spc_html_setup_handler (struct spc_handler *sph,
 
921
                        struct spc_env *spe, struct spc_arg *ap)
 
922
{
 
923
  ASSERT(sph && spe && ap);
 
924
 
 
925
  for ( ; ap->curptr < ap->endptr && isspace(ap->curptr[0]); ap->curptr++);
 
926
  if (ap->curptr + strlen("html:") > ap->endptr ||
 
927
      memcmp(ap->curptr, "html:", strlen("html:"))) {
 
928
    return  -1;
 
929
  }
 
930
 
 
931
  ap->command = (char *) "";
 
932
 
 
933
  sph->key    = (char *) "html:";
 
934
  sph->exec   = &spc_handler_html_default;
 
935
 
 
936
  ap->curptr += strlen("html:");
 
937
  for ( ; ap->curptr < ap->endptr && isspace(ap->curptr[0]); ap->curptr++);
 
938
 
 
939
  return  0;
 
940
}
 
941