~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to tests/poppler/utils/HtmlOutputDev.cc

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//========================================================================
 
2
//
 
3
// HtmlOutputDev.cc
 
4
//
 
5
// Copyright 1997-2002 Glyph & Cog, LLC
 
6
//
 
7
// Changed 1999-2000 by G.Ovtcharov
 
8
//
 
9
// Changed 2002 by Mikhail Kruk
 
10
//
 
11
//========================================================================
 
12
 
 
13
//========================================================================
 
14
//
 
15
// Modified under the Poppler project - http://poppler.freedesktop.org
 
16
//
 
17
// All changes made under the Poppler project to this file are licensed
 
18
// under GPL version 2 or later
 
19
//
 
20
// Copyright (C) 2005-2010 Albert Astals Cid <aacid@kde.org>
 
21
// Copyright (C) 2008 Kjartan Maraas <kmaraas@gnome.org>
 
22
// Copyright (C) 2008 Boris Toloknov <tlknv@yandex.ru>
 
23
// Copyright (C) 2008 Haruyuki Kawabe <Haruyuki.Kawabe@unisys.co.jp>
 
24
// Copyright (C) 2008 Tomas Are Haavet <tomasare@gmail.com>
 
25
// Copyright (C) 2009 Warren Toomey <wkt@tuhs.org>
 
26
// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
 
27
// Copyright (C) 2009 Reece Dunn <msclrhd@gmail.com>
 
28
// Copyright (C) 2010 Adrian Johnson <ajohnson@redneon.com>
 
29
// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
 
30
// Copyright (C) 2010 OSSD CDAC Mumbai by Leena Chourey (leenac@cdacmumbai.in) and Onkar Potdar (onkar@cdacmumbai.in)
 
31
//
 
32
// To see a description of the changes please see the Changelog file that
 
33
// came with your tarball or type make ChangeLog if you are building from git
 
34
//
 
35
//========================================================================
 
36
 
 
37
#ifdef __GNUC__
 
38
#pragma implementation
 
39
#endif
 
40
 
 
41
#include "config.h"
 
42
#include <stdio.h>
 
43
#include <stdlib.h>
 
44
#include <stdarg.h>
 
45
#include <stddef.h>
 
46
#include <ctype.h>
 
47
#include <math.h>
 
48
#include "goo/GooString.h"
 
49
#include "goo/GooList.h"
 
50
#include "UnicodeMap.h"
 
51
#include "goo/gmem.h"
 
52
#include "Error.h"
 
53
#include "GfxState.h"
 
54
#include "Page.h"
 
55
#include "PNGWriter.h"
 
56
#ifdef ENABLE_LIBJPEG
 
57
#include "DCTStream.h"
 
58
#endif
 
59
#include "GlobalParams.h"
 
60
#include "HtmlOutputDev.h"
 
61
#include "HtmlFonts.h"
 
62
 
 
63
int HtmlPage::pgNum=0;
 
64
int HtmlOutputDev::imgNum=1;
 
65
GooList *HtmlOutputDev::imgList=new GooList();
 
66
 
 
67
extern GBool complexMode;
 
68
extern GBool singleHtml;
 
69
extern GBool ignore;
 
70
extern GBool printCommands;
 
71
extern GBool printHtml;
 
72
extern GBool noframes;
 
73
extern GBool stout;
 
74
extern GBool xml;
 
75
extern GBool showHidden;
 
76
extern GBool noMerge;
 
77
 
 
78
static GooString* basename(GooString* str){
 
79
  
 
80
  char *p=str->getCString();
 
81
  int len=str->getLength();
 
82
  for (int i=len-1;i>=0;i--)
 
83
    if (*(p+i)==SLASH) 
 
84
      return new GooString((p+i+1),len-i-1);
 
85
  return new GooString(str);
 
86
}
 
87
 
 
88
#if 0
 
89
static GooString* Dirname(GooString* str){
 
90
  
 
91
  char *p=str->getCString();
 
92
  int len=str->getLength();
 
93
  for (int i=len-1;i>=0;i--)
 
94
    if (*(p+i)==SLASH) 
 
95
      return new GooString(p,i+1);
 
96
  return new GooString();
 
97
 
98
#endif
 
99
 
 
100
//------------------------------------------------------------------------
 
101
// HtmlString
 
102
//------------------------------------------------------------------------
 
103
 
 
104
HtmlString::HtmlString(GfxState *state, double fontSize, HtmlFontAccu* fonts) {
 
105
  GfxFont *font;
 
106
  double x, y;
 
107
 
 
108
  state->transform(state->getCurX(), state->getCurY(), &x, &y);
 
109
  if ((font = state->getFont())) {
 
110
    double ascent = font->getAscent();
 
111
    double descent = font->getDescent();
 
112
    if( ascent > 1.05 ){
 
113
        //printf( "ascent=%.15g is too high, descent=%.15g\n", ascent, descent );
 
114
        ascent = 1.05;
 
115
    }
 
116
    if( descent < -0.4 ){
 
117
        //printf( "descent %.15g is too low, ascent=%.15g\n", descent, ascent );
 
118
        descent = -0.4;
 
119
    }
 
120
    yMin = y - ascent * fontSize;
 
121
    yMax = y - descent * fontSize;
 
122
    GfxRGB rgb;
 
123
    state->getFillRGB(&rgb);
 
124
    GooString *name = state->getFont()->getName();
 
125
    if (!name) name = HtmlFont::getDefaultFont(); //new GooString("default");
 
126
    HtmlFont hfont=HtmlFont(name, static_cast<int>(fontSize-1), rgb);
 
127
    fontpos = fonts->AddFont(hfont);
 
128
  } else {
 
129
    // this means that the PDF file draws text without a current font,
 
130
    // which should never happen
 
131
    yMin = y - 0.95 * fontSize;
 
132
    yMax = y + 0.35 * fontSize;
 
133
    fontpos=0;
 
134
  }
 
135
  if (yMin == yMax) {
 
136
    // this is a sanity check for a case that shouldn't happen -- but
 
137
    // if it does happen, we want to avoid dividing by zero later
 
138
    yMin = y;
 
139
    yMax = y + 1;
 
140
  }
 
141
  col = 0;
 
142
  text = NULL;
 
143
  xRight = NULL;
 
144
  link = NULL;
 
145
  len = size = 0;
 
146
  yxNext = NULL;
 
147
  xyNext = NULL;
 
148
  htext=new GooString();
 
149
  dir = textDirUnknown;
 
150
}
 
151
 
 
152
 
 
153
HtmlString::~HtmlString() {
 
154
  gfree(text);
 
155
  delete htext;
 
156
  gfree(xRight);
 
157
}
 
158
 
 
159
void HtmlString::addChar(GfxState *state, double x, double y,
 
160
                         double dx, double dy, Unicode u) {
 
161
  if (dir == textDirUnknown) {
 
162
    //dir = UnicodeMap::getDirection(u);
 
163
    dir = textDirLeftRight;
 
164
  } 
 
165
 
 
166
  if (len == size) {
 
167
    size += 16;
 
168
    text = (Unicode *)grealloc(text, size * sizeof(Unicode));
 
169
    xRight = (double *)grealloc(xRight, size * sizeof(double));
 
170
  }
 
171
  text[len] = u;
 
172
  if (len == 0) {
 
173
    xMin = x;
 
174
  }
 
175
  xMax = xRight[len] = x + dx;
 
176
//printf("added char: %f %f xright = %f\n", x, dx, x+dx);
 
177
  ++len;
 
178
}
 
179
 
 
180
void HtmlString::endString()
 
181
{
 
182
  if( dir == textDirRightLeft && len > 1 )
 
183
  {
 
184
    //printf("will reverse!\n");
 
185
    for (int i = 0; i < len / 2; i++)
 
186
    {
 
187
      Unicode ch = text[i];
 
188
      text[i] = text[len - i - 1];
 
189
      text[len - i - 1] = ch;
 
190
    }
 
191
  }
 
192
}
 
193
 
 
194
//------------------------------------------------------------------------
 
195
// HtmlPage
 
196
//------------------------------------------------------------------------
 
197
 
 
198
HtmlPage::HtmlPage(GBool rawOrder, char *imgExtVal) {
 
199
  this->rawOrder = rawOrder;
 
200
  curStr = NULL;
 
201
  yxStrings = NULL;
 
202
  xyStrings = NULL;
 
203
  yxCur1 = yxCur2 = NULL;
 
204
  fonts=new HtmlFontAccu();
 
205
  links=new HtmlLinks();
 
206
  pageWidth=0;
 
207
  pageHeight=0;
 
208
  fontsPageMarker = 0;
 
209
  DocName=NULL;
 
210
  firstPage = -1;
 
211
  imgExt = new GooString(imgExtVal);
 
212
}
 
213
 
 
214
HtmlPage::~HtmlPage() {
 
215
  clear();
 
216
  if (DocName) delete DocName;
 
217
  if (fonts) delete fonts;
 
218
  if (links) delete links;
 
219
  if (imgExt) delete imgExt;  
 
220
}
 
221
 
 
222
void HtmlPage::updateFont(GfxState *state) {
 
223
  GfxFont *font;
 
224
  double *fm;
 
225
  char *name;
 
226
  int code;
 
227
  double w;
 
228
  
 
229
  // adjust the font size
 
230
  fontSize = state->getTransformedFontSize();
 
231
  if ((font = state->getFont()) && font->getType() == fontType3) {
 
232
    // This is a hack which makes it possible to deal with some Type 3
 
233
    // fonts.  The problem is that it's impossible to know what the
 
234
    // base coordinate system used in the font is without actually
 
235
    // rendering the font.  This code tries to guess by looking at the
 
236
    // width of the character 'm' (which breaks if the font is a
 
237
    // subset that doesn't contain 'm').
 
238
    for (code = 0; code < 256; ++code) {
 
239
      if ((name = ((Gfx8BitFont *)font)->getCharName(code)) &&
 
240
          name[0] == 'm' && name[1] == '\0') {
 
241
        break;
 
242
      }
 
243
    }
 
244
    if (code < 256) {
 
245
      w = ((Gfx8BitFont *)font)->getWidth(code);
 
246
      if (w != 0) {
 
247
        // 600 is a generic average 'm' width -- yes, this is a hack
 
248
        fontSize *= w / 0.6;
 
249
      }
 
250
    }
 
251
    fm = font->getFontMatrix();
 
252
    if (fm[0] != 0) {
 
253
      fontSize *= fabs(fm[3] / fm[0]);
 
254
    }
 
255
  }
 
256
}
 
257
 
 
258
void HtmlPage::beginString(GfxState *state, GooString *s) {
 
259
  curStr = new HtmlString(state, fontSize, fonts);
 
260
}
 
261
 
 
262
 
 
263
void HtmlPage::conv(){
 
264
  HtmlString *tmp;
 
265
 
 
266
  int linkIndex = 0;
 
267
  HtmlFont* h;
 
268
  for(tmp=yxStrings;tmp;tmp=tmp->yxNext){
 
269
     int pos=tmp->fontpos;
 
270
     //  printf("%d\n",pos);
 
271
     h=fonts->Get(pos);
 
272
 
 
273
     if (tmp->htext) delete tmp->htext; 
 
274
     tmp->htext=HtmlFont::simple(h,tmp->text,tmp->len);
 
275
 
 
276
     if (links->inLink(tmp->xMin,tmp->yMin,tmp->xMax,tmp->yMax, linkIndex)){
 
277
       tmp->link = links->getLink(linkIndex);
 
278
       /*GooString *t=tmp->htext;
 
279
       tmp->htext=links->getLink(k)->Link(tmp->htext);
 
280
       delete t;*/
 
281
     }
 
282
  }
 
283
 
 
284
}
 
285
 
 
286
 
 
287
void HtmlPage::addChar(GfxState *state, double x, double y,
 
288
                       double dx, double dy, 
 
289
                        double ox, double oy, Unicode *u, int uLen) {
 
290
  double x1, y1, w1, h1, dx2, dy2;
 
291
  int n, i;
 
292
  state->transform(x, y, &x1, &y1);
 
293
  n = curStr->len;
 
294
 
 
295
  // check that new character is in the same direction as current string
 
296
  // and is not too far away from it before adding 
 
297
  //if ((UnicodeMap::getDirection(u[0]) != curStr->dir) || 
 
298
  // XXX
 
299
  if (
 
300
     (n > 0 && 
 
301
      fabs(x1 - curStr->xRight[n-1]) > 0.1 * (curStr->yMax - curStr->yMin))) {
 
302
    endString();
 
303
    beginString(state, NULL);
 
304
  }
 
305
  state->textTransformDelta(state->getCharSpace() * state->getHorizScaling(),
 
306
                            0, &dx2, &dy2);
 
307
  dx -= dx2;
 
308
  dy -= dy2;
 
309
  state->transformDelta(dx, dy, &w1, &h1);
 
310
  if (uLen != 0) {
 
311
    w1 /= uLen;
 
312
    h1 /= uLen;
 
313
  }
 
314
  for (i = 0; i < uLen; ++i) {
 
315
    curStr->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u[i]);
 
316
  }
 
317
}
 
