significant improvement in startup-performance for DVI file with lots of fonts

svn path=/trunk/kdegraphics/kdvi/; revision=218683
This commit is contained in:
Stefan Kebekus 2003-04-06 17:32:11 +00:00
parent b1702ef090
commit 5b40d68f24
15 changed files with 183 additions and 643 deletions

7
TODO
View file

@ -2,6 +2,11 @@ ToDo-List for kdvi
URGENT / URGENT BUGFIXING
o Checksum mismatches in all PK files
o Bad display of virtual font ligatures
o implement background according to DVIPS specifications, make it work is there is PS on the page
o improve performance and perceived performance (see also under 'highly desirable')
o add "papersize" which does not display the margin
o get rid of useless README.kdvi
o Proper handling of the base-url
@ -12,8 +17,6 @@ HIGHLY DESIRABLE
o Speedup, in particular for ghostscript and glyph enlarging.
o Support for colored font specials
o Support papersize information given by the dvi-file on a page-by-page
basis.

View file

@ -100,27 +100,17 @@ void TeXFontDefinition::fontNameReceiver(QString fname)
set_char_p = &dviWindow::set_char;
int magic = two(file);
#ifdef HAVE_FREETYPE
if (fname.endsWith(".pfb")) {
fclose(file);
file = 0;
font = new TeXFont_PFB(this);
set_char_p = &dviWindow::set_char;
return;
}
#endif
if (fname.endsWith("pk"))
if (magic == PK_MAGIC) {
fclose(file);
file = 0;
font = new TeXFont_PK(this);
set_char_p = &dviWindow::set_char;
if ((font->checksum != 0) && (checksum != font->checksum))
if ((checksum != 0) && (checksum != font->checksum))
kdWarning(4300) << i18n("Checksum mismatch for font file %1").arg(filename) << endl;
return;
}
if (fname.endsWith(".vf"))
if (magic == VF_MAGIC) {
read_VF_index();
@ -135,8 +125,20 @@ void TeXFontDefinition::fontNameReceiver(QString fname)
set_char_p = &dviWindow::set_char;
return;
}
kdError(4300) << i18n("Cannot recognize format for font file %1").arg(filename) << endl; // @@@ Do sth smarter here
// None of these known types? Then it should be Type1 or TrueType,
// supported by the FreeType library
fclose(file);
file = 0;
#ifdef HAVE_FREETYPE
font = new TeXFont_PFB(this);
set_char_p = &dviWindow::set_char;
return;
#else
// If we don't have the FreeType library, we should never have
// reached this point. Complain, and leave this font blank
kdError(4300) << i18n("Cannot recognize format for font file %1").arg(filename) << endl;
#endif
}

View file

