Commit bf86a9fc authored by Albert Astals Cid's avatar Albert Astals Cid

introduce getChars to save some method calls

Can give us a decent speedup when we go a lot though this methods
parent 65c14073
......@@ -192,7 +192,6 @@ GooString *Catalog::readMetadata() {
GooString *s;
Dict *dict;
Object obj;
int c;
if (metadata.isNone()) {
Object catDict;
......@@ -217,10 +216,7 @@ GooString *Catalog::readMetadata() {
}
obj.free();
s = new GooString();
metadata.streamReset();
while ((c = metadata.streamGetChar()) != EOF) {
s->append(c);
}
metadata.getStream()->fillGooString(s);
metadata.streamClose();
return s;
}
......@@ -409,11 +405,7 @@ GooString *Catalog::getJS(int i)
else if (obj2.isStream()) {
Stream *stream = obj2.getStream();
js = new GooString();
stream->reset();
int j;
while ((j = stream->getChar()) != EOF) {
js->append((char)j);
}
stream->fillGooString(js);
}
obj2.free();
obj.free();
......
......@@ -145,27 +145,48 @@ void DCTStream::reset() {
}
}
// we can not go with inline since gcc
// refuses to inline because of setjmp
#define DO_GET_CHAR \
if (current == limit) { \
if (cinfo.output_scanline < cinfo.output_height) \
{ \
if (!setjmp(src.setjmp_buffer)) \
{ \
if (!jpeg_read_scanlines(&cinfo, row_buffer, 1)) c = EOF; \
else { \
current = &row_buffer[0][0]; \
limit = &row_buffer[0][(cinfo.output_width - 1) * cinfo.output_components] + cinfo.output_components; \
c = *current; \
++current; \
} \
} \
else c = EOF; \
} \
else c = EOF; \
} else { \
c = *current; \
++current; \
} \
int DCTStream::getChar() {
int c;
if (current == limit) {
if (cinfo.output_scanline < cinfo.output_height)
{
if (!setjmp(src.setjmp_buffer))
{
if (!jpeg_read_scanlines(&cinfo, row_buffer, 1)) return EOF;
current = &row_buffer[0][0];
limit = &row_buffer[0][(cinfo.output_width - 1) * cinfo.output_components] + cinfo.output_components;
}
else return EOF;
}
else return EOF;
}
c = *current;
++current;
DO_GET_CHAR
return c;
}
int DCTStream::getChars(int nChars, Guchar *buffer) {
int c;
for (int i = 0; i < nChars; ++i) {
DO_GET_CHAR
if (likely(c != EOF)) buffer[i] = c;
else return i;
}
return nChars;
}
int DCTStream::lookChar() {
return *current;
}
......
......@@ -69,6 +69,9 @@ public:
private:
void init();
virtual GBool hasGetChars() { return true; }
virtual int getChars(int nChars, Guchar *buffer);
JSAMPLE *current;
JSAMPLE *limit;
struct jpeg_decompress_struct cinfo;
......
......@@ -10,7 +10,7 @@
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
// Copyright (C) 2005, 2006, 2008, 2009 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2005, 2006, 2008-2010 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
......@@ -421,17 +421,13 @@ CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits,
CharCodeToUnicode *ctu) {
GooString *buf;
Object obj1;
int c;
if (!fontDict->lookup("ToUnicode", &obj1)->isStream()) {
obj1.free();
return NULL;
}
buf = new GooString();
obj1.streamReset();
while ((c = obj1.streamGetChar()) != EOF) {
buf->append(c);
}
obj1.getStream()->fillGooString(buf);
obj1.streamClose();
obj1.free();
if (ctu) {
......@@ -488,8 +484,6 @@ char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
char *buf;
Object obj1, obj2;
Stream *str;
int c;
int size, i;
obj1.initRef(embFontID.num, embFontID.gen);
obj1.fetch(xref, &obj2);
......@@ -503,17 +497,7 @@ char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
}
str = obj2.getStream();
buf = NULL;
i = size = 0;
str->reset();
while ((c = str->getChar()) != EOF) {
if (i == size) {
size += 4096;
buf = (char *)grealloc(buf, size);
}
buf[i++] = c;
}
*len = i;
buf = (char*)str->toUnsignedChars(len);
str->close();
obj2.free();
......
......@@ -1484,22 +1484,11 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, Gfx *gfx) {
arr->get(1, &obj1);
dict = obj1.streamGetDict();
Guchar *profBuf;
unsigned int bufSize;
Stream *iccStream = obj1.getStream();
int c;
unsigned int size = 0;
bufSize = 65536;
profBuf = (Guchar *)gmallocn(bufSize,1);
iccStream->reset();
while ((c = iccStream->getChar()) != EOF) {
if (bufSize <= size) {
bufSize += 65536;
profBuf = (Guchar *)greallocn(profBuf,bufSize,1);
}
profBuf[size++] = c;
}
cmsHPROFILE hp = cmsOpenProfileFromMem(profBuf,size);
int length = 0;
profBuf = iccStream->toUnsignedChars(&length, 65536, 65536);
cmsHPROFILE hp = cmsOpenProfileFromMem(profBuf,length);
gfree(profBuf);
if (hp == 0) {
error(-1, "read ICCBased color space profile error");
......@@ -1718,7 +1707,6 @@ GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr, Gfx *gfx) {
GfxColorSpace *baseA;
int indexHighA;
Object obj1;
int x;
char *s;
int n, i, j;
......@@ -1755,12 +1743,10 @@ GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr, Gfx *gfx) {
if (obj1.isStream()) {
obj1.streamReset();
for (i = 0; i <= indexHighA; ++i) {
for (j = 0; j < n; ++j) {
if ((x = obj1.streamGetChar()) == EOF) {
error(-1, "Bad Indexed color space (lookup table stream too short) padding with zeroes");
x = 0;
}
cs->lookup[i*n + j] = (Guchar)x;
const int readChars = obj1.streamGetChars(n, &cs->lookup[i*n]);
for (j = readChars; j < n; ++j) {
error(-1, "Bad Indexed color space (lookup table stream too short) padding with zeroes");
cs->lookup[i*n + j] = 0;
}
}
obj1.streamClose();
......
......@@ -4,7 +4,7 @@
//
// A JPX stream decoder using OpenJPEG
//
// Copyright 2008, 2009 Albert Astals Cid <aacid@kde.org>
// Copyright 2008-2010 Albert Astals Cid <aacid@kde.org>
//
// Licensed under GPLv2 or later
//
......@@ -43,42 +43,34 @@ int JPXStream::getPos() {
return counter;
}
int JPXStream::getChars(int nChars, Guchar *buffer) {
for (int i = 0; i < nChars; ++i) {
const int c = doGetChar();
if (likely(c != EOF)) buffer[i] = c;
else return i;
}
return nChars;
}
int JPXStream::getChar() {
int result = lookChar();
++counter;
return result;
return doGetChar();
}
#define BUFFER_INCREASE 4096
#define BUFFER_INITIAL_SIZE 4096
void JPXStream::init()
{
Object oLen;
if (getDict()) getDict()->lookup("Length", &oLen);
int bufSize = BUFFER_INCREASE;
int bufSize = BUFFER_INITIAL_SIZE;
if (oLen.isInt()) bufSize = oLen.getInt();
oLen.free();
unsigned char *buf = (unsigned char*)gmallocn(bufSize, sizeof(unsigned char));
int index = 0;
str->reset();
int c = str->getChar();
while(c != EOF)
{
if (index >= bufSize)
{
bufSize += BUFFER_INCREASE;
buf = (unsigned char*)greallocn(buf, bufSize, sizeof(unsigned char));
}
buf[index] = c;
++index;
c = str->getChar();
}
init2(buf, index, CODEC_JP2);
int length = 0;
unsigned char *buf = str->toUnsignedChars(&length, bufSize);
init2(buf, length, CODEC_JP2);
free(buf);
counter = 0;
......@@ -143,30 +135,7 @@ error:
}
int JPXStream::lookChar() {
if (inited == gFalse) init();
if (!image) return EOF;
int w = image->comps[0].w;
int h = image->comps[0].h;
int y = (counter / image->numcomps) / w;
int x = (counter / image->numcomps) % w;
if (y >= h) return EOF;
int component = counter % image->numcomps;
int adjust = 0;
if (image->comps[component].prec > 8) {
adjust = image->comps[component].prec - 8;
}
int r = image->comps[component].data[y * w + x];
r += (image->comps[component].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
unsigned char rc = (unsigned char) ((r >> adjust)+((r >> (adjust-1))%2));
return rc;
return doLookChar();
}
GooString *JPXStream::getPSFilter(int psLevel, char *indent) {
......
......@@ -4,7 +4,7 @@
//
// A JPX stream decoder using OpenJPEG
//
// Copyright 2008 Albert Astals Cid <aacid@kde.org>
// Copyright 2008, 2010 Albert Astals Cid <aacid@kde.org>
//
// Licensed under GPLv2 or later
//
......@@ -39,6 +39,42 @@ private:
void init();
void init2(unsigned char *buf, int bufLen, OPJ_CODEC_FORMAT format);
virtual GBool hasGetChars() { return true; }
virtual int getChars(int nChars, Guchar *buffer);
inline int doGetChar() {
int result = doLookChar();
++counter;
return result;
}
inline int doLookChar() {
if (inited == gFalse) init();
if (!image) return EOF;
int w = image->comps[0].w;
int h = image->comps[0].h;
int y = (counter / image->numcomps) / w;
int x = (counter / image->numcomps) % w;
if (y >= h) return EOF;
int component = counter % image->numcomps;
int adjust = 0;
if (image->comps[component].prec > 8) {
adjust = image->comps[component].prec - 8;
}
int r = image->comps[component].data[y * w + x];
r += (image->comps[component].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
unsigned char rc = (unsigned char) ((r >> adjust)+((r >> (adjust-1))%2));
return rc;
}
opj_image_t *image;
opj_dinfo_t *dinfo;
int counter;
......
......@@ -16,7 +16,7 @@
// Copyright (C) 2006, 2008 Pino Toscano <pino@kde.org>
// Copyright (C) 2007,2010 Carlos Garcia Campos <carlosgc@gnome.org>
// Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com>
// Copyright (C) 2008, 2009 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2008-2010 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
// Copyright (C) 2009 Ilya Gorenbein <igorenbein@finjan.com>
//
......@@ -704,11 +704,7 @@ LinkRendition::LinkRendition(Object *obj) {
} else if (tmp.isStream()) {
Stream *stream = tmp.getStream();
js = new GooString();
stream->reset();
int i;
while ((i = stream->getChar()) != EOF) {
js->append((char)i);
}
stream->fillGooString(js);
} else {
error(-1, "Invalid Rendition Action: JS not string or stream");
}
......@@ -766,11 +762,7 @@ LinkJavaScript::LinkJavaScript(Object *jsObj) {
else if (jsObj->isStream()) {
Stream *stream = jsObj->getStream();
js = new GooString();
stream->reset();
int i;
while ((i = stream->getChar()) != EOF) {
js->append((char)i);
}
stream->fillGooString(js);
}
}
......
......@@ -223,6 +223,7 @@ public:
void streamReset();
void streamClose();
int streamGetChar();
int streamGetChars(int nChars, Guchar *buffer);
int streamLookChar();
char *streamGetLine(char *buf, int size);
Guint streamGetPos();
......@@ -334,6 +335,9 @@ inline void Object::streamClose()
inline int Object::streamGetChar()
{ OBJECT_TYPE_CHECK(objStream); return stream->getChar(); }
inline int Object::streamGetChars(int nChars, Guchar *buffer)
{ OBJECT_TYPE_CHECK(objStream); return stream->doGetChars(nChars, buffer); }
inline int Object::streamLookChar()
{ OBJECT_TYPE_CHECK(objStream); return stream->lookChar(); }
......
......@@ -14,7 +14,7 @@
// under GPL version 2 or later
//
// Copyright (C) 2005 Jeff Muizelaar <jeff@infidigm.net>
// Copyright (C) 2006-2009 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2006-2010 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2007 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
// Copyright (C) 2008 Julien Rebetez <julien@fhtagn.net>
// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
......@@ -99,6 +99,15 @@ int Stream::getRawChar() {
return EOF;
}
int Stream::getChars(int nChars, Guchar *buffer) {
error(-1, "Internal: called getChars() on non-predictor stream");
return 0;
}
void Stream::getRawChars(int nChars, int *buffer) {
error(-1, "Internal: called getRawChars() on non-predictor stream");
}
char *Stream::getLine(char *buf, int size) {
int i;
int c;
......@@ -461,9 +470,8 @@ Guchar *ImageStream::getLine() {
}
} else if (nBits == 8) {
Guchar *line = imgLine;
for (i = 0; i < nVals; ++i) {
*line++ = str->getChar();
}
int readChars = str->doGetChars(nVals, line);
for ( ; readChars < nVals; readChars++) line[readChars] = EOF;
} else if (nBits == 16) {
// this is a hack to support 16 bits images, everywhere
// we assume a component fits in 8 bits, with this hack
......@@ -543,12 +551,17 @@ int StreamPredictor::lookChar() {
}
int StreamPredictor::getChar() {
if (predIdx >= rowBytes) {
if (!getNextLine()) {
return EOF;
}
return doGetChar();
}
int StreamPredictor::getChars(int nChars, Guchar *buffer)
{
for (int i = 0; i < nChars; ++i) {
const int c = doGetChar();
if (likely(c != EOF)) buffer[i] = c;
else return i;
}
return predLine[predIdx++];
return nChars;
}
GBool StreamPredictor::getNextLine() {
......@@ -571,13 +584,15 @@ GBool StreamPredictor::getNextLine() {
}
// read the raw line, apply PNG (byte) predictor
int *rawCharLine = new int[rowBytes - pixBytes];
str->getRawChars(rowBytes - pixBytes, rawCharLine);
memset(upLeftBuf, 0, pixBytes + 1);
for (i = pixBytes; i < rowBytes; ++i) {
for (j = pixBytes; j > 0; --j) {
upLeftBuf[j] = upLeftBuf[j-1];
}
upLeftBuf[0] = predLine[i];
if ((c = str->getRawChar()) == EOF) {
if ((c = rawCharLine[i - pixBytes]) == EOF) {
if (i > pixBytes) {
// this ought to return false, but some (broken) PDF files
// contain truncated image data, and Adobe apparently reads the
......@@ -621,6 +636,7 @@ GBool StreamPredictor::getNextLine() {
break;
}
}
delete[] rawCharLine;
// apply TIFF (component) predictor
if (predictor == 2) {
......@@ -1237,16 +1253,13 @@ int LZWStream::lookChar() {
return seqBuf[seqIndex];
}
void LZWStream::getRawChars(int nChars, int *buffer) {
for (int i = 0; i < nChars; ++i)
buffer[i] = doGetRawChar();
}
int LZWStream::getRawChar() {
if (eof) {
return EOF;
}
if (seqIndex >= seqLength) {
if (!processNextCode()) {
return EOF;
}
}
return seqBuf[seqIndex++];
return doGetRawChar();
}
void LZWStream::reset() {
......@@ -4231,20 +4244,20 @@ void FlateStream::reset() {
}
int FlateStream::getChar() {
int c;
return doGetChar();
}
int FlateStream::getChars(int nChars, Guchar *buffer) {
if (pred) {
return pred->getChar();
}
while (remain == 0) {
if (endOfBlock && eof)
return EOF;
readSome();
return pred->getChars(nChars, buffer);
} else {
for (int i = 0; i < nChars; ++i) {
const int c = doGetChar();
if (likely(c != EOF)) buffer[i] = c;
else return i;
}
return nChars;
}
c = buf[index];
index = (index + 1) & flateMask;
--remain;
return c;
}
int FlateStream::lookChar() {
......@@ -4262,18 +4275,13 @@ int FlateStream::lookChar() {
return c;
}
int FlateStream::getRawChar() {
int c;
void FlateStream::getRawChars(int nChars, int *buffer) {
for (int i = 0; i < nChars; ++i)
buffer[i] = doGetRawChar();
}
while (remain == 0) {
if (endOfBlock && eof)
return EOF;
readSome();
}
c = buf[index];
index = (index + 1) & flateMask;
--remain;
return c;
int FlateStream::getRawChar() {
return doGetRawChar();
}
GooString *FlateStream::getPSFilter(int psLevel, char *indent) {
......
......@@ -15,7 +15,7 @@
//
// Copyright (C) 2005 Jeff Muizelaar <jeff@infidigm.net>
// Copyright (C) 2008 Julien Rebetez <julien@fhtagn.net>
// Copyright (C) 2008 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2008, 2010 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
// Copyright (C) 2009 Stefan Thomas <thomas@eload24.com>
// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
......@@ -106,6 +106,56 @@ public:
// Close down the stream.
virtual void close();
inline int doGetChars(int nChars, Guchar *buffer)
{
if (hasGetChars()) {
return getChars(nChars, buffer);
} else {
for (int i = 0; i < nChars; ++i) {
const int c = getChar();
if (likely(c != EOF)) buffer[i] = c;
else return i;
}
return nChars;
}
}
inline void fillGooString(GooString *s)
{
Guchar readBuf[4096];
int readChars;
reset();
while ((readChars = doGetChars(4096, readBuf)) != 0) {
s->append((const char *)readBuf, readChars);
}
}
inline Guchar *toUnsignedChars(int *length, int initialSize = 4096, int sizeIncrement = 4096)
{
int readChars;
Guchar *buf = (Guchar *)gmalloc(initialSize);
int size = initialSize;
*length = 0;
int charsToRead = initialSize;
bool continueReading = true;
reset();
while (continueReading && (readChars = doGetChars(charsToRead, &buf[*length])) != 0) {
*length += readChars;
if (readChars == charsToRead) {
if (lookChar() != EOF) {
size += sizeIncrement;
charsToRead = initialSize;
buf = (Guchar *)grealloc(buf, size);
} else {
continueReading = false;
}
} else {
continueReading = false;
}
}
return buf;
}
// Get next char from stream.
virtual int getChar() = 0;
......@@ -115,6 +165,7 @@ public:
// Get next char from stream without using the predictor.
// This is only used by StreamPredictor.
virtual int getRawChar();
virtual void getRawChars(int nChars, int *buffer);
// Get next char directly from stream source, without filtering it
virtual int getUnfilteredChar () = 0;
......@@ -166,6 +217,8 @@ public:
Stream *addFilters(Object *dict);
private:
virtual GBool hasGetChars() { return false; }
virtual int getChars(int nChars, Guchar *buffer);
Stream *makeFilter(char *name, Stream *str, Object *params);
......@@ -347,11 +400,21 @@ public:
int lookChar();
int getChar();
int getChars(int nChars, Guchar *buffer);
private:
GBool getNextLine();
inline int doGetChar() {
if (predIdx >= rowBytes) {
if (!getNextLine()) {
return EOF;
}
}
return predLine[predIdx++];
}
Stream *str; // base stream
int predictor; // predictor
int width; // pixels per line
......@@ -383,7 +446,7 @@ public:
virtual void reset();
virtual void close();
virtual int getChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
{ return doGetChar(); }
virtual int lookChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
virtual int getPos() { return bufPos + (bufPtr - buf); }
......@@ -397,6 +460,20 @@ public:
private:
GBool fillBuf();
inline int doGetChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
virtual GBool hasGetChars() { return true; }
virtual int getChars(int nChars, Guchar *buffer)
{
for (int i = 0; i < nChars; ++i) {
const int c = doGetChar();
if (likely(c != EOF)) buffer[i] = c;
else return i;
}
return nChars;
}
FILE *f;
Guint start;
......@@ -596,11 +673,24 @@ public:
virtual int getChar();
virtual int lookChar();
virtual int getRawChar();
virtual void getRawChars(int nChars, int *buffer);
virtual GooString *getPSFilter(int psLevel, char *indent);
virtual GBool isBinary(GBool last = gTrue);
private:
inline int doGetRawChar() {
if (eof) {
return EOF;
}
if (seqIndex >= seqLength) {
if (!processNextCode()) {
return EOF;
}
}
return seqBuf[seqIndex++];
}
StreamPredictor *pred; // predictor
int early; // early parameter
GBool eof; // true if at eof
......@@ -855,11 +945,35 @@ public:
virtual int getChar();
virtual int lookChar();
virtual int getRawChar();
virtual void getRawChars(int nChars, int *buffer);
virtual GooString *getPSFilter(int psLevel, char *indent);