318
 
 
319
void HtmlPage::endString() {
 
320
  HtmlString *p1, *p2;
 
321
  double h, y1, y2;
 
322
 
 
323
  // throw away zero-length strings -- they don't have valid xMin/xMax
 
324
  // values, and they're useless anyway
 
325
  if (curStr->len == 0) {
 
326
    delete curStr;
 
327
    curStr = NULL;
 
328
    return;
 
329
  }
 
330
 
 
331
  curStr->endString();
 
332
 
 
333
#if 0 //~tmp
 
334
  if (curStr->yMax - curStr->yMin > 20) {
 
335
    delete curStr;
 
336
    curStr = NULL;
 
337
    return;
 
338
  }
 
339
#endif
 
340
 
 
341
  // insert string in y-major list
 
342
  h = curStr->yMax - curStr->yMin;
 
343
  y1 = curStr->yMin + 0.5 * h;
 
344
  y2 = curStr->yMin + 0.8 * h;
 
345
  if (rawOrder) {
 
346
    p1 = yxCur1;
 
347
    p2 = NULL;
 
348
  } else if ((!yxCur1 ||
 
349
              (y1 >= yxCur1->yMin &&
 
350
               (y2 >= yxCur1->yMax || curStr->xMax >= yxCur1->xMin))) &&
 
351
             (!yxCur2 ||
 
352
              (y1 < yxCur2->yMin ||
 
353
               (y2 < yxCur2->yMax && curStr->xMax < yxCur2->xMin)))) {
 
354
    p1 = yxCur1;
 
355
    p2 = yxCur2;
 
356
  } else {
 
357
    for (p1 = NULL, p2 = yxStrings; p2; p1 = p2, p2 = p2->yxNext) {
 
358
      if (y1 < p2->yMin || (y2 < p2->yMax && curStr->xMax < p2->xMin))
 
359
        break;
 
360
    }
 
361
    yxCur2 = p2;
 
362
  }
 
363
  yxCur1 = curStr;
 
364
  if (p1)
 
365
    p1->yxNext = curStr;
 
366
  else
 
367
    yxStrings = curStr;
 
368
  curStr->yxNext = p2;
 
369
  curStr = NULL;
 
370
}
 
371
 
 
372
static const char *strrstr( const char *s, const char *ss )
 
373
{
 
374
  const char *p = strstr( s, ss );
 
375
  for( const char *pp = p; pp != NULL; pp = strstr( p+1, ss ) ){
 
376
    p = pp;
 
377
  }
 
378
  return p;
 
379
}
 
380
 
 
381
static void CloseTags( GooString *htext, GBool &finish_a, GBool &finish_italic, GBool &finish_bold )
 
382
{
 
383
  const char *last_italic = finish_italic && ( finish_bold   || finish_a    ) ? strrstr( htext->getCString(), "<i>" ) : NULL;
 
384
  const char *last_bold   = finish_bold   && ( finish_italic || finish_a    ) ? strrstr( htext->getCString(), "<b>" ) : NULL;
 
385
  const char *last_a      = finish_a      && ( finish_italic || finish_bold ) ? strrstr( htext->getCString(), "<a " ) : NULL;
 
386
  if( finish_a && ( finish_italic || finish_bold ) && last_a > ( last_italic > last_bold ? last_italic : last_bold ) ){
 
387
    htext->append("</a>", 4);
 
388
    finish_a = false;
 
389
  }
 
390
  if( finish_italic && finish_bold && last_italic > last_bold ){
 
391
    htext->append("</i>", 4);
 
392
    finish_italic = false;
 
393
  }
 
394
  if( finish_bold )
 
395
    htext->append("</b>", 4);
 
396
  if( finish_italic )
 
397
    htext->append("</i>", 4);
 
398
  if( finish_a )
 
399
    htext->append("</a>");
 
400
}
 
