Coverage Report

Created: 2023-09-25 06:35

/src/xpdf-4.04/xpdf/Annot.cc
Line
Count
Source (jump to first uncovered line)
1
//========================================================================
2
//
3
// Annot.cc
4
//
5
// Copyright 2000-2003 Glyph & Cog, LLC
6
//
7
//========================================================================
8
9
#include <aconf.h>
10
11
#ifdef USE_GCC_PRAGMAS
12
#pragma implementation
13
#endif
14
15
#include <stdlib.h>
16
#include <math.h>
17
#include "gmem.h"
18
#include "gmempp.h"
19
#include "GList.h"
20
#include "Error.h"
21
#include "Object.h"
22
#include "Catalog.h"
23
#include "Gfx.h"
24
#include "GfxFont.h"
25
#include "Lexer.h"
26
#include "PDFDoc.h"
27
#include "OptionalContent.h"
28
#include "AcroForm.h"
29
#include "BuiltinFontTables.h"
30
#include "FontEncodingTables.h"
31
#include "Annot.h"
32
33
// the MSVC math.h doesn't define this
34
#ifndef M_PI
35
#define M_PI 3.14159265358979323846
36
#endif
37
38
//------------------------------------------------------------------------
39
40
0
#define annotFlagHidden    0x0002
41
0
#define annotFlagPrint     0x0004
42
0
#define annotFlagNoView    0x0020
43
44
// distance of Bezier control point from center for circle approximation
45
// = (4 * (sqrt(2) - 1) / 3) * r
46
0
#define bezierCircle 0.55228475
47
48
0
#define lineEndSize1    6
49
0
#define lineEndSize2   10
50
0
#define lineArrowAngle (M_PI / 6)
51
52
//------------------------------------------------------------------------
53
// AnnotBorderStyle
54
//------------------------------------------------------------------------
55
56
AnnotBorderStyle::AnnotBorderStyle(AnnotBorderType typeA, double widthA,
57
           double *dashA, int dashLengthA,
58
0
           double *colorA, int nColorCompsA) {
59
0
  type = typeA;
60
0
  width = widthA;
61
0
  dash = dashA;
62
0
  dashLength = dashLengthA;
63
0
  color[0] = colorA[0];
64
0
  color[1] = colorA[1];
65
0
  color[2] = colorA[2];
66
0
  color[3] = colorA[3];
67
0
  nColorComps = nColorCompsA;
68
0
}
69
70
0
AnnotBorderStyle::~AnnotBorderStyle() {
71
0
  if (dash) {
72
0
    gfree(dash);
73
0
  }
74
0
}
75
76
//------------------------------------------------------------------------
77
// Annot
78
//------------------------------------------------------------------------
79
80
0
Annot::Annot(PDFDoc *docA, Dict *dict, Ref *refA) {
81
0
  Object apObj, asObj, obj1, obj2, obj3;
82
0
  AnnotBorderType borderType;
83
0
  double borderWidth;
84
0
  double *borderDash;
85
0
  int borderDashLength;
86
0
  double borderColor[4];
87
0
  int nBorderColorComps;
88
0
  double t;
89
0
  int i;
90
91
0
  ok = gTrue;
92
0
  doc = docA;
93
0
  xref = doc->getXRef();
94
0
  ref = *refA;
95
0
  type = NULL;
96
0
  appearanceState = NULL;
97
0
  appearBuf = NULL;
98
0
  borderStyle = NULL;
99
100
  //----- parse the type
101
102
0
  if (dict->lookup("Subtype", &obj1)->isName()) {
103
0
    type = new GString(obj1.getName());
104
0
  }
105
0
  obj1.free();
106
107
  //----- parse the rectangle
108
109
0
  if (dict->lookup("Rect", &obj1)->isArray() &&
110
0
      obj1.arrayGetLength() == 4) {
111
0
    xMin = yMin = xMax = yMax = 0;
112
0
    if (obj1.arrayGet(0, &obj2)->isNum()) {
113
0
      xMin = obj2.getNum();
114
0
    }
115
0
    obj2.free();
116
0
    if (obj1.arrayGet(1, &obj2)->isNum()) {
117
0
      yMin = obj2.getNum();
118
0
    }
119
0
    obj2.free();
120
0
    if (obj1.arrayGet(2, &obj2)->isNum()) {
121
0
      xMax = obj2.getNum();
122
0
    }
123
0
    obj2.free();
124
0
    if (obj1.arrayGet(3, &obj2)->isNum()) {
125
0
      yMax = obj2.getNum();
126
0
    }
127
0
    obj2.free();
128
0
    if (xMin > xMax) {
129
0
      t = xMin; xMin = xMax; xMax = t;
130
0
    }
131
0
    if (yMin > yMax) {
132
0
      t = yMin; yMin = yMax; yMax = t;
133
0
    }
134
0
  } else {
135
0
    error(errSyntaxError, -1, "Bad bounding box for annotation");
136
0
    ok = gFalse;
137
0
  }
138
0
  obj1.free();
139
140
  //----- parse the flags
141
142
0
  if (dict->lookup("F", &obj1)->isInt()) {
143
0
    flags = obj1.getInt();
144
0
  } else {
145
0
    flags = 0;
146
0
  }
147
0
  obj1.free();
148
149
  //----- parse the border style
150
151
0
  borderType = annotBorderSolid;
152
0
  borderWidth = 1;
153
0
  borderDash = NULL;
154
0
  borderDashLength = 0;
155
0
  nBorderColorComps = 3;
156
0
  borderColor[0] = 0;
157
0
  borderColor[1] = 0;
158
0
  borderColor[2] = 1;
159
0
  borderColor[3] = 0;
160
0
  if (dict->lookup("BS", &obj1)->isDict()) {
161
0
    if (obj1.dictLookup("S", &obj2)->isName()) {
162
0
      if (obj2.isName("S")) {
163
0
  borderType = annotBorderSolid;
164
0
      } else if (obj2.isName("D")) {
165
0
  borderType = annotBorderDashed;
166
0
      } else if (obj2.isName("B")) {
167
0
  borderType = annotBorderBeveled;
168
0
      } else if (obj2.isName("I")) {
169
0
  borderType = annotBorderInset;
170
0
      } else if (obj2.isName("U")) {
171
0
  borderType = annotBorderUnderlined;
172
0
      }
173
0
    }
174
0
    obj2.free();
175
0
    if (obj1.dictLookup("W", &obj2)->isNum()) {
176
0
      borderWidth = obj2.getNum();
177
0
    }
178
0
    obj2.free();
179
0
    if (obj1.dictLookup("D", &obj2)->isArray()) {
180
0
      borderDashLength = obj2.arrayGetLength();
181
0
      borderDash = (double *)gmallocn(borderDashLength, sizeof(double));
182
0
      for (i = 0; i < borderDashLength; ++i) {
183
0
  if (obj2.arrayGet(i, &obj3)->isNum()) {
184
0
    borderDash[i] = obj3.getNum();
185
0
  } else {
186
0
    borderDash[i] = 1;
187
0
  }
188
0
  obj3.free();
189
0
      }
190
0
    }
191
0
    obj2.free();
192
0
  } else {
193
0
    obj1.free();
194
0
    if (dict->lookup("Border", &obj1)->isArray()) {
195
0
      if (obj1.arrayGetLength() >= 3) {
196
0
  if (obj1.arrayGet(2, &obj2)->isNum()) {
197
0
    borderWidth = obj2.getNum();
198
0
  }
199
0
  obj2.free();
200
0
  if (obj1.arrayGetLength() >= 4) {
201
0
    if (obj1.arrayGet(3, &obj2)->isArray()) {
202
0
      borderType = annotBorderDashed;
203
0
      borderDashLength = obj2.arrayGetLength();
204
0
      borderDash = (double *)gmallocn(borderDashLength, sizeof(double));
205
0
      for (i = 0; i < borderDashLength; ++i) {
206
0
        if (obj2.arrayGet(i, &obj3)->isNum()) {
207
0
    borderDash[i] = obj3.getNum();
208
0
        } else {
209
0
    borderDash[i] = 1;
210
0
        }
211
0
        obj3.free();
212
0
      }
213
0
    } else {
214
      // Adobe draws no border at all if the last element is of
215
      // the wrong type.
216
0
      borderWidth = 0;
217
0
    }
218
0
    obj2.free();
219
0
  }
220
0
      } else {
221
  // an empty Border array also means "no border"
222
0
  borderWidth = 0;
223
0
      }
224
0
    }
225
0
  }
226
0
  obj1.free();
227
  // Acrobat ignores borders with unreasonable widths
228
0
  if (borderWidth > 1 && (borderWidth > xMax - xMin ||
229
0
        borderWidth > yMax - yMin)) {
230
0
    borderWidth = 0;
231
0
  }
232
0
  if (dict->lookup("C", &obj1)->isArray() &&
233
0
      (obj1.arrayGetLength() == 1 ||
234
0
       obj1.arrayGetLength() == 3 ||
235
0
       obj1.arrayGetLength() == 4)) {
236
0
    nBorderColorComps = obj1.arrayGetLength();
237
0
    for (i = 0; i < nBorderColorComps; ++i) {
238
0
      if (obj1.arrayGet(i, &obj2)->isNum()) {
239
0
  borderColor[i] = obj2.getNum();
240
0
      } else {
241
0
  borderColor[i] = 0;
242
0
      }
243
0
      obj2.free();
244
0
    }
245
0
  }
246
0
  obj1.free();
247
0
  borderStyle = new AnnotBorderStyle(borderType, borderWidth,
248
0
             borderDash, borderDashLength,
249
0
             borderColor, nBorderColorComps);
250
251
  //----- get the appearance state
252
253
0
  dict->lookup("AP", &apObj);
254
0
  dict->lookup("AS", &asObj);
255
0
  if (asObj.isName()) {
256
0
    appearanceState = new GString(asObj.getName());
257
0
  } else if (apObj.isDict()) {
258
0
    apObj.dictLookup("N", &obj1);
259
0
    if (obj1.isDict() && obj1.dictGetLength() == 1) {
260
0
      appearanceState = new GString(obj1.dictGetKey(0));
261
0
    }
262
0
    obj1.free();
263
0
  }
264
0
  if (!appearanceState) {
265
0
    appearanceState = new GString("Off");
266
0
  }
267
0
  asObj.free();
268
269
  //----- get the annotation appearance
270
271
0
  if (apObj.isDict()) {
272
0
    apObj.dictLookup("N", &obj1);
273
0
    apObj.dictLookupNF("N", &obj2);
274
0
    if (obj1.isDict()) {
275
0
      if (obj1.dictLookupNF(appearanceState->getCString(), &obj3)->isRef()) {
276
0
  obj3.copy(&appearance);
277
0
      }
278
0
      obj3.free();
279
0
    } else if (obj2.isRef()) {
280
0
      obj2.copy(&appearance);
281
0
    }
282
0
    obj1.free();
283
0
    obj2.free();
284
0
  }
285
0
  apObj.free();
286
287
  //----- get the optional content entry
288
289
0
  dict->lookupNF("OC", &ocObj);
290
0
}
291
292
0
Annot::~Annot() {
293
0
  if (type) {
294
0
    delete type;
295
0
  }
296
0
  if (appearanceState) {
297
0
    delete appearanceState;
298
0
  }
299
0
  appearance.free();
300
0
  if (appearBuf) {
301
0
    delete appearBuf;
302
0
  }
303
0
  if (borderStyle) {
304
0
    delete borderStyle;
305
0
  }
306
0
  ocObj.free();
307
0
}
308
309
0
void Annot::generateAnnotAppearance() {
310
0
  Object obj;
311
312
0
  appearance.fetch(doc->getXRef(), &obj);
313
0
  if (!obj.isStream()) {
314
0
    if (type) {
315
0
      if (!type->cmp("Line")) {
316
0
  generateLineAppearance();
317
0
      } else if (!type->cmp("PolyLine")) {
318
0
  generatePolyLineAppearance();
319
0
      } else if (!type->cmp("Polygon")) {
320
0
  generatePolygonAppearance();
321
0
      } else if (!type->cmp("FreeText")) {
322
0
  generateFreeTextAppearance();
323
0
      }
324
0
    }
325
0
  }
326
0
  obj.free();
327
0
}
328
329
//~ this doesn't draw the caption
330
0
void Annot::generateLineAppearance() {
331
0
  Object annotObj, gfxStateDict, appearDict, obj1, obj2;
332
0
  MemStream *appearStream;
333
0
  double x1, y1, x2, y2, dx, dy, len, w;
334
0
  double lx1, ly1, lx2, ly2;
335
0
  double tx1, ty1, tx2, ty2;
336
0
  double ax1, ay1, ax2, ay2;
337
0
  double bx1, by1, bx2, by2;
338
0
  double leaderLen, leaderExtLen, leaderOffLen;
339
0
  AnnotLineEndType lineEnd1, lineEnd2;
340
0
  GBool fill;
341
342
0
  if (!getObject(&annotObj)->isDict()) {
343
0
    annotObj.free();
344
0
    return;
345
0
  }
346
347
0
  appearBuf = new GString();
348
349
  //----- check for transparency
350
0
  if (annotObj.dictLookup("CA", &obj1)->isNum()) {
351
0
    gfxStateDict.initDict(doc->getXRef());
352
0
    gfxStateDict.dictAdd(copyString("ca"), obj1.copy(&obj2));
353
0
    appearBuf->append("/GS1 gs\n");
354
0
  }
355
0
  obj1.free();
356
357
  //----- set line style, colors
358
0
  setLineStyle(borderStyle, &w);
359
0
  setStrokeColor(borderStyle->getColor(), borderStyle->getNumColorComps());
360
0
  fill = gFalse;
361
0
  if (annotObj.dictLookup("IC", &obj1)->isArray()) {
362
0
    if (setFillColor(&obj1)) {
363
0
      fill = gTrue;
364
0
    }
365
0
  }
366
0
  obj1.free();
367
368
  //----- get line properties
369
0
  if (annotObj.dictLookup("L", &obj1)->isArray() &&
370
0
      obj1.arrayGetLength() == 4) {
371
0
    if (obj1.arrayGet(0, &obj2)->isNum()) {
372
0
      x1 = obj2.getNum();
373
0
    } else {
374
0
      obj2.free();
375
0
      obj1.free();
376
0
      goto err1;
377
0
    }
378
0
    obj2.free();
379
0
    if (obj1.arrayGet(1, &obj2)->isNum()) {
380
0
      y1 = obj2.getNum();
381
0
    } else {
382
0
      obj2.free();
383
0
      obj1.free();
384
0
      goto err1;
385
0
    }
386
0
    obj2.free();
387
0
    if (obj1.arrayGet(2, &obj2)->isNum()) {
388
0
      x2 = obj2.getNum();
389
0
    } else {
390
0
      obj2.free();
391
0
      obj1.free();
392
0
      goto err1;
393
0
    }
394
0
    obj2.free();
395
0
    if (obj1.arrayGet(3, &obj2)->isNum()) {
396
0
      y2 = obj2.getNum();
397
0
    } else {
398
0
      obj2.free();
399
0
      obj1.free();
400
0
      goto err1;
401
0
    }
402
0
    obj2.free();
403
0
  } else {
404
0
    obj1.free();
405
0
    goto err1;
406
0
  }
407
0
  obj1.free();
408
0
  lineEnd1 = lineEnd2 = annotLineEndNone;
409
0
  if (annotObj.dictLookup("LE", &obj1)->isArray() &&
410
0
      obj1.arrayGetLength() == 2) {
411
0
    lineEnd1 = parseLineEndType(obj1.arrayGet(0, &obj2));
412
0
    obj2.free();
413
0
    lineEnd2 = parseLineEndType(obj1.arrayGet(1, &obj2));
414
0
    obj2.free();
415
0
  }
416
0
  obj1.free();
417
0
  if (annotObj.dictLookup("LL", &obj1)->isNum()) {
418
0
    leaderLen = obj1.getNum();
419
0
  } else {
420
0
    leaderLen = 0;
421
0
  }
422
0
  obj1.free();
423
0
  if (annotObj.dictLookup("LLE", &obj1)->isNum()) {
424
0
    leaderExtLen = obj1.getNum();
425
0
  } else {
426
0
    leaderExtLen = 0;
427
0
  }
428
0
  obj1.free();
429
0
  if (annotObj.dictLookup("LLO", &obj1)->isNum()) {
430
0
    leaderOffLen = obj1.getNum();
431
0
  } else {
432
0
    leaderOffLen = 0;
433
0
  }
434
0
  obj1.free();
435
436
  //----- compute positions
437
0
  x1 -= xMin;
438
0
  y1 -= yMin;
439
0
  x2 -= xMin;
440
0
  y2 -= yMin;
441
0
  dx = x2 - x1;
442
0
  dy = y2 - y1;
443
0
  len = sqrt(dx*dx + dy*dy);
444
0
  if (len > 0) {
445
0
    dx /= len;
446
0
    dy /= len;
447
0
  }
448
0
  if (leaderLen != 0) {
449
0
    ax1 = x1 + leaderOffLen * dy;
450
0
    ay1 = y1 - leaderOffLen * dx;
451
0
    lx1 = ax1 + leaderLen * dy;
452
0
    ly1 = ay1 - leaderLen * dx;
453
0
    bx1 = lx1 + leaderExtLen * dy;
454
0
    by1 = ly1 - leaderExtLen * dx;
455
0
    ax2 = x2 + leaderOffLen * dy;
456
0
    ay2 = y2 - leaderOffLen * dx;
457
0
    lx2 = ax2 + leaderLen * dy;
458
0
    ly2 = ay2 - leaderLen * dx;
459
0
    bx2 = lx2 + leaderExtLen * dy;
460
0
    by2 = ly2 - leaderExtLen * dx;
461
0
  } else {
462
0
    lx1 = x1;
463
0
    ly1 = y1;
464
0
    lx2 = x2;
465
0
    ly2 = y2;
466
0
    ax1 = ay1 = ax2 = ay2 = 0; // make gcc happy
467
0
    bx1 = by1 = bx2 = by2 = 0;
468
0
  }
469
0
  adjustLineEndpoint(lineEnd1, lx1, ly1, dx, dy, w, &tx1, &ty1);
470
0
  adjustLineEndpoint(lineEnd2, lx2, ly2, -dx, -dy, w, &tx2, &ty2);
471
472
  //----- draw leaders
473
0
  if (leaderLen != 0) {
474
0
    appearBuf->appendf("{0:.4f} {1:.4f} m {2:.4f} {3:.4f} l\n",
475
0
           ax1, ay1, bx1, by1);
476
0
    appearBuf->appendf("{0:.4f} {1:.4f} m {2:.4f} {3:.4f} l\n",
477
0
           ax2, ay2 , bx2, by2);
478
0
  }
479
480
  //----- draw the line
481
0
  appearBuf->appendf("{0:.4f} {1:.4f} m {2:.4f} {3:.4f} l\n",
482
0
         tx1, ty1, tx2, ty2);
483
0
  appearBuf->append("S\n");
484
485
  //----- draw the arrows
486
0
  if (borderStyle->getType() == annotBorderDashed) {
487
0
    appearBuf->append("[] 0 d\n");
488
0
  }
489
0
  drawLineArrow(lineEnd1, lx1, ly1, dx, dy, w, fill);
490
0
  drawLineArrow(lineEnd2, lx2, ly2, -dx, -dy, w, fill);
491
492
  //----- build the appearance stream dictionary
493
0
  appearDict.initDict(doc->getXRef());
494
0
  appearDict.dictAdd(copyString("Length"),
495
0
         obj1.initInt(appearBuf->getLength()));
496
0
  appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form"));
497
0
  obj1.initArray(doc->getXRef());
498
0
  obj1.arrayAdd(obj2.initReal(0));
499
0
  obj1.arrayAdd(obj2.initReal(0));
500
0
  obj1.arrayAdd(obj2.initReal(xMax - xMin));
501
0
  obj1.arrayAdd(obj2.initReal(yMax - yMin));
502
0
  appearDict.dictAdd(copyString("BBox"), &obj1);
503
0
  if (gfxStateDict.isDict()) {
504
0
    obj1.initDict(doc->getXRef());
505
0
    obj2.initDict(doc->getXRef());
506
0
    obj2.dictAdd(copyString("GS1"), &gfxStateDict);
507
0
    obj1.dictAdd(copyString("ExtGState"), &obj2);
508
0
    appearDict.dictAdd(copyString("Resources"), &obj1);
509
0
  }
510
511
  //----- build the appearance stream
512
0
  appearStream = new MemStream(appearBuf->getCString(), 0,
513
0
             appearBuf->getLength(), &appearDict);
514
0
  appearance.free();
515
0
  appearance.initStream(appearStream);
516
517
0
 err1:
518
0
  annotObj.free();
519
0
}
520
521
//~ this doesn't handle line ends (arrows)
522
0
void Annot::generatePolyLineAppearance() {
523
0
  Object annotObj, gfxStateDict, appearDict, obj1, obj2;
524
0
  MemStream *appearStream;
525
0
  double x1, y1, w;
526
0
  int i;
527
528
0
  if (!getObject(&annotObj)->isDict()) {
529
0
    annotObj.free();
530
0
    return;
531
0
  }
532
533
0
  appearBuf = new GString();
534
535
  //----- check for transparency
536
0
  if (annotObj.dictLookup("CA", &obj1)->isNum()) {
537
0
    gfxStateDict.initDict(doc->getXRef());
538
0
    gfxStateDict.dictAdd(copyString("ca"), obj1.copy(&obj2));
539
0
    appearBuf->append("/GS1 gs\n");
540
0
  }
541
0
  obj1.free();
542
543
  //----- set line style, colors
544
0
  setLineStyle(borderStyle, &w);
545
0
  setStrokeColor(borderStyle->getColor(), borderStyle->getNumColorComps());
546
  // fill = gFalse;
547
  // if (annotObj.dictLookup("IC", &obj1)->isArray()) {
548
  //   if (setFillColor(&obj1)) {
549
  //     fill = gTrue;
550
  //   }
551
  // }
552
  // obj1.free();
553
554
  //----- draw line
555
0
  if (!annotObj.dictLookup("Vertices", &obj1)->isArray()) {
556
0
    obj1.free();
557
0
    goto err1;
558
0
  }
559
0
  for (i = 0; i+1 < obj1.arrayGetLength(); i += 2) {
560
0
    if (!obj1.arrayGet(i, &obj2)->isNum()) {
561
0
      obj2.free();
562
0
      obj1.free();
563
0
      goto err1;
564
0
    }
565
0
    x1 = obj2.getNum();
566
0
    obj2.free();
567
0
    if (!obj1.arrayGet(i+1, &obj2)->isNum()) {
568
0
      obj2.free();
569
0
      obj1.free();
570
0
      goto err1;
571
0
    }
572
0
    y1 = obj2.getNum();
573
0
    obj2.free();
574
0
    x1 -= xMin;
575
0
    y1 -= yMin;
576
0
    if (i == 0) {
577
0
      appearBuf->appendf("{0:.4f} {1:.4f} m\n", x1, y1);
578
0
    } else {
579
0
      appearBuf->appendf("{0:.4f} {1:.4f} l\n", x1, y1);
580
0
    }
581
0
  }
582
0
  appearBuf->append("S\n");
583
0
  obj1.free();
584
585
  //----- build the appearance stream dictionary
586
0
  appearDict.initDict(doc->getXRef());
587
0
  appearDict.dictAdd(copyString("Length"),
588
0
         obj1.initInt(appearBuf->getLength()));
589
0
  appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form"));
590
0
  obj1.initArray(doc->getXRef());
591
0
  obj1.arrayAdd(obj2.initReal(0));
592
0
  obj1.arrayAdd(obj2.initReal(0));
593
0
  obj1.arrayAdd(obj2.initReal(xMax - xMin));
594
0
  obj1.arrayAdd(obj2.initReal(yMax - yMin));
595
0
  appearDict.dictAdd(copyString("BBox"), &obj1);
596
0
  if (gfxStateDict.isDict()) {
597
0
    obj1.initDict(doc->getXRef());
598
0
    obj2.initDict(doc->getXRef());
599
0
    obj2.dictAdd(copyString("GS1"), &gfxStateDict);
600
0
    obj1.dictAdd(copyString("ExtGState"), &obj2);
601
0
    appearDict.dictAdd(copyString("Resources"), &obj1);
602
0
  }
603
604
  //----- build the appearance stream
605
0
  appearStream = new MemStream(appearBuf->getCString(), 0,
606
0
             appearBuf->getLength(), &appearDict);
607
0
  appearance.free();
608
0
  appearance.initStream(appearStream);
609
610
0
 err1:
611
0
  annotObj.free();
612
0
}
613
614
0
void Annot::generatePolygonAppearance() {
615
0
  Object annotObj, gfxStateDict, appearDict, obj1, obj2;
616
0
  MemStream *appearStream;
617
0
  double x1, y1;
618
0
  int i;
619
620
0
  if (!getObject(&annotObj)->isDict()) {
621
0
    annotObj.free();
622
0
    return;
623
0
  }
624
625
0
  appearBuf = new GString();
626
627
  //----- check for transparency
628
0
  if (annotObj.dictLookup("CA", &obj1)->isNum()) {
629
0
    gfxStateDict.initDict(doc->getXRef());
630
0
    gfxStateDict.dictAdd(copyString("ca"), obj1.copy(&obj2));
631
0
    appearBuf->append("/GS1 gs\n");
632
0
  }
633
0
  obj1.free();
634
635
  //----- set fill color
636
0
  if (!annotObj.dictLookup("IC", &obj1)->isArray()  ||
637
0
      !setFillColor(&obj1)) {
638
0
    obj1.free();
639
0
    goto err1;
640
0
  }
641
0
  obj1.free();
642
643
  //----- fill polygon
644
0
  if (!annotObj.dictLookup("Vertices", &obj1)->isArray()) {
645
0
    obj1.free();
646
0
    goto err1;
647
0
  }
648
0
  for (i = 0; i+1 < obj1.arrayGetLength(); i += 2) {
649
0
    if (!obj1.arrayGet(i, &obj2)->isNum()) {
650
0
      obj2.free();
651
0
      obj1.free();
652
0
      goto err1;
653
0
    }
654
0
    x1 = obj2.getNum();
655
0
    obj2.free();
656
0
    if (!obj1.arrayGet(i+1, &obj2)->isNum()) {
657
0
      obj2.free();
658
0
      obj1.free();
659
0
      goto err1;
660
0
    }
661
0
    y1 = obj2.getNum();
662
0
    obj2.free();
663
0
    x1 -= xMin;
664
0
    y1 -= yMin;
665
0
    if (i == 0) {
666
0
      appearBuf->appendf("{0:.4f} {1:.4f} m\n", x1, y1);
667
0
    } else {
668
0
      appearBuf->appendf("{0:.4f} {1:.4f} l\n", x1, y1);
669
0
    }
670
0
  }
671
0
  appearBuf->append("f\n");
672
0
  obj1.free();
673
674
  //----- build the appearance stream dictionary
675
0
  appearDict.initDict(doc->getXRef());
676
0
  appearDict.dictAdd(copyString("Length"),
677
0
         obj1.initInt(appearBuf->getLength()));
678
0
  appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form"));
679
0
  obj1.initArray(doc->getXRef());
680
0
  obj1.arrayAdd(obj2.initReal(0));
681
0
  obj1.arrayAdd(obj2.initReal(0));
682
0
  obj1.arrayAdd(obj2.initReal(xMax - xMin));
683
0
  obj1.arrayAdd(obj2.initReal(yMax - yMin));
684
0
  appearDict.dictAdd(copyString("BBox"), &obj1);
685
0
  if (gfxStateDict.isDict()) {
686
0
    obj1.initDict(doc->getXRef());
687
0
    obj2.initDict(doc->getXRef());
688
0
    obj2.dictAdd(copyString("GS1"), &gfxStateDict);
689
0
    obj1.dictAdd(copyString("ExtGState"), &obj2);
690
0
    appearDict.dictAdd(copyString("Resources"), &obj1);
691
0
  }
692
693
  //----- build the appearance stream
694
0
  appearStream = new MemStream(appearBuf->getCString(), 0,
695
0
             appearBuf->getLength(), &appearDict);
696
0
  appearance.free();
697
0
  appearance.initStream(appearStream);
698
699
0
 err1:
700
0
  annotObj.free();
701
0
}
702
703
//~ this doesn't handle rich text
704
//~ this doesn't handle the callout
705
//~ this doesn't handle the RD field
706
0
void Annot::generateFreeTextAppearance() {
707
0
  Object annotObj, gfxStateDict, appearDict, obj1, obj2;
708
0
  Object resources, gsResources, fontResources, defaultFont;
709
0
  GString *text, *da;
710
0
  double lineWidth;
711
0
  int quadding, rot;
712
0
  MemStream *appearStream;
713
714
0
  if (!getObject(&annotObj)->isDict()) {
715
0
    annotObj.free();
716
0
    return;
717
0
  }
718
719
0
  appearBuf = new GString();
720
721
  //----- check for transparency
722
0
  if (annotObj.dictLookup("CA", &obj1)->isNum()) {
723
0
    gfxStateDict.initDict(doc->getXRef());
724
0
    gfxStateDict.dictAdd(copyString("ca"), obj1.copy(&obj2));
725
0
    appearBuf->append("/GS1 gs\n");
726
0
  }
727
0
  obj1.free();
728
729
  //----- draw the text
730
0
  if (annotObj.dictLookup("Contents", &obj1)->isString()) {
731
0
    text = obj1.getString()->copy();
732
0
  } else {
733
0
    text = new GString();
734
0
  }
735
0
  obj1.free();
736
0
  if (annotObj.dictLookup("Q", &obj1)->isInt()) {
737
0
    quadding = obj1.getInt();
738
0
  } else {
739
0
    quadding = 0;
740
0
  }
741
0
  obj1.free();
742
0
  if (annotObj.dictLookup("DA", &obj1)->isString()) {
743
0
    da = obj1.getString()->copy();
744
0
  } else {
745
0
    da = new GString();
746
0
  }
747
0
  obj1.free();
748
  // the "Rotate" field is not defined in the PDF spec, but Acrobat
749
  // looks at it
750
0
  if (annotObj.dictLookup("Rotate", &obj1)->isInt()) {
751
0
    rot = obj1.getInt();
752
0
  } else {
753
0
    rot = 0;
754
0
  }
755
0
  obj1.free();
756
0
  drawText(text, da, quadding, 0, rot);
757
0
  delete text;
758
0
  delete da;
759
760
  //----- draw the border
761
0
  if (borderStyle->getWidth() != 0) {
762
0
    setLineStyle(borderStyle, &lineWidth);
763
0
    appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} re s\n",
764
0
           0.5 * lineWidth, 0.5 * lineWidth,
765
0
           xMax - xMin - lineWidth, yMax - yMin - lineWidth);
