[poppler] splash/Splash.cc splash/SplashFont.cc splash/SplashFont.h splash/SplashFTFont.cc splash/SplashFTFont.h splash/Splash.h splash/SplashT1Font.cc splash/SplashT1Font.h

Albert Astals Cid aacid at kemper.freedesktop.org
Mon Oct 22 13:14:51 PDT 2007


 splash/Splash.cc       |  207 ++++++++++++++++++++++++-------------------------
 splash/Splash.h        |    4 
 splash/SplashFTFont.cc |   23 ++++-
 splash/SplashFTFont.h  |    4 
 splash/SplashFont.cc   |   29 +++++-
 splash/SplashFont.h    |    5 -
 splash/SplashT1Font.cc |   11 +-
 splash/SplashT1Font.h  |    4 
 8 files changed, 162 insertions(+), 125 deletions(-)

New commits:
commit 2a333e5a618b5c92f3c703816b950321f25d3aab
Author: Albert Astals Cid <tsdgeos at bluebox.localdomain>
Date:   Mon Oct 22 22:14:43 2007 +0200

    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

diff --git a/splash/Splash.cc b/splash/Splash.cc
index 45eb6fe..d9306fa 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -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,
diff --git a/splash/Splash.h b/splash/Splash.h
index 99203b2..58de95a 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -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);
 
diff --git a/splash/SplashFTFont.cc b/splash/SplashFTFont.cc
index 963d42d..0241df0 100644
--- a/splash/SplashFTFont.cc
+++ b/splash/SplashFTFont.cc
@@ -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;
diff --git a/splash/SplashFTFont.h b/splash/SplashFTFont.h
index f351b2f..70c01d3 100644
--- a/splash/SplashFTFont.h
+++ b/splash/SplashFTFont.h
@@ -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);
diff --git a/splash/SplashFont.cc b/splash/SplashFont.cc
index bea6fc9..9c34599 100644
--- a/splash/SplashFont.cc
+++ b/splash/SplashFont.cc
@@ -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) {
diff --git a/splash/SplashFont.h b/splash/SplashFont.h
index d3b0353..3af9412 100644
--- a/splash/SplashFont.h
+++ b/splash/SplashFont.h
@@ -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;
diff --git a/splash/SplashT1Font.cc b/splash/SplashT1Font.cc
index b30c0fc..87a51a7 100644
--- a/splash/SplashT1Font.cc
+++ b/splash/SplashT1Font.cc
@@ -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;
 }
 
diff --git a/splash/SplashT1Font.h b/splash/SplashT1Font.h
index 919dc03..d6816b8 100644
--- a/splash/SplashT1Font.h
+++ b/splash/SplashT1Font.h
@@ -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);


More information about the poppler mailing list