401
 
 
402
void HtmlPage::coalesce() {
 
403
  HtmlString *str1, *str2;
 
404
  HtmlFont *hfont1, *hfont2;
 
405
  double space, horSpace, vertSpace, vertOverlap;
 
406
  GBool addSpace, addLineBreak;
 
407
  int n, i;
 
408
  double curX, curY;
 
409
 
 
410
#if 0 //~ for debugging
 
411
  for (str1 = yxStrings; str1; str1 = str1->yxNext) {
 
412
    printf("x=%f..%f  y=%f..%f  size=%2d '",
 
413
           str1->xMin, str1->xMax, str1->yMin, str1->yMax,
 
414
           (int)(str1->yMax - str1->yMin));
 
415
    for (i = 0; i < str1->len; ++i) {
 
416
      fputc(str1->text[i] & 0xff, stdout);
 
417
    }
 
418
    printf("'\n");
 
419
  }
 
420
  printf("\n------------------------------------------------------------\n\n");
 
421
#endif
 
422
  str1 = yxStrings;
 
423
 
 
424
  if( !str1 ) return;
 
425
 
 
426
  //----- discard duplicated text (fake boldface, drop shadows)
 
427
  if( !complexMode )
 
428
  {     /* if not in complex mode get rid of duplicate strings */
 
429
        HtmlString *str3;
 
430
        GBool found;
 
431
        while (str1)
 
432
        {
 
433
                double size = str1->yMax - str1->yMin;
 
434
                double xLimit = str1->xMin + size * 0.2;
 
435
                found = gFalse;
 
436
                for (str2 = str1, str3 = str1->yxNext;
 
437
                        str3 && str3->xMin < xLimit;
 
438
                        str2 = str3, str3 = str2->yxNext)
 
439
                {
 
440
                        if (str3->len == str1->len &&
 
441
                                !memcmp(str3->text, str1->text, str1->len * sizeof(Unicode)) &&
 
442
                                fabs(str3->yMin - str1->yMin) < size * 0.2 &&
 
443
                                fabs(str3->yMax - str1->yMax) < size * 0.2 &&
 
444
                                fabs(str3->xMax - str1->xMax) < size * 0.2)
 
445
                        {
 
446
                                found = gTrue;
 
447
                                //printf("found duplicate!\n");
 
448
                                break;
 
449
                        }
 
450
                }
 
451
                if (found)
 
452
                {
 
453
                        str2->xyNext = str3->xyNext;
 
454
                        str2->yxNext = str3->yxNext;
 
455
                        delete str3;
 
456
                }
 
457
                else
 
458
                {
 
459
                        str1 = str1->yxNext;
 
460
                }
 
461
        }               
 
462
  }     /*- !complexMode */
 
463
  
 
464
  str1 = yxStrings;
 
465
  
 
466
  hfont1 = getFont(str1);
 
467
  if( hfont1->isBold() )
 
468
    str1->htext->insert(0,"<b>",3);
 
469
  if( hfont1->isItalic() )
 
470
    str1->htext->insert(0,"<i>",3);
 
471
  if( str1->getLink() != NULL ) {
 
472
    GooString *ls = str1->getLink()->getLinkStart();
 
473
    str1->htext->insert(0, ls);
 
474
    delete ls;
 
475
  }
 
476
  curX = str1->xMin; curY = str1->yMin;
 
477
 
 
478
  while (str1 && (str2 = str1->yxNext)) {
 
479
    hfont2 = getFont(str2);
 
480
    space = str1->yMax - str1->yMin;
 
481
    horSpace = str2->xMin - str1->xMax;
 
482
    addLineBreak = !noMerge && (fabs(str1->xMin - str2->xMin) < 0.4);
 
483
    vertSpace = str2->yMin - str1->yMax;
 
484
 
 
485
//printf("coalesce %d %d %f? ", str1->dir, str2->dir, d);
 
486
 
 
487
    if (str2->yMin >= str1->yMin && str2->yMin <= str1->yMax)
 
488
    {
 
489
        vertOverlap = str1->yMax - str2->yMin;
 
490
    } else
 
491
    if (str2->yMax >= str1->yMin && str2->yMax <= str1->yMax)
 
492
    {
 
493
        vertOverlap = str2->yMax - str1->yMin;
 
494
    } else
 
495
    {
 
496
        vertOverlap = 0;
 
497
    } 
 
498
    
 
499
    if (
 
500
        (
 
501
         (
 
502
          (
 
503
           (rawOrder && vertOverlap > 0.5 * space) 
 
504
           ||
 
505
           (!rawOrder && str2->yMin < str1->yMax)
 
506
          ) &&
 
507
          (horSpace > -0.5 * space && horSpace < space)
 
508
         ) ||
 
509
         (vertSpace >= 0 && vertSpace < 0.5 * space && addLineBreak)
 
510
        ) &&
 
511
        (!complexMode || (hfont1->isEqualIgnoreBold(*hfont2))) && // in complex mode fonts must be the same, in other modes fonts do not metter
 
512
        str1->dir == str2->dir // text direction the same
 
513
       ) 
 
514
    {
 
515
//      printf("yes\n");
 
516
      n = str1->len + str2->len;
 
517
      if ((addSpace = horSpace > 0.1 * space)) {
 
518
        ++n;
 
519
      }
 
520
      if (addLineBreak) {
 
521
        ++n;
 
522
      }
 
523
  
 
524
      str1->size = (n + 15) & ~15;
 
525
      str1->text = (Unicode *)grealloc(str1->text,
 
526
                                       str1->size * sizeof(Unicode));
 
527
      str1->xRight = (double *)grealloc(str1->xRight,
 
528
                                        str1->size * sizeof(double));
 
529
      if (addSpace) {
 
530
                  str1->text[str1->len] = 0x20;
 
531
                  str1->htext->append(xml?" ":"&nbsp;");
 
532
                  str1->xRight[str1->len] = str2->xMin;
 
533
                  ++str1->len;
 
534
      }
 
535
      if (addLineBreak) {
 
536
          str1->text[str1->len] = '\n';
 
537
          str1->htext->append("<br>");
 
538
          str1->xRight[str1->len] = str2->xMin;
 
539
          ++str1->len;
 
540
          str1->yMin = str2->yMin;
 
541
          str1->yMax = str2->yMax;
 
542
          str1->xMax = str2->xMax;
 
543
          int fontLineSize = hfont1->getLineSize();
 
544
          int curLineSize = (int)(vertSpace + space); 
 
545
          if( curLineSize != fontLineSize )
 
546
          {
 
547
              HtmlFont *newfnt = new HtmlFont(*hfont1);
 
548
              newfnt->setLineSize(curLineSize);
 
549
              str1->fontpos = fonts->AddFont(*newfnt);
 
550
              delete newfnt;
 
551
              hfont1 = getFont(str1);
 
552
              // we have to reget hfont2 because it's location could have
 
553
              // changed on resize
 
554
              hfont2 = getFont(str2); 
 
555
          }
 
556
      }
 
557
      for (i = 0; i < str2->len; ++i) {
 
558
        str1->text[str1->len] = str2->text[i];
 
559
        str1->xRight[str1->len] = str2->xRight[i];
 
560
        ++str1->len;
 
561
      }
 
562
 
 
563
      /* fix <i>, <b> if str1 and str2 differ and handle switch of links */
 
564
      HtmlLink *hlink1 = str1->getLink();
 
565
      HtmlLink *hlink2 = str2->getLink();
 
566
      bool switch_links = !hlink1 || !hlink2 || !hlink1->isEqualDest(*hlink2);
 
567
      GBool finish_a = switch_links && hlink1 != NULL;
 
568
      GBool finish_italic = hfont1->isItalic() && ( !hfont2->isItalic() || finish_a );
 
569
      GBool finish_bold   = hfont1->isBold()   && ( !hfont2->isBold()   || finish_a || finish_italic );
 
570
      CloseTags( str1->htext, finish_a, finish_italic, finish_bold );
 
571
      if( switch_links && hlink2 != NULL ) {
 
572
        GooString *ls = hlink2->getLinkStart();
 
573
        str1->htext->append(ls);
 
574
        delete ls;
 
575
      }
 
576
      if( ( !hfont1->isItalic() || finish_italic ) && hfont2->isItalic() )
 
577
            str1->htext->append("<i>", 3);
 
578
      if( ( !hfont1->isBold() || finish_bold ) && hfont2->isBold() )
 
579
            str1->htext->append("<b>", 3);
 
580
 
 
581
 
 
582
      str1->htext->append(str2->htext);
 
583
      // str1 now contains href for link of str2 (if it is defined)
 
584
      str1->link = str2->link; 
 
585
      hfont1 = hfont2;
 
586
      if (str2->xMax > str1->xMax) {
 
587
        str1->xMax = str2->xMax;
 
588
      }
 
589
      if (str2->yMax > str1->yMax) {
 
590
        str1->yMax = str2->yMax;
 
591
      }
 
592
      str1->yxNext = str2->yxNext;
 
593
      delete str2;
 
594
    } else { // keep strings separate
 
595
//      printf("no\n"); 
 
596
      GBool finish_a = str1->getLink() != NULL;
 
597
      GBool finish_bold   = hfont1->isBold();
 
598
      GBool finish_italic = hfont1->isItalic();
 
599
      CloseTags( str1->htext, finish_a, finish_italic, finish_bold );
 
600
     
 
601
      str1->xMin = curX; str1->yMin = curY; 
 
602
      str1 = str2;
 
603
      curX = str1->xMin; curY = str1->yMin;
 
604
      hfont1 = hfont2;
 
605
      if( hfont1->isBold() )
 
606
        str1->htext->insert(0,"<b>",3);
 
607
      if( hfont1->isItalic() )
 
608
        str1->htext->insert(0,"<i>",3);
 
609
      if( str1->getLink() != NULL ) {
 
610
        GooString *ls = str1->getLink()->getLinkStart();
 
611
        str1->htext->insert(0, ls);
 
612
        delete ls;
 
613
      }
 
614
    }
 
615
  }
 
616
  str1->xMin = curX; str1->yMin = curY;
 
617
 
 
618
  GBool finish_bold   = hfont1->isBold();
 
619
  GBool finish_italic = hfont1->isItalic();
 
620
  GBool finish_a = str1->getLink() != NULL;
 
621
  CloseTags( str1->htext, finish_a, finish_italic, finish_bold );
 
622
 
 
623
#if 0 //~ for debugging
 
624
  for (str1 = yxStrings; str1; str1 = str1->yxNext) {
 
625
    printf("x=%3d..%3d  y=%3d..%3d  size=%2d ",
 
626
           (int)str1->xMin, (int)str1->xMax, (int)str1->yMin, (int)str1->yMax,
 
627
           (int)(str1->yMax - str1->yMin));
 
628
    printf("'%s'\n", str1->htext->getCString());  
 
629
  }
 
630
  printf("\n------------------------------------------------------------\n\n");
 
631
#endif
 
632
 
 
633
}
 