766
0
  }
767
768
  //----- build the appearance stream dictionary
769
0
  appearDict.initDict(doc->getXRef());
770
0
  appearDict.dictAdd(copyString("Length"),
771
0
         obj1.initInt(appearBuf->getLength()));
772
0
  appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form"));
773
0
  obj1.initArray(doc->getXRef());
774
0
  obj1.arrayAdd(obj2.initReal(0));
775
0
  obj1.arrayAdd(obj2.initReal(0));
776
0
  obj1.arrayAdd(obj2.initReal(xMax - xMin));
777
0
  obj1.arrayAdd(obj2.initReal(yMax - yMin));
778
0
  appearDict.dictAdd(copyString("BBox"), &obj1);
779
0
  resources.initDict(doc->getXRef());
780
0
  defaultFont.initDict(doc->getXRef());
781
0
  defaultFont.dictAdd(copyString("Type"), obj1.initName("Font"));
782
0
  defaultFont.dictAdd(copyString("Subtype"), obj1.initName("Type1"));
783
0
  defaultFont.dictAdd(copyString("BaseFont"), obj1.initName("Helvetica"));
784
0
  defaultFont.dictAdd(copyString("Encoding"), obj1.initName("WinAnsiEncoding"));
785
0
  fontResources.initDict(doc->getXRef());
