~reviczky/luatex/texlive-bin-git

« back to all changes in this revision

Viewing changes to texk/dvisvgm/dvisvgm-1.8.1/src/GFReader.cpp

  • Committer: Adam Reviczky
  • Date: 2015-04-26 22:40:47 UTC
  • Revision ID: adam.reviczky@kclalumni.net-20150426224047-i2p26n3wqphupq6z
TeX Live 2015 import (rev. 37052)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*************************************************************************
2
 
** GFReader.cpp                                                         **
3
 
**                                                                      **
4
 
** This file is part of dvisvgm -- the DVI to SVG converter             **
5
 
** Copyright (C) 2005-2014 Martin Gieseking <martin.gieseking@uos.de>   **
6
 
**                                                                      **
7
 
** This program is free software; you can redistribute it and/or        **
8
 
** modify it under the terms of the GNU General Public License as       **
9
 
** published by the Free Software Foundation; either version 3 of       **
10
 
** the License, or (at your option) any later version.                  **
11
 
**                                                                      **
12
 
** This program is distributed in the hope that it will be useful, but  **
13
 
** WITHOUT ANY WARRANTY; without even the implied warranty of           **
14
 
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         **
15
 
** GNU General Public License for more details.                         **
16
 
**                                                                      **
17
 
** You should have received a copy of the GNU General Public License    **
18
 
** along with this program; if not, see <http://www.gnu.org/licenses/>. **
19
 
*************************************************************************/
20
 
 
21
 
#include <config.h>
22
 
#include <iostream>
23
 
#include <sstream>
24
 
#include "GFReader.h"
25
 
#include "macros.h"
26
 
#include "SignalHandler.h"
27
 
 
28
 
using namespace std;
29
 
 
30
 
struct GFCommand
31
 
{
32
 
        void (GFReader::*method)(int);
33
 
        int numBytes;
34
 
};
35
 
 
36
 
 
37
 
static inline double fix2double (Int32 fix) {
38
 
        return double(fix)/(1 << 20)*72/72.27;
39
 
}
40
 
 
41
 
 
42
 
static inline double scaled2double (Int32 scaled) {
43
 
        return double(scaled)/(1 << 16);
44
 
}
45
 
 
46
 
 
47
 
GFReader::GFReader (istream &is) : _in(is), _penDown(false)
48
 
{
49
 
        _minX = _maxX = _minY = _maxY = _x = _y = 0;
50
 
        _currentChar = 0;
51
 
        _designSize = 0;
52
 
        _hppp = _vppp = 0;
53
 
        _checksum = 0;
54
 
}
55
 
 
56
 
 
57
 
UInt32 GFReader::readUnsigned (int bytes) {
58
 
        UInt32 ret = 0;
59
 
        for (int i=bytes-1; i >= 0 && !_in.eof(); i--) {
60
 
                UInt32 b = _in.get();
61
 
                ret |= b << (8*i);
62
 
        }
63
 
        return ret;
64
 
}
65
 
 
66
 
 
67
 
Int32 GFReader::readSigned (int bytes) {
68
 
        Int32 ret = _in.get();
69
 
        if (ret & 128)        // negative value?
70
 
                ret |= 0xffffff00;
71
 
        for (int i=bytes-2; i >= 0 && !_in.eof(); i--)
72
 
                ret = (ret << 8) | _in.get();
73
 
        return ret;
74
 
}
75
 
 
76
 
 
77
 
string GFReader::readString (int bytes) {
78
 
        vector<char> buf(bytes+1);
79
 
        if (bytes > 0)
80
 
                _in.get(&buf[0], bytes+1);  // reads 'bytes' bytes (pos. bytes+1 is set to 0)
81
 
        else
82
 
                buf[0] = 0;
83
 
        return &buf[0];
84
 
}
85
 
 
86
 
 
87
 
/** Reads a single GF command from the current position of the input stream and calls the
88
 
 *  corresponding cmdFOO method.
89
 
 *  @return opcode of the executed command */
90
 
int GFReader::executeCommand () {
91
 
        SignalHandler::instance().check();
92
 
        /* Each cmdFOO command reads the necessary number of bytes from the stream so executeCommand
93
 
        doesn't need to know the exact GF command format. Some cmdFOO methods are used for multiple
94
 
        GF commands because they only differ in the size of their parameters. */
95
 
        static const GFCommand commands[] = {
96
 
                {&GFReader::cmdPaint, 1}, {&GFReader::cmdPaint, 2}, {&GFReader::cmdPaint, 3},                        // 64-66
97
 
                {&GFReader::cmdBoc, 0},   {&GFReader::cmdBoc1, 0},                                                   // 67-68
98
 
                {&GFReader::cmdEoc, 0},                                                                              // 69
99
 
                {&GFReader::cmdSkip, 0},  {&GFReader::cmdSkip, 1},  {&GFReader::cmdSkip, 2},{&GFReader::cmdSkip, 3}, // 70-73
100
 
                {&GFReader::cmdXXX, 1},   {&GFReader::cmdXXX, 2},   {&GFReader::cmdXXX, 3}, {&GFReader::cmdXXX, 4},  // 239-242
101
 
                {&GFReader::cmdYYY, 0},                                                                              // 243
102
 
                {&GFReader::cmdNop, 0},                                                                              // 244
103
 
                {&GFReader::cmdCharLoc, 0}, {&GFReader::cmdCharLoc0, 0},                                             // 245-246
104
 
                {&GFReader::cmdPre, 0},     {&GFReader::cmdPost, 0}, {&GFReader::cmdPostPost, 0}                     // 247-249
105
 
        };
106
 
 
107
 
        int opcode = _in.get();
108
 
        if (opcode < 0)  // at end of file?
109
 
                throw GFException("unexpected end of file");
110
 
 
111
 
        if (opcode >= 0 && opcode <= 63)
112
 
                cmdPaint0(opcode);
113
 
        else if (opcode >= 74 && opcode <= 238)
114
 
                cmdNewRow(opcode-74);
115
 
        else if (opcode >= 250) {
116
 
                ostringstream oss;
117
 
                oss << "undefined GF command (opcode " << opcode << ")";
118
 
                throw GFException(oss.str());
119
 
        }
120
 
        else {
121
 
                int offset = opcode <= 73 ? 64 : 239-(73-64+1);
122
 
                const GFCommand &cmd = commands[opcode-offset];
123
 
                if (cmd.method)
124
 
                        (this->*cmd.method)(cmd.numBytes);
125
 
        }
126
 
        return opcode;
127
 
}
128
 
 
129
 
 
130
 
bool GFReader::executeChar (UInt8 c) {
131
 
        _in.clear();
132
 
        if (_charInfoMap.empty())
133
 
                executePostamble();          // read character info
134
 
        _in.clear();
135
 
        Iterator it = _charInfoMap.find(c);
136
 
        if (_in && it != _charInfoMap.end()) {
137
 
                _in.seekg(it->second.location);
138
 
                while (executeCommand() != 69);  // execute all commands until eoc is reached
139
 
                return true;
140
 
        }
141
 
        return false;
142
 
}
143
 
 
144
 
 
145
 
bool GFReader::executeAllChars () {
146
 
        _in.clear();
147
 
        if (_charInfoMap.empty())
148
 
                executePostamble();   // read character info
149
 
        _in.clear();
150
 
        if (_in) {
151
 
                _in.seekg(0);
152
 
                while (executeCommand() != 248); // execute all commands until postamble is reached
153
 
                return true;
154
 
        }
155
 
        return false;
156
 
}
157
 
 
158
 
 
159
 
bool GFReader::executePostamble () {
160
 
        _in.clear();
161
 
        if (!_in)
162
 
                return false;
163
 
        _in.seekg(-1, ios_base::end);
164
 
        while (_in.peek() == 223)         // skip fill bytes
165
 
                _in.seekg(-1, ios_base::cur);
166
 
        _in.seekg(-4, ios_base::cur);
167
 
        UInt32 q = readUnsigned(4);      // pointer to begin of postamble
168
 
        _in.seekg(q);                    // now on begin of postamble
169
 
        while (executeCommand() != 249); // execute all commands until postpost is reached
170
 
        return true;
171
 
}
172
 
 
173
 
 
174
 