634
 
 
635
void HtmlPage::dumpAsXML(FILE* f,int page){  
 
636
  fprintf(f, "<page number=\"%d\" position=\"absolute\"", page);
 
637
  fprintf(f," top=\"0\" left=\"0\" height=\"%d\" width=\"%d\">\n", pageHeight,pageWidth);
 
638
    
 
639
  for(int i=fontsPageMarker;i < fonts->size();i++) {
 
640
    GooString *fontCSStyle = fonts->CSStyle(i);
 
641
    fprintf(f,"\t%s\n",fontCSStyle->getCString());
 
642
    delete fontCSStyle;
 
643
  }
 
644
  
 
645
  GooString *str, *str1 = NULL;
 
646
  for(HtmlString *tmp=yxStrings;tmp;tmp=tmp->yxNext){
 
647
    if (tmp->htext){
 
648
      str=new GooString(tmp->htext);
 
649
      fprintf(f,"<text top=\"%d\" left=\"%d\" ",xoutRound(tmp->yMin),xoutRound(tmp->xMin));
 
650
      fprintf(f,"width=\"%d\" height=\"%d\" ",xoutRound(tmp->xMax-tmp->xMin),xoutRound(tmp->yMax-tmp->yMin));
 
651
      fprintf(f,"font=\"%d\">", tmp->fontpos);
 
652
      str1=fonts->getCSStyle(tmp->fontpos, str);
 
653
      fputs(str1->getCString(),f);
 
654
      delete str;
 
655
      delete str1;
 
656
      fputs("</text>\n",f);
 
657
    }
 
658
  }
 
659
  fputs("</page>\n",f);
 
660
}
 
661
 
 
662
 
 
663
void HtmlPage::dumpComplex(FILE *file, int page){
 
664
  FILE* pageFile;
 
665
  GooString* tmp;
 
666
  char* htmlEncoding;
 
667
 
 
668
  if( firstPage == -1 ) firstPage = page; 
 
669
  
 
670
  if( !noframes )
 
671
  {
 
672
      GooString* pgNum=GooString::fromInt(page);
 
673
      tmp = new GooString(DocName);
 
674
      if (!singleHtml){
 
675
            tmp->append('-')->append(pgNum)->append(".html");
 
676
            pageFile = fopen(tmp->getCString(), "w");
 
677
      } else {
 
678
            tmp->append("-html")->append(".html");
 
679
            pageFile = fopen(tmp->getCString(), "a");
 
680
      }
 
681
      delete pgNum;
 
682
      if (!pageFile) {
 
683
          error(-1, "Couldn't open html file '%s'", tmp->getCString());
 
684
          delete tmp;
 
685
          return;
 
686
      } 
 
687
 
 
688
      if (!singleHtml)
 
689
          fprintf(pageFile,"%s\n<HTML>\n<HEAD>\n<TITLE>Page %d</TITLE>\n\n", DOCTYPE, page);
 
690
      else
 
691
          fprintf(pageFile,"%s\n<HTML>\n<HEAD>\n<TITLE>%s</TITLE>\n\n", DOCTYPE, tmp->getCString());
 
692
 
 
693
      delete tmp;
 
694
 
 
695
      htmlEncoding = HtmlOutputDev::mapEncodingToHtml
 
696
          (globalParams->getTextEncodingName());
 
697
      if (!singleHtml)
 
698
          fprintf(pageFile, "<META http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n", htmlEncoding);
 
699
      else
 
700
          fprintf(pageFile, "<META http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n <br>\n", htmlEncoding);
 
701
  }
 
702
  else 
 
703
  {
 
704
      pageFile = file;
 
705
      fprintf(pageFile,"<!-- Page %d -->\n", page);
 
706
      fprintf(pageFile,"<a name=\"%d\"></a>\n", page);
 
707
  } 
 
708
  
 
709
  fprintf(pageFile,"<DIV style=\"position:relative;width:%d;height:%d;\">\n",
 
710
        pageWidth, pageHeight);
 
711
 
 
712
  tmp=basename(DocName);
 
713
   
 
714
  fputs("<STYLE type=\"text/css\">\n<!--\n",pageFile);
 
715
  for(int i=fontsPageMarker;i!=fonts->size();i++) {
 
716
    GooString *fontCSStyle;
 
717
    if (!singleHtml)
 
718
         fontCSStyle = fonts->CSStyle(i);
 
719
    else
 
720
         fontCSStyle = fonts->CSStyle(i,page);
 
721
    fprintf(pageFile,"\t%s\n",fontCSStyle->getCString());
 
722
    delete fontCSStyle;
 
723
  }
 
724
 
 
725
  fputs("-->\n</STYLE>\n",pageFile);
 
726
  
 
727
  if( !noframes )
 
728
  {  
 
729
      fputs("</HEAD>\n<BODY bgcolor=\"#A0A0A0\" vlink=\"blue\" link=\"blue\">\n",pageFile); 
 
730
  }
 
731
  
 
732
  if( !ignore ) 
 
733
  {
 
734
    fprintf(pageFile,
 
735
            "<IMG width=\"%d\" height=\"%d\" src=\"%s%03d.%s\" alt=\"background image\">\n",
 
736
            pageWidth, pageHeight, tmp->getCString(), 
 
737
                (page-firstPage+1), imgExt->getCString());
 
738
  }
 
739
  
 
740
  delete tmp;
 
741
  
 
742
  GooString *str, *str1 = NULL;
 
743
  for(HtmlString *tmp1=yxStrings;tmp1;tmp1=tmp1->yxNext){
 
744
    if (tmp1->htext){
 
745
      str=new GooString(tmp1->htext);
 
746
      fprintf(pageFile,
 
747
              "<DIV style=\"position:absolute;top:%d;left:%d\">",
 
748
              xoutRound(tmp1->yMin),
 
749
              xoutRound(tmp1->xMin));
 
750
      fputs("<nobr>",pageFile); 
 
751
      if (!singleHtml)
 
752
          str1=fonts->getCSStyle(tmp1->fontpos, str);
 
753
      else
 
754
          str1=fonts->getCSStyle(tmp1->fontpos, str, page);
 
755
      fputs(str1->getCString(),pageFile);
 
756
      delete str;      
 
757
      delete str1;
 
758
      fputs("</nobr></DIV>\n",pageFile);
 
759
    }
 
760
  }
 
761
 
 
762
  fputs("</DIV>\n", pageFile);
 
763
  
 
764
  if( !noframes )
 
765
  {
 
766
      fputs("</BODY>\n</HTML>\n",pageFile);
 
767
      fclose(pageFile);
 
768
  }
 
769
}
 
770
 
 
771
 
 
772
void HtmlPage::dump(FILE *f, int pageNum) 
 
773
{
 
774
  if (complexMode || singleHtml)
 
775
  {
 
776
    if (xml) dumpAsXML(f, pageNum);
 
777
    if (!xml) dumpComplex(f, pageNum);  
 
778
  }
 
779
  else
 
780
  {
 
781
    fprintf(f,"<A name=%d></a>",pageNum);
 
782
    // Loop over the list of image names on this page
 
783
    int listlen=HtmlOutputDev::imgList->getLength();
 
784
    for (int i = 0; i < listlen; i++) {
 
785
      GooString *fName= (GooString *)HtmlOutputDev::imgList->del(0);
 
786
      fprintf(f,"<IMG src=\"%s\"><br>\n",fName->getCString());
 
787
      delete fName;
 
788
    }
 
789
    HtmlOutputDev::imgNum=1;
 
790
 
 
791
    GooString* str;
 
792
    for(HtmlString *tmp=yxStrings;tmp;tmp=tmp->yxNext){
 
793
      if (tmp->htext){
 
794
                str=new GooString(tmp->htext); 
 
795
                fputs(str->getCString(),f);
 
796
                delete str;      
 
797
                fputs("<br>\n",f);  
 
798
      }
 
799
    }
 
800
        fputs("<hr>\n",f);  
 
801
  }
 
802
}
 