786
0
  fontResources.dictAdd(copyString("xpdf_default_font"), &defaultFont);
787
0
  resources.dictAdd(copyString("Font"), &fontResources);
788
0
  if (gfxStateDict.isDict()) {
789
0
    gsResources.initDict(doc->getXRef());
790
0
    gsResources.dictAdd(copyString("GS1"), &gfxStateDict);
791
0
    resources.dictAdd(copyString("ExtGState"), &gsResources);
792
0
  }
793
0
  appearDict.dictAdd(copyString("Resources"), &resources);
794
795
  //----- build the appearance stream
796
0
  appearStream = new MemStream(appearBuf->getCString(), 0,
797
0
             appearBuf->getLength(), &appearDict);
798
0
  appearance.free();
799
0
  appearance.initStream(appearStream);
800
801
0
  annotObj.free();
802
0
}
803
804
0
void Annot::setLineStyle(AnnotBorderStyle *bs, double *lineWidth) {
805
0
  double *dash;
806
0
  double w;
807
0
  int dashLength, i;
808
809
0
  if ((w = borderStyle->getWidth()) <= 0) {
810
0
    w = 0.1;
811
0
  }
812
0
  *lineWidth = w;
813
0
  appearBuf->appendf("{0:.4f} w\n", w);
814
  // this treats beveled/inset/underline as solid
815
0
  if (borderStyle->getType() == annotBorderDashed) {
816
0
    borderStyle->getDash(&dash, &dashLength);
817
0
    appearBuf->append("[");
818
0
    for (i = 0; i < dashLength; ++i) {
819
0
      appearBuf->appendf(" {0:.4f}", dash[i]);
820
0
    }
821
0
    appearBuf->append("] 0 d\n");
822
0
  }
823
0
  appearBuf->append("0 j\n0 J\n");
824
0
}
825
826
0
void Annot::setStrokeColor(double *color, int nComps) {
827
0
  switch (nComps) {
828
0
  case 0:
829
0
    appearBuf->append("0 G\n");
830
0
    break;
831
0
  case 1:
832
0
    appearBuf->appendf("{0:.2f} G\n", color[0]);
833
0
    break;
834
0
  case 3:
835
0
    appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} RG\n",
836
0
           color[0], color[1], color[2]);
837
0
    break;
838
0
  case 4:
839
0
    appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} K\n",
840
0
           color[0], color[1], color[2], color[3]);
841
0
    break;
842
0
  }
843
0
}
844
845
0
GBool Annot::setFillColor(Object *colorObj) {
846
0
  Object obj;
847
0
  double color[4];
848
0
  int i;
849
850
0
  if (!colorObj->isArray()) {
851
0
    return gFalse;
852
0
  }
853
0
  for (i = 0; i < colorObj->arrayGetLength() && i < 4; ++i) {
854
0
    if (colorObj->arrayGet(i, &obj)->isNum()) {
855
0
      color[i] = obj.getNum();
856
0
    } else {
857
0
      color[i] = 0;
858
0
    }
859
0
    obj.free();
860
0
  }
861
0
  switch (colorObj->arrayGetLength()) {
862
0
  case 1:
863
0
    appearBuf->appendf("{0:.2f} g\n", color[0]);
864
0
    return gTrue;
865
0
  case 3:
866
0
    appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} rg\n",
867
0
           color[0], color[1], color[2]);
868
0
    return gTrue;
869
0
  case 4:
870
0
    appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.3f} k\n",
871
0
           color[0], color[1],
872
0
           color[2], color[3]);
873
0
    return gTrue;
