Diffstat (limited to 'noncore/unsupported/qpdf/xpdf/TextOutputDev.cc') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/unsupported/qpdf/xpdf/TextOutputDev.cc | 73 |
1 files changed, 50 insertions, 23 deletions
diff --git a/noncore/unsupported/qpdf/xpdf/TextOutputDev.cc b/noncore/unsupported/qpdf/xpdf/TextOutputDev.cc index aa9366a..d3b0137 100644 --- a/noncore/unsupported/qpdf/xpdf/TextOutputDev.cc +++ b/noncore/unsupported/qpdf/xpdf/TextOutputDev.cc | |||
@@ -1,17 +1,17 @@ | |||
1 | //======================================================================== | 1 | //======================================================================== |
2 | // | 2 | // |
3 | // TextOutputDev.cc | 3 | // TextOutputDev.cc |
4 | // | 4 | // |
5 | // Copyright 1997 Derek B. Noonburg | 5 | // Copyright 1997-2002 Glyph & Cog, LLC |
6 | // | 6 | // |
7 | //======================================================================== | 7 | //======================================================================== |
8 | 8 | ||
9 | #ifdef __GNUC__ | 9 | #ifdef __GNUC__ |
10 | #pragma implementation | 10 | #pragma implementation |
11 | #endif | 11 | #endif |
12 | 12 | ||
13 | #include <aconf.h> | 13 | #include <aconf.h> |
14 | #include <stdio.h> | 14 | #include <stdio.h> |
15 | #include <stdlib.h> | 15 | #include <stdlib.h> |
16 | #include <stddef.h> | 16 | #include <stddef.h> |
17 | #include <math.h> | 17 | #include <math.h> |
@@ -39,24 +39,30 @@ TextString::TextString(GfxState *state, fouble fontSize) { | |||
39 | fouble x, y; | 39 | fouble x, y; |
40 | 40 | ||
41 | state->transform(state->getCurX(), state->getCurY(), &x, &y); | 41 | state->transform(state->getCurX(), state->getCurY(), &x, &y); |
42 | if ((font = state->getFont())) { | 42 | if ((font = state->getFont())) { |
43 | yMin = y - font->getAscent() * fontSize; | 43 | yMin = y - font->getAscent() * fontSize; |
44 | yMax = y - font->getDescent() * fontSize; | 44 | yMax = y - font->getDescent() * fontSize; |
45 | } else { | 45 | } else { |
46 | // this means that the PDF file draws text without a current font, | 46 | // this means that the PDF file draws text without a current font, |
47 | // which should never happen | 47 | // which should never happen |
48 | yMin = y - 0.95 * fontSize; | 48 | yMin = y - 0.95 * fontSize; |
49 | yMax = y + 0.35 * fontSize; | 49 | yMax = y + 0.35 * fontSize; |
50 | } | 50 | } |
51 | if (yMin == yMax) { | ||
52 | // this is a sanity check for a case that shouldn't happen -- but | ||
53 | // if it does happen, we want to avoid dividing by zero later | ||
54 | yMin = y; | ||
55 | yMax = y + 1; | ||
56 | } | ||
51 | col = 0; | 57 | col = 0; |
52 | text = NULL; | 58 | text = NULL; |
53 | xRight = NULL; | 59 | xRight = NULL; |
54 | len = size = 0; | 60 | len = size = 0; |
55 | yxNext = NULL; | 61 | yxNext = NULL; |
56 | xyNext = NULL; | 62 | xyNext = NULL; |
57 | } | 63 | } |
58 | 64 | ||
59 | TextString::~TextString() { | 65 | TextString::~TextString() { |
60 | gfree(text); | 66 | gfree(text); |
61 | gfree(xRight); | 67 | gfree(xRight); |
62 | } | 68 | } |
@@ -90,43 +96,47 @@ TextPage::TextPage(GBool rawOrderA) { | |||
90 | nest = 0; | 96 | nest = 0; |
91 | } | 97 | } |
92 | 98 | ||
93 | TextPage::~TextPage() { | 99 | TextPage::~TextPage() { |
94 | clear(); | 100 | clear(); |
95 | } | 101 | } |
96 | 102 | ||
97 | void TextPage::updateFont(GfxState *state) { | 103 | void TextPage::updateFont(GfxState *state) { |
98 | GfxFont *font; | 104 | GfxFont *font; |
99 | fouble *fm; | 105 | fouble *fm; |
100 | char *name; | 106 | char *name; |
101 | int code; | 107 | int code; |
108 | fouble w; | ||
102 | 109 | ||
103 | // adjust the font size | 110 | // adjust the font size |
104 | fontSize = state->getTransformedFontSize(); | 111 | fontSize = state->getTransformedFontSize(); |
105 | if ((font = state->getFont()) && font->getType() == fontType3) { | 112 | if ((font = state->getFont()) && font->getType() == fontType3) { |
106 | // This is a hack which makes it possible to deal with some Type 3 | 113 | // This is a hack which makes it possible to deal with some Type 3 |
107 | // fonts. The problem is that it's impossible to know what the | 114 | // fonts. The problem is that it's impossible to know what the |
108 | // base coordinate system used in the font is without actually | 115 | // base coordinate system used in the font is without actually |
109 | // rendering the font. This code tries to guess by looking at the | 116 | // rendering the font. This code tries to guess by looking at the |
110 | // width of the character 'm' (which breaks if the font is a | 117 | // width of the character 'm' (which breaks if the font is a |
111 | // subset that doesn't contain 'm'). | 118 | // subset that doesn't contain 'm'). |
112 | for (code = 0; code < 256; ++code) { | 119 | for (code = 0; code < 256; ++code) { |
113 | if ((name = ((Gfx8BitFont *)font)->getCharName(code)) && | 120 | if ((name = ((Gfx8BitFont *)font)->getCharName(code)) && |
114 | name[0] == 'm' && name[1] == '\0') { | 121 | name[0] == 'm' && name[1] == '\0') { |
115 | break; | 122 | break; |
116 | } | 123 | } |
117 | } | 124 | } |
118 | if (code < 256) { | 125 | if (code < 256) { |
119 | // 600 is a generic average 'm' width -- yes, this is a hack | 126 | w = ((Gfx8BitFont *)font)->getWidth(code); |
120 | fontSize *= ((Gfx8BitFont *)font)->getWidth(code) / 0.6; | 127 | if (w != 0) { |
128 | // 600 is a generic average 'm' width -- yes, this is a hack | ||
129 | fontSize *= w / 0.6; | ||
130 | } | ||
121 | } | 131 | } |
122 | fm = font->getFontMatrix(); | 132 | fm = font->getFontMatrix(); |
123 | if (fm[0] != 0) { | 133 | if (fm[0] != 0) { |
124 | fontSize *= fabs(fm[3] / fm[0]); | 134 | fontSize *= fabs(fm[3] / fm[0]); |
125 | } | 135 | } |
126 | } | 136 | } |
127 | } | 137 | } |
128 | 138 | ||
129 | void TextPage::beginString(GfxState *state) { | 139 | void TextPage::beginString(GfxState *state) { |
130 | // This check is needed because Type 3 characters can contain | 140 | // This check is needed because Type 3 characters can contain |
131 | // text-drawing operations. | 141 | // text-drawing operations. |
132 | if (curStr) { | 142 | if (curStr) { |
@@ -145,26 +155,28 @@ void TextPage::addChar(GfxState *state, fouble x, fouble y, | |||
145 | state->transform(x, y, &x1, &y1); | 155 | state->transform(x, y, &x1, &y1); |
146 | n = curStr->len; | 156 | n = curStr->len; |
147 | if (n > 0 && | 157 | if (n > 0 && |
148 | x1 - curStr->xRight[n-1] > 0.1 * (curStr->yMax - curStr->yMin)) { | 158 | x1 - curStr->xRight[n-1] > 0.1 * (curStr->yMax - curStr->yMin)) { |
149 | endString(); | 159 | endString(); |
150 | beginString(state); | 160 | beginString(state); |
151 | } | 161 | } |
152 | state->textTransformDelta(state->getCharSpace() * state->getHorizScaling(), | 162 | state->textTransformDelta(state->getCharSpace() * state->getHorizScaling(), |
153 | 0, &dx2, &dy2); | 163 | 0, &dx2, &dy2); |
154 | dx -= dx2; | 164 | dx -= dx2; |
155 | dy -= dy2; | 165 | dy -= dy2; |
156 | state->transformDelta(dx, dy, &w1, &h1); | 166 | state->transformDelta(dx, dy, &w1, &h1); |
157 | w1 /= uLen; | 167 | if (uLen != 0) { |
158 | h1 /= uLen; | 168 | w1 /= uLen; |
169 | h1 /= uLen; | ||
170 | } | ||
159 | for (i = 0; i < uLen; ++i) { | 171 | for (i = 0; i < uLen; ++i) { |
160 | curStr->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u[i]); | 172 | curStr->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u[i]); |
161 | } | 173 | } |
162 | } | 174 | } |
163 | 175 | ||
164 | void TextPage::endString() { | 176 | void TextPage::endString() { |
165 | TextString *p1, *p2; | 177 | TextString *p1, *p2; |
166 | fouble h, y1, y2; | 178 | fouble h, y1, y2; |
167 | 179 | ||
168 | // This check is needed because Type 3 characters can contain | 180 | // This check is needed because Type 3 characters can contain |
169 | // text-drawing operations. | 181 | // text-drawing operations. |
170 | if (nest > 0) { | 182 | if (nest > 0) { |
@@ -420,25 +432,25 @@ GString *TextPage::getText(fouble xMin, fouble yMin, | |||
420 | } | 432 | } |
421 | xPrev = x2; | 433 | xPrev = x2; |
422 | yPrev = str1->yMax; | 434 | yPrev = str1->yMax; |
423 | } | 435 | } |
424 | } | 436 | } |
425 | if (multiLine) { | 437 | if (multiLine) { |
426 | s->append(eol, eolLen); | 438 | s->append(eol, eolLen); |
427 | } | 439 | } |
428 | uMap->decRefCnt(); | 440 | uMap->decRefCnt(); |
429 | return s; | 441 | return s; |
430 | } | 442 | } |
431 | 443 | ||
432 | void TextPage::dump(FILE *f) { | 444 | void TextPage::dump(void *outputStream, TextOutputFunc outputFunc) { |
433 | UnicodeMap *uMap; | 445 | UnicodeMap *uMap; |
434 | char space[8], eol[16], eop[8], buf[8]; | 446 | char space[8], eol[16], eop[8], buf[8]; |
435 | int spaceLen, eolLen, eopLen, n; | 447 | int spaceLen, eolLen, eopLen, n; |
436 | TextString *str1, *str2, *str3; | 448 | TextString *str1, *str2, *str3; |
437 | fouble yMin, yMax; | 449 | fouble yMin, yMax; |
438 | int col1, col2, d, i; | 450 | int col1, col2, d, i; |
439 | 451 | ||
440 | // get the output encoding | 452 | // get the output encoding |
441 | if (!(uMap = globalParams->getTextEncoding())) { | 453 | if (!(uMap = globalParams->getTextEncoding())) { |
442 | return; | 454 | return; |
443 | } | 455 | } |
444 | spaceLen = uMap->mapUnicode(0x20, space, sizeof(space)); | 456 | spaceLen = uMap->mapUnicode(0x20, space, sizeof(space)); |
@@ -489,74 +501,74 @@ void TextPage::dump(FILE *f) { | |||
489 | col2 = str2->col + | 501 | col2 = str2->col + |
490 | (int)(((str1->xMin - str2->xMin) / (str2->xMax - str2->xMin)) * | 502 | (int)(((str1->xMin - str2->xMin) / (str2->xMax - str2->xMin)) * |
491 | str2->len); | 503 | str2->len); |
492 | if (col2 > col1) { | 504 | if (col2 > col1) { |
493 | col1 = col2; | 505 | col1 = col2; |
494 | } | 506 | } |
495 | } | 507 | } |
496 | } | 508 | } |
497 | str1->col = col1; | 509 | str1->col = col1; |
498 | } | 510 | } |
499 | 511 | ||
500 | #if 0 //~ for debugging | 512 | #if 0 //~ for debugging |
501 | fprintf(f, "~~~~~~~~~~\n"); | 513 | fprintf((FILE *)outputStream, "~~~~~~~~~~\n"); |
502 | for (str1 = yxStrings; str1; str1 = str1->yxNext) { | 514 | for (str1 = yxStrings; str1; str1 = str1->yxNext) { |
503 | fprintf(f, "(%4d,%4d) - (%4d,%4d) [%3d] '", | 515 | fprintf((FILE *)outputStream, "(%4d,%4d) - (%4d,%4d) [%3d] '", |
504 | (int)str1->xMin, (int)str1->yMin, | 516 | (int)str1->xMin, (int)str1->yMin, |
505 | (int)str1->xMax, (int)str1->yMax, str1->col); | 517 | (int)str1->xMax, (int)str1->yMax, str1->col); |
506 | for (i = 0; i < str1->len; ++i) { | 518 | for (i = 0; i < str1->len; ++i) { |
507 | fputc(str1->text[i] & 0xff, stdout); | 519 | fputc(str1->text[i] & 0xff, stdout); |
508 | } | 520 | } |
509 | printf("'\n"); | 521 | printf("'\n"); |
510 | } | 522 | } |
511 | fprintf(f, "~~~~~~~~~~\n"); | 523 | fprintf((FILE *)outputStream, "~~~~~~~~~~\n"); |
512 | #endif | 524 | #endif |
513 | 525 | ||
514 | // output | 526 | // output |
515 | col1 = 0; | 527 | col1 = 0; |
516 | yMax = yxStrings ? yxStrings->yMax : fouble(0); | 528 | yMax = yxStrings ? yxStrings->yMax : fouble(0); |
517 | for (str1 = yxStrings; str1; str1 = str1->yxNext) { | 529 | for (str1 = yxStrings; str1; str1 = str1->yxNext) { |
518 | 530 | ||
519 | // line this string up with the correct column | 531 | // line this string up with the correct column |
520 | if (rawOrder && col1 == 0) { | 532 | if (rawOrder && col1 == 0) { |
521 | col1 = str1->col; | 533 | col1 = str1->col; |
522 | } else { | 534 | } else { |
523 | for (; col1 < str1->col; ++col1) { | 535 | for (; col1 < str1->col; ++col1) { |
524 | fwrite(space, 1, spaceLen, f); | 536 | (*outputFunc)(outputStream, space, spaceLen); |
525 | } | 537 | } |
526 | } | 538 | } |
527 | 539 | ||
528 | // print the string | 540 | // print the string |
529 | for (i = 0; i < str1->len; ++i) { | 541 | for (i = 0; i < str1->len; ++i) { |
530 | if ((n = uMap->mapUnicode(str1->text[i], buf, sizeof(buf))) > 0) { | 542 | if ((n = uMap->mapUnicode(str1->text[i], buf, sizeof(buf))) > 0) { |
531 | fwrite(buf, 1, n, f); | 543 | (*outputFunc)(outputStream, buf, n); |
532 | } | 544 | } |
533 | } | 545 | } |
534 | 546 | ||
535 | // increment column | 547 | // increment column |
536 | col1 += str1->len; | 548 | col1 += str1->len; |
537 | 549 | ||
538 | // update yMax for this line | 550 | // update yMax for this line |
539 | if (str1->yMax > yMax) { | 551 | if (str1->yMax > yMax) { |
540 | yMax = str1->yMax; | 552 | yMax = str1->yMax; |
541 | } | 553 | } |
542 | 554 | ||
543 | // if we've hit the end of the line... | 555 | // if we've hit the end of the line... |
544 | if (!(str1->yxNext && | 556 | if (!(str1->yxNext && |
545 | !(rawOrder && str1->yxNext->yMax < str1->yMin) && | 557 | !(rawOrder && str1->yxNext->yMax < str1->yMin) && |
546 | str1->yxNext->yMin < 0.2*str1->yMin + 0.8*str1->yMax && | 558 | str1->yxNext->yMin < 0.2*str1->yMin + 0.8*str1->yMax && |
547 | str1->yxNext->xMin >= str1->xMax)) { | 559 | str1->yxNext->xMin >= str1->xMax)) { |
548 | 560 | ||
549 | // print a return | 561 | // print a return |
550 | fwrite(eol, 1, eolLen, f); | 562 | (*outputFunc)(outputStream, eol, eolLen); |
551 | 563 | ||
552 | // print extra vertical space if necessary | 564 | // print extra vertical space if necessary |
553 | if (str1->yxNext) { | 565 | if (str1->yxNext) { |
554 | 566 | ||
555 | // find yMin for next line | 567 | // find yMin for next line |
556 | yMin = str1->yxNext->yMin; | 568 | yMin = str1->yxNext->yMin; |
557 | for (str2 = str1->yxNext; str2; str2 = str2->yxNext) { | 569 | for (str2 = str1->yxNext; str2; str2 = str2->yxNext) { |
558 | if (str2->yMin < yMin) { | 570 | if (str2->yMin < yMin) { |
559 | yMin = str2->yMin; | 571 | yMin = str2->yMin; |
560 | } | 572 | } |
561 | if (!(str2->yxNext && str2->yxNext->yMin < str2->yMax && | 573 | if (!(str2->yxNext && str2->yxNext->yMin < str2->yMax && |
562 | str2->yxNext->xMin >= str2->xMax)) | 574 | str2->yxNext->xMin >= str2->xMax)) |
@@ -564,107 +576,122 @@ void TextPage::dump(FILE *f) { | |||
564 | } | 576 | } |
565 | 577 | ||
566 | // print the space | 578 | // print the space |
567 | d = (int)((yMin - yMax) / (str1->yMax - str1->yMin) + 0.5); | 579 | d = (int)((yMin - yMax) / (str1->yMax - str1->yMin) + 0.5); |
568 | // various things (weird font matrices) can result in bogus | 580 | // various things (weird font matrices) can result in bogus |
569 | // values here, so do a sanity check | 581 | // values here, so do a sanity check |
570 | if (rawOrder && d > 2) { | 582 | if (rawOrder && d > 2) { |
571 | d = 2; | 583 | d = 2; |
572 | } else if (!rawOrder && d > 5) { | 584 | } else if (!rawOrder && d > 5) { |
573 | d = 5; | 585 | d = 5; |
574 | } | 586 | } |
575 | for (; d > 0; --d) { | 587 | for (; d > 0; --d) { |
576 | fwrite(eol, 1, eolLen, f); | 588 | (*outputFunc)(outputStream, eol, eolLen); |
577 | } | 589 | } |
578 | } | 590 | } |
579 | 591 | ||
580 | // set up for next line | 592 | // set up for next line |
581 | col1 = 0; | 593 | col1 = 0; |
582 | yMax = str1->yxNext ? str1->yxNext->yMax : fouble(0); | 594 | yMax = str1->yxNext ? str1->yxNext->yMax : fouble(0); |
583 | } | 595 | } |
584 | } | 596 | } |
585 | 597 | ||
586 | // end of page | 598 | // end of page |
587 | fwrite(eol, 1, eolLen, f); | 599 | (*outputFunc)(outputStream, eol, eolLen); |
588 | fwrite(eop, 1, eopLen, f); | 600 | (*outputFunc)(outputStream, eop, eopLen); |
589 | fwrite(eol, 1, eolLen, f); | 601 | (*outputFunc)(outputStream, eol, eolLen); |
590 | 602 | ||
591 | uMap->decRefCnt(); | 603 | uMap->decRefCnt(); |
592 | } | 604 | } |
593 | 605 | ||
594 | void TextPage::clear() { | 606 | void TextPage::clear() { |
595 | TextString *p1, *p2; | 607 | TextString *p1, *p2; |
596 | 608 | ||
597 | if (curStr) { | 609 | if (curStr) { |
598 | delete curStr; | 610 | delete curStr; |
599 | curStr = NULL; | 611 | curStr = NULL; |
600 | } | 612 | } |
601 | for (p1 = yxStrings; p1; p1 = p2) { | 613 | for (p1 = yxStrings; p1; p1 = p2) { |
602 | p2 = p1->yxNext; | 614 | p2 = p1->yxNext; |
603 | delete p1; | 615 | delete p1; |
604 | } | 616 | } |
605 | yxStrings = NULL; | 617 | yxStrings = NULL; |
606 | xyStrings = NULL; | 618 | xyStrings = NULL; |
607 | yxCur1 = yxCur2 = NULL; | 619 | yxCur1 = yxCur2 = NULL; |
608 | } | 620 | } |
609 | 621 | ||
610 | //------------------------------------------------------------------------ | 622 | //------------------------------------------------------------------------ |
611 | // TextOutputDev | 623 | // TextOutputDev |
612 | //------------------------------------------------------------------------ | 624 | //------------------------------------------------------------------------ |
613 | 625 | ||
626 | static void outputToFile(void *stream, char *text, int len) { | ||
627 | fwrite(text, 1, len, (FILE *)stream); | ||
628 | } | ||
629 | |||
614 | TextOutputDev::TextOutputDev(char *fileName, GBool rawOrderA, GBool append) { | 630 | TextOutputDev::TextOutputDev(char *fileName, GBool rawOrderA, GBool append) { |
615 | text = NULL; | 631 | text = NULL; |
616 | rawOrder = rawOrderA; | 632 | rawOrder = rawOrderA; |
617 | ok = gTrue; | 633 | ok = gTrue; |
618 | 634 | ||
619 | // open file | 635 | // open file |
620 | needClose = gFalse; | 636 | needClose = gFalse; |
621 | if (fileName) { | 637 | if (fileName) { |
622 | if (!strcmp(fileName, "-")) { | 638 | if (!strcmp(fileName, "-")) { |
623 | f = stdout; | 639 | outputStream = stdout; |
624 | } else if ((f = fopen(fileName, append ? "a" : "w"))) { | 640 | } else if ((outputStream = fopen(fileName, append ? "ab" : "wb"))) { |
625 | needClose = gTrue; | 641 | needClose = gTrue; |
626 | } else { | 642 | } else { |
627 | error(-1, "Couldn't open text file '%s'", fileName); | 643 | error(-1, "Couldn't open text file '%s'", fileName); |
628 | ok = gFalse; | 644 | ok = gFalse; |
629 | return; | 645 | return; |
630 | } | 646 | } |
647 | outputFunc = &outputToFile; | ||
631 | } else { | 648 | } else { |
632 | f = NULL; | 649 | outputStream = NULL; |
633 | } | 650 | } |
634 | 651 | ||
635 | // set up text object | 652 | // set up text object |
636 | text = new TextPage(rawOrder); | 653 | text = new TextPage(rawOrder); |
637 | } | 654 | } |
638 | 655 | ||
656 | TextOutputDev::TextOutputDev(TextOutputFunc func, void *stream, | ||
657 | GBool rawOrderA) { | ||
658 | outputFunc = func; | ||
659 | outputStream = stream; | ||
660 | needClose = gFalse; | ||
661 | rawOrder = rawOrderA; | ||
662 | text = new TextPage(rawOrder); | ||
663 | ok = gTrue; | ||
664 | } | ||
665 | |||
639 | TextOutputDev::~TextOutputDev() { | 666 | TextOutputDev::~TextOutputDev() { |
640 | if (needClose) { | 667 | if (needClose) { |
641 | #ifdef MACOS | 668 | #ifdef MACOS |
642 | ICS_MapRefNumAndAssign((short)f->handle); | 669 | ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle); |
643 | #endif | 670 | #endif |
644 | fclose(f); | 671 | fclose((FILE *)outputStream); |
645 | } | 672 | } |
646 | if (text) { | 673 | if (text) { |
647 | delete text; | 674 | delete text; |
648 | } | 675 | } |
649 | } | 676 | } |
650 | 677 | ||
651 | void TextOutputDev::startPage(int pageNum, GfxState *state) { | 678 | void TextOutputDev::startPage(int pageNum, GfxState *state) { |
652 | text->clear(); | 679 | text->clear(); |
653 | } | 680 | } |
654 | 681 | ||
655 | void TextOutputDev::endPage() { | 682 | void TextOutputDev::endPage() { |
656 | text->coalesce(); | 683 | text->coalesce(); |
657 | if (f) { | 684 | if (outputStream) { |
658 | text->dump(f); | 685 | text->dump(outputStream, outputFunc); |
659 | } | 686 | } |
660 | } | 687 | } |
661 | 688 | ||
662 | void TextOutputDev::updateFont(GfxState *state) { | 689 | void TextOutputDev::updateFont(GfxState *state) { |
663 | text->updateFont(state); | 690 | text->updateFont(state); |
664 | } | 691 | } |
665 | 692 | ||
666 | void TextOutputDev::beginString(GfxState *state, GString *s) { | 693 | void TextOutputDev::beginString(GfxState *state, GString *s) { |
667 | text->beginString(state); | 694 | text->beginString(state); |
668 | } | 695 | } |
669 | 696 | ||
670 | void TextOutputDev::endString(GfxState *state) { | 697 | void TextOutputDev::endString(GfxState *state) { |