/** Returns the design size of this font int PS point units. */
175
 
double GFReader::getDesignSize () const {
176
 
        return fix2double(_designSize);
177
 
}
178
 
 
179
 
/** Returns the number of horizontal pixels per point. */
180
 
double GFReader::getHPixelsPerPoint () const {
181
 
        return scaled2double(_hppp)*72/72.27;
182
 
}
183
 
 
184
 
/** Returns the number of vertical pixels per point. */
185
 
double GFReader::getVPixelsPerPoint () const {
186
 
        return scaled2double(_vppp)*72/72.27;
187
 
}
188
 
 
189
 
/** Returns the width of character c in PS point units */
190
 
double GFReader::getCharWidth (UInt32 c) const {
191
 
        ConstIterator it = _charInfoMap.find(c%256);
192
 
        return it == _charInfoMap.end() ? 0 : it->second.width*getDesignSize()/(1<<24);
193
 
}
194
 
 
195
 
///////////////////////
196
 
 
197
 
 
198
 
/** Reads the preamble. */
199
 
void GFReader::cmdPre (int) {
200
 
        UInt32 i = readUnsigned(1);
201
 
        if (i == 131) {
202
 
                UInt32 k = readUnsigned(1);
203
 
                string s = readString(k);
204
 
                preamble(s);
205
 
        }
206
 
        else
207
 
                throw GFException("invalid identification number in GF preamble");
208
 
}
209
 
 
210
 
 
211
 
/** Reads the postamble. */
212
 
void GFReader::cmdPost (int) {
213
 
        readUnsigned(4);                // pointer to byte after final eoc
214
 
        _designSize = readUnsigned(4);  // design size of font in points
215
 
        _checksum   = readUnsigned(4);  // checksum
216
 
        _hppp       = readUnsigned(4);  // horizontal pixels per point (scaled int)
217
 
        _vppp       = readUnsigned(4);  // vertical pixels per point (scaled int)
218
 
        _in.seekg(16, ios_base::cur);   // skip x and y bounds
219
 
        postamble();
220
 
}
221
 
 
222
 
 
223
 
/** Reads trailing bytes at end of stream. */
224
 
void GFReader::cmdPostPost (int) {
225
 
        readUnsigned(4);   // pointer to begin of postamble
226
 
        UInt32 i = readUnsigned(1);
227
 
        if (i == 131)
228
 
                while (readUnsigned(1) == 223); // skip fill bytes
229
 
        else
230
 
                throw GFException("invalid identification number in GF preamble");
231
 
}
232
 
 
233
 
 
234
 
/** Inverts "paint color" (black to white or vice versa) of n pixels
235
 
 *  and advances the cursor by n.
236
 
 *  @param[in] n number of pixels to be inverted */
237
 
void GFReader::cmdPaint0 (int n) {
238
 
        if (_penDown)                    // set pixels?
239
 
                _bitmap.setBits(_y, _x, n);
240
 
        _x += n;
241
 
        _penDown = !_penDown;             // inverse pen state
242
 
}
243
 
 
244
 
 
245
 
/** Inverts "paint color" (black to white or vice versa) of n pixels
246
 
 *  and advances the cursor by n. The number n of pixels is read from
247
 
 *  the input stream.
248
 
 *  @param[in] len size of n in bytes */
249
 
void GFReader::cmdPaint (int len) {
250
 
        UInt32 pixels = readUnsigned(len);
251
 
        cmdPaint0(pixels);
252
 
}
253
 
 
254
 
 
255
 
/** Beginning of character (generic format). */
256
 