874
0
  }
875
0
  return gFalse;
876
0
}
877
878
0
AnnotLineEndType Annot::parseLineEndType(Object *obj) {
879
0
  if (obj->isName("None")) {
880
0
    return annotLineEndNone;
881
0
  } else if (obj->isName("Square")) {
882
0
    return annotLineEndSquare;
883
0
  } else if (obj->isName("Circle")) {
884
0
    return annotLineEndCircle;
885
0
  } else if (obj->isName("Diamond")) {
886
0
    return annotLineEndDiamond;
887
0
  } else if (obj->isName("OpenArrow")) {
888
0
    return annotLineEndOpenArrow;
889
0
  } else if (obj->isName("ClosedArrow")) {
890
0
    return annotLineEndClosedArrow;
891
0
  } else if (obj->isName("Butt")) {
892
0
    return annotLineEndButt;
893
0
  } else if (obj->isName("ROpenArrow")) {
894
0
    return annotLineEndROpenArrow;
895
0
  } else if (obj->isName("RClosedArrow")) {
896
0
    return annotLineEndRClosedArrow;
897
0
  } else if (obj->isName("Slash")) {
898
0
    return annotLineEndSlash;
899
0
  } else {
900
0
    return annotLineEndNone;
901
0
  }
902
0
}
903
904
void Annot::adjustLineEndpoint(AnnotLineEndType lineEnd,
905
             double x, double y, double dx, double dy,
906
0
             double w, double *tx, double *ty) {
907
0
  switch (lineEnd) {
908
0
  case annotLineEndNone:
909
0
    w = 0;
910
0
    break;
911
0
  case annotLineEndSquare:
912
0
    w *= lineEndSize1;
913
0
    break;
914
0
  case annotLineEndCircle:
915
0
    w *= lineEndSize1;
916
0
    break;
917
0
  case annotLineEndDiamond:
918
0
    w *= lineEndSize1;
919
0
    break;
920
0
  case annotLineEndOpenArrow:
921
0
    w = 0;
922
0
    break;
923
0
  case annotLineEndClosedArrow:
924
0
    w *= lineEndSize2 * cos(lineArrowAngle);
925
0
    break;
926
0
  case annotLineEndButt:
927
0
    w = 0;
928
0
    break;
929
0
  case annotLineEndROpenArrow:
930
0
    w *= lineEndSize2 * cos(lineArrowAngle);
931
0
    break;
932
0
  case annotLineEndRClosedArrow:
933
0
    w *= lineEndSize2 * cos(lineArrowAngle);
934
0
    break;
935
0
  case annotLineEndSlash:
936
0
    w = 0;
937
0
    break;
938
0
  }
939
0
  *tx = x + w * dx;
940
0
  *ty = y + w * dy;
941
0
}
942
943
void Annot::drawLineArrow(AnnotLineEndType lineEnd,
944
        double x, double y, double dx, double dy,
945
0
        double w, GBool fill) {
946
0
  switch (lineEnd) {
947
0
  case annotLineEndNone:
948
0
    break;
949
0
  case annotLineEndSquare:
950
0
    w *= lineEndSize1;
951
0
    appearBuf->appendf("{0:.4f} {1:.4f} m\n",
952
0
           x + w*dx + 0.5*w*dy,
953
0
           y + w*dy - 0.5*w*dx);
954
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n",
955
0
           x + 0.5*w*dy,
956
0
           y - 0.5*w*dx);
957
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n",
958
0
           x - 0.5*w*dy,
959
0
           y + 0.5*w*dx);
