Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDGraphicsState.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDGraphicsState.java	(revision 1601390)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDGraphicsState.java	(working copy)
@@ -438,11 +438,7 @@
             if( lineDashPattern != null )
             {
                 clone.setLineDashPattern( lineDashPattern ); // immutable
-            }
-            if (currentClippingPath != null)
-            {
-                clone.setCurrentClippingPath((GeneralPath)currentClippingPath.clone());
-            }
+            }            
         }
         catch( CloneNotSupportedException e )
         {
@@ -559,6 +555,8 @@
 
     /**
      * This will get the current clipping path.
+     * WARNING: The returned Shape is not immutable, but not expected
+     * to be modified outside of this class.
      *
      * @return The current clipping path.
      */
Index: pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java	(revision 1601390)
+++ pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java	(working copy)
@@ -25,6 +25,7 @@
 import java.awt.Image;
 import java.awt.Paint;
 import java.awt.RenderingHints;
+import java.awt.Shape;
 import java.awt.font.FontRenderContext;
 import java.awt.font.GlyphVector;
 import java.awt.geom.AffineTransform;
@@ -93,6 +94,7 @@
     // parent document renderer
     private final PDFRenderer renderer;
 
+    private Shape lastClip;
     private Graphics2D graphics;
 
     // clipping winding rule used for the clipping path.
@@ -191,6 +193,7 @@
                             at.transform(point, point);
                         }
                         graphics.translate((int) point.getX(), -(int) point.getY());
+                        lastClip = null;
                         processSubStream(appearance.getResources(), appearance.getStream());
                         graphics.translate(-(int) point.getX(), (int) point.getY());
                     }
@@ -300,8 +303,7 @@
             PDFont font = text.getFont();
             AffineTransform at = text.getTextPos().createAffineTransform();
             PDMatrix fontMatrix = font.getFontMatrix();
-            // TODO setClip() is a massive performance hot spot. Investigate optimization possibilities
-            graphics.setClip(graphicsState.getCurrentClippingPath());
+            applyClipping();
 
             // use different methods to draw the string
             if (font.isType3Font())
@@ -336,6 +338,15 @@
             LOG.error (io, io);
         }
     }
+    
+    private void applyClipping()
+    {        
+        Shape clip = getGraphicsState().getCurrentClippingPath();
+        if(clip != lastClip) { // || !compareTransform(lastClipTransform, graphics.getTransform())) {
+            graphics.setClip(clip);
+            lastClip = clip;
+        }
+    }
 
     /**
      * Render the font using the Glyph2d interface.
@@ -686,7 +697,7 @@
         graphics.setPaint(strokingPaint);
         graphics.setStroke(getStroke());
         graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
-        graphics.setClip(getGraphicsState().getCurrentClippingPath());
+        applyClipping();
         graphics.draw(linePath);
         linePath.reset();
     }
@@ -711,7 +722,7 @@
         graphics.setPaint(nonStrokingPaint);
         linePath.setWindingRule(windingRule);
         graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
-        graphics.setClip(getGraphicsState().getCurrentClippingPath());
+        applyClipping();
         graphics.fill(linePath);
         linePath.reset();
     }
@@ -784,12 +795,13 @@
         if (clippingWindingRule > -1)
         {
             PDGraphicsState graphicsState = getGraphicsState();
-            GeneralPath clippingPath = (GeneralPath) linePath.clone();  // TODO do we really need to clone this? isn't the line path reset anyway?
+            GeneralPath clippingPath = linePath; 
             clippingPath.setWindingRule(clippingWindingRule);
             // If there is already set a clipping path, we have to intersect the new with the existing one
             if (graphicsState.getCurrentClippingPath() != null)
             {
                 Area currentArea = new Area(getGraphicsState().getCurrentClippingPath());
+                
                 Area newArea = new Area(clippingPath);
                 currentArea.intersect(newArea);
                 graphicsState.setCurrentClippingPath(currentArea);
@@ -800,7 +812,9 @@
             }
             clippingWindingRule = -1;
         }
-        linePath.reset();
+        // Do not touch the original linePath any more as we assigned it to graphic state clippingPath
+        // Use new instead of linePath.reset()
+        linePath = new GeneralPath();
     }
 
     /**
@@ -814,7 +828,7 @@
     public void drawImage(Image awtImage, AffineTransform at)
     {
         graphics.setComposite(getGraphicsState().getNonStrokeJavaComposite());
-        graphics.setClip(getGraphicsState().getCurrentClippingPath());
+        applyClipping();
         int width = awtImage.getWidth(null);
         int height = awtImage.getHeight(null);
         AffineTransform imageTransform = new AffineTransform(at);
