Backed out changeset 5005fe56b7b0 (bug 1616715) for failures on test_2_conformance2__canvas__to-data-url-with-pack-params.html. CLOSED TREE

This commit is contained in:
Csoregi Natalia 2020-02-21 01:33:48 +02:00
Родитель a15f9174ec
Коммит 0d667d17dd
8 изменённых файлов: 71 добавлений и 112 удалений

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

@ -18,7 +18,6 @@
#include "mozilla/layers/OOPCanvasRenderer.h" #include "mozilla/layers/OOPCanvasRenderer.h"
#include "mozilla/layers/TextureClientSharedSurface.h" #include "mozilla/layers/TextureClientSharedSurface.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/StaticPrefs_webgl.h" #include "mozilla/StaticPrefs_webgl.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsIGfxInfo.h" #include "nsIGfxInfo.h"
@ -884,106 +883,9 @@ ClientWebGLContext::SetContextOptions(JSContext* cx,
void ClientWebGLContext::DidRefresh() { Run<RPROC(DidRefresh)>(); } void ClientWebGLContext::DidRefresh() { Run<RPROC(DidRefresh)>(); }
already_AddRefed<gfx::SourceSurface> ClientWebGLContext::GetSurfaceSnapshot( already_AddRefed<gfx::SourceSurface> ClientWebGLContext::GetSurfaceSnapshot(
gfxAlphaType* const out_alphaType) { gfxAlphaType* out_alphaType) {
const FuncScope funcScope(*this, "<GetSurfaceSnapshot>"); auto ret = Run<RPROC(GetSurfaceSnapshot)>(out_alphaType);
if (IsContextLost()) return nullptr; return ret.forget();
const auto notLost =
mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF.
const auto& options = mNotLost->info.options;
const auto& state = State();
const auto drawFbWas = state.mBoundDrawFb;
const auto readFbWas = state.mBoundReadFb;
const auto alignmentWas = Run<RPROC(GetParameter)>(LOCAL_GL_PACK_ALIGNMENT);
if (!alignmentWas) return nullptr;
const auto size = DrawingBufferSize();
// -
BindFramebuffer(LOCAL_GL_FRAMEBUFFER, nullptr);
PixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
auto reset = MakeScopeExit([&] {
if (drawFbWas == readFbWas) {
BindFramebuffer(LOCAL_GL_FRAMEBUFFER, drawFbWas);
} else {
BindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, drawFbWas);
BindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, readFbWas);
}
PixelStorei(LOCAL_GL_PACK_ALIGNMENT, *alignmentWas);
});
const auto surfFormat = options.alpha ? gfx::SurfaceFormat::B8G8R8A8
: gfx::SurfaceFormat::B8G8R8X8;
const auto stride = size.x * 4;
RefPtr<gfx::DataSourceSurface> surf =
gfx::Factory::CreateDataSourceSurfaceWithStride(
{size.x, size.y}, surfFormat, stride, /*zero=*/true);
MOZ_ASSERT(surf);
if (NS_WARN_IF(!surf)) return nullptr;
{
const gfx::DataSourceSurface::ScopedMap map(
surf, gfx::DataSourceSurface::READ_WRITE);
if (!map.IsMapped()) {
MOZ_ASSERT(false);
return nullptr;
}
MOZ_ASSERT(static_cast<uint32_t>(map.GetStride()) == stride);
const auto range = Range<uint8_t>(map.GetData(), stride * size.y);
auto view = RawBufferView(range);
Run<RPROC(ReadPixels)>(0, 0, size.x, size.y, LOCAL_GL_RGBA,
LOCAL_GL_UNSIGNED_BYTE, view);
// -
const auto swapRowRedBlue = [&](uint8_t* const row) {
for (const auto x : IntegerRange(size.x)) {
std::swap(row[4 * x], row[4 * x + 2]);
}
};
std::vector<uint8_t> tempRow(stride);
for (const auto srcY : IntegerRange(size.y / 2)) {
const auto dstY = size.y - 1 - srcY;
const auto srcRow = (range.begin() + (stride * srcY)).get();
const auto dstRow = (range.begin() + (stride * dstY)).get();
memcpy(tempRow.data(), dstRow, stride);
memcpy(dstRow, srcRow, stride);
swapRowRedBlue(dstRow);
memcpy(srcRow, tempRow.data(), stride);
swapRowRedBlue(srcRow);
}
if (size.y & 1) {
const auto midY = size.y / 2; // size.y = 3 => midY = 1
const auto midRow = (range.begin() + (stride * midY)).get();
swapRowRedBlue(midRow);
}
}
gfxAlphaType srcAlphaType;
if (!options.alpha) {
srcAlphaType = gfxAlphaType::Opaque;
} else if (options.premultipliedAlpha) {
srcAlphaType = gfxAlphaType::Premult;
} else {
srcAlphaType = gfxAlphaType::NonPremult;
}
if (out_alphaType) {
*out_alphaType = srcAlphaType;
} else {
// Expects Opaque or Premult
if (srcAlphaType == gfxAlphaType::NonPremult) {
gfxUtils::PremultiplyDataSurface(surf, surf);
}
}
return surf.forget();
} }
UniquePtr<uint8_t[]> ClientWebGLContext::GetImageBuffer(int32_t* out_format) { UniquePtr<uint8_t[]> ClientWebGLContext::GetImageBuffer(int32_t* out_format) {

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

@ -196,6 +196,11 @@ class HostWebGLContext final : public SupportsWeakPtr<HostWebGLContext> {
void DidRefresh() { mContext->DidRefresh(); } void DidRefresh() { mContext->DidRefresh(); }
RefPtr<gfx::SourceSurface> GetSurfaceSnapshot(
gfxAlphaType* out_alphaType) const {
return mContext->GetSurfaceSnapshot(out_alphaType);
}
void GenerateError(const GLenum error, const std::string& text) const { void GenerateError(const GLenum error, const std::string& text) const {
mContext->GenerateErrorImpl(error, text); mContext->GenerateErrorImpl(error, text);
} }

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

@ -1252,6 +1252,56 @@ void WebGLContext::LoseContext(const webgl::ContextLossReason reason) {
mHost->OnContextLoss(reason); mHost->OnContextLoss(reason);
} }
RefPtr<gfx::SourceSurface> WebGLContext::GetSurfaceSnapshot(
gfxAlphaType* const out_alphaType) {
const FuncScope funcScope(*this, "<GetSurfaceSnapshot>");
if (IsContextLost()) return nullptr;
if (!BindDefaultFBForRead()) return nullptr;
const auto surfFormat = mOptions.alpha ? gfx::SurfaceFormat::B8G8R8A8
: gfx::SurfaceFormat::B8G8R8X8;
const auto& size = mDefaultFB->mSize;
RefPtr<gfx::DataSourceSurface> surf;
surf = gfx::Factory::CreateDataSourceSurfaceWithStride(size, surfFormat,
size.width * 4);
if (NS_WARN_IF(!surf)) return nullptr;
ReadPixelsIntoDataSurface(gl, surf);
gfxAlphaType alphaType;
if (!mOptions.alpha) {
alphaType = gfxAlphaType::Opaque;
} else if (mOptions.premultipliedAlpha) {
alphaType = gfxAlphaType::Premult;
} else {
alphaType = gfxAlphaType::NonPremult;
}
if (out_alphaType) {
*out_alphaType = alphaType;
} else {
// Expects Opaque or Premult
if (alphaType == gfxAlphaType::NonPremult) {
gfxUtils::PremultiplyDataSurface(surf, surf);
}
}
RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateDrawTarget(
gfxPlatform::GetPlatform()->GetSoftwareBackend(), size,
gfx::SurfaceFormat::B8G8R8A8);
if (!dt) return nullptr;
dt->SetTransform(
gfx::Matrix::Translation(0.0, size.height).PreScale(1.0, -1.0));
const gfx::Rect rect{0, 0, float(size.width), float(size.height)};
dt->DrawSurface(surf, rect, rect, gfx::DrawSurfaceOptions(),
gfx::DrawOptions(1.0f, gfx::CompositionOp::OP_SOURCE));
return dt->Snapshot();
}
void WebGLContext::DidRefresh() { void WebGLContext::DidRefresh() {
if (gl) { if (gl) {
gl->FlushIfHeavyGLCallsSinceLastFlush(); gl->FlushIfHeavyGLCallsSinceLastFlush();

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

@ -374,6 +374,9 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
void SetCompositableHost(RefPtr<layers::CompositableHost>& aCompositableHost); void SetCompositableHost(RefPtr<layers::CompositableHost>& aCompositableHost);
RefPtr<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(
gfxAlphaType* out_alphaType);
/** /**
* An abstract base class to be implemented by callers wanting to be notified * An abstract base class to be implemented by callers wanting to be notified
* that a refresh has occurred. Callers must ensure an observer is removed * that a refresh has occurred. Callers must ensure an observer is removed

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

@ -52,6 +52,7 @@ DEFINE_ASYNC(HostWebGLContext::DeleteTransformFeedback)
DEFINE_ASYNC(HostWebGLContext::DeleteVertexArray) DEFINE_ASYNC(HostWebGLContext::DeleteVertexArray)
DEFINE_ASYNC(HostWebGLContext::ClearVRFrame) DEFINE_ASYNC(HostWebGLContext::ClearVRFrame)
DEFINE_SYNC(HostWebGLContext::GetSurfaceSnapshot)
DEFINE_SYNC(HostWebGLContext::GetVRFrame) DEFINE_SYNC(HostWebGLContext::GetVRFrame)
DEFINE_ASYNC(HostWebGLContext::Disable) DEFINE_ASYNC(HostWebGLContext::Disable)

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

@ -170,12 +170,14 @@ UniquePtr<webgl::TexUnpackBlob> WebGLContext::FromDomElem(
// same as drawImage. // same as drawImage.
uint32_t flags = nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE | uint32_t flags = nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE |
nsLayoutUtils::SFE_WANT_IMAGE_SURFACE | nsLayoutUtils::SFE_WANT_IMAGE_SURFACE |
nsLayoutUtils::SFE_USE_ELEMENT_SIZE_IF_VECTOR | nsLayoutUtils::SFE_USE_ELEMENT_SIZE_IF_VECTOR;
nsLayoutUtils::SFE_ALLOW_NON_PREMULT;
if (mPixelStore.mColorspaceConversion == LOCAL_GL_NONE) if (mPixelStore.mColorspaceConversion == LOCAL_GL_NONE)
flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION; flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
if (!mPixelStore.mPremultiplyAlpha)
flags |= nsLayoutUtils::SFE_PREFER_NO_PREMULTIPLY_ALPHA;
RefPtr<gfx::DrawTarget> idealDrawTarget = nullptr; // Don't care for now. RefPtr<gfx::DrawTarget> idealDrawTarget = nullptr; // Don't care for now.
auto sfer = nsLayoutUtils::SurfaceFromElement( auto sfer = nsLayoutUtils::SurfaceFromElement(
const_cast<dom::Element*>(&elem), flags, idealDrawTarget); const_cast<dom::Element*>(&elem), flags, idealDrawTarget);

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

@ -7580,7 +7580,7 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(
imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY; imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY;
if (aSurfaceFlags & SFE_NO_COLORSPACE_CONVERSION) if (aSurfaceFlags & SFE_NO_COLORSPACE_CONVERSION)
frameFlags |= imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION; frameFlags |= imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION;
if (aSurfaceFlags & SFE_ALLOW_NON_PREMULT) { if (aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) {
frameFlags |= imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA; frameFlags |= imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
} }
@ -7666,12 +7666,7 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(
IntSize size = aElement->GetSize(); IntSize size = aElement->GetSize();
auto pAlphaType = &result.mAlphaType; result.mSourceSurface = aElement->GetSurfaceSnapshot(&result.mAlphaType);
if (!(aSurfaceFlags & SFE_ALLOW_NON_PREMULT)) {
pAlphaType =
nullptr; // Coersce GetSurfaceSnapshot to give us Opaque/Premult only.
}
result.mSourceSurface = aElement->GetSurfaceSnapshot(pAlphaType);
if (!result.mSourceSurface) { if (!result.mSourceSurface) {
// If the element doesn't have a context then we won't get a snapshot. The // If the element doesn't have a context then we won't get a snapshot. The
// canvas spec wants us to not error and just draw nothing, so return an // canvas spec wants us to not error and just draw nothing, so return an

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

@ -2125,8 +2125,9 @@ class nsLayoutUtils {
SFE_WANT_FIRST_FRAME_IF_IMAGE = 1 << 1, SFE_WANT_FIRST_FRAME_IF_IMAGE = 1 << 1,
/* Whether we should skip colorspace/gamma conversion */ /* Whether we should skip colorspace/gamma conversion */
SFE_NO_COLORSPACE_CONVERSION = 1 << 2, SFE_NO_COLORSPACE_CONVERSION = 1 << 2,
/* Caller handles SFER::mAlphaType = NonPremult */ /* Specifies that the caller wants either OPAQUE or NON_PREMULT mAlphaType,
SFE_ALLOW_NON_PREMULT = 1 << 3, if this is can be done efficiently. */
SFE_PREFER_NO_PREMULTIPLY_ALPHA = 1 << 3,
/* Whether we should skip getting a surface for vector images and /* Whether we should skip getting a surface for vector images and
return a DirectDrawInfo containing an imgIContainer instead. */ return a DirectDrawInfo containing an imgIContainer instead. */
SFE_NO_RASTERIZING_VECTORS = 1 << 4, SFE_NO_RASTERIZING_VECTORS = 1 << 4,