@ -213,8 +213,8 @@ glyph *TeXFont_PK::getGlyph(Q_UINT16 ch, bool generateCharacterPixmap, QColor co
// character.
QBitmap bm(characterBitmaps[ch]->bytes_wide*8, (int)characterBitmaps[ch]->h, (const uchar *)(characterBitmaps[ch]->bits), TRUE);
// ... turn it into a Pixmap (highly inefficient, please improve)
g->shrunkenCharacter.resize(characterBitmaps[ch]->w + pre_cols+post_cols, characterBitmaps[ch]->h + pre_rows+post_rows);
QPainter paint(&g->shrunkenCharacter);
QPixmap intpm(characterBitmaps[ch]->w + pre_cols+post_cols, characterBitmaps[ch]->h + pre_rows+post_rows);
QPainter paint(&intpm);
paint.setBackgroundColor(Qt::white);
paint.setPen( Qt::black );
paint.fillRect(0,0,characterBitmaps[ch]->w + pre_cols+post_cols, characterBitmaps[ch]->h + pre_rows+post_rows, Qt::white);
@ -224,7 +224,7 @@ glyph *TeXFont_PK::getGlyph(Q_UINT16 ch, bool generateCharacterPixmap, QColor co
// Generate an Image and shrink it to the proper size. By the
// documentation of smoothScale, the resulting Image will be
// 8-bit.
QImage EightBitImage = g->shrunkenCharacter.convertToImage().smoothScale(shrunk_width, shrunk_height).convertDepth(32);
QImage EightBitImage = intpm.convertToImage().smoothScale(shrunk_width, shrunk_height).convertDepth(32);
// Generate the alpha-channel. This again is highly inefficient.
// Would anybody please produce a faster routine?

View file

@ -189,6 +189,7 @@ void dvifile::read_postamble(void)
font_pool->release_fonts();
}
void dvifile::prepare_pages()
{
#ifdef DEBUG_DVIFILE
@ -196,6 +197,9 @@ void dvifile::prepare_pages()
#endif
page_offset = new Q_UINT32[total_pages+1];
for(int i=0; i<=total_pages; i++)
page_offset[i] = 0;
if (page_offset == 0) {
kdError(4300) << "No memory for page list!" << endl;
return;
@ -207,8 +211,7 @@ void dvifile::prepare_pages()
// Follow back pointers through pages in the DVI file, storing the
// offsets in the page_offset table.
// @@@@ ADD CHECK FOR CONSISTENCY !!! NEVER LET THE COMMAND PTR POINT OUTSIDE THE ALLOCATED MEM !!!!
while (i > 0) {
while (i > 0) {
command_pointer = dvi_Data + page_offset[i--];
if (readUINT8() != BOP) {
errorMsg = i18n("The page %1 does not start with the BOP command.").arg(i+1);
@ -217,7 +220,7 @@ void dvifile::prepare_pages()
command_pointer += 10 * 4;
page_offset[i] = readUINT32();
if ((dvi_Data+page_offset[i] < dvi_Data)||(dvi_Data+page_offset[i] > dvi_Data+size_of_file))
page_offset[i] = 0;
break;
}
}

View file

@ -44,13 +44,13 @@
#include "fontprogress.h"
#include "infodialog.h"
#include "optiondialog.h"
#include "performanceMeasurement.h"
#include "xdvi.h"
#include "zoomlimits.h"
QPainter foreGroundPaint; // QPainter used for text
//------ now comes the dviWindow class implementation ----------
dviWindow::dviWindow(double zoom, QWidget *parent, const char *name )
@ -77,7 +77,7 @@ dviWindow::dviWindow(double zoom, QWidget *parent, const char *name )
exit(-1);
}
connect(font_pool, SIGNAL( setStatusBarText( const QString& ) ), this, SIGNAL( setStatusBarText( const QString& ) ) );
connect(font_pool, SIGNAL(fonts_have_been_loaded()), this, SLOT(all_fonts_loaded()));
connect(font_pool, SIGNAL(fonts_have_been_loaded(fontPool *)), this, SLOT(all_fonts_loaded(fontPool *)));
info = new infoDialog(this);
if (info == 0) {
@ -86,7 +86,7 @@ dviWindow::dviWindow(double zoom, QWidget *parent, const char *name )
kdError(4300) << "Could not allocate memory for the info dialog." << endl;
} else {
qApp->connect(font_pool, SIGNAL(MFOutput(QString)), info, SLOT(outputReceiver(QString)));
qApp->connect(font_pool, SIGNAL(fonts_info(fontPool *)), info, SLOT(setFontInfo(fontPool *)));
qApp->connect(font_pool, SIGNAL(fonts_have_been_loaded(fontPool *)), info, SLOT(setFontInfo(fontPool *)));
qApp->connect(font_pool, SIGNAL(new_kpsewhich_run(QString)), info, SLOT(clear(QString)));
}
@ -254,19 +254,20 @@ void dviWindow::drawPage()
kdDebug(4300) << "dviWindow::drawPage()" << endl;
#endif
start:
shrinkfactor = MFResolutions[font_pool->getMetafontMode()]/(xres*_zoom);
setCursor(arrowCursor);
// Stop any animation which may be in progress
if (timerIdent != 0) {
killTimer(timerIdent);
timerIdent = 0;
animationCounter = 0;
}
// Remove the mouse selection
DVIselection.clear();
// Stop if there is no dvi-file present
if ( dviFile == 0 ) {
resize(0, 0);
@ -357,6 +358,19 @@ void dviWindow::drawPage()
}
update();
emit contents_changed();
#ifdef PERFORMANCE_MEASUREMENT
if (performanceFlag == 1) {
qApp->processEvents(30);
current_page++;
if (current_page < dviFile->total_pages)
goto start;
else {
kdDebug(4300) << "Time required to draw all pages: " << performanceTimer.restart() << "ms" << endl;
performanceFlag = 2;
}
}
#endif
}
@ -494,6 +508,13 @@ bool dviWindow::setFile(QString fname, QString ref, bool sourceMarker)
if (dviFile->page_offset == 0)
return false;
// Prescan phase starts here
#ifdef PERFORMANCE_MEASUREMENT
kdDebug(4300) << "Time elapsed till prescan phase starts " << performanceTimer.elapsed() << "ms" << endl;
QTime preScanTimer;
preScanTimer.start();
#endif
for(current_page=0; current_page < dviFile->total_pages; current_page++) {
PostScriptOutPutString = new QString();
@ -515,13 +536,17 @@ bool dviWindow::setFile(QString fname, QString ref, bool sourceMarker)
}
PostScriptOutPutString = NULL;
is_current_page_drawn = 0;
#ifdef PERFORMANCE_MEASUREMENT
kdDebug(4300) << "Time required for prescan phase: " << preScanTimer.restart() << "ms" << endl;
#endif
QApplication::restoreOverrideCursor();
reference = ref;
return true;
}
void dviWindow::all_fonts_loaded(void)
void dviWindow::all_fonts_loaded(fontPool *)
{
if (dviFile == 0)
return;

View file

@ -39,6 +39,10 @@ class TeXFontDefinition;
extern const int MFResolutions[];
// If this is defined, KDVI will emitt debugging messages to tell how
// long certain tasks take
class DVI_Hyperlink {
public:
DVI_Hyperlink() {}
@ -202,7 +206,7 @@ public slots:
corresponding section of the DVI file can be found. If so, it
will emit a "requestGotoPage", otherwise it will just call
drawpage */
void all_fonts_loaded();
void all_fonts_loaded(fontPool *);
signals:
/** Emitted to indicate that a hyperlink has been clicked on, and

View file

@ -54,6 +54,7 @@
#include "dviwin.h"
#include "dvi.h"
#include "fontpool.h"
#include "performanceMeasurement.h"
#include "TeXFont.h"
#include "xdvi.h"
@ -70,7 +71,6 @@
extern QPainter foreGroundPaint;
/** Routine to print characters. */
void dviWindow::set_char(unsigned int cmd, unsigned int ch)
@ -571,12 +571,25 @@ void dviWindow::draw_page(void)
if (font_pool->check_if_fonts_filenames_are_looked_up() == false)
return;
#ifdef PERFORMANCE_MEASUREMENT
// If this is the first time a page is drawn, take the time that is
// elapsed till the kdvi_multipage was constructed, and print
// it. Set the flag so that is message will not be printed again.
if (performanceFlag == 0) {
kdDebug(4300) << "Time elapsed till the first page is drawn: " << performanceTimer.restart() << "ms" << endl;
exit(0);
performanceFlag = 1;
}
#endif
#ifdef DEBUG_RENDER
kdDebug() <<"draw_page" << endl;
#endif
foreGroundPaint.fillRect(pixmap->rect(), PS_interface->getBackgroundColor(current_page) );
// Render the PostScript background, if there is one.
foreGroundPaint.fillRect(pixmap->rect(), Qt::white );
if (_postscript) {
QPixmap *pxm = PS_interface->graphics(current_page);
if (pxm != NULL) {

View file

@ -19,6 +19,7 @@
#include "fontpool.h"
#include "fontprogress.h"
#include "performanceMeasurement.h"
#include "TeXFont.h"
// List of permissible MetaFontModes which are supported by kdvi.
@ -27,6 +28,11 @@ const char *MFModes[] = { "cx", "ljfour", "lexmarks" };
const char *MFModenames[] = { "Canon CX", "LaserJet 4", "Lexmark S" };
const int MFResolutions[] = { 300, 600, 1200 };
#ifdef PERFORMANCE_MEASUREMENT
QTime fontPoolTimer;
bool fontPoolTimerFlag;
#endif
//#define DEBUG_FONTPOOL
fontPool::fontPool(void)
@ -176,7 +182,7 @@ void fontPool::setParameters( unsigned int _metafontMode, bool _makePK, bool _en
if (kpsewhichNeeded == true)
check_if_fonts_filenames_are_looked_up();
else
emit fonts_have_been_loaded();
emit fonts_have_been_loaded(this);
}
@ -207,7 +213,12 @@ class TeXFontDefinition *fontPool::appendx(QString fontname, Q_UINT32 checksum,
exit(0);
}
fontList.append(fontp);
#ifdef PERFORMANCE_MEASUREMENT
fontPoolTimer.start();
fontPoolTimerFlag = false;
#endif
// Now start kpsewhich/MetaFont, etc. if necessary
return fontp;
}
@ -215,6 +226,10 @@ class TeXFontDefinition *fontPool::appendx(QString fontname, Q_UINT32 checksum,
QString fontPool::status(void)
{
#ifdef DEBUG_FONTPOOL
kdDebug(4300) << "fontPool::status() called" << endl;
#endif
QString text;
QStringList tmp;
@ -261,10 +276,9 @@ bool fontPool::check_if_fonts_filenames_are_looked_up(void)
#ifdef DEBUG_FONTPOOL
kdDebug(4300) << "... no, kpsewhich is still running." << endl;
#endif
emit fonts_info(this);
return false;
}
// Is there a font whose name we did not try to find out yet?
TeXFontDefinition *fontp = fontList.first();
while( fontp != 0 ) {
@ -277,7 +291,6 @@ bool fontPool::check_if_fonts_filenames_are_looked_up(void)
#ifdef DEBUG_FONTPOOL
kdDebug(4300) << "... yes, all fonts are there, or could not be found." << endl;
#endif
emit fonts_info(this);
return true; // That says that all fonts are loaded.
}
@ -293,13 +306,12 @@ void fontPool::start_kpsewhich(void)
kdDebug(4300) << "fontPool::start_kpsewhich(void) called" << endl;
#endif
// Check if kpsewhich is still running. In that case certainly not
// all fonts have been properly looked up.
// Check if kpsewhich is still running. In that case we certainly do
// not want to run another kpsewhich process
if (proc != 0) {
#ifdef DEBUG_FONTPOOL
kdDebug(4300) << "kpsewhich is still running." << endl;
#endif
emit fonts_info(this);
return;
}
@ -398,7 +410,7 @@ void fontPool::start_kpsewhich(void)
#endif
break;
case 1:
// In the second pass, we generate PK fonts, but be also look
// In the second pass, we generate PK fonts, but we also look
// for PFB fonts, as they might be used by virtual fonts.
#ifdef HAVE_FREETYPE
if ((useType1Fonts == true) && (FreeType_could_be_loaded == true)) {
@ -452,8 +464,6 @@ void fontPool::start_kpsewhich(void)
if (proc->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) {
kdError(4300) << "kpsewhich failed to start" << endl;
}
emit fonts_info(this);
}
@ -502,7 +512,6 @@ void fontPool::kpsewhich_terminated(KProcess *)
#endif
fontp->fontNameReceiver(matchingFiles.first());
fontp->flags |= TeXFontDefinition::FONT_KPSE_NAME;
emit fonts_info(this);
// Constructing a virtual font will most likely insert other
// fonts into the fontList. After that, fontList.next() will
// no longer work. It is therefore safer to start over.
@ -514,7 +523,7 @@ void fontPool::kpsewhich_terminated(KProcess *)
}
// Check if some font filenames are still missing. If not, or if we
// have just finished the lass pass, we quit here.
// have just finished the last pass, we quit here.
bool all_fonts_are_found = true;
fontp = fontList.first();
@ -527,10 +536,13 @@ void fontPool::kpsewhich_terminated(KProcess *)
}
if ((all_fonts_are_found) || (pass >= 2)) {
#ifdef DEBUG_FONTPOOL
kdDebug(4300) << "Emitting fonts_have_been_loaded()" << endl;
kdDebug(4300) << "Emitting fonts_have_been_loaded(this)" << endl;
#endif
#ifdef PERFORMANCE_MEASUREMENT
kdDebug(4300) << "Time required to look up fonts: " << fontPoolTimer.elapsed() << "ms" << endl;
#endif
emit setStatusBarText(QString::null);
emit fonts_have_been_loaded();
emit fonts_have_been_loaded(this);
return;
}
@ -614,7 +626,7 @@ void fontPool::setDisplayResolution( double _displayResolution_in_dpi )
}
// Do something that causes re-rendering of the dvi-window
emit fonts_have_been_loaded();
emit fonts_have_been_loaded(this);
}

View file

@ -158,7 +158,7 @@ signals:
/** Emitted to indicate that all the fonts have now been loaded so
that the first page can be rendered. */
void fonts_have_been_loaded(void);
void fonts_have_been_loaded(fontPool *);
/** The title says it all... */
void hide_progress_dialog(void);
@ -179,12 +179,6 @@ signals:
info dialog window. */
void new_kpsewhich_run(QString);
/** Emitted when the font-pool has changed. The class receiving the
signal might whish to call status() in order to receive the
data. We don't send the data here directly as the compilation of
the string is quite costy. */
void fonts_info(fontPool *);
/** Passed through to the top-level kpart. */
void setStatusBarText( const QString& );

View file

@ -19,8 +19,16 @@
#include "kdvi_multipage.h"
#include "kviewpart.h"
#include "optiondialog.h"
#include "performanceMeasurement.h"
#include "zoomlimits.h"
#ifdef PERFORMANCE_MEASUREMENT
// These objects are explained in the file "performanceMeasurement.h"
QTime performanceTimer;
int performanceFlag = 0;
#endif
extern "C"
{
void *init_kdvipart()
@ -66,6 +74,10 @@ KInstance *KDVIMultiPageFactory::instance()
KDVIMultiPage::KDVIMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name)
: KMultiPage(parentWidget, widgetName, parent, name), window(0), options(0)
{
#ifdef PERFORMANCE_MEASUREMENT
performanceTimer.start();
#endif
timer_id = -1;
setInstance(KDVIMultiPageFactory::instance());
@ -145,7 +157,7 @@ void KDVIMultiPage::jumpToReference(QString reference)
{
if (window != 0) {
window->reference = reference;
window->all_fonts_loaded(); // In spite of its name, this method tries to parse the reference.
window->all_fonts_loaded(0); // In spite of its name, this method tries to parse the reference.
}
}

20
performanceMeasurement.h Normal file
View file

@ -0,0 +1,20 @@
//#define PERFORMANCE_MEASUREMENT
#ifdef PERFORMANCE_MEASUREMENT
#include <qdatetime.h>
// This is the central timer used for performance measurement. It is
// set to zero and started when the kdvi_multipage is
// constructed. This object is statically defined in
// kdvi_multipage.cpp.
extern QTime performanceTimer;
// A flag that is set to TRUE once the first page of the document was
// successfully drawn. This object is statically defined in
// kdvi_multipage.cpp.
// 0 = initial value
// 1 = first page was drawn
// 2 = last page was drawn
extern int performanceFlag;
#endif

538
pk.cpp
View file

@ -1,538 +0,0 @@
/*
* Copyright (c) 1994 Paul Vojta. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* NOTE:
* xdvi is based on prior work as noted in the modification history, below.
*/
/*
* DVI previewer for X.
*
* Eric Cooper, CMU, September 1985.
*
* Code derived from dvi-imagen.c.
*
* Modification history:
* 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS.
* 7/1988 Modified for X.11 --Mark Eichin, MIT
* 12/1988 Added 'R' option, toolkit, magnifying glass
* --Paul Vojta, UC Berkeley.
* 2/1989 Added tpic support --Jeffrey Lee, U of Toronto
* 4/1989 Modified for System V --Donald Richardson, Clarkson Univ.
* 3/1990 Added VMS support --Scott Allendorf, U of Iowa
* 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem
* 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen
* and Lee Hetherington, MIT
* 4/1994 Added DPS support, bounding box
* --Ricardo Telichevesky
* and Luis Miguel Silveira, MIT RLE.
*/
#include <kdebug.h>
#include <klocale.h>
#include "font.h"
#include "dviwin.h"
#include "kdvi.h" // This is where debugging flags are set.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "glyph.h"
#include "xdvi.h"
#define BMUNIT Q_UINT32
#define BITS_PER_BMUNIT 32
#define BYTES_PER_BMUNIT 4
#define ADD(a, b) ((BMUNIT *) (((char *) a) + b))
#define SUB(a, b) ((BMUNIT *) (((char *) a) - b))
extern void oops(QString message);
/*
* Allocate bitmap for given font and character
*/
void alloc_bitmap(bitmap *bitmap)
{
register unsigned int size;
/* width must be multiple of 16 bits for raster_op */
bitmap->bytes_wide = ROUNDUP((int) bitmap->w, BITS_PER_BMUNIT) * BYTES_PER_BMUNIT;
size = bitmap->bytes_wide * bitmap->h;
bitmap->bits = new char[size != 0 ? size : 1];
}
// This table is used for changing the bit order in a byte. The
// expression bitflp[byte] takes a byte in big endian and gives the
// little endian equivalent of that.
static const uchar bitflip[256] = {
0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
};
BMUNIT bit_masks[33] = {
0x0, 0x1, 0x3, 0x7,
0xf, 0x1f, 0x3f, 0x7f,
0xff, 0x1ff, 0x3ff, 0x7ff,
0xfff, 0x1fff, 0x3fff, 0x7fff,
0xffff, 0x1ffff, 0x3ffff, 0x7ffff,
0xfffff, 0x1fffff, 0x3fffff, 0x7fffff,
0xffffff, 0x1ffffff, 0x3ffffff, 0x7ffffff,
0xfffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
0xffffffff
};
/***
*** PK font reading routines.
*** Public routines are read_PK_index and read_PK_char.
***/
#define PK_ID 89
#define PK_CMD_START 240
#define PK_X1 240
#define PK_X2 241
#define PK_X3 242
#define PK_X4 243
#define PK_Y 244
#define PK_POST 245
#define PK_NOOP 246
#define PK_PRE 247
static int PK_flag_byte;
static unsigned PK_input_byte;
static int PK_bitpos;
static int PK_dyn_f;
static int PK_repeat_count;
int font::PK_get_nyb(FILE *fp)
{
#ifdef DEBUG_PK
kdDebug(4300) << "PK_get_nyb" << endl;
#endif
unsigned temp;
if (PK_bitpos < 0) {
PK_input_byte = one(fp);
PK_bitpos = 4;
}
temp = PK_input_byte >> PK_bitpos;
PK_bitpos -= 4;
return (temp & 0xf);
}
int font::PK_packed_num(FILE *fp)
{
#ifdef DEBUG_PK
kdDebug(4300) << "PK_packed_num" << endl;
#endif
int i,j;
if ((i = PK_get_nyb(fp)) == 0) {
do {
j = PK_get_nyb(fp);
++i;
}
while (j == 0);
while (i > 0) {
j = (j << 4) | PK_get_nyb(fp);
--i;
}
return (j - 15 + ((13 - PK_dyn_f) << 4) + PK_dyn_f);
}
else {
if (i <= PK_dyn_f) return i;
if (i < 14)
return (((i - PK_dyn_f - 1) << 4) + PK_get_nyb(fp)
+ PK_dyn_f + 1);
if (i == 14) PK_repeat_count = PK_packed_num(fp);
else PK_repeat_count = 1;
return PK_packed_num(fp);
}
}
void font::PK_skip_specials(void)
{
#ifdef DEBUG_PK
kdDebug(4300) << "PK_skip_specials" << endl;
#endif
int i,j;
register FILE *fp = file;
do {
PK_flag_byte = one(fp);
if (PK_flag_byte >= PK_CMD_START) {
switch (PK_flag_byte) {
case PK_X1 :
case PK_X2 :
case PK_X3 :
case PK_X4 :
i = 0;
for (j = PK_CMD_START; j <= PK_flag_byte; ++j)
i = (i << 8) | one(fp);
while (i--) (void) one(fp);
break;
case PK_Y :
(void) four(fp);
case PK_POST :
case PK_NOOP :
break;
default :
oops(i18n("Unexpected %1 in PK file %2").arg(PK_flag_byte).arg(filename) );
break;
}
}
}
while (PK_flag_byte != PK_POST && PK_flag_byte >= PK_CMD_START)
;
}
/*
* Public routines
*/
void font::read_PK_char(unsigned int ch)
{
#ifdef DEBUG_PK
kdDebug(4300) << "read_PK_char" << endl;
#endif
int i, j;
int n;
int row_bit_pos;
bool paint_switch;
BMUNIT *cp;
register struct glyph *g;
register FILE *fp = file;
long fpwidth;
BMUNIT word = 0;
int word_weight, bytes_wide;
int rows_left, h_bit, count;
g = glyphtable + ch;
PK_flag_byte = g->x2;
PK_dyn_f = PK_flag_byte >> 4;
paint_switch = ((PK_flag_byte & 8) != 0);
PK_flag_byte &= 0x7;
if (PK_flag_byte == 7)
n = 4;
else
if (PK_flag_byte > 3)
n = 2;
else
n = 1;
#ifdef DEBUG_PK
kdDebug(4300) << "loading pk char " << ch << ", char type " << n << endl;
#endif
/*
* now read rest of character preamble
*/
if (n != 4)
fpwidth = num(fp, 3);
else {
fpwidth = sfour(fp);
(void) four(fp); /* horizontal escapement */
}
(void) num(fp, n); /* vertical escapement */
{
unsigned long w, h;
w = num(fp, n);
h = num(fp, n);
if (w > 0x7fff || h > 0x7fff)
oops(i18n("The character %1 is too large in file %2").arg(ch).arg(fontname));
g->bitmap.w = w;
g->bitmap.h = h;
}
g->x = snum(fp, n);
g->y = snum(fp, n);
g->dvi_advance_in_DVI_units = fpwidth; // ####
alloc_bitmap(&g->bitmap);
cp = (BMUNIT *) g->bitmap.bits;
/*
* read character data into *cp
*/
bytes_wide = ROUNDUP((int) g->bitmap.w, BITS_PER_BMUNIT) * BYTES_PER_BMUNIT;
PK_bitpos = -1;
// The routines which read the character depend on the byte
// ordering. In principle, the byte order should be detected at
// compile time and the proper routing chosen. For the moment, as
// autoconf is somewhat complicated for the author, we prefer a
// simpler -even if somewhat slower approach and detect the ordering
// at runtime. That should of course be changed in the future.
int wordSize;
bool bigEndian;
qSysInfo (&wordSize, &bigEndian);
if (bigEndian) {
// Routine for big Endian machines. Applies e.g. to Motorola and
// (Ultra-)Sparc processors.
#ifdef DEBUG_PK
kdDebug(4300) << "big Endian byte ordering" << endl;
#endif
if (PK_dyn_f == 14) { /* get raster by bits */
memset(g->bitmap.bits, 0, (int) g->bitmap.h * bytes_wide);
for (i = 0; i < (int) g->bitmap.h; i++) { /* get all rows */
cp = ADD(g->bitmap.bits, i * bytes_wide);
row_bit_pos = BITS_PER_BMUNIT;
for (j = 0; j < (int) g->bitmap.w; j++) { /* get one row */
if (--PK_bitpos < 0) {
word = one(fp);
PK_bitpos = 7;
}
if (--row_bit_pos < 0) {
cp++;
row_bit_pos = BITS_PER_BMUNIT - 1;
}
if (word & (1 << PK_bitpos))
*cp |= 1 << row_bit_pos;
}
}
} else { /* get packed raster */
rows_left = g->bitmap.h;
h_bit = g->bitmap.w;
PK_repeat_count = 0;
word_weight = BITS_PER_BMUNIT;
word = 0;
while (rows_left > 0) {
count = PK_packed_num(fp);
while (count > 0) {
if (count < word_weight && count < h_bit) {
h_bit -= count;
word_weight -= count;
if (paint_switch)
word |= bit_masks[count] << word_weight;
count = 0;
} else
if (count >= h_bit && h_bit <= word_weight) {
if (paint_switch)
word |= bit_masks[h_bit] << (word_weight - h_bit);
*cp++ = word;
/* "output" row(s) */
for (i = PK_repeat_count * bytes_wide /
BYTES_PER_BMUNIT; i > 0; --i) {
*cp = *SUB(cp, bytes_wide);
++cp;
}
rows_left -= PK_repeat_count + 1;
PK_repeat_count = 0;
word = 0;
word_weight = BITS_PER_BMUNIT;
count -= h_bit;
h_bit = g->bitmap.w;
} else {
if (paint_switch)
word |= bit_masks[word_weight];
*cp++ = word;
word = 0;
count -= word_weight;
h_bit -= word_weight;
word_weight = BITS_PER_BMUNIT;
}
}
paint_switch = 1 - paint_switch;
}
if (cp != ((BMUNIT *) (g->bitmap.bits + bytes_wide * g->bitmap.h)))
oops(i18n("Wrong number of bits stored: char. %1, font %2").arg(ch).arg(fontname));
if (rows_left != 0 || h_bit != g->bitmap.w)
oops(i18n("Bad pk file (%1), too many bits").arg(fontname));
}
// The data in the bitmap is now in the processor's bit order,
// that is, big endian. Since XWindows needs little endian, we
// need to change the bit order now.
register unsigned char* bitmapData = (unsigned char*) g->bitmap.bits;
register unsigned char* endOfData = bitmapData + g->bitmap.bytes_wide*g->bitmap.h;
while(bitmapData < endOfData) {
*bitmapData = bitflip[*bitmapData];
bitmapData++;
}
} else {
// Routines for small Endian start here. This applies e.g. to
// Intel and Alpha processors.
#ifdef DEBUG_PK
kdDebug(4300) << "small Endian byte ordering" << endl;
#endif
if (PK_dyn_f == 14) { /* get raster by bits */
memset(g->bitmap.bits, 0, (int) g->bitmap.h * bytes_wide);
for (i = 0; i < (int) g->bitmap.h; i++) { /* get all rows */
cp = ADD(g->bitmap.bits, i * bytes_wide);
row_bit_pos = -1;
for (j = 0; j < (int) g->bitmap.w; j++) { /* get one row */
if (--PK_bitpos < 0) {
word = one(fp);
PK_bitpos = 7;
}
if (++row_bit_pos >= BITS_PER_BMUNIT) {
cp++;
row_bit_pos = 0;
}
if (word & (1 << PK_bitpos))
*cp |= 1 << row_bit_pos;
}
}
} else { /* get packed raster */
rows_left = g->bitmap.h;
h_bit = g->bitmap.w;
PK_repeat_count = 0;
word_weight = BITS_PER_BMUNIT;
word = 0;
while (rows_left > 0) {
count = PK_packed_num(fp);
while (count > 0) {
if (count < word_weight && count < h_bit) {
if (paint_switch)
word |= bit_masks[count] << (BITS_PER_BMUNIT - word_weight);
h_bit -= count;
word_weight -= count;
count = 0;
} else
if (count >= h_bit && h_bit <= word_weight) {
if (paint_switch)
word |= bit_masks[h_bit] << (BITS_PER_BMUNIT - word_weight);
*cp++ = word;
/* "output" row(s) */
for (i = PK_repeat_count * bytes_wide /
BYTES_PER_BMUNIT; i > 0; --i) {
*cp = *SUB(cp, bytes_wide);
++cp;
}
rows_left -= PK_repeat_count + 1;
PK_repeat_count = 0;
word = 0;
word_weight = BITS_PER_BMUNIT;
count -= h_bit;
h_bit = g->bitmap.w;
} else {
if (paint_switch)
word |= bit_masks[word_weight] << (BITS_PER_BMUNIT - word_weight);
*cp++ = word;
word = 0;
count -= word_weight;
h_bit -= word_weight;
word_weight = BITS_PER_BMUNIT;
}
}
paint_switch = 1 - paint_switch;
}
if (cp != ((BMUNIT *) (g->bitmap.bits + bytes_wide * g->bitmap.h)))
oops(i18n("Wrong number of bits stored: char. %1, font %2").arg(ch).arg(fontname));
if (rows_left != 0 || h_bit != g->bitmap.w)
oops(i18n("Bad pk file (%1), too many bits").arg(fontname));
}
} // endif: big or small Endian?
}
void font::read_PK_index(void)
{
#ifdef DEBUG_PK
kdDebug(4300) << "Reading PK pixel file " << filename << endl;
#endif
fseek(file, (long) one(file), SEEK_CUR); /* skip comment */
(void) four(file); /* skip design size */
Q_UINT32 file_checksum = four(file);
if (checksum && checksum && file_checksum != checksum)
kdWarning(4300) << i18n("Checksum mismatch for PK font file %3 (dvi=%1, pk=%2)").arg(checksum).arg(file_checksum).arg(filename) << endl;
int hppp = sfour(file);
int vppp = sfour(file);
if (hppp != vppp)
kdWarning(4300) << i18n("Font has non-square aspect ratio ") << vppp << ":" << hppp << endl;
// Prepare glyph array.
glyphtable = new glyph[max_num_of_chars_in_font];
if (glyphtable == 0) {
kdError(4300) << i18n("Could not allocate memory for a glyph table.") << endl;
exit(0);
}
// Read glyph directory (really a whole pass over the file).
for (;;) {
int bytes_left, flag_low_bits;
unsigned int ch;
PK_skip_specials();
if (PK_flag_byte == PK_POST)
break;
flag_low_bits = PK_flag_byte & 0x7;
if (flag_low_bits == 7) {
bytes_left = four(file);
ch = four(file);
} else
if (flag_low_bits > 3) {
bytes_left = ((flag_low_bits - 4) << 16) + two(file);
ch = one(file);
} else {
bytes_left = (flag_low_bits << 8) + one(file);
ch = one(file);
}
glyphtable[ch].addr = ftell(file);
glyphtable[ch].x2 = PK_flag_byte;
fseek(file, (long) bytes_left, SEEK_CUR);
#ifdef DEBUG_PK
kdDebug(4300) << "Scanning pk char " << ch << "at " << glyphtable[ch].addr << endl;
#endif
}
}

View file

@ -23,15 +23,9 @@ pageInfo::~pageInfo() {
// ======================================================
ghostscript_interface::ghostscript_interface(double dpi, int pxlw, int pxlh) {
//@@@ Error checking !
pageList = new QIntDict<pageInfo>(256);
pageList->setAutoDelete(TRUE);
MemoryCache = new QIntCache<QPixmap>(PAGES_IN_MEMORY_CACHE, PAGES_IN_MEMORY_CACHE);
MemoryCache->setAutoDelete(TRUE);
DiskCache = new QIntCache<KTempFile>(PAGES_IN_DISK_CACHE, PAGES_IN_DISK_CACHE);
DiskCache->setAutoDelete(TRUE);
pageList.setAutoDelete(TRUE);
MemoryCache.setAutoDelete(TRUE);
DiskCache.setAutoDelete(TRUE);
PostScriptHeaderString = new QString();
resolution = dpi;
@ -40,12 +34,6 @@ ghostscript_interface::ghostscript_interface(double dpi, int pxlw, int pxlh) {
}
ghostscript_interface::~ghostscript_interface() {
if (pageList != 0L)
delete pageList;
if (MemoryCache != 0L)
delete MemoryCache;
if (DiskCache != 0L)
delete DiskCache;
if (PostScriptHeaderString != 0L)
delete PostScriptHeaderString;
}
@ -56,58 +44,61 @@ void ghostscript_interface::setSize(double dpi, int pxlw, int pxlh) {
pixel_page_w = pxlw;
pixel_page_h = pxlh;
MemoryCache->clear();
DiskCache->clear();
MemoryCache.clear();
DiskCache.clear();
}
void ghostscript_interface::setPostScript(int page, QString PostScript) {
if (pageList->find(page) == 0) {
if (pageList.find(page) == 0) {
pageInfo *info = new pageInfo(PostScript);
// Check if dict is big enough
if (pageList->count() > pageList->size() -2)
pageList->resize(pageList->size()*2);
pageList->insert(page, info);
if (pageList.count() > pageList.size() -2)
pageList.resize(pageList.size()*2);
pageList.insert(page, info);
} else
*(pageList->find(page)->PostScriptString) = PostScript;
*(pageList.find(page)->PostScriptString) = PostScript;
}
void ghostscript_interface::setColor(int page, QColor background_color) {
if (pageList->find(page) == 0) {
if (pageList.find(page) == 0) {
pageInfo *info = new pageInfo(QString::null);
info->background = background_color;
// Check if dict is big enough
if (pageList->count() > pageList->size() -2)
pageList->resize(pageList->size()*2);
pageList->insert(page, info);
} else
pageList->find(page)->background = background_color;
if (pageList.count() > pageList.size() -2)
pageList.resize(pageList.size()*2);
pageList.insert(page, info);
} else
pageList.find(page)->background = background_color;
}
// Returns the background color for a certain page. This color is
// always guaranteed to be valid
QColor ghostscript_interface::getBackgroundColor(int page) {
if (pageList->find(page) == 0)
if (pageList.find(page) == 0)
return Qt::white;
else
return pageList->find(page)->background;
return pageList.find(page)->background;
}
void ghostscript_interface::clear(void) {
PostScriptHeaderString->truncate(0);
MemoryCache->clear();
DiskCache->clear();
MemoryCache.clear();
DiskCache.clear();
// Deletes all items, removes temporary files, etc.
pageList->clear();
pageList.clear();
}
void ghostscript_interface::gs_generate_graphics_file(int page, QString filename) {
emit(setStatusBarText(i18n("Generating PostScript graphics...")));
pageInfo *info = pageList->find(page);
pageInfo *info = pageList.find(page);
// Generate a PNG-file
// Step 1: Write the PostScriptString to a File
@ -162,23 +153,23 @@ void ghostscript_interface::gs_generate_graphics_file(int page, QString filename
QPixmap *ghostscript_interface::graphics(int page) {
pageInfo *info = pageList->find(page);
pageInfo *info = pageList.find(page);
// No PostScript? Then return immediately.
if (info == NULL)
return NULL;
if ((info == 0) || (info->PostScriptString->isEmpty()))
return 0;
// Gfx exists in the MemoryCache?
QPixmap *CachedCopy = MemoryCache->find(page);
QPixmap *CachedCopy = MemoryCache.find(page);
if (CachedCopy != NULL)
return new QPixmap(*CachedCopy);
// Gfx exists in the DiskCache?
KTempFile *CachedCopyFile = DiskCache->find(page);
KTempFile *CachedCopyFile = DiskCache.find(page);
if (CachedCopyFile != NULL) {
QPixmap *MemoryCopy = new QPixmap(CachedCopyFile->name());
QPixmap *ReturnCopy = new QPixmap(*MemoryCopy);
MemoryCache->insert(page, MemoryCopy);
MemoryCache.insert(page, MemoryCopy);
return ReturnCopy;
}
@ -192,8 +183,8 @@ QPixmap *ghostscript_interface::graphics(int page) {
QPixmap *MemoryCopy = new QPixmap(GfxFile->name());
QPixmap *ReturnCopy = new QPixmap(*MemoryCopy);
MemoryCache->insert(page, MemoryCopy);
DiskCache->insert(page, GfxFile);
MemoryCache.insert(page, MemoryCopy);
DiskCache.insert(page, GfxFile);
return ReturnCopy;
}
#include "psgs.moc"

6
psgs.h
View file

@ -59,15 +59,15 @@ public:
private:
void gs_generate_graphics_file(int page, QString filename);
QIntDict<pageInfo> *pageList;
QIntDict<pageInfo> pageList;
// Chache to store pages which contain PostScript and are therefore
// slow to render.
QIntCache<QPixmap> *MemoryCache;
QIntCache<QPixmap> MemoryCache;
// Chache to store pages which contain PostScript and are therefore
// slow to render.
QIntCache<KTempFile> *DiskCache;
QIntCache<KTempFile> DiskCache;
double resolution; // in dots per inch
int pixel_page_w; // in pixels

View file

@ -172,11 +172,10 @@ void dviWindow::background_special(QString cp)
{
// The color specials are ignored during rendering, and used only in
// the pre-scan phase
if (PostScriptOutPutString == NULL) {
if (PostScriptOutPutString != NULL) {
QColor col = parseColorSpecification(cp.stripWhiteSpace());
//@@@@ do something with the color!
if (col.isValid())
PS_interface->setColor(current_page, col);
return;
}
}