Splash rework, check if font is inside clip area before rendering it to a temporary bitmap. Fixes bug 150693

This change is not trivial. What i did is:
It is getGlyph the one that does the intersection between clip area and rendering area of the font instead fillGlyph2
That means some clipRes = state->clip->testRect but we win more robustness against broken pdf that specify HUGE fonts

BUG: 150693

svn path=/branches/KDE/3.5/kdegraphics/kpdf/; revision=728256
remotes/origin/kpdf-3.5
Albert Astals Cid 19 years ago
parent f2e72a9f66
commit 7bad8214a8
  1. 19
      xpdf/goo/gmem.cc
  2. 1
      xpdf/goo/gmem.h
  3. 37
      xpdf/splash/Splash.cc
  4. 4
      xpdf/splash/Splash.h
  5. 24
      xpdf/splash/SplashFTFont.cc
  6. 4
      xpdf/splash/SplashFTFont.h
  7. 29
      xpdf/splash/SplashFont.cc
  8. 5
      xpdf/splash/SplashFont.h
  9. 11
      xpdf/splash/SplashT1Font.cc
  10. 4
      xpdf/splash/SplashT1Font.h

@ -172,6 +172,25 @@ void *gmallocn(int nObjs, int objSize) GMEM_EXCEP {
return gmalloc(n);
}
void *gmallocn_checkoverflow(int nObjs, int objSize) GMEM_EXCEP {
int n;
if (nObjs == 0) {
return NULL;
}
n = nObjs * objSize;
if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) {
#if USE_EXCEPTIONS
throw GMemException();
#else
fprintf(stderr, "Bogus memory allocation size\n");
return NULL;
#endif
}
return gmalloc(n);
}
void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP {
int n;

@ -52,6 +52,7 @@ extern void *grealloc(void *p, int size) GMEM_EXCEP;
*/
extern void *gmallocn(int nObjs, int objSize) GMEM_EXCEP;
extern void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP;
extern void *gmallocn_checkoverflow(int nObjs, int objSize) GMEM_EXCEP;
/*
* Same as free, but checks for and ignores NULL pointers.

@ -1626,7 +1626,7 @@ SplashError Splash::fillChar(SplashCoord x, SplashCoord y,
SplashGlyphBitmap glyph;
SplashCoord xt, yt;
int x0, y0, xFrac, yFrac;
SplashError err;
SplashClipResult clipRes;
if (debugMode) {
printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n",
@ -1637,17 +1637,20 @@ SplashError Splash::fillChar(SplashCoord x, SplashCoord y,
xFrac = splashFloor((xt - x0) * splashFontFraction);
y0 = splashFloor(yt);
yFrac = splashFloor((yt - y0) * splashFontFraction);
if (!font->getGlyph(c, xFrac, yFrac, &glyph)) {
if (!font->getGlyph(c, xFrac, yFrac, &glyph, x0, y0, state->clip, &clipRes)) {
return splashErrNoGlyph;
}
err = fillGlyph2(x0, y0, &glyph);
if (clipRes != splashClipAllOutside) {
fillGlyph2(x0, y0, &glyph, clipRes == splashClipAllInside);
}
opClipRes = clipRes;
if (glyph.freeData) {
gfree(glyph.data);
}
return err;
return splashOk;
}
SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y,
void Splash::fillGlyph(SplashCoord x, SplashCoord y,
SplashGlyphBitmap *glyph) {
SplashCoord xt, yt;
int x0, y0;
@ -1655,24 +1658,22 @@ SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y,
transform(state->matrix, x, y, &xt, &yt);
x0 = splashFloor(xt);
y0 = splashFloor(yt);
return fillGlyph2(x0, y0, glyph);
SplashClipResult clipRes = state->clip->testRect(x0 - glyph->x,
y0 - glyph->y,
x0 - glyph->x + glyph->w - 1,
y0 - glyph->y + glyph->h - 1);
if (clipRes != splashClipAllOutside) {
fillGlyph2(x0, y0, glyph, clipRes == splashClipAllInside);
}
opClipRes = clipRes;
}
SplashError Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph) {
void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip) {
SplashPipe pipe;
SplashClipResult clipRes;
GBool noClip;
int alpha0, alpha;
Guchar *p;
int x1, y1, xx, xx1, yy;
if ((clipRes = state->clip->testRect(x0 - glyph->x,
y0 - glyph->y,
x0 - glyph->x + glyph->w - 1,
y0 - glyph->y + glyph->h - 1))
!= splashClipAllOutside) {
noClip = clipRes == splashClipAllInside;
if (noClip) {
if (glyph->aa) {
pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y,
@ -1763,10 +1764,6 @@ SplashError Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph) {
}
}
}
}
opClipRes = clipRes;
return splashOk;
}
SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,

@ -151,7 +151,7 @@ public:
// Draw a glyph, using the current fill pattern. This function does
// not free any data, i.e., it ignores glyph->freeData.
SplashError fillGlyph(SplashCoord x, SplashCoord y,
void fillGlyph(SplashCoord x, SplashCoord y,
SplashGlyphBitmap *glyph);
// Draws an image mask using the fill color. This will read <h>
@ -267,7 +267,7 @@ private:
SplashPath *makeDashedPath(SplashPath *xPath);
SplashError fillWithPattern(SplashPath *path, GBool eo,
SplashPattern *pattern, SplashCoord alpha);
SplashError fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph);
void fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noclip);
void dumpPath(SplashPath *path);
void dumpXPath(SplashXPath *path);

@ -147,12 +147,12 @@ SplashFTFont::~SplashFTFont() {
}
GBool SplashFTFont::getGlyph(int c, int xFrac, int /*yFrac*/,
SplashGlyphBitmap *bitmap) {
return SplashFont::getGlyph(c, xFrac, 0, bitmap);
SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
return SplashFont::getGlyph(c, xFrac, 0, bitmap, x0, y0, clip, clipRes);
}
GBool SplashFTFont::makeGlyph(int c, int xFrac, int /*yFrac*/,
SplashGlyphBitmap *bitmap) {
SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
SplashFTFontFile *ff;
FT_Vector offset;
FT_GlyphSlot slot;
@ -196,6 +196,24 @@ GBool SplashFTFont::makeGlyph(int c, int xFrac, int /*yFrac*/,
return gFalse;
}
#endif
FT_Glyph_Metrics *glyphMetrics = &(ff->face->glyph->metrics);
// prelimirary values from FT_Glyph_Metrics
bitmap->x = splashRound(-glyphMetrics->horiBearingX / 64.0);
bitmap->y = splashRound(glyphMetrics->horiBearingY / 64.0);
bitmap->w = splashRound(glyphMetrics->width / 64.0);
bitmap->h = splashRound(glyphMetrics->height / 64.0);
*clipRes = clip->testRect(x0 - bitmap->x,
y0 - bitmap->y,
x0 - bitmap->x + bitmap->w - 1,
y0 - bitmap->y + bitmap->h - 1);
if (*clipRes == splashClipAllOutside)
{
bitmap->freeData = gFalse;
return gTrue;
}
if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal
: ft_render_mode_mono)) {
return gFalse;

@ -35,12 +35,12 @@ public:
// Munge xFrac and yFrac before calling SplashFont::getGlyph.
virtual GBool getGlyph(int c, int xFrac, int yFrac,
SplashGlyphBitmap *bitmap);
SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes);
// Rasterize a glyph. The <xFrac> and <yFrac> values are the same
// as described for getGlyph.
virtual GBool makeGlyph(int c, int xFrac, int yFrac,
SplashGlyphBitmap *bitmap);
SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes);
// Return the path for a glyph.
virtual SplashPath *getGlyphPath(int c);

