зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
a15f9174ec
Коммит
0d667d17dd
|
@ -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,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче