File indexing completed on 2024-05-12 04:33:56
0001 // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; c-brace-offset: 0; -*- 0002 /* 0003 * SPDX-FileCopyrightText: 1994 Paul Vojta. All rights reserved. 0004 * 0005 * SPDX-License-Identifier: BSD-2-Clause 0006 * 0007 * NOTE: 0008 * xdvi is based on prior work as noted in the modification history, below. 0009 */ 0010 0011 /* 0012 * DVI previewer for X. 0013 * 0014 * Eric Cooper, CMU, September 1985. 0015 * 0016 * Code derived from dvi-imagen.c. 0017 * 0018 * Modification history: 0019 * 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS. 0020 * 7/1988 Modified for X.11 --Mark Eichin, MIT 0021 * 12/1988 Added 'R' option, toolkit, magnifying glass 0022 * --Paul Vojta, UC Berkeley. 0023 * 2/1989 Added tpic support --Jeffrey Lee, U of Toronto 0024 * 4/1989 Modified for System V --Donald Richardson, Clarkson Univ. 0025 * 3/1990 Added VMS support --Scott Allendorf, U of Iowa 0026 * 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem 0027 * 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen 0028 * and Lee Hetherington, MIT 0029 * 4/1994 Added DPS support, bounding box 0030 * --Ricardo Telichevesky 0031 * and Luis Miguel Silveira, MIT RLE. 0032 */ 0033 0034 //#define DEBUG_RENDER 0 0035 0036 #include <config.h> 0037 0038 #include "debug_dvi.h" 0039 #include "dvi.h" 0040 #include "dviFile.h" 0041 #include "dviRenderer.h" 0042 #include "hyperlink.h" 0043 #include "psgs.h" 0044 //#include "renderedDviPagePixmap.h" 0045 #include "TeXFont.h" 0046 #include "textBox.h" 0047 #include "xdvi.h" 0048 0049 #include <KLocalizedString> 0050 0051 #include <QLoggingCategory> 0052 #include <QPainter> 0053 0054 /** Routine to print characters. */ 0055 0056 void dviRenderer::set_char(unsigned int cmd, unsigned int ch) 0057 { 0058 #ifdef DEBUG_RENDER 0059 qCDebug(OkularDviDebug) << "set_char #" << ch; 0060 #endif 0061 0062 glyph *g; 0063 if (colorStack.isEmpty()) { 0064 g = ((TeXFont *)(currinf.fontp->font))->getGlyph(ch, true, globalColor); 0065 } else { 0066 g = ((TeXFont *)(currinf.fontp->font))->getGlyph(ch, true, colorStack.top()); 0067 } 0068 if (g == nullptr) { 0069 return; 0070 } 0071 0072 long dvi_h_sav = currinf.data.dvi_h; 0073 0074 QImage pix = g->shrunkenCharacter; 0075 int x = ((int)((currinf.data.dvi_h) / (shrinkfactor * 65536))) - g->x2; 0076 int y = currinf.data.pxl_v - g->y2; 0077 0078 // Draw the character. 0079 foreGroundPainter->drawImage(x, y, pix); 0080 0081 // Are we drawing text for a hyperlink? And are hyperlinks 0082 // enabled? 0083 if (HTML_href != nullptr) { 0084 // Now set up a rectangle which is checked against every mouse 0085 // event. 0086 if (line_boundary_encountered == true) { 0087 // Set up hyperlink 0088 Hyperlink dhl; 0089 dhl.baseline = currinf.data.pxl_v; 0090 dhl.box.setRect(x, y, pix.width(), pix.height()); 0091 dhl.linkText = *HTML_href; 0092 currentlyDrawnPage->hyperLinkList.push_back(dhl); 0093 } else { 0094 QRect dshunion = currentlyDrawnPage->hyperLinkList[currentlyDrawnPage->hyperLinkList.size() - 1].box.united(QRect(x, y, pix.width(), pix.height())); 0095 currentlyDrawnPage->hyperLinkList[currentlyDrawnPage->hyperLinkList.size() - 1].box = dshunion; 0096 } 0097 } 0098 0099 // Are we drawing text for a source hyperlink? And are source 0100 // hyperlinks enabled? 0101 // If we are printing source hyperlinks are irrelevant, otherwise we 0102 // actually got a pointer to a RenderedDviPagePixmap. 0103 RenderedDviPagePixmap *currentDVIPage = dynamic_cast<RenderedDviPagePixmap *>(currentlyDrawnPage); 0104 if (source_href != nullptr && currentDVIPage) { 0105 // Now set up a rectangle which is checked against every mouse 0106 // event. 0107 if (line_boundary_encountered == true) { 0108 // Set up source hyperlinks 0109 Hyperlink dhl; 0110 dhl.baseline = currinf.data.pxl_v; 0111 dhl.box.setRect(x, y, pix.width(), pix.height()); 0112 if (source_href != nullptr) { 0113 dhl.linkText = *source_href; 0114 } else { 0115 dhl.linkText = QLatin1String(""); 0116 } 0117 currentDVIPage->sourceHyperLinkList.push_back(dhl); 0118 } else { 0119 QRect dshunion = currentDVIPage->sourceHyperLinkList[currentDVIPage->sourceHyperLinkList.size() - 1].box.united(QRect(x, y, pix.width(), pix.height())); 0120 currentDVIPage->sourceHyperLinkList[currentDVIPage->sourceHyperLinkList.size() - 1].box = dshunion; 0121 } 0122 } 0123 0124 // Code for DVI -> text functions (e.g. marking of text, full text 0125 // search, etc.). Set up the currentlyDrawnPage->textBoxList. 0126 TextBox link; 0127 link.box.setRect(x, y, pix.width(), pix.height()); 0128 link.text = QLatin1String(""); 0129 currentlyDrawnPage->textBoxList.push_back(link); 0130 0131 switch (ch) { 0132 case 0x0b: 0133 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QLatin1String("ff"); 0134 break; 0135 case 0x0c: 0136 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QLatin1String("fi"); 0137 break; 0138 case 0x0d: 0139 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QLatin1String("fl"); 0140 break; 0141 case 0x0e: 0142 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QLatin1String("ffi"); 0143 break; 0144 case 0x0f: 0145 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QLatin1String("ffl"); 0146 break; 0147 0148 case 0x7b: 0149 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QLatin1Char('-'); 0150 break; 0151 case 0x7c: 0152 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QLatin1String("---"); 0153 break; 0154 case 0x7d: 0155 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QLatin1String("\""); 0156 break; 0157 case 0x7e: 0158 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QLatin1Char('~'); 0159 break; 0160 case 0x7f: 0161 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QLatin1String("@@"); // @@@ check! 0162 break; 0163 0164 default: 0165 if ((ch >= 0x21) && (ch <= 0x7a)) { 0166 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QChar(ch); 0167 } else { 0168 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QLatin1Char('?'); 0169 } 0170 break; 0171 } 0172 0173 if (cmd == PUT1) { 0174 currinf.data.dvi_h = dvi_h_sav; 0175 } else { 0176 currinf.data.dvi_h += (int)(currinf.fontp->scaled_size_in_DVI_units * dviFile->getCmPerDVIunit() * (1200.0 / 2.54) / 16.0 * g->dvi_advance_in_units_of_design_size_by_2e20 + 0.5); 0177 } 0178 0179 word_boundary_encountered = false; 0180 line_boundary_encountered = false; 0181 } 0182 0183 void dviRenderer::set_empty_char(unsigned int, unsigned int) 0184 { 0185 return; 0186 } 0187 0188 void dviRenderer::set_vf_char(unsigned int cmd, unsigned int ch) 0189 { 0190 #ifdef DEBUG_RENDER 0191 qCDebug(OkularDviDebug) << "dviRenderer::set_vf_char( cmd=" << cmd << ", ch=" << ch << " )"; 0192 #endif 0193 0194 static unsigned char c; 0195 macro *m = &currinf.fontp->macrotable[ch]; 0196 if (m->pos == nullptr) { 0197 qCCritical(OkularDviDebug) << "Character " << ch << " not defined in font " << currinf.fontp->fontname; 0198 m->pos = m->end = &c; 0199 return; 0200 } 0201 0202 long dvi_h_sav = currinf.data.dvi_h; 0203 0204 struct drawinf oldinfo = currinf; 0205 currinf.data.w = 0; 0206 currinf.data.x = 0; 0207 currinf.data.y = 0; 0208 currinf.data.z = 0; 0209 0210 currinf.fonttable = &(currinf.fontp->vf_table); 0211 currinf._virtual = currinf.fontp; 0212 quint8 *command_ptr_sav = command_pointer; 0213 quint8 *end_ptr_sav = end_pointer; 0214 command_pointer = m->pos; 0215 end_pointer = m->end; 0216 draw_part(currinf.fontp->scaled_size_in_DVI_units * (dviFile->getCmPerDVIunit() * 1200.0 / 2.54) / 16.0, true); 0217 command_pointer = command_ptr_sav; 0218 end_pointer = end_ptr_sav; 0219 currinf = oldinfo; 0220 0221 if (cmd == PUT1) { 0222 currinf.data.dvi_h = dvi_h_sav; 0223 } else { 0224 currinf.data.dvi_h += (int)(currinf.fontp->scaled_size_in_DVI_units * dviFile->getCmPerDVIunit() * (1200.0 / 2.54) / 16.0 * m->dvi_advance_in_units_of_design_size_by_2e20 + 0.5); 0225 } 0226 } 0227 0228 void dviRenderer::set_no_char(unsigned int cmd, unsigned int ch) 0229 { 0230 #ifdef DEBUG_RENDER 0231 qCDebug(OkularDviDebug) << "dviRenderer::set_no_char( cmd=" << cmd << ", ch =" << ch << " )"; 0232 #endif 0233 0234 if (currinf._virtual) { 0235 currinf.fontp = currinf._virtual->first_font; 0236 if (currinf.fontp != nullptr) { 0237 currinf.set_char_p = currinf.fontp->set_char_p; 0238 (this->*currinf.set_char_p)(cmd, ch); 0239 return; 0240 } 0241 } 0242 0243 errorMsg = i18n("The DVI code set a character of an unknown font."); 0244 return; 0245 } 0246 0247 void dviRenderer::draw_part(double current_dimconv, bool is_vfmacro) 0248 { 0249 #ifdef DEBUG_RENDER 0250 qCDebug(OkularDviDebug) << "draw_part"; 0251 #endif 0252 0253 qint32 RRtmp = 0, WWtmp = 0, XXtmp = 0, YYtmp = 0, ZZtmp = 0; 0254 quint8 ch; 0255 0256 currinf.fontp = nullptr; 0257 currinf.set_char_p = &dviRenderer::set_no_char; 0258 0259 int last_space_index = 0; 0260 bool space_encountered = false; 0261 bool after_space = false; 0262 for (;;) { 0263 space_encountered = false; 0264 ch = readUINT8(); 0265 if (ch <= (unsigned char)(SETCHAR0 + 127)) { 0266 (this->*currinf.set_char_p)(ch, ch); 0267 } else if (FNTNUM0 <= ch && ch <= (unsigned char)(FNTNUM0 + 63)) { 0268 currinf.fontp = currinf.fonttable->value(ch - FNTNUM0); 0269 if (currinf.fontp == nullptr) { 0270 errorMsg = i18n("The DVI code referred to font #%1, which was not previously defined.", ch - FNTNUM0); 0271 return; 0272 } 0273 currinf.set_char_p = currinf.fontp->set_char_p; 0274 } else { 0275 qint32 a, b; 0276 0277 switch (ch) { 0278 case SET1: 0279 case PUT1: 0280 (this->*currinf.set_char_p)(ch, readUINT8()); 0281 break; 0282 0283 case SETRULE: 0284 if (is_vfmacro == false) { 0285 word_boundary_encountered = true; 0286 line_boundary_encountered = true; 0287 } 0288 /* Be careful, dvicopy outputs rules with height = 0289 0x80000000. We don't want any SIGFPE here. */ 0290 a = readUINT32(); 0291 b = readUINT32(); 0292 b = ((long)(b * current_dimconv)); 0293 if (a > 0 && b > 0) { 0294 int h = ((int)ROUNDUP(((long)(a * current_dimconv)), shrinkfactor * 65536)); 0295 int w = ((int)ROUNDUP(b, shrinkfactor * 65536)); 0296 0297 if (colorStack.isEmpty()) { 0298 foreGroundPainter->fillRect(((int)((currinf.data.dvi_h) / (shrinkfactor * 65536))), currinf.data.pxl_v - h + 1, w ? w : 1, h ? h : 1, globalColor); 0299 } else { 0300 foreGroundPainter->fillRect(((int)((currinf.data.dvi_h) / (shrinkfactor * 65536))), currinf.data.pxl_v - h + 1, w ? w : 1, h ? h : 1, colorStack.top()); 0301 } 0302 } 0303 currinf.data.dvi_h += b; 0304 break; 0305 0306 case PUTRULE: 0307 if (is_vfmacro == false) { 0308 word_boundary_encountered = true; 0309 line_boundary_encountered = true; 0310 } 0311 a = readUINT32(); 0312 b = readUINT32(); 0313 a = ((long)(a * current_dimconv)); 0314 b = ((long)(b * current_dimconv)); 0315 if (a > 0 && b > 0) { 0316 int h = ((int)ROUNDUP(a, shrinkfactor * 65536)); 0317 int w = ((int)ROUNDUP(b, shrinkfactor * 65536)); 0318 if (colorStack.isEmpty()) { 0319 foreGroundPainter->fillRect(((int)((currinf.data.dvi_h) / (shrinkfactor * 65536))), currinf.data.pxl_v - h + 1, w ? w : 1, h ? h : 1, globalColor); 0320 } else { 0321 foreGroundPainter->fillRect(((int)((currinf.data.dvi_h) / (shrinkfactor * 65536))), currinf.data.pxl_v - h + 1, w ? w : 1, h ? h : 1, colorStack.top()); 0322 } 0323 } 0324 break; 0325 0326 case NOP: 0327 break; 0328 0329 case BOP: 0330 if (is_vfmacro == false) { 0331 word_boundary_encountered = true; 0332 line_boundary_encountered = true; 0333 } 0334 command_pointer += 11 * 4; 0335 currinf.data.dvi_h = 1200 << 16; // Reminder: DVI-coordinates start at (1",1") from top of page 0336 currinf.data.dvi_v = 1200; 0337 currinf.data.pxl_v = int(currinf.data.dvi_v / shrinkfactor); 0338 currinf.data.w = currinf.data.x = currinf.data.y = currinf.data.z = 0; 0339 break; 0340 0341 case EOP: 0342 // Check if we are just at the end of a virtual font macro. 0343 if (is_vfmacro == false) { 0344 // This is really the end of a page, and not just the end 0345 // of a macro. Mark the end of the current word. 0346 word_boundary_encountered = true; 0347 line_boundary_encountered = true; 0348 // Sanity check for the dvi-file: The DVI-standard asserts 0349 // that at the end of a page, the stack should always be 0350 // empty. 0351 if (!stack.isEmpty()) { 0352 qCDebug(OkularDviDebug) << "DRAW: The stack was not empty when the EOP command was encountered."; 0353 errorMsg = i18n("The stack was not empty when the EOP command was encountered."); 0354 return; 0355 } 0356 } 0357 return; 0358 0359 case PUSH: 0360 stack.push(currinf.data); 0361 break; 0362 0363 case POP: 0364 if (stack.isEmpty()) { 0365 errorMsg = i18n("The stack was empty when a POP command was encountered."); 0366 return; 0367 } else { 0368 currinf.data = stack.pop(); 0369 } 0370 word_boundary_encountered = true; 0371 line_boundary_encountered = true; 0372 break; 0373 0374 case RIGHT1: 0375 case RIGHT2: 0376 case RIGHT3: 0377 case RIGHT4: 0378 RRtmp = readINT(ch - RIGHT1 + 1); 0379 0380 // A horizontal motion in the range 4 * font space [f] < h < 0381 // font space [f] will be treated as a kern that is not 0382 // indicated in the printouts that DVItype produces between 0383 // brackets. We allow a larger space in the negative 0384 // direction than in the positive one, because TEX makes 0385 // comparatively large backspaces when it positions 0386 // accents. (comments stolen from the source of dvitype) 0387 if ((is_vfmacro == false) && (currinf.fontp != nullptr) && ((RRtmp >= currinf.fontp->scaled_size_in_DVI_units / 6) || (RRtmp <= -4 * (currinf.fontp->scaled_size_in_DVI_units / 6))) && 0388 (currentlyDrawnPage->textBoxList.size() > 0)) { 0389 // currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += ' '; 0390 space_encountered = true; 0391 } 0392 currinf.data.dvi_h += ((long)(RRtmp * current_dimconv)); 0393 break; 0394 0395 case W1: 0396 case W2: 0397 case W3: 0398 case W4: 0399 WWtmp = readINT(ch - W0); 0400 currinf.data.w = ((long)(WWtmp * current_dimconv)); 0401 // fallthrough 0402 case W0: 0403 if ((is_vfmacro == false) && (currinf.fontp != nullptr) && ((WWtmp >= currinf.fontp->scaled_size_in_DVI_units / 6) || (WWtmp <= -4 * (currinf.fontp->scaled_size_in_DVI_units / 6))) && 0404 (currentlyDrawnPage->textBoxList.size() > 0)) { 0405 // currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += ' '; 0406 space_encountered = true; 0407 } 0408 currinf.data.dvi_h += currinf.data.w; 0409 break; 0410 0411 case X1: 0412 case X2: 0413 case X3: 0414 case X4: 0415 XXtmp = readINT(ch - X0); 0416 currinf.data.x = ((long)(XXtmp * current_dimconv)); 0417 // fallthrough 0418 case X0: 0419 if ((is_vfmacro == false) && (currinf.fontp != nullptr) && ((XXtmp >= currinf.fontp->scaled_size_in_DVI_units / 6) || (XXtmp <= -4 * (currinf.fontp->scaled_size_in_DVI_units / 6))) && 0420 (currentlyDrawnPage->textBoxList.size() > 0)) { 0421 // currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += ' '; 0422 space_encountered = true; 0423 } 0424 currinf.data.dvi_h += currinf.data.x; 0425 break; 0426 0427 case DOWN1: 0428 case DOWN2: 0429 case DOWN3: 0430 case DOWN4: { 0431 qint32 DDtmp = readINT(ch - DOWN1 + 1); 0432 if ((is_vfmacro == false) && (currinf.fontp != nullptr) && (abs(DDtmp) >= 5 * (currinf.fontp->scaled_size_in_DVI_units / 6)) && (currentlyDrawnPage->textBoxList.size() > 0)) { 0433 word_boundary_encountered = true; 0434 line_boundary_encountered = true; 0435 space_encountered = true; 0436 if (abs(DDtmp) >= 10 * (currinf.fontp->scaled_size_in_DVI_units / 6)) { 0437 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QLatin1Char('\n'); 0438 } 0439 } 0440 currinf.data.dvi_v += ((long)(DDtmp * current_dimconv)) / 65536; 0441 currinf.data.pxl_v = int(currinf.data.dvi_v / shrinkfactor); 0442 } break; 0443 0444 case Y1: 0445 case Y2: 0446 case Y3: 0447 case Y4: 0448 YYtmp = readINT(ch - Y0); 0449 currinf.data.y = ((long)(YYtmp * current_dimconv)); 0450 // fallthrough 0451 case Y0: 0452 if ((is_vfmacro == false) && (currinf.fontp != nullptr) && (abs(YYtmp) >= 5 * (currinf.fontp->scaled_size_in_DVI_units / 6)) && (currentlyDrawnPage->textBoxList.size() > 0)) { 0453 word_boundary_encountered = true; 0454 line_boundary_encountered = true; 0455 space_encountered = true; 0456 if (abs(YYtmp) >= 10 * (currinf.fontp->scaled_size_in_DVI_units / 6)) { 0457 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QLatin1Char('\n'); 0458 } 0459 } 0460 currinf.data.dvi_v += currinf.data.y / 65536; 0461 currinf.data.pxl_v = int(currinf.data.dvi_v / shrinkfactor); 0462 break; 0463 0464 case Z1: 0465 case Z2: 0466 case Z3: 0467 case Z4: 0468 ZZtmp = readINT(ch - Z0); 0469 currinf.data.z = ((long)(ZZtmp * current_dimconv)); 0470 // fallthrough 0471 case Z0: 0472 if ((is_vfmacro == false) && (currinf.fontp != nullptr) && (abs(ZZtmp) >= 5 * (currinf.fontp->scaled_size_in_DVI_units / 6)) && (currentlyDrawnPage->textBoxList.size() > 0)) { 0473 word_boundary_encountered = true; 0474 line_boundary_encountered = true; 0475 space_encountered = true; 0476 if (abs(ZZtmp) >= 10 * (currinf.fontp->scaled_size_in_DVI_units / 6)) { 0477 currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size() - 1].text += QLatin1Char('\n'); 0478 } 0479 } 0480 currinf.data.dvi_v += currinf.data.z / 65536; 0481 currinf.data.pxl_v = int(currinf.data.dvi_v / shrinkfactor); 0482 break; 0483 0484 case FNT1: 0485 case FNT2: 0486 case FNT3: 0487 currinf.fontp = currinf.fonttable->value(readUINT(ch - FNT1 + 1)); 0488 if (currinf.fontp == nullptr) { 0489 errorMsg = i18n("The DVI code referred to a font which was not previously defined."); 0490 return; 0491 } 0492 currinf.set_char_p = currinf.fontp->set_char_p; 0493 break; 0494 0495 case FNT4: 0496 currinf.fontp = currinf.fonttable->value(readINT(ch - FNT1 + 1)); 0497 if (currinf.fontp == nullptr) { 0498 errorMsg = i18n("The DVI code referred to a font which was not previously defined."); 0499 return; 0500 } 0501 currinf.set_char_p = currinf.fontp->set_char_p; 0502 break; 0503 0504 case XXX1: 0505 case XXX2: 0506 case XXX3: 0507 case XXX4: 0508 if (is_vfmacro == false) { 0509 word_boundary_encountered = true; 0510 line_boundary_encountered = true; 0511 space_encountered = true; 0512 } 0513 a = readUINT(ch - XXX1 + 1); 0514 if (a > 0) { 0515 char *cmd = new char[a + 1]; 0516 strncpy(cmd, (char *)command_pointer, a); 0517 command_pointer += a; 0518 cmd[a] = '\0'; 0519 applicationDoSpecial(cmd); 0520 delete[] cmd; 0521 } 0522 break; 0523 0524 case FNTDEF1: 0525 case FNTDEF2: 0526 case FNTDEF3: 0527 case FNTDEF4: 0528 command_pointer += 12 + ch - FNTDEF1 + 1; 0529 { 0530 quint8 tempa = readUINT8(); 0531 quint8 tempb = readUINT8(); 0532 command_pointer += tempa + tempb; 0533 } 0534 break; 0535 0536 case PRE: 0537 case POST: 0538 case POSTPOST: 0539 errorMsg = i18n("An illegal command was encountered."); 0540 return; 0541 break; 0542 0543 default: 0544 errorMsg = i18n("The unknown op-code %1 was encountered.", ch); 0545 return; 0546 } /* end switch*/ 0547 } /* end else (ch not a SETCHAR or FNTNUM) */ 0548 0549 #ifdef DEBUG_RENDER 0550 if (currentlyDrawnPage->textBoxList.size() > 0) 0551 qCDebug(OkularDviDebug) << "Element:" << currentlyDrawnPage->textBoxList.last().box << currentlyDrawnPage->textBoxList.last().text << " ? s:" << space_encountered << " / nl:" << line_boundary_encountered 0552 << " / w:" << word_boundary_encountered << ", " << last_space_index << "/" << currentlyDrawnPage->textBoxList.size(); 0553 #endif 0554 0555 /* heuristic to properly detect newlines; a space is needed */ 0556 if (after_space && line_boundary_encountered && word_boundary_encountered) { 0557 if (currentlyDrawnPage->textBoxList.last().text.endsWith(QLatin1Char('\n'))) { 0558 currentlyDrawnPage->textBoxList.last().text.chop(1); 0559 } 0560 currentlyDrawnPage->textBoxList.last().text += QLatin1String(" \n"); 0561 after_space = false; 0562 } 0563 0564 /* a "space" has been found and there is some (new) character 0565 in the array */ 0566 if (space_encountered && (currentlyDrawnPage->textBoxList.size() > last_space_index)) { 0567 for (int lidx = last_space_index + 1; lidx < currentlyDrawnPage->textBoxList.size(); ++lidx) { 0568 // merge two adjacent boxes which are part of the same word 0569 currentlyDrawnPage->textBoxList[lidx - 1].box.setRight(currentlyDrawnPage->textBoxList[lidx].box.x()); 0570 } 0571 #ifdef DEBUG_RENDER 0572 QString lastword(currentlyDrawnPage->textBoxList[last_space_index].text); 0573 for (int lidx = last_space_index + 1; lidx < currentlyDrawnPage->textBoxList.size(); ++lidx) 0574 lastword += currentlyDrawnPage->textBoxList[lidx].text; 0575 qCDebug(OkularDviDebug) << "space encountered: '" << lastword << "'"; 0576 #endif 0577 last_space_index = currentlyDrawnPage->textBoxList.size(); 0578 after_space = true; 0579 } 0580 } /* end for */ 0581 } 0582 0583 void dviRenderer::draw_page() 0584 { 0585 // Reset a couple of variables 0586 HTML_href = nullptr; 0587 source_href = nullptr; 0588 penWidth_in_mInch = 0.0; 0589 0590 // Calling resize() here rather than clear() means that the memory 0591 // taken up by the vector is not freed. This is faster than 0592 // constantly allocating/freeing memory. 0593 currentlyDrawnPage->textBoxList.resize(0); 0594 0595 RenderedDviPagePixmap *currentDVIPage = dynamic_cast<RenderedDviPagePixmap *>(currentlyDrawnPage); 0596 if (currentDVIPage) { 0597 currentDVIPage->sourceHyperLinkList.resize(0); 0598 } 0599 0600 #ifdef PERFORMANCE_MEASUREMENT 0601 // If this is the first time a page is drawn, take the time that is 0602 // elapsed till the kdvi_multipage was constructed, and print 0603 // it. Set the flag so that is message will not be printed again. 0604 if (performanceFlag == 0) { 0605 qCDebug(OkularDviDebug) << "Time elapsed till the first page is drawn: " << performanceTimer.restart() << "ms"; 0606 performanceFlag = 1; 0607 } 0608 #endif 0609 0610 #ifdef DEBUG_RENDER 0611 qCDebug(OkularDviDebug) << "draw_page"; 0612 #endif 0613 0614 foreGroundPainter->fillRect(foreGroundPainter->viewport(), PS_interface->getBackgroundColor(current_page)); 0615 0616 // Render the PostScript background, if there is one. 0617 if (_postscript) { 0618 PS_interface->restoreBackgroundColor(current_page); 0619 0620 PS_interface->graphics(current_page, resolutionInDPI, dviFile->getMagnification(), foreGroundPainter); 0621 } 0622 0623 // Now really write the text 0624 if (dviFile->page_offset.isEmpty() == true) { 0625 return; 0626 } 0627 if (current_page < dviFile->total_pages) { 0628 command_pointer = dviFile->dvi_Data() + dviFile->page_offset[int(current_page)]; 0629 end_pointer = dviFile->dvi_Data() + dviFile->page_offset[int(current_page + 1)]; 0630 } else { 0631 command_pointer = end_pointer = nullptr; 0632 } 0633 0634 memset((char *)&currinf.data, 0, sizeof(currinf.data)); 0635 currinf.fonttable = &(dviFile->tn_table); 0636 currinf._virtual = nullptr; 0637 0638 double fontPixelPerDVIunit = dviFile->getCmPerDVIunit() * 1200.0 / 2.54; 0639 0640 draw_part(65536.0 * fontPixelPerDVIunit, false); 0641 if (HTML_href != nullptr) { 0642 delete HTML_href; 0643 HTML_href = nullptr; 0644 } 0645 if (source_href != nullptr) { 0646 delete source_href; 0647 source_href = nullptr; 0648 } 0649 }