@ -74,11 +74,15 @@ void SplashFont::initCache() {
} else {
cacheSets = 1;
}
cache = (Guchar *)gmallocn(cacheSets * cacheAssoc, glyphSize);
cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc,
cache = (Guchar *)gmallocn_checkoverflow(cacheSets * cacheAssoc, glyphSize);
if (cache != NULL) {
cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc,
sizeof(SplashFontCacheTag));
for (i = 0; i < cacheSets * cacheAssoc; ++i) {
cacheTags[i].mru = i & (cacheAssoc - 1);
for (i = 0; i < cacheSets * cacheAssoc; ++i) {
cacheTags[i].mru = i & (cacheAssoc - 1);
}
} else {
cacheAssoc = 0;
}
}
@ -93,7 +97,7 @@ SplashFont::~SplashFont() {
}
GBool SplashFont::getGlyph(int c, int xFrac, int yFrac,
SplashGlyphBitmap *bitmap) {
SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
SplashGlyphBitmap bitmap2;
int size;
Guchar *p;
@ -127,15 +131,28 @@ GBool SplashFont::getGlyph(int c, int xFrac, int yFrac,
bitmap->aa = aa;
bitmap->data = cache + (i+j) * glyphSize;
bitmap->freeData = gFalse;
*clipRes = clip->testRect(x0 - bitmap->x,
y0 - bitmap->y,
x0 - bitmap->x + bitmap->w - 1,
y0 - bitmap->y + bitmap->h - 1);
return gTrue;
}
}
// generate the glyph bitmap
if (!makeGlyph(c, xFrac, yFrac, &bitmap2)) {
if (!makeGlyph(c, xFrac, yFrac, &bitmap2, x0, y0, clip, clipRes)) {
return gFalse;
}
if (*clipRes == splashClipAllOutside)
{
bitmap->freeData = gFalse;
if (bitmap2.freeData) gfree(bitmap2.data);
return gTrue;
}
// if the glyph doesn't fit in the bounding box, return a temporary
// uncached bitmap
if (bitmap2.w > glyphW || bitmap2.h > glyphH) {

@ -15,6 +15,7 @@
#include "gtypes.h"
#include "SplashTypes.h"
#include "SplashClip.h"
struct SplashGlyphBitmap;
struct SplashFontCacheTag;
@ -66,12 +67,12 @@ public:
// should override this to zero out xFrac and/or yFrac if they don't
// support fractional coordinates.
virtual GBool getGlyph(int c, int xFrac, int yFrac,
SplashGlyphBitmap *bitmap);
SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes);
// Rasterize a glyph. The <xFrac> and <yFrac> values are the same
// as described for getGlyph.
virtual GBool makeGlyph(int c, int xFrac, int yFrac,
SplashGlyphBitmap *bitmap) = 0;
SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) = 0;
// Return the path for a glyph.
virtual SplashPath *getGlyphPath(int c) = 0;

