Bug 748116; Make DrawTargetCairo::DrawSurface work with non-Cairo source surfaces. r=roc
authorNicholas Cameron <ncameron@mozilla.com>
Tue, 24 Jul 2012 22:18:39 +1200
changeset 100618 7378179b373e1c9749e413fd7af9a18afdc94f13
parent 100617 1bb02cc7e1ab3f27d0b8de279b3d2c3422a64bd4
child 100619 95f261232c71121b33a2a3c339054367c4e85eef
push id23188
push useremorley@mozilla.com
push dateFri, 27 Jul 2012 08:54:50 +0000
treeherdermozilla-central@399aff2fb74f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs748116
milestone17.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 748116; Make DrawTargetCairo::DrawSurface work with non-Cairo source surfaces. r=roc
gfx/2d/DrawTargetCairo.cpp
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -293,38 +293,74 @@ DrawTargetCairo::Flush()
 }
 
 void
 DrawTargetCairo::PrepareForDrawing(cairo_t* aContext, const Path* aPath /* = NULL */)
 {
   WillChange(aPath);
 }
 
+static cairo_user_data_key_t surfaceDataKey;
+
+void
+ReleaseData(void* aData)
+{
+  static_cast<DataSourceSurface*>(aData)->Release();
+}
+
+/**
+ * Returns cairo surface for the given SourceSurface.
+ * If possible, it will use the cairo_surface associated with aSurface,
+ * otherwise, it will create a new cairo_surface.
+ * In either case, the caller must call cairo_surface_destroy on the
+ * result when it is done with it.
+ */
+cairo_surface_t*
+GetCairoSurfaceForSourceSurface(SourceSurface *aSurface)
+{
+  if (aSurface->GetType() == SURFACE_CAIRO) {
+    cairo_surface_t* surf = static_cast<SourceSurfaceCairo*>(aSurface)->GetSurface();
+    cairo_surface_reference(surf);
+    return surf;
+  } else {
+    RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
+    cairo_surface_t* surf =
+      cairo_image_surface_create_for_data(data->GetData(),
+                                          GfxFormatToCairoFormat(data->GetFormat()),
+                                          data->GetSize().width,
+                                          data->GetSize().height,
+                                          data->Stride());
+    cairo_surface_set_user_data(surf,
+                                 &surfaceDataKey,
+                                 data.forget(),
+                                 ReleaseData);
+    return surf;
+  }
+}
+
 void
 DrawTargetCairo::DrawSurface(SourceSurface *aSurface,
                              const Rect &aDest,
                              const Rect &aSource,
                              const DrawSurfaceOptions &aSurfOptions,
                              const DrawOptions &aOptions)
 {
   AutoPrepareForDrawing prep(this, mContext);
 
   float sx = aSource.Width() / aDest.Width();
   float sy = aSource.Height() / aDest.Height();
 
   cairo_matrix_t src_mat;
   cairo_matrix_init_translate(&src_mat, aSource.X(), aSource.Y());
   cairo_matrix_scale(&src_mat, sx, sy);
 
-  cairo_surface_t* surf = NULL;
-  if (aSurface->GetType() == SURFACE_CAIRO) {
-    surf = static_cast<SourceSurfaceCairo*>(aSurface)->GetSurface();
-  }
+  cairo_surface_t* surf = GetCairoSurfaceForSourceSurface(aSurface);
+  cairo_pattern_t* pat = cairo_pattern_create_for_surface(surf);
+  cairo_surface_destroy(surf);
 
-  cairo_pattern_t* pat = cairo_pattern_create_for_surface(surf);
   cairo_pattern_set_matrix(pat, &src_mat);
   cairo_pattern_set_filter(pat, GfxFilterToCairoFilter(aSurfOptions.mFilter));
   cairo_pattern_set_extend(pat, CAIRO_EXTEND_PAD);
 
   cairo_save(mContext);
   cairo_translate(mContext, aDest.X(), aDest.Y());
 
   if (OperatorAffectsUncoveredAreas(aOptions.mCompositionOp) ||
@@ -801,16 +837,17 @@ DrawTargetCairo::CreateSimilarDrawTarget
 
 bool
 DrawTargetCairo::Init(cairo_surface_t* aSurface, const IntSize& aSize)
 {
   mContext = cairo_create(aSurface);
   mSurface = aSurface;
   cairo_surface_reference(mSurface);
   mSize = aSize;
+  mFormat = CairoContentToGfxFormat(cairo_surface_get_content(aSurface));
 
   return true;
 }
 
 void *
 DrawTargetCairo::GetNativeSurface(NativeSurfaceType aType)
 {
   if (aType == NATIVE_SURFACE_CAIRO_SURFACE) {