960
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n",
961
0
           x + w*dx - 0.5*w*dy,
962
0
           y + w*dy + 0.5*w*dx);
963
0
    appearBuf->append(fill ? "b\n" : "s\n");
964
0
    break;
965
0
  case annotLineEndCircle:
966
0
    w *= lineEndSize1;
967
0
    drawCircle(x + 0.5*w*dx, y + 0.5*w*dy, 0.5*w, fill ? "b" : "s");
968
0
    break;
969
0
  case annotLineEndDiamond:
970
0
    w *= lineEndSize1;
971
0
    appearBuf->appendf("{0:.4f} {1:.4f} m\n", x, y);
972
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n",
973
0
           x + 0.5*w*dx - 0.5*w*dy,
974
0
           y + 0.5*w*dy + 0.5*w*dx);
975
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n",
976
0
           x + w*dx,
977
0
           y + w*dy);
978
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n",
979
0
           x + 0.5*w*dx + 0.5*w*dy,
980
0
           y + 0.5*w*dy - 0.5*w*dx);
981
0
    appearBuf->append(fill ? "b\n" : "s\n");
982
0
    break;
983
0
  case annotLineEndOpenArrow:
984
0
    w *= lineEndSize2;
985
0
    appearBuf->appendf("{0:.4f} {1:.4f} m\n",
986
0
           x + w*cos(lineArrowAngle)*dx + w*sin(lineArrowAngle)*dy,
987
0
           y + w*cos(lineArrowAngle)*dy - w*sin(lineArrowAngle)*dx);
988
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n", x, y);
989
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n",
990
0
           x + w*cos(lineArrowAngle)*dx - w*sin(lineArrowAngle)*dy,
991
0
           y + w*cos(lineArrowAngle)*dy + w*sin(lineArrowAngle)*dx);
992
0
    appearBuf->append("S\n");
993
0
    break;
994
0
  case annotLineEndClosedArrow:
995
0
    w *= lineEndSize2;
996
0
    appearBuf->appendf("{0:.4f} {1:.4f} m\n",
997
0
           x + w*cos(lineArrowAngle)*dx + w*sin(lineArrowAngle)*dy,
998
0
           y + w*cos(lineArrowAngle)*dy - w*sin(lineArrowAngle)*dx);
999
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n", x, y);
1000
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n",
1001
0
           x + w*cos(lineArrowAngle)*dx - w*sin(lineArrowAngle)*dy,
1002
0
           y + w*cos(lineArrowAngle)*dy + w*sin(lineArrowAngle)*dx);
1003
0
    appearBuf->append(fill ? "b\n" : "s\n");
1004
0
    break;
1005
0
  case annotLineEndButt:
1006
0
    w *= lineEndSize1;
1007
0
    appearBuf->appendf("{0:.4f} {1:.4f} m\n",
1008
0
           x + 0.5*w*dy,
1009
0
           y - 0.5*w*dx);
1010
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n",
1011
0
           x - 0.5*w*dy,
1012
0
           y + 0.5*w*dx);
1013
0
    appearBuf->append("S\n");
1014
0
    break;
1015
0
  case annotLineEndROpenArrow:
1016
0
    w *= lineEndSize2;
1017
0
    appearBuf->appendf("{0:.4f} {1:.4f} m\n",
1018
0
           x + w*sin(lineArrowAngle)*dy,
1019
0
           y - w*sin(lineArrowAngle)*dx);
1020
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n",
1021
0
           x + w*cos(lineArrowAngle)*dx,
1022
0
           y + w*cos(lineArrowAngle)*dy);
1023
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n",
1024
0
           x - w*sin(lineArrowAngle)*dy,
1025
0
           y + w*sin(lineArrowAngle)*dx);
1026
0
    appearBuf->append("S\n");
1027
0
    break;
1028
0
  case annotLineEndRClosedArrow:
1029
0
    w *= lineEndSize2;
1030
0
    appearBuf->appendf("{0:.4f} {1:.4f} m\n",
1031
0
           x + w*sin(lineArrowAngle)*dy,
1032
0
           y - w*sin(lineArrowAngle)*dx);
1033
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n",
1034
0
           x + w*cos(lineArrowAngle)*dx,
1035
0
           y + w*cos(lineArrowAngle)*dy);
1036
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n",
1037
0
           x - w*sin(lineArrowAngle)*dy,
1038
0
           y + w*sin(lineArrowAngle)*dx);
1039
0
    appearBuf->append(fill ? "b\n" : "s\n");
1040
0
    break;
1041
0
  case annotLineEndSlash:
1042
0
    w *= lineEndSize1;
1043
0
    appearBuf->appendf("{0:.4f} {1:.4f} m\n",
1044
0
           x + 0.5*w*cos(lineArrowAngle)*dy
1045
0
             - 0.5*w*sin(lineArrowAngle)*dx,
1046
0
           y - 0.5*w*cos(lineArrowAngle)*dx
1047
0
             - 0.5*w*sin(lineArrowAngle)*dy);
1048
0
    appearBuf->appendf("{0:.4f} {1:.4f} l\n",
1049
0
           x - 0.5*w*cos(lineArrowAngle)*dy
1050
0
             + 0.5*w*sin(lineArrowAngle)*dx,
1051
0
           y + 0.5*w*cos(lineArrowAngle)*dx
1052
0
             + 0.5*w*sin(lineArrowAngle)*dy);
1053
0
    appearBuf->append("S\n");
1054
0
    break;
1055
0
  }
1056
0
}
1057
1058
// Draw an (approximate) circle of radius <r> centered at (<cx>, <cy>).
1059
// <cmd> is used to draw the circle ("f", "s", or "b").
1060
0
void Annot::drawCircle(double cx, double cy, double r, const char *cmd) {
1061
0
  appearBuf->appendf("{0:.4f} {1:.4f} m\n",
1062
0
         cx + r, cy);
1063
0
  appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} {4:.4f} {5:.4f} c\n",
1064
0
         cx + r, cy + bezierCircle * r,
1065
0
         cx + bezierCircle * r, cy + r,
1066
0
         cx, cy + r);
1067
0
  appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} {4:.4f} {5:.4f} c\n",
1068
0
         cx - bezierCircle * r, cy + r,
1069
0
         cx - r, cy + bezierCircle * r,
1070
0
         cx - r, cy);
1071
0
  appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} {4:.4f} {5:.4f} c\n",
1072
0
         cx - r, cy - bezierCircle * r,
1073
0
         cx - bezierCircle * r, cy - r,
1074
0
         cx, cy - r);
1075
0
  appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} {4:.4f} {5:.4f} c\n",
1076
0
         cx + bezierCircle * r, cy - r,
1077
0
         cx + r, cy - bezierCircle * r,
