compile
[kdegraphics.git] / okular / generators / dvi / dviRenderer_prescan.cpp
blobc8a6ecfb3bbb44f4575af097311d369b3e906468
1 // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; c-brace-offset: 0; -*-
2 // dviRenderer_prescan.cpp
3 //
4 // Part of KDVI - A DVI previewer for the KDE desktop environment
5 //
6 // (C) 2003--2004 Stefan Kebekus
7 // Distributed under the GPL
9 #include <config.h>
11 #include "dviRenderer.h"
12 #include "dvi.h"
13 #include "dviFile.h"
14 #include "kvs_debug.h"
15 #include "prebookmark.h"
16 #include "psgs.h"
17 #include "TeXFont.h"
19 #include <klocale.h>
20 #include <kmessagebox.h>
21 #include <kmimetype.h>
22 #include <kprocess.h>
24 #include <Q3MemArray>
25 #include <QApplication>
26 #include <QDir>
27 #include <QFileInfo>
28 #include <QImage>
29 #include <QPaintDevice>
30 #include <QProgressBar>
31 #include <QTextStream>
34 extern QPainter foreGroundPaint;
35 extern void parse_special_argument(const QString& strg, const char* argument_name, int* variable);
38 //#define DEBUG_PRESCAN
41 void dviRenderer::prescan_embedPS(char *cp, quint8 *beginningOfSpecialCommand)
43 #ifdef DEBUG_PRESCAN
44 kDebug(kvs::dvi) << "dviRenderer::prescan_embedPS( cp = " << cp << " ) ";
45 #endif
47 // Encapsulated Postscript File
48 if (strncasecmp(cp, "PSfile=", 7) != 0)
49 return;
51 QString command(cp+7);
53 QString include_command = command.simplified();
55 // The line is supposed to start with "..ile=", and then comes the
56 // filename. Figure out what the filename is and stow it away. Of
57 // course, this does not work if the filename contains spaces
58 // (already the simplified() above is wrong). If you have
59 // files like this, go away.
60 QString EPSfilename = include_command;
61 EPSfilename.truncate(EPSfilename.indexOf(' '));
63 // Strip enclosing quotation marks which are included by some LaTeX
64 // macro packages (but not by others). This probably means that
65 // graphic files are no longer found if the filename really does
66 // contain quotes, but we don't really care that much.
67 if ((EPSfilename.at(0) == '\"') && (EPSfilename.at(EPSfilename.length()-1) == '\"'))
68 EPSfilename = EPSfilename.mid(1,EPSfilename.length()-2);
70 // Now locate the Gfx file on the hard disk...
71 EPSfilename = ghostscript_interface::locateEPSfile(EPSfilename, baseURL);
73 // If the file is neither a PostScript not a PDF file, we exit here.
74 // The graphic file is later read when the page is rendered.
75 KMimeType::Ptr const mime_type =
76 KMimeType::findByFileContent(EPSfilename);
77 QString const & mime_type_name = mime_type?mime_type->name():"";
79 bool const is_ps_file = (mime_type_name == "application/postscript" ||
80 mime_type_name == "image/x-eps");
81 bool const is_pdf_file = (!is_ps_file &&
82 mime_type_name == "application/pdf");
83 if (!(is_ps_file || is_pdf_file))
84 return;
86 QString originalFName = EPSfilename;
88 embedPS_progress->setLabelText(i18n("Embedding %1", EPSfilename));
89 qApp->processEvents();
91 // If the EPSfilename really points to a PDF file, convert that file now.
92 if (is_pdf_file)
93 EPSfilename = dviFile->convertPDFtoPS(EPSfilename);
95 if (!QFile::exists(EPSfilename)) {
96 // Find the number of the page
97 quint32 currentOffset = beginningOfSpecialCommand - dviFile->dvi_Data();
98 int page=0;
99 for(; page < dviFile->total_pages; page++)
100 if ((dviFile->page_offset[page] <= currentOffset) && (currentOffset <= dviFile->page_offset[page+1]))
101 break;
102 if (is_pdf_file)
103 errorMsg += i18n("Page %1: The PDF file <strong>%2</strong> could not be converted to PostScript.<br>", page+1, originalFName);
104 else
105 errorMsg += i18n("Page %1: The PostScript file <strong>%2</strong> could not be found.<br>", page+1, originalFName);
106 embedPS_progress->progressBar()->setValue(embedPS_progress->progressBar()->value()+1);
107 qApp->processEvents();
108 return;
111 // Now parse the arguments.
112 int llx = 0;
113 int lly = 0;
114 int urx = 0;
115 int ury = 0;
116 int rwi = 0;
117 int rhi = 0;
118 int angle = 0;
120 // just to avoid ambiguities; the filename could contain keywords
121 include_command = include_command.mid(include_command.indexOf(' '));
123 parse_special_argument(include_command, "llx=", &llx);
124 parse_special_argument(include_command, "lly=", &lly);
125 parse_special_argument(include_command, "urx=", &urx);
126 parse_special_argument(include_command, "ury=", &ury);
127 parse_special_argument(include_command, "rwi=", &rwi);
128 parse_special_argument(include_command, "rhi=", &rhi);
129 parse_special_argument(include_command, "angle=", &angle);
131 int clip=include_command.indexOf(" clip"); // -1 if clip keyword is not present, >= 0 otherwise
133 // Generate the PostScript commands to be included
134 QString PS = QString("ps: @beginspecial %1 @llx %2 @lly %3 @urx %4 @ury").arg(llx).arg(lly).arg(urx).arg(ury);
135 if (rwi != 0)
136 PS.append( QString(" %1 @rwi").arg(rwi) );
137 if (rhi != 0)
138 PS.append( QString(" %1 @rhi").arg(rhi) );
139 if (angle != 0)
140 PS.append( QString(" %1 @angle").arg(angle) );
141 if (clip != -1)
142 PS.append(" @clip");
143 PS.append( " @setspecial\n" );
145 QFile file( EPSfilename );
146 if ( file.open( QIODevice::ReadOnly ) ) {
147 QTextStream stream( &file );
148 while ( !stream.atEnd() ) {
149 PS += stream.readLine().section( '%', 0, 0);
150 PS += '\n';
152 file.close();
154 PS.append( "@endspecial" );
155 PS = PS.simplified();
158 _isModified = true;
159 quint32 lengthOfOldSpecial = command_pointer - beginningOfSpecialCommand;
160 quint32 lengthOfNewSpecial = PS.length()+5;
162 Q3MemArray<quint8> newDVI(dviFile->size_of_file + lengthOfNewSpecial-lengthOfOldSpecial);
164 quint8 *commandPtrSav = command_pointer;
165 quint8 *endPtrSav = end_pointer;
166 end_pointer = newDVI.data() + dviFile->size_of_file + lengthOfNewSpecial-lengthOfOldSpecial;
167 memcpy(newDVI.data(), dviFile->dvi_Data(), beginningOfSpecialCommand-dviFile->dvi_Data());
168 command_pointer = newDVI.data()+(beginningOfSpecialCommand-dviFile->dvi_Data());
169 command_pointer[0] = XXX4;
170 command_pointer++;
171 writeUINT32(PS.length());
172 memcpy(newDVI.data()+(beginningOfSpecialCommand-dviFile->dvi_Data())+5, PS.toLatin1(), PS.length() );
173 memcpy(newDVI.data()+(beginningOfSpecialCommand-dviFile->dvi_Data())+lengthOfNewSpecial, beginningOfSpecialCommand+lengthOfOldSpecial,
174 dviFile->size_of_file-(beginningOfSpecialCommand-dviFile->dvi_Data())-lengthOfOldSpecial );
176 // Adjust page pointers in the DVI file
177 dviFile->size_of_file = dviFile->size_of_file + lengthOfNewSpecial-lengthOfOldSpecial;
178 end_pointer = newDVI.data() + dviFile->size_of_file;
179 quint32 currentOffset = beginningOfSpecialCommand-dviFile->dvi_Data();
180 for(int i=0; i < dviFile->total_pages; i++) {
181 if (dviFile->page_offset[i] > currentOffset) {
182 dviFile->page_offset[i] = dviFile->page_offset[i] + lengthOfNewSpecial-lengthOfOldSpecial;
183 command_pointer = dviFile->page_offset[i] + newDVI.data() + 4*10 + 1;
184 quint32 a = readUINT32();
185 if (a > currentOffset) {
186 a = a + lengthOfNewSpecial-lengthOfOldSpecial;
187 command_pointer = dviFile->page_offset[i] + newDVI.data() + 4*10 + 1;
188 writeUINT32(a);
193 dviFile->beginning_of_postamble = dviFile->beginning_of_postamble + lengthOfNewSpecial - lengthOfOldSpecial;
194 dviFile->page_offset[int(dviFile->total_pages)] = dviFile->beginning_of_postamble;
196 command_pointer = newDVI.data() + dviFile->beginning_of_postamble + 1;
197 quint32 a = readUINT32();
198 if (a > currentOffset) {
199 a = a + lengthOfNewSpecial - lengthOfOldSpecial;
200 command_pointer = newDVI.data() + dviFile->beginning_of_postamble + 1;
201 writeUINT32(a);
204 command_pointer = newDVI.data() + dviFile->size_of_file - 1;
205 while((*command_pointer == TRAILER) && (command_pointer > newDVI.data()))
206 command_pointer--;
207 command_pointer -= 4;
208 writeUINT32(dviFile->beginning_of_postamble);
209 command_pointer -= 4;
211 command_pointer = commandPtrSav;
212 end_pointer = endPtrSav;
214 // Modify all pointers to point to the newly allocated memory
215 command_pointer = newDVI.data() + (command_pointer - dviFile->dvi_Data()) + lengthOfNewSpecial-lengthOfOldSpecial;
216 end_pointer = newDVI.data() + (end_pointer - dviFile->dvi_Data()) + lengthOfNewSpecial-lengthOfOldSpecial;
218 dviFile->setNewData(newDVI);
220 embedPS_progress->progressBar()->setValue(embedPS_progress->progressBar()->value()+1);
221 qApp->processEvents();
222 return;
226 void dviRenderer::prescan_removePageSizeInfo(char *cp, quint8 *beginningOfSpecialCommand)
228 #ifdef DEBUG_PRESCAN
229 kDebug(kvs::dvi) << "dviRenderer::prescan_embedPS( cp = " << cp << " ) ";
230 #endif
232 // Encapsulated Postscript File
233 if (strncasecmp(cp, "papersize=", 10) != 0)
234 return;
236 for (quint8 *ptr=beginningOfSpecialCommand; ptr<command_pointer; ptr++)
237 *ptr = NOP;
241 void dviRenderer::prescan_ParsePapersizeSpecial(const QString& _cp)
243 #ifdef DEBUG_PRESCAN
244 kDebug(kvs::dvi) << "Papersize-Special : papersize" << _cp;
245 #endif
247 QString cp = _cp.simplified();
249 if (cp[0] == '=') {
250 cp = cp.mid(1);
251 dviFile->suggestedPageSize = new pageSize;
252 dviFile->suggestedPageSize->setPageSize(cp);
253 } else
254 printErrorMsgForSpecials(i18n("The papersize data '%1' could not be parsed.", cp));
256 return;
260 void dviRenderer::prescan_ParseBackgroundSpecial(const QString& cp)
262 QColor col = parseColorSpecification(cp.trimmed());
263 if (col.isValid())
264 for(quint16 page=current_page; page < dviFile->total_pages; page++)
265 PS_interface->setBackgroundColor(page, col);
266 return;
270 void dviRenderer::prescan_ParseHTMLAnchorSpecial(const QString& _cp)
272 QString cp = _cp;
273 cp.truncate(cp.indexOf('"'));
274 Length l;
275 l.setLength_in_inch(currinf.data.dvi_v/(resolutionInDPI*shrinkfactor));
276 anchorList[cp] = Anchor(current_page+1, l);
280 void dviRenderer::prescan_ParsePSHeaderSpecial(const QString& cp)
282 #ifdef DEBUG_PRESCAN
283 kDebug(kvs::dvi) << "PostScript-special, header " << cp.latin1();
284 #endif
286 QString _file = cp;
288 // If the file is not found in the current directory, use kpsewhich
289 // to find it.
290 if (!QFile::exists(_file)) {
291 // Otherwise, use kpsewhich to find the eps file.
292 KProcess proc;
293 proc << "kpsewhich" << cp;
294 proc.setOutputChannelMode(KProcess::SeparateChannels);
295 proc.execute();
296 _file = QString::fromLocal8Bit(proc.readLine().trimmed());
299 if (QFile::exists(_file))
300 PS_interface->PostScriptHeaderString->append( QString(" (%1) run\n").arg(_file) );
304 void dviRenderer::prescan_ParsePSBangSpecial(const QString& cp)
306 #ifdef DEBUG_PRESCAN
307 kDebug(kvs::dvi) << "PostScript-special, literal header " << cp.latin1();
308 #endif
310 PS_interface->PostScriptHeaderString->append( " @defspecial \n" );
311 PS_interface->PostScriptHeaderString->append( cp );
312 PS_interface->PostScriptHeaderString->append( " @fedspecial \n" );
316 void dviRenderer::prescan_ParsePSQuoteSpecial(const QString& cp)
318 #ifdef DEBUG_PRESCAN
319 kError(kvs::dvi) << "PostScript-special, literal PostScript " << cp.latin1() << endl;
320 #endif
322 double PS_H = (currinf.data.dvi_h*300.0)/(65536*1200)-300;
323 double PS_V = (currinf.data.dvi_v*300.0)/1200 - 300;
324 PostScriptOutPutString->append( QString(" %1 %2 moveto\n").arg(PS_H).arg(PS_V) );
325 PostScriptOutPutString->append( " @beginspecial @setspecial \n" );
326 PostScriptOutPutString->append( cp );
327 PostScriptOutPutString->append( " @endspecial \n" );
331 void dviRenderer::prescan_ParsePSSpecial(const QString& cp)
333 #ifdef DEBUG_PRESCAN
334 kDebug(kvs::dvi) << "PostScript-special, direct PostScript " << cp;
335 #endif
337 // Unfortunately, in some TeX distribution the hyperref package uses
338 // the dvips driver by default, rather than the hypertex driver. As
339 // a result, the DVI files produced are full of PostScript that
340 // specifies links and anchors, and KDVI would call the ghostscript
341 // interpreter for every page which makes it really slow. This is a
342 // major nuisance, so that we try to filter and interpret the
343 // hypertex generated PostScript here.
344 if (cp.startsWith("ps:SDict begin")) {
345 // We suspect this may be hyperref generated nonsense. Let's check
346 // for some known code that hyperref generates.
347 if (cp == "ps:SDict begin H.S end")
348 return; // start of hyperref rectangle
349 if (cp == "ps:SDict begin H.R end")
350 return; // end of hyperref rectangle
351 if (cp.endsWith("H.A end"))
352 return; // end of hyperref anchor
353 if (cp.endsWith("H.L end"))
354 return; // end of hyperref link
355 if (cp.startsWith("ps:SDict begin /product where{pop product(Distiller)"))
356 return; // hyperref tries to work around Distiller bug
357 if (cp.startsWith("ps:SDict begin [") && cp.endsWith(" pdfmark end")) { // hyperref definition of link/anchor/bookmark/etc
358 if (cp.contains("/DEST")) { // The PostScript code defines an anchor
359 QString anchorName = cp.section('(', 1, 1).section(')', 0, 0);
360 Length l;
361 l.setLength_in_inch(currinf.data.dvi_v/(resolutionInDPI*shrinkfactor));
362 anchorList[anchorName] = Anchor(current_page+1, l);
364 // The PostScript code defines a bookmark
365 if (cp.contains("/Dest") && cp.contains("/Title"))
366 prebookmarks.append(PreBookmark(PDFencodingToQString(cp.section('(', 2, 2).section(')', 0, 0)),
367 cp.section('(', 1, 1).section(')', 0, 0),
368 cp.section('-', 1, 1).section(' ', 0, 0).toUInt()
370 return;
374 double PS_H = (currinf.data.dvi_h*300.0)/(65536*1200)-300;
375 double PS_V = (currinf.data.dvi_v*300.0)/1200 - 300;
377 if (cp.indexOf("ps::[begin]", 0, Qt::CaseInsensitive) == 0) {
378 PostScriptOutPutString->append( QString(" %1 %2 moveto\n").arg(PS_H).arg(PS_V) );
379 PostScriptOutPutString->append( QString(" %1\n").arg(cp.mid(11)) );
380 } else {
381 if (cp.indexOf("ps::[end]", 0, Qt::CaseInsensitive) == 0) {
382 PostScriptOutPutString->append( QString(" %1\n").arg(cp.mid(9)) );
383 } else {
384 if (cp.indexOf("ps::", 0, Qt::CaseInsensitive) == 0) {
385 PostScriptOutPutString->append( QString(" %1\n").arg(cp.mid(4)) );
386 } else {
387 PostScriptOutPutString->append( QString(" %1 %2 moveto\n").arg(PS_H).arg(PS_V) );
388 PostScriptOutPutString->append( QString(" %1\n").arg(cp.mid(3)) );
395 void dviRenderer::prescan_ParsePSFileSpecial(const QString& cp)
397 #ifdef DEBUG_PRESCAN
398 kDebug(kvs::dvi) << "epsf-special: psfile=" << cp;
399 #endif
401 QString include_command = cp.simplified();
403 // The line is supposed to start with "..ile=", and then comes the
404 // filename. Figure out what the filename is and stow it away. Of
405 // course, this does not work if the filename contains spaces
406 // (already the simplified() above is wrong). If you have
407 // files like this, go away.
408 QString EPSfilename = include_command;
409 EPSfilename.truncate(EPSfilename.indexOf(' '));
411 // Strip enclosing quotation marks which are included by some LaTeX
412 // macro packages (but not by others). This probably means that
413 // graphic files are no longer found if the filename really does
414 // contain quotes, but we don't really care that much.
415 if ((EPSfilename.at(0) == '\"') && (EPSfilename.at(EPSfilename.length()-1) == '\"')) {
416 EPSfilename = EPSfilename.mid(1,EPSfilename.length()-2);
419 // If the file name ends in 'png', 'gif', 'jpg' or 'jpeg', we assume
420 // that this is NOT a PostScript file, and we exit here.
421 QString ending = EPSfilename.section('.', -1).toLower();
422 if ((ending == "png") || (ending == "gif") || (ending == "jpg") || (ending == "jpeg")) {
423 dviFile->numberOfExternalNONPSFiles++;
424 return;
427 // Now assume that the graphics file *is* a PostScript file
428 dviFile->numberOfExternalPSFiles++;
430 // Now locate the Gfx file on the hard disk...
431 EPSfilename = ghostscript_interface::locateEPSfile(EPSfilename, baseURL);
433 // If the EPSfilename really points to a PDF file, convert that file now.
434 if (ending == "pdf") {
435 QString convErrorMsg;
436 QString oEPSfilename = EPSfilename;
437 //emit setStatusBarText( i18n("Converting PDF-file %1...", EPSfilename) );
438 EPSfilename = dviFile->convertPDFtoPS(EPSfilename, &convErrorMsg);
439 //emit setStatusBarText( QString::null ); //krazy:exclude=nullstrassign for old broken gcc
440 if (convErrorMsg.isEmpty() != true) {
441 /* KMessageBox::detailedError(parentWidget,
442 i18n("<qt><strong>File conversion error</strong> KDVI was not able to convert the external "
443 "PDF file <strong>%1</strong> into PostScript. Expect missing graphics or graphic errors.</qt>", oEPSfilename),
444 convErrorMsg, i18n("PDF/PS conversion error"));*/
445 return;
449 // Now parse the arguments.
450 int llx = 0;
451 int lly = 0;
452 int urx = 0;
453 int ury = 0;
454 int rwi = 0;
455 int rhi = 0;
456 int angle = 0;
458 // just to avoid ambiguities; the filename could contain keywords
459 include_command = include_command.mid(include_command.indexOf(' '));
461 parse_special_argument(include_command, "llx=", &llx);
462 parse_special_argument(include_command, "lly=", &lly);
463 parse_special_argument(include_command, "urx=", &urx);
464 parse_special_argument(include_command, "ury=", &ury);
465 parse_special_argument(include_command, "rwi=", &rwi);
466 parse_special_argument(include_command, "rhi=", &rhi);
467 parse_special_argument(include_command, "angle=", &angle);
469 int clip=include_command.indexOf(" clip"); // -1 if clip keyword is not present, >= 0 otherwise
471 if (QFile::exists(EPSfilename)) {
472 double PS_H = (currinf.data.dvi_h*300.0)/(65536*1200)-300;
473 double PS_V = (currinf.data.dvi_v*300.0)/1200 - 300;
474 PostScriptOutPutString->append( QString(" %1 %2 moveto\n").arg(PS_H).arg(PS_V) );
475 PostScriptOutPutString->append( "@beginspecial " );
476 PostScriptOutPutString->append( QString(" %1 @llx").arg(llx) );
477 PostScriptOutPutString->append( QString(" %1 @lly").arg(lly) );
478 PostScriptOutPutString->append( QString(" %1 @urx").arg(urx) );
479 PostScriptOutPutString->append( QString(" %1 @ury").arg(ury) );
480 if (rwi != 0)
481 PostScriptOutPutString->append( QString(" %1 @rwi").arg(rwi) );
482 if (rhi != 0)
483 PostScriptOutPutString->append( QString(" %1 @rhi").arg(rhi) );
484 if (angle != 0)
485 PostScriptOutPutString->append( QString(" %1 @angle").arg(angle) );
486 if (clip != -1)
487 PostScriptOutPutString->append(" @clip");
488 PostScriptOutPutString->append( " @setspecial \n" );
489 PostScriptOutPutString->append( QString(" (%1) run\n").arg(EPSfilename) );
490 PostScriptOutPutString->append( "@endspecial \n" );
493 return;
497 void dviRenderer::prescan_ParseSourceSpecial(const QString& cp)
499 // if no rendering takes place, i.e. when the DVI file is first
500 // loaded, generate a DVI_SourceFileAnchor. These anchors are used
501 // in forward search, i.e. to relate references line
502 // "src:123file.tex" to positions in the DVI file
504 // extract the file name and the numeral part from the string
505 qint32 j;
506 for(j=0;j<cp.length();j++)
507 if (!cp.at(j).isNumber())
508 break;
509 quint32 sourceLineNumber = cp.left(j).toUInt();
510 QFileInfo fi1(dviFile->filename);
511 QString sourceFileName = QFileInfo(fi1.dir(), cp.mid(j).trimmed()).absoluteFilePath();
512 Length l;
513 l.setLength_in_inch(currinf.data.dvi_v/(resolutionInDPI*shrinkfactor));
514 DVI_SourceFileAnchor sfa(sourceFileName, sourceLineNumber, current_page+1, l);
515 sourceHyperLinkAnchors.push_back(sfa);
519 void dviRenderer::prescan_parseSpecials(char *cp, quint8 *)
521 QString special_command(cp);
523 // Now to those specials which are only interpreted during the
524 // prescan phase, and NOT during rendering.
526 // PaperSize special
527 if (strncasecmp(cp, "papersize", 9) == 0) {
528 prescan_ParsePapersizeSpecial(special_command.mid(9));
529 return;
532 // color special for background color
533 if (strncasecmp(cp, "background", 10) == 0) {
534 prescan_ParseBackgroundSpecial(special_command.mid(10));
535 return;
538 // HTML anchor special
539 if (strncasecmp(cp, "html:<A name=", 13) == 0) {
540 prescan_ParseHTMLAnchorSpecial(special_command.mid(14));
541 return;
544 // Postscript Header File
545 if (strncasecmp(cp, "header=", 7) == 0) {
546 prescan_ParsePSHeaderSpecial(special_command.mid(7));
547 return;
550 // Literal Postscript Header
551 if (cp[0] == '!') {
552 prescan_ParsePSBangSpecial(special_command.mid(1));
553 return;
556 // Literal Postscript inclusion
557 if (cp[0] == '"') {
558 prescan_ParsePSQuoteSpecial(special_command.mid(1));
559 return;
562 // PS-Postscript inclusion
563 if (strncasecmp(cp, "ps:", 3) == 0) {
564 prescan_ParsePSSpecial(special_command);
565 return;
568 // Encapsulated Postscript File
569 if (strncasecmp(cp, "PSfile=", 7) == 0) {
570 prescan_ParsePSFileSpecial(special_command.mid(7));
571 return;
574 // source special
575 if (strncasecmp(cp, "src:", 4) == 0) {
576 prescan_ParseSourceSpecial(special_command.mid(4));
577 return;
580 // Finally there are those special commands which must be considered
581 // both during rendering and during the pre-scan phase
583 // HTML anchor end
584 if (strncasecmp(cp, "html:</A>", 9) == 0) {
585 html_anchor_end();
586 return;
589 return;
593 void dviRenderer::prescan_setChar(unsigned int ch)
595 TeXFontDefinition *fontp = currinf.fontp;
596 if (fontp == NULL)
597 return;
599 if (currinf.set_char_p == &dviRenderer::set_char) {
600 glyph *g = ((TeXFont *)(currinf.fontp->font))->getGlyph(ch, true, globalColor);
601 if (g == NULL)
602 return;
603 currinf.data.dvi_h += (int)(currinf.fontp->scaled_size_in_DVI_units * dviFile->getCmPerDVIunit() *
604 (1200.0 / 2.54)/16.0 * g->dvi_advance_in_units_of_design_size_by_2e20 + 0.5);
605 return;
608 if (currinf.set_char_p == &dviRenderer::set_vf_char) {
609 macro *m = &currinf.fontp->macrotable[ch];
610 if (m->pos == NULL)
611 return;
612 currinf.data.dvi_h += (int)(currinf.fontp->scaled_size_in_DVI_units * dviFile->getCmPerDVIunit() *
613 (1200.0 / 2.54)/16.0 * m->dvi_advance_in_units_of_design_size_by_2e20 + 0.5);
614 return;
619 void dviRenderer::prescan(parseSpecials specialParser)
621 #ifdef DEBUG_PRESCAN
622 kDebug(kvs::dvi) << "dviRenderer::prescan( ... )";
623 #endif
625 if (resolutionInDPI == 0.0)
626 setResolution(100);
628 qint32 RRtmp=0, WWtmp=0, XXtmp=0, YYtmp=0, ZZtmp=0;
629 quint8 ch;
630 double fontPixelPerDVIunit = dviFile->getCmPerDVIunit() * 1200.0/2.54;
632 stack.clear();
634 currinf.fontp = NULL;
635 currinf.set_char_p = &dviRenderer::set_no_char;
637 for (;;) {
638 ch = readUINT8();
640 if (ch <= (unsigned char) (SETCHAR0 + 127)) {
641 prescan_setChar(ch);
642 continue;
645 if (FNTNUM0 <= ch && ch <= (unsigned char) (FNTNUM0 + 63)) {
646 currinf.fontp = currinf.fonttable->find(ch - FNTNUM0);
647 if (currinf.fontp == NULL) {
648 errorMsg = i18n("The DVI code referred to font #%1, which was not previously defined.", ch - FNTNUM0);
649 return;
651 currinf.set_char_p = currinf.fontp->set_char_p;
652 continue;
656 qint32 a, b;
658 switch (ch) {
659 case SET1:
660 prescan_setChar(readUINT8());
661 break;
663 case SETRULE:
664 /* Be careful, dvicopy outputs rules with height =
665 0x80000000. We don't want any SIGFPE here. */
666 a = readUINT32();
667 b = readUINT32();
668 b = ((long) (b * 65536.0*fontPixelPerDVIunit));
669 currinf.data.dvi_h += b;
670 break;
672 case PUTRULE:
673 a = readUINT32();
674 b = readUINT32();
675 break;
677 case PUT1:
678 case NOP:
679 break;
681 case BOP:
682 command_pointer += 11 * 4;
683 currinf.data.dvi_h = 1200 << 16; // Reminder: DVI-coordinates start at (1",1") from top of page
684 currinf.data.dvi_v = 1200;
685 currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor);
686 currinf.data.w = currinf.data.x = currinf.data.y = currinf.data.z = 0;
687 break;
689 case PUSH:
690 stack.push(currinf.data);
691 break;
693 case POP:
694 if (stack.isEmpty())
695 return;
696 else
697 currinf.data = stack.pop();
698 break;
700 case RIGHT1:
701 case RIGHT2:
702 case RIGHT3:
703 case RIGHT4:
704 RRtmp = readINT(ch - RIGHT1 + 1);
705 currinf.data.dvi_h += ((long) (RRtmp * 65536.0*fontPixelPerDVIunit));
706 break;
708 case W1:
709 case W2:
710 case W3:
711 case W4:
712 WWtmp = readINT(ch - W0);
713 currinf.data.w = ((long) (WWtmp * 65536.0*fontPixelPerDVIunit));
714 case W0:
715 currinf.data.dvi_h += currinf.data.w;
716 break;
718 case X1:
719 case X2:
720 case X3:
721 case X4:
722 XXtmp = readINT(ch - X0);
723 currinf.data.x = ((long) (XXtmp * 65536.0*fontPixelPerDVIunit));
724 case X0:
725 currinf.data.dvi_h += currinf.data.x;
726 break;
728 case DOWN1:
729 case DOWN2:
730 case DOWN3:
731 case DOWN4:
733 qint32 DDtmp = readINT(ch - DOWN1 + 1);
734 currinf.data.dvi_v += ((long) (DDtmp * 65536.0*fontPixelPerDVIunit))/65536;
735 currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor);
737 break;
739 case Y1:
740 case Y2:
741 case Y3:
742 case Y4:
743 YYtmp = readINT(ch - Y0);
744 currinf.data.y = ((long) (YYtmp * 65536.0*fontPixelPerDVIunit));
745 case Y0:
746 currinf.data.dvi_v += currinf.data.y/65536;
747 currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor);
748 break;
750 case Z1:
751 case Z2:
752 case Z3:
753 case Z4:
754 ZZtmp = readINT(ch - Z0);
755 currinf.data.z = ((long) (ZZtmp * 65536.0*fontPixelPerDVIunit));
756 case Z0:
757 currinf.data.dvi_v += currinf.data.z/65536;
758 currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor);
759 break;
761 case FNT1:
762 case FNT2:
763 case FNT3:
764 case FNT4:
765 currinf.fontp = currinf.fonttable->find(readUINT(ch - FNT1 + 1));
766 if (currinf.fontp == NULL)
767 return;
768 currinf.set_char_p = currinf.fontp->set_char_p;
769 break;
771 case XXX1:
772 case XXX2:
773 case XXX3:
774 case XXX4:
776 quint8 *beginningOfSpecialCommand = command_pointer-1;
777 a = readUINT(ch - XXX1 + 1);
778 if (a > 0) {
779 char *cmd = new char[a+1];
780 strncpy(cmd, (char *)command_pointer, a);
781 command_pointer += a;
782 cmd[a] = '\0';
783 (this->*specialParser)(cmd, beginningOfSpecialCommand);
784 delete [] cmd;
787 break;
789 case FNTDEF1:
790 case FNTDEF2:
791 case FNTDEF3:
792 case FNTDEF4:
793 command_pointer += 12 + ch - FNTDEF1 + 1;
794 command_pointer += readUINT8() + readUINT8();
795 break;
797 default:
798 return;
799 } /* end switch */
800 } /* end for */