803
 
 
804
 
 
805
 
 
806
void HtmlPage::clear() {
 
807
  HtmlString *p1, *p2;
 
808
 
 
809
  if (curStr) {
 
810
    delete curStr;
 
811
    curStr = NULL;
 
812
  }
 
813
  for (p1 = yxStrings; p1; p1 = p2) {
 
814
    p2 = p1->yxNext;
 
815
    delete p1;
 
816
  }
 
817
  yxStrings = NULL;
 
818
  xyStrings = NULL;
 
819
  yxCur1 = yxCur2 = NULL;
 
820
 
 
821
  if( !noframes )
 
822
  {
 
823
      delete fonts;
 
824
      fonts=new HtmlFontAccu();
 
825
      fontsPageMarker = 0;
 
826
  }
 
827
  else
 
828
  {
 
829
      fontsPageMarker = fonts->size();
 
830
  }
 
831
 
 
832
  delete links;
 
833
  links=new HtmlLinks();
 
834
 
 
835
 
 
836
}
 
837
 
 
838
void HtmlPage::setDocName(char *fname){
 
839
  DocName=new GooString(fname);
 
840
}
 
841
 
 
842
//------------------------------------------------------------------------
 
843
// HtmlMetaVar
 
844
//------------------------------------------------------------------------
 
845
 
 
846
HtmlMetaVar::HtmlMetaVar(char *_name, char *_content)
 
847
{
 
848
    name = new GooString(_name);
 
849
    content = new GooString(_content);
 
850
}
 
851
 
 
852
HtmlMetaVar::~HtmlMetaVar()
 
