Commit 2a333e5a authored by Albert Astals Cid's avatar Albert Astals Cid

Splash rework, check if font is inside clip area before rendering it to a...

Splash rework, check if font is inside clip area before rendering it to a temporary bitmap. Fixes KDE 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
parent cf785cd1
......@@ -1675,7 +1675,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",
......@@ -1686,17 +1686,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;
......@@ -1704,118 +1707,112 @@ 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,
state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse);
p = glyph->data;
for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
pipeSetXY(&pipe, x0 - glyph->x, y1);
for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) {
alpha = *p++;
if (alpha != 0) {
pipe.shape = (SplashCoord)(alpha / 255.0);
pipeRun(&pipe);
updateModX(x1);
updateModY(y1);
} else {
pipeIncX(&pipe);
}
}
}
} else {
pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y,
state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse);
p = glyph->data;
for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
pipeSetXY(&pipe, x0 - glyph->x, y1);
for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) {
alpha0 = *p++;
for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) {
if (alpha0 & 0x80) {
pipeRun(&pipe);
updateModX(x1);
updateModY(y1);
} else {
pipeIncX(&pipe);
}
alpha0 <<= 1;
}
}
}
if (noClip) {
if (glyph->aa) {
pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y,
state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse);
p = glyph->data;
for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
pipeSetXY(&pipe, x0 - glyph->x, y1);
for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) {
alpha = *p++;
if (alpha != 0) {
pipe.shape = (SplashCoord)(alpha / 255.0);
pipeRun(&pipe);
updateModX(x1);
updateModY(y1);
} else {
pipeIncX(&pipe);
}
}
}
} else {
if (glyph->aa) {
pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y,
state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse);
p = glyph->data;
for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
pipeSetXY(&pipe, x0 - glyph->x, y1);
for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) {
if (state->clip->test(x1, y1)) {
alpha = *p++;
if (alpha != 0) {
pipe.shape = (SplashCoord)(alpha / 255.0);
pipeRun(&pipe);
updateModX(x1);
updateModY(y1);
} else {
pipeIncX(&pipe);
}
} else {
pipeIncX(&pipe);
++p;
}
}
}
} else {
pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y,
state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse);
p = glyph->data;
for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
pipeSetXY(&pipe, x0 - glyph->x, y1);
for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) {
alpha0 = *p++;
for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) {
if (state->clip->test(x1, y1)) {
if (alpha0 & 0x80) {
pipeRun(&pipe);
updateModX(x1);
updateModY(y1);
} else {
pipeIncX(&pipe);
}
} else {
pipeIncX(&pipe);
}
alpha0 <<= 1;
}
}
}
pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y,
state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse);
p = glyph->data;
for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
pipeSetXY(&pipe, x0 - glyph->x, y1);
for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) {
alpha0 = *p++;
for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) {
if (alpha0 & 0x80) {
pipeRun(&pipe);
updateModX(x1);
updateModY(y1);
} else {
pipeIncX(&pipe);
}
alpha0 <<= 1;
}
}
}
}
} else {
if (glyph->aa) {
pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y,
state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse);
p = glyph->data;
for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
pipeSetXY(&pipe, x0 - glyph->x, y1);
for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) {
if (state->clip->test(x1, y1)) {
alpha = *p++;
if (alpha != 0) {
pipe.shape = (SplashCoord)(alpha / 255.0);
pipeRun(&pipe);
updateModX(x1);
updateModY(y1);
} else {
pipeIncX(&pipe);
}
} else {
pipeIncX(&pipe);
++p;
}
}
}
} else {
pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y,
state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse);
p = glyph->data;
for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) {
pipeSetXY(&pipe, x0 - glyph->x, y1);
for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) {
alpha0 = *p++;
for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) {
if (state->clip->test(x1, y1)) {
if (alpha0 & 0x80) {
pipeRun(&pipe);
updateModX(x1);
updateModY(y1);
} else {
pipeIncX(&pipe);
}
} else {
pipeIncX(&pipe);
}
alpha0 <<= 1;
}
}
}
}
}
opClipRes = clipRes;
return splashOk;
}
SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
......
......@@ -149,7 +149,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>
......@@ -265,7 +265,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,23 @@ 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;
......
......@@ -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);
......
......@@ -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) {
......
......@@ -13,6 +13,7 @@
#include "goo/gtypes.h"
#include "SplashTypes.h"
#include "SplashClip.h"
struct SplashGlyphBitmap;
struct SplashFontCacheTag;
......@@ -64,12 +65,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;
}
......
......@@ -31,12 +31,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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment