mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backout 013743bb609e (bug 591358) for Windows orange.
This commit is contained in:
parent
01eb6774e4
commit
f7c91e83b4
@ -546,7 +546,6 @@ NS_INTERFACE_MAP_END
|
|||||||
uint32_t nsCanvasRenderingContext2DAzure::sNumLivingContexts = 0;
|
uint32_t nsCanvasRenderingContext2DAzure::sNumLivingContexts = 0;
|
||||||
uint8_t (*nsCanvasRenderingContext2DAzure::sUnpremultiplyTable)[256] = nullptr;
|
uint8_t (*nsCanvasRenderingContext2DAzure::sUnpremultiplyTable)[256] = nullptr;
|
||||||
uint8_t (*nsCanvasRenderingContext2DAzure::sPremultiplyTable)[256] = nullptr;
|
uint8_t (*nsCanvasRenderingContext2DAzure::sPremultiplyTable)[256] = nullptr;
|
||||||
RefPtr<DrawTarget> nsCanvasRenderingContext2DAzure::sErrorTarget = nullptr;
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
@ -578,7 +577,7 @@ NS_NewCanvasRenderingContext2DAzure(nsIDOMCanvasRenderingContext2D** aResult)
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsCanvasRenderingContext2DAzure::nsCanvasRenderingContext2DAzure()
|
nsCanvasRenderingContext2DAzure::nsCanvasRenderingContext2DAzure()
|
||||||
: mZero(false), mOpaque(false), mResetLayer(true)
|
: mValid(false), mZero(false), mOpaque(false), mResetLayer(true)
|
||||||
, mIPC(false)
|
, mIPC(false)
|
||||||
, mIsEntireFrameInvalid(false)
|
, mIsEntireFrameInvalid(false)
|
||||||
, mPredictManyRedrawCalls(false), mPathTransformWillUpdate(false)
|
, mPredictManyRedrawCalls(false), mPathTransformWillUpdate(false)
|
||||||
@ -601,7 +600,6 @@ nsCanvasRenderingContext2DAzure::~nsCanvasRenderingContext2DAzure()
|
|||||||
delete[] sPremultiplyTable;
|
delete[] sPremultiplyTable;
|
||||||
sUnpremultiplyTable = nullptr;
|
sUnpremultiplyTable = nullptr;
|
||||||
sPremultiplyTable = nullptr;
|
sPremultiplyTable = nullptr;
|
||||||
NS_IF_RELEASE(sErrorTarget);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -651,7 +649,7 @@ nsCanvasRenderingContext2DAzure::Reset()
|
|||||||
|
|
||||||
// only do this for non-docshell created contexts,
|
// only do this for non-docshell created contexts,
|
||||||
// since those are the ones that we created a surface for
|
// since those are the ones that we created a surface for
|
||||||
if (mTarget && IsTargetValid() && !mDocShell) {
|
if (mValid && !mDocShell) {
|
||||||
gCanvasAzureMemoryUsed -= mWidth * mHeight * 4;
|
gCanvasAzureMemoryUsed -= mWidth * mHeight * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -660,6 +658,7 @@ nsCanvasRenderingContext2DAzure::Reset()
|
|||||||
// Since the target changes the backing texture will change, and this will
|
// Since the target changes the backing texture will change, and this will
|
||||||
// no longer be valid.
|
// no longer be valid.
|
||||||
mThebesSurface = nullptr;
|
mThebesSurface = nullptr;
|
||||||
|
mValid = false;
|
||||||
mIsEntireFrameInvalid = false;
|
mIsEntireFrameInvalid = false;
|
||||||
mPredictManyRedrawCalls = false;
|
mPredictManyRedrawCalls = false;
|
||||||
|
|
||||||
@ -836,15 +835,22 @@ nsCanvasRenderingContext2DAzure::RedrawUser(const gfxRect& r)
|
|||||||
Redraw(newr);
|
Redraw(newr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
NS_IMETHODIMP
|
||||||
nsCanvasRenderingContext2DAzure::EnsureTarget()
|
nsCanvasRenderingContext2DAzure::SetDimensions(int32_t width, int32_t height)
|
||||||
{
|
{
|
||||||
if (mTarget) {
|
RefPtr<DrawTarget> target;
|
||||||
return;
|
|
||||||
|
// Zero sized surfaces cause issues, so just go with 1x1.
|
||||||
|
if (height == 0 || width == 0) {
|
||||||
|
mZero = true;
|
||||||
|
height = 1;
|
||||||
|
width = 1;
|
||||||
|
} else {
|
||||||
|
mZero = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the dimensions are sane
|
// Check that the dimensions are sane
|
||||||
IntSize size(mWidth, mHeight);
|
IntSize size(width, height);
|
||||||
if (size.width <= 0xFFFF && size.height <= 0xFFFF &&
|
if (size.width <= 0xFFFF && size.height <= 0xFFFF &&
|
||||||
size.width >= 0 && size.height >= 0) {
|
size.width >= 0 && size.height >= 0) {
|
||||||
SurfaceFormat format = GetSurfaceFormat();
|
SurfaceFormat format = GetSurfaceFormat();
|
||||||
@ -860,53 +866,41 @@ nsCanvasRenderingContext2DAzure::EnsureTarget()
|
|||||||
nsContentUtils::PersistentLayerManagerForDocument(ownerDoc);
|
nsContentUtils::PersistentLayerManagerForDocument(ownerDoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layerManager) {
|
if (layerManager) {
|
||||||
mTarget = layerManager->CreateDrawTarget(size, format);
|
target = layerManager->CreateDrawTarget(size, format);
|
||||||
} else {
|
} else {
|
||||||
mTarget = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(size, format);
|
target = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(size, format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mTarget) {
|
if (target) {
|
||||||
if (gCanvasAzureMemoryReporter == nullptr) {
|
if (gCanvasAzureMemoryReporter == nullptr) {
|
||||||
gCanvasAzureMemoryReporter = new NS_MEMORY_REPORTER_NAME(CanvasAzureMemory);
|
gCanvasAzureMemoryReporter = new NS_MEMORY_REPORTER_NAME(CanvasAzureMemory);
|
||||||
NS_RegisterMemoryReporter(gCanvasAzureMemoryReporter);
|
NS_RegisterMemoryReporter(gCanvasAzureMemoryReporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
gCanvasAzureMemoryUsed += mWidth * mHeight * 4;
|
gCanvasAzureMemoryUsed += width * height * 4;
|
||||||
JSContext* context = nsContentUtils::GetCurrentJSContext();
|
JSContext* context = nsContentUtils::GetCurrentJSContext();
|
||||||
if (context) {
|
if (context) {
|
||||||
JS_updateMallocCounter(context, mWidth * mHeight * 4);
|
JS_updateMallocCounter(context, width * height * 4);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
EnsureErrorTarget();
|
|
||||||
mTarget = sErrorTarget;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsCanvasRenderingContext2DAzure::SetDimensions(int32_t width, int32_t height)
|
|
||||||
{
|
|
||||||
ClearTarget();
|
|
||||||
|
|
||||||
// Zero sized surfaces cause issues, so just go with 1x1.
|
|
||||||
if (height == 0 || width == 0) {
|
|
||||||
mZero = true;
|
|
||||||
mWidth = 1;
|
|
||||||
mHeight = 1;
|
|
||||||
} else {
|
|
||||||
mZero = false;
|
|
||||||
mWidth = width;
|
|
||||||
mHeight = height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return InitializeWithTarget(target, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
nsresult
|
||||||
nsCanvasRenderingContext2DAzure::ClearTarget()
|
nsCanvasRenderingContext2DAzure::Initialize(int32_t width, int32_t height)
|
||||||
{
|
{
|
||||||
Reset();
|
mWidth = width;
|
||||||
|
mHeight = height;
|
||||||
|
|
||||||
|
if (!mValid) {
|
||||||
|
// Create a dummy target in the hopes that it will help us deal with users
|
||||||
|
// calling into us after having changed the size where the size resulted
|
||||||
|
// in an inability to create a correct DrawTarget.
|
||||||
|
mTarget = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(IntSize(1, 1), FORMAT_B8G8R8A8);
|
||||||
|
}
|
||||||
|
|
||||||
mResetLayer = true;
|
mResetLayer = true;
|
||||||
|
|
||||||
@ -922,6 +916,42 @@ nsCanvasRenderingContext2DAzure::ClearTarget()
|
|||||||
state->colorStyles[STYLE_FILL] = NS_RGB(0,0,0);
|
state->colorStyles[STYLE_FILL] = NS_RGB(0,0,0);
|
||||||
state->colorStyles[STYLE_STROKE] = NS_RGB(0,0,0);
|
state->colorStyles[STYLE_STROKE] = NS_RGB(0,0,0);
|
||||||
state->shadowColor = NS_RGBA(0,0,0,0);
|
state->shadowColor = NS_RGBA(0,0,0,0);
|
||||||
|
|
||||||
|
if (mTarget) {
|
||||||
|
mTarget->ClearRect(mgfx::Rect(Point(0, 0), Size(mWidth, mHeight)));
|
||||||
|
// always force a redraw, because if the surface dimensions were reset
|
||||||
|
// then the surface became cleared, and we need to redraw everything.
|
||||||
|
Redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mValid ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsCanvasRenderingContext2DAzure::InitializeWithTarget(DrawTarget *target, int32_t width, int32_t height)
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
|
||||||
|
NS_ASSERTION(mCanvasElement, "Must have a canvas element!");
|
||||||
|
mDocShell = nullptr;
|
||||||
|
|
||||||
|
// This first time this is called on this object is via
|
||||||
|
// nsHTMLCanvasElement::GetContext. If target was non-null then mTarget is
|
||||||
|
// non-null, otherwise we'll return an error here and GetContext won't
|
||||||
|
// return this context object and we'll never enter this code again.
|
||||||
|
// All other times this method is called, if target is null then
|
||||||
|
// mTarget won't be changed, i.e. it will remain non-null, or else it
|
||||||
|
// will be set to non-null.
|
||||||
|
// In all cases, any usable canvas context will have non-null mTarget.
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
mValid = true;
|
||||||
|
mTarget = target;
|
||||||
|
} else {
|
||||||
|
mValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Initialize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
@ -930,22 +960,25 @@ nsCanvasRenderingContext2DAzure::InitializeWithSurface(nsIDocShell *shell, gfxAS
|
|||||||
mDocShell = shell;
|
mDocShell = shell;
|
||||||
mThebesSurface = surface;
|
mThebesSurface = surface;
|
||||||
|
|
||||||
SetDimensions(width, height);
|
|
||||||
mTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surface, IntSize(width, height));
|
mTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surface, IntSize(width, height));
|
||||||
if (!mTarget) {
|
mValid = mTarget != nullptr;
|
||||||
EnsureErrorTarget();
|
|
||||||
mTarget = sErrorTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
return Initialize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsCanvasRenderingContext2DAzure::SetIsOpaque(bool isOpaque)
|
nsCanvasRenderingContext2DAzure::SetIsOpaque(bool isOpaque)
|
||||||
{
|
{
|
||||||
if (isOpaque != mOpaque) {
|
if (isOpaque == mOpaque)
|
||||||
mOpaque = isOpaque;
|
return NS_OK;
|
||||||
ClearTarget();
|
|
||||||
|
mOpaque = isOpaque;
|
||||||
|
|
||||||
|
if (mValid) {
|
||||||
|
/* If we've already been created, let SetDimensions take care of
|
||||||
|
* recreating our surface
|
||||||
|
*/
|
||||||
|
return SetDimensions(mWidth, mHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -954,9 +987,16 @@ nsCanvasRenderingContext2DAzure::SetIsOpaque(bool isOpaque)
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsCanvasRenderingContext2DAzure::SetIsIPC(bool isIPC)
|
nsCanvasRenderingContext2DAzure::SetIsIPC(bool isIPC)
|
||||||
{
|
{
|
||||||
if (isIPC != mIPC) {
|
if (isIPC == mIPC)
|
||||||
mIPC = isIPC;
|
return NS_OK;
|
||||||
ClearTarget();
|
|
||||||
|
mIPC = isIPC;
|
||||||
|
|
||||||
|
if (mValid) {
|
||||||
|
/* If we've already been created, let SetDimensions take care of
|
||||||
|
* recreating our surface
|
||||||
|
*/
|
||||||
|
return SetDimensions(mWidth, mHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -967,8 +1007,7 @@ nsCanvasRenderingContext2DAzure::Render(gfxContext *ctx, gfxPattern::GraphicsFil
|
|||||||
{
|
{
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
EnsureTarget();
|
if (!mValid || !mTarget) {
|
||||||
if (!IsTargetValid()) {
|
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1012,8 +1051,7 @@ nsCanvasRenderingContext2DAzure::GetInputStream(const char *aMimeType,
|
|||||||
const PRUnichar *aEncoderOptions,
|
const PRUnichar *aEncoderOptions,
|
||||||
nsIInputStream **aStream)
|
nsIInputStream **aStream)
|
||||||
{
|
{
|
||||||
EnsureTarget();
|
if (!mValid || !mTarget) {
|
||||||
if (!IsTargetValid()) {
|
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1100,7 +1138,6 @@ nsCanvasRenderingContext2DAzure::GetCanvas(nsIDOMHTMLCanvasElement **canvas)
|
|||||||
void
|
void
|
||||||
nsCanvasRenderingContext2DAzure::Save()
|
nsCanvasRenderingContext2DAzure::Save()
|
||||||
{
|
{
|
||||||
EnsureTarget();
|
|
||||||
mStyleStack[mStyleStack.Length() - 1].transform = mTarget->GetTransform();
|
mStyleStack[mStyleStack.Length() - 1].transform = mTarget->GetTransform();
|
||||||
mStyleStack.SetCapacity(mStyleStack.Length() + 1);
|
mStyleStack.SetCapacity(mStyleStack.Length() + 1);
|
||||||
mStyleStack.AppendElement(CurrentState());
|
mStyleStack.AppendElement(CurrentState());
|
||||||
@ -1119,14 +1156,14 @@ nsCanvasRenderingContext2DAzure::Restore()
|
|||||||
if (mStyleStack.Length() - 1 == 0)
|
if (mStyleStack.Length() - 1 == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TransformWillUpdate();
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < CurrentState().clipsPushed.size(); i++) {
|
for (uint32_t i = 0; i < CurrentState().clipsPushed.size(); i++) {
|
||||||
mTarget->PopClip();
|
mTarget->PopClip();
|
||||||
}
|
}
|
||||||
|
|
||||||
mStyleStack.RemoveElementAt(mStyleStack.Length() - 1);
|
mStyleStack.RemoveElementAt(mStyleStack.Length() - 1);
|
||||||
|
|
||||||
|
TransformWillUpdate();
|
||||||
|
|
||||||
mTarget->SetTransform(CurrentState().transform);
|
mTarget->SetTransform(CurrentState().transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1144,15 +1181,16 @@ nsCanvasRenderingContext2DAzure::MozRestore()
|
|||||||
void
|
void
|
||||||
nsCanvasRenderingContext2DAzure::Scale(double x, double y, ErrorResult& error)
|
nsCanvasRenderingContext2DAzure::Scale(double x, double y, ErrorResult& error)
|
||||||
{
|
{
|
||||||
|
if (!mTarget) {
|
||||||
|
error.Throw(NS_ERROR_FAILURE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!FloatValidate(x,y)) {
|
if (!FloatValidate(x,y)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransformWillUpdate();
|
TransformWillUpdate();
|
||||||
if (!IsTargetValid()) {
|
|
||||||
error.Throw(NS_ERROR_FAILURE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix newMatrix = mTarget->GetTransform();
|
Matrix newMatrix = mTarget->GetTransform();
|
||||||
mTarget->SetTransform(newMatrix.Scale(x, y));
|
mTarget->SetTransform(newMatrix.Scale(x, y));
|
||||||
@ -1169,16 +1207,16 @@ nsCanvasRenderingContext2DAzure::Scale(float x, float y)
|
|||||||
void
|
void
|
||||||
nsCanvasRenderingContext2DAzure::Rotate(double angle, ErrorResult& error)
|
nsCanvasRenderingContext2DAzure::Rotate(double angle, ErrorResult& error)
|
||||||
{
|
{
|
||||||
|
if (!mTarget) {
|
||||||
|
error.Throw(NS_ERROR_FAILURE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!FloatValidate(angle)) {
|
if (!FloatValidate(angle)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransformWillUpdate();
|
TransformWillUpdate();
|
||||||
if (!IsTargetValid()) {
|
|
||||||
error.Throw(NS_ERROR_FAILURE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Matrix rotation = Matrix::Rotation(angle);
|
Matrix rotation = Matrix::Rotation(angle);
|
||||||
mTarget->SetTransform(rotation * mTarget->GetTransform());
|
mTarget->SetTransform(rotation * mTarget->GetTransform());
|
||||||
@ -1195,15 +1233,16 @@ nsCanvasRenderingContext2DAzure::Rotate(float angle)
|
|||||||
void
|
void
|
||||||
nsCanvasRenderingContext2DAzure::Translate(double x, double y, ErrorResult& error)
|
nsCanvasRenderingContext2DAzure::Translate(double x, double y, ErrorResult& error)
|
||||||
{
|
{
|
||||||
|
if (!mTarget) {
|
||||||
|
error.Throw(NS_ERROR_FAILURE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!FloatValidate(x,y)) {
|
if (!FloatValidate(x,y)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransformWillUpdate();
|
TransformWillUpdate();
|
||||||
if (!IsTargetValid()) {
|
|
||||||
error.Throw(NS_ERROR_FAILURE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix newMatrix = mTarget->GetTransform();
|
Matrix newMatrix = mTarget->GetTransform();
|
||||||
mTarget->SetTransform(newMatrix.Translate(x, y));
|
mTarget->SetTransform(newMatrix.Translate(x, y));
|
||||||
@ -1222,15 +1261,16 @@ nsCanvasRenderingContext2DAzure::Transform(double m11, double m12, double m21,
|
|||||||
double m22, double dx, double dy,
|
double m22, double dx, double dy,
|
||||||
ErrorResult& error)
|
ErrorResult& error)
|
||||||
{
|
{
|
||||||
|
if (!mTarget) {
|
||||||
|
error.Throw(NS_ERROR_FAILURE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!FloatValidate(m11,m12,m21,m22,dx,dy)) {
|
if (!FloatValidate(m11,m12,m21,m22,dx,dy)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransformWillUpdate();
|
TransformWillUpdate();
|
||||||
if (!IsTargetValid()) {
|
|
||||||
error.Throw(NS_ERROR_FAILURE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix matrix(m11, m12, m21, m22, dx, dy);
|
Matrix matrix(m11, m12, m21, m22, dx, dy);
|
||||||
mTarget->SetTransform(matrix * mTarget->GetTransform());
|
mTarget->SetTransform(matrix * mTarget->GetTransform());
|
||||||
@ -1251,15 +1291,16 @@ nsCanvasRenderingContext2DAzure::SetTransform(double m11, double m12,
|
|||||||
double dx, double dy,
|
double dx, double dy,
|
||||||
ErrorResult& error)
|
ErrorResult& error)
|
||||||
{
|
{
|
||||||
|
if (!mTarget) {
|
||||||
|
error.Throw(NS_ERROR_FAILURE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!FloatValidate(m11,m12,m21,m22,dx,dy)) {
|
if (!FloatValidate(m11,m12,m21,m22,dx,dy)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransformWillUpdate();
|
TransformWillUpdate();
|
||||||
if (!IsTargetValid()) {
|
|
||||||
error.Throw(NS_ERROR_FAILURE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix matrix(m11, m12, m21, m22, dx, dy);
|
Matrix matrix(m11, m12, m21, m22, dx, dy);
|
||||||
mTarget->SetTransform(matrix);
|
mTarget->SetTransform(matrix);
|
||||||
@ -1328,8 +1369,7 @@ nsCanvasRenderingContext2DAzure::SetMozCurrentTransform(JSContext* cx,
|
|||||||
JSObject& currentTransform,
|
JSObject& currentTransform,
|
||||||
ErrorResult& error)
|
ErrorResult& error)
|
||||||
{
|
{
|
||||||
EnsureTarget();
|
if (!mTarget) {
|
||||||
if (!IsTargetValid()) {
|
|
||||||
error.Throw(NS_ERROR_FAILURE);
|
error.Throw(NS_ERROR_FAILURE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1357,7 +1397,12 @@ JSObject*
|
|||||||
nsCanvasRenderingContext2DAzure::GetMozCurrentTransform(JSContext* cx,
|
nsCanvasRenderingContext2DAzure::GetMozCurrentTransform(JSContext* cx,
|
||||||
ErrorResult& error) const
|
ErrorResult& error) const
|
||||||
{
|
{
|
||||||
return MatrixToJSObject(cx, mTarget ? mTarget->GetTransform() : Matrix(), error);
|
if (!mTarget) {
|
||||||
|
error.Throw(NS_ERROR_FAILURE);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MatrixToJSObject(cx, mTarget->GetTransform(), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
@ -1377,8 +1422,7 @@ nsCanvasRenderingContext2DAzure::SetMozCurrentTransformInverse(JSContext* cx,
|
|||||||
JSObject& currentTransform,
|
JSObject& currentTransform,
|
||||||
ErrorResult& error)
|
ErrorResult& error)
|
||||||
{
|
{
|
||||||
EnsureTarget();
|
if (!mTarget) {
|
||||||
if (!IsTargetValid()) {
|
|
||||||
error.Throw(NS_ERROR_FAILURE);
|
error.Throw(NS_ERROR_FAILURE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1410,7 +1454,8 @@ nsCanvasRenderingContext2DAzure::GetMozCurrentTransformInverse(JSContext* cx,
|
|||||||
ErrorResult& error) const
|
ErrorResult& error) const
|
||||||
{
|
{
|
||||||
if (!mTarget) {
|
if (!mTarget) {
|
||||||
return MatrixToJSObject(cx, Matrix(), error);
|
error.Throw(NS_ERROR_FAILURE);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix ctm = mTarget->GetTransform();
|
Matrix ctm = mTarget->GetTransform();
|
||||||
@ -1857,7 +1902,6 @@ nsCanvasRenderingContext2DAzure::CreatePattern(const HTMLImageOrCanvasOrVideoEle
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnsureTarget();
|
|
||||||
RefPtr<SourceSurface> srcSurf =
|
RefPtr<SourceSurface> srcSurf =
|
||||||
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mTarget, res.mSurface);
|
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mTarget, res.mSurface);
|
||||||
|
|
||||||
@ -1961,7 +2005,7 @@ void
|
|||||||
nsCanvasRenderingContext2DAzure::ClearRect(double x, double y, double w,
|
nsCanvasRenderingContext2DAzure::ClearRect(double x, double y, double w,
|
||||||
double h)
|
double h)
|
||||||
{
|
{
|
||||||
if (!FloatValidate(x,y,w,h) || !mTarget) {
|
if (!FloatValidate(x,y,w,h)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2035,7 +2079,6 @@ nsCanvasRenderingContext2DAzure::FillRect(double x, double y, double w,
|
|||||||
|
|
||||||
mgfx::Rect bounds;
|
mgfx::Rect bounds;
|
||||||
|
|
||||||
EnsureTarget();
|
|
||||||
if (NeedToDrawShadow()) {
|
if (NeedToDrawShadow()) {
|
||||||
bounds = mgfx::Rect(x, y, w, h);
|
bounds = mgfx::Rect(x, y, w, h);
|
||||||
bounds = mTarget->GetTransform().TransformBounds(bounds);
|
bounds = mTarget->GetTransform().TransformBounds(bounds);
|
||||||
@ -2067,22 +2110,17 @@ nsCanvasRenderingContext2DAzure::StrokeRect(double x, double y, double w,
|
|||||||
const ContextState &state = CurrentState();
|
const ContextState &state = CurrentState();
|
||||||
|
|
||||||
mgfx::Rect bounds;
|
mgfx::Rect bounds;
|
||||||
|
|
||||||
if (!w && !h) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EnsureTarget();
|
|
||||||
if (!IsTargetValid()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NeedToDrawShadow()) {
|
if (NeedToDrawShadow()) {
|
||||||
bounds = mgfx::Rect(x - state.lineWidth / 2.0f, y - state.lineWidth / 2.0f,
|
bounds = mgfx::Rect(x - state.lineWidth / 2.0f, y - state.lineWidth / 2.0f,
|
||||||
w + state.lineWidth, h + state.lineWidth);
|
w + state.lineWidth, h + state.lineWidth);
|
||||||
bounds = mTarget->GetTransform().TransformBounds(bounds);
|
bounds = mTarget->GetTransform().TransformBounds(bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!w && !h) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!h) {
|
if (!h) {
|
||||||
CapStyle cap = CAP_BUTT;
|
CapStyle cap = CAP_BUTT;
|
||||||
if (state.lineJoin == JOIN_ROUND) {
|
if (state.lineJoin == JOIN_ROUND) {
|
||||||
@ -2453,7 +2491,6 @@ nsCanvasRenderingContext2DAzure::EnsureWritablePath()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnsureTarget();
|
|
||||||
if (!mPath) {
|
if (!mPath) {
|
||||||
NS_ASSERTION(!mPathTransformWillUpdate, "mPathTransformWillUpdate should be false, if all paths are null");
|
NS_ASSERTION(!mPathTransformWillUpdate, "mPathTransformWillUpdate should be false, if all paths are null");
|
||||||
mPathBuilder = mTarget->CreatePathBuilder(fillRule);
|
mPathBuilder = mTarget->CreatePathBuilder(fillRule);
|
||||||
@ -2472,7 +2509,6 @@ nsCanvasRenderingContext2DAzure::EnsureUserSpacePath(bool aCommitTransform /* =
|
|||||||
FillRule fillRule = CurrentState().fillRule;
|
FillRule fillRule = CurrentState().fillRule;
|
||||||
|
|
||||||
if (!mPath && !mPathBuilder && !mDSPathBuilder) {
|
if (!mPath && !mPathBuilder && !mDSPathBuilder) {
|
||||||
EnsureTarget();
|
|
||||||
mPathBuilder = mTarget->CreatePathBuilder(fillRule);
|
mPathBuilder = mTarget->CreatePathBuilder(fillRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2518,8 +2554,6 @@ nsCanvasRenderingContext2DAzure::EnsureUserSpacePath(bool aCommitTransform /* =
|
|||||||
void
|
void
|
||||||
nsCanvasRenderingContext2DAzure::TransformWillUpdate()
|
nsCanvasRenderingContext2DAzure::TransformWillUpdate()
|
||||||
{
|
{
|
||||||
EnsureTarget();
|
|
||||||
|
|
||||||
// Store the matrix that would transform the current path to device
|
// Store the matrix that would transform the current path to device
|
||||||
// space.
|
// space.
|
||||||
if (mPath || mPathBuilder) {
|
if (mPath || mPathBuilder) {
|
||||||
@ -3003,7 +3037,6 @@ struct NS_STACK_CLASS nsCanvasBidiProcessorAzure : public nsBidiPresUtils::BidiP
|
|||||||
|
|
||||||
float advanceSum = 0;
|
float advanceSum = 0;
|
||||||
|
|
||||||
mCtx->EnsureTarget();
|
|
||||||
for (uint32_t c = 0; c < numRuns; c++) {
|
for (uint32_t c = 0; c < numRuns; c++) {
|
||||||
gfxFont *font = runs[c].mFont;
|
gfxFont *font = runs[c].mFont;
|
||||||
uint32_t endRun = 0;
|
uint32_t endRun = 0;
|
||||||
@ -3204,14 +3237,8 @@ nsCanvasRenderingContext2DAzure::DrawOrMeasureText(const nsAString& aRawText,
|
|||||||
processor.mPt = gfxPoint(aX, aY);
|
processor.mPt = gfxPoint(aX, aY);
|
||||||
processor.mThebes =
|
processor.mThebes =
|
||||||
new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface());
|
new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface());
|
||||||
|
Matrix matrix = mTarget->GetTransform();
|
||||||
// If we don't have a target then we don't have a transform. A target won't
|
processor.mThebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21, matrix._22, matrix._31, matrix._32));
|
||||||
// be needed in the case where we're measuring the text size. This allows
|
|
||||||
// to avoid creating a target if it's only being used to measure text sizes.
|
|
||||||
if (mTarget) {
|
|
||||||
Matrix matrix = mTarget->GetTransform();
|
|
||||||
processor.mThebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21, matrix._22, matrix._31, matrix._32));
|
|
||||||
}
|
|
||||||
processor.mCtx = this;
|
processor.mCtx = this;
|
||||||
processor.mOp = aOp;
|
processor.mOp = aOp;
|
||||||
processor.mBoundingBox = gfxRect(0, 0, 0, 0);
|
processor.mBoundingBox = gfxRect(0, 0, 0, 0);
|
||||||
@ -3301,7 +3328,6 @@ nsCanvasRenderingContext2DAzure::DrawOrMeasureText(const nsAString& aRawText,
|
|||||||
processor.mPt.x *= processor.mAppUnitsPerDevPixel;
|
processor.mPt.x *= processor.mAppUnitsPerDevPixel;
|
||||||
processor.mPt.y *= processor.mAppUnitsPerDevPixel;
|
processor.mPt.y *= processor.mAppUnitsPerDevPixel;
|
||||||
|
|
||||||
EnsureTarget();
|
|
||||||
Matrix oldTransform = mTarget->GetTransform();
|
Matrix oldTransform = mTarget->GetTransform();
|
||||||
// if text is over aMaxWidth, then scale the text horizontally such that its
|
// if text is over aMaxWidth, then scale the text horizontally such that its
|
||||||
// width is precisely aMaxWidth
|
// width is precisely aMaxWidth
|
||||||
@ -3641,8 +3667,6 @@ nsCanvasRenderingContext2DAzure::DrawImage(const HTMLImageOrCanvasOrVideoElement
|
|||||||
gfxIntSize imgSize;
|
gfxIntSize imgSize;
|
||||||
|
|
||||||
Element* element;
|
Element* element;
|
||||||
|
|
||||||
EnsureTarget();
|
|
||||||
if (image.IsHTMLCanvasElement()) {
|
if (image.IsHTMLCanvasElement()) {
|
||||||
nsHTMLCanvasElement* canvas = image.GetAsHTMLCanvasElement();
|
nsHTMLCanvasElement* canvas = image.GetAsHTMLCanvasElement();
|
||||||
element = canvas;
|
element = canvas;
|
||||||
@ -3904,7 +3928,6 @@ nsCanvasRenderingContext2DAzure::DrawWindow(nsIDOMWindow* window, double x,
|
|||||||
|
|
||||||
nsRefPtr<gfxContext> thebes = new gfxContext(drawSurf);
|
nsRefPtr<gfxContext> thebes = new gfxContext(drawSurf);
|
||||||
|
|
||||||
EnsureTarget();
|
|
||||||
Matrix matrix = mTarget->GetTransform();
|
Matrix matrix = mTarget->GetTransform();
|
||||||
thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21,
|
thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21,
|
||||||
matrix._22, matrix._31, matrix._32));
|
matrix._22, matrix._31, matrix._32));
|
||||||
@ -4123,8 +4146,7 @@ nsCanvasRenderingContext2DAzure::GetImageData(JSContext* aCx, double aSx,
|
|||||||
double aSy, double aSw,
|
double aSy, double aSw,
|
||||||
double aSh, ErrorResult& error)
|
double aSh, ErrorResult& error)
|
||||||
{
|
{
|
||||||
EnsureTarget();
|
if (!mValid) {
|
||||||
if (!IsTargetValid()) {
|
|
||||||
error.Throw(NS_ERROR_FAILURE);
|
error.Throw(NS_ERROR_FAILURE);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -4317,19 +4339,6 @@ nsCanvasRenderingContext2DAzure::EnsurePremultiplyTable() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
nsCanvasRenderingContext2DAzure::EnsureErrorTarget()
|
|
||||||
{
|
|
||||||
if (sErrorTarget) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sErrorTarget = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(IntSize(1, 1), FORMAT_B8G8R8A8);
|
|
||||||
NS_ABORT_IF_FALSE(sErrorTarget, "Failed to allocate the error target!");
|
|
||||||
|
|
||||||
NS_ADDREF(sErrorTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsCanvasRenderingContext2DAzure::FillRuleChanged()
|
nsCanvasRenderingContext2DAzure::FillRuleChanged()
|
||||||
{
|
{
|
||||||
@ -4398,6 +4407,10 @@ nsCanvasRenderingContext2DAzure::PutImageData_explicit(int32_t x, int32_t y, uin
|
|||||||
bool hasDirtyRect, int32_t dirtyX, int32_t dirtyY,
|
bool hasDirtyRect, int32_t dirtyX, int32_t dirtyY,
|
||||||
int32_t dirtyWidth, int32_t dirtyHeight)
|
int32_t dirtyWidth, int32_t dirtyHeight)
|
||||||
{
|
{
|
||||||
|
if (!mValid) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
if (w == 0 || h == 0) {
|
if (w == 0 || h == 0) {
|
||||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||||
}
|
}
|
||||||
@ -4486,11 +4499,6 @@ nsCanvasRenderingContext2DAzure::PutImageData_explicit(int32_t x, int32_t y, uin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EnsureTarget();
|
|
||||||
if (!IsTargetValid()) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<SourceSurface> sourceSurface =
|
RefPtr<SourceSurface> sourceSurface =
|
||||||
mTarget->CreateSourceSurfaceFromData(imgsurf->Data(), IntSize(w, h), imgsurf->Stride(), FORMAT_B8G8R8A8);
|
mTarget->CreateSourceSurfaceFromData(imgsurf->Data(), IntSize(w, h), imgsurf->Stride(), FORMAT_B8G8R8A8);
|
||||||
|
|
||||||
@ -4508,7 +4516,13 @@ nsCanvasRenderingContext2DAzure::PutImageData_explicit(int32_t x, int32_t y, uin
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsCanvasRenderingContext2DAzure::GetThebesSurface(gfxASurface **surface)
|
nsCanvasRenderingContext2DAzure::GetThebesSurface(gfxASurface **surface)
|
||||||
{
|
{
|
||||||
EnsureTarget();
|
if (!mTarget) {
|
||||||
|
nsRefPtr<gfxASurface> tmpSurf =
|
||||||
|
gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(1, 1), gfxASurface::CONTENT_COLOR_ALPHA);
|
||||||
|
*surface = tmpSurf.forget().get();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mThebesSurface) {
|
if (!mThebesSurface) {
|
||||||
mThebesSurface =
|
mThebesSurface =
|
||||||
gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget);
|
gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget);
|
||||||
@ -4618,15 +4632,16 @@ nsCanvasRenderingContext2DAzure::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
|||||||
CanvasLayer *aOldLayer,
|
CanvasLayer *aOldLayer,
|
||||||
LayerManager *aManager)
|
LayerManager *aManager)
|
||||||
{
|
{
|
||||||
EnsureTarget();
|
if (!mValid) {
|
||||||
if (!IsTargetValid()) {
|
|
||||||
// No DidTransactionCallback will be received, so mark the context clean
|
// No DidTransactionCallback will be received, so mark the context clean
|
||||||
// now so future invalidations will be dispatched.
|
// now so future invalidations will be dispatched.
|
||||||
MarkContextClean();
|
MarkContextClean();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
mTarget->Flush();
|
if (mTarget) {
|
||||||
|
mTarget->Flush();
|
||||||
|
}
|
||||||
|
|
||||||
if (!mResetLayer && aOldLayer) {
|
if (!mResetLayer && aOldLayer) {
|
||||||
CanvasRenderingContext2DUserDataAzure* userData =
|
CanvasRenderingContext2DUserDataAzure* userData =
|
||||||
@ -4692,5 +4707,5 @@ nsCanvasRenderingContext2DAzure::MarkContextClean()
|
|||||||
bool
|
bool
|
||||||
nsCanvasRenderingContext2DAzure::ShouldForceInactiveLayer(LayerManager *aManager)
|
nsCanvasRenderingContext2DAzure::ShouldForceInactiveLayer(LayerManager *aManager)
|
||||||
{
|
{
|
||||||
return !aManager->CanUseCanvasLayerForSize(gfxIntSize(mWidth, mHeight));
|
return !aManager->CanUseCanvasLayerForSize(gfxIntSize(mWidth, mHeight));
|
||||||
}
|
}
|
||||||
|
@ -566,8 +566,6 @@ protected:
|
|||||||
*/
|
*/
|
||||||
static uint8_t (*sPremultiplyTable)[256];
|
static uint8_t (*sPremultiplyTable)[256];
|
||||||
|
|
||||||
static mozilla::RefPtr<mozilla::gfx::DrawTarget> sErrorTarget;
|
|
||||||
|
|
||||||
// Some helpers. Doesn't modify a color on failure.
|
// Some helpers. Doesn't modify a color on failure.
|
||||||
void SetStyleFromJSValue(JSContext* cx, JS::Value& value, Style whichStyle);
|
void SetStyleFromJSValue(JSContext* cx, JS::Value& value, Style whichStyle);
|
||||||
void SetStyleFromString(const nsAString& str, Style whichStyle);
|
void SetStyleFromString(const nsAString& str, Style whichStyle);
|
||||||
@ -600,11 +598,6 @@ protected:
|
|||||||
*/
|
*/
|
||||||
void EnsurePremultiplyTable();
|
void EnsurePremultiplyTable();
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the error target, if it doesn't exist
|
|
||||||
*/
|
|
||||||
static void EnsureErrorTarget();
|
|
||||||
|
|
||||||
/* This function ensures there is a writable pathbuilder available, this
|
/* This function ensures there is a writable pathbuilder available, this
|
||||||
* pathbuilder may be working in user space or in device space or
|
* pathbuilder may be working in user space or in device space or
|
||||||
* device space.
|
* device space.
|
||||||
@ -617,33 +610,11 @@ protected:
|
|||||||
// used for the path.
|
// used for the path.
|
||||||
void EnsureUserSpacePath(bool aCommitTransform = true);
|
void EnsureUserSpacePath(bool aCommitTransform = true);
|
||||||
|
|
||||||
/**
|
|
||||||
* Needs to be called before updating the transform. This makes a call to
|
|
||||||
* EnsureTarget() so you don't have to.
|
|
||||||
*/
|
|
||||||
void TransformWillUpdate();
|
void TransformWillUpdate();
|
||||||
|
|
||||||
// Report the fillRule has changed.
|
// Report the fillRule has changed.
|
||||||
void FillRuleChanged();
|
void FillRuleChanged();
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the backing surfacing, if it doesn't exist. If there is an error
|
|
||||||
* in creating the target then it will put sErrorTarget in place. If there
|
|
||||||
* is in turn an error in creating the sErrorTarget then they would both
|
|
||||||
* be null so IsTargetValid() would still return null.
|
|
||||||
*/
|
|
||||||
void EnsureTarget();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Disposes an old target and prepares to lazily create a new target.
|
|
||||||
*/
|
|
||||||
void ClearTarget();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the target is valid after calling EnsureTarget.
|
|
||||||
*/
|
|
||||||
bool IsTargetValid() { return mTarget != sErrorTarget; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the surface format this canvas should be allocated using. Takes
|
* Returns the surface format this canvas should be allocated using. Takes
|
||||||
* into account mOpaque, platform requirements, etc.
|
* into account mOpaque, platform requirements, etc.
|
||||||
@ -692,6 +663,10 @@ protected:
|
|||||||
// Member vars
|
// Member vars
|
||||||
int32_t mWidth, mHeight;
|
int32_t mWidth, mHeight;
|
||||||
|
|
||||||
|
// This is true when the canvas is valid, false otherwise, this occurs when
|
||||||
|
// for some reason initialization of the drawtarget fails. If the canvas
|
||||||
|
// is invalid certain behavior is expected.
|
||||||
|
bool mValid;
|
||||||
// This is true when the canvas is valid, but of zero size, this requires
|
// This is true when the canvas is valid, but of zero size, this requires
|
||||||
// specific behavior on some operations.
|
// specific behavior on some operations.
|
||||||
bool mZero;
|
bool mZero;
|
||||||
@ -709,9 +684,7 @@ protected:
|
|||||||
// If mCanvasElement is not provided, then a docshell is
|
// If mCanvasElement is not provided, then a docshell is
|
||||||
nsCOMPtr<nsIDocShell> mDocShell;
|
nsCOMPtr<nsIDocShell> mDocShell;
|
||||||
|
|
||||||
// This is created lazily so it is necessary to call EnsureTarget before
|
// our drawing surfaces, contexts, and layers
|
||||||
// accessing it. In the event of an error it will be equal to
|
|
||||||
// sErrorTarget.
|
|
||||||
mozilla::RefPtr<mozilla::gfx::DrawTarget> mTarget;
|
mozilla::RefPtr<mozilla::gfx::DrawTarget> mTarget;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user