@ -176,12 +176,12 @@ SplashT1Font::~SplashT1Font() {
}
GBool SplashT1Font::getGlyph(int c, int xFrac, int yFrac,
SplashGlyphBitmap *bitmap) {
return SplashFont::getGlyph(c, 0, 0, bitmap);
SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
return SplashFont::getGlyph(c, 0, 0, bitmap, x0, y0, clip, clipRes);
}
GBool SplashT1Font::makeGlyph(int c, int xFrac, int yFrac,
SplashGlyphBitmap *bitmap) {
SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
GLYPH *glyph;
int n, i;
@ -211,6 +211,11 @@ GBool SplashT1Font::makeGlyph(int c, int xFrac, int yFrac,
bitmap->freeData = gTrue;
}
*clipRes = clip->testRect(x0 - bitmap->x,
y0 - bitmap->y,
x0 - bitmap->x + bitmap->w - 1,
y0 - bitmap->y + bitmap->h - 1);
return gTrue;
}

@ -33,12 +33,12 @@ public:
// Munge xFrac and yFrac before calling SplashFont::getGlyph.
virtual GBool getGlyph(int c, int xFrac, int yFrac,
SplashGlyphBitmap *bitmap);
SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes);
// Rasterize a glyph. The <xFrac> and <yFrac> values are the same
// as described for getGlyph.
virtual GBool makeGlyph(int c, int xFrac, int yFrac,
SplashGlyphBitmap *bitmap);
SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes);
// Return the path for a glyph.
virtual SplashPath *getGlyphPath(int c);

Loading…
Cancel
Save