diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp index f090b8d18d1d..9c833c3ac593 100644 --- a/dom/plugins/ipc/PluginInstanceParent.cpp +++ b/dom/plugins/ipc/PluginInstanceParent.cpp @@ -954,8 +954,9 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect, updatedRect.bottom - updatedRect.top); surface->MarkDirty(ur); + bool isPlugin = true; RefPtr sourceSurface = - gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr, surface); + gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr, surface, isPlugin); RefPtr image = new SourceSurfaceImage(surface->GetSize(), sourceSurface); AutoTArray imageList; diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index d161c99c74ac..ba4838017b90 100644 --- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -1037,6 +1037,9 @@ public: * aSourceSurface or some other existing surface. */ virtual already_AddRefed OptimizeSourceSurface(SourceSurface *aSurface) const = 0; + virtual already_AddRefed OptimizeSourceSurfaceForUnknownAlpha(SourceSurface *aSurface) const { + return OptimizeSourceSurface(aSurface); + } /** * Create a SourceSurface for a type of NativeSurface. This may fail if the diff --git a/gfx/2d/DrawTargetSkia.cpp b/gfx/2d/DrawTargetSkia.cpp index 9799f679eba8..4e7f9cc6df8c 100644 --- a/gfx/2d/DrawTargetSkia.cpp +++ b/gfx/2d/DrawTargetSkia.cpp @@ -103,6 +103,31 @@ ReleaseTemporarySurface(void* aPixels, void* aContext) } } +static void +WriteRGBXFormat(uint8_t* aData, const IntSize &aSize, + const int32_t aStride, SurfaceFormat aFormat) +{ + if (aFormat != SurfaceFormat::B8G8R8X8 || aSize.IsEmpty()) { + return; + } + + int height = aSize.height; + int width = aSize.width * 4; + + for (int row = 0; row < height; ++row) { + for (int column = 0; column < width; column += 4) { +#ifdef IS_BIG_ENDIAN + aData[column] = 0xFF; +#else + aData[column + 3] = 0xFF; +#endif + } + aData += aStride; + } + + return; +} + #ifdef DEBUG static bool VerifyRGBXFormat(uint8_t* aData, const IntSize &aSize, const int32_t aStride, SurfaceFormat aFormat) @@ -1377,43 +1402,76 @@ DrawTargetSkia::UsingSkiaGPU() const #endif } +#ifdef USE_SKIA_GPU +already_AddRefed +DrawTargetSkia::OptimizeGPUSourceSurface(SourceSurface *aSurface) const +{ + // Check if the underlying SkBitmap already has an associated GrTexture. + if (aSurface->GetType() == SurfaceType::SKIA && + static_cast(aSurface)->GetBitmap().getTexture()) { + RefPtr surface(aSurface); + return surface.forget(); + } + + SkBitmap bitmap = GetBitmapForSurface(aSurface); + + // Upload the SkBitmap to a GrTexture otherwise. + SkAutoTUnref texture( + GrRefCachedBitmapTexture(mGrContext.get(), bitmap, GrTextureParams::ClampBilerp())); + + if (texture) { + // Create a new SourceSurfaceSkia whose SkBitmap contains the GrTexture. + RefPtr surface = new SourceSurfaceSkia(); + if (surface->InitFromGrTexture(texture, aSurface->GetSize(), aSurface->GetFormat())) { + return surface.forget(); + } + } + + // The data was too big to fit in a GrTexture. + if (aSurface->GetType() == SurfaceType::SKIA) { + // It is already a Skia source surface, so just reuse it as-is. + RefPtr surface(aSurface); + return surface.forget(); + } + + // Wrap it in a Skia source surface so that can do tiled uploads on-demand. + RefPtr surface = new SourceSurfaceSkia(); + surface->InitFromBitmap(bitmap); + return surface.forget(); +} +#endif + +already_AddRefed +DrawTargetSkia::OptimizeSourceSurfaceForUnknownAlpha(SourceSurface *aSurface) const +{ +#ifdef USE_SKIA_GPU + if (UsingSkiaGPU()) { + return OptimizeGPUSourceSurface(aSurface); + } +#endif + + if (aSurface->GetType() == SurfaceType::SKIA) { + RefPtr surface(aSurface); + return surface.forget(); + } + + RefPtr dataSurface = aSurface->GetDataSurface(); + + // For plugins, GDI can sometimes just write 0 to the alpha channel + // even for RGBX formats. In this case, we have to manually write + // the alpha channel to make Skia happy with RGBX and in case GDI + // writes some bad data. Luckily, this only happens on plugins. + WriteRGBXFormat(dataSurface->GetData(), dataSurface->GetSize(), + dataSurface->Stride(), dataSurface->GetFormat()); + return dataSurface.forget(); +} + already_AddRefed DrawTargetSkia::OptimizeSourceSurface(SourceSurface *aSurface) const { #ifdef USE_SKIA_GPU if (UsingSkiaGPU()) { - // Check if the underlying SkBitmap already has an associated GrTexture. - if (aSurface->GetType() == SurfaceType::SKIA && - static_cast(aSurface)->GetBitmap().getTexture()) { - RefPtr surface(aSurface); - return surface.forget(); - } - - SkBitmap bitmap = GetBitmapForSurface(aSurface); - - // Upload the SkBitmap to a GrTexture otherwise. - SkAutoTUnref texture( - GrRefCachedBitmapTexture(mGrContext.get(), bitmap, GrTextureParams::ClampBilerp())); - - if (texture) { - // Create a new SourceSurfaceSkia whose SkBitmap contains the GrTexture. - RefPtr surface = new SourceSurfaceSkia(); - if (surface->InitFromGrTexture(texture, aSurface->GetSize(), aSurface->GetFormat())) { - return surface.forget(); - } - } - - // The data was too big to fit in a GrTexture. - if (aSurface->GetType() == SurfaceType::SKIA) { - // It is already a Skia source surface, so just reuse it as-is. - RefPtr surface(aSurface); - return surface.forget(); - } - - // Wrap it in a Skia source surface so that can do tiled uploads on-demand. - RefPtr surface = new SourceSurfaceSkia(); - surface->InitFromBitmap(bitmap); - return surface.forget(); + return OptimizeGPUSourceSurface(aSurface); } #endif diff --git a/gfx/2d/DrawTargetSkia.h b/gfx/2d/DrawTargetSkia.h index e00f9957f38c..62401f5bb98a 100644 --- a/gfx/2d/DrawTargetSkia.h +++ b/gfx/2d/DrawTargetSkia.h @@ -116,6 +116,7 @@ public: int32_t aStride, SurfaceFormat aFormat) const override; virtual already_AddRefed OptimizeSourceSurface(SourceSurface *aSurface) const override; + virtual already_AddRefed OptimizeSourceSurfaceForUnknownAlpha(SourceSurface *aSurface) const override; virtual already_AddRefed CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const override; virtual already_AddRefed @@ -141,6 +142,8 @@ public: SurfaceFormat aFormat) override { return InitWithGrContext(aGrContext, aSize, aFormat, false); } + + already_AddRefed OptimizeGPUSourceSurface(SourceSurface *aSurface) const; #endif // Skia assumes that texture sizes fit in 16-bit signed integers. diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index d72034eaa6b3..172abbed77d5 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -1006,7 +1006,9 @@ gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface) } /* static */ already_AddRefed -gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface) +gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, + gfxASurface *aSurface, + bool aIsPlugin) { if (!aSurface->CairoSurface() || aSurface->CairoStatus()) { return nullptr; @@ -1064,7 +1066,9 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa // the same data, then optimize it for aTarget: RefPtr surf = GetWrappedDataSourceSurface(aSurface); if (surf) { - srcBuffer = aTarget->OptimizeSourceSurface(surf); + srcBuffer = aIsPlugin ? aTarget->OptimizeSourceSurfaceForUnknownAlpha(surf) + : aTarget->OptimizeSourceSurface(surf); + if (srcBuffer == surf) { // GetWrappedDataSourceSurface returns a SourceSurface that holds a // strong reference to aSurface since it wraps aSurface's data and diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index d89ac7daa962..701a3effa56c 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -210,9 +210,14 @@ public: * This function is static so that it can be accessed from * PluginInstanceChild (where we can't call gfxPlatform::GetPlatform() * because the prefs service can only be accessed from the main process). + * + * aIsPlugin is used to tell the backend that they can optimize this surface + * specifically because it's used for a plugin. This is mostly for Skia. */ static already_AddRefed - GetSourceSurfaceForSurface(mozilla::gfx::DrawTarget *aTarget, gfxASurface *aSurface); + GetSourceSurfaceForSurface(mozilla::gfx::DrawTarget *aTarget, + gfxASurface *aSurface, + bool aIsPlugin = false); static void ClearSourceSurfaceForSurface(gfxASurface *aSurface);