void GFReader::cmdBoc (int) {
257
 
        _currentChar = readSigned(4);
258
 
        readSigned(4);  // pointer to previous boc with same c mod 256
259
 
        _minX = readSigned(4);
260
 
        _maxX = readSigned(4);
261
 
        _minY = readSigned(4);
262
 
        _maxY = readSigned(4);
263
 
        _x = _minX;
264
 
        _y = _maxY;
265
 
        _penDown = false;
266
 
        _bitmap.resize(_minX, _maxX, _minY, _maxY);
267
 
        beginChar(_currentChar);
268
 
}
269
 
 
270
 
 
271
 
/** Beginning of character (compact format). */
272
 
void GFReader::cmdBoc1 (int) {
273
 
        _currentChar = readUnsigned(1);
274
 
        UInt32 dx = readUnsigned(1);
275
 
        _maxX = readUnsigned(1);
276
 
        _minX = _maxX - dx;
277
 
        UInt32 dy = readUnsigned(1);
278
 
        _maxY = readUnsigned(1);
279
 
        _minY = _maxY - dy;
280
 
        _x = _minX;
281
 
        _y = _maxY;
282
 
        _penDown = false;
283
 
        _bitmap.resize(_minX, _maxX, _minY, _maxY);
284
 
        beginChar(_currentChar);
285
 
}
286
 
 
287
 
 
288
 
/** End of character. */
289
 
void GFReader::cmdEoc (int) {
290
 
        endChar(_currentChar);
291
 
}
292
 
 
293
 
 
294
 
/** Moves cursor to the beginning of a following row and sets
295
 
 *  paint color to white.
296
 
 *  @param[in] len if 0: move to next row, otherwise: number of bytes to read.
297
 
 *                 The read value denotes the number of rows to be skipped.  */
298
 
void GFReader::cmdSkip (int len) {
299
 
        if (len == 0)
300
 
                _y--;
301
 
        else
302
 
                _y -= readUnsigned(len)+1;
303
 
        _x = _minX;
304
 
        _penDown = false;
305
 
}
306
 
 
307
 
 
308
 
/** Moves cursor to pixel number 'col' in the next row and sets
309
 
 *  the paint color to black.
310
 
 *  @param[in] col pixel/column number */
311
 
void GFReader::cmdNewRow (int col) {
312
 
        _x = _minX + col ;
313
 
        _y--;
314
 
        _penDown = true;
315
 
}
316
 
 
317
 
 
318
 
void GFReader::cmdXXX (int len) {
319
 
        UInt32 n = readUnsigned(len);
320
 
        string str = readString(n);
321
 
        special(str);
322
 
}
323
 
 
324
 
 
325
 
void GFReader::cmdYYY (int) {
326
 
        Int32 y = readSigned(4);
327
 
        numspecial(y);
328
 
}
329
 
 
330
 
 
331
 
/** Does nothing. */
332
 
void GFReader::cmdNop (int) {
333
 
}
334
 
 
335
 
 
336
 
/** Reads character locator (part of postamble) */
337
 
void GFReader::cmdCharLoc0 (int) {
338
 
        UInt8 c  = readUnsigned(1); // character code mod 256
339
 
        UInt8 dm = readUnsigned(1); //
340
 
        Int32 w  = readSigned(4);   // (1<<24)*characterWidth/designSize
341
 
        Int32 p   = readSigned(4);  // pointer to begin of (last) character data
342
 
        Int32 dx  = 65536*dm;
343
 
        Int32 dy  = 0;
344
 
        _charInfoMap[c] = CharInfo(dx, dy, w, p);
345
 
}
346
 
 
347
 
 
348
 
/** Reads character locator (part of postamble) */
349
 
void GFReader::cmdCharLoc (int) {
350
 
        UInt32 c = readUnsigned(1); // character code mod 256
351
 
        Int32 dx = readSigned(4);   // horizontal escapement (scaled pixel units)
352
 
        Int32 dy = readSigned(4);   // vertical escapement (scaled pixel units)
353
 
        Int32 w  = readSigned(4);   // (1<<24)*characterWidth/designSize
354
 
        Int32 p  = readSigned(4);   // pointer to begin of (last) character data
355
 
        _charInfoMap[c] = CharInfo(dx, dy, w, p);
356
 
}
357