Bug 740200 - BorrowedContext support for cairo; r=mattwoodrow
authorAnthony Jones <ajones@mozilla.com>
Fri, 20 Sep 2013 14:00:35 +1200
changeset 148006 e649d78553ec849a501a04ea52b538b60a933de2
parent 148005 d70c5c90f07702dd3257257c3410e43674afd308
child 148007 cebeca8df9863637df466b5165a33f2681198757
push id34072
push userajones@mozilla.com
push dateFri, 20 Sep 2013 02:00:42 +0000
treeherdermozilla-inbound@d074ae862d16 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs740200
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 740200 - BorrowedContext support for cairo; r=mattwoodrow
gfx/2d/2D.h
gfx/2d/DrawTargetCairo.cpp
gfx/2d/DrawTargetCairo.h
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -22,16 +22,19 @@
 // outparams using the &-operator. But it will have to do as there's no easy
 // solution.
 #include "mozilla/RefPtr.h"
 
 #ifdef MOZ_ENABLE_FREETYPE
 #include <string>
 #endif
 
+struct _cairo;
+typedef struct _cairo cairo_t;
+
 struct _cairo_surface;
 typedef _cairo_surface cairo_surface_t;
 
 struct _cairo_scaled_font;
 typedef _cairo_scaled_font cairo_scaled_font_t;
 
 struct ID3D10Device1;
 struct ID3D10Texture2D;
@@ -1012,16 +1015,70 @@ private:
   static ID3D11Device *mD3D11Device;
   static ID2D1Device *mD2D1Device;
 #endif
 #endif
 
   static DrawEventRecorder *mRecorder;
 };
 
+/* This is a helper class that let's you borrow a cairo_t from a
+ * DrawTargetCairo. This is used for drawing themed widgets.
+ *
+ * Callers should check the cr member after constructing the object
+ * to see if it succeeded. The DrawTarget should not be used while
+ * the context is borrowed. */
+class BorrowedCairoContext
+{
+public:
+  BorrowedCairoContext()
+    : mCairo(nullptr)
+    , mDT(nullptr)
+  { }
+
+  BorrowedCairoContext(DrawTarget *aDT)
+    : mDT(aDT)
+  {
+    mCairo = BorrowCairoContextFromDrawTarget(aDT);
+  }
+
+  // We can optionally Init after construction in
+  // case we don't know what the DT will be at construction
+  // time.
+  cairo_t *Init(DrawTarget *aDT)
+  {
+    MOZ_ASSERT(!mDT, "Can't initialize twice!");
+    mDT = aDT;
+    return mCairo = BorrowCairoContextFromDrawTarget(aDT);
+  }
+
+  // The caller needs to call Finish if cr is non-null when
+  // they are done with the context. This is currently explicit
+  // instead of happening implicitly in the destructor to make
+  // what's happening in the caller more clear. It also
+  // let's you resume using the DrawTarget in the same scope.
+  void Finish()
+  {
+    if (mCairo) {
+      ReturnCairoContextToDrawTarget(mDT, mCairo);
+      mCairo = nullptr;
+    }
+  }
+
+  ~BorrowedCairoContext() {
+    MOZ_ASSERT(!mCairo);
+  }
+
+  cairo_t *mCairo;
+private:
+  static cairo_t* BorrowCairoContextFromDrawTarget(DrawTarget *aDT);
+  static void ReturnCairoContextToDrawTarget(DrawTarget *aDT, cairo_t *aCairo);
+  DrawTarget *mDT;
+};
+
 #ifdef XP_MACOSX
 /* This is a helper class that let's you borrow a CGContextRef from a
  * DrawTargetCG. This is used for drawing themed widgets.
  *
  * Callers should check the cg member after constructing the object
  * to see if it succeeded. The DrawTarget should not be used while
  * the context is borrowed. */
 class BorrowedCGContext
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -1091,10 +1091,43 @@ DrawTargetCairo::SetTransform(const Matr
 {
   mTransform = aTransform;
 
   cairo_matrix_t mat;
   GfxMatrixToCairoMatrix(mTransform, mat);
   cairo_set_matrix(mContext, &mat);
 }
 
+cairo_t*
+BorrowedCairoContext::BorrowCairoContextFromDrawTarget(DrawTarget* aDT)
+{
+  if (aDT->GetType() != BACKEND_CAIRO || aDT->IsDualDrawTarget()) {
+    return nullptr;
+  }
+  DrawTargetCairo* cairoDT = static_cast<DrawTargetCairo*>(aDT);
+
+  cairoDT->WillChange();
+
+  // save the state to make it easier for callers to avoid mucking with things
+  cairo_save(cairoDT->mContext);
+
+  // Neuter the DrawTarget while the context is being borrowed
+  cairo_t* cairo = cairoDT->mContext;
+  cairoDT->mContext = nullptr;
+
+  return cairo;
+}
+
+void
+BorrowedCairoContext::ReturnCairoContextToDrawTarget(DrawTarget* aDT,
+                                                     cairo_t* aCairo)
+{
+  if (aDT->GetType() != BACKEND_CAIRO || aDT->IsDualDrawTarget()) {
+    return;
+  }
+  DrawTargetCairo* cairoDT = static_cast<DrawTargetCairo*>(aDT);
+
+  cairo_restore(aCairo);
+  cairoDT->mContext = aCairo;
+}
+
 }
 }
--- a/gfx/2d/DrawTargetCairo.h
+++ b/gfx/2d/DrawTargetCairo.h
@@ -46,16 +46,18 @@ class GradientStopsCairo : public Gradie
   private:
     std::vector<GradientStop> mStops;
     ExtendMode mExtendMode;
 };
 
 class DrawTargetCairo : public DrawTarget
 {
 public:
+  friend class BorrowedCairoContext;
+
   DrawTargetCairo();
   virtual ~DrawTargetCairo();
 
   virtual BackendType GetType() const { return BACKEND_CAIRO; }
   virtual TemporaryRef<SourceSurface> Snapshot();
   virtual IntSize GetSize();
 
   virtual void Flush();