1078
0
         cx + r, cy);
1079
0
  appearBuf->appendf("{0:s}\n", cmd);
1080
0
}
1081
1082
// Draw the top-left half of an (approximate) circle of radius <r>
1083
// centered at (<cx>, <cy>).
1084
0
void Annot::drawCircleTopLeft(double cx, double cy, double r) {
1085
0
  double r2;
1086
1087
0
  r2 = r / sqrt(2.0);
1088
0
  appearBuf->appendf("{0:.4f} {1:.4f} m\n",
1089
0
         cx + r2, cy + r2);
1090
0
  appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} {4:.4f} {5:.4f} c\n",
1091
0
         cx + (1 - bezierCircle) * r2,
1092
0
         cy + (1 + bezierCircle) * r2,
1093
0
         cx - (1 - bezierCircle) * r2,
1094
0
         cy + (1 + bezierCircle) * r2,
1095
0
         cx - r2,
1096
0
         cy + r2);
1097
0
  appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} {4:.4f} {5:.4f} c\n",
1098
0
         cx - (1 + bezierCircle) * r2,
1099
0
         cy + (1 - bezierCircle) * r2,
1100
0
         cx - (1 + bezierCircle) * r2,
1101
0
         cy - (1 - bezierCircle) * r2,
1102
0
         cx - r2,
1103
0
         cy - r2);
1104
0
  appearBuf->append("S\n");
1105
0
}
1106
1107
// Draw the bottom-right half of an (approximate) circle of radius <r>
1108
// centered at (<cx>, <cy>).
1109
0
void Annot::drawCircleBottomRight(double cx, double cy, double r) {
1110
0
  double r2;
1111
1112
0
  r2 = r / sqrt(2.0);
1113
0
  appearBuf->appendf("{0:.4f} {1:.4f} m\n",
1114
0
         cx - r2, cy - r2);
1115
0
  appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} {4:.4f} {5:.4f} c\n",
1116
0
         cx - (1 - bezierCircle) * r2,
1117
0
         cy - (1 + bezierCircle) * r2,
1118
0
         cx + (1 - bezierCircle) * r2,
1119
0
         cy - (1 + bezierCircle) * r2,
1120
0
         cx + r2,
1121
0
         cy - r2);
1122
0
  appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} {4:.4f} {5:.4f} c\n",
1123
0
         cx + (1 + bezierCircle) * r2,
1124
0
         cy - (1 - bezierCircle) * r2,
1125
0
         cx + (1 + bezierCircle) * r2,
1126
0
         cy + (1 - bezierCircle) * r2,
1127
0
         cx + r2,
1128
0
         cy + r2);
1129
0
  appearBuf->append("S\n");
1130
0
}
1131
1132
void Annot::drawText(GString *text, GString *da, int quadding, double margin,
1133
0
         int rot) {
1134
0
  GString *text2, *tok;
1135
0
  GList *daToks;
1136
0
  const char *charName;
1137
0
  double dx, dy, fontSize, fontSize2, x, y, w;
1138
0
  Gushort charWidth;
1139
0
  int tfPos, tmPos, i, j, c;
1140
1141
  // check for a Unicode string
1142
  //~ this currently drops all non-Latin1 characters
1143
0
  if (text->getLength() >= 2 &&
1144
0
      text->getChar(0) == '\xfe' && text->getChar(1) == '\xff') {
1145
0
    text2 = new GString();
1146
0
    for (i = 2; i+1 < text->getLength(); i += 2) {
1147
0
      c = ((text->getChar(i) & 0xff) << 8) + (text->getChar(i+1) & 0xff);
1148
0
      if (c <= 0xff) {
1149
0
  text2->append((char)c);
1150
0
      } else {
1151
0
  text2->append('?');
1152
0
      }
1153
0
    }
1154
0
  } else {
1155
0
    text2 = text;
1156
0
  }
1157
1158
  // parse the default appearance string
1159
0
  tfPos = tmPos = -1;
1160
0
  if (da) {
1161
0
    daToks = new GList();
1162
0
    i = 0;
1163
0
    while (i < da->getLength()) {
1164
0
      while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) {
1165
0
  ++i;
1166
0
      }
1167
0
      if (i < da->getLength()) {
1168
0
  for (j = i + 1;
1169
0
       j < da->getLength() && !Lexer::isSpace(da->getChar(j));
1170
0
       ++j) ;
1171
0
  daToks->append(new GString(da, i, j - i));
1172
0
  i = j;
1173
0
      }
1174
0
    }
1175
0
    for (i = 2; i < daToks->getLength(); ++i) {
1176
0
      if (i >= 2 && !((GString *)daToks->get(i))->cmp("Tf")) {
1177
0
  tfPos = i - 2;
1178
0
      } else if (i >= 6 && !((GString *)daToks->get(i))->cmp("Tm")) {
1179
0
  tmPos = i - 6;
1180
0
      }
1181
0
    }
1182
0
  } else {
1183
0
    daToks = NULL;
1184
0
  }
1185
1186
  // get the font and font size
1187
0
  fontSize = 0;
1188
0
  if (tfPos >= 0) {
1189
    //~ where do we look up the font?
1190
0
    tok = (GString *)daToks->get(tfPos);
1191
0
    tok->clear();
1192
0
    tok->append("/xpdf_default_font");
1193
0
    tok = (GString *)daToks->get(tfPos + 1);
1194
0
    fontSize = atof(tok->getCString());
1195
0
  } else {
1196
0
    error(errSyntaxError, -1,
1197
0
    "Missing 'Tf' operator in annotation's DA string");
1198
0
    daToks->append(new GString("/xpdf_default_font"));
1199
0
    daToks->append(new GString("10"));
1200
0
    daToks->append(new GString("Tf"));
1201
0
  }
1202
1203
  // setup
1204
0
  appearBuf->append("q\n");
1205
0
  if (rot == 90) {
1206
0
    appearBuf->appendf("0 1 -1 0 {0:.4f} 0 cm\n", xMax - xMin);
1207
0
    dx = yMax - yMin;
1208
0
    dy = xMax - xMin;
1209
0
  } else if (rot == 180) {
1210
0
    appearBuf->appendf("-1 0 0 -1 {0:.4f} {1:.4f} cm\n",
1211
0
           xMax - xMin, yMax - yMin);
1212
0
    dx = xMax - yMax;
1213
0
    dy = yMax - yMin;
1214
0
  } else if (rot == 270) {
1215
0
    appearBuf->appendf("0 -1 1 0 0 {0:.4f} cm\n", yMax - yMin);
1216
0
    dx = yMax - yMin;
1217
0
    dy = xMax - xMin;
1218
0
  } else { // assume rot == 0
1219
0
    dx = xMax - xMin;
1220
0
    dy = yMax - yMin;
1221
0
  }
1222
0
  appearBuf->append("BT\n");
1223
1224
  // compute string width
1225
  //~ this assumes we're substituting Helvetica/WinAnsiEncoding for everything
1226
0
  w = 0;
1227
0
  for (i = 0; i < text2->getLength(); ++i) {
1228
0
    charName = winAnsiEncoding[text->getChar(i) & 0xff];
1229
0
    if (charName && builtinFonts[4].widths->getWidth(charName, &charWidth)) {
1230
0
      w += charWidth;
1231
0
    } else {
1232
0
      w += 0.5;
1233
0
    }
1234
0
  }
1235
1236
  // compute font autosize
1237
0
  if (fontSize == 0) {
1238
0
    fontSize = dy - 2 * margin;
1239
0
    fontSize2 = (dx - 2 * margin) / w;
1240
0
    if (fontSize2 < fontSize) {
1241
0
      fontSize = fontSize2;
1242
0
    }
1243
0
    fontSize = floor(fontSize);
1244
0
    if (tfPos >= 0) {
1245
0
      tok = (GString *)daToks->get(tfPos + 1);
1246
0
      tok->clear();
1247
0
      tok->appendf("{0:.4f}", fontSize);
1248
0
    }
1249
0
  }