853
{
 
854
   delete name;
 
855
   delete content;
 
856
 
857
    
 
858
GooString* HtmlMetaVar::toString()      
 
859
{
 
860
    GooString *result = new GooString("<META name=\"");
 
861
    result->append(name);
 
862
    result->append("\" content=\"");
 
863
    result->append(content);
 
864
    result->append("\">"); 
 
865
    return result;
 
866
}
 
867
 
 
868
//------------------------------------------------------------------------
 
869
// HtmlOutputDev
 
870
//------------------------------------------------------------------------
 
871
 
 
872
static char* HtmlEncodings[][2] = {
 
873
    {"Latin1", "ISO-8859-1"},
 
874
    {NULL, NULL}
 
875
};
 
876
 
 
877
 
 
878
char* HtmlOutputDev::mapEncodingToHtml(GooString* encoding)
 
879
{
 
880
    char* enc = encoding->getCString();
 
881
    for(int i = 0; HtmlEncodings[i][0] != NULL; i++)
 
882
    {
 
883
        if( strcmp(enc, HtmlEncodings[i][0]) == 0 )
 
884
        {
 
885
            return HtmlEncodings[i][1];
 
886
        }
 
887
    }
 
888
    return enc; 
 
889
}
 
890
 
 
891
void HtmlOutputDev::doFrame(int firstPage){
 
892
  GooString* fName=new GooString(Docname);
 
893
  char* htmlEncoding;
 
894
  fName->append(".html");
 
895
 
 
896
  if (!(fContentsFrame = fopen(fName->getCString(), "w"))){
 
897
    error(-1, "Couldn't open html file '%s'", fName->getCString());
 
898
    delete fName;
 
899
    return;
 
900
  }
 
901
  
 
902
  delete fName;
 
903
    
 
904
  fName=basename(Docname);
 
905
  fputs(DOCTYPE_FRAMES, fContentsFrame);
 
906
  fputs("\n<HTML>",fContentsFrame);
 
907
  fputs("\n<HEAD>",fContentsFrame);
 
908
  fprintf(fContentsFrame,"\n<TITLE>%s</TITLE>",docTitle->getCString());
 
909
  htmlEncoding = mapEncodingToHtml(globalParams->getTextEncodingName());
 
910
  fprintf(fContentsFrame, "\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n", htmlEncoding);
 
911
  dumpMetaVars(fContentsFrame);
 
912
  fprintf(fContentsFrame, "</HEAD>\n");
 
913
  fputs("<FRAMESET cols=\"100,*\">\n",fContentsFrame);
 
914
  fprintf(fContentsFrame,"<FRAME name=\"links\" src=\"%s_ind.html\">\n",fName->getCString());
 
915
  fputs("<FRAME name=\"contents\" src=",fContentsFrame); 
 
916
  if (complexMode) 
 
917
      fprintf(fContentsFrame,"\"%s-%d.html\"",fName->getCString(), firstPage);
 
918
  else
 
919
      fprintf(fContentsFrame,"\"%ss.html\"",fName->getCString());
 
920
  
 
921
  fputs(">\n</FRAMESET>\n</HTML>\n",fContentsFrame);
 
922
 
 
923
  delete fName;
 
924
  fclose(fContentsFrame);  
 
925
}
 
926
 
 
927
HtmlOutputDev::HtmlOutputDev(char *fileName, char *title, 
 
928
        char *author, char *keywords, char *subject, char *date,
 
929
        char *extension,
 
930
        GBool rawOrder, int firstPage, GBool outline) 
 
931
{
 
932
  char *htmlEncoding;
 
933
  
 
934
  fContentsFrame = NULL;
 
935
  docTitle = new GooString(title);
 
936
  pages = NULL;
 
937
  dumpJPEG=gTrue;
 
938
  //write = gTrue;
 
939
  this->rawOrder = rawOrder;
 
940
  this->doOutline = outline;
 
941
  ok = gFalse;
 
942
  imgNum=1;
 
943
  //this->firstPage = firstPage;
 
944
  //pageNum=firstPage;
 
945
  // open file
 
946
  needClose = gFalse;
 
947
  pages = new HtmlPage(rawOrder, extension);
 
948
  
 
949
  glMetaVars = new GooList();
 
950
  glMetaVars->append(new HtmlMetaVar("generator", "pdftohtml 0.36"));  
 
951
  if( author ) glMetaVars->append(new HtmlMetaVar("author", author));  
 
952
  if( keywords ) glMetaVars->append(new HtmlMetaVar("keywords", keywords));  
 
953
  if( date ) glMetaVars->append(new HtmlMetaVar("date", date));  
 
954
  if( subject ) glMetaVars->append(new HtmlMetaVar("subject", subject));
 
955
 
 
956
  maxPageWidth = 0;
 
957
  maxPageHeight = 0;
 
958
 
 
959
  pages->setDocName(fileName);
 
960
  Docname=new GooString (fileName);
 
961
 
 
962
  // for non-xml output (complex or simple) with frames generate the left frame
 
963
  if(!xml && !noframes)
 
964
  {
 
965
     if (!singleHtml)
 
966
     {
 
967
         GooString* left=new GooString(fileName);
 
968
         left->append("_ind.html");
 
969
 
 
970
         doFrame(firstPage);
 
971
 
 
972
         if (!(fContentsFrame = fopen(left->getCString(), "w")))
 
973
         {
 
974
             error(-1, "Couldn't open html file '%s'", left->getCString());
 
975
             delete left;
 
976
             return;
 
977
         }
 
978
         delete left;
 
979
         fputs(DOCTYPE, fContentsFrame);
 
980
         fputs("<HTML>\n<HEAD>\n<TITLE></TITLE>\n</HEAD>\n<BODY>\n",fContentsFrame);
 
981
 
 
982
         if (doOutline)
 
983
         {
 
984
             GooString *str = basename(Docname);
 
985
             fprintf(fContentsFrame, "<A href=\"%s%s\" target=\"contents\">Outline</a><br>", str->getCString(), complexMode ? "-outline.html" : "s.html#outline");
 
986
             delete str;
 
987
         }
 
988
     }
 
989
        if (!complexMode)
 
990
        {       /* not in complex mode */
 
991
                
 
992
       GooString* right=new GooString(fileName);
 
993
       right->append("s.html");
 
994
 
 
995
       if (!(page=fopen(right->getCString(),"w"))){
 
996
        error(-1, "Couldn't open html file '%s'", right->getCString());
 
997
        delete right;
 
998
                return;
 
999
       }
 
1000
       delete right;
 
1001
       fputs(DOCTYPE, page);
 
1002
       fputs("<HTML>\n<HEAD>\n<TITLE></TITLE>\n</HEAD>\n<BODY>\n",page);
 
1003
     }
 
1004
  }
 
1005
 
 
1006
  if (noframes) {
 
1007
    if (stout) page=stdout;
 
1008
    else {
 
1009
      GooString* right=new GooString(fileName);
 
1010
      if (!xml) right->append(".html");
 
1011
      if (xml) right->append(".xml");
 
1012
      if (!(page=fopen(right->getCString(),"w"))){
 
1013
        error(-1, "Couldn't open html file '%s'", right->getCString());
 
1014
        delete right;
 
1015
        return;
 
1016
      }  
 
1017
      delete right;
 
1018
    }
 
1019
 
 
1020
    htmlEncoding = mapEncodingToHtml(globalParams->getTextEncodingName()); 
 
1021
    if (xml) 
 
1022
    {
 
1023
      fprintf(page, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", htmlEncoding);
 
1024
      fputs("<!DOCTYPE pdf2xml SYSTEM \"pdf2xml.dtd\">\n\n", page);
 
1025
      fputs("<pdf2xml>\n",page);
 
1026
    } 
 
1027
    else 
 
1028
    {
 
1029
      fprintf(page,"%s\n<HTML>\n<HEAD>\n<TITLE>%s</TITLE>\n",
 
1030
              DOCTYPE, docTitle->getCString());
 
1031
      
 
1032
      fprintf(page, "<META http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n", htmlEncoding);
 
1033
      
 
1034
      dumpMetaVars(page);
 
1035
      fprintf(page,"</HEAD>\n");
 
1036
      fprintf(page,"<BODY bgcolor=\"#A0A0A0\" vlink=\"blue\" link=\"blue\">\n");
 
1037
    }
 
1038
  }
 
1039
  ok = gTrue; 
 
1040
}
 
1041
 
 
1042
HtmlOutputDev::~HtmlOutputDev() {
 
1043
    HtmlFont::clear(); 
 
1044
    
 
1045
    delete Docname;
 
1046
    delete docTitle;
 
1047
 
 
1048
    deleteGooList(glMetaVars, HtmlMetaVar);
 
1049
 
 
1050
    if (fContentsFrame){
 
1051
      fputs("</BODY>\n</HTML>\n",fContentsFrame);  
 
1052
      fclose(fContentsFrame);
 
1053
    }
 
1054
    if (xml) {
 
1055
      fputs("</pdf2xml>\n",page);  
 
1056
      fclose(page);
 
1057
    } else
 
1058
    if ( !complexMode || xml || noframes )
 
1059
    { 
 
1060
      fputs("</BODY>\n</HTML>\n",page);  
 
1061
      fclose(page);
 
1062
    }
 
1063
    if (pages)
 
1064
      delete pages;
 
1065
}
 
1066
 
 
1067
void HtmlOutputDev::startPage(int pageNum, GfxState *state) {
 
1068
#if 0
 
1069
  if (mode&&!xml){
 
1070
    if (write){
 
1071
      write=gFalse;
 
1072
      GooString* fname=Dirname(Docname);
 
1073
      fname->append("image.log");
 
1074
      if((tin=fopen(getFileNameFromPath(fname->getCString(),fname->getLength()),"w"))==NULL){
 
1075
        printf("Error : can not open %s",fname);
 
1076
        exit(1);
 
1077
      }
 
1078
      delete fname;
 
1079
    // if(state->getRotation()!=0) 
 
1080
    //  fprintf(tin,"ROTATE=%d rotate %d neg %d neg translate\n",state->getRotation(),state->getX1(),-state->getY1());
 
1081
    // else 
 
1082
      fprintf(tin,"ROTATE=%d neg %d neg translate\n",state->getX1(),state->getY1());  
 
1083
    }
 
1084
  }
 
1085
#endif
 
1086
 
 
1087
  this->pageNum = pageNum;
 
1088
  GooString *str=basename(Docname);
 
1089
  pages->clear(); 
 
1090
  if(!noframes)
 
1091
  {
 
1092
    if (fContentsFrame)
 
1093
        {
 
1094
      if (complexMode)
 
1095
                fprintf(fContentsFrame,"<A href=\"%s-%d.html\"",str->getCString(),pageNum);
 
1096
      else 
 
1097
                fprintf(fContentsFrame,"<A href=\"%ss.html#%d\"",str->getCString(),pageNum);
 
1098
      fprintf(fContentsFrame," target=\"contents\" >Page %d</a><br>\n",pageNum);
 
1099
    }
 
1100
  }
 
1101
 
 
1102
  pages->pageWidth=static_cast<int>(state->getPageWidth());
 
1103
  pages->pageHeight=static_cast<int>(state->getPageHeight());
 
1104
 
 
1105
  delete str;
 
1106
 
1107
 
 
1108
 
 
1109
void HtmlOutputDev::endPage() {
 
1110
  Links *linksList = docPage->getLinks(catalog);
 
1111
  for (int i = 0; i < linksList->getNumLinks(); ++i)
 
1112
  {
 
1113
      doProcessLink(linksList->getLink(i));
 
1114
  }
 
1115
  delete linksList;
 
1116
 
 
1117
  pages->conv();
 
1118
  pages->coalesce();
 
1119
  pages->dump(page, pageNum);
 
1120
  
 
1121
  // I don't yet know what to do in the case when there are pages of different
 
1122
  // sizes and we want complex output: running ghostscript many times 
 
1123
  // seems very inefficient. So for now I'll just use last page's size
 
1124
  maxPageWidth = pages->pageWidth;
 
1125
  maxPageHeight = pages->pageHeight;
 
1126
  
 
1127
  //if(!noframes&&!xml) fputs("<br>\n", fContentsFrame);
 
1128
  if(!stout && !globalParams->getErrQuiet()) printf("Page-%d\n",(pageNum));
 
1129
}
 
1130
 
 
1131
void HtmlOutputDev::updateFont(GfxState *state) {
 
1132
  pages->updateFont(state);
 
1133
}
 
1134
 
 
1135
void HtmlOutputDev::beginString(GfxState *state, GooString *s) {
 
1136
  pages->beginString(state, s);
 
1137
}
 
1138
 
 
1139
void HtmlOutputDev::endString(GfxState *state) {
 
1140
  pages->endString();
 
1141
}
 
1142
 
 
1143
void HtmlOutputDev::drawChar(GfxState *state, double x, double y,
 
1144
              double dx, double dy,
 
1145
              double originX, double originY,
 
1146
              CharCode code, int /*nBytes*/, Unicode *u, int uLen) 
 
1147
{
 
1148
  if ( !showHidden && (state->getRender() & 3) == 3) {
 
1149
    return;
 
1150
  }
 
1151
  pages->addChar(state, x, y, dx, dy, originX, originY, u, uLen);
 
1152
}
 
1153
 
 
1154
void HtmlOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
 
1155
                                  int width, int height, GBool invert,
 
1156
                                  GBool interpolate, GBool inlineImg) {
 
1157
 
 
1158
  if (ignore||complexMode) {
 
1159
    OutputDev::drawImageMask(state, ref, str, width, height, invert, interpolate, inlineImg);
 
1160
    return;
 
1161
  }
 
1162
  
 
1163
  FILE *f1;
 
1164
  int c;
 
1165
  
 
1166
  int x0, y0;                   // top left corner of image
 
1167
  int w0, h0, w1, h1;           // size of image
 
1168
  double xt, yt, wt, ht;
 
1169
  GBool rotate, xFlip, yFlip;
 
1170
 
 
1171
  // get image position and size
 
1172
  state->transform(0, 0, &xt, &yt);
 
1173
  state->transformDelta(1, 1, &wt, &ht);
 
1174
  if (wt > 0) {
 
1175
    x0 = xoutRound(xt);
 
1176
    w0 = xoutRound(wt);
 
1177
  } else {
 
1178
    x0 = xoutRound(xt + wt);
 
1179
    w0 = xoutRound(-wt);
 
1180
  }
 
1181
  if (ht > 0) {
 
1182
    y0 = xoutRound(yt);
 
1183
    h0 = xoutRound(ht);
 
1184
  } else {
 
1185
    y0 = xoutRound(yt + ht);
 
1186
    h0 = xoutRound(-ht);
 
1187
  }
 
1188
  state->transformDelta(1, 0, &xt, &yt);
 
1189
  rotate = fabs(xt) < fabs(yt);
 
1190
  if (rotate) {
 
1191
    w1 = h0;
 
1192
    h1 = w0;
 
1193
    xFlip = ht < 0;
 
1194
    yFlip = wt > 0;
 
1195
  } else {
 
1196
    w1 = w0;
 
1197
    h1 = h0;
 
1198
    xFlip = wt < 0;
 
1199
    yFlip = ht > 0;
 
1200
  }
 
1201
 
 
1202
  // dump JPEG file
 
1203
  if (dumpJPEG  && str->getKind() == strDCT) {
 
1204
    GooString *fName=new GooString(Docname);
 
1205
    fName->append("-");
 
1206
    GooString *pgNum=GooString::fromInt(pageNum);
 
1207
    GooString *imgnum=GooString::fromInt(imgNum);
 
1208
    // open the image file
 
1209
    fName->append(pgNum)->append("_")->append(imgnum)->append(".jpg");
 
1210
    delete pgNum;
 
1211
    delete imgnum;
 
1212
 
 
1213
    ++imgNum;
 
1214
    if (!(f1 = fopen(fName->getCString(), "wb"))) {
 
1215
      error(-1, "Couldn't open image file '%s'", fName->getCString());
 
1216
      delete fName;
 
1217
      return;
 
1218
    }
 
1219
 
 
1220
    // initialize stream
 
1221
    str = ((DCTStream *)str)->getRawStream();
 
1222
    str->reset();
 
1223
 
 
1224
    // copy the stream
 
1225
    while ((c = str->getChar()) != EOF)
 
1226
      fputc(c, f1);
 
1227
 
 
1228
    fclose(f1);
 
1229
   
 
1230
  if (fName) imgList->append(fName);
 
1231
  }
 
1232
  else {
 
1233
    OutputDev::drawImageMask(state, ref, str, width, height, invert, interpolate, inlineImg);
 
1234
  }
 
1235
}
 
1236
 
 
1237
void HtmlOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
 
1238
                              int width, int height, GfxImageColorMap *colorMap,
 
1239
                              GBool interpolate, int *maskColors, GBool inlineImg) {
 
1240
 
 
1241
  if (ignore||complexMode) {
 
1242
    OutputDev::drawImage(state, ref, str, width, height, colorMap, interpolate,
 
1243
                         maskColors, inlineImg);
 
1244
    return;
 
1245
  }
 
1246
 
 
1247
  FILE *f1;
 
1248
  int c;
 
1249
  
 
1250
  int x0, y0;                   // top left corner of image
 
1251
  int w0, h0, w1, h1;           // size of image
 
1252
  double xt, yt, wt, ht;
 
1253
  GBool rotate, xFlip, yFlip;
 
1254
 
 
1255
  // get image position and size
 
1256
  state->transform(0, 0, &xt, &yt);
 
1257
  state->transformDelta(1, 1, &wt, &ht);
 
1258
  if (wt > 0) {
 
1259
    x0 = xoutRound(xt);
 
1260
    w0 = xoutRound(wt);
 
1261
  } else {
 
1262
    x0 = xoutRound(xt + wt);
 
1263
    w0 = xoutRound(-wt);
 
1264
  }
 
1265
  if (ht > 0) {
 
1266
    y0 = xoutRound(yt);
 
1267
    h0 = xoutRound(ht);
 
1268
  } else {
 
1269
    y0 = xoutRound(yt + ht);
 
1270
    h0 = xoutRound(-ht);
 
1271
  }
 
1272
  state->transformDelta(1, 0, &xt, &yt);
 
1273
  rotate = fabs(xt) < fabs(yt);
 
1274
  if (rotate) {
 
1275
    w1 = h0;
 
1276
    h1 = w0;
 
1277
    xFlip = ht < 0;
 
1278
    yFlip = wt > 0;
 
1279
  } else {
 
1280
    w1 = w0;
 
1281
    h1 = h0;
 
1282
    xFlip = wt < 0;
 
1283
    yFlip = ht > 0;
 
1284
  }
 
1285
 
 
1286
   
 
1287
  /*if( !globalParams->getErrQuiet() )
 
1288
    printf("image stream of kind %d\n", str->getKind());*/
 
1289
  // dump JPEG file
 
1290
  if (dumpJPEG && str->getKind() == strDCT) {
 
1291
    GooString *fName=new GooString(Docname);
 
1292
    fName->append("-");
 
1293
    GooString *pgNum= GooString::fromInt(pageNum);
 
1294
    GooString *imgnum= GooString::fromInt(imgNum);  
 
1295
    
 
1296
    // open the image file
 
1297
    fName->append(pgNum)->append("_")->append(imgnum)->append(".jpg");
 
1298
    delete pgNum;
 
1299
    delete imgnum;
 
1300
 
 
1301
    ++imgNum;
 
1302
    
 
1303
    if (!(f1 = fopen(fName->getCString(), "wb"))) {
 
1304
      error(-1, "Couldn't open image file '%s'", fName->getCString());
 
1305
      delete fName;
 
1306
      return;
 
1307
    }
 
1308
 
 
1309
    // initialize stream
 
1310
    str = ((DCTStream *)str)->getRawStream();
 
1311
    str->reset();
 
1312
 
 
1313
    // copy the stream
 
1314
    while ((c = str->getChar()) != EOF)
 
1315
      fputc(c, f1);
 
1316
    
 
1317
    fclose(f1);
 
1318
  
 
1319
    if (fName) imgList->append(fName);
 
1320
  }
 
1321
  else {
 
1322
#ifdef ENABLE_LIBPNG
 
1323
    // Dump the image as a PNG file. Much of the PNG code
 
1324
    // comes from an example by Guillaume Cottenceau.
 
1325
    Guchar *p;
 
1326
    GfxRGB rgb;
 
1327
    png_byte *row = (png_byte *) malloc(3 * width);   // 3 bytes/pixel: RGB
 
1328
    png_bytep *row_pointer= &row;
 
1329
 
 
1330
    // Create the image filename
 
1331
    GooString *fName=new GooString(Docname);
 
1332
    fName->append("-");
 
1333
    GooString *pgNum= GooString::fromInt(pageNum);
 
1334
    GooString *imgnum= GooString::fromInt(imgNum);  
 
1335
    fName->append(pgNum)->append("_")->append(imgnum)->append(".png");
 
1336
    delete pgNum;
 
1337
    delete imgnum;
 
1338
 
 
1339
    // Open the image file
 
1340
    if (!(f1 = fopen(fName->getCString(), "wb"))) {
 
1341
      error(-1, "Couldn't open image file '%s'", fName->getCString());
 
1342
      delete fName;
 
1343
      return;
 
1344
    }
 
1345
 
 
1346
    PNGWriter *writer = new PNGWriter();
 
1347
    // TODO can we calculate the resolution of the image?
 
1348
    if (!writer->init(f1, width, height, 72, 72)) {
 
1349
        delete writer;
 
1350
        fclose(f1);
 
1351
        return;
 
1352
    }
 
1353
 
 
1354
    // Initialize the image stream
 
1355
    ImageStream *imgStr = new ImageStream(str, width,
 
1356
                        colorMap->getNumPixelComps(), colorMap->getBits());
 
1357
    imgStr->reset();
 
1358
 
 
1359
    // For each line...
 
1360
    for (int y = 0; y < height; y++) {
 
1361
 
 
1362
      // Convert into a PNG row
 
1363
      p = imgStr->getLine();
 
1364
      for (int x = 0; x < width; x++) {
 
1365
        colorMap->getRGB(p, &rgb);
 
1366
        // Write the RGB pixels into the row
 
1367
        row[3*x]= colToByte(rgb.r);
 
1368
        row[3*x+1]= colToByte(rgb.g);
 
1369
        row[3*x+2]= colToByte(rgb.b);
 
1370
         p += colorMap->getNumPixelComps();
 
1371
      }
 
1372
 
 
1373
      if (!writer->writeRow(row_pointer)) {
 
1374
        delete writer;
 
1375
        fclose(f1);
 
1376
        return;
 
1377
      }
 
1378
    }
 
1379
 
 
1380
    writer->close();
 
1381
    delete writer;
 
1382
    fclose(f1);
 
1383
 
 
1384
    free(row);
 
1385
    imgList->append(fName);
 
1386
    ++imgNum;
 
1387
    imgStr->close();
 
1388
    delete imgStr;
 
1389
#else
 
1390
    OutputDev::drawImage(state, ref, str, width, height, colorMap, interpolate,
 
1391
                         maskColors, inlineImg);
 
1392
#endif
 
1393
  }
 
1394
}
 
1395
 
 
1396
 
 
1397
 
 
1398
void HtmlOutputDev::doProcessLink(Link* link){
 
1399
  double _x1,_y1,_x2,_y2;
 
1400
  int x1,y1,x2,y2;
 
1401
  
 
1402
  link->getRect(&_x1,&_y1,&_x2,&_y2);
 
1403
  cvtUserToDev(_x1,_y1,&x1,&y1);
 
1404
  
 
1405
  cvtUserToDev(_x2,_y2,&x2,&y2); 
 
1406
 
 
1407
 
 
1408
  GooString* _dest=getLinkDest(link,catalog);
 
1409
  HtmlLink t((double) x1,(double) y2,(double) x2,(double) y1,_dest);
 
1410
  pages->AddLink(t);
 
1411
  delete _dest;
 
1412
}
 
1413
 
 
1414
GooString* HtmlOutputDev::getLinkDest(Link *link,Catalog* catalog){
 
1415
  char *p;
 
1416
  switch(link->getAction()->getKind()) 
 
1417
  {
 
1418
      case actionGoTo:
 
1419
          { 
 
1420
          GooString* file=basename(Docname);
 
1421
          int page=1;
 
1422
          LinkGoTo *ha=(LinkGoTo *)link->getAction();
 
1423
          LinkDest *dest=NULL;
 
1424
          if (ha->getDest()!=NULL)
 
1425
              dest=ha->getDest()->copy();
 
1426
          else if (ha->getNamedDest()!=NULL)
 
1427
              dest=catalog->findDest(ha->getNamedDest());
 
1428
              
 
1429
          if (dest){ 
 
1430
              if (dest->isPageRef()){
 
1431
                  Ref pageref=dest->getPageRef();
 
1432
                  page=catalog->findPage(pageref.num,pageref.gen);
 
1433
              }
 
1434
              else {
 
1435
                  page=dest->getPageNum();
 
1436
              }
 
1437
 
 
1438
              delete dest;
 
1439
 
 
1440
              GooString *str=GooString::fromInt(page);
 
1441
              /*                complex         simple
 
1442
                frames          file-4.html     files.html#4
 
1443
                noframes        file.html#4     file.html#4
 
1444
               */
 
1445
              if (noframes)
 
1446
              {
 
1447
                  file->append(".html#");
 
1448
                  file->append(str);
 
1449
              }
 
1450
              else
 
1451
              {
 
1452
                if( complexMode ) 
 
1453
                {
 
1454
                    file->append("-");
 
1455
                    file->append(str);
 
1456
                    file->append(".html");
 
1457
                }
 
1458
                else
 
1459
                {
 
1460
                    file->append("s.html#");
 
1461
                    file->append(str);
 
1462
                }
 
1463
              }
 
1464
 
 
1465
              if (printCommands) printf(" link to page %d ",page);
 
1466
              delete str;
 
1467
              return file;
 
1468
          }
 
1469
          else 
 
1470
          {
 
1471
              return new GooString();
 
1472
          }
 
1473
          }
 
1474
      case actionGoToR:
 
1475
          {
 
1476
          LinkGoToR *ha=(LinkGoToR *) link->getAction();
 
1477
          LinkDest *dest=NULL;
 
1478
          int page=1;
 
1479
          GooString *file=new GooString();
 
1480
          if (ha->getFileName()){
 
1481
              delete file;
 
1482
              file=new GooString(ha->getFileName()->getCString());
 
1483
          }
 
1484
          if (ha->getDest()!=NULL)  dest=ha->getDest()->copy();
 
1485
          if (dest&&file){
 
1486
              if (!(dest->isPageRef()))  page=dest->getPageNum();
 
1487
              delete dest;
 
1488
 
 
1489
              if (printCommands) printf(" link to page %d ",page);
 
1490
              if (printHtml){
 
1491
                  p=file->getCString()+file->getLength()-4;
 
1492
                  if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF")){
 
1493
                      file->del(file->getLength()-4,4);
 
1494
                      file->append(".html");
 
1495
                  }
 
1496
                  file->append('#');
 
1497
                  file->append(GooString::fromInt(page));
 
1498
              }
 
1499
          }
 
1500
          if (printCommands && file) printf("filename %s\n",file->getCString());
 
1501
          return file;
 
1502
          }
 
1503
      case actionURI:
 
1504
          { 
 
1505
          LinkURI *ha=(LinkURI *) link->getAction();
 
1506
          GooString* file=new GooString(ha->getURI()->getCString());
 
1507
          // printf("uri : %s\n",file->getCString());
 
1508
          return file;
 
1509
          }
 
1510
      case actionLaunch:
 
1511
          {
 
1512
          LinkLaunch *ha=(LinkLaunch *) link->getAction();
 
1513
          GooString* file=new GooString(ha->getFileName()->getCString());
 
1514
          if (printHtml) { 
 
1515
              p=file->getCString()+file->getLength()-4;
 
1516
              if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF")){
 
1517
                  file->del(file->getLength()-4,4);
 
1518
                  file->append(".html");
 
1519
              }
 
1520
              if (printCommands) printf("filename %s",file->getCString());
 
1521
    
 
1522
              return file;      
 
1523
  
 
1524
          }
 
1525
          }
 
1526
      default:
 
1527
          return new GooString();
 
1528
  }
 
