Bug 1290323. Write alpha values for plugin surfaces when using the Skia backend. r=jrmuizel

This commit is contained in:
Mason Chang 2016-08-05 10:29:12 -07:00
Родитель 82b2646797
Коммит 21793bcce5
6 изменённых файлов: 110 добавлений и 36 удалений

Просмотреть файл

@ -954,8 +954,9 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect,
updatedRect.bottom - updatedRect.top);
surface->MarkDirty(ur);
bool isPlugin = true;
RefPtr<gfx::SourceSurface> sourceSurface =
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr, surface);
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr, surface, isPlugin);
RefPtr<SourceSurfaceImage> image = new SourceSurfaceImage(surface->GetSize(), sourceSurface);
AutoTArray<ImageContainer::NonOwningImage,1> imageList;

Просмотреть файл

@ -1037,6 +1037,9 @@ public:
* aSourceSurface or some other existing surface.
*/
virtual already_AddRefed<SourceSurface> OptimizeSourceSurface(SourceSurface *aSurface) const = 0;
virtual already_AddRefed<SourceSurface> OptimizeSourceSurfaceForUnknownAlpha(SourceSurface *aSurface) const {
return OptimizeSourceSurface(aSurface);
}
/**
* Create a SourceSurface for a type of NativeSurface. This may fail if the

Просмотреть файл

@ -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<SourceSurface>
DrawTargetSkia::OptimizeGPUSourceSurface(SourceSurface *aSurface) const
{
// Check if the underlying SkBitmap already has an associated GrTexture.
if (aSurface->GetType() == SurfaceType::SKIA &&
static_cast<SourceSurfaceSkia*>(aSurface)->GetBitmap().getTexture()) {
RefPtr<SourceSurface> surface(aSurface);
return surface.forget();
}
SkBitmap bitmap = GetBitmapForSurface(aSurface);
// Upload the SkBitmap to a GrTexture otherwise.
SkAutoTUnref<GrTexture> texture(
GrRefCachedBitmapTexture(mGrContext.get(), bitmap, GrTextureParams::ClampBilerp()));
if (texture) {
// Create a new SourceSurfaceSkia whose SkBitmap contains the GrTexture.
RefPtr<SourceSurfaceSkia> 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<SourceSurface> surface(aSurface);
return surface.forget();
}
// Wrap it in a Skia source surface so that can do tiled uploads on-demand.
RefPtr<SourceSurfaceSkia> surface = new SourceSurfaceSkia();
surface->InitFromBitmap(bitmap);
return surface.forget();
}
#endif
already_AddRefed<SourceSurface>
DrawTargetSkia::OptimizeSourceSurfaceForUnknownAlpha(SourceSurface *aSurface) const
{
#ifdef USE_SKIA_GPU
if (UsingSkiaGPU()) {
return OptimizeGPUSourceSurface(aSurface);
}
#endif
if (aSurface->GetType() == SurfaceType::SKIA) {
RefPtr<SourceSurface> surface(aSurface);
return surface.forget();
}
RefPtr<DataSourceSurface> 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<SourceSurface>
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<SourceSurfaceSkia*>(aSurface)->GetBitmap().getTexture()) {
RefPtr<SourceSurface> surface(aSurface);
return surface.forget();
}
SkBitmap bitmap = GetBitmapForSurface(aSurface);
// Upload the SkBitmap to a GrTexture otherwise.
SkAutoTUnref<GrTexture> texture(
GrRefCachedBitmapTexture(mGrContext.get(), bitmap, GrTextureParams::ClampBilerp()));
if (texture) {
// Create a new SourceSurfaceSkia whose SkBitmap contains the GrTexture.
RefPtr<SourceSurfaceSkia> 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<SourceSurface> surface(aSurface);
return surface.forget();
}
// Wrap it in a Skia source surface so that can do tiled uploads on-demand.
RefPtr<SourceSurfaceSkia> surface = new SourceSurfaceSkia();
surface->InitFromBitmap(bitmap);
return surface.forget();
return OptimizeGPUSourceSurface(aSurface);
}
#endif

Просмотреть файл

@ -116,6 +116,7 @@ public:
int32_t aStride,
SurfaceFormat aFormat) const override;
virtual already_AddRefed<SourceSurface> OptimizeSourceSurface(SourceSurface *aSurface) const override;
virtual already_AddRefed<SourceSurface> OptimizeSourceSurfaceForUnknownAlpha(SourceSurface *aSurface) const override;
virtual already_AddRefed<SourceSurface>
CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const override;
virtual already_AddRefed<DrawTarget>
@ -141,6 +142,8 @@ public:
SurfaceFormat aFormat) override {
return InitWithGrContext(aGrContext, aSize, aFormat, false);
}
already_AddRefed<SourceSurface> OptimizeGPUSourceSurface(SourceSurface *aSurface) const;
#endif
// Skia assumes that texture sizes fit in 16-bit signed integers.

Просмотреть файл

@ -1006,7 +1006,9 @@ gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
}
/* static */ already_AddRefed<SourceSurface>
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<DataSourceSurface> 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

Просмотреть файл

@ -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<SourceSurface>
GetSourceSurfaceForSurface(mozilla::gfx::DrawTarget *aTarget, gfxASurface *aSurface);
GetSourceSurfaceForSurface(mozilla::gfx::DrawTarget *aTarget,
gfxASurface *aSurface,
bool aIsPlugin = false);
static void ClearSourceSurfaceForSurface(gfxASurface *aSurface);