1250
1251
  // compute text start position
1252
0
  w *= fontSize;
1253
0
  switch (quadding) {
1254
0
  case 0:
1255
0
  default:
1256
0
    x = margin + 2;
1257
0
    break;
1258
0
  case 1:
1259
0
    x = (dx - w) / 2;
1260
0
    break;
1261
0
  case 2:
1262
0
    x = dx - margin - 2 - w;
1263
0
    break;
1264
0
  }
1265
0
  y = 0.5 * dy - 0.4 * fontSize;
1266
1267
  // set the font matrix
1268
0
  if (tmPos >= 0) {
1269
0
    tok = (GString *)daToks->get(tmPos + 4);
1270
0
    tok->clear();
1271
0
    tok->appendf("{0:.4f}", x);
1272
0
    tok = (GString *)daToks->get(tmPos + 5);
1273
0
    tok->clear();
1274
0
    tok->appendf("{0:.4f}", y);
1275
0
  }
1276
  
1277
  // write the DA string
1278
0
  if (daToks) {
1279
0
    for (i = 0; i < daToks->getLength(); ++i) {
1280
0
      appearBuf->append((GString *)daToks->get(i))->append(' ');
1281
0
    }
1282
0
  }
1283
1284
  // write the font matrix (if not part of the DA string)
1285
0
  if (tmPos < 0) {
1286
0
    appearBuf->appendf("1 0 0 1 {0:.4f} {1:.4f} Tm\n", x, y);
1287
0
  }
1288
1289
  // write the text string
1290
0
  appearBuf->append('(');
1291
0
  for (i = 0; i < text2->getLength(); ++i) {
1292
0
    c = text2->getChar(i) & 0xff;
1293
0
    if (c == '(' || c == ')' || c == '\\') {
1294
0
      appearBuf->append('\\');
1295
0
      appearBuf->append((char)c);
1296
0
    } else if (c < 0x20 || c >= 0x80) {
1297
0
      appearBuf->appendf("\\{0:03o}", c);
1298
0
    } else {
1299
0
      appearBuf->append((char)c);
1300
0
    }
1301
0
  }
1302
0
  appearBuf->append(") Tj\n");
1303
1304
  // cleanup
1305
0
  appearBuf->append("ET\n");
1306
0
  appearBuf->append("Q\n");
1307
1308
0
  if (daToks) {
1309
0
    deleteGList(daToks, GString);
1310
0
  }
1311
0
  if (text2 != text) {
1312
0
    delete text2;
1313
0
  }
1314
0
}
1315
1316
0
void Annot::draw(Gfx *gfx, GBool printing) {
1317
0
  GBool oc, isLink;
1318
1319
  // check the flags
1320
0
  if ((flags & annotFlagHidden) ||
1321
0
      (printing && !(flags & annotFlagPrint)) ||
1322
0
      (!printing && (flags & annotFlagNoView))) {
1323
0
    return;
1324
0
  }
1325
1326
  // check the optional content entry
1327
0
  if (doc->getOptionalContent()->evalOCObject(&ocObj, &oc) && !oc) {
1328
0
    return;
1329
0
  }
1330
1331
  // draw the appearance stream
1332
0
  isLink = type && !type->cmp("Link");
1333
0
  gfx->drawAnnot(&appearance, isLink ? borderStyle : (AnnotBorderStyle *)NULL,
1334
0
     xMin, yMin, xMax, yMax);
1335
0
}
1336
1337
0
Object *Annot::getObject(Object *obj) {
1338
0
  if (ref.num >= 0) {
1339
0
    xref->fetch(ref.num, ref.gen, obj);
1340
0
  } else {
1341
0
    obj->initNull();
1342
0
  }
1343
0
  return obj;
1344
0
}
1345
1346
//------------------------------------------------------------------------
1347
// Annots
1348
//------------------------------------------------------------------------
1349
1350
0
Annots::Annots(PDFDoc *docA, Object *annotsObj) {
1351
0
  Annot *annot;
1352
0
  Object obj1, obj2;
1353
0
  Ref ref;
1354
0
  GBool drawWidgetAnnots;
1355
0
  int size;
1356
0
  int i;
1357
1358
0
  doc = docA;
1359
0
  annots = NULL;
1360
0
  size = 0;
1361
0
  nAnnots = 0;
1362
1363
0
  if (annotsObj->isArray()) {
1364
    // Kludge: some PDF files define an empty AcroForm, but still
1365
    // include Widget-type annotations -- in that case, we want to
1366
    // draw the widgets (since the form code won't).  This really
1367
    // ought to look for Widget-type annotations that are not included
1368
    // in any form field.
1369
0
    drawWidgetAnnots = !doc->getCatalog()->getForm() ||
1370
0
                       doc->getCatalog()->getForm()->getNumFields() == 0;
1371
0
    for (i = 0; i < annotsObj->arrayGetLength(); ++i) {
1372
0
      if (annotsObj->arrayGetNF(i, &obj1)->isRef()) {
1373
0
  ref = obj1.getRef();
1374
0
  obj1.free();
1375
0
  annotsObj->arrayGet(i, &obj1);
1376
0
      } else {
1377
0
  ref.num = ref.gen = -1;
1378
0
      }
1379
0
      if (obj1.isDict()) {
1380
0
  if (drawWidgetAnnots ||
1381
0
      !obj1.dictLookup("Subtype", &obj2)->isName("Widget")) {
1382
0
    annot = new Annot(doc, obj1.getDict(), &ref);
1383
0
    if (annot->isOk()) {
1384
0
      if (nAnnots >= size) {
1385
0
        size += 16;
1386
0
        annots = (Annot **)greallocn(annots, size, sizeof(Annot *));
1387
0
      }
1388
0
      annots[nAnnots++] = annot;
1389
0
    } else {
1390
0
      delete annot;
1391
0
    }
1392
0
  }
1393
0
  obj2.free();
1394
0
      }
1395
0
      obj1.free();
1396
0
    }
1397
0
  }
1398
0
}
1399
1400
0
Annots::~Annots() {
1401
0
  int i;
1402
1403
0
  for (i = 0; i < nAnnots; ++i) {
1404
0
    delete annots[i];
1405
0
  }
1406
0
  gfree(annots);
1407
0
}
1408
1409
0
Annot *Annots::find(double x, double y) {
1410
0
  int i;
1411
1412
0
  for (i = nAnnots - 1; i >= 0; --i) {
1413
0
    if (annots[i]->inRect(x, y)) {
1414
0
      return annots[i];
1415
0
    }
1416
0
  }
1417
0
  return NULL;
1418
0
}
1419
1420
0
int Annots::findIdx(double x, double y) {
1421
0
  int i;
1422
1423
0
  for (i = nAnnots - 1; i >= 0; --i) {
1424
0
    if (annots[i]->inRect(x, y)) {
1425
0
      return i;
1426
0
    }
1427
0
  }
1428
0
  return -1;
1429
0
}
1430
1431
0
void Annots::generateAnnotAppearances() {
1432
0
  int i;
1433
1434
0
  for (i = 0; i < nAnnots; ++i) {
1435
0
    annots[i]->generateAnnotAppearance();
1436
0
  }
1437
0
}
1438
1439
0
Annot *Annots::findAnnot(Ref *ref) {
1440
0
  int i;
1441
1442
0
  for (i = 0; i < nAnnots; ++i) {
1443
0
    if (annots[i]->match(ref)) {
1444
0
      return annots[i];
1445
0
    }
1446
0
  }
1447
0
  return NULL;
1448
0
}