1529
}
 
1530
 
 
1531
void HtmlOutputDev::dumpMetaVars(FILE *file)
 
1532
{
 
1533
  GooString *var;
 
1534
 
 
1535
  for(int i = 0; i < glMetaVars->getLength(); i++)
 
1536
  {
 
1537
     HtmlMetaVar *t = (HtmlMetaVar*)glMetaVars->get(i); 
 
1538
     var = t->toString(); 
 
1539
     fprintf(file, "%s\n", var->getCString());
 
1540
     delete var;
 
1541
  }
 
1542
}
 
1543
 
 
1544
GBool HtmlOutputDev::dumpDocOutline(Catalog* catalog)
 
1545
 
1546
        FILE * output = NULL;
 
1547
        GBool bClose = gFalse;
 
1548
 
 
1549
        if (!ok || xml)
 
1550
        return gFalse;
 
1551
  
 
1552
        Object *outlines = catalog->getOutline();
 
1553
        if (!outlines->isDict())
 
1554
        return gFalse;
 
1555
  
 
1556
        if (!complexMode && !xml)
 
1557
        {
 
1558
                output = page;
 
1559
        }
 
1560
        else if (complexMode && !xml)
 
1561
        {
 
1562
                if (noframes)
 
1563
                {
 
1564
                        output = page; 
 
1565
                        fputs("<hr>\n", output);
 
1566
                }
 
1567
                else
 
1568
                {
 
1569
                        GooString *str = Docname->copy();
 
1570
                        str->append("-outline.html");
 
1571
                        output = fopen(str->getCString(), "w");
 
1572
                        if (output == NULL)
 
1573
                                return gFalse;
 
1574
                        delete str;
 
1575
                        bClose = gTrue;
 
1576
                fputs("<HTML>\n<HEAD>\n<TITLE>Document Outline</TITLE>\n</HEAD>\n<BODY>\n", output);
 
1577
                }
 
1578
        }
 
