Bug 411334. Try optimistically to not use a temporary group for SVG drawing on Mac. If drawing fails we try again with a temporary group. r+sr=vlad
authorroc+@cs.cmu.edu
Wed, 09 Jan 2008 14:53:59 -0800
changeset 10103 814abbe356b8e2a1dfc17d8583160a4a98a56552
parent 10102 e49f72c2098e36e89d6617e83df24d309482aa9d
child 10104 1d87279f0487e1d6d48d6a94e5185fda0fdb3b79
push idunknown
push userunknown
push dateunknown
bugs411334
milestone1.9b3pre
Bug 411334. Try optimistically to not use a temporary group for SVG drawing on Mac. If drawing fails we try again with a temporary group. r+sr=vlad
gfx/thebes/public/gfxContext.h
gfx/thebes/src/gfxContext.cpp
layout/svg/base/src/nsSVGOuterSVGFrame.cpp
layout/svg/base/src/nsSVGOuterSVGFrame.h
--- a/gfx/thebes/public/gfxContext.h
+++ b/gfx/thebes/public/gfxContext.h
@@ -93,16 +93,21 @@ public:
 
     /**
      * Return the raw cairo_t object.
      * XXX this should go away at some point.
      */
     cairo_t *GetCairo() { return mCairo; }
 
     /**
+     * Returns true if the cairo context is in an error state.
+     */
+    PRBool HasError();
+
+    /**
      ** State
      **/
     // XXX document exactly what bits are saved
     void Save();
     void Restore();
 
     /**
      ** Paths & Drawing
--- a/gfx/thebes/src/gfxContext.cpp
+++ b/gfx/thebes/src/gfxContext.cpp
@@ -759,8 +759,14 @@ gfxContext::GetUserStrokeExtent()
 already_AddRefed<gfxFlattenedPath>
 gfxContext::GetFlattenedPath()
 {
     gfxFlattenedPath *path =
         new gfxFlattenedPath(cairo_copy_path_flat(mCairo));
     NS_IF_ADDREF(path);
     return path;
 }
+
+PRBool
+gfxContext::HasError()
+{
+     return cairo_status(mCairo) != CAIRO_STATUS_SUCCESS;
+}
--- a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp
@@ -151,20 +151,23 @@ NS_NewSVGOuterSVGFrame(nsIPresShell* aPr
     NS_ERROR("Can't create frame! Content is not an SVG 'svg' element!");
     return nsnull;
   }
 
   return new (aPresShell) nsSVGOuterSVGFrame(aContext);
 }
 
 nsSVGOuterSVGFrame::nsSVGOuterSVGFrame(nsStyleContext* aContext)
-    : nsSVGOuterSVGFrameBase(aContext),
-      mRedrawSuspendCount(0),
-      mFullZoom(0),
-      mViewportInitialized(PR_FALSE)
+    : nsSVGOuterSVGFrameBase(aContext)
+    ,  mRedrawSuspendCount(0)
+    , mFullZoom(0)
+    , mViewportInitialized(PR_FALSE)
+#ifdef XP_MACOSX
+    , mEnableBitmapFallback(PR_FALSE)
+#endif
 {
 }
 
 NS_IMETHODIMP
 nsSVGOuterSVGFrame::Init(nsIContent* aContent,
                          nsIFrame* aParent,
                          nsIFrame* aPrevInFlow)
 {
@@ -575,32 +578,55 @@ nsSVGOuterSVGFrame::Paint(nsIRenderingCo
 #if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
   PRTime start = PR_Now();
 #endif
 
   dirtyRect.ScaleRoundOut(1.0f / PresContext()->AppUnitsPerDevPixel());
 
   nsSVGRenderState ctx(&aRenderingContext);
 
-  // nquartz fallback paths, which svg tends to trigger, need
-  // a non-window context target
 #ifdef XP_MACOSX
-  ctx.GetGfxContext()->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
+  if (mEnableBitmapFallback) {
+    // nquartz fallback paths, which svg tends to trigger, need
+    // a non-window context target
+    ctx.GetGfxContext()->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
+  }
 #endif
 
   // paint children:
   for (nsIFrame* kid = mFrames.FirstChild(); kid;
        kid = kid->GetNextSibling()) {
     nsSVGUtils::PaintChildWithEffects(&ctx, &dirtyRect, kid);
   }
 
-// show the surface we pushed earlier for nquartz fallbacks
 #ifdef XP_MACOSX
-  ctx.GetGfxContext()->PopGroupToSource();
-  ctx.GetGfxContext()->Paint();
+  if (mEnableBitmapFallback) {
+    // show the surface we pushed earlier for fallbacks
+    ctx.GetGfxContext()->PopGroupToSource();
+    ctx.GetGfxContext()->Paint();
+  }
+  
+  if (ctx.GetGfxContext()->HasError() && !mEnableBitmapFallback) {
+    mEnableBitmapFallback = PR_TRUE;
+    // It's not really clear what area to invalidate here. We might have
+    // stuffed up rendering for the entire window in this paint pass,
+    // so we can't just invalidate our own rect. Invalidate everything
+    // in sight.
+    // This won't work for printing, by the way, but failure to print the
+    // odd document is probably no worse than printing horribly for all
+    // documents. Better to fix things so we don't need fallback.
+    nsIFrame* frame = this;
+    while (PR_TRUE) {
+      nsIFrame* next = nsLayoutUtils::GetCrossDocParentFrame(frame);
+      if (!next)
+        break;
+      frame = next;
+    }
+    frame->Invalidate(nsRect(nsPoint(0, 0), frame->GetSize()));
+  }
 #endif
 
 #if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
   PRTime end = PR_Now();
   printf("SVG Paint Timing: %f ms\n", (end-start)/1000.0);
 #endif
   
   aRenderingContext.PopState();
--- a/layout/svg/base/src/nsSVGOuterSVGFrame.h
+++ b/layout/svg/base/src/nsSVGOuterSVGFrame.h
@@ -166,11 +166,14 @@ protected:
 
   // zoom and pan
   nsCOMPtr<nsIDOMSVGPoint>  mCurrentTranslate;
   nsCOMPtr<nsIDOMSVGNumber> mCurrentScale;
 
   float mFullZoom;
 
   PRPackedBool mViewportInitialized;
+#ifdef XP_MACOSX
+  PRPackedBool mEnableBitmapFallback;
+#endif
 };
 
 #endif