Bug 1309272, part 2 - Support the creation of a DrawTargetSkia for an SkCanvas. r=lsalzman
authorJonathan Watt <jwatt@jwatt.org>
Wed, 26 Oct 2016 19:23:07 +0100
changeset 320100 c974afea821bdd83ebedd3adeefe0bbe87cb1fb5
parent 320099 89304c2622668a206897b66c51cd8f048b9106a3
child 320101 ee15183d057288ccd8b6b22b13b85c540229f736
push id20749
push userryanvm@gmail.com
push dateSat, 29 Oct 2016 13:21:21 +0000
treeherderfx-team@1b170b39ed6b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsalzman
bugs1309272
milestone52.0a1
Bug 1309272, part 2 - Support the creation of a DrawTargetSkia for an SkCanvas. r=lsalzman
gfx/2d/2D.h
gfx/2d/DrawTargetSkia.cpp
gfx/2d/DrawTargetSkia.h
gfx/2d/Factory.cpp
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -43,16 +43,17 @@ typedef _FcPattern FcPattern;
 
 struct ID3D11Texture2D;
 struct ID3D11Device;
 struct ID2D1Device;
 struct IDWriteRenderingParams;
 struct IDWriteFontFace;
 
 class GrContext;
+class SkCanvas;
 struct gfxFontStyle;
 
 struct CGContext;
 typedef struct CGContext *CGContextRef;
 
 namespace mozilla {
 
 namespace gfx {
@@ -1461,16 +1462,20 @@ public:
    * drawing is distributed over number of tiles which may each hold an
    * individual offset. The tiles in the set must each have the same backend
    * and format.
    */
   static already_AddRefed<DrawTarget> CreateTiledDrawTarget(const TileSet& aTileSet);
 
   static bool DoesBackendSupportDataDrawtarget(BackendType aType);
 
+#ifdef USE_SKIA
+  static already_AddRefed<DrawTarget> CreateDrawTargetWithSkCanvas(SkCanvas* aCanvas);
+#endif
+
 #ifdef XP_DARWIN
   static already_AddRefed<GlyphRenderingOptions>
     CreateCGGlyphRenderingOptions(const Color &aFontSmoothingBackgroundColor);
 #endif
 
 #ifdef WIN32
   static already_AddRefed<DrawTarget> CreateDrawTargetForD3D11Texture(ID3D11Texture2D *aTexture, SurfaceFormat aFormat);
 
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -1562,16 +1562,20 @@ DrawTargetSkia::CreateSimilarDrawTarget(
     // Try to create a GPU draw target first if we're currently using the GPU.
     // Mark the DT as cached so that shadow DTs, extracted subrects, and similar can be reused.
     if (target->InitWithGrContext(mGrContext.get(), aSize, aFormat, true)) {
       return target.forget();
     }
     // Otherwise, just fall back to a software draw target.
   }
 #endif
+  // Check that our SkCanvas isn't backed by vector storage such as PDF.  If it
+  // is then we want similar storage to avoid losing fidelity.
+  MOZ_ASSERT(mCanvas->imageInfo().colorType() != kUnknown_SkColorType,
+             "Not backed by pixels - we need to handle PDF backed SkCanvas");
   if (!target->Init(aSize, aFormat)) {
     return nullptr;
   }
   return target.forget();
 }
 
 bool
 DrawTargetSkia::UsingSkiaGPU() const
@@ -1749,16 +1753,40 @@ DrawTargetSkia::Init(const IntSize &aSiz
   mCanvas = sk_ref_sp(mSurface->getCanvas());
 
   if (info.isOpaque()) {
     mCanvas->clear(SK_ColorBLACK);
   }
   return true;
 }
 
+bool
+DrawTargetSkia::Init(SkCanvas* aCanvas)
+{
+  mCanvas = sk_ref_sp(aCanvas);
+
+  SkImageInfo imageInfo = mCanvas->imageInfo();
+
+  // If the canvas is backed by pixels we clear it to be on the safe side.  If
+  // it's not (for example, for PDF output) we don't.
+  bool isBackedByPixels = imageInfo.colorType() != kUnknown_SkColorType;
+  if (isBackedByPixels) {
+    // Note for PDF backed SkCanvas |alphaType == kUnknown_SkAlphaType|.
+    SkColor clearColor = imageInfo.isOpaque() ? SK_ColorBLACK : SK_ColorTRANSPARENT;
+    mCanvas->clear(clearColor);
+  }
+
+  SkISize size = mCanvas->getBaseLayerSize();
+  mSize.width = size.width();
+  mSize.height = size.height();
+  mFormat = SkiaColorTypeToGfxFormat(imageInfo.colorType(),
+                                     imageInfo.alphaType());
+  return true;
+}
+
 #ifdef USE_SKIA_GPU
 /** Indicating a DT should be cached means that space will be reserved in Skia's cache
  * for the render target at creation time, with any unused resources exceeding the cache
  * limits being purged. When the DT is freed, it will then be guaranteed to be kept around
  * for subsequent allocations until it gets incidentally purged.
  *
  * If it is not marked as cached, no space will be purged to make room for the render
  * target in the cache. When the DT is freed, If there is space within the resource limits
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -127,16 +127,17 @@ public:
   virtual already_AddRefed<GradientStops> CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode = ExtendMode::CLAMP) const override;
   virtual already_AddRefed<FilterNode> CreateFilter(FilterType aType) override;
   virtual void SetTransform(const Matrix &aTransform) override;
   virtual void *GetNativeSurface(NativeSurfaceType aType) override;
   virtual void DetachAllSnapshots() override { MarkChanged(); }
 
   bool Init(const IntSize &aSize, SurfaceFormat aFormat);
   bool Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat, bool aUninitialized = false);
+  bool Init(SkCanvas* aCanvas);
 
 #ifdef USE_SKIA_GPU
   bool InitWithGrContext(GrContext* aGrContext,
                          const IntSize &aSize,
                          SurfaceFormat aFormat,
                          bool aCached);
   virtual bool
     InitWithGrContext(GrContext* aGrContext,
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -699,16 +699,28 @@ Factory::CreateDrawTargetSkiaWithGrConte
   if (!newTarget->InitWithGrContext(aGrContext, aSize, aFormat)) {
     return nullptr;
   }
   return newTarget.forget();
 }
 
 #endif // USE_SKIA_GPU
 
+#ifdef USE_SKIA
+already_AddRefed<DrawTarget>
+Factory::CreateDrawTargetWithSkCanvas(SkCanvas* aCanvas)
+{
+  RefPtr<DrawTargetSkia> newTarget = new DrawTargetSkia();
+  if (!newTarget->Init(aCanvas)) {
+    return nullptr;
+  }
+  return newTarget.forget();
+}
+#endif
+
 void
 Factory::PurgeAllCaches()
 {
 }
 
 already_AddRefed<DrawTarget>
 Factory::CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat)
 {