1579
 
 
1580
        GBool done = newOutlineLevel(output, outlines, catalog);
 
1581
        if (done && !complexMode)
 
1582
        fputs("<hr>\n", output);
 
1583
        
 
1584
        if (bClose)
 
1585
        {
 
1586
                fputs("</BODY>\n</HTML>\n", output);
 
1587
                fclose(output);
 
1588
        }
 
1589
        return done;
 
1590
}
 
1591
 
 
1592
GBool HtmlOutputDev::newOutlineLevel(FILE *output, Object *node, Catalog* catalog, int level)
 
1593
{
 
1594
  Object curr, next;
 
1595
  GBool atLeastOne = gFalse;
 
1596
  
 
1597
  if (node->dictLookup("First", &curr)->isDict()) {
 
1598
    if (level == 1)
 
1599
        {
 
1600
                fputs("<A name=\"outline\"></a>", output);
 
1601
                fputs("<h1>Document Outline</h1>\n", output);
 
1602
        }
 
1603
    fputs("<ul>",output);
 
1604
    do {
 
1605
      // get title, give up if not found
 
1606
      Object title;
 
1607
      if (curr.dictLookup("Title", &title)->isNull()) {
 
1608
                title.free();
 
1609
                break;
 
1610
      }
 
1611
      GooString *titleStr = new GooString(title.getString());
 
1612
      title.free();
 
1613
 
 
1614
      // get corresponding link
 
1615
      // Note: some code duplicated from HtmlOutputDev::getLinkDest().
 
1616
      GooString *linkName = NULL;;
 
1617
      Object dest;
 
1618
      if (!curr.dictLookup("Dest", &dest)->isNull()) {
 
1619
                LinkGoTo *link = new LinkGoTo(&dest);
 
1620
                LinkDest *linkdest=NULL;
 
1621
                if (link->getDest()!=NULL)
 
1622
                        linkdest=link->getDest()->copy();
 
1623
                else if (link->getNamedDest()!=NULL)
 
1624
                        linkdest=catalog->findDest(link->getNamedDest());
 
1625
                        
 
1626
                delete link;
 
1627
                if (linkdest) { 
 
1628
                        int page;
 
1629
                        if (linkdest->isPageRef()) {
 
1630
                        Ref pageref=linkdest->getPageRef();
 
1631
                        page=catalog->findPage(pageref.num,pageref.gen);
 
1632
                        } else {
 
1633
                        page=linkdest->getPageNum();
 
1634
                        }
 
1635
                        delete linkdest;
 
1636
 
 
1637
                        /*                      complex         simple
 
1638
                        frames          file-4.html     files.html#4
 
1639
                        noframes        file.html#4     file.html#4
 
1640
                        */
 
1641
                        linkName=basename(Docname);
 
1642
                        GooString *str=GooString::fromInt(page);
 
1643
                        if (noframes) {
 
1644
                        linkName->append(".html#");
 
1645
                                linkName->append(str);
 
1646
                        } else {
 
1647
                        if( complexMode ) {
 
1648
                                        linkName->append("-");
 
1649
                                linkName->append(str);
 
1650
                                linkName->append(".html");
 
1651
                        } else {
 
1652
                                linkName->append("s.html#");
 
1653
                                linkName->append(str);
 
1654
                        }
 
1655
                        }
 
1656
                        delete str;
 
1657
                }
 
1658
      }
 
1659
      dest.free();
 
1660
 
 
1661
      fputs("<li>",output);
 
1662
      if (linkName)
 
1663
                fprintf(output,"<A href=\"%s\">", linkName->getCString());
 
1664
      fputs(titleStr->getCString(),output);
 
1665
      if (linkName) {
 
1666
                fputs("</A>",output);
 
1667
                delete linkName;
 
1668
      }
 
1669
      fputs("\n",output);
 
1670
      delete titleStr;
 
1671
      atLeastOne = gTrue;
 
1672
 
 
1673
      newOutlineLevel(output, &curr, catalog, level+1);
 
1674
      curr.dictLookup("Next", &next);
 
1675
      curr.free();
 
1676
      curr = next;
 
1677
    } while(curr.isDict());
 
1678
    fputs("</ul>",output);
 
1679
  }
 
1680
  curr.free();
 
1681
 
 
1682
  return atLeastOne;
 
1683
}