From 461e2332fff80f671209402dbfc00dd97db7e978 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Sep 2015 19:09:04 -0700 Subject: [PATCH 001/104] Bug 1208300 (part 1) - Remove unused default arguments from ClearThebesSurface. r=jwatt. --HG-- extra : rebase_source : 8d91060e8ac1458b858bf961b608bb4b68eff6dc --- gfx/thebes/gfxUtils.cpp | 13 +++---------- gfx/thebes/gfxUtils.h | 4 +--- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index b301586ff104..2aea00695ebe 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -1101,9 +1101,7 @@ gfxUtils::ConvertYCbCrToRGB(const PlanarYCbCrData& aData, } } -/* static */ void gfxUtils::ClearThebesSurface(gfxASurface* aSurface, - IntRect* aRect, - const gfxRGBA& aColor) +/* static */ void gfxUtils::ClearThebesSurface(gfxASurface* aSurface) { if (aSurface->CairoStatus()) { return; @@ -1113,14 +1111,9 @@ gfxUtils::ConvertYCbCrToRGB(const PlanarYCbCrData& aData, return; } cairo_t* ctx = cairo_create(surf); - cairo_set_source_rgba(ctx, aColor.r, aColor.g, aColor.b, aColor.a); + cairo_set_source_rgba(ctx, 0.0, 0.0, 0.0, 0.0); cairo_set_operator(ctx, CAIRO_OPERATOR_SOURCE); - IntRect bounds; - if (aRect) { - bounds = *aRect; - } else { - bounds = IntRect(nsIntPoint(0, 0), aSurface->GetSize()); - } + IntRect bounds(nsIntPoint(0, 0), aSurface->GetSize()); cairo_rectangle(ctx, bounds.x, bounds.y, bounds.width, bounds.height); cairo_fill(ctx); cairo_destroy(ctx); diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index d8d62b8ade5b..70760da3a4d0 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -161,9 +161,7 @@ public: /** * Clears surface to aColor (which defaults to transparent black). */ - static void ClearThebesSurface(gfxASurface* aSurface, - mozilla::gfx::IntRect* aRect = nullptr, - const gfxRGBA& aColor = gfxRGBA(0.0, 0.0, 0.0, 0.0)); + static void ClearThebesSurface(gfxASurface* aSurface); /** * Creates a copy of aSurface, but having the SurfaceFormat aFormat. From 58378c408ecfe2025989f67f7201b1756168c643 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Sep 2015 19:13:50 -0700 Subject: [PATCH 002/104] Bug 1208300 (part 2) - Convert gfxRGBA uses to gfx::Color in CompositorBench.cpp. r=jwatt. I don't know how those modf() calls were compiling without error given that the second arg was a |float*|. --HG-- extra : rebase_source : 0ecf7bda4664aa6eb735aff676341b7e063e0f29 --- gfx/layers/ipc/CompositorBench.cpp | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/gfx/layers/ipc/CompositorBench.cpp b/gfx/layers/ipc/CompositorBench.cpp index 2c0f893dad2a..0eba3c395057 100644 --- a/gfx/layers/ipc/CompositorBench.cpp +++ b/gfx/layers/ipc/CompositorBench.cpp @@ -96,15 +96,11 @@ public: {} void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep) { - float red; float tmp; - red = modf(aStep * 0.03f, &tmp); + float red = modff(aStep * 0.03f, &tmp); EffectChain effects; - gfxRGBA color(red, 0.4f, 0.4f, 1.0f); - effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(color.r, - color.g, - color.b, - color.a)); + effects.mPrimaryEffect = + new EffectSolidColor(gfx::Color(red, 0.4f, 0.4f, 1.0f)); const gfx::Rect& rect = aScreenRect; const gfx::Rect& clipRect = aScreenRect; @@ -130,15 +126,10 @@ public: } already_AddRefed CreateEffect(size_t i) { - float red; float tmp; - red = modf(i * 0.03f, &tmp); + float red = modff(i * 0.03f, &tmp); EffectChain effects; - gfxRGBA color(red, 0.4f, 0.4f, 1.0f); - return MakeAndAddRef(gfx::Color(color.r, - color.g, - color.b, - color.a)); + return MakeAndAddRef(gfx::Color(red, 0.4f, 0.4f, 1.0f)); } }; @@ -156,15 +147,10 @@ public: } already_AddRefed CreateEffect(size_t i) { - float red; float tmp; - red = modf(i * 0.03f, &tmp); + float red = modff(i * 0.03f, &tmp); EffectChain effects; - gfxRGBA color(red, 0.4f, 0.4f, 1.0f); - return MakeAndAddRef(gfx::Color(color.r, - color.g, - color.b, - color.a)); + return MakeAndAddRef(gfx::Color(red, 0.4f, 0.4f, 1.0f)); } }; From 0b89111ec3140f1bf50fda48c95608e51ec03f80 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Sep 2015 19:18:03 -0700 Subject: [PATCH 003/104] Bug 1208300 (part 3) - Convert gfxRGBA uses to gfx::Color in LayerScope.cpp. r=jwatt. --HG-- extra : rebase_source : 8393efea38fb7df8138c0ec2f894eff2808c5a81 --- gfx/layers/LayerScope.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/gfx/layers/LayerScope.cpp b/gfx/layers/LayerScope.cpp index a4f86208ae4b..7546136f1533 100644 --- a/gfx/layers/LayerScope.cpp +++ b/gfx/layers/LayerScope.cpp @@ -599,12 +599,12 @@ protected: class DebugGLColorData final: public DebugGLData { public: DebugGLColorData(void* layerRef, - const gfxRGBA& color, + const Color& color, int width, int height) : DebugGLData(Packet::COLOR), mLayerRef(reinterpret_cast(layerRef)), - mColor(color.Packed()), + mColor(color.ToABGR()), mSize(width, height) { } @@ -902,7 +902,7 @@ public: // Sender private functions private: static void SendColor(void* aLayerRef, - const gfxRGBA& aColor, + const Color& aColor, int aWidth, int aHeight); static void SendTextureSource(GLContext* aGLContext, @@ -1004,7 +1004,7 @@ SenderHelper::SendLayer(LayerComposite* aLayer, void SenderHelper::SendColor(void* aLayerRef, - const gfxRGBA& aColor, + const Color& aColor, int aWidth, int aHeight) { @@ -1179,11 +1179,8 @@ SenderHelper::SendEffectChain(GLContext* aGLContext, case EffectTypes::SOLID_COLOR: { const EffectSolidColor* solidColorEffect = static_cast(primaryEffect); - gfxRGBA color(solidColorEffect->mColor.r, - solidColorEffect->mColor.g, - solidColorEffect->mColor.b, - solidColorEffect->mColor.a); - SendColor(aEffectChain.mLayerRef, color, aWidth, aHeight); + SendColor(aEffectChain.mLayerRef, solidColorEffect->mColor, + aWidth, aHeight); break; } case EffectTypes::COMPONENT_ALPHA: From d0c4a9db1b5d9d0e63ec605fecfb91ba93a86f5b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Sep 2015 19:24:16 -0700 Subject: [PATCH 004/104] Bug 1208300 (part 4) - Remove gfxRGBA and some related things. r=jwatt. Hooray! --HG-- extra : rebase_source : d691b55eef5a8655aa98b81b5398452a5ebe860d --- dom/media/webm/WebMDemuxer.cpp | 1 + dom/plugins/ipc/PluginInstanceParent.cpp | 1 - gfx/gl/GLContext.cpp | 1 - gfx/gl/GLReadTexImageHelper.cpp | 1 + gfx/ipc/GfxMessageUtils.h | 23 --- gfx/layers/FrameMetrics.h | 1 - gfx/layers/LayerScope.cpp | 1 - gfx/layers/LayerTreeInvalidation.cpp | 1 - gfx/layers/Layers.h | 1 - gfx/layers/LayersLogging.cpp | 12 -- gfx/layers/LayersLogging.h | 6 - gfx/layers/ReadbackLayer.h | 5 +- gfx/layers/ReadbackProcessor.cpp | 1 - gfx/layers/basic/BasicLayerManager.cpp | 1 - gfx/layers/client/ContentClient.cpp | 1 - gfx/layers/composite/ColorLayerComposite.cpp | 1 - gfx/layers/ipc/CompositorBench.cpp | 1 - gfx/layers/opengl/OGLShaderProgram.cpp | 2 - gfx/layers/opengl/OGLShaderProgram.h | 17 --- gfx/src/nsColor.h | 4 - gfx/thebes/gfx2DGlue.h | 17 --- gfx/thebes/gfxBlur.h | 1 - gfx/thebes/gfxColor.h | 150 +------------------ gfx/thebes/gfxContext.cpp | 1 - gfx/thebes/gfxDrawable.cpp | 1 - gfx/thebes/gfxFontUtils.cpp | 1 - gfx/thebes/gfxQtNativeRenderer.h | 1 - gfx/thebes/gfxSVGGlyphs.cpp | 1 - gfx/thebes/gfxUtils.h | 1 - layout/base/nsCSSRendering.cpp | 1 - layout/svg/nsSVGGradientFrame.cpp | 1 - layout/svg/nsSVGPatternFrame.cpp | 1 - widget/windows/WinUtils.cpp | 1 - 33 files changed, 7 insertions(+), 253 deletions(-) diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index 8d9b4157ed2d..73f40a38c63b 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -11,6 +11,7 @@ #include "WebMDemuxer.h" #include "WebMBufferedParser.h" #include "gfx2DGlue.h" +#include "mozilla/Endian.h" #include "mozilla/Preferences.h" #include "mozilla/SharedThreadPool.h" #include "MediaDataDemuxer.h" diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp index 284f3cc5acd7..bf90b483f7c5 100644 --- a/dom/plugins/ipc/PluginInstanceParent.cpp +++ b/dom/plugins/ipc/PluginInstanceParent.cpp @@ -31,7 +31,6 @@ #include "gfxXlibSurface.h" #endif #include "gfxContext.h" -#include "gfxColor.h" #include "gfxUtils.h" #include "mozilla/gfx/2D.h" #include "Layers.h" diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index b8761294d5a6..5a1172ecfcdb 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -39,7 +39,6 @@ #ifdef XP_MACOSX #include -#include "gfxColor.h" #endif #if defined(MOZ_WIDGET_COCOA) diff --git a/gfx/gl/GLReadTexImageHelper.cpp b/gfx/gl/GLReadTexImageHelper.cpp index 6ba1a1238bcb..d93b4914937f 100644 --- a/gfx/gl/GLReadTexImageHelper.cpp +++ b/gfx/gl/GLReadTexImageHelper.cpp @@ -7,6 +7,7 @@ #include "GLReadTexImageHelper.h" #include "gfx2DGlue.h" +#include "gfxColor.h" #include "gfxTypes.h" #include "GLContext.h" #include "OGLShaderProgram.h" diff --git a/gfx/ipc/GfxMessageUtils.h b/gfx/ipc/GfxMessageUtils.h index 79c7e47074c3..744907970ba5 100644 --- a/gfx/ipc/GfxMessageUtils.h +++ b/gfx/ipc/GfxMessageUtils.h @@ -13,7 +13,6 @@ #include -#include "gfxColor.h" #include "mozilla/gfx/Matrix.h" #include "GraphicsFilter.h" #include "gfxPoint.h" @@ -293,28 +292,6 @@ struct ParamTraits {}; */ -template<> -struct ParamTraits -{ - typedef gfxRGBA paramType; - - static void Write(Message* msg, const paramType& param) - { - WriteParam(msg, param.r); - WriteParam(msg, param.g); - WriteParam(msg, param.b); - WriteParam(msg, param.a); - } - - static bool Read(const Message* msg, void** iter, paramType* result) - { - return (ReadParam(msg, iter, &result->r) && - ReadParam(msg, iter, &result->g) && - ReadParam(msg, iter, &result->b) && - ReadParam(msg, iter, &result->a)); - } -}; - template<> struct ParamTraits { diff --git a/gfx/layers/FrameMetrics.h b/gfx/layers/FrameMetrics.h index bdd6179401d1..d3eb4c287ec2 100644 --- a/gfx/layers/FrameMetrics.h +++ b/gfx/layers/FrameMetrics.h @@ -13,7 +13,6 @@ #include "mozilla/gfx/Rect.h" // for RoundedIn #include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor #include "mozilla/gfx/Logging.h" // for Log -#include "gfxColor.h" #include "nsString.h" namespace IPC { diff --git a/gfx/layers/LayerScope.cpp b/gfx/layers/LayerScope.cpp index 7546136f1533..9c5bfd53e4ed 100644 --- a/gfx/layers/LayerScope.cpp +++ b/gfx/layers/LayerScope.cpp @@ -21,7 +21,6 @@ #include "mozilla/layers/LayerManagerComposite.h" #include "mozilla/layers/TextureHostOGL.h" -#include "gfxColor.h" #include "gfxContext.h" #include "gfxUtils.h" #include "gfxPrefs.h" diff --git a/gfx/layers/LayerTreeInvalidation.cpp b/gfx/layers/LayerTreeInvalidation.cpp index 5d507608ae06..8c2a45921cf6 100644 --- a/gfx/layers/LayerTreeInvalidation.cpp +++ b/gfx/layers/LayerTreeInvalidation.cpp @@ -10,7 +10,6 @@ #include "ImageLayers.h" // for ImageLayer, etc #include "Layers.h" // for Layer, ContainerLayer, etc #include "Units.h" // for ParentLayerIntRect -#include "gfxColor.h" // for gfxRGBA #include "GraphicsFilter.h" // for GraphicsFilter #include "gfxRect.h" // for gfxRect #include "gfxUtils.h" // for gfxUtils diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index b3b2cfc961c9..88238216f065 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -13,7 +13,6 @@ #include "Units.h" // for LayerMargin, LayerPoint, ParentLayerIntRect #include "gfxContext.h" #include "gfxTypes.h" -#include "gfxColor.h" // for gfxRGBA #include "GraphicsFilter.h" // for GraphicsFilter #include "gfxPoint.h" // for gfxPoint #include "gfxRect.h" // for gfxRect diff --git a/gfx/layers/LayersLogging.cpp b/gfx/layers/LayersLogging.cpp index ea917b69292a..4bef36ad30af 100644 --- a/gfx/layers/LayersLogging.cpp +++ b/gfx/layers/LayersLogging.cpp @@ -7,7 +7,6 @@ #include "LayersLogging.h" #include // for uint8_t -#include "gfxColor.h" // for gfxRGBA #include "ImageTypes.h" // for ImageFormat #include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix #include "mozilla/gfx/Point.h" // for IntSize @@ -57,17 +56,6 @@ AppendToString(std::stringstream& aStream, FrameMetrics::ViewID n, aStream << sfx; } -void -AppendToString(std::stringstream& aStream, const gfxRGBA& c, - const char* pfx, const char* sfx) -{ - aStream << pfx; - aStream << nsPrintfCString( - "rgba(%d, %d, %d, %g)", - uint8_t(c.r*255.0), uint8_t(c.g*255.0), uint8_t(c.b*255.0), c.a).get(); - aStream << sfx; -} - void AppendToString(std::stringstream& aStream, const Color& c, const char* pfx, const char* sfx) diff --git a/gfx/layers/LayersLogging.h b/gfx/layers/LayersLogging.h index ebc456c023e1..25340405f1e0 100644 --- a/gfx/layers/LayersLogging.h +++ b/gfx/layers/LayersLogging.h @@ -16,8 +16,6 @@ #include "nsRegion.h" // for nsRegion, nsIntRegion #include "nscore.h" // for nsACString, etc -struct gfxRGBA; - namespace mozilla { namespace gfx { class Matrix4x4; @@ -40,10 +38,6 @@ void AppendToString(std::stringstream& aStream, FrameMetrics::ViewID n, const char* pfx="", const char* sfx=""); -void -AppendToString(std::stringstream& aStream, const gfxRGBA& c, - const char* pfx="", const char* sfx=""); - void AppendToString(std::stringstream& aStream, const gfx::Color& c, const char* pfx="", const char* sfx=""); diff --git a/gfx/layers/ReadbackLayer.h b/gfx/layers/ReadbackLayer.h index eb2daa06c33a..69a4f6e3297a 100644 --- a/gfx/layers/ReadbackLayer.h +++ b/gfx/layers/ReadbackLayer.h @@ -8,9 +8,8 @@ #include // for uint64_t #include "Layers.h" // for Layer, etc -#include "gfxColor.h" // for gfxRGBA -#include "mozilla/gfx/Rect.h" // for gfxRect -#include "mozilla/gfx/Point.h" // for gfxRect +#include "mozilla/gfx/Rect.h" // for gfxRect +#include "mozilla/gfx/Point.h" // for IntPoint #include "mozilla/mozalloc.h" // for operator delete #include "nsAutoPtr.h" // for nsAutoPtr #include "nsCOMPtr.h" // for already_AddRefed diff --git a/gfx/layers/ReadbackProcessor.cpp b/gfx/layers/ReadbackProcessor.cpp index 88755a14377e..b31775407f5d 100644 --- a/gfx/layers/ReadbackProcessor.cpp +++ b/gfx/layers/ReadbackProcessor.cpp @@ -9,7 +9,6 @@ #include "ReadbackLayer.h" // for ReadbackLayer, ReadbackSink #include "UnitTransforms.h" // for ViewAs #include "Units.h" // for ParentLayerIntRect -#include "gfxColor.h" // for gfxRGBA #include "gfxContext.h" // for gfxContext #include "gfxUtils.h" #include "gfxRect.h" // for gfxRect diff --git a/gfx/layers/basic/BasicLayerManager.cpp b/gfx/layers/basic/BasicLayerManager.cpp index 87081f1d01d2..0f014bb33296 100644 --- a/gfx/layers/basic/BasicLayerManager.cpp +++ b/gfx/layers/basic/BasicLayerManager.cpp @@ -17,7 +17,6 @@ #include "basic/BasicImplData.h" // for BasicImplData #include "basic/BasicLayers.h" // for BasicLayerManager, etc #include "gfxASurface.h" // for gfxASurface, etc -#include "gfxColor.h" // for gfxRGBA #include "gfxContext.h" // for gfxContext, etc #include "gfxImageSurface.h" // for gfxImageSurface #include "gfxMatrix.h" // for gfxMatrix diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp index 1efa41da06af..ea87d1421530 100644 --- a/gfx/layers/client/ContentClient.cpp +++ b/gfx/layers/client/ContentClient.cpp @@ -5,7 +5,6 @@ #include "mozilla/layers/ContentClient.h" #include "BasicLayers.h" // for BasicLayerManager -#include "gfxColor.h" // for gfxRGBA #include "gfxContext.h" // for gfxContext, etc #include "gfxPlatform.h" // for gfxPlatform #include "gfxPrefs.h" // for gfxPrefs diff --git a/gfx/layers/composite/ColorLayerComposite.cpp b/gfx/layers/composite/ColorLayerComposite.cpp index a6daa29338fd..179e20102b8e 100644 --- a/gfx/layers/composite/ColorLayerComposite.cpp +++ b/gfx/layers/composite/ColorLayerComposite.cpp @@ -4,7 +4,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ColorLayerComposite.h" -#include "gfxColor.h" // for gfxRGBA #include "mozilla/RefPtr.h" // for RefPtr #include "mozilla/gfx/Matrix.h" // for Matrix4x4 #include "mozilla/gfx/Point.h" // for Point diff --git a/gfx/layers/ipc/CompositorBench.cpp b/gfx/layers/ipc/CompositorBench.cpp index 0eba3c395057..5b9e61c2516e 100644 --- a/gfx/layers/ipc/CompositorBench.cpp +++ b/gfx/layers/ipc/CompositorBench.cpp @@ -10,7 +10,6 @@ #include "mozilla/layers/Compositor.h" #include "mozilla/layers/Effects.h" #include "mozilla/TimeStamp.h" -#include "gfxColor.h" #include "gfxPrefs.h" #include #include "GeckoProfiler.h" diff --git a/gfx/layers/opengl/OGLShaderProgram.cpp b/gfx/layers/opengl/OGLShaderProgram.cpp index 2bc22cf9f7c2..3a0ce9abbae3 100644 --- a/gfx/layers/opengl/OGLShaderProgram.cpp +++ b/gfx/layers/opengl/OGLShaderProgram.cpp @@ -14,8 +14,6 @@ #include "Layers.h" #include "GLContext.h" -struct gfxRGBA; - namespace mozilla { namespace layers { diff --git a/gfx/layers/opengl/OGLShaderProgram.h b/gfx/layers/opengl/OGLShaderProgram.h index 83ddac53efe7..f1d5ae1b70e7 100644 --- a/gfx/layers/opengl/OGLShaderProgram.h +++ b/gfx/layers/opengl/OGLShaderProgram.h @@ -20,8 +20,6 @@ #include -struct gfxRGBA; - namespace mozilla { namespace layers { @@ -435,10 +433,6 @@ public: SetUniform(KnownUniform::MaskTexture, aUnit); } - void SetRenderColor(const gfxRGBA& aColor) { - SetUniform(KnownUniform::RenderColor, aColor); - } - void SetRenderColor(const gfx::Color& aColor) { SetUniform(KnownUniform::RenderColor, aColor); } @@ -507,17 +501,6 @@ protected: } } - void SetUniform(KnownUniform::KnownUniformName aKnownUniform, const gfxRGBA& aColor) - { - ASSERT_THIS_PROGRAM; - NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform"); - - KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); - if (ku.UpdateUniform(aColor.r, aColor.g, aColor.b, aColor.a)) { - mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v); - } - } - void SetUniform(KnownUniform::KnownUniformName aKnownUniform, const gfx::Color& aColor) { ASSERT_THIS_PROGRAM; NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform"); diff --git a/gfx/src/nsColor.h b/gfx/src/nsColor.h index b03263da21ab..7570def100c1 100644 --- a/gfx/src/nsColor.h +++ b/gfx/src/nsColor.h @@ -27,10 +27,6 @@ typedef uint32_t nscolor; #define NS_RGBA(_r,_g,_b,_a) \ ((nscolor) (((_a) << 24) | ((_b)<<16) | ((_g)<<8) | (_r))) -// Make a color out of a gfxRGBA. -#define NS_RGBA_FROM_GFXRGBA(gfxColor) \ - ((nscolor) (gfxColor.Packed())) - // Extract color components from nscolor #define NS_GET_R(_rgba) ((uint8_t) ((_rgba) & 0xff)) #define NS_GET_G(_rgba) ((uint8_t) (((_rgba) >> 8) & 0xff)) diff --git a/gfx/thebes/gfx2DGlue.h b/gfx/thebes/gfx2DGlue.h index 8b1c32a4c18c..bb5788b088bb 100644 --- a/gfx/thebes/gfx2DGlue.h +++ b/gfx/thebes/gfx2DGlue.h @@ -13,7 +13,6 @@ #include "mozilla/gfx/Matrix.h" #include "mozilla/gfx/Rect.h" #include "mozilla/gfx/2D.h" -#include "gfxColor.h" namespace mozilla { namespace gfx { @@ -34,17 +33,6 @@ inline Rect ToRect(const IntRect &aRect) return Rect(aRect.x, aRect.y, aRect.width, aRect.height); } -inline Color ToColor(const gfxRGBA &aRGBA) -{ - return Color(Float(aRGBA.r), Float(aRGBA.g), - Float(aRGBA.b), Float(aRGBA.a)); -} - -inline gfxRGBA ThebesColor(const Color &aColor) -{ - return gfxRGBA(aColor.r, aColor.g, aColor.b, aColor.a); -} - inline Matrix ToMatrix(const gfxMatrix &aMatrix) { return Matrix(Float(aMatrix._11), Float(aMatrix._12), Float(aMatrix._21), @@ -138,11 +126,6 @@ inline gfxRect ThebesRect(const RectDouble &aRect) return gfxRect(aRect.x, aRect.y, aRect.width, aRect.height); } -inline gfxRGBA ThebesRGBA(const Color &aColor) -{ - return gfxRGBA(aColor.r, aColor.g, aColor.b, aColor.a); -} - inline gfxImageFormat SurfaceFormatToImageFormat(SurfaceFormat aFormat) { switch (aFormat) { diff --git a/gfx/thebes/gfxBlur.h b/gfx/thebes/gfxBlur.h index 792d01042e34..7f69288fe12c 100644 --- a/gfx/thebes/gfxBlur.h +++ b/gfx/thebes/gfxBlur.h @@ -15,7 +15,6 @@ class gfxContext; struct gfxRect; -struct gfxRGBA; namespace mozilla { namespace gfx { diff --git a/gfx/thebes/gfxColor.h b/gfx/thebes/gfxColor.h index cc99b2945ea8..2cc0350f419f 100644 --- a/gfx/thebes/gfxColor.h +++ b/gfx/thebes/gfxColor.h @@ -6,29 +6,9 @@ #ifndef GFX_COLOR_H #define GFX_COLOR_H -#include "gfxTypes.h" - #include "mozilla/Attributes.h" // for MOZ_ALWAYS_INLINE #include "mozilla/Endian.h" // for mozilla::NativeEndian::swapToBigEndian -#define GFX_UINT32_FROM_BPTR(pbptr,i) (((uint32_t*)(pbptr))[i]) - -/** - * GFX_0XFF_PPIXEL_FROM_BPTR(x) - * - * Avoid tortured construction of 32-bit ARGB pixel from 3 individual bytes - * of memory plus constant 0xFF. RGB bytes are already contiguous! - * Equivalent to: GFX_PACKED_PIXEL(0xff,r,g,b) - * - * Attempt to use fast byte-swapping instruction(s), e.g. bswap on x86, in - * preference to a sequence of shift/or operations. - */ -#define GFX_0XFF_PPIXEL_FROM_UINT32(x) \ - ( (mozilla::NativeEndian::swapToBigEndian(uint32_t(x)) >> 8) | (0xFFU << 24) ) - -#define GFX_0XFF_PPIXEL_FROM_BPTR(x) \ - ( GFX_0XFF_PPIXEL_FROM_UINT32(GFX_UINT32_FROM_BPTR((x),0)) ) - /** * GFX_BLOCK_RGB_TO_FRGB(from,to) * sizeof(*from) == sizeof(char) @@ -39,9 +19,9 @@ */ #define GFX_BLOCK_RGB_TO_FRGB(from,to) \ PR_BEGIN_MACRO \ - uint32_t m0 = GFX_UINT32_FROM_BPTR(from,0), \ - m1 = GFX_UINT32_FROM_BPTR(from,1), \ - m2 = GFX_UINT32_FROM_BPTR(from,2), \ + uint32_t m0 = ((uint32_t*)from)[0], \ + m1 = ((uint32_t*)from)[1], \ + m2 = ((uint32_t*)from)[2], \ rgbr = mozilla::NativeEndian::swapToBigEndian(m0), \ gbrg = mozilla::NativeEndian::swapToBigEndian(m1), \ brgb = mozilla::NativeEndian::swapToBigEndian(m2), \ @@ -100,128 +80,4 @@ gfxPackedPixel(uint8_t a, uint8_t r, uint8_t g, uint8_t b) { } } -/** - * A color value, storing red, green, blue and alpha components. - * This class does not use premultiplied alpha. - * - * XXX should this use doubles (instead of gfxFloat), for consistency with - * cairo? - */ -struct gfxRGBA { - gfxFloat r, g, b, a; - - enum PackedColorType { - PACKED_ABGR, - PACKED_ABGR_PREMULTIPLIED, - - PACKED_ARGB, - PACKED_ARGB_PREMULTIPLIED, - - PACKED_XRGB - }; - - gfxRGBA() { } - /** - * Intialize this color using explicit red, green, blue and alpha - * values. - */ - MOZ_CONSTEXPR gfxRGBA(gfxFloat _r, gfxFloat _g, gfxFloat _b, gfxFloat _a=1.0) : r(_r), g(_g), b(_b), a(_a) {} - - /** - * Initialize this color from a packed 32-bit color. - * The color value is interpreted based on colorType; - * all values use the native platform endianness. - * - * Resulting gfxRGBA stores non-premultiplied data. - * - * @see gfxRGBA::Packed - */ - MOZ_IMPLICIT gfxRGBA(uint32_t c, PackedColorType colorType = PACKED_ABGR) { - if (colorType == PACKED_ABGR || - colorType == PACKED_ABGR_PREMULTIPLIED) - { - r = ((c >> 0) & 0xff) * (1.0 / 255.0); - g = ((c >> 8) & 0xff) * (1.0 / 255.0); - b = ((c >> 16) & 0xff) * (1.0 / 255.0); - a = ((c >> 24) & 0xff) * (1.0 / 255.0); - } else if (colorType == PACKED_ARGB || - colorType == PACKED_XRGB || - colorType == PACKED_ARGB_PREMULTIPLIED) - { - b = ((c >> 0) & 0xff) * (1.0 / 255.0); - g = ((c >> 8) & 0xff) * (1.0 / 255.0); - r = ((c >> 16) & 0xff) * (1.0 / 255.0); - a = ((c >> 24) & 0xff) * (1.0 / 255.0); - } - - if (colorType == PACKED_ABGR_PREMULTIPLIED || - colorType == PACKED_ARGB_PREMULTIPLIED) - { - if (a > 0.0) { - r /= a; - g /= a; - b /= a; - } - } else if (colorType == PACKED_XRGB) { - a = 1.0; - } - } - - bool operator==(const gfxRGBA& other) const - { - return r == other.r && g == other.g && b == other.b && a == other.a; - } - bool operator!=(const gfxRGBA& other) const - { - return !(*this == other); - } - - /** - * Returns this color value as a packed 32-bit integer. This reconstructs - * the int32_t based on the given colorType, always in the native byte order. - * - * Note: gcc 4.2.3 on at least Ubuntu (x86) does something strange with - * (uint8_t)(c * 255.0) << x, where the result is different than - * double d = c * 255.0; v = ((uint8_t) d) << x. - */ - uint32_t Packed(PackedColorType colorType = PACKED_ABGR) const { - gfxFloat rb = (r * 255.0); - gfxFloat gb = (g * 255.0); - gfxFloat bb = (b * 255.0); - gfxFloat ab = (a * 255.0); - - if (colorType == PACKED_ABGR) { - return (uint8_t(ab) << 24) | - (uint8_t(bb) << 16) | - (uint8_t(gb) << 8) | - (uint8_t(rb) << 0); - } - if (colorType == PACKED_ARGB || colorType == PACKED_XRGB) { - return (uint8_t(ab) << 24) | - (uint8_t(rb) << 16) | - (uint8_t(gb) << 8) | - (uint8_t(bb) << 0); - } - - rb *= a; - gb *= a; - bb *= a; - - if (colorType == PACKED_ABGR_PREMULTIPLIED) { - return (((uint8_t)(ab) << 24) | - ((uint8_t)(bb) << 16) | - ((uint8_t)(gb) << 8) | - ((uint8_t)(rb) << 0)); - } - if (colorType == PACKED_ARGB_PREMULTIPLIED) { - return (((uint8_t)(ab) << 24) | - ((uint8_t)(rb) << 16) | - ((uint8_t)(gb) << 8) | - ((uint8_t)(bb) << 0)); - } - - return 0; - } -}; - #endif /* _GFX_COLOR_H */ diff --git a/gfx/thebes/gfxContext.cpp b/gfx/thebes/gfxContext.cpp index 4631b06b8cca..6035c12d71e7 100644 --- a/gfx/thebes/gfxContext.cpp +++ b/gfx/thebes/gfxContext.cpp @@ -14,7 +14,6 @@ #include "gfxContext.h" -#include "gfxColor.h" #include "gfxMatrix.h" #include "gfxUtils.h" #include "gfxASurface.h" diff --git a/gfx/thebes/gfxDrawable.cpp b/gfx/thebes/gfxDrawable.cpp index 18a68bd0e69e..c7ee4af23912 100644 --- a/gfx/thebes/gfxDrawable.cpp +++ b/gfx/thebes/gfxDrawable.cpp @@ -7,7 +7,6 @@ #include "gfxASurface.h" #include "gfxContext.h" #include "gfxPlatform.h" -#include "gfxColor.h" #include "gfx2DGlue.h" #ifdef MOZ_X11 #include "cairo.h" diff --git a/gfx/thebes/gfxFontUtils.cpp b/gfx/thebes/gfxFontUtils.cpp index f6d7af2a3b0e..a0779ea3fe1f 100644 --- a/gfx/thebes/gfxFontUtils.cpp +++ b/gfx/thebes/gfxFontUtils.cpp @@ -7,7 +7,6 @@ #include "mozilla/BinarySearch.h" #include "gfxFontUtils.h" -#include "gfxColor.h" #include "nsServiceManagerUtils.h" diff --git a/gfx/thebes/gfxQtNativeRenderer.h b/gfx/thebes/gfxQtNativeRenderer.h index 35617ab42c56..23c138e11fc0 100644 --- a/gfx/thebes/gfxQtNativeRenderer.h +++ b/gfx/thebes/gfxQtNativeRenderer.h @@ -6,7 +6,6 @@ #ifndef GFXQTNATIVERENDER_H_ #define GFXQTNATIVERENDER_H_ -#include "gfxColor.h" #include "gfxContext.h" #include "gfxXlibSurface.h" #include "mozilla/gfx/Rect.h" diff --git a/gfx/thebes/gfxSVGGlyphs.cpp b/gfx/thebes/gfxSVGGlyphs.cpp index 5d3b2de1b823..1e07b0f2c2b8 100644 --- a/gfx/thebes/gfxSVGGlyphs.cpp +++ b/gfx/thebes/gfxSVGGlyphs.cpp @@ -28,7 +28,6 @@ #include "gfxFont.h" #include "nsSMILAnimationController.h" #include "gfxContext.h" -#include "gfxColor.h" #include "harfbuzz/hb.h" #define SVG_CONTENT_TYPE NS_LITERAL_CSTRING("image/svg+xml") diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index 70760da3a4d0..c1bfcc734c0d 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -6,7 +6,6 @@ #ifndef GFX_UTILS_H #define GFX_UTILS_H -#include "gfxColor.h" #include "gfxTypes.h" #include "GraphicsFilter.h" #include "imgIContainer.h" diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index ace67493567c..b4d1c4b3df73 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -54,7 +54,6 @@ #include "ImageContainer.h" #include "mozilla/Telemetry.h" #include "gfxUtils.h" -#include "gfxColor.h" #include "gfxGradientCache.h" #include "GraphicsFilter.h" #include "nsInlineFrame.h" diff --git a/layout/svg/nsSVGGradientFrame.cpp b/layout/svg/nsSVGGradientFrame.cpp index f56beb77dc9f..9af45a8270b3 100644 --- a/layout/svg/nsSVGGradientFrame.cpp +++ b/layout/svg/nsSVGGradientFrame.cpp @@ -14,7 +14,6 @@ #include "nsContentUtils.h" #include "nsSVGEffects.h" #include "nsSVGAnimatedTransformList.h" -#include "gfxColor.h" // XXX Tight coupling with content classes ahead! diff --git a/layout/svg/nsSVGPatternFrame.cpp b/layout/svg/nsSVGPatternFrame.cpp index b8240a6faaf3..0b2a6d257eb7 100644 --- a/layout/svg/nsSVGPatternFrame.cpp +++ b/layout/svg/nsSVGPatternFrame.cpp @@ -23,7 +23,6 @@ #include "nsSVGUtils.h" #include "nsSVGAnimatedTransformList.h" #include "SVGContentUtils.h" -#include "gfxColor.h" using namespace mozilla; using namespace mozilla::dom; diff --git a/widget/windows/WinUtils.cpp b/widget/windows/WinUtils.cpp index f8c8184966fd..bb8517066817 100644 --- a/widget/windows/WinUtils.cpp +++ b/widget/windows/WinUtils.cpp @@ -42,7 +42,6 @@ #include "imgIEncoder.h" #include "nsIThread.h" #include "MainThreadUtils.h" -#include "gfxColor.h" #include "nsLookAndFeel.h" #ifdef NS_ENABLE_TSF From 2f51a9688ae3cbf6faa264764ea86150331a5354 Mon Sep 17 00:00:00 2001 From: Victor Carlquist Date: Thu, 17 Sep 2015 09:24:36 -0300 Subject: [PATCH 005/104] Bug 984018 - Fixed build on Arm64. r=nbp --HG-- extra : rebase_source : cee1b06da3fb8c8ae8a260498e365bc2fc382ba8 --- js/src/jit/arm64/vixl/MozSimulator-vixl.cpp | 2 ++ js/src/jit/shared/Lowering-shared-inl.h | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp b/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp index c78b5660450b..08389d2d1d8f 100644 --- a/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp +++ b/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp @@ -120,7 +120,9 @@ void Simulator::init(Decoder* decoder, FILE* stream) { lock_ = PR_NewLock(); if (!lock_) MOZ_CRASH("Could not allocate simulator lock."); +#ifdef DEBUG lockOwner_ = nullptr; +#endif redirection_ = nullptr; } diff --git a/js/src/jit/shared/Lowering-shared-inl.h b/js/src/jit/shared/Lowering-shared-inl.h index c151d17efa76..c7c01e50d80e 100644 --- a/js/src/jit/shared/Lowering-shared-inl.h +++ b/js/src/jit/shared/Lowering-shared-inl.h @@ -184,8 +184,12 @@ LIRGeneratorShared::defineSinCos(LInstructionHelper<2, Ops, Temps> *lir, MDefini uint32_t vreg = getVirtualRegister(); lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnDoubleReg))); -#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) - lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(d1))); +#if defined(JS_CODEGEN_ARM) + lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, + LFloatReg(FloatRegister(FloatRegisters::d1, FloatRegister::Double)))); +#elif defined(JS_CODEGEN_ARM64) + lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, + LFloatReg(FloatRegister(FloatRegisters::d1, FloatRegisters::Double)))); #elif defined(JS_CODEGEN_MIPS32) lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(f2))); #elif defined(JS_CODEGEN_NONE) From f30dfdb4a2b6775e59431ee12fe8c952c03ede68 Mon Sep 17 00:00:00 2001 From: "Jim Mathies [:jimm]" Date: Mon, 28 Sep 2015 12:35:00 +0200 Subject: [PATCH 006/104] Bug 1158111 - "Add caching and control updating tab offset values in the child from the parent side". a=klotz --HG-- extra : rebase_source : 905ab38197d648ba88fc6ea941f575208df9ff4d --- dom/ipc/PBrowser.ipdl | 8 -------- dom/ipc/TabParent.cpp | 7 ------- dom/ipc/TabParent.h | 1 - layout/generic/nsPluginFrame.cpp | 4 +--- 4 files changed, 1 insertion(+), 19 deletions(-) diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 4980b44e6d3d..d1cd7ae86d39 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -330,14 +330,6 @@ parent: sync IsParentWindowMainWidgetVisible() returns (bool visible); - /** - * Returns the offset of this tab from the top level window - * origin in device pixels. - * - * aPoint offset values in device pixels. - */ - prio(high) sync GetTabOffset() returns (LayoutDeviceIntPoint aPoint); - /** * Gets the DPI of the screen corresponding to this browser. */ diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 8f423c54b1de..d1132e9b1e17 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -2266,13 +2266,6 @@ TabParent::RecvEnableDisableCommands(const nsString& aAction, return true; } -bool -TabParent::RecvGetTabOffset(LayoutDeviceIntPoint* aPoint) -{ - *aPoint = GetChildProcessOffset(); - return true; -} - NS_IMETHODIMP TabParent::GetChildProcessOffset(int32_t* aOutCssX, int32_t* aOutCssY) { diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 80d67b5269e1..6ef8ca79b481 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -219,7 +219,6 @@ public: virtual bool RecvIsParentWindowMainWidgetVisible(bool* aIsVisible) override; virtual bool RecvShowTooltip(const uint32_t& aX, const uint32_t& aY, const nsString& aTooltip) override; virtual bool RecvHideTooltip() override; - virtual bool RecvGetTabOffset(LayoutDeviceIntPoint* aPoint) override; virtual bool RecvGetDPI(float* aValue) override; virtual bool RecvGetDefaultScale(double* aValue) override; virtual bool RecvGetMaxTouchPoints(uint32_t* aTouchPoints) override; diff --git a/layout/generic/nsPluginFrame.cpp b/layout/generic/nsPluginFrame.cpp index 97a713d9f2ae..81f248f893fb 100644 --- a/layout/generic/nsPluginFrame.cpp +++ b/layout/generic/nsPluginFrame.cpp @@ -776,9 +776,7 @@ nsPluginFrame::GetRemoteTabChromeOffset() if (topWindow) { dom::TabChild* tc = dom::TabChild::GetFrom(topWindow); if (tc) { - LayoutDeviceIntPoint chromeOffset; - tc->SendGetTabOffset(&chromeOffset); - offset -= chromeOffset; + offset += tc->GetChromeDisplacement(); } } } From 5c07d1ccdbc9272ea059e29217f074e958a4d378 Mon Sep 17 00:00:00 2001 From: David Newton Date: Fri, 25 Sep 2015 11:36:00 +0200 Subject: [PATCH 007/104] Bug 1160200 - APNG can't be used with type switching. r=mcaceres, sr=jrmuizel --HG-- extra : rebase_source : ea7ff84295608a51d663fee48707bfec5a8c13e5 --- image/DecoderFactory.cpp | 2 ++ image/build/nsImageModule.cpp | 1 + layout/reftests/apng-mime/animated.apng | Bin 0 -> 361 bytes layout/reftests/apng-mime/expected.html | 3 +++ layout/reftests/apng-mime/reftest.list | 1 + layout/reftests/apng-mime/static.png | Bin 0 -> 100 bytes layout/reftests/apng-mime/test.html | 6 ++++++ layout/reftests/reftest.list | 3 +++ netwerk/mime/nsMimeTypes.h | 1 + .../exthandler/nsExternalHelperAppService.cpp | 1 + 10 files changed, 18 insertions(+) create mode 100644 layout/reftests/apng-mime/animated.apng create mode 100644 layout/reftests/apng-mime/expected.html create mode 100644 layout/reftests/apng-mime/reftest.list create mode 100644 layout/reftests/apng-mime/static.png create mode 100644 layout/reftests/apng-mime/test.html diff --git a/image/DecoderFactory.cpp b/image/DecoderFactory.cpp index 5b4d8c808090..fbb448a73e89 100644 --- a/image/DecoderFactory.cpp +++ b/image/DecoderFactory.cpp @@ -34,6 +34,8 @@ DecoderFactory::GetDecoderType(const char* aMimeType) type = DecoderType::PNG; } else if (!strcmp(aMimeType, IMAGE_X_PNG)) { type = DecoderType::PNG; + } else if (!strcmp(aMimeType, IMAGE_APNG)) { + type = DecoderType::PNG; // GIF } else if (!strcmp(aMimeType, IMAGE_GIF)) { diff --git a/image/build/nsImageModule.cpp b/image/build/nsImageModule.cpp index 6bc4c04a6b46..f786005ddca4 100644 --- a/image/build/nsImageModule.cpp +++ b/image/build/nsImageModule.cpp @@ -77,6 +77,7 @@ static const mozilla::Module::CategoryEntry kImageCategories[] = { { "Gecko-Content-Viewers", IMAGE_BMP_MS, "@mozilla.org/content/document-loader-factory;1" }, { "Gecko-Content-Viewers", IMAGE_ICON_MS, "@mozilla.org/content/document-loader-factory;1" }, { "Gecko-Content-Viewers", IMAGE_PNG, "@mozilla.org/content/document-loader-factory;1" }, + { "Gecko-Content-Viewers", IMAGE_APNG, "@mozilla.org/content/document-loader-factory;1" }, { "Gecko-Content-Viewers", IMAGE_X_PNG, "@mozilla.org/content/document-loader-factory;1" }, { "content-sniffing-services", "@mozilla.org/image/loader;1", "@mozilla.org/image/loader;1" }, { nullptr } diff --git a/layout/reftests/apng-mime/animated.apng b/layout/reftests/apng-mime/animated.apng new file mode 100644 index 0000000000000000000000000000000000000000..a310055bb899e99249f157582bc4f7f873fcff2b GIT binary patch literal 361 zcmeAS@N?(olHy`uVBq!ia0vp^DImpw;&hW|jw@M)f~98i$4B*-tA!Qt5rkS?h-h%O)#VkC$G1}PwZZuB8dAkWs*#W5t~ z-rKW=ybKIH%nO$Ob3O0c&&E@rIl)6ksMAGhB2Fqrp>oN8KgA_kLSjIJVAe4L*%M7d`~|Wd(^4EmfHV`xN=HGUl}rn6?*9_?@7@ BT?POE literal 0 HcmV?d00001 diff --git a/layout/reftests/apng-mime/expected.html b/layout/reftests/apng-mime/expected.html new file mode 100644 index 000000000000..d069957fdf67 --- /dev/null +++ b/layout/reftests/apng-mime/expected.html @@ -0,0 +1,3 @@ + +apng expected + diff --git a/layout/reftests/apng-mime/reftest.list b/layout/reftests/apng-mime/reftest.list new file mode 100644 index 000000000000..fef0f4a7364d --- /dev/null +++ b/layout/reftests/apng-mime/reftest.list @@ -0,0 +1 @@ +== test.html expected.html diff --git a/layout/reftests/apng-mime/static.png b/layout/reftests/apng-mime/static.png new file mode 100644 index 0000000000000000000000000000000000000000..6f76d4438724111983a11860f13568361b52d9bc GIT binary patch literal 100 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5y8Awi_W^)%vF$egBxTd6}EPfSw1jv=~ba4!k rkbHZv5y)XUyx@1R|3ikWAU1;^qeuV)<1IPC3=q%L)z4*}Q$iB}r??p{ literal 0 HcmV?d00001 diff --git a/layout/reftests/apng-mime/test.html b/layout/reftests/apng-mime/test.html new file mode 100644 index 000000000000..35c1dc09d58f --- /dev/null +++ b/layout/reftests/apng-mime/test.html @@ -0,0 +1,6 @@ + +apng test + + + + diff --git a/layout/reftests/reftest.list b/layout/reftests/reftest.list index eca7e0c590c1..9b38f585d31c 100644 --- a/layout/reftests/reftest.list +++ b/layout/reftests/reftest.list @@ -19,6 +19,9 @@ include w3c-css/received/reftest.list include abs-pos/reftest.list include position-relative/reftest.list +# apng-mime +include apng-mime/reftest.list + include async-scrolling/reftest.list # backgrounds/ diff --git a/netwerk/mime/nsMimeTypes.h b/netwerk/mime/nsMimeTypes.h index 13d99b3cc56c..c4c3a5245ef4 100644 --- a/netwerk/mime/nsMimeTypes.h +++ b/netwerk/mime/nsMimeTypes.h @@ -94,6 +94,7 @@ #define IMAGE_JPG "image/jpg" #define IMAGE_PJPEG "image/pjpeg" #define IMAGE_PNG "image/png" +#define IMAGE_APNG "video/vnd.mozilla.apng" #define IMAGE_X_PNG "image/x-png" #define IMAGE_PPM "image/x-portable-pixmap" #define IMAGE_XBM "image/x-xbitmap" diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index c7bfb9f50b0a..52fdd1cce95f 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -576,6 +576,7 @@ static nsExtraMimeTypeEntry extraMimeEntries [] = { IMAGE_ICO, "ico,cur", "ICO Image" }, { IMAGE_JPEG, "jpeg,jpg,jfif,pjpeg,pjp", "JPEG Image" }, { IMAGE_PNG, "png", "PNG Image" }, + { IMAGE_APNG, "apng", "APNG Image" }, { IMAGE_TIFF, "tiff,tif", "TIFF Image" }, { IMAGE_XBM, "xbm", "XBM Image" }, { IMAGE_SVG_XML, "svg", "Scalable Vector Graphics" }, From f6556a02ec40d707608d5c187ccf7e55c5048873 Mon Sep 17 00:00:00 2001 From: Jakob Olesen Date: Fri, 18 Sep 2015 10:40:00 +0200 Subject: [PATCH 008/104] Bug 1205893 - Remove vanilla allocations in ARM64 simulator. r=sstangl Use js_malloc/js_free and js_new/js_delete where appropriate. Replace std::list with mozilla::Vector. The standard list template uses operator new which isn't allowed in SpiderMonkey sources. The Vector is also a more appropriate data structure for these short, infrequently modified lists. Remove the Decoder::visitors() method which was unused and leaking internal representation details anyway. --HG-- extra : rebase_source : 9fe5bceb9dd7eb7375187f62f27289c3900240f4 --- js/src/jit/arm64/vixl/Decoder-vixl.cpp | 32 ++++++++---------- js/src/jit/arm64/vixl/Decoder-vixl.h | 18 ++++------- js/src/jit/arm64/vixl/Instrument-vixl.cpp | 36 +++++++++------------ js/src/jit/arm64/vixl/Instrument-vixl.h | 6 +++- js/src/jit/arm64/vixl/MozSimulator-vixl.cpp | 6 ++-- js/src/jit/arm64/vixl/Simulator-vixl.cpp | 10 +++--- 6 files changed, 48 insertions(+), 60 deletions(-) diff --git a/js/src/jit/arm64/vixl/Decoder-vixl.cpp b/js/src/jit/arm64/vixl/Decoder-vixl.cpp index f60c29d7c5ea..52f05f9b26af 100644 --- a/js/src/jit/arm64/vixl/Decoder-vixl.cpp +++ b/js/src/jit/arm64/vixl/Decoder-vixl.cpp @@ -26,6 +26,8 @@ #include "jit/arm64/vixl/Decoder-vixl.h" +#include + #include "jit/arm64/vixl/Globals-vixl.h" #include "jit/arm64/vixl/Utils-vixl.h" @@ -110,50 +112,45 @@ void Decoder::DecodeInstruction(const Instruction *instr) { } void Decoder::AppendVisitor(DecoderVisitor* new_visitor) { - visitors_.push_back(new_visitor); + visitors_.append(new_visitor); } void Decoder::PrependVisitor(DecoderVisitor* new_visitor) { - visitors_.push_front(new_visitor); + visitors_.insert(visitors_.begin(), new_visitor); } void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor, DecoderVisitor* registered_visitor) { - std::list::iterator it; - for (it = visitors_.begin(); it != visitors_.end(); it++) { + for (auto it = visitors_.begin(); it != visitors_.end(); it++) { if (*it == registered_visitor) { visitors_.insert(it, new_visitor); return; } } - // We reached the end of the list. The last element must be - // registered_visitor. - VIXL_ASSERT(*it == registered_visitor); - visitors_.insert(it, new_visitor); + // We reached the end of the list without finding registered_visitor. + visitors_.append(new_visitor); } void Decoder::InsertVisitorAfter(DecoderVisitor* new_visitor, DecoderVisitor* registered_visitor) { - std::list::iterator it; - for (it = visitors_.begin(); it != visitors_.end(); it++) { + for (auto it = visitors_.begin(); it != visitors_.end(); it++) { if (*it == registered_visitor) { it++; visitors_.insert(it, new_visitor); return; } } - // We reached the end of the list. The last element must be - // registered_visitor. - VIXL_ASSERT(*it == registered_visitor); - visitors_.push_back(new_visitor); + // We reached the end of the list without finding registered_visitor. + visitors_.append(new_visitor); } void Decoder::RemoveVisitor(DecoderVisitor* visitor) { - visitors_.remove(visitor); + visitors_.erase(std::remove(visitors_.begin(), visitors_.end(), visitor), + visitors_.end()); } @@ -698,9 +695,8 @@ void Decoder::DecodeAdvSIMDDataProcessing(const Instruction* instr) { #define DEFINE_VISITOR_CALLERS(A) \ void Decoder::Visit##A(const Instruction *instr) { \ VIXL_ASSERT(instr->Mask(A##FMask) == A##Fixed); \ - std::list::iterator it; \ - for (it = visitors_.begin(); it != visitors_.end(); it++) { \ - (*it)->Visit##A(instr); \ + for (auto visitor : visitors_) { \ + visitor->Visit##A(instr); \ } \ } VISITOR_LIST(DEFINE_VISITOR_CALLERS) diff --git a/js/src/jit/arm64/vixl/Decoder-vixl.h b/js/src/jit/arm64/vixl/Decoder-vixl.h index a095e16f9792..f3228b5cf5d5 100644 --- a/js/src/jit/arm64/vixl/Decoder-vixl.h +++ b/js/src/jit/arm64/vixl/Decoder-vixl.h @@ -27,7 +27,9 @@ #ifndef VIXL_A64_DECODER_A64_H_ #define VIXL_A64_DECODER_A64_H_ -#include +#include "mozilla/Vector.h" + +#include "jsalloc.h" #include "jit/arm64/vixl/Globals-vixl.h" #include "jit/arm64/vixl/Instructions-vixl.h" @@ -118,9 +120,8 @@ class Decoder { // Top-level wrappers around the actual decoding function. void Decode(const Instruction* instr) { - std::list::iterator it; - for (it = visitors_.begin(); it != visitors_.end(); it++) { - VIXL_ASSERT((*it)->IsConstVisitor()); + for (auto visitor : visitors_) { + VIXL_ASSERT(visitor->IsConstVisitor()); } DecodeInstruction(instr); } @@ -154,10 +155,6 @@ class Decoder { // d.InsertVisitorBefore(V4, V2); // will yield the order // V1, V3, V4, V2, V1, V2 - // - // For more complex modifications of the order of registered visitors, one can - // directly access and modify the list of visitors via the `visitors()' - // accessor. void InsertVisitorBefore(DecoderVisitor* new_visitor, DecoderVisitor* registered_visitor); void InsertVisitorAfter(DecoderVisitor* new_visitor, @@ -171,9 +168,6 @@ class Decoder { VISITOR_LIST(DECLARE) #undef DECLARE - - std::list* visitors() { return &visitors_; } - private: // Decodes an instruction and calls the visitor functions registered with the // Decoder class. @@ -231,7 +225,7 @@ class Decoder { private: // Visitors are registered in a list. - std::list visitors_; + mozilla::Vector visitors_; }; } // namespace vixl diff --git a/js/src/jit/arm64/vixl/Instrument-vixl.cpp b/js/src/jit/arm64/vixl/Instrument-vixl.cpp index c45e95a9209c..bc8535a0d909 100644 --- a/js/src/jit/arm64/vixl/Instrument-vixl.cpp +++ b/js/src/jit/arm64/vixl/Instrument-vixl.cpp @@ -136,8 +136,8 @@ Instrument::Instrument(const char* datafile, uint64_t sample_period) // Construct Counter objects from counter description array. for (int i = 0; i < num_counters; i++) { - Counter* counter = new Counter(kCounterList[i].name, kCounterList[i].type); - counters_.push_back(counter); + Counter* counter = js_new(kCounterList[i].name, kCounterList[i].type); + counters_.append(counter); } DumpCounterNames(); @@ -149,9 +149,8 @@ Instrument::~Instrument() { DumpCounters(); // Free all the counter objects. - std::list::iterator it; - for (it = counters_.begin(); it != counters_.end(); it++) { - delete *it; + for (auto counter : counters_) { + js_delete(counter); } if (output_stream_ != stdout) { @@ -176,9 +175,8 @@ void Instrument::Update() { void Instrument::DumpCounters() { // Iterate through the counter objects, dumping their values to the output // stream. - std::list::const_iterator it; - for (it = counters_.begin(); it != counters_.end(); it++) { - fprintf(output_stream_, "%" PRIu64 ",", (*it)->count()); + for (auto counter : counters_) { + fprintf(output_stream_, "%" PRIu64 ",", counter->count()); } fprintf(output_stream_, "\n"); fflush(output_stream_); @@ -188,9 +186,8 @@ void Instrument::DumpCounters() { void Instrument::DumpCounterNames() { // Iterate through the counter objects, dumping the counter names to the // output stream. - std::list::const_iterator it; - for (it = counters_.begin(); it != counters_.end(); it++) { - fprintf(output_stream_, "%s,", (*it)->name()); + for (auto counter : counters_) { + fprintf(output_stream_, "%s,", counter->name()); } fprintf(output_stream_, "\n"); fflush(output_stream_); @@ -218,10 +215,9 @@ void Instrument::DumpEventMarker(unsigned marker) { Counter* Instrument::GetCounter(const char* name) { // Get a Counter object by name from the counter list. - std::list::const_iterator it; - for (it = counters_.begin(); it != counters_.end(); it++) { - if (strcmp((*it)->name(), name) == 0) { - return *it; + for (auto counter : counters_) { + if (strcmp(counter->name(), name) == 0) { + return counter; } } @@ -236,17 +232,15 @@ Counter* Instrument::GetCounter(const char* name) { void Instrument::Enable() { - std::list::iterator it; - for (it = counters_.begin(); it != counters_.end(); it++) { - (*it)->Enable(); + for (auto counter : counters_) { + counter->Enable(); } } void Instrument::Disable() { - std::list::iterator it; - for (it = counters_.begin(); it != counters_.end(); it++) { - (*it)->Disable(); + for (auto counter : counters_) { + counter->Disable(); } } diff --git a/js/src/jit/arm64/vixl/Instrument-vixl.h b/js/src/jit/arm64/vixl/Instrument-vixl.h index c09fdbabb2c1..43cd37ad74ce 100644 --- a/js/src/jit/arm64/vixl/Instrument-vixl.h +++ b/js/src/jit/arm64/vixl/Instrument-vixl.h @@ -27,6 +27,10 @@ #ifndef VIXL_A64_INSTRUMENT_A64_H_ #define VIXL_A64_INSTRUMENT_A64_H_ +#include "mozilla/Vector.h" + +#include "jsalloc.h" + #include "jit/arm64/vixl/Constants-vixl.h" #include "jit/arm64/vixl/Decoder-vixl.h" #include "jit/arm64/vixl/Globals-vixl.h" @@ -95,7 +99,7 @@ class Instrument: public DecoderVisitor { void InstrumentLoadStore(const Instruction* instr); void InstrumentLoadStorePair(const Instruction* instr); - std::list counters_; + mozilla::Vector counters_; FILE *output_stream_; uint64_t sample_period_; diff --git a/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp b/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp index 08389d2d1d8f..a9169e41d9ea 100644 --- a/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp +++ b/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp @@ -91,14 +91,14 @@ void Simulator::init(Decoder* decoder, FILE* stream) { decoder_->AppendVisitor(this); stream_ = stream; - print_disasm_ = new PrintDisassembler(stream_); + print_disasm_ = js_new(stream_); set_coloured_trace(false); trace_parameters_ = LOG_NONE; ResetState(); // Allocate and set up the simulator stack. - stack_ = new byte[stack_size_]; + stack_ = (byte*)js_malloc(stack_size_); stack_limit_ = stack_ + stack_protection_size_; // Configure the starting stack pointer. // - Find the top of the stack. @@ -110,7 +110,7 @@ void Simulator::init(Decoder* decoder, FILE* stream) { set_sp(tos); // Set the sample period to 10, as the VIXL examples and tests are short. - instrumentation_ = new Instrument("vixl_stats.csv", 10); + instrumentation_ = js_new("vixl_stats.csv", 10); // Print a warning about exclusive-access instructions, but only the first // time they are encountered. This warning can be silenced using diff --git a/js/src/jit/arm64/vixl/Simulator-vixl.cpp b/js/src/jit/arm64/vixl/Simulator-vixl.cpp index a01df8b2608c..391ca38ffa38 100644 --- a/js/src/jit/arm64/vixl/Simulator-vixl.cpp +++ b/js/src/jit/arm64/vixl/Simulator-vixl.cpp @@ -68,13 +68,13 @@ SimSystemRegister SimSystemRegister::DefaultValueFor(SystemRegister id) { Simulator::~Simulator() { - delete [] stack_; + js_free(stack_); // The decoder may outlive the simulator. decoder_->RemoveVisitor(print_disasm_); - delete print_disasm_; + js_delete(print_disasm_); decoder_->RemoveVisitor(instrumentation_); - delete instrumentation_; + js_delete(instrumentation_); } @@ -2791,7 +2791,7 @@ void Simulator::DoPrintf(const Instruction* instr) { const char * format_base = reg(0); VIXL_ASSERT(format_base != NULL); size_t length = strlen(format_base) + 1; - char * const format = new char[length + arg_count]; + char * const format = (char*)js_malloc(length + arg_count); // A list of chunks, each with exactly one format placeholder. const char * chunks[kPrintfMaxArgCount]; @@ -2867,7 +2867,7 @@ void Simulator::DoPrintf(const Instruction* instr) { // Set LR as if we'd just called a native printf function. set_lr(pc()); - delete[] format; + js_free(format); } } // namespace vixl From 0e76bec44c1cca6c18e1a363f4696c4b6829f185 Mon Sep 17 00:00:00 2001 From: Jakob Olesen Date: Fri, 18 Sep 2015 10:41:00 +0200 Subject: [PATCH 009/104] Bug 1205893 - Eliminate vanilla memory allocations in Debugger-vixl. r=sstangl Use js_malloc/js_free or js_new/js_delete pairs where appropriate. Replace the use of std::vector for debugger command arguments with a mozilla::Vector. Also use move constructors everywhere for the command arguments instead of passing vector around by value. --HG-- extra : rebase_source : 35b164aec865817aa907d553772a2f99d4ee9b85 --- js/src/jit/arm64/vixl/Debugger-vixl.cpp | 231 ++++++++++++------------ js/src/jit/arm64/vixl/Debugger-vixl.h | 1 - 2 files changed, 117 insertions(+), 115 deletions(-) diff --git a/js/src/jit/arm64/vixl/Debugger-vixl.cpp b/js/src/jit/arm64/vixl/Debugger-vixl.cpp index 96844127c2bf..27a20a4d7baf 100644 --- a/js/src/jit/arm64/vixl/Debugger-vixl.cpp +++ b/js/src/jit/arm64/vixl/Debugger-vixl.cpp @@ -30,6 +30,10 @@ #include "jit/arm64/vixl/Debugger-vixl.h" +#include "mozilla/Vector.h" + +#include "jsalloc.h" + namespace vixl { // List of commands supported by the debugger. @@ -63,6 +67,8 @@ class Token { static Token* Tokenize(const char* arg); }; +typedef mozilla::Vector TokenVector; + // Tokens often hold one value. template class ValueToken : public Token { public: @@ -124,10 +130,10 @@ class IdentifierToken : public ValueToken { public: explicit IdentifierToken(const char* name) { int size = strlen(name) + 1; - value_ = new char[size]; + value_ = (char*)js_malloc(size); strncpy(value_, name, size); } - virtual ~IdentifierToken() { delete[] value_; } + virtual ~IdentifierToken() { js_free(value_); } virtual bool IsIdentifier() const { return true; } virtual bool CanAddressMemory() const { return strcmp(value(), "pc") == 0; } @@ -227,10 +233,10 @@ class UnknownToken : public Token { public: explicit UnknownToken(const char* arg) { int size = strlen(arg) + 1; - unknown_ = new char[size]; + unknown_ = (char*)js_malloc(size); strncpy(unknown_, arg, size); } - virtual ~UnknownToken() { delete[] unknown_; } + virtual ~UnknownToken() { js_free(unknown_); } virtual bool IsUnknown() const { return true; } virtual void Print(FILE* out = stdout) const; @@ -246,7 +252,7 @@ class DebugCommand { public: explicit DebugCommand(Token* name) : name_(IdentifierToken::Cast(name)) {} DebugCommand() : name_(NULL) {} - virtual ~DebugCommand() { delete name_; } + virtual ~DebugCommand() { js_delete(name_); } const char* name() { return name_->value(); } // Run the command on the given debugger. The command returns true if @@ -272,7 +278,7 @@ class HelpCommand : public DebugCommand { virtual bool Run(Debugger* debugger); - static DebugCommand* Build(std::vector args); + static DebugCommand* Build(TokenVector &&args); static const char* kHelp; static const char* kAliases[]; @@ -286,7 +292,7 @@ class ContinueCommand : public DebugCommand { virtual bool Run(Debugger* debugger); - static DebugCommand* Build(std::vector args); + static DebugCommand* Build(TokenVector &&args); static const char* kHelp; static const char* kAliases[]; @@ -298,13 +304,13 @@ class StepCommand : public DebugCommand { public: StepCommand(Token* name, IntegerToken* count) : DebugCommand(name), count_(count) {} - virtual ~StepCommand() { delete count_; } + virtual ~StepCommand() { js_delete(count_); } int64_t count() { return count_->value(); } virtual bool Run(Debugger* debugger); virtual void Print(FILE* out = stdout); - static DebugCommand* Build(std::vector args); + static DebugCommand* Build(TokenVector &&args); static const char* kHelp; static const char* kAliases[]; @@ -316,7 +322,7 @@ class StepCommand : public DebugCommand { class DisasmCommand : public DebugCommand { public: - static DebugCommand* Build(std::vector args); + static DebugCommand* Build(TokenVector &&args); static const char* kHelp; static const char* kAliases[]; @@ -329,8 +335,8 @@ class PrintCommand : public DebugCommand { PrintCommand(Token* name, Token* target, FormatToken* format) : DebugCommand(name), target_(target), format_(format) {} virtual ~PrintCommand() { - delete target_; - delete format_; + js_delete(target_); + js_delete(format_); } Token* target() { return target_; } @@ -338,7 +344,7 @@ class PrintCommand : public DebugCommand { virtual bool Run(Debugger* debugger); virtual void Print(FILE* out = stdout); - static DebugCommand* Build(std::vector args); + static DebugCommand* Build(TokenVector &&args); static const char* kHelp; static const char* kAliases[]; @@ -357,9 +363,9 @@ class ExamineCommand : public DebugCommand { IntegerToken* count) : DebugCommand(name), target_(target), format_(format), count_(count) {} virtual ~ExamineCommand() { - delete target_; - delete format_; - delete count_; + js_delete(target_); + js_delete(format_); + js_delete(count_); } Token* target() { return target_; } @@ -368,7 +374,7 @@ class ExamineCommand : public DebugCommand { virtual bool Run(Debugger* debugger); virtual void Print(FILE* out = stdout); - static DebugCommand* Build(std::vector args); + static DebugCommand* Build(TokenVector &&args); static const char* kHelp; static const char* kAliases[]; @@ -383,26 +389,26 @@ class ExamineCommand : public DebugCommand { // Commands which name does not match any of the known commnand. class UnknownCommand : public DebugCommand { public: - explicit UnknownCommand(std::vector args) : args_(args) {} + explicit UnknownCommand(TokenVector &&args) : args_(Move(args)) {} virtual ~UnknownCommand(); virtual bool Run(Debugger* debugger); private: - std::vector args_; + TokenVector args_; }; // Commands which name match a known command but the syntax is invalid. class InvalidCommand : public DebugCommand { public: - InvalidCommand(std::vector args, int index, const char* cause) - : args_(args), index_(index), cause_(cause) {} + InvalidCommand(TokenVector &&args, int index, const char* cause) + : args_(Move(args)), index_(index), cause_(cause) {} virtual ~InvalidCommand(); virtual bool Run(Debugger* debugger); private: - std::vector args_; + TokenVector args_; int index_; const char* cause_; }; @@ -530,8 +536,8 @@ Debugger::Debugger(Decoder* decoder, FILE* stream) pending_request_(false), steps_(0), last_command_(NULL) { - disasm_ = new PrintDisassembler(stdout); - printer_ = new Decoder(); + disasm_ = js_new(stdout); + printer_ = js_new(); printer_->AppendVisitor(disasm_); } @@ -823,7 +829,7 @@ Token* Token::Tokenize(const char* arg) { return token; } - return new UnknownToken(arg); + return js_new(arg); } @@ -856,14 +862,14 @@ Token* RegisterToken::Tokenize(const char* arg) { // Is it a X register or alias? for (const char** current = kXAliases[i]; *current != NULL; current++) { if (strcmp(arg, *current) == 0) { - return new RegisterToken(Register::XRegFromCode(i)); + return js_new(Register::XRegFromCode(i)); } } // Is it a W register or alias? for (const char** current = kWAliases[i]; *current != NULL; current++) { if (strcmp(arg, *current) == 0) { - return new RegisterToken(Register::WRegFromCode(i)); + return js_new(Register::WRegFromCode(i)); } } } @@ -904,7 +910,7 @@ Token* FPRegisterToken::Tokenize(const char* arg) { default: VIXL_UNREACHABLE(); } - return new FPRegisterToken(fpreg); + return js_new(fpreg); } return NULL; @@ -935,7 +941,7 @@ Token* IdentifierToken::Tokenize(const char* arg) { } if (*cursor == '\0') { - return new IdentifierToken(arg); + return js_new(arg); } return NULL; @@ -964,7 +970,7 @@ Token* AddressToken::Tokenize(const char* arg) { } uint8_t* address = reinterpret_cast(ptr); - return new AddressToken(address); + return js_new(address); } @@ -979,7 +985,7 @@ Token* IntegerToken::Tokenize(const char* arg) { return NULL; } - return new IntegerToken(value); + return js_new(value); } @@ -993,7 +999,7 @@ Token* FormatToken::Tokenize(const char* arg) { if (length == 1) return NULL; break; case 'i': - if (length == 1) return new Format("%08" PRIx32, 'i'); + if (length == 1) return js_new>("%08" PRIx32, 'i'); default: return NULL; } @@ -1019,32 +1025,32 @@ Token* FormatToken::Tokenize(const char* arg) { switch (arg[0]) { case 'x': switch (count) { - case 8: return new Format("%02" PRIx8, 'x'); - case 16: return new Format("%04" PRIx16, 'x'); - case 32: return new Format("%08" PRIx32, 'x'); - case 64: return new Format("%016" PRIx64, 'x'); + case 8: return js_new>("%02" PRIx8, 'x'); + case 16: return js_new>("%04" PRIx16, 'x'); + case 32: return js_new>("%08" PRIx32, 'x'); + case 64: return js_new>("%016" PRIx64, 'x'); default: return NULL; } case 's': switch (count) { - case 8: return new Format("%4" PRId8, 's'); - case 16: return new Format("%6" PRId16, 's'); - case 32: return new Format("%11" PRId32, 's'); - case 64: return new Format("%20" PRId64, 's'); + case 8: return js_new>("%4" PRId8, 's'); + case 16: return js_new>("%6" PRId16, 's'); + case 32: return js_new>("%11" PRId32, 's'); + case 64: return js_new>("%20" PRId64, 's'); default: return NULL; } case 'u': switch (count) { - case 8: return new Format("%3" PRIu8, 'u'); - case 16: return new Format("%5" PRIu16, 'u'); - case 32: return new Format("%10" PRIu32, 'u'); - case 64: return new Format("%20" PRIu64, 'u'); + case 8: return js_new>("%3" PRIu8, 'u'); + case 16: return js_new>("%5" PRIu16, 'u'); + case 32: return js_new>("%10" PRIu32, 'u'); + case 64: return js_new>("%20" PRIu64, 'u'); default: return NULL; } case 'f': switch (count) { - case 32: return new Format("%13g", 'f'); - case 64: return new Format("%13g", 'f'); + case 32: return js_new>("%13g", 'f'); + case 64: return js_new>("%13g", 'f'); default: return NULL; } default: @@ -1083,7 +1089,7 @@ bool DebugCommand::Match(const char* name, const char** aliases) { DebugCommand* DebugCommand::Parse(char* line) { - std::vector args; + TokenVector args; for (char* chunk = strtok(line, " \t"); chunk != NULL; @@ -1094,35 +1100,35 @@ DebugCommand* DebugCommand::Parse(char* line) { Token* format = FormatToken::Tokenize(dot + 1); if (format != NULL) { *dot = '\0'; - args.push_back(Token::Tokenize(chunk)); - args.push_back(format); + args.append(Token::Tokenize(chunk)); + args.append(format); } else { // Error while parsing the format, push the UnknownToken so an error // can be accurately reported. - args.push_back(Token::Tokenize(chunk)); + args.append(Token::Tokenize(chunk)); } } else { - args.push_back(Token::Tokenize(chunk)); + args.append(Token::Tokenize(chunk)); } } - if (args.size() == 0) { + if (args.empty()) { return NULL; } if (!args[0]->IsIdentifier()) { - return new InvalidCommand(args, 0, "command name is not valid"); + return js_new(Move(args), 0, "command name is not valid"); } const char* name = IdentifierToken::Cast(args[0])->value(); #define RETURN_IF_MATCH(Command) \ if (Match(name, Command::kAliases)) { \ - return Command::Build(args); \ + return Command::Build(Move(args)); \ } DEBUG_COMMAND_LIST(RETURN_IF_MATCH); #undef RETURN_IF_MATCH - return new UnknownCommand(args); + return js_new(Move(args)); } @@ -1160,12 +1166,12 @@ bool HelpCommand::Run(Debugger* debugger) { } -DebugCommand* HelpCommand::Build(std::vector args) { - if (args.size() != 1) { - return new InvalidCommand(args, -1, "too many arguments"); +DebugCommand* HelpCommand::Build(TokenVector &&args) { + if (args.length() != 1) { + return js_new(Move(args), -1, "too many arguments"); } - return new HelpCommand(args[0]); + return js_new(args[0]); } @@ -1177,12 +1183,12 @@ bool ContinueCommand::Run(Debugger* debugger) { } -DebugCommand* ContinueCommand::Build(std::vector args) { - if (args.size() != 1) { - return new InvalidCommand(args, -1, "too many arguments"); +DebugCommand* ContinueCommand::Build(TokenVector &&args) { + if (args.length() != 1) { + return js_new(Move(args), -1, "too many arguments"); } - return new ContinueCommand(args[0]); + return js_new(args[0]); } @@ -1205,52 +1211,52 @@ void StepCommand::Print(FILE* out) { } -DebugCommand* StepCommand::Build(std::vector args) { +DebugCommand* StepCommand::Build(TokenVector &&args) { IntegerToken* count = NULL; - switch (args.size()) { + switch (args.length()) { case 1: { // step [1] - count = new IntegerToken(1); + count = js_new(1); break; } case 2: { // step n Token* first = args[1]; if (!first->IsInteger()) { - return new InvalidCommand(args, 1, "expects int"); + return js_new(Move(args), 1, "expects int"); } count = IntegerToken::Cast(first); break; } default: - return new InvalidCommand(args, -1, "too many arguments"); + return js_new(Move(args), -1, "too many arguments"); } - return new StepCommand(args[0], count); + return js_new(args[0], count); } -DebugCommand* DisasmCommand::Build(std::vector args) { +DebugCommand* DisasmCommand::Build(TokenVector &&args) { IntegerToken* count = NULL; - switch (args.size()) { + switch (args.length()) { case 1: { // disasm [10] - count = new IntegerToken(10); + count = js_new(10); break; } case 2: { // disasm n Token* first = args[1]; if (!first->IsInteger()) { - return new InvalidCommand(args, 1, "expects int"); + return js_new(Move(args), 1, "expects int"); } count = IntegerToken::Cast(first); break; } default: - return new InvalidCommand(args, -1, "too many arguments"); + return js_new(Move(args), -1, "too many arguments"); } - Token* target = new IdentifierToken("pc"); - FormatToken* format = new Format("%08" PRIx32, 'i'); - return new ExamineCommand(args[0], target, format, count); + Token* target = js_new("pc"); + FormatToken* format = js_new>("%08" PRIx32, 'i'); + return js_new(args[0], target, format, count); } @@ -1308,16 +1314,16 @@ bool PrintCommand::Run(Debugger* debugger) { } -DebugCommand* PrintCommand::Build(std::vector args) { - if (args.size() < 2) { - return new InvalidCommand(args, -1, "too few arguments"); +DebugCommand* PrintCommand::Build(TokenVector &&args) { + if (args.length() < 2) { + return js_new(Move(args), -1, "too few arguments"); } Token* target = args[1]; if (!target->IsRegister() && !target->IsFPRegister() && !target->IsIdentifier()) { - return new InvalidCommand(args, 1, "expects reg or identifier"); + return js_new(Move(args), 1, "expects reg or identifier"); } FormatToken* format = NULL; @@ -1332,18 +1338,18 @@ DebugCommand* PrintCommand::Build(std::vector args) { // If the target is an identifier there must be no format. This is checked // in the switch statement below. - switch (args.size()) { + switch (args.length()) { case 2: { if (target->IsRegister()) { switch (target_size) { - case 4: format = new Format("%08" PRIx32, 'x'); break; - case 8: format = new Format("%016" PRIx64, 'x'); break; + case 4: format = js_new>("%08" PRIx32, 'x'); break; + case 8: format = js_new>("%016" PRIx64, 'x'); break; default: VIXL_UNREACHABLE(); } } else if (target->IsFPRegister()) { switch (target_size) { - case 4: format = new Format("%8g", 'f'); break; - case 8: format = new Format("%8g", 'f'); break; + case 4: format = js_new>("%8g", 'f'); break; + case 8: format = js_new>("%8g", 'f'); break; default: VIXL_UNREACHABLE(); } } @@ -1351,27 +1357,27 @@ DebugCommand* PrintCommand::Build(std::vector args) { } case 3: { if (target->IsIdentifier()) { - return new InvalidCommand(args, 2, + return js_new(Move(args), 2, "format is only allowed with registers"); } Token* second = args[2]; if (!second->IsFormat()) { - return new InvalidCommand(args, 2, "expects format"); + return js_new(Move(args), 2, "expects format"); } format = FormatToken::Cast(second); if (format->SizeOf() > target_size) { - return new InvalidCommand(args, 2, "format too wide"); + return js_new(Move(args), 2, "format too wide"); } break; } default: - return new InvalidCommand(args, -1, "too many arguments"); + return js_new(Move(args), -1, "too many arguments"); } - return new PrintCommand(args[0], target, format); + return js_new(args[0], target, format); } @@ -1397,23 +1403,23 @@ void ExamineCommand::Print(FILE* out) { } -DebugCommand* ExamineCommand::Build(std::vector args) { - if (args.size() < 2) { - return new InvalidCommand(args, -1, "too few arguments"); +DebugCommand* ExamineCommand::Build(TokenVector &&args) { + if (args.length() < 2) { + return js_new(Move(args), -1, "too few arguments"); } Token* target = args[1]; if (!target->CanAddressMemory()) { - return new InvalidCommand(args, 1, "expects address"); + return js_new(Move(args), 1, "expects address"); } FormatToken* format = NULL; IntegerToken* count = NULL; - switch (args.size()) { + switch (args.length()) { case 2: { // mem addr[.x64] [10] - format = new Format("%016" PRIx64, 'x'); - count = new IntegerToken(10); + format = js_new>("%016" PRIx64, 'x'); + count = js_new(10); break; } case 3: { // mem addr.format [10] @@ -1421,13 +1427,13 @@ DebugCommand* ExamineCommand::Build(std::vector args) { Token* second = args[2]; if (second->IsFormat()) { format = FormatToken::Cast(second); - count = new IntegerToken(10); + count = js_new(10); break; } else if (second->IsInteger()) { - format = new Format("%016" PRIx64, 'x'); + format = js_new>("%016" PRIx64, 'x'); count = IntegerToken::Cast(second); } else { - return new InvalidCommand(args, 2, "expects format or integer"); + return js_new(Move(args), 2, "expects format or integer"); } VIXL_UNREACHABLE(); break; @@ -1436,24 +1442,23 @@ DebugCommand* ExamineCommand::Build(std::vector args) { Token* second = args[2]; Token* third = args[3]; if (!second->IsFormat() || !third->IsInteger()) { - return new InvalidCommand(args, -1, "expects addr[.format] [n]"); + return js_new(Move(args), -1, "expects addr[.format] [n]"); } format = FormatToken::Cast(second); count = IntegerToken::Cast(third); break; } default: - return new InvalidCommand(args, -1, "too many arguments"); + return js_new(Move(args), -1, "too many arguments"); } - return new ExamineCommand(args[0], target, format, count); + return js_new(args[0], target, format, count); } UnknownCommand::~UnknownCommand() { - const int size = args_.size(); - for (int i = 0; i < size; ++i) { - delete args_[i]; + for (auto arg : args_) { + js_delete(arg); } } @@ -1463,10 +1468,9 @@ bool UnknownCommand::Run(Debugger* debugger) { USE(debugger); printf(" ** Unknown Command:"); - const int size = args_.size(); - for (int i = 0; i < size; ++i) { + for (auto arg : args_) { printf(" "); - args_[i]->Print(stdout); + arg->Print(stdout); } printf(" **\n"); @@ -1475,9 +1479,8 @@ bool UnknownCommand::Run(Debugger* debugger) { InvalidCommand::~InvalidCommand() { - const int size = args_.size(); - for (int i = 0; i < size; ++i) { - delete args_[i]; + for (auto arg : args_) { + js_delete(arg); } } @@ -1487,7 +1490,7 @@ bool InvalidCommand::Run(Debugger* debugger) { USE(debugger); printf(" ** Invalid Command:"); - const int size = args_.size(); + const int size = args_.length(); for (int i = 0; i < size; ++i) { printf(" "); if (i == index_) { diff --git a/js/src/jit/arm64/vixl/Debugger-vixl.h b/js/src/jit/arm64/vixl/Debugger-vixl.h index 2866383df2e1..e140f1808cc5 100644 --- a/js/src/jit/arm64/vixl/Debugger-vixl.h +++ b/js/src/jit/arm64/vixl/Debugger-vixl.h @@ -30,7 +30,6 @@ #include #include #include -#include #include "jit/arm64/vixl/Constants-vixl.h" #include "jit/arm64/vixl/Globals-vixl.h" From 07a9c250f82a561db4552a9ba1322bf45753ac51 Mon Sep 17 00:00:00 2001 From: Henrik Skupin Date: Mon, 28 Sep 2015 23:17:25 +0200 Subject: [PATCH 010/104] Bug 1208431 - Allow query_minidump_stackwalk() to take a specific manifest file as parameter. r=jlund --- .../mozharness/mozilla/testing/testbase.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/testing/mozharness/mozharness/mozilla/testing/testbase.py b/testing/mozharness/mozharness/mozilla/testing/testbase.py index fc19622f0a2a..782300ae85df 100755 --- a/testing/mozharness/mozharness/mozilla/testing/testbase.py +++ b/testing/mozharness/mozharness/mozilla/testing/testbase.py @@ -642,7 +642,7 @@ Did you run with --create-virtualenv? Is mozinstall in virtualenv_modules?""") else: self.fatal('could not determine minidump filename') - def query_minidump_stackwalk(self): + def query_minidump_stackwalk(self, manifest=None): if self.minidump_stackwalk_path: return self.minidump_stackwalk_path c = self.config @@ -650,13 +650,17 @@ Did you run with --create-virtualenv? Is mozinstall in virtualenv_modules?""") if c.get('download_minidump_stackwalk'): minidump_stackwalk_path = self.query_minidump_filename() - tooltool_manifest_path = self.query_minidump_tooltool_manifest() + + if not manifest: + tooltool_manifest_path = self.query_minidump_tooltool_manifest() + manifest = os.path.join(dirs.get('abs_test_install_dir', + os.path.join(dirs['abs_work_dir'], 'tests')), + tooltool_manifest_path) + self.info('grabbing minidump binary from tooltool') try: self.tooltool_fetch( - manifest=os.path.join(dirs.get('abs_test_install_dir', - os.path.join(dirs['abs_work_dir'], 'tests')), - tooltool_manifest_path), + manifest=manifest, output_dir=dirs['abs_work_dir'], cache=c.get('tooltool_cache') ) From 92731da747045399e7812018dbf02d26a30c52a6 Mon Sep 17 00:00:00 2001 From: Jorg K Date: Mon, 28 Sep 2015 13:28:00 +0200 Subject: [PATCH 011/104] Bug 1205983 - Remove all observer code from nsEditor (tests). r=ehsan --HG-- extra : rebase_source : 71701166ea470c001fba64241545b03361df8a44 --- editor/composer/test/chrome.ini | 1 + editor/composer/test/test_bug1205983.html | 122 ++++++++++++++++++ editor/composer/test/test_bug697981.html | 5 + .../chrome/test_add_remove_dictionaries.xul | 12 +- 4 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 editor/composer/test/test_bug1205983.html diff --git a/editor/composer/test/chrome.ini b/editor/composer/test/chrome.ini index 6ae8cae9038e..cbf01740a71a 100644 --- a/editor/composer/test/chrome.ini +++ b/editor/composer/test/chrome.ini @@ -9,3 +9,4 @@ skip-if = buildapp == 'b2g' || os == 'android' [test_bug717433.html] [test_bug1204147.html] [test_bug1200533.html] +[test_bug1205983.html] diff --git a/editor/composer/test/test_bug1205983.html b/editor/composer/test/test_bug1205983.html new file mode 100644 index 000000000000..58f0f7a1857c --- /dev/null +++ b/editor/composer/test/test_bug1205983.html @@ -0,0 +1,122 @@ + + + + + Test for Bug 1205983 + + + + +Mozilla Bug 1205983 +

+ + +
German heute ist ein guter Tag
+ + +
+
+
+ + diff --git a/editor/composer/test/test_bug697981.html b/editor/composer/test/test_bug697981.html index ba9778e0a8ee..96cc5942498f 100644 --- a/editor/composer/test/test_bug697981.html +++ b/editor/composer/test/test_bug697981.html @@ -98,6 +98,11 @@ function enFocus() { // Remove the fake de_DE dictionary again. hunspell.removeDirectory(de_DE); + // Focus again, so the spelling gets updated, but before we need to kill the focus handler. + elem_de.onfocus = null; + elem_de.blur(); + elem_de.focus(); + // After removal, the de_DE editor should refresh the spelling with en-US. onSpellCheck(elem_de, function () { spellchecker = inlineSpellChecker.spellChecker; diff --git a/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul b/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul index 7fed54acf024..7375c744409f 100644 --- a/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul +++ b/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul @@ -82,17 +82,25 @@ function RunTest() { // select map dictionary setCurrentDictionary(editor, "maputf"); + // Focus again, so the spelling gets updated. + textbox.blur(); + textbox.focus(); + onSpellCheck(textbox, function () { // test that map dictionary is in use - is(getMisspelledWords(editor), "created" + "imply" + "tomorrow" + "qwertyu", "map misspellings"); + is(getMisspelledWords(editor), "created" + "imply" + "tomorrow" + "qwertyu", "map misspellings (1)"); is(getCurrentDictionary(editor), "maputf", "current dictionary"); // uninstall map dictionary hunspell.removeDirectory(map); + // Focus again, so the spelling gets updated. + textbox.blur(); + textbox.focus(); + onSpellCheck(textbox, function () { // test that map dictionary is not in use - isnot(getMisspelledWords(editor), "created" + "imply" + "tomorrow" + "qwertyu", "map misspellings"); + isnot(getMisspelledWords(editor), "created" + "imply" + "tomorrow" + "qwertyu", "map misspellings (2)"); isnot(getCurrentDictionary(editor), "maputf", "current dictionary"); // test that base dictionary is available and map dictionary is unavailable From 41a777b2d2608e7fe3130d9ad5078cdbe33fbdaf Mon Sep 17 00:00:00 2001 From: Jorg K Date: Mon, 28 Sep 2015 23:53:00 +0200 Subject: [PATCH 012/104] Bug 1205983 - Remove all observer code from nsEditor. r=ehsan --HG-- extra : rebase_source : 3a3375a44d16d1a4a93c670c5ed44adefe6dbb9e --- editor/composer/nsEditorSpellCheck.cpp | 7 -- editor/libeditor/nsEditor.cpp | 71 ------------------- editor/libeditor/nsEditor.h | 8 --- editor/libeditor/nsEditorEventListener.cpp | 4 -- editor/nsIEditorSpellCheck.idl | 8 +-- editor/txtsvc/nsISpellChecker.h | 6 -- .../spellcheck/hunspell/glue/mozHunspell.cpp | 21 +++--- .../idl/mozISpellCheckingEngine.idl | 2 - .../spellcheck/src/mozInlineSpellChecker.cpp | 6 +- extensions/spellcheck/src/mozSpellChecker.cpp | 25 ------- extensions/spellcheck/src/mozSpellChecker.h | 1 - 11 files changed, 11 insertions(+), 148 deletions(-) diff --git a/editor/composer/nsEditorSpellCheck.cpp b/editor/composer/nsEditorSpellCheck.cpp index c9292b9796bf..f20a66f9e538 100644 --- a/editor/composer/nsEditorSpellCheck.cpp +++ b/editor/composer/nsEditorSpellCheck.cpp @@ -636,13 +636,6 @@ nsEditorSpellCheck::SetCurrentDictionary(const nsAString& aDictionary) return mSpellChecker->SetCurrentDictionary(aDictionary); } -NS_IMETHODIMP -nsEditorSpellCheck::CheckCurrentDictionary() -{ - mSpellChecker->CheckCurrentDictionary(); - return NS_OK; -} - NS_IMETHODIMP nsEditorSpellCheck::UninitSpellChecker() { diff --git a/editor/libeditor/nsEditor.cpp b/editor/libeditor/nsEditor.cpp index bbf97f051416..d4557baf5453 100644 --- a/editor/libeditor/nsEditor.cpp +++ b/editor/libeditor/nsEditor.cpp @@ -24,7 +24,6 @@ #include "PlaceholderTxn.h" // for PlaceholderTxn #include "SplitNodeTxn.h" // for SplitNodeTxn #include "mozFlushType.h" // for mozFlushType::Flush_Frames -#include "mozISpellCheckingEngine.h" #include "mozInlineSpellChecker.h" // for mozInlineSpellChecker #include "mozilla/CheckedInt.h" // for CheckedInt #include "mozilla/IMEStateManager.h" // for IMEStateManager @@ -79,7 +78,6 @@ #include "nsIInlineSpellChecker.h" // for nsIInlineSpellChecker, etc #include "nsNameSpaceManager.h" // for kNameSpaceID_None, etc #include "nsINode.h" // for nsINode, etc -#include "nsIObserverService.h" // for nsIObserverService #include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc #include "nsIPresShell.h" // for nsIPresShell #include "nsISelectionController.h" // for nsISelectionController, etc @@ -148,7 +146,6 @@ nsEditor::nsEditor() , mDispatchInputEvent(true) , mIsInEditAction(false) , mHidingCaret(false) -, mObservingDictionaryUpdates(false) { } @@ -204,7 +201,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEditor) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsIEditorIMESupport) NS_INTERFACE_MAP_ENTRY(nsIEditor) - NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditor) NS_INTERFACE_MAP_END @@ -304,13 +300,6 @@ nsEditor::PostCreate() // update the UI with our state NotifyDocumentListeners(eDocumentCreated); NotifyDocumentListeners(eDocumentStateChanged); - - nsCOMPtr obs = mozilla::services::GetObserverService(); - if (obs) { - obs->AddObserver(this, - SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION, - false); - } } // update nsTextStateManager and caret if we have focus @@ -448,14 +437,6 @@ nsEditor::PreDestroy(bool aDestroyingFrames) IMEStateManager::OnEditorDestroying(this); - nsCOMPtr obs = mozilla::services::GetObserverService(); - if (obs) { - obs->RemoveObserver(this, - SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION); - obs->RemoveObserver(this, - SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION); - } - // Let spellchecker clean up its observers etc. It is important not to // actually free the spellchecker here, since the spellchecker could have // caused flush notifications, which could have gotten here if a textbox @@ -1314,35 +1295,6 @@ NS_IMETHODIMP nsEditor::GetInlineSpellChecker(bool autoCreate, return NS_OK; } -NS_IMETHODIMP nsEditor::Observe(nsISupports* aSubj, const char *aTopic, - const char16_t *aData) -{ - NS_ASSERTION(!strcmp(aTopic, - SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION) || - !strcmp(aTopic, - SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION), - "Unexpected observer topic"); - - // When mozInlineSpellChecker::CanEnableInlineSpellChecking changes - SyncRealTimeSpell(); - - // When nsIEditorSpellCheck::GetCurrentDictionary changes - if (mInlineSpellChecker) { - // Do the right thing in the spellchecker, if the dictionary is no longer - // available. This will not set a new dictionary. - nsCOMPtr editorSpellCheck; - mInlineSpellChecker->GetSpellChecker(getter_AddRefs(editorSpellCheck)); - if (editorSpellCheck) { - editorSpellCheck->CheckCurrentDictionary(); - } - - // update the inline spell checker to reflect the new current dictionary - mInlineSpellChecker->SpellCheckRange(nullptr); // causes recheck - } - - return NS_OK; -} - NS_IMETHODIMP nsEditor::SyncRealTimeSpell() { bool enable = GetDesiredSpellCheckState(); @@ -5206,29 +5158,6 @@ nsEditor::OnFocus(nsIDOMEventTarget* aFocusEventTarget) } } -void -nsEditor::StartWatchingDictionaryChanges() -{ - if (!mObservingDictionaryUpdates) { - nsCOMPtr obs = mozilla::services::GetObserverService(); - if (obs) { - obs->AddObserver(this, SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION, false); - } - mObservingDictionaryUpdates = true; - } -} - -void -nsEditor::StopWatchingDictionaryChanges() -{ - // Removing an observer that wasn't added doesn't cause any harm. - nsCOMPtr obs = mozilla::services::GetObserverService(); - if (obs) { - obs->RemoveObserver(this, SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION); - } - mObservingDictionaryUpdates = false; -} - NS_IMETHODIMP nsEditor::GetSuppressDispatchingInputEvent(bool *aSuppressed) { diff --git a/editor/libeditor/nsEditor.h b/editor/libeditor/nsEditor.h index 31d2416cd995..4873838fca30 100644 --- a/editor/libeditor/nsEditor.h +++ b/editor/libeditor/nsEditor.h @@ -140,7 +140,6 @@ inline bool operator!(const EditAction& aOp) class nsEditor : public nsIEditor, public nsIEditorIMESupport, public nsSupportsWeakReference, - public nsIObserver, public nsIPhonetic { public: @@ -188,9 +187,6 @@ public: /* ------------ nsIEditorIMESupport methods -------------- */ NS_DECL_NSIEDITORIMESUPPORT - /* ------------ nsIObserver methods -------------- */ - NS_DECL_NSIOBSERVER - // nsIPhonetic NS_DECL_NSIPHONETIC @@ -249,9 +245,6 @@ public: void SwitchTextDirectionTo(uint32_t aDirection); - void StartWatchingDictionaryChanges(); - void StopWatchingDictionaryChanges(); - protected: nsresult DetermineCurrentDirection(); void FireInputEvent(); @@ -894,7 +887,6 @@ protected: bool mDispatchInputEvent; bool mIsInEditAction; // true while the instance is handling an edit action bool mHidingCaret; // whether caret is hidden forcibly. - bool mObservingDictionaryUpdates; // whether the editor is observing dictionary changes. friend bool NSCanUnload(nsISupports* serviceMgr); friend class nsAutoTxnsConserveSelection; diff --git a/editor/libeditor/nsEditorEventListener.cpp b/editor/libeditor/nsEditorEventListener.cpp index 86e107404de7..e3010bff30d4 100644 --- a/editor/libeditor/nsEditorEventListener.cpp +++ b/editor/libeditor/nsEditorEventListener.cpp @@ -1114,8 +1114,6 @@ nsEditorEventListener::Focus(nsIDOMEvent* aEvent) } } - mEditor->StartWatchingDictionaryChanges(); - mEditor->OnFocus(target); nsCOMPtr ps = GetPresShell(); @@ -1132,8 +1130,6 @@ nsEditorEventListener::Blur(nsIDOMEvent* aEvent) { NS_ENSURE_TRUE(aEvent, NS_OK); - mEditor->StopWatchingDictionaryChanges(); - // check if something else is focused. If another element is focused, then // we should not change the selection. nsIFocusManager* fm = nsFocusManager::GetFocusManager(); diff --git a/editor/nsIEditorSpellCheck.idl b/editor/nsIEditorSpellCheck.idl index 5a8d1be95ea7..adf4a0a03444 100644 --- a/editor/nsIEditorSpellCheck.idl +++ b/editor/nsIEditorSpellCheck.idl @@ -9,16 +9,10 @@ interface nsIEditor; interface nsITextServicesFilter; interface nsIEditorSpellCheckCallback; -[scriptable, uuid(dd32ef3b-a7d8-43d1-9617-5f2dddbe29eb)] +[scriptable, uuid(a171c25f-e4a8-4d08-adef-b797e6377bdc)] interface nsIEditorSpellCheck : nsISupports { - /** - * Call this on any change in installed dictionaries to ensure that the spell - * checker is not using a current dictionary which is no longer available. - */ - void checkCurrentDictionary(); - /** * Returns true if we can enable spellchecking. If there are no available * dictionaries, this will return false. diff --git a/editor/txtsvc/nsISpellChecker.h b/editor/txtsvc/nsISpellChecker.h index c63f57091274..cafc725bec93 100644 --- a/editor/txtsvc/nsISpellChecker.h +++ b/editor/txtsvc/nsISpellChecker.h @@ -114,12 +114,6 @@ public: * empty string, spellchecker will be disabled. */ NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary) = 0; - - /** - * Call this on any change in installed dictionaries to ensure that the spell - * checker is not using a current dictionary which is no longer available. - */ - NS_IMETHOD CheckCurrentDictionary() = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsISpellChecker, NS_ISPELLCHECKER_IID) diff --git a/extensions/spellcheck/hunspell/glue/mozHunspell.cpp b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp index 3b66cac1324d..ddf3a58b3b7c 100644 --- a/extensions/spellcheck/hunspell/glue/mozHunspell.cpp +++ b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp @@ -160,12 +160,6 @@ NS_IMETHODIMP mozHunspell::SetDictionary(const char16_t *aDictionary) mDecoder = nullptr; mEncoder = nullptr; - nsCOMPtr obs = mozilla::services::GetObserverService(); - if (obs) { - obs->NotifyObservers(nullptr, - SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION, - nullptr); - } return NS_OK; } @@ -226,13 +220,6 @@ NS_IMETHODIMP mozHunspell::SetDictionary(const char16_t *aDictionary) else mLanguage = Substring(mDictionary, 0, pos); - nsCOMPtr obs = mozilla::services::GetObserverService(); - if (obs) { - obs->NotifyObservers(nullptr, - SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION, - nullptr); - } - return NS_OK; } @@ -604,11 +591,19 @@ NS_IMETHODIMP mozHunspell::RemoveDirectory(nsIFile *aDir) { mDynamicDirectories.RemoveObject(aDir); LoadDictionaryList(true); + +#ifdef MOZ_THUNDERBIRD + /* + * This notification is needed for Thunderbird. Thunderbird derives the dictionary + * from the document's "lang" attribute. If a dictionary is removed, + * we need to change the "lang" attribute. + */ nsCOMPtr obs = mozilla::services::GetObserverService(); if (obs) { obs->NotifyObservers(nullptr, SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION, nullptr); } +#endif return NS_OK; } diff --git a/extensions/spellcheck/idl/mozISpellCheckingEngine.idl b/extensions/spellcheck/idl/mozISpellCheckingEngine.idl index c124bb8bca85..c5f7db4210a5 100644 --- a/extensions/spellcheck/idl/mozISpellCheckingEngine.idl +++ b/extensions/spellcheck/idl/mozISpellCheckingEngine.idl @@ -102,8 +102,6 @@ interface mozISpellCheckingEngine : nsISupports { #define DICTIONARY_SEARCH_DIRECTORY "DictD" #define DICTIONARY_SEARCH_DIRECTORY_LIST "DictDL" -#define SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION \ - "spellcheck-dictionary-update" #define SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION \ "spellcheck-dictionary-remove" %} diff --git a/extensions/spellcheck/src/mozInlineSpellChecker.cpp b/extensions/spellcheck/src/mozInlineSpellChecker.cpp index 89c0546d326d..a9fcb3041050 100644 --- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp +++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp @@ -2021,10 +2021,8 @@ nsresult mozInlineSpellChecker::CurrentDictionaryUpdated() currentDictionary.Truncate(); } - if (!mPreviousDictionary.Equals(currentDictionary)) { - nsresult rv = SpellCheckRange(nullptr); - NS_ENSURE_SUCCESS(rv, rv); - } + nsresult rv = SpellCheckRange(nullptr); + NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } diff --git a/extensions/spellcheck/src/mozSpellChecker.cpp b/extensions/spellcheck/src/mozSpellChecker.cpp index adc34f2898ac..c695efb863ab 100644 --- a/extensions/spellcheck/src/mozSpellChecker.cpp +++ b/extensions/spellcheck/src/mozSpellChecker.cpp @@ -428,31 +428,6 @@ mozSpellChecker::SetCurrentDictionary(const nsAString &aDictionary) return NS_ERROR_NOT_AVAILABLE; } -NS_IMETHODIMP -mozSpellChecker::CheckCurrentDictionary() -{ - // If the current dictionary has been uninstalled, we need to stop using it. - // This happens when there is a current engine, but that engine has no - // current dictionary. - - if (!mSpellCheckingEngine) { - // We didn't have a current dictionary - return NS_OK; - } - - nsXPIDLString dictname; - mSpellCheckingEngine->GetDictionary(getter_Copies(dictname)); - - if (!dictname.IsEmpty()) { - // We still have a current dictionary - return NS_OK; - } - - // We had a current dictionary, but it has gone, so we cannot use it anymore. - mSpellCheckingEngine = nullptr; - return NS_OK; -} - nsresult mozSpellChecker::SetupDoc(int32_t *outBlockOffset) { diff --git a/extensions/spellcheck/src/mozSpellChecker.h b/extensions/spellcheck/src/mozSpellChecker.h index d60b5ac26d21..883dee38d76e 100644 --- a/extensions/spellcheck/src/mozSpellChecker.h +++ b/extensions/spellcheck/src/mozSpellChecker.h @@ -48,7 +48,6 @@ public: NS_IMETHOD GetDictionaryList(nsTArray *aDictionaryList) override; NS_IMETHOD GetCurrentDictionary(nsAString &aDictionary) override; NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary) override; - NS_IMETHOD CheckCurrentDictionary() override; void DeleteRemoteEngine() { mEngine = nullptr; From 2a1411fa20af61a93c08103a0d8ea2f345cb2928 Mon Sep 17 00:00:00 2001 From: "Nils Ohlmeier [:drno]" Date: Fri, 18 Sep 2015 23:25:38 -0700 Subject: [PATCH 013/104] Bug 1206465 - removed ice_ctx from TestStunTcpServer. r=bwc --HG-- extra : rebase_source : 88db248915f75421f881f293ed08963065a21b31 --- media/mtransport/test/stunserver.cpp | 163 +++++++++++++----- media/mtransport/test/stunserver.h | 36 ++-- .../nICEr/src/stun/nr_socket_buffered_stun.c | 30 +++- 3 files changed, 172 insertions(+), 57 deletions(-) diff --git a/media/mtransport/test/stunserver.cpp b/media/mtransport/test/stunserver.cpp index 1ed02905787f..67b150ed4f47 100644 --- a/media/mtransport/test/stunserver.cpp +++ b/media/mtransport/test/stunserver.cpp @@ -92,7 +92,7 @@ extern "C" { #include "local_addr.h" #include "stun_util.h" #include "registry.h" -#include "nr_socket_multi_tcp.h" +#include "nr_socket_buffered_stun.h" } #include "stunserver.h" @@ -131,11 +131,15 @@ static int nr_socket_wrapped_sendto(void *obj, const void *msg, size_t len, int static int nr_socket_wrapped_recvfrom(void *obj, void * restrict buf, size_t maxlen, size_t *len, int flags, nr_transport_addr *addr) { - MOZ_CRASH(); + nr_socket_wrapped *wrapped = static_cast(obj); + + return nr_socket_recvfrom(wrapped->sock_, buf, maxlen, len, flags, addr); } static int nr_socket_wrapped_getfd(void *obj, NR_SOCKET *fd) { - MOZ_CRASH(); + nr_socket_wrapped *wrapped = static_cast(obj); + + return nr_socket_getfd(wrapped->sock_, fd); } static int nr_socket_wrapped_getaddr(void *obj, nr_transport_addr *addrp) { @@ -186,10 +190,10 @@ int nr_socket_wrapped_create(nr_socket *inner, nr_socket **outp) { // Instance static. // Note: Calling Create() at static init time is not going to be safe, since // we have no reason to expect this will be initted to a nullptr yet. -TestStunServer* TestStunServer::instance; -TestStunTcpServer* TestStunTcpServer::instance; -TestStunServer* TestStunServer::instance6; -TestStunTcpServer* TestStunTcpServer::instance6; +TestStunServer *TestStunServer::instance; +TestStunTcpServer *TestStunTcpServer::instance; +TestStunServer *TestStunServer::instance6; +TestStunTcpServer *TestStunTcpServer::instance6; uint16_t TestStunServer::instance_port = 3478; uint16_t TestStunTcpServer::instance_port = 3478; @@ -216,7 +220,7 @@ TestStunServer::~TestStunServer() { delete response_addr_; } -int TestStunServer::SetInternalPort(nr_local_addr* addr, uint16_t port) { +int TestStunServer::SetInternalPort(nr_local_addr *addr, uint16_t port) { if (nr_transport_addr_set_port(&addr->addr, port)) { MOZ_MTLOG(ML_ERROR, "Couldn't set port"); return R_INTERNAL; @@ -230,7 +234,7 @@ int TestStunServer::SetInternalPort(nr_local_addr* addr, uint16_t port) { return 0; } -int TestStunServer::TryOpenListenSocket(nr_local_addr* addr, uint16_t port) { +int TestStunServer::TryOpenListenSocket(nr_local_addr *addr, uint16_t port) { int r = SetInternalPort(addr, port); @@ -372,21 +376,30 @@ void TestStunServer::ShutdownInstance() { struct DeferredStunOperation { DeferredStunOperation(TestStunServer *server, const char *data, size_t len, - nr_transport_addr *addr) : + nr_transport_addr *addr, + nr_socket *sock) : server_(server), - buffer_(reinterpret_cast(data), len) { + buffer_(reinterpret_cast(data), len), + sock_(sock) { nr_transport_addr_copy(&addr_, addr); } TestStunServer *server_; DataBuffer buffer_; nr_transport_addr addr_; + nr_socket *sock_; }; -void TestStunServer::Process(const uint8_t *msg, size_t len, nr_transport_addr *addr) { +void TestStunServer::Process(const uint8_t *msg, size_t len, nr_transport_addr *addr, nr_socket *sock) { + + if (!sock) { + sock = send_sock_; + } + // Set the wrapped address so that the response goes to the right place. - nr_socket_wrapped_set_send_addr(send_sock_, addr); - nr_stun_server_process_request(stun_server_, send_sock_, + nr_socket_wrapped_set_send_addr(sock, addr); + + nr_stun_server_process_request(stun_server_, sock, const_cast(reinterpret_cast(msg)), len, response_addr_ ? @@ -397,32 +410,43 @@ void TestStunServer::Process(const uint8_t *msg, size_t len, nr_transport_addr * void TestStunServer::process_cb(NR_SOCKET s, int how, void *cb_arg) { DeferredStunOperation *op = static_cast(cb_arg); op->server_->timer_handle_ = nullptr; - op->server_->Process(op->buffer_.data(), op->buffer_.len(), &op->addr_); + op->server_->Process(op->buffer_.data(), op->buffer_.len(), &op->addr_, op->sock_); delete op; } -void TestStunServer::readable_cb(NR_SOCKET s, int how, void *cb_arg) { - TestStunServer* server = static_cast(cb_arg); +nr_socket* TestStunServer::GetReceivingSocket(NR_SOCKET s) { + return listen_sock_; +} - char message[4096]; +nr_socket* TestStunServer::GetSendingSocket(nr_socket *sock) { + return send_sock_; +} + +void TestStunServer::readable_cb(NR_SOCKET s, int how, void *cb_arg) { + TestStunServer *server = static_cast(cb_arg); + + char message[max_stun_message_size]; size_t message_len; nr_transport_addr addr; + nr_socket *recv_sock = server->GetReceivingSocket(s); + if (!recv_sock) { + MOZ_MTLOG(ML_ERROR, "Failed to lookup receiving socket"); + return; + } + nr_socket *send_sock = server->GetSendingSocket(recv_sock); - int r = nr_socket_recvfrom(server->listen_sock_, message, sizeof(message), - &message_len, 0, &addr); + /* Re-arm. */ + NR_ASYNC_WAIT(s, NR_ASYNC_WAIT_READ, &TestStunServer::readable_cb, server); - if (r) { + if (nr_socket_recvfrom(recv_sock, message, sizeof(message), + &message_len, 0, &addr)) { MOZ_MTLOG(ML_ERROR, "Couldn't read STUN message"); return; } MOZ_MTLOG(ML_DEBUG, "Received data of length " << message_len); - // Re-arm. - NR_ASYNC_WAIT(s, NR_ASYNC_WAIT_READ, &TestStunServer::readable_cb, server); - - // If we have initial dropping set, check at this point. std::string key(addr.as_string); @@ -444,10 +468,11 @@ void TestStunServer::readable_cb(NR_SOCKET s, int how, void *cb_arg) { new DeferredStunOperation( server, message, message_len, - &addr), + &addr, send_sock), &server->timer_handle_); } else { - server->Process(reinterpret_cast(message), message_len, &addr); + server->Process(reinterpret_cast(message), message_len, + &addr, send_sock); } } @@ -525,11 +550,12 @@ TestStunTcpServer* TestStunTcpServer::GetInstance(int address_family) { void TestStunTcpServer::ShutdownInstance() { delete instance; - instance = nullptr; + delete instance6; + instance6 = nullptr; } -int TestStunTcpServer::TryOpenListenSocket(nr_local_addr* addr, uint16_t port) { +int TestStunTcpServer::TryOpenListenSocket(nr_local_addr *addr, uint16_t port) { addr->addr.protocol=IPPROTO_TCP; @@ -538,17 +564,15 @@ int TestStunTcpServer::TryOpenListenSocket(nr_local_addr* addr, uint16_t port) { if (r) return r; - if (ice_ctx_ == NULL) - ice_ctx_ = NrIceCtx::Create("stun", false, false, false, false, false); + nr_socket *sock; + if (nr_socket_local_create(nullptr, &addr->addr, &sock)) { + MOZ_MTLOG(ML_ERROR, "Couldn't create listen tcp socket"); + return R_ALREADY; + } - //TODO (nils@mozilla.com) can we replace this with a more basic TCP socket - // alternative which would allow us to remove the framing argument from the - // nr_socket_multi_tcp_create() call? - if(nr_socket_multi_tcp_create(ice_ctx_->ctx(), - &addr->addr, TCP_TYPE_PASSIVE, 0, 0, 2048, - &listen_sock_)) { - MOZ_MTLOG(ML_ERROR, "Couldn't create listen socket"); - return R_ALREADY; + if (nr_socket_buffered_stun_create(sock, 2048, TURN_TCP_FRAMING, &listen_sock_)) { + MOZ_MTLOG(ML_ERROR, "Couldn't create listen tcp socket"); + return R_ALREADY; } if(nr_socket_listen(listen_sock_, 10)) { @@ -559,6 +583,51 @@ int TestStunTcpServer::TryOpenListenSocket(nr_local_addr* addr, uint16_t port) { return 0; } +nr_socket* TestStunTcpServer::GetReceivingSocket(NR_SOCKET s) { + return connections_[s]; +} + +nr_socket* TestStunTcpServer::GetSendingSocket(nr_socket *sock) { + return sock; +} + +void TestStunTcpServer::accept_cb(NR_SOCKET s, int how, void *cb_arg) { + TestStunTcpServer *server = static_cast(cb_arg); + nr_socket *newsock, *bufsock, *wrapsock; + nr_transport_addr remote_addr; + NR_SOCKET fd; + + /* rearm */ + NR_ASYNC_WAIT(s, NR_ASYNC_WAIT_READ, &TestStunTcpServer::accept_cb, cb_arg); + + /* accept */ + if (nr_socket_accept(server->listen_sock_, &remote_addr, &newsock)) { + MOZ_MTLOG(ML_ERROR, "Couldn't accept incoming tcp connection"); + return; + } + + if(nr_socket_buffered_stun_create(newsock, 2048, TURN_TCP_FRAMING, &bufsock)) { + MOZ_MTLOG(ML_ERROR, "Couldn't create connected tcp socket"); + return; + } + + nr_socket_buffered_set_connected_to(bufsock, &remote_addr); + + if(nr_socket_wrapped_create(bufsock, &wrapsock)) { + MOZ_MTLOG(ML_ERROR, "Couldn't wrap connected tcp socket"); + return; + } + + if(nr_socket_getfd(bufsock, &fd)) { + MOZ_MTLOG(ML_ERROR, "Couldn't get fd from connected tcp socket"); + return; + } + + server->connections_[fd] = wrapsock; + + NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, &TestStunServer::readable_cb, server); +} + TestStunTcpServer* TestStunTcpServer::Create(int address_family) { NR_reg_init(NR_REG_MODE_LOCAL); @@ -568,15 +637,23 @@ TestStunTcpServer* TestStunTcpServer::Create(int address_family) { return nullptr; } - nr_socket_multi_tcp_set_readable_cb(server->listen_sock_, - &TestStunServer::readable_cb, server.get()); + NR_SOCKET fd; + if(nr_socket_getfd(server->listen_sock_, &fd)) { + MOZ_MTLOG(ML_ERROR, "Couldn't get tcp fd"); + return nullptr; + } + + NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, &TestStunTcpServer::accept_cb, server.get()); return server.forget(); } TestStunTcpServer::~TestStunTcpServer() { - ice_ctx_ = nullptr; - nr_socket_destroy(&listen_sock_); + for (auto it = connections_.begin(); it != connections_.end();) { + NR_ASYNC_CANCEL(it->first, NR_ASYNC_WAIT_READ); + nr_socket_destroy(&it->second); + connections_.erase(it++); + } } } // close namespace diff --git a/media/mtransport/test/stunserver.h b/media/mtransport/test/stunserver.h index ad8cfb8b82fc..c1a8c9e93541 100644 --- a/media/mtransport/test/stunserver.h +++ b/media/mtransport/test/stunserver.h @@ -18,6 +18,7 @@ typedef struct nr_stun_server_ctx_ nr_stun_server_ctx; typedef struct nr_socket_ nr_socket; typedef struct nr_local_addr_ nr_local_addr; + namespace mozilla { class TestStunServer { @@ -47,6 +48,11 @@ class TestStunServer { void Reset(); + static const size_t max_stun_message_size = 4096; + + virtual nr_socket* GetReceivingSocket(NR_SOCKET s); + virtual nr_socket* GetSendingSocket(nr_socket *sock); + protected: TestStunServer() : listen_port_(0), @@ -59,13 +65,14 @@ class TestStunServer { response_addr_(nullptr), timer_handle_(nullptr) {} - int SetInternalPort(nr_local_addr* addr, uint16_t port); + int SetInternalPort(nr_local_addr *addr, uint16_t port); int Initialize(int address_family); + static void readable_cb(NR_SOCKET sock, int how, void *cb_arg); private: - void Process(const uint8_t *msg, size_t len, nr_transport_addr *addr_in); - virtual int TryOpenListenSocket(nr_local_addr* addr, uint16_t port); + void Process(const uint8_t *msg, size_t len, nr_transport_addr *addr_in, nr_socket *sock); + virtual int TryOpenListenSocket(nr_local_addr *addr, uint16_t port); static void process_cb(NR_SOCKET sock, int how, void *cb_arg); protected: @@ -82,8 +89,8 @@ class TestStunServer { void *timer_handle_; std::map received_ct_; - static TestStunServer* instance; - static TestStunServer* instance6; + static TestStunServer *instance; + static TestStunServer *instance6; static uint16_t instance_port; }; @@ -93,18 +100,23 @@ class TestStunTcpServer: public TestStunServer { static void ShutdownInstance(); static void ConfigurePort(uint16_t port); virtual ~TestStunTcpServer(); - protected: - TestStunTcpServer() - : ice_ctx_(nullptr) {} - nsRefPtr ice_ctx_; + virtual nr_socket* GetReceivingSocket(NR_SOCKET s); + virtual nr_socket* GetSendingSocket(nr_socket *sock); + + protected: + TestStunTcpServer() {} + static void accept_cb(NR_SOCKET sock, int how, void *cb_arg); + private: - virtual int TryOpenListenSocket(nr_local_addr* addr, uint16_t port); + virtual int TryOpenListenSocket(nr_local_addr *addr, uint16_t port); static TestStunTcpServer *Create(int address_family); - static TestStunTcpServer* instance; - static TestStunTcpServer* instance6; + static TestStunTcpServer *instance; + static TestStunTcpServer *instance6; static uint16_t instance_port; + + std::map connections_; }; } // End of namespace mozilla #endif diff --git a/media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c b/media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c index c4c042162515..b2a5631c402f 100644 --- a/media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c +++ b/media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c @@ -86,6 +86,8 @@ static int nr_socket_buffered_stun_close(void *obj); static int nr_socket_buffered_stun_connect(void *sock, nr_transport_addr *addr); static int nr_socket_buffered_stun_write(void *obj,const void *msg, size_t len, size_t *written); static void nr_socket_buffered_stun_writable_cb(NR_SOCKET s, int how, void *arg); +static int nr_socket_buffered_stun_listen(void *obj, int backlog); +static int nr_socket_buffered_stun_accept(void *obj, nr_transport_addr *addrp, nr_socket **sockp); static nr_socket_vtbl nr_socket_buffered_stun_vtbl={ 2, @@ -98,8 +100,8 @@ static nr_socket_vtbl nr_socket_buffered_stun_vtbl={ 0, 0, nr_socket_buffered_stun_close, - 0, - 0 + nr_socket_buffered_stun_listen, + nr_socket_buffered_stun_accept }; int nr_socket_buffered_set_connected_to(nr_socket *sock, nr_transport_addr *remote_addr) @@ -368,6 +370,30 @@ static int nr_socket_buffered_stun_close(void *obj) return nr_socket_close(sock->inner); } +static int nr_socket_buffered_stun_listen(void *obj, int backlog) +{ + int r, _status; + nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)obj; + + if (!sock->inner) + ABORT(R_FAILED); + + if ((r=nr_socket_listen(sock->inner, backlog))) + ABORT(r); + + _status=0; +abort: + return(_status); +} + + +static int nr_socket_buffered_stun_accept(void *obj, nr_transport_addr *addrp, nr_socket **sockp) +{ + nr_socket_buffered_stun *bsock = (nr_socket_buffered_stun *)obj; + + return nr_socket_accept(bsock->inner, addrp, sockp); +} + static void nr_socket_buffered_stun_connected_cb(NR_SOCKET s, int how, void *arg) { nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)arg; From 1983959f975f2308748c68ed28781a87880788be Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Tue, 29 Sep 2015 17:08:42 +0900 Subject: [PATCH 014/104] Bug 1208969 TSFTextStore shouldn't grant document lock after starting to destroy the context r=emk --- widget/windows/TSFTextStore.cpp | 13 +++++++++++-- widget/windows/TSFTextStore.h | 3 +++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/widget/windows/TSFTextStore.cpp b/widget/windows/TSFTextStore.cpp index 67ce45c84c33..3d0584adc8fd 100644 --- a/widget/windows/TSFTextStore.cpp +++ b/widget/windows/TSFTextStore.cpp @@ -1320,6 +1320,7 @@ TSFTextStore::TSFTextStore() , mDeferClearingLockedContent(false) , mNativeCaretIsCreated(false) , mDeferNotifyingTSF(false) + , mDestroyed(false) { for (int32_t i = 0; i < NUM_OF_SUPPORTED_ATTRS; i++) { mRequestedAttrs[i] = false; @@ -1404,6 +1405,8 @@ TSFTextStore::Destroy() this, GetLockFlagNameStr(mLock).get(), GetBoolName(mComposition.IsComposing()))); + mDestroyed = true; + if (mLock) { mPendingDestroy = true; return true; @@ -1565,8 +1568,8 @@ TSFTextStore::RequestLock(DWORD dwLockFlags, { MOZ_LOG(sTextStoreLog, LogLevel::Info, ("TSF: 0x%p TSFTextStore::RequestLock(dwLockFlags=%s, phrSession=0x%p), " - "mLock=%s", this, GetLockFlagNameStr(dwLockFlags).get(), phrSession, - GetLockFlagNameStr(mLock).get())); + "mLock=%s, mDestroyed=%s", this, GetLockFlagNameStr(dwLockFlags).get(), + phrSession, GetLockFlagNameStr(mLock).get(), GetBoolName(mDestroyed))); if (!mSink) { MOZ_LOG(sTextStoreLog, LogLevel::Error, @@ -1574,6 +1577,12 @@ TSFTextStore::RequestLock(DWORD dwLockFlags, "any sink not stored", this)); return E_FAIL; } + if (mDestroyed) { + MOZ_LOG(sTextStoreLog, LogLevel::Error, + ("TSF: 0x%p TSFTextStore::RequestLock() FAILED due to " + "being destroyed", this)); + return E_FAIL; + } if (!phrSession) { MOZ_LOG(sTextStoreLog, LogLevel::Error, ("TSF: 0x%p TSFTextStore::RequestLock() FAILED due to " diff --git a/widget/windows/TSFTextStore.h b/widget/windows/TSFTextStore.h index fe13289df61e..bdfc3ba8987e 100644 --- a/widget/windows/TSFTextStore.h +++ b/widget/windows/TSFTextStore.h @@ -805,6 +805,9 @@ protected: // For preventing it to be called, we should put off notifying TSF of // anything until layout information becomes available. bool mDeferNotifyingTSF; + // Immediately after a call of Destroy(), mDestroyed becomes true. If this + // is true, the instance shouldn't grant any requests from the TIP anymore. + bool mDestroyed; // TSF thread manager object for the current application From f2287a4015c02164a10ed57ee2628f02a2fa76c7 Mon Sep 17 00:00:00 2001 From: Henrik Skupin Date: Thu, 24 Sep 2015 21:42:02 +0200 Subject: [PATCH 015/104] Bug 1201588 - Refactor crash symbols handling for firefox-ui-tests scripts. r=armenzg DONTBUILD --- .../configs/firefox_ui_tests/jenkins.py | 6 -- .../configs/firefox_ui_tests/qa_jenkins.py | 25 +++++ .../firefox_ui_tests/releng_release.py | 25 +++++ .../mozilla/testing/firefox_ui_tests.py | 101 +++++++++--------- .../firefox_ui_tests/update_release.py | 33 +----- 5 files changed, 101 insertions(+), 89 deletions(-) delete mode 100644 testing/mozharness/configs/firefox_ui_tests/jenkins.py create mode 100644 testing/mozharness/configs/firefox_ui_tests/qa_jenkins.py create mode 100644 testing/mozharness/configs/firefox_ui_tests/releng_release.py diff --git a/testing/mozharness/configs/firefox_ui_tests/jenkins.py b/testing/mozharness/configs/firefox_ui_tests/jenkins.py deleted file mode 100644 index c3811688c5c9..000000000000 --- a/testing/mozharness/configs/firefox_ui_tests/jenkins.py +++ /dev/null @@ -1,6 +0,0 @@ -config = { - 'virtualenv_modules': [ - # optional packages we need for Jenkins - 'mozdownload==1.17', - ] -} diff --git a/testing/mozharness/configs/firefox_ui_tests/qa_jenkins.py b/testing/mozharness/configs/firefox_ui_tests/qa_jenkins.py new file mode 100644 index 000000000000..cd10677c0148 --- /dev/null +++ b/testing/mozharness/configs/firefox_ui_tests/qa_jenkins.py @@ -0,0 +1,25 @@ +# Default configuration as used by Mozmill CI (Jenkins) + +import os + + +config = { + 'env': { + 'PIP_TRUSTED_HOST': 'pypi.pub.build.mozilla.org', + }, + + # General local variable overwrite + 'exes': { + 'gittool.py': os.path.join(os.getcwd(), 'external_tools', 'gittool.py'), + 'hgtool.py': os.path.join(os.getcwd(), 'external_tools', 'hgtool.py'), + }, + + # PIP + 'find_links': ['http://pypi.pub.build.mozilla.org/pub'], + 'pip_index': False, + + # mozcrash support + 'download_minidump_stackwalk': True, + 'download_symbols': 'ondemand', + 'download_tooltool': True, +} diff --git a/testing/mozharness/configs/firefox_ui_tests/releng_release.py b/testing/mozharness/configs/firefox_ui_tests/releng_release.py new file mode 100644 index 000000000000..77e1e2ecee93 --- /dev/null +++ b/testing/mozharness/configs/firefox_ui_tests/releng_release.py @@ -0,0 +1,25 @@ +# Default configuration as used by Release Engineering for testing release/beta builds + +import os + + +config = { + 'env': { + 'PIP_TRUSTED_HOST': 'pypi.pub.build.mozilla.org', + }, + + # General local variable overwrite + 'exes': { + 'gittool.py': os.path.join(os.getcwd(), 'external_tools', 'gittool.py'), + 'hgtool.py': os.path.join(os.getcwd(), 'external_tools', 'hgtool.py'), + }, + + # PIP + 'find_links': ['http://pypi.pub.build.mozilla.org/pub'], + 'pip_index': False, + + # mozcrash support + 'download_minidump_stackwalk': True, + 'download_symbols': 'ondemand', + 'download_tooltool': True, +} diff --git a/testing/mozharness/mozharness/mozilla/testing/firefox_ui_tests.py b/testing/mozharness/mozharness/mozilla/testing/firefox_ui_tests.py index c43baffeeeb2..a5ce7c966c1b 100644 --- a/testing/mozharness/mozharness/mozilla/testing/firefox_ui_tests.py +++ b/testing/mozharness/mozharness/mozilla/testing/firefox_ui_tests.py @@ -12,14 +12,15 @@ Author: Armen Zambrano G. import copy import os import sys -import urllib2 +import urlparse from mozharness.base.python import ( PreScriptAction, - VirtualenvMixin, - virtualenv_config_options, ) -from mozharness.mozilla.testing.testbase import (INSTALLER_SUFFIXES) +from mozharness.mozilla.testing.testbase import ( + TestingMixin, + testing_config_options, +) from mozharness.mozilla.vcstools import VCSToolsScript @@ -44,15 +45,7 @@ firefox_ui_tests_config_options = [ 'help': 'absolute path to directory containing breakpad ' 'symbols, or the url of a zip file containing symbols.', }], - [['--installer-url'], { - 'dest': 'installer_url', - 'help': 'Point to an installer to download and test against.', - }], - [['--installer-path'], { - 'dest': 'installer_path', - 'help': 'Point to an installer to test against.', - }], -] + copy.deepcopy(virtualenv_config_options) +] + copy.deepcopy(testing_config_options) # Command line arguments for update tests firefox_ui_update_harness_config_options = [ @@ -94,7 +87,7 @@ firefox_ui_update_config_options = firefox_ui_update_harness_config_options \ + copy.deepcopy(firefox_ui_tests_config_options) -class FirefoxUITests(VCSToolsScript, VirtualenvMixin): +class FirefoxUITests(TestingMixin, VCSToolsScript): cli_script = 'firefox-ui-tests' @@ -106,15 +99,15 @@ class FirefoxUITests(VCSToolsScript, VirtualenvMixin): 'clobber', 'checkout', 'create-virtualenv', + 'query_minidump_stackwalk', 'run-tests', ] - VCSToolsScript.__init__(self, - config_options=config_options, - all_actions=all_actions or actions, - default_actions=default_actions or actions, - *args, **kwargs) - VirtualenvMixin.__init__(self) + super(FirefoxUITests, self).__init__( + config_options=config_options, + all_actions=all_actions or actions, + default_actions=default_actions or actions, + *args, **kwargs) self.firefox_ui_repo = self.config['firefox_ui_repo'] self.firefox_ui_branch = self.config.get('firefox_ui_branch') @@ -124,16 +117,13 @@ class FirefoxUITests(VCSToolsScript, VirtualenvMixin): 'Please specify --firefox-ui-branch. Valid values can be found ' 'in here https://github.com/mozilla/firefox-ui-tests/branches') + # As long as we don't run on buildbot the installers are not handled by TestingMixin self.installer_url = self.config.get('installer_url') self.installer_path = self.config.get('installer_path') if self.installer_path: self.installer_path = os.path.abspath(self.installer_path) - if not os.path.exists(self.installer_path): - self.critical('Please make sure that the path to the installer exists.') - sys.exit(1) - @PreScriptAction('create-virtualenv') def _pre_create_virtualenv(self, action): dirs = self.query_abs_dirs() @@ -150,28 +140,6 @@ class FirefoxUITests(VCSToolsScript, VirtualenvMixin): self.register_virtualenv_module('firefox-ui-tests', url=dirs['fx_ui_dir']) - def _query_symbols_url(self, installer_url): - for suffix in INSTALLER_SUFFIXES: - if installer_url.endswith(suffix): - symbols_url = installer_url[:-len(suffix)] + '.crashreporter-symbols.zip' - continue - - if symbols_url: - self.info('Symbols_url: {}'.format(symbols_url)) - if not symbols_url.startswith('http'): - return symbols_url - - try: - # Let's see if the symbols are available - urllib2.urlopen(symbols_url) - return symbols_url - - except urllib2.HTTPError, e: - self.warning('{} - {}'.format(str(e), symbols_url)) - return None - else: - self.fatal('Can\'t find symbols_url from installer_url: {}!'.format(installer_url)) - @PreScriptAction('checkout') def _pre_checkout(self, action): if not self.firefox_ui_branch: @@ -212,7 +180,32 @@ class FirefoxUITests(VCSToolsScript, VirtualenvMixin): """ return [] - def run_test(self, installer_path, script_name, env=None, symbols_url=None, + def query_minidump_stackwalk(self): + """We don't have an extracted test package available to get the manifest file. + + So we have to explicitely download the latest version of the manifest from the + mozilla-central repository and feed it into the query_minidump_stackwalk() method. + + We can remove this whole method once our tests are part of the tree. + + """ + manifest_path = None + + if self.config.get('download_minidump_stackwalk'): + tooltool_manifest = self.query_minidump_tooltool_manifest() + url_base = 'https://hg.mozilla.org/mozilla-central/raw-file/default/testing/' + + dirs = self.query_abs_dirs() + manifest_path = os.path.join(dirs['abs_work_dir'], 'releng.manifest') + try: + self.download_file(urlparse.urljoin(url_base, tooltool_manifest), + manifest_path) + except Exception as e: + self.fatal('Download of tooltool manifest file failed: %s' % e.message) + + super(FirefoxUITests, self).query_minidump_stackwalk(manifest=manifest_path) + + def run_test(self, installer_path, script_name, env=None, cleanup=True, marionette_port=2828): """All required steps for running the tests against an installer.""" dirs = self.query_abs_dirs() @@ -233,12 +226,17 @@ class FirefoxUITests(VCSToolsScript, VirtualenvMixin): '--workspace', dirs['abs_work_dir'], ] - if symbols_url: - cmd += ['--symbols-path', symbols_url] - # Collect all pass-through harness options to the script cmd.extend(self.query_extra_cmd_args()) + # Set further environment settings + env = env or self.query_env() + if self.minidump_stackwalk_path: + env['MINIDUMP_STACKWALK'] = self.minidump_stackwalk_path + + if self.query_symbols_url(): + cmd += ['--symbols-path', self.symbols_url] + return_code = self.run_command(cmd, cwd=dirs['abs_work_dir'], output_timeout=300, env=env) @@ -279,13 +277,10 @@ class FirefoxUITests(VCSToolsScript, VirtualenvMixin): parent_dir=dirs['abs_work_dir'] ) - symbols_url = self._query_symbols_url(installer_url=self.installer_path) - return self.run_test( installer_path=self.installer_path, script_name=self.cli_script, env=self.query_env(), - symbols_url=symbols_url, cleanup=False, ) diff --git a/testing/mozharness/scripts/firefox_ui_tests/update_release.py b/testing/mozharness/scripts/firefox_ui_tests/update_release.py index 7d8ba1f1b923..92aa6ab40dea 100755 --- a/testing/mozharness/scripts/firefox_ui_tests/update_release.py +++ b/testing/mozharness/scripts/firefox_ui_tests/update_release.py @@ -12,7 +12,6 @@ Author: Armen Zambrano G. import copy import os import pprint -import re import sys import urllib @@ -72,6 +71,7 @@ class ReleaseFirefoxUIUpdateTests(FirefoxUIUpdateTests): 'clobber', 'checkout', 'create-virtualenv', + 'query_minidump_stackwalk', 'read-release-update-config', 'run-tests', ] @@ -93,26 +93,6 @@ class ReleaseFirefoxUIUpdateTests(FirefoxUIUpdateTests): # from tools/release/updates/*cfg self.releases = None - def _modify_url(self, rel_info): - # This is a temporary hack to find crash symbols. It should be replaced - # with something that doesn't make wild guesses about where symbol - # packages are. - # We want this: - # https://ftp.mozilla.org/pub/mozilla.org/firefox/candidates/40.0b1-candidates/build1/mac/en-US/Firefox%2040.0b1.crashreporter-symbols.zip - # https://ftp.mozilla.org/pub/mozilla.org//firefox/releases/40.0b1/mac/en-US/Firefox%2040.0b1.crashreporter-symbols.zip - installer_from = rel_info['from'] - version = (re.search('/firefox/releases/(%s.*)\/.*\/.*\/.*' % rel_info['release'], - installer_from)).group(1) - - temp_from = installer_from.replace(version, '%s-candidates/build%s' % ( - version, self.config['build_number']), - 1).replace('releases', 'candidates') - temp_url = rel_info['ftp_server_from'] + urllib.quote(temp_from.replace('%locale%', - 'en-US')) - self.info('Installer url under stage/candidates dir: {}'.format(temp_url)) - - return temp_url - def checkout(self): """ We checkout the tools repository and update to the right branch @@ -253,12 +233,6 @@ class ReleaseFirefoxUIUpdateTests(FirefoxUIUpdateTests): if self.config['dry_run']: continue - # Safe temporary hack to determine symbols URL from en-US - # build1 in the candidates dir - ftp_candidates_installer_url = self._modify_url(rel_info) - symbols_url = self._query_symbols_url( - installer_url=ftp_candidates_installer_url) - # Determine from where to download the file installer_url = '{server}/{fragment}'.format( server=rel_info['ftp_server_from'], @@ -275,7 +249,6 @@ class ReleaseFirefoxUIUpdateTests(FirefoxUIUpdateTests): installer_path=installer_path, script_name=self.cli_script, env=self.query_env(avoid_host_env=True), - symbols_url=symbols_url, marionette_port=marionette_port, ) @@ -293,8 +266,8 @@ class ReleaseFirefoxUIUpdateTests(FirefoxUIUpdateTests): for config in self.config['config_files']: base_cmd += ' --cfg {}'.format(config) - if symbols_url: - base_cmd += ' --symbols-path {}'.format(symbols_url) + if self.symbols_url: + base_cmd += ' --symbols-path {}'.format(self.symbols_url) base_cmd += ' --installer-url {}'.format(installer_url) From 8276df15d8897aa08254e4d39a8cc50952a7bb2e Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 29 Sep 2015 10:13:43 +0100 Subject: [PATCH 016/104] Bug 1208055 - Fix test which can be confused by compacting GC discarding JIT code r=terrence --- js/src/jit-test/tests/debug/Frame-newTargetOverflow-01.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/src/jit-test/tests/debug/Frame-newTargetOverflow-01.js b/js/src/jit-test/tests/debug/Frame-newTargetOverflow-01.js index 2a413404c177..1dd0b1bd4ac0 100644 --- a/js/src/jit-test/tests/debug/Frame-newTargetOverflow-01.js +++ b/js/src/jit-test/tests/debug/Frame-newTargetOverflow-01.js @@ -7,6 +7,10 @@ load(libdir + "jitopts.js"); if (!jitTogglesMatch(Opts_Ion2NoOffthreadCompilation)) quit(); +// GCs can invalidate JIT code and cause this test to fail. +if ('gczeal' in this) + gczeal(0); + withJitOptions(Opts_Ion2NoOffthreadCompilation, function () { var g = newGlobal(); var dbg = new Debugger; From e84d998fadfaf85554a0afdf251544c07dccfdbb Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 29 Sep 2015 10:14:56 +0100 Subject: [PATCH 017/104] Bug 1209001 - Fix OOM handling when creating ModuleObject r=terrence --- js/src/builtin/ModuleObject.cpp | 6 +++++- js/src/jit-test/tests/gc/bug-1209001.js | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 js/src/jit-test/tests/gc/bug-1209001.js diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index 8ea790fee513..ceb702ce1bcc 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -265,6 +265,8 @@ ModuleObject::isInstance(HandleValue value) ModuleObject::create(ExclusiveContext* cx) { Rooted self(cx, NewBuiltinClassInstance(cx, TenuredObject)); + if (!self) + return nullptr; IndirectBindingMap* bindings = cx->new_(); if (!bindings || !bindings->init()) { @@ -280,7 +282,9 @@ ModuleObject::create(ExclusiveContext* cx) /* static */ void ModuleObject::finalize(js::FreeOp* fop, JSObject* obj) { - fop->delete_(&obj->as().importBindings()); + ModuleObject* self = &obj->as(); + if (!self->getReservedSlot(ImportBindingsSlot).isUndefined()) + fop->delete_(&self->importBindings()); } ModuleEnvironmentObject* diff --git a/js/src/jit-test/tests/gc/bug-1209001.js b/js/src/jit-test/tests/gc/bug-1209001.js new file mode 100644 index 000000000000..5ea291c01768 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-1209001.js @@ -0,0 +1,4 @@ +// |jit-test| --no-threads + +load(libdir + 'oomTest.js'); +oomTest(() => parseModule('import v from "mod";')); From ea9c1220e9afadcf30f25a15c4af7d19b2455a92 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 29 Sep 2015 10:15:42 +0100 Subject: [PATCH 018/104] Bug 1208994 - ToAtom should not throw an exception on failure r=terrence --- js/src/jit-test/tests/gc/bug-1208994.js | 4 ++++ js/src/jsatom.cpp | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 js/src/jit-test/tests/gc/bug-1208994.js diff --git a/js/src/jit-test/tests/gc/bug-1208994.js b/js/src/jit-test/tests/gc/bug-1208994.js new file mode 100644 index 000000000000..151ec909aee8 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-1208994.js @@ -0,0 +1,4 @@ +// |jit-test| --no-threads + +load(libdir + 'oomTest.js'); +oomTest(() => getBacktrace({args: oomTest[load+1], locals: true, thisprops: true})); diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index eab5fd9804a9..0cf8e06aa64b 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -498,7 +498,12 @@ js::ToAtom(ExclusiveContext* cx, typename MaybeRooted::HandleTyp if (str->isAtom()) return &str->asAtom(); - return AtomizeString(cx, str); + JSAtom* atom = AtomizeString(cx, str); + if (!atom && !allowGC) { + MOZ_ASSERT_IF(cx->isJSContext(), cx->asJSContext()->isThrowingOutOfMemory()); + cx->recoverFromOutOfMemory(); + } + return atom; } template JSAtom* From 4b5a0cb0bac386465d171ef9b978dc2a421c183d Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Wed, 23 Sep 2015 18:40:36 +0900 Subject: [PATCH 019/104] Bug 1207495 - Remove use of expression closure from layout/. r=bz --HG-- extra : commitid : DsNCuxMDmUn extra : rebase_source : 5d3f00526ecbd257ee54f176fe919ce6d20f6ed6 --- layout/base/tests/chrome/test_bug551434.html | 2 +- layout/forms/test/test_bug534785.html | 6 +++--- layout/forms/test/test_textarea_resize.html | 2 +- layout/generic/test/test_bug290397.html | 2 +- layout/generic/test/test_bug469613.xul | 2 +- layout/style/test/test_transitions_cancel_near_end.html | 6 +++--- layout/xul/test/test_windowminmaxsize.xul | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/layout/base/tests/chrome/test_bug551434.html b/layout/base/tests/chrome/test_bug551434.html index 15c78693b0a5..10691c53a94a 100644 --- a/layout/base/tests/chrome/test_bug551434.html +++ b/layout/base/tests/chrome/test_bug551434.html @@ -69,7 +69,7 @@ function runTest() // key events should also be retargeted when the focus changes to an // element in a chrome document from a content document. - i4.addEventListener("keydown", function () $("i3").focus(), false); + i4.addEventListener("keydown", () => $("i3").focus(), false); synthesizeKey("c", { code: "KeyC", keyCode: KeyboardEvent.DOM_VK_C }); diff --git a/layout/forms/test/test_bug534785.html b/layout/forms/test/test_bug534785.html index eb1c6702e581..76590798f521 100644 --- a/layout/forms/test/test_bug534785.html +++ b/layout/forms/test/test_bug534785.html @@ -61,15 +61,15 @@ SimpleTest.waitForFocus(function() { [textAreaWithValue, inputWithValue].forEach(function (elem) { is(elem.value, "test", "Value should persist correctly"); }); - [inputWithoutValue, inputWithValue].forEach(function (elem) elem.type = "submit"); + [inputWithoutValue, inputWithValue].forEach(elem => elem.type = "submit"); document.body.offsetWidth; is(inputWithoutValue.value, "", "Value should persist correctly"); is(inputWithValue.value, "test", "Value should persist correctly"); - [inputWithoutValue, inputWithValue].forEach(function (elem) elem.type = "text"); + [inputWithoutValue, inputWithValue].forEach(elem => elem.type = "text"); document.body.offsetWidth; is(inputWithoutValue.value, "", "Value should persist correctly"); is(inputWithValue.value, "test", "Value should persist correctly"); - [inputWithoutValue, inputWithValue].forEach(function (elem) elem.focus()); // initialze the editor + [inputWithoutValue, inputWithValue].forEach(elem => elem.focus()); // initialze the editor reframeDiv.style.display = "none"; document.body.offsetWidth; reframeDiv.style.display = ""; diff --git a/layout/forms/test/test_textarea_resize.html b/layout/forms/test/test_textarea_resize.html index 5761b1f9d50d..c71f554e0dd0 100644 --- a/layout/forms/test/test_textarea_resize.html +++ b/layout/forms/test/test_textarea_resize.html @@ -17,7 +17,7 @@ /** Test for textbox resizing **/ SimpleTest.waitForExplicitFinish(); -addLoadEvent(function() SimpleTest.executeSoon(doTheTest)); +addLoadEvent(() => SimpleTest.executeSoon(doTheTest)); // -1 means use the default value which is 'both', then test explicitly // setting each possible value. diff --git a/layout/generic/test/test_bug290397.html b/layout/generic/test/test_bug290397.html index c0652e3d93cd..b907b53fa51b 100644 --- a/layout/generic/test/test_bug290397.html +++ b/layout/generic/test/test_bug290397.html @@ -31,7 +31,7 @@ onhashchange = function() { }; function runTest() { var image = document.getElementById("image"); - SimpleTest.waitForFocus(function() synthesizeMouse(image, 10, 10, {})); + SimpleTest.waitForFocus(() => synthesizeMouse(image, 10, 10, {})); } addLoadEvent(runTest); diff --git a/layout/generic/test/test_bug469613.xul b/layout/generic/test/test_bug469613.xul index d15ec4732f32..0310cfe8c97c 100644 --- a/layout/generic/test/test_bug469613.xul +++ b/layout/generic/test/test_bug469613.xul @@ -78,7 +78,7 @@ function doTest() { } SimpleTest.waitForExplicitFinish(); -addLoadEvent(function() setTimeout(doTest, 0)); +addLoadEvent(() => setTimeout(doTest, 0)); ]]> diff --git a/layout/style/test/test_transitions_cancel_near_end.html b/layout/style/test/test_transitions_cancel_near_end.html index 124d90890aac..4fca67adaa0f 100644 --- a/layout/style/test/test_transitions_cancel_near_end.html +++ b/layout/style/test/test_transitions_cancel_near_end.html @@ -66,10 +66,10 @@ window.addEventListener('load', function() { }, false); }); - cases.forEach(function(aCase) aCase.className = 'another' ); + cases.forEach(aCase => aCase.className = 'another' ); - window.setTimeout(function() cases[0].className = '', 500); - window.setTimeout(function() cases[1].className = cases[2].className = '', 250); + window.setTimeout(() => cases[0].className = '', 500); + window.setTimeout(() => cases[1].className = cases[2].className = '', 250); }, false); diff --git a/layout/xul/test/test_windowminmaxsize.xul b/layout/xul/test/test_windowminmaxsize.xul index d41f6a5f5eb2..2d54ee39f32b 100644 --- a/layout/xul/test/test_windowminmaxsize.xul +++ b/layout/xul/test/test_windowminmaxsize.xul @@ -207,8 +207,8 @@ function titledPanelWindowOpened(panelwindow) { var panel = panelwindow.document.documentElement.firstChild; panel.openPopup(); - panel.addEventListener("popupshown", function() doTitledPanelTest(panel), false); - panel.addEventListener("popuphidden", function() done(panelwindow), false); + panel.addEventListener("popupshown", () => doTitledPanelTest(panel), false); + panel.addEventListener("popuphidden", () => done(panelwindow), false); } function doTitledPanelTest(panel) From 95e75e96f83fa3ff59d37aa1aafe7fa82cc4c0d6 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Wed, 23 Sep 2015 18:40:52 +0900 Subject: [PATCH 020/104] Bug 1207496 - Part 1: Remove use of expression closure from services/common/. r=gps --HG-- extra : commitid : EeWW6zhKp9t extra : rebase_source : b23def2c39cad03dd5e4b3a3b440e43d3b343b7a --- services/common/observers.js | 6 +++--- services/common/tests/unit/test_utils_stackTrace.js | 4 ++-- services/common/utils.js | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/services/common/observers.js b/services/common/observers.js index 46f79b9b5b5f..78b14376a37f 100644 --- a/services/common/observers.js +++ b/services/common/observers.js @@ -62,9 +62,9 @@ this.Observers = { // we can make it. We could index by topic, but we can't index by callback // or thisObject, as far as I know, since the keys to JavaScript hashes // (a.k.a. objects) can apparently only be primitive values. - let [observer] = this._cache.filter(function(v) v.topic == topic && - v.callback == callback && - v.thisObject == thisObject); + let [observer] = this._cache.filter(v => v.topic == topic && + v.callback == callback && + v.thisObject == thisObject); if (observer) { this._service.removeObserver(observer, topic); this._cache.splice(this._cache.indexOf(observer), 1); diff --git a/services/common/tests/unit/test_utils_stackTrace.js b/services/common/tests/unit/test_utils_stackTrace.js index 31fa598248aa..6c71d07535d2 100644 --- a/services/common/tests/unit/test_utils_stackTrace.js +++ b/services/common/tests/unit/test_utils_stackTrace.js @@ -2,8 +2,8 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ _("Define some functions in well defined line positions for the test"); -function foo(v) bar(v + 1); // line 2 -function bar(v) baz(v + 1); // line 3 +function foo(v) { return bar(v + 1); } // line 2 +function bar(v) { return baz(v + 1); } // line 3 function baz(v) { throw new Error(v + 1); } // line 4 _("Make sure lazy constructor calling/assignment works"); diff --git a/services/common/utils.js b/services/common/utils.js index 6921dbbe35ef..4353a12cf7f4 100644 --- a/services/common/utils.js +++ b/services/common/utils.js @@ -314,8 +314,9 @@ this.CommonUtils = { } // Handle a left shift, restricted to bytes. - function left(octet, shift) - (octet << shift) & 0xff; + function left(octet, shift) { + return (octet << shift) & 0xff; + } advance(); accumulate(left(val, 3)); From eee84639cb445af29c114ade465e50f15aa84f0a Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Wed, 23 Sep 2015 18:40:52 +0900 Subject: [PATCH 021/104] Bug 1207496 - Part 2: Remove use of expression closure from services/crypt/. r=mrbkap --HG-- extra : commitid : LkPx7u92lV8 extra : rebase_source : 6de876017e9758260ea3ba84633262d44e7bdee5 --- services/crypto/modules/WeaveCrypto.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/crypto/modules/WeaveCrypto.js b/services/crypto/modules/WeaveCrypto.js index df6cd57839a1..fc1140851d4b 100644 --- a/services/crypto/modules/WeaveCrypto.js +++ b/services/crypto/modules/WeaveCrypto.js @@ -538,7 +538,9 @@ WeaveCrypto.prototype = { } }, - generateRandomIV : function() this.generateRandomBytes(this.ivLength), + generateRandomIV : function() { + return this.generateRandomBytes(this.ivLength); + }, generateRandomBytes : function(byteCount) { this.log("generateRandomBytes() called"); From 1bddf54a42325c0dfe73174d46e50892c263fdf8 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Wed, 23 Sep 2015 18:40:52 +0900 Subject: [PATCH 022/104] Bug 1207496 - Part 3: Remove use of expression closure from services/fxaccounts/. r=markh --HG-- extra : commitid : HCAQePE8WbS extra : rebase_source : 2d0c293f88060e187f92f437b2b45aa2c50cfb04 --- services/fxaccounts/FxAccounts.jsm | 4 +++- services/fxaccounts/tests/xpcshell/test_profile.js | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/services/fxaccounts/FxAccounts.jsm b/services/fxaccounts/FxAccounts.jsm index 2984cd5cb5b8..4e665f8c6a44 100644 --- a/services/fxaccounts/FxAccounts.jsm +++ b/services/fxaccounts/FxAccounts.jsm @@ -88,7 +88,9 @@ AccountState.prototype = { whenKeysReadyDeferred: null, // If the storage manager has been nuked then we are no longer current. - get isCurrent() this.storageManager != null, + get isCurrent() { + return this.storageManager != null; + }, abort() { if (this.whenVerifiedDeferred) { diff --git a/services/fxaccounts/tests/xpcshell/test_profile.js b/services/fxaccounts/tests/xpcshell/test_profile.js index 76d0969d2d93..81d239100ded 100644 --- a/services/fxaccounts/tests/xpcshell/test_profile.js +++ b/services/fxaccounts/tests/xpcshell/test_profile.js @@ -69,7 +69,9 @@ function FxaMock() { FxaMock.prototype = { currentAccountState: { profile: null, - get isCurrent() true, + get isCurrent() { + return true; + } }, getSignedInUser: function () { From 1f8ec8e3d4e0a0e8cc43d52ab01ad25be08dfdda Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Wed, 23 Sep 2015 18:40:53 +0900 Subject: [PATCH 023/104] Bug 1207496 - Part 4: Remove use of expression closure from services/sync/. r=gps --HG-- extra : commitid : JyCsU57jx9W extra : rebase_source : ed21660ac295a1d1a2fd423e86b8a74267eba088 --- services/sync/modules/engines/clients.js | 20 +++++-- services/sync/modules/engines/forms.js | 4 +- services/sync/modules/main.js | 14 ++--- services/sync/modules/policies.js | 40 ++++++++++---- services/sync/modules/record.js | 13 +++-- services/sync/modules/resource.js | 4 +- services/sync/modules/service.js | 8 ++- services/sync/modules/util.js | 4 +- ..._bookmark_legacy_microsummaries_support.js | 4 +- services/sync/tests/unit/test_corrupt_keys.js | 2 +- .../tests/unit/test_service_detect_upgrade.js | 4 +- .../test_service_sync_updateEnabledEngines.js | 4 +- services/sync/tests/unit/test_tab_tracker.js | 4 +- services/sync/tests/unit/test_utils_catch.js | 52 +++++++++++-------- .../sync/tests/unit/test_utils_deferGetSet.js | 8 ++- services/sync/tests/unit/test_utils_lock.js | 28 +++++----- services/sync/tests/unit/test_utils_notify.js | 24 +++++---- 17 files changed, 152 insertions(+), 85 deletions(-) diff --git a/services/sync/modules/engines/clients.js b/services/sync/modules/engines/clients.js index f423242c9ac0..7d55cded58fc 100644 --- a/services/sync/modules/engines/clients.js +++ b/services/sync/modules/engines/clients.js @@ -49,7 +49,9 @@ ClientEngine.prototype = { _trackerObj: ClientsTracker, // Always sync client data as it controls other sync behavior - get enabled() true, + get enabled() { + return true; + }, get lastRecordUpload() { return Svc.Prefs.get(this.name + ".lastRecordUpload", 0); @@ -102,7 +104,9 @@ ClientEngine.prototype = { let localID = Svc.Prefs.get("client.GUID", ""); return localID == "" ? this.localID = Utils.makeGUID() : localID; }, - set localID(value) Svc.Prefs.set("client.GUID", value), + set localID(value) { + Svc.Prefs.set("client.GUID", value); + }, get brandName() { let brand = new StringBundle("chrome://branding/locale/brand.properties"); @@ -116,10 +120,16 @@ ClientEngine.prototype = { return this.localName = Utils.getDefaultDeviceName(); }, - set localName(value) Svc.Prefs.set("client.name", value), + set localName(value) { + Svc.Prefs.set("client.name", value); + }, - get localType() Svc.Prefs.get("client.type", "desktop"), - set localType(value) Svc.Prefs.set("client.type", value), + get localType() { + return Svc.Prefs.get("client.type", "desktop"); + }, + set localType(value) { + Svc.Prefs.set("client.type", value); + }, isMobile: function isMobile(id) { if (this._store._remoteClients[id]) diff --git a/services/sync/modules/engines/forms.js b/services/sync/modules/engines/forms.js index a139280b31e0..84e46de622c2 100644 --- a/services/sync/modules/engines/forms.js +++ b/services/sync/modules/engines/forms.js @@ -109,7 +109,9 @@ FormEngine.prototype = { syncPriority: 6, - get prefName() "history", + get prefName() { + return "history"; + }, _findDupe: function _findDupe(item) { return FormWrapper.getGUID(item.name, item.value); diff --git a/services/sync/modules/main.js b/services/sync/modules/main.js index f59beb184d78..e8e705e726af 100644 --- a/services/sync/modules/main.js +++ b/services/sync/modules/main.js @@ -15,12 +15,14 @@ var lazies = { }; function lazyImport(module, dest, props) { - function getter(prop) function() { - let ns = {}; - Components.utils.import(module, ns); - delete dest[prop]; - return dest[prop] = ns[prop]; - }; + function getter(prop) { + return function() { + let ns = {}; + Components.utils.import(module, ns); + delete dest[prop]; + return dest[prop] = ns[prop]; + }; + } props.forEach(function (prop) { dest.__defineGetter__(prop, getter(prop)); }); } diff --git a/services/sync/modules/policies.js b/services/sync/modules/policies.js index fbc547d1073d..e940f3febb3f 100644 --- a/services/sync/modules/policies.js +++ b/services/sync/modules/policies.js @@ -61,20 +61,40 @@ SyncScheduler.prototype = { }, // nextSync is in milliseconds, but prefs can't hold that much - get nextSync() Svc.Prefs.get("nextSync", 0) * 1000, - set nextSync(value) Svc.Prefs.set("nextSync", Math.floor(value / 1000)), + get nextSync() { + return Svc.Prefs.get("nextSync", 0) * 1000; + }, + set nextSync(value) { + Svc.Prefs.set("nextSync", Math.floor(value / 1000)); + }, - get syncInterval() Svc.Prefs.get("syncInterval", this.singleDeviceInterval), - set syncInterval(value) Svc.Prefs.set("syncInterval", value), + get syncInterval() { + return Svc.Prefs.get("syncInterval", this.singleDeviceInterval); + }, + set syncInterval(value) { + Svc.Prefs.set("syncInterval", value); + }, - get syncThreshold() Svc.Prefs.get("syncThreshold", SINGLE_USER_THRESHOLD), - set syncThreshold(value) Svc.Prefs.set("syncThreshold", value), + get syncThreshold() { + return Svc.Prefs.get("syncThreshold", SINGLE_USER_THRESHOLD); + }, + set syncThreshold(value) { + Svc.Prefs.set("syncThreshold", value); + }, - get globalScore() Svc.Prefs.get("globalScore", 0), - set globalScore(value) Svc.Prefs.set("globalScore", value), + get globalScore() { + return Svc.Prefs.get("globalScore", 0); + }, + set globalScore(value) { + Svc.Prefs.set("globalScore", value); + }, - get numClients() Svc.Prefs.get("numClients", 0), - set numClients(value) Svc.Prefs.set("numClients", value), + get numClients() { + return Svc.Prefs.get("numClients", 0); + }, + set numClients(value) { + Svc.Prefs.set("numClients", value); + }, init: function init() { this._log.level = Log.Level[Svc.Prefs.get("log.logger.service.main")]; diff --git a/services/sync/modules/record.js b/services/sync/modules/record.js index 71a6b4083f6a..43e452a41001 100644 --- a/services/sync/modules/record.js +++ b/services/sync/modules/record.js @@ -196,7 +196,9 @@ CryptoWrapper.prototype = { }, // The custom setter below masks the parent's getter, so explicitly call it :( - get id() WBORecord.prototype.__lookupGetter__("id").call(this), + get id() { + return WBORecord.prototype.__lookupGetter__("id").call(this); + }, // Keep both plaintext and encrypted versions of the id to verify integrity set id(val) { @@ -356,8 +358,9 @@ CollectionKeyManager.prototype = { /** * Create a WBO for the current keys. */ - asWBO: function(collection, id) - this._makeWBO(this._collections, this._default), + asWBO: function(collection, id) { + return this._makeWBO(this._collections, this._default); + }, /** * Compute a new default key, and new keys for any specified collections. @@ -560,14 +563,14 @@ Collection.prototype = { }, // Apply the action to a certain set of ids - get ids() this._ids, + get ids() { return this._ids; }, set ids(value) { this._ids = value; this._rebuildURL(); }, // Limit how many records to get - get limit() this._limit, + get limit() { return this._limit; }, set limit(value) { this._limit = value; this._rebuildURL(); diff --git a/services/sync/modules/resource.js b/services/sync/modules/resource.js index 9bacb3491a98..84cc99f8d71e 100644 --- a/services/sync/modules/resource.js +++ b/services/sync/modules/resource.js @@ -134,7 +134,9 @@ AsyncResource.prototype = { // // Get and set the data encapulated in the resource. _data: null, - get data() this._data, + get data() { + return this._data; + }, set data(value) { this._data = value; }, diff --git a/services/sync/modules/service.js b/services/sync/modules/service.js index 43b1d979c9f8..9c7dd0321a76 100644 --- a/services/sync/modules/service.js +++ b/services/sync/modules/service.js @@ -79,7 +79,9 @@ Sync11Service.prototype = { metaURL: null, cryptoKeyURL: null, - get serverURL() Svc.Prefs.get("serverURL"), + get serverURL() { + return Svc.Prefs.get("serverURL"); + }, set serverURL(value) { if (!value.endsWith("/")) { value += "/"; @@ -94,7 +96,9 @@ Sync11Service.prototype = { Svc.Prefs.reset("clusterURL"); }, - get clusterURL() Svc.Prefs.get("clusterURL", ""), + get clusterURL() { + return Svc.Prefs.get("clusterURL", ""); + }, set clusterURL(value) { Svc.Prefs.set("clusterURL", value); this._updateCachedURLs(); diff --git a/services/sync/modules/util.js b/services/sync/modules/util.js index 85f67d78ae22..a43d506884e7 100644 --- a/services/sync/modules/util.js +++ b/services/sync/modules/util.js @@ -477,7 +477,7 @@ this.Utils = { // 20-char sync key. if (pp.length == 23 && - [5, 11, 17].every(function(i) pp[i] == '-')) { + [5, 11, 17].every(i => pp[i] == '-')) { return pp.slice(0, 5) + pp.slice(6, 11) + pp.slice(12, 17) + pp.slice(18, 23); @@ -485,7 +485,7 @@ this.Utils = { // "Modern" 26-char key. if (pp.length == 31 && - [1, 7, 13, 19, 25].every(function(i) pp[i] == '-')) { + [1, 7, 13, 19, 25].every(i => pp[i] == '-')) { return pp.slice(0, 1) + pp.slice(2, 7) + pp.slice(8, 13) + pp.slice(14, 19) diff --git a/services/sync/tests/unit/test_bookmark_legacy_microsummaries_support.js b/services/sync/tests/unit/test_bookmark_legacy_microsummaries_support.js index a7e3a46477f0..207372ed68cb 100644 --- a/services/sync/tests/unit/test_bookmark_legacy_microsummaries_support.js +++ b/services/sync/tests/unit/test_bookmark_legacy_microsummaries_support.js @@ -85,12 +85,12 @@ function run_test() { do_check_eq(PlacesUtils.bookmarks.getKeywordForBookmark(id), null); do_check_throws( - function () PlacesUtils.annotations.getItemAnnotation(id, GENERATORURI_ANNO), + () => PlacesUtils.annotations.getItemAnnotation(id, GENERATORURI_ANNO), Cr.NS_ERROR_NOT_AVAILABLE ); do_check_throws( - function () PlacesUtils.annotations.getItemAnnotation(id, STATICTITLE_ANNO), + () => PlacesUtils.annotations.getItemAnnotation(id, STATICTITLE_ANNO), Cr.NS_ERROR_NOT_AVAILABLE ); diff --git a/services/sync/tests/unit/test_corrupt_keys.js b/services/sync/tests/unit/test_corrupt_keys.js index 2db080a8f809..cce01636170c 100644 --- a/services/sync/tests/unit/test_corrupt_keys.js +++ b/services/sync/tests/unit/test_corrupt_keys.js @@ -51,7 +51,7 @@ add_task(function test_locally_changed_keys() { }]}]}; delete Svc.Session; Svc.Session = { - getBrowserState: function () JSON.stringify(myTabs) + getBrowserState: () => JSON.stringify(myTabs) }; setBasicCredentials("johndoe", "password", passphrase); diff --git a/services/sync/tests/unit/test_service_detect_upgrade.js b/services/sync/tests/unit/test_service_detect_upgrade.js index 528bd751b133..0f46832d9836 100644 --- a/services/sync/tests/unit/test_service_detect_upgrade.js +++ b/services/sync/tests/unit/test_service_detect_upgrade.js @@ -60,7 +60,7 @@ add_test(function v4_upgrade() { }]}]}; delete Svc.Session; Svc.Session = { - getBrowserState: function () JSON.stringify(myTabs) + getBrowserState: () => JSON.stringify(myTabs) }; Service.status.resetSync(); @@ -229,7 +229,7 @@ add_test(function v5_upgrade() { }]}]}; delete Svc.Session; Svc.Session = { - getBrowserState: function () JSON.stringify(myTabs) + getBrowserState: () => JSON.stringify(myTabs) }; Service.status.resetSync(); diff --git a/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js b/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js index ffc631dd5f80..5192e694d07b 100644 --- a/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js +++ b/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js @@ -41,7 +41,9 @@ function StirlingEngine() { StirlingEngine.prototype = { __proto__: SteamEngine.prototype, // This engine's enabled state is the same as the SteamEngine's. - get prefName() "steam" + get prefName() { + return "steam"; + } }; Service.engineManager.register(StirlingEngine); diff --git a/services/sync/tests/unit/test_tab_tracker.js b/services/sync/tests/unit/test_tab_tracker.js index 620ea07e58a4..f0bff3cc91d3 100644 --- a/services/sync/tests/unit/test_tab_tracker.js +++ b/services/sync/tests/unit/test_tab_tracker.js @@ -15,7 +15,9 @@ function fakeSvcWinMediator() { getEnumerator: function() { return { cnt: 2, - hasMoreElements: function() this.cnt-- > 0, + hasMoreElements: function() { + return this.cnt-- > 0; + }, getNext: function() { let elt = {addTopics: [], remTopics: []}; logs.push(elt); diff --git a/services/sync/tests/unit/test_utils_catch.js b/services/sync/tests/unit/test_utils_catch.js index a10e5eb0d804..302e20e2c311 100644 --- a/services/sync/tests/unit/test_utils_catch.js +++ b/services/sync/tests/unit/test_utils_catch.js @@ -15,31 +15,39 @@ function run_test() { } }, - func: function() this.catch(function() { - rightThis = this == obj; - didCall = true; - return 5; - })(), + func: function() { + return this.catch(function() { + rightThis = this == obj; + didCall = true; + return 5; + })(); + }, - throwy: function() this.catch(function() { - rightThis = this == obj; - didCall = true; - throw 10; - })(), + throwy: function() { + return this.catch(function() { + rightThis = this == obj; + didCall = true; + throw 10; + })(); + }, - callbacky: function() this.catch(function() { - rightThis = this == obj; - didCall = true; - throw 10; - }, function(ex) { - wasTen = (ex == 10) - })(), + callbacky: function() { + return this.catch(function() { + rightThis = this == obj; + didCall = true; + throw 10; + }, function(ex) { + wasTen = (ex == 10) + })(); + }, - lockedy: function() this.catch(function() { - rightThis = this == obj; - didCall = true; - throw("Could not acquire lock."); - })() + lockedy: function() { + return this.catch(function() { + rightThis = this == obj; + didCall = true; + throw("Could not acquire lock."); + })(); + } }; _("Make sure a normal call will call and return"); diff --git a/services/sync/tests/unit/test_utils_deferGetSet.js b/services/sync/tests/unit/test_utils_deferGetSet.js index 55c0fcb0e670..9d58a9873e3b 100644 --- a/services/sync/tests/unit/test_utils_deferGetSet.js +++ b/services/sync/tests/unit/test_utils_deferGetSet.js @@ -6,8 +6,12 @@ function run_test() { base.prototype = { dst: {}, - get a() "a", - set b(val) this.dst.b = val + "!!!" + get a() { + return "a"; + }, + set b(val) { + this.dst.b = val + "!!!"; + } }; let src = new base(); diff --git a/services/sync/tests/unit/test_utils_lock.js b/services/sync/tests/unit/test_utils_lock.js index fd8a4b1f522e..d1830787e63a 100644 --- a/services/sync/tests/unit/test_utils_lock.js +++ b/services/sync/tests/unit/test_utils_lock.js @@ -27,19 +27,23 @@ function run_test() { this._locked = false; }, - func: function() this._lock("Test utils lock", - function() { - rightThis = this == obj; - didCall = true; - return 5; - })(), + func: function() { + return this._lock("Test utils lock", + function() { + rightThis = this == obj; + didCall = true; + return 5; + })(); + }, - throwy: function() this._lock("Test utils lock throwy", - function() { - rightThis = this == obj; - didCall = true; - this.throwy(); - })() + throwy: function() { + return this._lock("Test utils lock throwy", + function() { + rightThis = this == obj; + didCall = true; + this.throwy(); + })(); + } }; _("Make sure a normal call will call and return"); diff --git a/services/sync/tests/unit/test_utils_notify.js b/services/sync/tests/unit/test_utils_notify.js index c191bbfef67d..5bd38da5f272 100644 --- a/services/sync/tests/unit/test_utils_notify.js +++ b/services/sync/tests/unit/test_utils_notify.js @@ -9,17 +9,21 @@ function run_test() { trace: function() {} }, - func: function() this.notify("bar", "baz", function() { - rightThis = this == obj; - didCall = true; - return 5; - })(), + func: function() { + return this.notify("bar", "baz", function() { + rightThis = this == obj; + didCall = true; + return 5; + })(); + }, - throwy: function() this.notify("bad", "one", function() { - rightThis = this == obj; - didCall = true; - throw 10; - })() + throwy: function() { + return this.notify("bad", "one", function() { + rightThis = this == obj; + didCall = true; + throw 10; + })(); + } }; let state = 0; From 804c890bc05925e7881cb8922cc504fae4f88971 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Tue, 29 Sep 2015 11:48:53 +0200 Subject: [PATCH 024/104] Backed out 1 changesets (bug 1160200) for causing R2 test failures Backed out changeset b4f64c940524 (bug 1160200) --HG-- extra : rebase_source : d037665348c358848b40f6b09194f58b66ce8be9 --- image/DecoderFactory.cpp | 2 -- image/build/nsImageModule.cpp | 1 - layout/reftests/apng-mime/animated.apng | Bin 361 -> 0 bytes layout/reftests/apng-mime/expected.html | 3 --- layout/reftests/apng-mime/reftest.list | 1 - layout/reftests/apng-mime/static.png | Bin 100 -> 0 bytes layout/reftests/apng-mime/test.html | 6 ------ layout/reftests/reftest.list | 3 --- netwerk/mime/nsMimeTypes.h | 1 - .../exthandler/nsExternalHelperAppService.cpp | 1 - 10 files changed, 18 deletions(-) delete mode 100644 layout/reftests/apng-mime/animated.apng delete mode 100644 layout/reftests/apng-mime/expected.html delete mode 100644 layout/reftests/apng-mime/reftest.list delete mode 100644 layout/reftests/apng-mime/static.png delete mode 100644 layout/reftests/apng-mime/test.html diff --git a/image/DecoderFactory.cpp b/image/DecoderFactory.cpp index fbb448a73e89..5b4d8c808090 100644 --- a/image/DecoderFactory.cpp +++ b/image/DecoderFactory.cpp @@ -34,8 +34,6 @@ DecoderFactory::GetDecoderType(const char* aMimeType) type = DecoderType::PNG; } else if (!strcmp(aMimeType, IMAGE_X_PNG)) { type = DecoderType::PNG; - } else if (!strcmp(aMimeType, IMAGE_APNG)) { - type = DecoderType::PNG; // GIF } else if (!strcmp(aMimeType, IMAGE_GIF)) { diff --git a/image/build/nsImageModule.cpp b/image/build/nsImageModule.cpp index f786005ddca4..6bc4c04a6b46 100644 --- a/image/build/nsImageModule.cpp +++ b/image/build/nsImageModule.cpp @@ -77,7 +77,6 @@ static const mozilla::Module::CategoryEntry kImageCategories[] = { { "Gecko-Content-Viewers", IMAGE_BMP_MS, "@mozilla.org/content/document-loader-factory;1" }, { "Gecko-Content-Viewers", IMAGE_ICON_MS, "@mozilla.org/content/document-loader-factory;1" }, { "Gecko-Content-Viewers", IMAGE_PNG, "@mozilla.org/content/document-loader-factory;1" }, - { "Gecko-Content-Viewers", IMAGE_APNG, "@mozilla.org/content/document-loader-factory;1" }, { "Gecko-Content-Viewers", IMAGE_X_PNG, "@mozilla.org/content/document-loader-factory;1" }, { "content-sniffing-services", "@mozilla.org/image/loader;1", "@mozilla.org/image/loader;1" }, { nullptr } diff --git a/layout/reftests/apng-mime/animated.apng b/layout/reftests/apng-mime/animated.apng deleted file mode 100644 index a310055bb899e99249f157582bc4f7f873fcff2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 361 zcmeAS@N?(olHy`uVBq!ia0vp^DImpw;&hW|jw@M)f~98i$4B*-tA!Qt5rkS?h-h%O)#VkC$G1}PwZZuB8dAkWs*#W5t~ z-rKW=ybKIH%nO$Ob3O0c&&E@rIl)6ksMAGhB2Fqrp>oN8KgA_kLSjIJVAe4L*%M7d`~|Wd(^4EmfHV`xN=HGUl}rn6?*9_?@7@ BT?POE diff --git a/layout/reftests/apng-mime/expected.html b/layout/reftests/apng-mime/expected.html deleted file mode 100644 index d069957fdf67..000000000000 --- a/layout/reftests/apng-mime/expected.html +++ /dev/null @@ -1,3 +0,0 @@ - -apng expected - diff --git a/layout/reftests/apng-mime/reftest.list b/layout/reftests/apng-mime/reftest.list deleted file mode 100644 index fef0f4a7364d..000000000000 --- a/layout/reftests/apng-mime/reftest.list +++ /dev/null @@ -1 +0,0 @@ -== test.html expected.html diff --git a/layout/reftests/apng-mime/static.png b/layout/reftests/apng-mime/static.png deleted file mode 100644 index 6f76d4438724111983a11860f13568361b52d9bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 100 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5y8Awi_W^)%vF$egBxTd6}EPfSw1jv=~ba4!k rkbHZv5y)XUyx@1R|3ikWAU1;^qeuV)<1IPC3=q%L)z4*}Q$iB}r??p{ diff --git a/layout/reftests/apng-mime/test.html b/layout/reftests/apng-mime/test.html deleted file mode 100644 index 35c1dc09d58f..000000000000 --- a/layout/reftests/apng-mime/test.html +++ /dev/null @@ -1,6 +0,0 @@ - -apng test - - - - diff --git a/layout/reftests/reftest.list b/layout/reftests/reftest.list index 9b38f585d31c..eca7e0c590c1 100644 --- a/layout/reftests/reftest.list +++ b/layout/reftests/reftest.list @@ -19,9 +19,6 @@ include w3c-css/received/reftest.list include abs-pos/reftest.list include position-relative/reftest.list -# apng-mime -include apng-mime/reftest.list - include async-scrolling/reftest.list # backgrounds/ diff --git a/netwerk/mime/nsMimeTypes.h b/netwerk/mime/nsMimeTypes.h index c4c3a5245ef4..13d99b3cc56c 100644 --- a/netwerk/mime/nsMimeTypes.h +++ b/netwerk/mime/nsMimeTypes.h @@ -94,7 +94,6 @@ #define IMAGE_JPG "image/jpg" #define IMAGE_PJPEG "image/pjpeg" #define IMAGE_PNG "image/png" -#define IMAGE_APNG "video/vnd.mozilla.apng" #define IMAGE_X_PNG "image/x-png" #define IMAGE_PPM "image/x-portable-pixmap" #define IMAGE_XBM "image/x-xbitmap" diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index 52fdd1cce95f..c7bfb9f50b0a 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -576,7 +576,6 @@ static nsExtraMimeTypeEntry extraMimeEntries [] = { IMAGE_ICO, "ico,cur", "ICO Image" }, { IMAGE_JPEG, "jpeg,jpg,jfif,pjpeg,pjp", "JPEG Image" }, { IMAGE_PNG, "png", "PNG Image" }, - { IMAGE_APNG, "apng", "APNG Image" }, { IMAGE_TIFF, "tiff,tif", "TIFF Image" }, { IMAGE_XBM, "xbm", "XBM Image" }, { IMAGE_SVG_XML, "svg", "Scalable Vector Graphics" }, From 9d409001a2ecd251e66f216f1749622baa67036b Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 29 Sep 2015 19:10:51 +0900 Subject: [PATCH 025/104] Bug 1209132 - Part 2: Fix SSE assertion in Assembler::vhaddpd. r=jandem --HG-- extra : commitid : AUILx1fRp6I extra : amend_source : 9b3524feee409649adc3b7811687c238a69fce1b --- js/src/jit/x86/Assembler-x86.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jit/x86/Assembler-x86.h b/js/src/jit/x86/Assembler-x86.h index 780d71b020a7..d1acac67e31c 100644 --- a/js/src/jit/x86/Assembler-x86.h +++ b/js/src/jit/x86/Assembler-x86.h @@ -392,7 +392,7 @@ class Assembler : public AssemblerX86Shared } void vhaddpd(FloatRegister src, FloatRegister dest) { - MOZ_ASSERT(HasSSE2()); + MOZ_ASSERT(HasSSE3()); MOZ_ASSERT(src.size() == 16); MOZ_ASSERT(dest.size() == 16); masm.vhaddpd_rr(src.encoding(), dest.encoding()); From 6c605d106de827c3da77ae2ce6fa532924662c96 Mon Sep 17 00:00:00 2001 From: Morris Tseng Date: Tue, 29 Sep 2015 11:51:23 +0100 Subject: [PATCH 026/104] Bug 709490 - Part 1: Let ImageBridge transfer CanvasClient async, r=nical --- dom/html/HTMLCanvasElement.cpp | 38 +++++++ dom/html/HTMLCanvasElement.h | 7 ++ gfx/gl/GLScreenBuffer.cpp | 69 +++++++++++- gfx/gl/GLScreenBuffer.h | 7 ++ gfx/gl/SharedSurface.cpp | 6 +- gfx/gl/SharedSurface.h | 2 + gfx/layers/AsyncCanvasRenderer.cpp | 80 ++++++++++++++ gfx/layers/AsyncCanvasRenderer.h | 100 ++++++++++++++++++ gfx/layers/CopyableCanvasLayer.cpp | 6 +- gfx/layers/Layers.cpp | 20 ++++ gfx/layers/Layers.h | 20 ++-- gfx/layers/client/CanvasClient.cpp | 83 +++++++++++++-- gfx/layers/client/CanvasClient.h | 55 ++++++++++ gfx/layers/client/ClientCanvasLayer.cpp | 86 ++++----------- gfx/layers/client/ClientCanvasLayer.h | 1 - gfx/layers/client/TextureClient.cpp | 1 + gfx/layers/ipc/ImageBridgeChild.cpp | 135 +++++++++++++++++++++++- gfx/layers/ipc/ImageBridgeChild.h | 10 ++ gfx/layers/ipc/PImageBridge.ipdl | 2 +- gfx/layers/moz.build | 2 + 20 files changed, 631 insertions(+), 99 deletions(-) create mode 100644 gfx/layers/AsyncCanvasRenderer.cpp create mode 100644 gfx/layers/AsyncCanvasRenderer.h diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp index f816f39a17c9..a6f89034f079 100644 --- a/dom/html/HTMLCanvasElement.cpp +++ b/dom/html/HTMLCanvasElement.cpp @@ -21,6 +21,7 @@ #include "mozilla/dom/MouseEvent.h" #include "mozilla/EventDispatcher.h" #include "mozilla/gfx/Rect.h" +#include "mozilla/layers/AsyncCanvasRenderer.h" #include "mozilla/MouseEvents.h" #include "mozilla/Preferences.h" #include "mozilla/Telemetry.h" @@ -251,6 +252,10 @@ HTMLCanvasElement::~HTMLCanvasElement() if (mRequestedFrameRefreshObserver) { mRequestedFrameRefreshObserver->DetachFromRefreshDriver(); } + + if (mAsyncCanvasRenderer) { + mAsyncCanvasRenderer->mHTMLCanvasElement = nullptr; + } } NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement, nsGenericHTMLElement, @@ -1236,5 +1241,38 @@ HTMLCanvasElement::GetSurfaceSnapshot(bool* aPremultAlpha) return mCurrentContext->GetSurfaceSnapshot(aPremultAlpha); } +AsyncCanvasRenderer* +HTMLCanvasElement::GetAsyncCanvasRenderer() +{ + if (!mAsyncCanvasRenderer) { + mAsyncCanvasRenderer = new AsyncCanvasRenderer(); + mAsyncCanvasRenderer->mHTMLCanvasElement = this; + } + + return mAsyncCanvasRenderer; +} + +/* static */ void +HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer) +{ + HTMLCanvasElement *element = aRenderer->mHTMLCanvasElement; + if (!element) { + return; + } + + gfx::IntSize asyncCanvasSize = aRenderer->GetSize(); + + ErrorResult rv; + element->SetUnsignedIntAttr(nsGkAtoms::width, asyncCanvasSize.width, rv); + if (rv.Failed()) { + NS_WARNING("Failed to set width attribute to a canvas element asynchronously."); + } + + element->SetUnsignedIntAttr(nsGkAtoms::height, asyncCanvasSize.height, rv); + if (rv.Failed()) { + NS_WARNING("Failed to set height attribute to a canvas element asynchronously."); + } +} + } // namespace dom } // namespace mozilla diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h index dc76df89d903..8c12c98dd28b 100644 --- a/dom/html/HTMLCanvasElement.h +++ b/dom/html/HTMLCanvasElement.h @@ -22,6 +22,7 @@ class nsITimerCallback; namespace mozilla { namespace layers { +class AsyncCanvasRenderer; class CanvasLayer; class Image; class LayerManager; @@ -91,6 +92,7 @@ class HTMLCanvasElement final : public nsGenericHTMLElement, DEFAULT_CANVAS_HEIGHT = 150 }; + typedef layers::AsyncCanvasRenderer AsyncCanvasRenderer; typedef layers::CanvasLayer CanvasLayer; typedef layers::LayerManager LayerManager; @@ -282,6 +284,8 @@ public: nsresult GetContext(const nsAString& aContextId, nsISupports** aContext); + static void SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer); + protected: virtual ~HTMLCanvasElement(); @@ -307,6 +311,8 @@ protected: nsISupports** aResult); void CallPrintCallback(); + AsyncCanvasRenderer* GetAsyncCanvasRenderer(); + CanvasContextType mCurrentContextType; nsRefPtr mOriginalCanvas; nsRefPtr mPrintCallback; @@ -314,6 +320,7 @@ protected: nsRefPtr mPrintState; nsTArray> mRequestedFrameListeners; nsRefPtr mRequestedFrameRefreshObserver; + nsRefPtr mAsyncCanvasRenderer; public: // Record whether this canvas should be write-only or not. diff --git a/gfx/gl/GLScreenBuffer.cpp b/gfx/gl/GLScreenBuffer.cpp index d02876868ee2..f6490911d2af 100755 --- a/gfx/gl/GLScreenBuffer.cpp +++ b/gfx/gl/GLScreenBuffer.cpp @@ -10,18 +10,32 @@ #include "GLContext.h" #include "GLBlitHelper.h" #include "GLReadTexImageHelper.h" +#include "SharedSurfaceEGL.h" #include "SharedSurfaceGL.h" +#include "ScopedGLHelpers.h" +#include "gfx2DGlue.h" +#include "../layers/ipc/ShadowLayers.h" +#include "mozilla/layers/CompositableForwarder.h" +#include "mozilla/layers/TextureClientSharedSurface.h" + +#ifdef XP_WIN +#include "SharedSurfaceANGLE.h" // for SurfaceFactory_ANGLEShareHandle +#include "gfxWindowsPlatform.h" +#endif + #ifdef MOZ_WIDGET_GONK #include "SharedSurfaceGralloc.h" #include "nsXULAppAPI.h" #endif + #ifdef XP_MACOSX #include "SharedSurfaceIO.h" #endif -#include "ScopedGLHelpers.h" -#include "gfx2DGlue.h" -#include "../layers/ipc/ShadowLayers.h" -#include "mozilla/layers/TextureClientSharedSurface.h" + +#ifdef GL_PROVIDER_GLX +#include "GLXLibrary.h" +#include "SharedSurfaceGLX.h" +#endif namespace mozilla { namespace gl { @@ -51,6 +65,53 @@ GLScreenBuffer::Create(GLContext* gl, return Move(ret); } +/* static */ UniquePtr +GLScreenBuffer::CreateFactory(GLContext* gl, + const SurfaceCaps& caps, + const RefPtr& forwarder, + const layers::TextureFlags& flags) +{ + UniquePtr factory = nullptr; + if (!gfxPrefs::WebGLForceLayersReadback()) { + switch (forwarder->GetCompositorBackendType()) { + case mozilla::layers::LayersBackend::LAYERS_OPENGL: { +#if defined(XP_MACOSX) + factory = SurfaceFactory_IOSurface::Create(gl, caps, forwarder, flags); +#elif defined(MOZ_WIDGET_GONK) + factory = MakeUnique(gl, caps, forwarder, flags); +#elif defined(GL_PROVIDER_GLX) + if (sGLXLibrary.UseSurfaceSharing()) + factory = SurfaceFactory_GLXDrawable::Create(gl, caps, forwarder, flags); +#else + if (gl->GetContextType() == GLContextType::EGL) { + if (XRE_IsParentProcess()) { + factory = SurfaceFactory_EGLImage::Create(gl, caps, forwarder, flags); + } + } +#endif + break; + } + case mozilla::layers::LayersBackend::LAYERS_D3D11: { +#ifdef XP_WIN + // Enable surface sharing only if ANGLE and compositing devices + // are both WARP or both not WARP + if (gl->IsANGLE() && + (gl->IsWARP() == gfxWindowsPlatform::GetPlatform()->IsWARP()) && + gfxWindowsPlatform::GetPlatform()->CompositorD3D11TextureSharingWorks()) + { + factory = SurfaceFactory_ANGLEShareHandle::Create(gl, caps, forwarder, flags); + } +#endif + break; + } + default: + break; + } + } + + return factory; +} + GLScreenBuffer::GLScreenBuffer(GLContext* gl, const SurfaceCaps& caps, UniquePtr factory) diff --git a/gfx/gl/GLScreenBuffer.h b/gfx/gl/GLScreenBuffer.h index 15edad69250b..2b31500cebfb 100644 --- a/gfx/gl/GLScreenBuffer.h +++ b/gfx/gl/GLScreenBuffer.h @@ -25,6 +25,7 @@ namespace mozilla { namespace layers { +class CompositableForwarder; class SharedSurfaceTextureClient; } // namespace layers @@ -133,6 +134,12 @@ public: const gfx::IntSize& size, const SurfaceCaps& caps); + static UniquePtr + CreateFactory(GLContext* gl, + const SurfaceCaps& caps, + const RefPtr& forwarder, + const layers::TextureFlags& flags); + protected: GLContext* const mGL; // Owns us. public: diff --git a/gfx/gl/SharedSurface.cpp b/gfx/gl/SharedSurface.cpp index 634cc794a731..5631be1772e3 100644 --- a/gfx/gl/SharedSurface.cpp +++ b/gfx/gl/SharedSurface.cpp @@ -311,6 +311,7 @@ SurfaceFactory::SurfaceFactory(SharedSurfaceType type, GLContext* gl, , mAllocator(allocator) , mFlags(flags) , mFormats(gl->ChooseGLFormats(caps)) + , mMutex("SurfaceFactor::mMutex") { ChooseBufferBits(mCaps, &mDrawCaps, &mReadCaps); } @@ -368,6 +369,7 @@ SurfaceFactory::StartRecycling(layers::SharedSurfaceTextureClient* tc) void SurfaceFactory::StopRecycling(layers::SharedSurfaceTextureClient* tc) { + MutexAutoLock autoLock(mMutex); // Must clear before releasing ref. tc->ClearRecycleCallback(); @@ -379,11 +381,8 @@ SurfaceFactory::StopRecycling(layers::SharedSurfaceTextureClient* tc) /*static*/ void SurfaceFactory::RecycleCallback(layers::TextureClient* rawTC, void* rawFactory) { - MOZ_ASSERT(NS_IsMainThread()); - RefPtr tc; tc = static_cast(rawTC); - SurfaceFactory* factory = static_cast(rawFactory); if (tc->mSurf->mCanRecycle) { @@ -399,6 +398,7 @@ bool SurfaceFactory::Recycle(layers::SharedSurfaceTextureClient* texClient) { MOZ_ASSERT(texClient); + MutexAutoLock autoLock(mMutex); if (mRecycleFreePool.size() >= 2) { return false; diff --git a/gfx/gl/SharedSurface.h b/gfx/gl/SharedSurface.h index 8c25ac7063d1..217cac05b23d 100644 --- a/gfx/gl/SharedSurface.h +++ b/gfx/gl/SharedSurface.h @@ -24,6 +24,7 @@ #include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" #include "mozilla/gfx/Point.h" +#include "mozilla/Mutex.h" #include "mozilla/UniquePtr.h" #include "mozilla/WeakPtr.h" #include "ScopedGLHelpers.h" @@ -298,6 +299,7 @@ public: const RefPtr mAllocator; const layers::TextureFlags mFlags; const GLFormats mFormats; + Mutex mMutex; protected: SurfaceCaps mDrawCaps; SurfaceCaps mReadCaps; diff --git a/gfx/layers/AsyncCanvasRenderer.cpp b/gfx/layers/AsyncCanvasRenderer.cpp new file mode 100644 index 000000000000..951188b75418 --- /dev/null +++ b/gfx/layers/AsyncCanvasRenderer.cpp @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AsyncCanvasRenderer.h" + +#include "gfxUtils.h" +#include "GLContext.h" +#include "mozilla/dom/HTMLCanvasElement.h" +#include "mozilla/layers/CanvasClient.h" +#include "nsIRunnable.h" +#include "nsThreadUtils.h" + +namespace mozilla { +namespace layers { + +AsyncCanvasRenderer::AsyncCanvasRenderer() + : mWidth(0) + , mHeight(0) + , mCanvasClientAsyncID(0) + , mCanvasClient(nullptr) +{ + MOZ_COUNT_CTOR(AsyncCanvasRenderer); +} + +AsyncCanvasRenderer::~AsyncCanvasRenderer() +{ + MOZ_COUNT_DTOR(AsyncCanvasRenderer); +} + +void +AsyncCanvasRenderer::NotifyElementAboutAttributesChanged() +{ + class Runnable final : public nsRunnable + { + public: + Runnable(AsyncCanvasRenderer* aRenderer) + : mRenderer(aRenderer) + {} + + NS_IMETHOD Run() + { + if (mRenderer) { + dom::HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(mRenderer); + } + + return NS_OK; + } + + void Revoke() + { + mRenderer = nullptr; + } + + private: + nsRefPtr mRenderer; + }; + + nsRefPtr runnable = new Runnable(this); + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to dispatch a runnable to the main-thread."); + } +} + +void +AsyncCanvasRenderer::SetCanvasClient(CanvasClient* aClient) +{ + mCanvasClient = aClient; + if (aClient) { + mCanvasClientAsyncID = aClient->GetAsyncID(); + } else { + mCanvasClientAsyncID = 0; + } +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/AsyncCanvasRenderer.h b/gfx/layers/AsyncCanvasRenderer.h new file mode 100644 index 000000000000..049443ea84b9 --- /dev/null +++ b/gfx/layers/AsyncCanvasRenderer.h @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_ +#define MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_ + +#include "mozilla/gfx/Point.h" // for IntSize +#include "mozilla/RefPtr.h" // for nsAutoPtr, nsRefPtr, etc + +class nsICanvasRenderingContextInternal; + +namespace mozilla { + +namespace gl { +class GLContext; +} + +namespace dom { +class HTMLCanvasElement; +} + +namespace layers { + +class CanvasClient; + +/** + * Since HTMLCanvasElement and OffscreenCanvas are not thread-safe, we create + * AsyncCanvasRenderer which is thread-safe wrapper object for communicating + * among main, worker and ImageBridgeChild threads. + * + * Each HTMLCanvasElement object is responsible for creating + * AsyncCanvasRenderer object. Once Canvas is transfered to worker, + * OffscreenCanvas will keep reference pointer of this object. + * This object will pass to ImageBridgeChild for submitting frames to + * Compositor. + */ +class AsyncCanvasRenderer final +{ + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncCanvasRenderer) + +public: + AsyncCanvasRenderer(); + + void NotifyElementAboutAttributesChanged(); + + void SetCanvasClient(CanvasClient* aClient); + + void SetWidth(uint32_t aWidth) + { + mWidth = aWidth; + } + + void SetHeight(uint32_t aHeight) + { + mHeight = aHeight; + } + + gfx::IntSize GetSize() const + { + return gfx::IntSize(mWidth, mHeight); + } + + uint64_t GetCanvasClientAsyncID() const + { + return mCanvasClientAsyncID; + } + + CanvasClient* GetCanvasClient() const + { + return mCanvasClient; + } + + // The lifetime is controllered by HTMLCanvasElement. + dom::HTMLCanvasElement* mHTMLCanvasElement; + + nsICanvasRenderingContextInternal* mContext; + + // We need to keep a reference to the context around here, otherwise the + // canvas' surface texture destructor will deref and destroy it too early + RefPtr mGLContext; + +private: + + virtual ~AsyncCanvasRenderer(); + + uint32_t mWidth; + uint32_t mHeight; + uint64_t mCanvasClientAsyncID; + + // The lifetime of this pointer is controlled by OffscreenCanvas + CanvasClient* mCanvasClient; +}; + +} // namespace layers +} // namespace mozilla + +#endif // MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_ diff --git a/gfx/layers/CopyableCanvasLayer.cpp b/gfx/layers/CopyableCanvasLayer.cpp index be171b4bcb23..22acc69e26f4 100644 --- a/gfx/layers/CopyableCanvasLayer.cpp +++ b/gfx/layers/CopyableCanvasLayer.cpp @@ -80,6 +80,10 @@ CopyableCanvasLayer::IsDataValid(const Data& aData) void CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) { + if (!mBufferProvider && !mGLContext) { + return; + } + if (mBufferProvider) { mSurface = mBufferProvider->GetSnapshot(); } @@ -99,8 +103,6 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) return; } - MOZ_ASSERT(mGLContext); - SharedSurface* frontbuffer = nullptr; if (mGLFrontbuffer) { frontbuffer = mGLFrontbuffer.get(); diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index a815d5c114e6..f20214175186 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -25,6 +25,7 @@ #include "mozilla/gfx/2D.h" // for DrawTarget #include "mozilla/gfx/BaseSize.h" // for BaseSize #include "mozilla/gfx/Matrix.h" // for Matrix4x4 +#include "mozilla/layers/AsyncCanvasRenderer.h" #include "mozilla/layers/Compositor.h" // for Compositor #include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite @@ -2104,6 +2105,25 @@ ColorLayer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent) layer->set_color(mColor.ToABGR()); } +CanvasLayer::CanvasLayer(LayerManager* aManager, void* aImplData) + : Layer(aManager, aImplData) + , mPreTransCallback(nullptr) + , mPreTransCallbackData(nullptr) + , mPostTransCallback(nullptr) + , mPostTransCallbackData(nullptr) + , mFilter(GraphicsFilter::FILTER_GOOD) + , mDirty(false) +{} + +CanvasLayer::~CanvasLayer() +{} + +void +CanvasLayer::SetAsyncRenderer(AsyncCanvasRenderer *aAsyncRenderer) +{ + mAsyncRenderer = aAsyncRenderer; +} + void CanvasLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix) { diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 88238216f065..6d7c0b507523 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -74,6 +74,7 @@ namespace layers { class Animation; class AnimationData; +class AsyncCanvasRenderer; class AsyncPanZoomController; class ClientLayerManager; class Layer; @@ -2392,16 +2393,16 @@ public: ComputeEffectiveTransformForMaskLayers(aTransformToSurface); } + bool GetIsAsyncRenderer() const + { + return !!mAsyncRenderer; + } + + void SetAsyncRenderer(AsyncCanvasRenderer *aAsyncRenderer); + protected: - CanvasLayer(LayerManager* aManager, void* aImplData) - : Layer(aManager, aImplData) - , mPreTransCallback(nullptr) - , mPreTransCallbackData(nullptr) - , mPostTransCallback(nullptr) - , mPostTransCallbackData(nullptr) - , mFilter(GraphicsFilter::FILTER_GOOD) - , mDirty(false) - {} + CanvasLayer(LayerManager* aManager, void* aImplData); + virtual ~CanvasLayer(); virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override; @@ -2423,6 +2424,7 @@ protected: DidTransactionCallback mPostTransCallback; void* mPostTransCallbackData; GraphicsFilter mFilter; + nsRefPtr mAsyncRenderer; private: /** diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index cd2222c60236..b6f0b5dabebb 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -13,6 +13,7 @@ #include "gfxPlatform.h" // for gfxPlatform #include "GLReadTexImageHelper.h" #include "mozilla/gfx/BaseSize.h" // for BaseSize +#include "mozilla/layers/AsyncCanvasRenderer.h" #include "mozilla/layers/CompositableForwarder.h" #include "mozilla/layers/CompositorChild.h" // for CompositorChild #include "mozilla/layers/GrallocTextureClient.h" @@ -38,14 +39,32 @@ CanvasClient::CreateCanvasClient(CanvasClientType aType, switch (aType) { case CanvasClientTypeShSurf: return MakeAndAddRef(aForwarder, aFlags); - break; - + case CanvasClientAsync: + return MakeAndAddRef(aForwarder, aFlags); default: return MakeAndAddRef(aForwarder, aFlags); break; } } +void +CanvasClientBridge::UpdateAsync(AsyncCanvasRenderer* aRenderer) +{ + if (!GetForwarder() || !mLayer || !aRenderer || + !aRenderer->GetCanvasClient()) { + return; + } + + uint64_t asyncID = aRenderer->GetCanvasClientAsyncID(); + if (asyncID == 0 || mAsyncID == asyncID) { + return; + } + + static_cast(GetForwarder()) + ->AttachAsyncCompositable(asyncID, mLayer); + mAsyncID = asyncID; +} + void CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) { @@ -321,13 +340,38 @@ CloneSurface(gl::SharedSurface* src, gl::SurfaceFactory* factory) void CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) { - auto gl = aLayer->mGLContext; + Renderer renderer; + renderer.construct(aLayer); + UpdateRenderer(aSize, renderer); +} + +void +CanvasClientSharedSurface::UpdateAsync(AsyncCanvasRenderer* aRenderer) +{ + Renderer renderer; + renderer.construct(aRenderer); + UpdateRenderer(aRenderer->GetSize(), renderer); +} + +void +CanvasClientSharedSurface::UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer) +{ + GLContext* gl = nullptr; + ClientCanvasLayer* layer = nullptr; + AsyncCanvasRenderer* asyncRenderer = nullptr; + if (aRenderer.constructed()) { + layer = aRenderer.ref(); + gl = layer->mGLContext; + } else { + asyncRenderer = aRenderer.ref(); + gl = asyncRenderer->mGLContext; + } gl->MakeCurrent(); RefPtr newFront; - if (aLayer->mGLFrontbuffer) { - mShSurfClient = CloneSurface(aLayer->mGLFrontbuffer.get(), aLayer->mFactory.get()); + if (layer && layer->mGLFrontbuffer) { + mShSurfClient = CloneSurface(layer->mGLFrontbuffer.get(), layer->mFactory.get()); if (!mShSurfClient) { gfxCriticalError() << "Invalid canvas front buffer"; return; @@ -351,11 +395,18 @@ CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) bool needsReadback = (surf->mType == SharedSurfaceType::Basic); if (needsReadback) { - TextureFlags flags = aLayer->Flags() | - TextureFlags::IMMUTABLE; + TextureFlags flags = TextureFlags::IMMUTABLE; + + CompositableForwarder* shadowForwarder = nullptr; + if (layer) { + flags |= layer->Flags(); + shadowForwarder = layer->ClientManager()->AsShadowForwarder(); + } else { + MOZ_ASSERT(asyncRenderer); + flags |= mTextureFlags; + shadowForwarder = GetForwarder(); + } - auto manager = aLayer->ClientManager(); - auto shadowForwarder = manager->AsShadowForwarder(); auto layersBackend = shadowForwarder->GetCompositorBackendType(); mReadbackClient = TexClientFromReadback(surf, forwarder, flags, layersBackend); @@ -371,6 +422,14 @@ CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) return; } + mNewFront = newFront; +} + +void +CanvasClientSharedSurface::Updated() +{ + auto forwarder = GetForwarder(); + #ifndef MOZ_WIDGET_GONK if (mFront) { if (mFront->GetFlags() & TextureFlags::RECYCLE) { @@ -385,12 +444,13 @@ CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) // - Call RemoveTexture() after newFront's UseTextures() call. // It could improve performance of Host side's EGL handling on gonk AutoRemoveTexture autoRemove(this); - if (mFront && mFront != newFront) { + if (mFront && mFront != mNewFront) { autoRemove.mTexture = mFront; } #endif - mFront = newFront; + mFront = mNewFront; + mNewFront = nullptr; // Add the new TexClient. MOZ_ALWAYS_TRUE( AddTextureClient(mFront) ); @@ -406,6 +466,7 @@ void CanvasClientSharedSurface::ClearSurfaces() { mFront = nullptr; + mNewFront = nullptr; mShSurfClient = nullptr; mReadbackClient = nullptr; } diff --git a/gfx/layers/client/CanvasClient.h b/gfx/layers/client/CanvasClient.h index 5bdeb7f3f2be..539ff85cbb67 100644 --- a/gfx/layers/client/CanvasClient.h +++ b/gfx/layers/client/CanvasClient.h @@ -13,6 +13,11 @@ #include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor #include "mozilla/layers/TextureClient.h" // for TextureClient, etc + +// Fix X11 header brain damage that conflicts with MaybeOneOf::None +#undef None +#include "mozilla/MaybeOneOf.h" + #include "mozilla/mozalloc.h" // for operator delete #include "mozilla/gfx/Point.h" // for IntSize @@ -21,8 +26,10 @@ namespace mozilla { namespace layers { +class AsyncCanvasRenderer; class ClientCanvasLayer; class CompositableForwarder; +class ShadowableLayer; class SharedSurfaceTextureClient; /** @@ -31,6 +38,8 @@ class SharedSurfaceTextureClient; class CanvasClient : public CompositableClient { public: + typedef MaybeOneOf Renderer; + /** * Creates, configures, and returns a new canvas client. If necessary, a * message will be sent to the compositor to create a corresponding image @@ -40,6 +49,7 @@ public: CanvasClientSurface, CanvasClientGLContext, CanvasClientTypeShSurf, + CanvasClientAsync, // webgl on workers }; static already_AddRefed CreateCanvasClient(CanvasClientType aType, CompositableForwarder* aFwd, @@ -57,6 +67,8 @@ public: virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) = 0; + virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) {} + virtual void Updated() { } }; @@ -111,6 +123,7 @@ private: RefPtr mShSurfClient; RefPtr mReadbackClient; RefPtr mFront; + RefPtr mNewFront; void ClearSurfaces(); @@ -130,12 +143,54 @@ public: virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) override; + void UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer); + + virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) override; + + virtual void Updated() override; virtual void OnDetach() override { ClearSurfaces(); } }; +/** + * Used for OMT uploads using the image bridge protocol. + * Actual CanvasClient is on the ImageBridgeChild thread, so we + * only forward its AsyncID here + */ +class CanvasClientBridge final : public CanvasClient +{ +public: + CanvasClientBridge(CompositableForwarder* aLayerForwarder, + TextureFlags aFlags) + : CanvasClient(aLayerForwarder, aFlags) + , mAsyncID(0) + , mLayer(nullptr) + { + } + + TextureInfo GetTextureInfo() const override + { + return TextureInfo(CompositableType::IMAGE); + } + + virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) override + { + } + + virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) override; + + void SetLayer(ShadowableLayer* aLayer) + { + mLayer = aLayer; + } + +protected: + uint64_t mAsyncID; + ShadowableLayer* mLayer; +}; + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/client/ClientCanvasLayer.cpp b/gfx/layers/client/ClientCanvasLayer.cpp index 0e1fcdf6c503..1c9b1bc17bdf 100644 --- a/gfx/layers/client/ClientCanvasLayer.cpp +++ b/gfx/layers/client/ClientCanvasLayer.cpp @@ -11,6 +11,7 @@ #include "SharedSurfaceGL.h" // for SurfaceFactory_GLTexture, etc #include "ClientLayerManager.h" // for ClientLayerManager, etc #include "mozilla/gfx/Point.h" // for IntSize +#include "mozilla/layers/AsyncCanvasRenderer.h" #include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/LayersTypes.h" #include "nsCOMPtr.h" // for already_AddRefed @@ -19,24 +20,6 @@ #include "nsXULAppAPI.h" // for XRE_GetProcessType, etc #include "gfxPrefs.h" // for WebGLForceLayersReadback -#ifdef XP_WIN -#include "SharedSurfaceANGLE.h" // for SurfaceFactory_ANGLEShareHandle -#include "gfxWindowsPlatform.h" -#endif - -#ifdef MOZ_WIDGET_GONK -#include "SharedSurfaceGralloc.h" -#endif - -#ifdef XP_MACOSX -#include "SharedSurfaceIO.h" -#endif - -#ifdef GL_PROVIDER_GLX -#include "GLXLibrary.h" -#include "SharedSurfaceGLX.h" -#endif - using namespace mozilla::gfx; using namespace mozilla::gl; @@ -82,46 +65,7 @@ ClientCanvasLayer::Initialize(const Data& aData) mFlags |= TextureFlags::NON_PREMULTIPLIED; } - UniquePtr factory; - - if (!gfxPrefs::WebGLForceLayersReadback()) { - switch (forwarder->GetCompositorBackendType()) { - case mozilla::layers::LayersBackend::LAYERS_OPENGL: { -#if defined(XP_MACOSX) - factory = SurfaceFactory_IOSurface::Create(mGLContext, caps, forwarder, mFlags); -#elif defined(MOZ_WIDGET_GONK) - factory = MakeUnique(mGLContext, caps, forwarder, mFlags); -#elif defined(GL_PROVIDER_GLX) - if (sGLXLibrary.UseSurfaceSharing()) - factory = SurfaceFactory_GLXDrawable::Create(mGLContext, caps, forwarder, mFlags); -#else - if (mGLContext->GetContextType() == GLContextType::EGL) { - if (XRE_IsParentProcess()) { - factory = SurfaceFactory_EGLImage::Create(mGLContext, caps, forwarder, - mFlags); - } - } -#endif - break; - } - case mozilla::layers::LayersBackend::LAYERS_D3D11: { -#ifdef XP_WIN - // Enable surface sharing only if ANGLE and compositing devices - // are both WARP or both not WARP - if (mGLContext->IsANGLE() && - (mGLContext->IsWARP() == gfxWindowsPlatform::GetPlatform()->IsWARP()) && - gfxWindowsPlatform::GetPlatform()->CompositorD3D11TextureSharingWorks()) - { - factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, caps, forwarder, - mFlags); - } -#endif - break; - } - default: - break; - } - } + UniquePtr factory = GLScreenBuffer::CreateFactory(mGLContext, caps, forwarder, mFlags); if (mGLFrontbuffer) { // We're using a source other than the one in the default screen. @@ -145,11 +89,6 @@ ClientCanvasLayer::RenderLayer() RenderMaskLayers(this); - if (!IsDirty()) { - return; - } - Painted(); - if (!mCanvasClient) { TextureFlags flags = TextureFlags::IMMEDIATE_UPLOAD; if (mOriginPos == gl::OriginPos::BottomLeft) { @@ -172,11 +111,24 @@ ClientCanvasLayer::RenderLayer() return; } if (HasShadow()) { - mCanvasClient->Connect(); - ClientManager()->AsShadowForwarder()->Attach(mCanvasClient, this); + if (mAsyncRenderer) { + static_cast(mCanvasClient.get())->SetLayer(this); + } else { + mCanvasClient->Connect(); + ClientManager()->AsShadowForwarder()->Attach(mCanvasClient, this); + } } } + if (mCanvasClient && mAsyncRenderer) { + mCanvasClient->UpdateAsync(mAsyncRenderer); + } + + if (!IsDirty()) { + return; + } + Painted(); + FirePreTransactionCallback(); mCanvasClient->Update(gfx::IntSize(mBounds.width, mBounds.height), this); @@ -189,6 +141,10 @@ ClientCanvasLayer::RenderLayer() CanvasClient::CanvasClientType ClientCanvasLayer::GetCanvasClientType() { + if (mAsyncRenderer) { + return CanvasClient::CanvasClientAsync; + } + if (mGLContext) { return CanvasClient::CanvasClientTypeShSurf; } diff --git a/gfx/layers/client/ClientCanvasLayer.h b/gfx/layers/client/ClientCanvasLayer.h index 9167a1d2b3b1..d2308197b17e 100644 --- a/gfx/layers/client/ClientCanvasLayer.h +++ b/gfx/layers/client/ClientCanvasLayer.h @@ -97,7 +97,6 @@ protected: TextureFlags mFlags; - friend class DeprecatedCanvasClient2D; friend class CanvasClient2D; friend class CanvasClientSharedSurface; }; diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index c97f6727b743..3e04121ea471 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -169,6 +169,7 @@ TextureChild::ActorDestroy(ActorDestroyReason why) { if (mTextureClient) { mTextureClient->mActor = nullptr; + mTextureClient->mAllocator = nullptr; } mWaitForRecycle = nullptr; mKeep = nullptr; diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index 06cb4ca773dc..231b3ada0b1a 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -21,6 +21,7 @@ #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc #include "mozilla/ipc/Transport.h" // for Transport #include "mozilla/gfx/Point.h" // for IntSize +#include "mozilla/layers/AsyncCanvasRenderer.h" #include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager #include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild #include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc @@ -231,6 +232,19 @@ static void CreateImageClientSync(RefPtr* result, barrier->NotifyAll(); } +// dispatched function +static void CreateCanvasClientSync(ReentrantMonitor* aBarrier, + CanvasClient::CanvasClientType aType, + TextureFlags aFlags, + RefPtr* const outResult, + bool* aDone) +{ + ReentrantMonitorAutoEnter autoMon(*aBarrier); + *outResult = sImageBridgeChildSingleton->CreateCanvasClientNow(aType, aFlags); + *aDone = true; + aBarrier->NotifyAll(); +} + static void ConnectImageBridge(ImageBridgeChild * child, ImageBridgeParent * parent) { MessageLoop *parentMsgLoop = parent->GetMessageLoop(); @@ -269,9 +283,14 @@ ImageBridgeChild::Connect(CompositableClient* aCompositable, MOZ_ASSERT(aCompositable); MOZ_ASSERT(!mShuttingDown); uint64_t id = 0; + + PImageContainerChild* imageContainerChild = nullptr; + if (aImageContainer) + imageContainerChild = aImageContainer->GetPImageContainerChild(); + PCompositableChild* child = SendPCompositableConstructor(aCompositable->GetTextureInfo(), - aImageContainer->GetPImageContainerChild(), &id); + imageContainerChild, &id); MOZ_ASSERT(child); aCompositable->InitIPDLActor(child, id); } @@ -374,6 +393,35 @@ void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient, NewRunnableFunction(&ReleaseImageClientNow, aClient, aChild)); } +static void ReleaseCanvasClientNow(CanvasClient* aClient) +{ + MOZ_ASSERT(InImageBridgeChildThread()); + aClient->Release(); +} + +// static +void ImageBridgeChild::DispatchReleaseCanvasClient(CanvasClient* aClient) +{ + if (!aClient) { + return; + } + + if (!IsCreated()) { + // CompositableClient::Release should normally happen in the ImageBridgeChild + // thread because it usually generate some IPDL messages. + // However, if we take this branch it means that the ImageBridgeChild + // has already shut down, along with the CompositableChild, which means no + // message will be sent and it is safe to run this code from any thread. + MOZ_ASSERT(aClient->GetIPDLActor() == nullptr); + aClient->Release(); + return; + } + + sImageBridgeChildSingleton->GetMessageLoop()->PostTask( + FROM_HERE, + NewRunnableFunction(&ReleaseCanvasClientNow, aClient)); +} + static void ReleaseTextureClientNow(TextureClient* aClient) { MOZ_ASSERT(InImageBridgeChildThread()); @@ -412,7 +460,7 @@ static void UpdateImageClientNow(ImageClient* aClient, ImageContainer* aContaine sImageBridgeChildSingleton->EndTransaction(); } -//static +// static void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient, ImageContainer* aContainer) { @@ -432,6 +480,51 @@ void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient, nsRefPtr >(&UpdateImageClientNow, aClient, aContainer)); } +static void UpdateAsyncCanvasRendererSync(AsyncCanvasRenderer* aWrapper, + ReentrantMonitor* aBarrier, + bool* const outDone) +{ + ImageBridgeChild::UpdateAsyncCanvasRendererNow(aWrapper); + + ReentrantMonitorAutoEnter autoMon(*aBarrier); + *outDone = true; + aBarrier->NotifyAll(); +} + +// static +void ImageBridgeChild::UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aWrapper) +{ + aWrapper->GetCanvasClient()->UpdateAsync(aWrapper); + + if (InImageBridgeChildThread()) { + UpdateAsyncCanvasRendererNow(aWrapper); + return; + } + + ReentrantMonitor barrier("UpdateAsyncCanvasRenderer Lock"); + ReentrantMonitorAutoEnter autoMon(barrier); + bool done = false; + + sImageBridgeChildSingleton->GetMessageLoop()->PostTask( + FROM_HERE, + NewRunnableFunction(&UpdateAsyncCanvasRendererSync, aWrapper, &barrier, &done)); + + // should stop the thread until the CanvasClient has been created on + // the other thread + while (!done) { + barrier.Wait(); + } +} + +// static +void ImageBridgeChild::UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aWrapper) +{ + MOZ_ASSERT(aWrapper); + sImageBridgeChildSingleton->BeginTransaction(); + aWrapper->GetCanvasClient()->Updated(); + sImageBridgeChildSingleton->EndTransaction(); +} + static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer, AsyncTransactionWaiter* aWaiter) { @@ -449,7 +542,7 @@ static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer, aWaiter->DecrementWaitCount(); } -//static +// static void ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer) { @@ -705,6 +798,42 @@ ImageBridgeChild::CreateImageClientNow(CompositableType aType, return client.forget(); } +already_AddRefed +ImageBridgeChild::CreateCanvasClient(CanvasClient::CanvasClientType aType, + TextureFlags aFlag) +{ + if (InImageBridgeChildThread()) { + return CreateCanvasClientNow(aType, aFlag); + } + ReentrantMonitor barrier("CreateCanvasClient Lock"); + ReentrantMonitorAutoEnter autoMon(barrier); + bool done = false; + + RefPtr result = nullptr; + GetMessageLoop()->PostTask(FROM_HERE, + NewRunnableFunction(&CreateCanvasClientSync, + &barrier, aType, aFlag, &result, &done)); + // should stop the thread until the CanvasClient has been created on the + // other thread + while (!done) { + barrier.Wait(); + } + return result.forget(); +} + +already_AddRefed +ImageBridgeChild::CreateCanvasClientNow(CanvasClient::CanvasClientType aType, + TextureFlags aFlag) +{ + RefPtr client + = CanvasClient::CreateCanvasClient(aType, this, aFlag); + MOZ_ASSERT(client, "failed to create CanvasClient"); + if (client) { + client->Connect(); + } + return client.forget(); +} + bool ImageBridgeChild::AllocUnsafeShmem(size_t aSize, ipc::SharedMemory::SharedMemoryType aType, diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h index 8d4f6c087b01..c3b37aa19591 100644 --- a/gfx/layers/ipc/ImageBridgeChild.h +++ b/gfx/layers/ipc/ImageBridgeChild.h @@ -12,6 +12,7 @@ #include "mozilla/RefPtr.h" // for already_AddRefed #include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc #include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTrackerHolder +#include "mozilla/layers/CanvasClient.h" #include "mozilla/layers/CompositableForwarder.h" #include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/PImageBridgeChild.h" @@ -32,6 +33,7 @@ class Shmem; namespace layers { +class AsyncCanvasRenderer; class AsyncTransactionTracker; class ImageClient; class ImageContainer; @@ -210,12 +212,20 @@ public: ImageContainer* aImageContainer); already_AddRefed CreateImageClientNow(CompositableType aType, ImageContainer* aImageContainer); + already_AddRefed CreateCanvasClient(CanvasClient::CanvasClientType aType, + TextureFlags aFlag); + already_AddRefed CreateCanvasClientNow(CanvasClient::CanvasClientType aType, + TextureFlags aFlag); static void DispatchReleaseImageClient(ImageClient* aClient, PImageContainerChild* aChild = nullptr); + static void DispatchReleaseCanvasClient(CanvasClient* aClient); static void DispatchReleaseTextureClient(TextureClient* aClient); static void DispatchImageClientUpdate(ImageClient* aClient, ImageContainer* aContainer); + static void UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aClient); + static void UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aClient); + /** * Flush all Images sent to CompositableHost. */ diff --git a/gfx/layers/ipc/PImageBridge.ipdl b/gfx/layers/ipc/PImageBridge.ipdl index 99a4a704407f..9f32993c6565 100644 --- a/gfx/layers/ipc/PImageBridge.ipdl +++ b/gfx/layers/ipc/PImageBridge.ipdl @@ -58,7 +58,7 @@ parent: sync Stop(); sync PCompositable(TextureInfo aInfo, - PImageContainer aImageContainer) returns (uint64_t id); + nullable PImageContainer aImageContainer) returns (uint64_t id); async PTexture(SurfaceDescriptor aSharedData, TextureFlags aTextureFlags); async PMediaSystemResourceManager(); async PImageContainer(); diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 5ce9a5863b88..37fcf8d5f216 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -107,6 +107,7 @@ EXPORTS.mozilla.layers += [ 'apz/util/ChromeProcessController.h', 'apz/util/DoubleTapToZoom.h', 'apz/util/InputAPZContext.h', + 'AsyncCanvasRenderer.h', 'AtomicRefCountedWithFinalize.h', 'AxisPhysicsModel.h', 'AxisPhysicsMSDModel.h', @@ -252,6 +253,7 @@ UNIFIED_SOURCES += [ 'apz/util/ChromeProcessController.cpp', 'apz/util/DoubleTapToZoom.cpp', 'apz/util/InputAPZContext.cpp', + 'AsyncCanvasRenderer.cpp', 'AxisPhysicsModel.cpp', 'AxisPhysicsMSDModel.cpp', 'basic/BasicCanvasLayer.cpp', From 1d4157900ab561c68beb73ce46a77ff4f2752e59 Mon Sep 17 00:00:00 2001 From: Morris Tseng Date: Tue, 29 Sep 2015 11:51:24 +0100 Subject: [PATCH 027/104] Bug 709490 - Part 2: Introduce OffscreenCanvas and let WebGL context work on workers., r=ehsan, r=jgilbert, r=nical --- dom/canvas/CanvasRenderingContextHelper.cpp | 264 +++++++++ dom/canvas/CanvasRenderingContextHelper.h | 71 +++ dom/canvas/CanvasUtils.cpp | 35 ++ dom/canvas/CanvasUtils.h | 1 + dom/canvas/OffscreenCanvas.cpp | 210 +++++++ dom/canvas/OffscreenCanvas.h | 166 ++++++ dom/canvas/WebGLContext.cpp | 342 +++++------ dom/canvas/WebGLContext.h | 43 +- dom/canvas/WebGLContextExtensions.cpp | 14 +- dom/canvas/WebGLContextGL.cpp | 5 +- dom/canvas/WebGLContextLossHandler.cpp | 119 ++++ dom/canvas/WebGLContextLossHandler.h | 5 +- dom/canvas/WebGLContextReporter.cpp | 2 - dom/canvas/WebGLContextValidate.cpp | 19 +- dom/canvas/WebGLMemoryTracker.cpp | 2 - dom/canvas/WebGLShaderValidator.cpp | 3 +- dom/canvas/moz.build | 5 + .../nsICanvasRenderingContextInternal.h | 15 +- dom/html/HTMLCanvasElement.cpp | 551 ++++++++++-------- dom/html/HTMLCanvasElement.h | 81 ++- dom/webidl/HTMLCanvasElement.webidl | 7 + dom/webidl/OffscreenCanvas.webidl | 28 + dom/webidl/WebGLRenderingContext.webidl | 30 +- dom/webidl/moz.build | 1 + gfx/gl/GLLibraryEGL.cpp | 5 +- gfx/layers/AsyncCanvasRenderer.h | 3 + gfx/src/gfxCrashReporterUtils.cpp | 19 +- gfx/thebes/gfxPrefs.h | 27 +- gfx/thebes/gfxUtils.cpp | 59 ++ gfx/thebes/gfxUtils.h | 5 + gfx/thebes/moz.build | 1 + modules/libpref/init/all.js | 2 + 32 files changed, 1614 insertions(+), 526 deletions(-) create mode 100644 dom/canvas/CanvasRenderingContextHelper.cpp create mode 100644 dom/canvas/CanvasRenderingContextHelper.h create mode 100644 dom/canvas/OffscreenCanvas.cpp create mode 100644 dom/canvas/OffscreenCanvas.h create mode 100644 dom/webidl/OffscreenCanvas.webidl diff --git a/dom/canvas/CanvasRenderingContextHelper.cpp b/dom/canvas/CanvasRenderingContextHelper.cpp new file mode 100644 index 000000000000..0c498b7d525b --- /dev/null +++ b/dom/canvas/CanvasRenderingContextHelper.cpp @@ -0,0 +1,264 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CanvasRenderingContextHelper.h" +#include "ImageEncoder.h" +#include "mozilla/dom/CanvasRenderingContext2D.h" +#include "mozilla/Telemetry.h" +#include "nsContentUtils.h" +#include "nsDOMJSUtils.h" +#include "nsIScriptContext.h" +#include "nsJSUtils.h" +#include "WebGL1Context.h" +#include "WebGL2Context.h" + +namespace mozilla { +namespace dom { + +void +CanvasRenderingContextHelper::ToBlob(JSContext* aCx, + nsIGlobalObject* aGlobal, + FileCallback& aCallback, + const nsAString& aType, + JS::Handle aParams, + ErrorResult& aRv) +{ + nsAutoString type; + nsContentUtils::ASCIIToLower(aType, type); + + nsAutoString params; + bool usingCustomParseOptions; + aRv = ParseParams(aCx, type, aParams, params, &usingCustomParseOptions); + if (aRv.Failed()) { + return; + } + +#ifdef DEBUG + if (mCurrentContext) { + // We disallow canvases of width or height zero, and set them to 1, so + // we will have a discrepancy with the sizes of the canvas and the context. + // That discrepancy is OK, the rest are not. + nsIntSize elementSize = GetWidthHeight(); + MOZ_ASSERT(elementSize.width == mCurrentContext->GetWidth() || + (elementSize.width == 0 && mCurrentContext->GetWidth() == 1)); + MOZ_ASSERT(elementSize.height == mCurrentContext->GetHeight() || + (elementSize.height == 0 && mCurrentContext->GetHeight() == 1)); + } +#endif + + uint8_t* imageBuffer = nullptr; + int32_t format = 0; + if (mCurrentContext) { + mCurrentContext->GetImageBuffer(&imageBuffer, &format); + } + + // Encoder callback when encoding is complete. + class EncodeCallback : public EncodeCompleteCallback + { + public: + EncodeCallback(nsIGlobalObject* aGlobal, FileCallback* aCallback) + : mGlobal(aGlobal) + , mFileCallback(aCallback) {} + + // This is called on main thread. + nsresult ReceiveBlob(already_AddRefed aBlob) + { + nsRefPtr blob = aBlob; + + ErrorResult rv; + uint64_t size = blob->GetSize(rv); + if (rv.Failed()) { + rv.SuppressException(); + } else { + AutoJSAPI jsapi; + if (jsapi.Init(mGlobal)) { + JS_updateMallocCounter(jsapi.cx(), size); + } + } + + nsRefPtr newBlob = Blob::Create(mGlobal, blob->Impl()); + + mFileCallback->Call(*newBlob, rv); + + mGlobal = nullptr; + mFileCallback = nullptr; + + return rv.StealNSResult(); + } + + nsCOMPtr mGlobal; + nsRefPtr mFileCallback; + }; + + nsRefPtr callback = + new EncodeCallback(aGlobal, &aCallback); + + aRv = ImageEncoder::ExtractDataAsync(type, + params, + usingCustomParseOptions, + imageBuffer, + format, + GetWidthHeight(), + callback); +} + +already_AddRefed +CanvasRenderingContextHelper::CreateContext(CanvasContextType aContextType) +{ + MOZ_ASSERT(aContextType != CanvasContextType::NoContext); + nsRefPtr ret; + + switch (aContextType) { + case CanvasContextType::NoContext: + break; + + case CanvasContextType::Canvas2D: + Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1); + ret = new CanvasRenderingContext2D(); + break; + + case CanvasContextType::WebGL1: + Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1); + + ret = WebGL1Context::Create(); + if (!ret) + return nullptr; + + break; + + case CanvasContextType::WebGL2: + Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1); + + ret = WebGL2Context::Create(); + if (!ret) + return nullptr; + + break; + } + MOZ_ASSERT(ret); + + return ret.forget(); +} + +already_AddRefed +CanvasRenderingContextHelper::GetContext(JSContext* aCx, + const nsAString& aContextId, + JS::Handle aContextOptions, + ErrorResult& aRv) +{ + CanvasContextType contextType; + if (!CanvasUtils::GetCanvasContextType(aContextId, &contextType)) + return nullptr; + + if (!mCurrentContext) { + // This canvas doesn't have a context yet. + nsRefPtr context; + context = CreateContext(contextType); + if (!context) { + return nullptr; + } + + // Ensure that the context participates in CC. Note that returning a + // CC participant from QI doesn't addref. + nsXPCOMCycleCollectionParticipant* cp = nullptr; + CallQueryInterface(context, &cp); + if (!cp) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + mCurrentContext = context.forget(); + mCurrentContextType = contextType; + + aRv = UpdateContext(aCx, aContextOptions); + if (aRv.Failed()) { + aRv = NS_OK; // See bug 645792 + return nullptr; + } + } else { + // We already have a context of some type. + if (contextType != mCurrentContextType) + return nullptr; + } + + nsCOMPtr context = mCurrentContext; + return context.forget(); +} + +nsresult +CanvasRenderingContextHelper::UpdateContext(JSContext* aCx, + JS::Handle aNewContextOptions) +{ + if (!mCurrentContext) + return NS_OK; + + nsIntSize sz = GetWidthHeight(); + + nsCOMPtr currentContext = mCurrentContext; + + nsresult rv = currentContext->SetIsOpaque(GetOpaqueAttr()); + if (NS_FAILED(rv)) { + mCurrentContext = nullptr; + return rv; + } + + rv = currentContext->SetContextOptions(aCx, aNewContextOptions); + if (NS_FAILED(rv)) { + mCurrentContext = nullptr; + return rv; + } + + rv = currentContext->SetDimensions(sz.width, sz.height); + if (NS_FAILED(rv)) { + mCurrentContext = nullptr; + } + + return rv; +} + +nsresult +CanvasRenderingContextHelper::ParseParams(JSContext* aCx, + const nsAString& aType, + const JS::Value& aEncoderOptions, + nsAString& outParams, + bool* const outUsingCustomParseOptions) +{ + // Quality parameter is only valid for the image/jpeg MIME type + if (aType.EqualsLiteral("image/jpeg")) { + if (aEncoderOptions.isNumber()) { + double quality = aEncoderOptions.toNumber(); + // Quality must be between 0.0 and 1.0, inclusive + if (quality >= 0.0 && quality <= 1.0) { + outParams.AppendLiteral("quality="); + outParams.AppendInt(NS_lround(quality * 100.0)); + } + } + } + + // If we haven't parsed the aParams check for proprietary options. + // The proprietary option -moz-parse-options will take a image lib encoder + // parse options string as is and pass it to the encoder. + *outUsingCustomParseOptions = false; + if (outParams.Length() == 0 && aEncoderOptions.isString()) { + NS_NAMED_LITERAL_STRING(mozParseOptions, "-moz-parse-options:"); + nsAutoJSString paramString; + if (!paramString.init(aCx, aEncoderOptions.toString())) { + return NS_ERROR_FAILURE; + } + if (StringBeginsWith(paramString, mozParseOptions)) { + nsDependentSubstring parseOptions = Substring(paramString, + mozParseOptions.Length(), + paramString.Length() - + mozParseOptions.Length()); + outParams.Append(parseOptions); + *outUsingCustomParseOptions = true; + } + } + + return NS_OK; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/canvas/CanvasRenderingContextHelper.h b/dom/canvas/CanvasRenderingContextHelper.h new file mode 100644 index 000000000000..89cf9e8b3cc8 --- /dev/null +++ b/dom/canvas/CanvasRenderingContextHelper.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_ +#define MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_ + +#include "mozilla/dom/BindingDeclarations.h" +#include "nsSize.h" + +class nsICanvasRenderingContextInternal; +class nsIGlobalObject; + +namespace mozilla { + +class ErrorResult; + +namespace dom { + +class FileCallback; + +enum class CanvasContextType : uint8_t { + NoContext, + Canvas2D, + WebGL1, + WebGL2 +}; + +/** + * Povides common RenderingContext functionality used by both OffscreenCanvas + * and HTMLCanvasElement. + */ +class CanvasRenderingContextHelper +{ +public: + virtual already_AddRefed + GetContext(JSContext* aCx, + const nsAString& aContextId, + JS::Handle aContextOptions, + ErrorResult& aRv); + + virtual bool GetOpaqueAttr() = 0; + +protected: + virtual nsresult UpdateContext(JSContext* aCx, + JS::Handle aNewContextOptions); + + virtual nsresult ParseParams(JSContext* aCx, + const nsAString& aType, + const JS::Value& aEncoderOptions, + nsAString& outParams, + bool* const outCustomParseOptions); + + void ToBlob(JSContext* aCx, nsIGlobalObject* global, FileCallback& aCallback, + const nsAString& aType, JS::Handle aParams, + ErrorResult& aRv); + + virtual already_AddRefed + CreateContext(CanvasContextType aContextType); + + virtual nsIntSize GetWidthHeight() = 0; + + CanvasContextType mCurrentContextType; + nsCOMPtr mCurrentContext; +}; + +} // namespace dom +} // namespace mozilla + +#endif // MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_ diff --git a/dom/canvas/CanvasUtils.cpp b/dom/canvas/CanvasUtils.cpp index 04fec40e8c60..9d258c01f706 100644 --- a/dom/canvas/CanvasUtils.cpp +++ b/dom/canvas/CanvasUtils.cpp @@ -23,12 +23,47 @@ #include "CanvasUtils.h" #include "mozilla/gfx/Matrix.h" +#include "WebGL2Context.h" using namespace mozilla::gfx; namespace mozilla { namespace CanvasUtils { +bool +GetCanvasContextType(const nsAString& str, dom::CanvasContextType* const out_type) +{ + if (str.EqualsLiteral("2d")) { + *out_type = dom::CanvasContextType::Canvas2D; + return true; + } + + if (str.EqualsLiteral("experimental-webgl")) { + *out_type = dom::CanvasContextType::WebGL1; + return true; + } + +#ifdef MOZ_WEBGL_CONFORMANT + if (str.EqualsLiteral("webgl")) { + /* WebGL 1.0, $2.1 "Context Creation": + * If the user agent supports both the webgl and experimental-webgl + * canvas context types, they shall be treated as aliases. + */ + *out_type = dom::CanvasContextType::WebGL1; + return true; + } +#endif + + if (WebGL2Context::IsSupported()) { + if (str.EqualsLiteral("webgl2")) { + *out_type = dom::CanvasContextType::WebGL2; + return true; + } + } + + return false; +} + /** * This security check utility might be called from an source that never taints * others. For example, while painting a CanvasPattern, which is created from an diff --git a/dom/canvas/CanvasUtils.h b/dom/canvas/CanvasUtils.h index 044b847053e9..b1237b69e6ff 100644 --- a/dom/canvas/CanvasUtils.h +++ b/dom/canvas/CanvasUtils.h @@ -21,6 +21,7 @@ class HTMLCanvasElement; namespace CanvasUtils { +bool GetCanvasContextType(const nsAString& str, dom::CanvasContextType* const out_type); // Check that the rectangle [x,y,w,h] is a subrectangle of [0,0,realWidth,realHeight] diff --git a/dom/canvas/OffscreenCanvas.cpp b/dom/canvas/OffscreenCanvas.cpp new file mode 100644 index 000000000000..8489ca9e2803 --- /dev/null +++ b/dom/canvas/OffscreenCanvas.cpp @@ -0,0 +1,210 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "OffscreenCanvas.h" + +#include "mozilla/dom/OffscreenCanvasBinding.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/layers/AsyncCanvasRenderer.h" +#include "mozilla/layers/CanvasClient.h" +#include "mozilla/layers/ImageBridgeChild.h" +#include "mozilla/Telemetry.h" +#include "CanvasRenderingContext2D.h" +#include "CanvasUtils.h" +#include "GLScreenBuffer.h" +#include "WebGL1Context.h" +#include "WebGL2Context.h" + +namespace mozilla { +namespace dom { + +OffscreenCanvasCloneData::OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer, + uint32_t aWidth, uint32_t aHeight, + bool aNeutered) + : mRenderer(aRenderer) + , mWidth(aWidth) + , mHeight(aHeight) + , mNeutered(aNeutered) +{ +} + +OffscreenCanvasCloneData::~OffscreenCanvasCloneData() +{ +} + +OffscreenCanvas::OffscreenCanvas(uint32_t aWidth, + uint32_t aHeight, + layers::AsyncCanvasRenderer* aRenderer) + : mAttrDirty(false) + , mNeutered(false) + , mWidth(aWidth) + , mHeight(aHeight) + , mCanvasClient(nullptr) + , mCanvasRenderer(aRenderer) +{} + +OffscreenCanvas::~OffscreenCanvas() +{ + if (mCanvasRenderer) { + mCanvasRenderer->SetCanvasClient(nullptr); + mCanvasRenderer->mContext = nullptr; + mCanvasRenderer->mActiveThread = nullptr; + } + + if (mCanvasClient) { + ImageBridgeChild::DispatchReleaseCanvasClient(mCanvasClient); + } +} + +OffscreenCanvas* +OffscreenCanvas::GetParentObject() const +{ + return nullptr; +} + +JSObject* +OffscreenCanvas::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) +{ + return OffscreenCanvasBinding::Wrap(aCx, this, aGivenProto); +} + +already_AddRefed +OffscreenCanvas::GetContext(JSContext* aCx, + const nsAString& aContextId, + JS::Handle aContextOptions, + ErrorResult& aRv) +{ + if (mNeutered) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + // We only support WebGL in workers for now + CanvasContextType contextType; + if (!CanvasUtils::GetCanvasContextType(aContextId, &contextType)) { + aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); + return nullptr; + } + + if (!(contextType == CanvasContextType::WebGL1 || + contextType == CanvasContextType::WebGL2)) + { + aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); + return nullptr; + } + + already_AddRefed result = + CanvasRenderingContextHelper::GetContext(aCx, + aContextId, + aContextOptions, + aRv); + + if (mCanvasRenderer && mCurrentContext && ImageBridgeChild::IsCreated()) { + TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT; + + mCanvasClient = ImageBridgeChild::GetSingleton()-> + CreateCanvasClient(CanvasClient::CanvasClientTypeShSurf, flags).take(); + mCanvasRenderer->SetCanvasClient(mCanvasClient); + gl::GLContext* gl = static_cast(mCurrentContext.get())->GL(); + mCanvasRenderer->mContext = mCurrentContext; + mCanvasRenderer->mActiveThread = NS_GetCurrentThread(); + mCanvasRenderer->mGLContext = gl; + + gl::GLScreenBuffer* screen = gl->Screen(); + gl::SurfaceCaps caps = screen->mCaps; + auto forwarder = mCanvasClient->GetForwarder(); + + UniquePtr factory = + gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags); + + if (factory) + screen->Morph(Move(factory)); + } + + return result; +} + +already_AddRefed +OffscreenCanvas::CreateContext(CanvasContextType aContextType) +{ + nsRefPtr ret = + CanvasRenderingContextHelper::CreateContext(aContextType); + + ret->SetOffscreenCanvas(this); + return ret.forget(); +} + +void +OffscreenCanvas::CommitFrameToCompositor() +{ + // The attributes has changed, we have to notify main + // thread to change canvas size. + if (mAttrDirty) { + if (mCanvasRenderer) { + mCanvasRenderer->SetWidth(mWidth); + mCanvasRenderer->SetHeight(mHeight); + mCanvasRenderer->NotifyElementAboutAttributesChanged(); + } + mAttrDirty = false; + } + + if (mCurrentContext) { + static_cast(mCurrentContext.get())->PresentScreenBuffer(); + } + + if (mCanvasRenderer && mCanvasRenderer->mGLContext) { + ImageBridgeChild::GetSingleton()-> + UpdateAsyncCanvasRenderer(mCanvasRenderer); + } +} + +OffscreenCanvasCloneData* +OffscreenCanvas::ToCloneData() +{ + return new OffscreenCanvasCloneData(mCanvasRenderer, mWidth, + mHeight, mNeutered); +} + +/* static */ already_AddRefed +OffscreenCanvas::CreateFromCloneData(OffscreenCanvasCloneData* aData) +{ + MOZ_ASSERT(aData); + nsRefPtr wc = + new OffscreenCanvas(aData->mWidth, aData->mHeight, aData->mRenderer); + if (aData->mNeutered) { + wc->SetNeutered(); + } + return wc.forget(); +} + +/* static */ bool +OffscreenCanvas::PrefEnabled(JSContext* aCx, JSObject* aObj) +{ + return gfxPrefs::OffscreenCanvasEnabled(); +} + +/* static */ bool +OffscreenCanvas::PrefEnabledOnWorkerThread(JSContext* aCx, JSObject* aObj) +{ + if (NS_IsMainThread()) { + return true; + } + + return PrefEnabled(aCx, aObj); +} + +NS_IMPL_CYCLE_COLLECTION_INHERITED(OffscreenCanvas, DOMEventTargetHelper, mCurrentContext) + +NS_IMPL_ADDREF_INHERITED(OffscreenCanvas, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(OffscreenCanvas, DOMEventTargetHelper) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(OffscreenCanvas) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +} // namespace dom +} // namespace mozilla diff --git a/dom/canvas/OffscreenCanvas.h b/dom/canvas/OffscreenCanvas.h new file mode 100644 index 000000000000..f2bddd0af01c --- /dev/null +++ b/dom/canvas/OffscreenCanvas.h @@ -0,0 +1,166 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_DOM_OFFSCREENCANVAS_H_ +#define MOZILLA_DOM_OFFSCREENCANVAS_H_ + +#include "mozilla/DOMEventTargetHelper.h" +#include "mozilla/RefPtr.h" +#include "CanvasRenderingContextHelper.h" +#include "nsCycleCollectionParticipant.h" + +struct JSContext; + +namespace mozilla { + +class ErrorResult; + +namespace layers { +class AsyncCanvasRenderer; +class CanvasClient; +} // namespace layers + +namespace dom { + +// This is helper class for transferring OffscreenCanvas to worker thread. +// Because OffscreenCanvas is not thread-safe. So we cannot pass Offscreen- +// Canvas to worker thread directly. Thus, we create this helper class and +// store necessary data in it then pass it to worker thread. +struct OffscreenCanvasCloneData final +{ + OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer, + uint32_t aWidth, uint32_t aHeight, + bool aNeutered); + ~OffscreenCanvasCloneData(); + + RefPtr mRenderer; + uint32_t mWidth; + uint32_t mHeight; + bool mNeutered; +}; + +class OffscreenCanvas final : public DOMEventTargetHelper + , public CanvasRenderingContextHelper +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(OffscreenCanvas, DOMEventTargetHelper) + + OffscreenCanvas(uint32_t aWidth, + uint32_t aHeight, + layers::AsyncCanvasRenderer* aRenderer); + + OffscreenCanvas* GetParentObject() const; + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + uint32_t Width() const + { + return mWidth; + } + + uint32_t Height() const + { + return mHeight; + } + + void SetWidth(uint32_t aWidth, ErrorResult& aRv) + { + if (mNeutered) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + + if (mWidth != aWidth) { + mWidth = aWidth; + CanvasAttrChanged(); + } + } + + void SetHeight(uint32_t aHeight, ErrorResult& aRv) + { + if (mNeutered) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + + if (mHeight != aHeight) { + mHeight = aHeight; + CanvasAttrChanged(); + } + } + + nsICanvasRenderingContextInternal* GetContext() const + { + return mCurrentContext; + } + + static already_AddRefed + CreateFromCloneData(OffscreenCanvasCloneData* aData); + + static bool PrefEnabled(JSContext* aCx, JSObject* aObj); + + // Return true on main-thread, and return gfx.offscreencanvas.enabled + // on worker thread. + static bool PrefEnabledOnWorkerThread(JSContext* aCx, JSObject* aObj); + + OffscreenCanvasCloneData* ToCloneData(); + + void CommitFrameToCompositor(); + + virtual bool GetOpaqueAttr() override + { + return false; + } + + virtual nsIntSize GetWidthHeight() override + { + return nsIntSize(mWidth, mHeight); + } + + virtual already_AddRefed + CreateContext(CanvasContextType aContextType) override; + + virtual already_AddRefed + GetContext(JSContext* aCx, + const nsAString& aContextId, + JS::Handle aContextOptions, + ErrorResult& aRv) override; + + void SetNeutered() + { + mNeutered = true; + } + + bool IsNeutered() const + { + return mNeutered; + } + +private: + ~OffscreenCanvas(); + + void CanvasAttrChanged() + { + mAttrDirty = true; + UpdateContext(nullptr, JS::NullHandleValue); + } + + bool mAttrDirty; + bool mNeutered; + + uint32_t mWidth; + uint32_t mHeight; + + layers::CanvasClient* mCanvasClient; + RefPtr mCanvasRenderer; +}; + +} // namespace dom +} // namespace mozilla + +#endif // MOZILLA_DOM_OFFSCREENCANVAS_H_ diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index f86094c60b20..61996962d814 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -22,6 +22,7 @@ #include "ImageEncoder.h" #include "Layers.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/Event.h" #include "mozilla/dom/HTMLVideoElement.h" #include "mozilla/dom/ImageData.h" #include "mozilla/EnumeratedArrayCycleCollection.h" @@ -79,125 +80,6 @@ using namespace mozilla::gfx; using namespace mozilla::gl; using namespace mozilla::layers; -WebGLObserver::WebGLObserver(WebGLContext* webgl) - : mWebGL(webgl) -{ -} - -WebGLObserver::~WebGLObserver() -{ -} - -void -WebGLObserver::Destroy() -{ - UnregisterMemoryPressureEvent(); - UnregisterVisibilityChangeEvent(); - mWebGL = nullptr; -} - -void -WebGLObserver::RegisterVisibilityChangeEvent() -{ - if (!mWebGL) - return; - - HTMLCanvasElement* canvas = mWebGL->GetCanvas(); - MOZ_ASSERT(canvas); - - if (canvas) { - nsIDocument* document = canvas->OwnerDoc(); - - document->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), - this, true, false); - } -} - -void -WebGLObserver::UnregisterVisibilityChangeEvent() -{ - if (!mWebGL) - return; - - HTMLCanvasElement* canvas = mWebGL->GetCanvas(); - - if (canvas) { - nsIDocument* document = canvas->OwnerDoc(); - - document->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"), - this, true); - } -} - -void -WebGLObserver::RegisterMemoryPressureEvent() -{ - if (!mWebGL) - return; - - nsCOMPtr observerService = - mozilla::services::GetObserverService(); - - MOZ_ASSERT(observerService); - - if (observerService) - observerService->AddObserver(this, "memory-pressure", false); -} - -void -WebGLObserver::UnregisterMemoryPressureEvent() -{ - if (!mWebGL) - return; - - nsCOMPtr observerService = - mozilla::services::GetObserverService(); - - // Do not assert on observerService here. This might be triggered by - // the cycle collector at a late enough time, that XPCOM services are - // no longer available. See bug 1029504. - if (observerService) - observerService->RemoveObserver(this, "memory-pressure"); -} - -NS_IMETHODIMP -WebGLObserver::Observe(nsISupports*, const char* topic, const char16_t*) -{ - if (!mWebGL || strcmp(topic, "memory-pressure")) { - return NS_OK; - } - - bool wantToLoseContext = mWebGL->mLoseContextOnMemoryPressure; - - if (!mWebGL->mCanLoseContextInForeground && - ProcessPriorityManager::CurrentProcessIsForeground()) - { - wantToLoseContext = false; - } - - if (wantToLoseContext) - mWebGL->ForceLoseContext(); - - return NS_OK; -} - -NS_IMETHODIMP -WebGLObserver::HandleEvent(nsIDOMEvent* event) -{ - nsAutoString type; - event->GetType(type); - if (!mWebGL || !type.EqualsLiteral("visibilitychange")) - return NS_OK; - - HTMLCanvasElement* canvas = mWebGL->GetCanvas(); - MOZ_ASSERT(canvas); - - if (canvas && !canvas->OwnerDoc()->Hidden()) - mWebGL->ForceRestoreContext(); - - return NS_OK; -} - WebGLContextOptions::WebGLContextOptions() : alpha(true) , depth(true) @@ -208,7 +90,7 @@ WebGLContextOptions::WebGLContextOptions() , failIfMajorPerformanceCaveat(false) { // Set default alpha state based on preference. - if (Preferences::GetBool("webgl.default-no-alpha", false)) + if (gfxPrefs::WebGLDefaultNoAlpha()) alpha = false; } @@ -282,7 +164,10 @@ WebGLContext::WebGLContext() mPixelStorePackAlignment = 4; mPixelStoreUnpackAlignment = 4; - WebGLMemoryTracker::AddWebGLContext(this); + if (NS_IsMainThread()) { + // XXX mtseng: bug 709490, not thread safe + WebGLMemoryTracker::AddWebGLContext(this); + } mAllowContextRestore = true; mLastLossWasSimulated = false; @@ -296,15 +181,12 @@ WebGLContext::WebGLContext() mAlreadyWarnedAboutFakeVertexAttrib0 = false; mAlreadyWarnedAboutViewportLargerThanDest = false; - mMaxWarnings = Preferences::GetInt("webgl.max-warnings-per-context", 32); + mMaxWarnings = gfxPrefs::WebGLMaxWarningsPerContext(); if (mMaxWarnings < -1) { GenerateWarning("webgl.max-warnings-per-context size is too large (seems like a negative value wrapped)"); mMaxWarnings = 0; } - mContextObserver = new WebGLObserver(this); - MOZ_RELEASE_ASSERT(mContextObserver, "Can't alloc WebGLContextObserver"); - mLastUseIndex = 0; InvalidateBufferFetching(); @@ -319,10 +201,12 @@ WebGLContext::WebGLContext() WebGLContext::~WebGLContext() { RemovePostRefreshObserver(); - mContextObserver->Destroy(); DestroyResourcesAndContext(); - WebGLMemoryTracker::RemoveWebGLContext(this); + if (NS_IsMainThread()) { + // XXX mtseng: bug 709490, not thread safe + WebGLMemoryTracker::RemoveWebGLContext(this); + } mContextLossHandler->DisableTimer(); mContextLossHandler = nullptr; @@ -331,8 +215,6 @@ WebGLContext::~WebGLContext() void WebGLContext::DestroyResourcesAndContext() { - mContextObserver->UnregisterMemoryPressureEvent(); - if (!gl) return; @@ -431,6 +313,35 @@ WebGLContext::Invalidate() mCanvasElement->InvalidateCanvasContent(nullptr); } +void +WebGLContext::OnVisibilityChange() +{ + if (!IsContextLost()) { + return; + } + + if (!mRestoreWhenVisible || mLastLossWasSimulated) { + return; + } + + ForceRestoreContext(); +} + +void +WebGLContext::OnMemoryPressure() +{ + bool shouldLoseContext = mLoseContextOnMemoryPressure; + + if (!mCanLoseContextInForeground && + ProcessPriorityManager::CurrentProcessIsForeground()) + { + shouldLoseContext = false; + } + + if (shouldLoseContext) + ForceLoseContext(); +} + // // nsICanvasRenderingContextInternal // @@ -515,7 +426,7 @@ static bool IsFeatureInBlacklist(const nsCOMPtr& gfxInfo, int32_t feature) { int32_t status; - if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(feature, &status))) + if (!NS_SUCCEEDED(gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, feature, &status))) return false; return status != nsIGfxInfo::FEATURE_STATUS_OK; @@ -526,19 +437,29 @@ HasAcceleratedLayers(const nsCOMPtr& gfxInfo) { int32_t status; - gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status); + gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, + nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, + &status); if (status) return true; - gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS, &status); + gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, + nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS, + &status); if (status) return true; - gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS, &status); + gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, + nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS, + &status); if (status) return true; - gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status); + gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, + nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, + &status); if (status) return true; - gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status); + gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, + nsIGfxInfo::FEATURE_OPENGL_LAYERS, + &status); if (status) return true; @@ -595,11 +516,14 @@ BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl) // we should really have this behind a // |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but // for now it's just behind a pref for testing/evaluation. - baseCaps.bpp16 = Preferences::GetBool("webgl.prefer-16bpp", false); + baseCaps.bpp16 = gfxPrefs::WebGLPrefer16bpp(); #ifdef MOZ_WIDGET_GONK do { auto canvasElement = webgl->GetCanvas(); + if (!canvasElement) + break; + auto ownerDoc = canvasElement->OwnerDoc(); nsIWidget* docWidget = nsContentUtils::WidgetForDocument(ownerDoc); if (!docWidget) @@ -620,7 +544,7 @@ BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl) // Done with baseCaps construction. - bool forceAllowAA = Preferences::GetBool("webgl.msaa-force", false); + bool forceAllowAA = gfxPrefs::WebGLForceMSAA(); nsCOMPtr gfxInfo = services::GetGfxInfo(); if (!forceAllowAA && IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA)) @@ -740,7 +664,7 @@ bool WebGLContext::CreateAndInitGL(bool forceEnabled) { bool preferEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL"); - bool disableANGLE = Preferences::GetBool("webgl.disable-angle", false); + bool disableANGLE = gfxPrefs::WebGLDisableANGLE(); if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) disableANGLE = true; @@ -821,10 +745,6 @@ WebGLContext::ResizeBackbuffer(uint32_t requestedWidth, NS_IMETHODIMP WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) { - // Early error return cases - if (!GetCanvas()) - return NS_ERROR_FAILURE; - if (signedWidth < 0 || signedHeight < 0) { GenerateWarning("Canvas size is too large (seems like a negative value wrapped)"); return NS_ERROR_OUT_OF_MEMORY; @@ -834,7 +754,10 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) uint32_t height = signedHeight; // Early success return cases - GetCanvas()->InvalidateCanvas(); + + // May have a OffscreenCanvas instead of an HTMLCanvasElement + if (GetCanvas()) + GetCanvas()->InvalidateCanvas(); // Zero-sized surfaces can cause problems. if (width == 0) @@ -907,10 +830,7 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) // pick up the old generation. ++mGeneration; - // Get some prefs for some preferred/overriden things - NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE); - - bool disabled = Preferences::GetBool("webgl.disabled", false); + bool disabled = gfxPrefs::WebGLDisabled(); // TODO: When we have software webgl support we should use that instead. disabled |= gfxPlatform::InSafeMode(); @@ -933,7 +853,7 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) } // Alright, now let's start trying. - bool forceEnabled = Preferences::GetBool("webgl.force-enabled", false); + bool forceEnabled = gfxPrefs::WebGLForceEnabled(); ScopedGfxFeatureReporter reporter("WebGL", forceEnabled); MOZ_ASSERT(!gl); @@ -1054,6 +974,11 @@ WebGLContext::LoseOldestWebGLContextIfLimitExceeded() #endif MOZ_ASSERT(kMaxWebGLContextsPerPrincipal < kMaxWebGLContexts); + if (!NS_IsMainThread()) { + // XXX mtseng: bug 709490, WebGLMemoryTracker is not thread safe. + return; + } + // it's important to update the index on a new context before losing old contexts, // otherwise new unused contexts would all have index 0 and we couldn't distinguish older ones // when choosing which one to lose first. @@ -1270,25 +1195,26 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder, } WebGLContextUserData* userData = nullptr; - if (builder->IsPaintingToWindow()) { - // Make the layer tell us whenever a transaction finishes (including - // the current transaction), so we can clear our invalidation state and - // start invalidating again. We need to do this for the layer that is - // being painted to a window (there shouldn't be more than one at a time, - // and if there is, flushing the invalidation state more often than - // necessary is harmless). + if (builder->IsPaintingToWindow() && mCanvasElement) { + // Make the layer tell us whenever a transaction finishes (including + // the current transaction), so we can clear our invalidation state and + // start invalidating again. We need to do this for the layer that is + // being painted to a window (there shouldn't be more than one at a time, + // and if there is, flushing the invalidation state more often than + // necessary is harmless). - // The layer will be destroyed when we tear down the presentation - // (at the latest), at which time this userData will be destroyed, - // releasing the reference to the element. - // The userData will receive DidTransactionCallbacks, which flush the - // the invalidation state to indicate that the canvas is up to date. - userData = new WebGLContextUserData(mCanvasElement); - canvasLayer->SetDidTransactionCallback( - WebGLContextUserData::DidTransactionCallback, userData); - canvasLayer->SetPreTransactionCallback( - WebGLContextUserData::PreTransactionCallback, userData); + // The layer will be destroyed when we tear down the presentation + // (at the latest), at which time this userData will be destroyed, + // releasing the reference to the element. + // The userData will receive DidTransactionCallbacks, which flush the + // the invalidation state to indicate that the canvas is up to date. + userData = new WebGLContextUserData(mCanvasElement); + canvasLayer->SetDidTransactionCallback( + WebGLContextUserData::DidTransactionCallback, userData); + canvasLayer->SetPreTransactionCallback( + WebGLContextUserData::PreTransactionCallback, userData); } + canvasLayer->SetUserData(&gWebGLLayerUserData, userData); CanvasLayer::Data data; @@ -1318,6 +1244,27 @@ WebGLContext::GetCompositorBackendType() const return LayersBackend::LAYERS_NONE; } +void +WebGLContext::Commit() +{ + if (mOffscreenCanvas) { + mOffscreenCanvas->CommitFrameToCompositor(); + } +} + +void +WebGLContext::GetCanvas(Nullable& retval) +{ + if (mCanvasElement) { + MOZ_RELEASE_ASSERT(!mOffscreenCanvas); + retval.SetValue().SetAsHTMLCanvasElement() = mCanvasElement; + } else if (mOffscreenCanvas) { + retval.SetValue().SetAsOffscreenCanvas() = mOffscreenCanvas; + } else { + retval.SetNull(); + } +} + void WebGLContext::GetContextAttributes(dom::Nullable& retval) { @@ -1626,7 +1573,7 @@ WebGLContext::RunContextLossTimer() mContextLossHandler->RunTimer(); } -class UpdateContextLossStatusTask : public nsRunnable +class UpdateContextLossStatusTask : public nsCancelableRunnable { nsRefPtr mWebGL; @@ -1637,10 +1584,16 @@ public: } NS_IMETHOD Run() { - mWebGL->UpdateContextLossStatus(); + if (mWebGL) + mWebGL->UpdateContextLossStatus(); return NS_OK; } + + NS_IMETHOD Cancel() { + mWebGL = nullptr; + return NS_OK; + } }; void @@ -1667,7 +1620,7 @@ WebGLContext::EnqueueUpdateContextLossStatus() void WebGLContext::UpdateContextLossStatus() { - if (!mCanvasElement) { + if (!mCanvasElement && !mOffscreenCanvas) { // the canvas is gone. That happens when the page was closed before we got // this timer event. In this case, there's nothing to do here, just don't crash. return; @@ -1695,12 +1648,23 @@ WebGLContext::UpdateContextLossStatus() // callback, so do that now. bool useDefaultHandler; - nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(), - static_cast(mCanvasElement), - NS_LITERAL_STRING("webglcontextlost"), - true, - true, - &useDefaultHandler); + + if (mCanvasElement) { + nsContentUtils::DispatchTrustedEvent( + mCanvasElement->OwnerDoc(), + static_cast(mCanvasElement), + NS_LITERAL_STRING("webglcontextlost"), + true, + true, + &useDefaultHandler); + } else { + // OffscreenCanvas case + nsRefPtr event = new Event(mOffscreenCanvas, nullptr, nullptr); + event->InitEvent(NS_LITERAL_STRING("webglcontextlost"), true, true); + event->SetTrusted(true); + mOffscreenCanvas->DispatchEvent(event, &useDefaultHandler); + } + // We sent the callback, so we're just 'regular lost' now. mContextStatus = ContextLost; // If we're told to use the default handler, it means the script @@ -1752,11 +1716,22 @@ WebGLContext::UpdateContextLossStatus() // Revival! mContextStatus = ContextNotLost; - nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(), - static_cast(mCanvasElement), - NS_LITERAL_STRING("webglcontextrestored"), - true, - true); + + if (mCanvasElement) { + nsContentUtils::DispatchTrustedEvent( + mCanvasElement->OwnerDoc(), + static_cast(mCanvasElement), + NS_LITERAL_STRING("webglcontextrestored"), + true, + true); + } else { + nsRefPtr event = new Event(mOffscreenCanvas, nullptr, nullptr); + event->InitEvent(NS_LITERAL_STRING("webglcontextrestored"), true, true); + event->SetTrusted(true); + bool unused; + mOffscreenCanvas->DispatchEvent(event, &unused); + } + mEmitContextLostErrorOnce = true; return; } @@ -1774,12 +1749,6 @@ WebGLContext::ForceLoseContext(bool simulateLosing) DestroyResourcesAndContext(); mLastLossWasSimulated = simulateLosing; - // Register visibility change observer to defer the context restoring. - // Restore the context when the app is visible. - if (mRestoreWhenVisible && !mLastLossWasSimulated) { - mContextObserver->RegisterVisibilityChangeEvent(); - } - // Queue up a task, since we know the status changed. EnqueueUpdateContextLossStatus(); } @@ -1791,8 +1760,6 @@ WebGLContext::ForceRestoreContext() mContextStatus = ContextLostAwaitingRestore; mAllowContextRestore = true; // Hey, you did say 'force'. - mContextObserver->UnregisterVisibilityChangeEvent(); - // Queue up a task, since we know the status changed. EnqueueUpdateContextLossStatus(); } @@ -1927,6 +1894,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext) NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext, mCanvasElement, + mOffscreenCanvas, mExtensions, mBound2DTextures, mBoundCubeMapTextures, diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index 6c1ff727e4ed..b19bc06efd83 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -40,7 +40,11 @@ // Generated #include "nsIDOMEventListener.h" #include "nsIDOMWebGLRenderingContext.h" +#include "nsICanvasRenderingContextInternal.h" #include "nsIObserver.h" +#include "mozilla/dom/HTMLCanvasElement.h" +#include "nsWrapperCache.h" +#include "nsLayoutUtils.h" class nsIDocShell; @@ -80,7 +84,6 @@ class WebGLContextLossHandler; class WebGLBuffer; class WebGLExtensionBase; class WebGLFramebuffer; -class WebGLObserver; class WebGLProgram; class WebGLQuery; class WebGLRenderbuffer; @@ -95,6 +98,7 @@ class WebGLVertexArray; namespace dom { class Element; class ImageData; +class OwningHTMLCanvasElementOrOffscreenCanvas; struct WebGLContextAttributes; template struct Nullable; } // namespace dom @@ -184,7 +188,6 @@ class WebGLContext friend class WebGLExtensionLoseContext; friend class WebGLExtensionVertexArray; friend class WebGLMemoryTracker; - friend class WebGLObserver; enum { UNPACK_FLIP_Y_WEBGL = 0x9240, @@ -214,6 +217,9 @@ public: NS_DECL_NSIDOMWEBGLRENDERINGCONTEXT + virtual void OnVisibilityChange() override; + virtual void OnMemoryPressure() override; + // nsICanvasRenderingContextInternal #ifdef DEBUG virtual int32_t GetWidth() const override; @@ -362,8 +368,11 @@ public: void AssertCachedBindings(); void AssertCachedState(); - // WebIDL WebGLRenderingContext API dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; } + + // WebIDL WebGLRenderingContext API + void Commit(); + void GetCanvas(Nullable& retval); GLsizei DrawingBufferWidth() const { return IsContextLost() ? 0 : mWidth; } GLsizei DrawingBufferHeight() const { return IsContextLost() ? 0 : mHeight; @@ -1509,8 +1518,6 @@ protected: ForceDiscreteGPUHelperCGL mForceDiscreteGPUHelper; #endif - nsRefPtr mContextObserver; - public: // console logging helpers void GenerateWarning(const char* fmt, ...); @@ -1615,32 +1622,6 @@ WebGLContext::ValidateObject(const char* info, ObjectType* object) return ValidateObjectAssumeNonNull(info, object); } -// Listen visibilitychange and memory-pressure event for context lose/restore -class WebGLObserver final - : public nsIObserver - , public nsIDOMEventListener -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - NS_DECL_NSIDOMEVENTLISTENER - - explicit WebGLObserver(WebGLContext* webgl); - - void Destroy(); - - void RegisterVisibilityChangeEvent(); - void UnregisterVisibilityChangeEvent(); - - void RegisterMemoryPressureEvent(); - void UnregisterMemoryPressureEvent(); - -private: - ~WebGLObserver(); - - WebGLContext* mWebGL; -}; - size_t RoundUpToMultipleOf(size_t value, size_t multiple); bool diff --git a/dom/canvas/WebGLContextExtensions.cpp b/dom/canvas/WebGLContextExtensions.cpp index 79040e1a4111..39b3ebd64713 100644 --- a/dom/canvas/WebGLContextExtensions.cpp +++ b/dom/canvas/WebGLContextExtensions.cpp @@ -6,6 +6,7 @@ #include "WebGLContext.h" #include "WebGLContextUtils.h" #include "WebGLExtensions.h" +#include "gfxPrefs.h" #include "GLContext.h" #include "nsString.h" @@ -74,12 +75,15 @@ bool WebGLContext::IsExtensionSupported(JSContext* cx, // Chrome contexts need access to debug information even when // webgl.disable-extensions is set. This is used in the graphics - // section of about:support. - if (xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) + // section of about:support + if (NS_IsMainThread() && + xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) { allowPrivilegedExts = true; + } - if (Preferences::GetBool("webgl.enable-privileged-extensions", false)) + if (gfxPrefs::WebGLPrivilegedExtensionsEnabled()) { allowPrivilegedExts = true; + } if (allowPrivilegedExts) { switch (ext) { @@ -181,9 +185,7 @@ WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const break; } - if (Preferences::GetBool("webgl.enable-draft-extensions", false) || - IsWebGL2()) - { + if (gfxPrefs::WebGLDraftExtensionsEnabled() || IsWebGL2()) { switch (ext) { case WebGLExtensionID::EXT_disjoint_timer_query: return WebGLExtensionDisjointTimerQuery::IsSupported(this); diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index 10cc59e4d4ef..53bd8d8e8ea5 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -1390,7 +1390,10 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, if (IsContextLost()) return; - if (mCanvasElement->IsWriteOnly() && !nsContentUtils::IsCallerChrome()) { + if (mCanvasElement && + mCanvasElement->IsWriteOnly() && + !nsContentUtils::IsCallerChrome()) + { GenerateWarning("readPixels: Not allowed"); return rv.Throw(NS_ERROR_DOM_SECURITY_ERR); } diff --git a/dom/canvas/WebGLContextLossHandler.cpp b/dom/canvas/WebGLContextLossHandler.cpp index 3cc1af031492..ddffbe994864 100644 --- a/dom/canvas/WebGLContextLossHandler.cpp +++ b/dom/canvas/WebGLContextLossHandler.cpp @@ -8,15 +8,103 @@ #include "nsITimer.h" #include "nsThreadUtils.h" #include "WebGLContext.h" +#include "mozilla/dom/WorkerPrivate.h" namespace mozilla { +// ------------------------------------------------------------------- +// Begin worker specific code +// ------------------------------------------------------------------- + +// On workers we can only dispatch CancelableRunnables, so we have to wrap the +// timer's EventTarget to use our own cancelable runnable + +class ContextLossWorkerEventTarget final : public nsIEventTarget +{ +public: + explicit ContextLossWorkerEventTarget(nsIEventTarget* aEventTarget) + : mEventTarget(aEventTarget) + { + MOZ_ASSERT(aEventTarget); + } + + NS_DECL_NSIEVENTTARGET + NS_DECL_THREADSAFE_ISUPPORTS + +protected: + ~ContextLossWorkerEventTarget() {} + +private: + nsCOMPtr mEventTarget; +}; + +class ContextLossWorkerRunnable final : public nsICancelableRunnable +{ +public: + explicit ContextLossWorkerRunnable(nsIRunnable* aRunnable) + : mRunnable(aRunnable) + { + } + + NS_DECL_NSICANCELABLERUNNABLE + NS_DECL_THREADSAFE_ISUPPORTS + + NS_FORWARD_NSIRUNNABLE(mRunnable->) + +protected: + ~ContextLossWorkerRunnable() {} + +private: + nsCOMPtr mRunnable; +}; + +NS_IMPL_ISUPPORTS(ContextLossWorkerEventTarget, nsIEventTarget, + nsISupports) + +NS_IMETHODIMP +ContextLossWorkerEventTarget::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags) +{ + nsCOMPtr event(aEvent); + return Dispatch(event.forget(), aFlags); +} + +NS_IMETHODIMP +ContextLossWorkerEventTarget::Dispatch(already_AddRefed&& aEvent, + uint32_t aFlags) +{ + nsCOMPtr eventRef(aEvent); + nsRefPtr wrappedEvent = + new ContextLossWorkerRunnable(eventRef); + return mEventTarget->Dispatch(wrappedEvent, aFlags); +} + +NS_IMETHODIMP +ContextLossWorkerEventTarget::IsOnCurrentThread(bool* aResult) +{ + return mEventTarget->IsOnCurrentThread(aResult); +} + +NS_IMPL_ISUPPORTS(ContextLossWorkerRunnable, nsICancelableRunnable, + nsIRunnable) + +NS_IMETHODIMP +ContextLossWorkerRunnable::Cancel() +{ + mRunnable = nullptr; + return NS_OK; +} + +// ------------------------------------------------------------------- +// End worker-specific code +// ------------------------------------------------------------------- + WebGLContextLossHandler::WebGLContextLossHandler(WebGLContext* webgl) : mWeakWebGL(webgl) , mTimer(do_CreateInstance(NS_TIMER_CONTRACTID)) , mIsTimerRunning(false) , mShouldRunTimerAgain(false) , mIsDisabled(false) + , mFeatureAdded(false) #ifdef DEBUG , mThread(NS_GetCurrentThread()) #endif @@ -90,6 +178,17 @@ WebGLContextLossHandler::RunTimer() return; } + if (!NS_IsMainThread()) { + dom::workers::WorkerPrivate* workerPrivate = + dom::workers::GetCurrentThreadWorkerPrivate(); + nsCOMPtr target = workerPrivate->GetEventTarget(); + mTimer->SetTarget(new ContextLossWorkerEventTarget(target)); + if (!mFeatureAdded) { + workerPrivate->AddFeature(workerPrivate->GetJSContext(), this); + mFeatureAdded = true; + } + } + StartTimer(1000); mIsTimerRunning = true; @@ -104,6 +203,14 @@ WebGLContextLossHandler::DisableTimer() mIsDisabled = true; + if (mFeatureAdded) { + dom::workers::WorkerPrivate* workerPrivate = + dom::workers::GetCurrentThreadWorkerPrivate(); + MOZ_RELEASE_ASSERT(workerPrivate); + workerPrivate->RemoveFeature(workerPrivate->GetJSContext(), this); + mFeatureAdded = false; + } + // We can't just Cancel() the timer, as sometimes we end up // receiving a callback after calling Cancel(). This could cause us // to receive the callback after object destruction. @@ -116,4 +223,16 @@ WebGLContextLossHandler::DisableTimer() mTimer->SetDelay(0); } +bool +WebGLContextLossHandler::Notify(JSContext* aCx, dom::workers::Status aStatus) +{ + bool isWorkerRunning = aStatus < dom::workers::Closing; + if (!isWorkerRunning && mIsTimerRunning) { + mIsTimerRunning = false; + this->Release(); + } + + return true; +} + } // namespace mozilla diff --git a/dom/canvas/WebGLContextLossHandler.h b/dom/canvas/WebGLContextLossHandler.h index 0769de910535..70d8c671fad5 100644 --- a/dom/canvas/WebGLContextLossHandler.h +++ b/dom/canvas/WebGLContextLossHandler.h @@ -10,6 +10,7 @@ #include "mozilla/WeakPtr.h" #include "nsCOMPtr.h" #include "nsISupportsImpl.h" +#include "WorkerFeature.h" class nsIThread; class nsITimer; @@ -17,13 +18,14 @@ class nsITimer; namespace mozilla { class WebGLContext; -class WebGLContextLossHandler +class WebGLContextLossHandler : public dom::workers::WorkerFeature { WeakPtr mWeakWebGL; nsCOMPtr mTimer; bool mIsTimerRunning; bool mShouldRunTimerAgain; bool mIsDisabled; + bool mFeatureAdded; DebugOnly mThread; public: @@ -33,6 +35,7 @@ public: void RunTimer(); void DisableTimer(); + bool Notify(JSContext* aCx, dom::workers::Status aStatus) override; protected: ~WebGLContextLossHandler(); diff --git a/dom/canvas/WebGLContextReporter.cpp b/dom/canvas/WebGLContextReporter.cpp index d257d9662b4f..4aab34a079c3 100644 --- a/dom/canvas/WebGLContextReporter.cpp +++ b/dom/canvas/WebGLContextReporter.cpp @@ -9,8 +9,6 @@ namespace mozilla { -NS_IMPL_ISUPPORTS(WebGLObserver, nsIObserver) - NS_IMETHODIMP WebGLMemoryTracker::CollectReports(nsIHandleReportCallback* handleReport, nsISupports* data, bool) diff --git a/dom/canvas/WebGLContextValidate.cpp b/dom/canvas/WebGLContextValidate.cpp index ff366b1b74ab..29dedac8f98a 100644 --- a/dom/canvas/WebGLContextValidate.cpp +++ b/dom/canvas/WebGLContextValidate.cpp @@ -8,6 +8,7 @@ #include #include "angle/ShaderLang.h" #include "CanvasUtils.h" +#include "gfxPrefs.h" #include "GLContext.h" #include "jsfriendapi.h" #include "mozilla/CheckedInt.h" @@ -1665,11 +1666,11 @@ WebGLContext::InitAndValidateGL() return false; } - mMinCapability = Preferences::GetBool("webgl.min_capability_mode", false); - mDisableExtensions = Preferences::GetBool("webgl.disable-extensions", false); - mLoseContextOnMemoryPressure = Preferences::GetBool("webgl.lose-context-on-memory-pressure", false); - mCanLoseContextInForeground = Preferences::GetBool("webgl.can-lose-context-in-foreground", true); - mRestoreWhenVisible = Preferences::GetBool("webgl.restore-context-when-visible", true); + mMinCapability = gfxPrefs::WebGLMinCapabilityMode(); + mDisableExtensions = gfxPrefs::WebGLDisableExtensions(); + mLoseContextOnMemoryPressure = gfxPrefs::WebGLLoseContextOnMemoryPressure(); + mCanLoseContextInForeground = gfxPrefs::WebGLCanLoseContextInForeground(); + mRestoreWhenVisible = gfxPrefs::WebGLRestoreWhenVisible(); if (MinCapabilityMode()) mDisableFragHighP = true; @@ -1878,10 +1879,7 @@ WebGLContext::InitAndValidateGL() #endif // Check the shader validator pref - NS_ENSURE_TRUE(Preferences::GetRootBranch(), false); - - mBypassShaderValidation = Preferences::GetBool("webgl.bypass-shader-validation", - mBypassShaderValidation); + mBypassShaderValidation = gfxPrefs::WebGLBypassShaderValidator(); // initialize shader translator if (!ShInitialize()) { @@ -1937,9 +1935,6 @@ WebGLContext::InitAndValidateGL() mDefaultVertexArray->BindVertexArray(); } - if (mLoseContextOnMemoryPressure) - mContextObserver->RegisterMemoryPressureEvent(); - return true; } diff --git a/dom/canvas/WebGLMemoryTracker.cpp b/dom/canvas/WebGLMemoryTracker.cpp index b13d9d7c43bd..5bc4b31fb5d9 100644 --- a/dom/canvas/WebGLMemoryTracker.cpp +++ b/dom/canvas/WebGLMemoryTracker.cpp @@ -16,8 +16,6 @@ namespace mozilla { -NS_IMPL_ISUPPORTS(WebGLObserver, nsIObserver) - NS_IMETHODIMP WebGLMemoryTracker::CollectReports(nsIHandleReportCallback* handleReport, nsISupports* data, bool) diff --git a/dom/canvas/WebGLShaderValidator.cpp b/dom/canvas/WebGLShaderValidator.cpp index 4f8741547270..5553ad8f72ec 100644 --- a/dom/canvas/WebGLShaderValidator.cpp +++ b/dom/canvas/WebGLShaderValidator.cpp @@ -6,6 +6,7 @@ #include "WebGLShaderValidator.h" #include "angle/ShaderLang.h" +#include "gfxPrefs.h" #include "GLContext.h" #include "mozilla/Preferences.h" #include "MurmurHash3.h" @@ -43,7 +44,7 @@ ChooseValidatorCompileOptions(const ShBuiltInResources& resources, options |= SH_LIMIT_EXPRESSION_COMPLEXITY; } - if (Preferences::GetBool("webgl.all-angle-options", false)) { + if (gfxPrefs::WebGLAllANGLEOptions()) { return options | SH_VALIDATE_LOOP_INDEXING | SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX | diff --git a/dom/canvas/moz.build b/dom/canvas/moz.build index 39288fe6be89..762741b22f7d 100644 --- a/dom/canvas/moz.build +++ b/dom/canvas/moz.build @@ -28,10 +28,12 @@ EXPORTS.mozilla.dom += [ 'CanvasPath.h', 'CanvasPattern.h', 'CanvasRenderingContext2D.h', + 'CanvasRenderingContextHelper.h', 'CanvasUtils.h', 'ImageBitmap.h', 'ImageBitmapSource.h', 'ImageData.h', + 'OffscreenCanvas.h', 'TextMetrics.h', 'WebGLVertexArrayObject.h', ] @@ -40,11 +42,13 @@ EXPORTS.mozilla.dom += [ UNIFIED_SOURCES += [ 'CanvasImageCache.cpp', 'CanvasRenderingContext2D.cpp', + 'CanvasRenderingContextHelper.cpp', 'CanvasUtils.cpp', 'DocumentRendererChild.cpp', 'DocumentRendererParent.cpp', 'ImageBitmap.cpp', 'ImageData.cpp', + 'OffscreenCanvas.cpp', ] # WebGL Sources @@ -150,6 +154,7 @@ LOCAL_INCLUDES += [ '/dom/base', '/dom/html', '/dom/svg', + '/dom/workers', '/dom/xul', '/gfx/gl', '/image', diff --git a/dom/canvas/nsICanvasRenderingContextInternal.h b/dom/canvas/nsICanvasRenderingContextInternal.h index ec62bd97a493..820b1d5d1314 100644 --- a/dom/canvas/nsICanvasRenderingContextInternal.h +++ b/dom/canvas/nsICanvasRenderingContextInternal.h @@ -12,12 +12,13 @@ #include "nsIDocShell.h" #include "nsRefreshDriver.h" #include "mozilla/dom/HTMLCanvasElement.h" +#include "mozilla/dom/OffscreenCanvas.h" #include "GraphicsFilter.h" #include "mozilla/RefPtr.h" #define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \ -{ 0x3cc9e801, 0x1806, 0x4ff6, \ - { 0x86, 0x14, 0xf9, 0xd0, 0xf4, 0xfb, 0x3b, 0x08 } } +{ 0xb84f2fed, 0x9d4b, 0x430b, \ + { 0xbd, 0xfb, 0x85, 0x57, 0x8a, 0xc2, 0xb4, 0x4b } } class gfxASurface; class nsDisplayListBuilder; @@ -80,6 +81,11 @@ public: return mCanvasElement; } + void SetOffscreenCanvas(mozilla::dom::OffscreenCanvas* aOffscreenCanvas) + { + mOffscreenCanvas = aOffscreenCanvas; + } + #ifdef DEBUG // Useful for testing virtual int32_t GetWidth() const = 0; @@ -154,6 +160,10 @@ public: // Given a point, return hit region ID if it exists or an empty string if it doesn't virtual nsString GetHitRegion(const mozilla::gfx::Point& point) { return nsString(); } + virtual void OnVisibilityChange() {} + + virtual void OnMemoryPressure() {} + // // shmem support // @@ -166,6 +176,7 @@ public: protected: nsRefPtr mCanvasElement; + nsRefPtr mOffscreenCanvas; nsRefPtr mRefreshDriver; }; diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp index a6f89034f079..e37569ec210a 100644 --- a/dom/html/HTMLCanvasElement.cpp +++ b/dom/html/HTMLCanvasElement.cpp @@ -19,6 +19,7 @@ #include "mozilla/dom/File.h" #include "mozilla/dom/HTMLCanvasElementBinding.h" #include "mozilla/dom/MouseEvent.h" +#include "mozilla/dom/OffscreenCanvas.h" #include "mozilla/EventDispatcher.h" #include "mozilla/gfx/Rect.h" #include "mozilla/layers/AsyncCanvasRenderer.h" @@ -240,6 +241,113 @@ HTMLCanvasPrintState::NotifyDone() // --------------------------------------------------------------------------- +HTMLCanvasElementObserver::HTMLCanvasElementObserver(HTMLCanvasElement* aElement) + : mElement(aElement) +{ + RegisterVisibilityChangeEvent(); + RegisterMemoryPressureEvent(); +} + +HTMLCanvasElementObserver::~HTMLCanvasElementObserver() +{ + Destroy(); +} + +void +HTMLCanvasElementObserver::Destroy() +{ + UnregisterMemoryPressureEvent(); + UnregisterVisibilityChangeEvent(); + mElement = nullptr; +} + +void +HTMLCanvasElementObserver::RegisterVisibilityChangeEvent() +{ + if (!mElement) { + return; + } + + nsIDocument* document = mElement->OwnerDoc(); + document->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), + this, true, false); +} + +void +HTMLCanvasElementObserver::UnregisterVisibilityChangeEvent() +{ + if (!mElement) { + return; + } + + nsIDocument* document = mElement->OwnerDoc(); + document->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"), + this, true); +} + +void +HTMLCanvasElementObserver::RegisterMemoryPressureEvent() +{ + if (!mElement) { + return; + } + + nsCOMPtr observerService = + mozilla::services::GetObserverService(); + + MOZ_ASSERT(observerService); + + if (observerService) + observerService->AddObserver(this, "memory-pressure", false); +} + +void +HTMLCanvasElementObserver::UnregisterMemoryPressureEvent() +{ + if (!mElement) { + return; + } + + nsCOMPtr observerService = + mozilla::services::GetObserverService(); + + // Do not assert on observerService here. This might be triggered by + // the cycle collector at a late enough time, that XPCOM services are + // no longer available. See bug 1029504. + if (observerService) + observerService->RemoveObserver(this, "memory-pressure"); +} + +NS_IMETHODIMP +HTMLCanvasElementObserver::Observe(nsISupports*, const char* aTopic, const char16_t*) +{ + if (!mElement || strcmp(aTopic, "memory-pressure")) { + return NS_OK; + } + + mElement->OnMemoryPressure(); + + return NS_OK; +} + +NS_IMETHODIMP +HTMLCanvasElementObserver::HandleEvent(nsIDOMEvent* aEvent) +{ + nsAutoString type; + aEvent->GetType(type); + if (!mElement || !type.EqualsLiteral("visibilitychange")) { + return NS_OK; + } + + mElement->OnVisibilityChange(); + + return NS_OK; +} + +NS_IMPL_ISUPPORTS(HTMLCanvasElementObserver, nsIObserver) + +// --------------------------------------------------------------------------- + HTMLCanvasElement::HTMLCanvasElement(already_AddRefed& aNodeInfo) : nsGenericHTMLElement(aNodeInfo), mWriteOnly(false) @@ -248,6 +356,11 @@ HTMLCanvasElement::HTMLCanvasElement(already_AddRefed& a HTMLCanvasElement::~HTMLCanvasElement() { + if (mContextObserver) { + mContextObserver->Destroy(); + mContextObserver = nullptr; + } + ResetPrintCallback(); if (mRequestedFrameRefreshObserver) { mRequestedFrameRefreshObserver->DetachFromRefreshDriver(); @@ -277,6 +390,22 @@ HTMLCanvasElement::WrapNode(JSContext* aCx, JS::Handle aGivenProto) return HTMLCanvasElementBinding::Wrap(aCx, this, aGivenProto); } +already_AddRefed +HTMLCanvasElement::CreateContext(CanvasContextType aContextType) +{ + nsRefPtr ret = + CanvasRenderingContextHelper::CreateContext(aContextType); + + // Add Observer for webgl canvas. + if (aContextType == CanvasContextType::WebGL1 || + aContextType == CanvasContextType::WebGL2) { + mContextObserver = new HTMLCanvasElementObserver(this); + } + + ret->SetCanvasElement(this); + return ret.forget(); +} + nsIntSize HTMLCanvasElement::GetWidthHeight() { @@ -564,48 +693,6 @@ HTMLCanvasElement::ExtractData(nsAString& aType, aStream); } -nsresult -HTMLCanvasElement::ParseParams(JSContext* aCx, - const nsAString& aType, - const JS::Value& aEncoderOptions, - nsAString& aParams, - bool* usingCustomParseOptions) -{ - // Quality parameter is only valid for the image/jpeg MIME type - if (aType.EqualsLiteral("image/jpeg")) { - if (aEncoderOptions.isNumber()) { - double quality = aEncoderOptions.toNumber(); - // Quality must be between 0.0 and 1.0, inclusive - if (quality >= 0.0 && quality <= 1.0) { - aParams.AppendLiteral("quality="); - aParams.AppendInt(NS_lround(quality * 100.0)); - } - } - } - - // If we haven't parsed the aParams check for proprietary options. - // The proprietary option -moz-parse-options will take a image lib encoder - // parse options string as is and pass it to the encoder. - *usingCustomParseOptions = false; - if (aParams.Length() == 0 && aEncoderOptions.isString()) { - NS_NAMED_LITERAL_STRING(mozParseOptions, "-moz-parse-options:"); - nsAutoJSString paramString; - if (!paramString.init(aCx, aEncoderOptions.toString())) { - return NS_ERROR_FAILURE; - } - if (StringBeginsWith(paramString, mozParseOptions)) { - nsDependentSubstring parseOptions = Substring(paramString, - mozParseOptions.Length(), - paramString.Length() - - mozParseOptions.Length()); - aParams.Append(parseOptions); - *usingCustomParseOptions = true; - } - } - - return NS_OK; -} - nsresult HTMLCanvasElement::ToDataURLImpl(JSContext* aCx, const nsAString& aMimeType, @@ -664,83 +751,35 @@ HTMLCanvasElement::ToBlob(JSContext* aCx, return; } - nsAutoString type; - nsContentUtils::ASCIIToLower(aType, type); - - nsAutoString params; - bool usingCustomParseOptions; - aRv = ParseParams(aCx, type, aParams, params, &usingCustomParseOptions); - if (aRv.Failed()) { - return; - } - -#ifdef DEBUG - if (mCurrentContext) { - // We disallow canvases of width or height zero, and set them to 1, so - // we will have a discrepancy with the sizes of the canvas and the context. - // That discrepancy is OK, the rest are not. - nsIntSize elementSize = GetWidthHeight(); - MOZ_ASSERT(elementSize.width == mCurrentContext->GetWidth() || - (elementSize.width == 0 && mCurrentContext->GetWidth() == 1)); - MOZ_ASSERT(elementSize.height == mCurrentContext->GetHeight() || - (elementSize.height == 0 && mCurrentContext->GetHeight() == 1)); - } -#endif - - uint8_t* imageBuffer = nullptr; - int32_t format = 0; - if (mCurrentContext) { - mCurrentContext->GetImageBuffer(&imageBuffer, &format); - } - - // Encoder callback when encoding is complete. - class EncodeCallback : public EncodeCompleteCallback - { - public: - EncodeCallback(nsIGlobalObject* aGlobal, FileCallback* aCallback) - : mGlobal(aGlobal) - , mFileCallback(aCallback) {} - - // This is called on main thread. - nsresult ReceiveBlob(already_AddRefed aBlob) - { - nsRefPtr blob = aBlob; - - ErrorResult rv; - uint64_t size = blob->GetSize(rv); - if (rv.Failed()) { - rv.SuppressException(); - } else { - AutoJSAPI jsapi; - if (jsapi.Init(mGlobal)) { - JS_updateMallocCounter(jsapi.cx(), size); - } - } - - nsRefPtr newBlob = Blob::Create(mGlobal, blob->Impl()); - - mFileCallback->Call(*newBlob, rv); - - mGlobal = nullptr; - mFileCallback = nullptr; - - return rv.StealNSResult(); - } - - nsCOMPtr mGlobal; - nsRefPtr mFileCallback; - }; - nsCOMPtr global = OwnerDoc()->GetScopeObject(); MOZ_ASSERT(global); - nsRefPtr callback = new EncodeCallback(global, &aCallback); - aRv = ImageEncoder::ExtractDataAsync(type, - params, - usingCustomParseOptions, - imageBuffer, - format, - GetSize(), - callback); + + CanvasRenderingContextHelper::ToBlob(aCx, global, aCallback, aType, + aParams, aRv); + +} + +OffscreenCanvas* +HTMLCanvasElement::TransferControlToOffscreen(ErrorResult& aRv) +{ + if (mCurrentContext) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } + + if (!mOffscreenCanvas) { + nsIntSize sz = GetWidthHeight(); + nsRefPtr renderer = GetAsyncCanvasRenderer(); + renderer->SetWidth(sz.width); + renderer->SetHeight(sz.height); + + mOffscreenCanvas = new OffscreenCanvas(sz.width, sz.height, renderer); + mContextObserver = new HTMLCanvasElementObserver(this); + } else { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + } + + return mOffscreenCanvas; } already_AddRefed @@ -811,76 +850,6 @@ HTMLCanvasElement::MozGetAsBlobImpl(const nsAString& aName, return NS_OK; } -static bool -GetCanvasContextType(const nsAString& str, CanvasContextType* const out_type) -{ - if (str.EqualsLiteral("2d")) { - *out_type = CanvasContextType::Canvas2D; - return true; - } - - if (str.EqualsLiteral("experimental-webgl")) { - *out_type = CanvasContextType::WebGL1; - return true; - } - -#ifdef MOZ_WEBGL_CONFORMANT - if (str.EqualsLiteral("webgl")) { - /* WebGL 1.0, $2.1 "Context Creation": - * If the user agent supports both the webgl and experimental-webgl - * canvas context types, they shall be treated as aliases. - */ - *out_type = CanvasContextType::WebGL1; - return true; - } -#endif - - if (WebGL2Context::IsSupported()) { - if (str.EqualsLiteral("webgl2")) { - *out_type = CanvasContextType::WebGL2; - return true; - } - } - - return false; -} - -static already_AddRefed -CreateContextForCanvas(CanvasContextType contextType, HTMLCanvasElement* canvas) -{ - MOZ_ASSERT(contextType != CanvasContextType::NoContext); - nsRefPtr ret; - - switch (contextType) { - case CanvasContextType::NoContext: - break; - case CanvasContextType::Canvas2D: - Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1); - ret = new CanvasRenderingContext2D(); - break; - - case CanvasContextType::WebGL1: - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1); - - ret = WebGL1Context::Create(); - if (!ret) - return nullptr; - break; - - case CanvasContextType::WebGL2: - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1); - - ret = WebGL2Context::Create(); - if (!ret) - return nullptr; - break; - } - MOZ_ASSERT(ret); - - ret->SetCanvasElement(canvas); - return ret.forget(); -} - nsresult HTMLCanvasElement::GetContext(const nsAString& aContextId, nsISupports** aContext) @@ -894,45 +863,14 @@ already_AddRefed HTMLCanvasElement::GetContext(JSContext* aCx, const nsAString& aContextId, JS::Handle aContextOptions, - ErrorResult& rv) + ErrorResult& aRv) { - CanvasContextType contextType; - if (!GetCanvasContextType(aContextId, &contextType)) + if (mOffscreenCanvas) { return nullptr; - - if (!mCurrentContext) { - // This canvas doesn't have a context yet. - - nsRefPtr context; - context = CreateContextForCanvas(contextType, this); - if (!context) - return nullptr; - - // Ensure that the context participates in CC. Note that returning a - // CC participant from QI doesn't addref. - nsXPCOMCycleCollectionParticipant* cp = nullptr; - CallQueryInterface(context, &cp); - if (!cp) { - rv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - mCurrentContext = context.forget(); - mCurrentContextType = contextType; - - rv = UpdateContext(aCx, aContextOptions); - if (rv.Failed()) { - rv = NS_OK; // See bug 645792 - return nullptr; - } - } else { - // We already have a context of some type. - if (contextType != mCurrentContextType) - return nullptr; } - nsCOMPtr context = mCurrentContext; - return context.forget(); + return CanvasRenderingContextHelper::GetContext(aCx, aContextId, + aContextOptions, aRv); } NS_IMETHODIMP @@ -954,7 +892,7 @@ HTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId, // This canvas doesn't have a context yet. nsRefPtr context; - context = CreateContextForCanvas(contextType, this); + context = CreateContext(contextType); if (!context) { *aContext = nullptr; return NS_OK; @@ -976,36 +914,6 @@ HTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId, return NS_OK; } -nsresult -HTMLCanvasElement::UpdateContext(JSContext* aCx, JS::Handle aNewContextOptions) -{ - if (!mCurrentContext) - return NS_OK; - - nsIntSize sz = GetWidthHeight(); - - nsCOMPtr currentContext = mCurrentContext; - - nsresult rv = currentContext->SetIsOpaque(HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque)); - if (NS_FAILED(rv)) { - mCurrentContext = nullptr; - return rv; - } - - rv = currentContext->SetContextOptions(aCx, aNewContextOptions); - if (NS_FAILED(rv)) { - mCurrentContext = nullptr; - return rv; - } - - rv = currentContext->SetDimensions(sz.width, sz.height); - if (NS_FAILED(rv)) { - mCurrentContext = nullptr; - return rv; - } - - return rv; -} nsIntSize HTMLCanvasElement::GetSize() @@ -1109,6 +1017,12 @@ HTMLCanvasElement::GetIsOpaque() return mCurrentContext->GetIsOpaque(); } + return GetOpaqueAttr(); +} + +bool +HTMLCanvasElement::GetOpaqueAttr() +{ return HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque); } @@ -1117,16 +1031,51 @@ HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder, CanvasLayer *aOldLayer, LayerManager *aManager) { - if (!mCurrentContext) - return nullptr; + // The address of sOffscreenCanvasLayerUserDataDummy is used as the user + // data key for retained LayerManagers managed by FrameLayerBuilder. + // We don't much care about what value in it, so just assign a dummy + // value for it. + static uint8_t sOffscreenCanvasLayerUserDataDummy = 0; - return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager); + if (mCurrentContext) { + return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager); + } + + if (mOffscreenCanvas) { + if (aOldLayer && aOldLayer->HasUserData(&sOffscreenCanvasLayerUserDataDummy)) { + nsRefPtr ret = aOldLayer; + return ret.forget(); + } + + nsRefPtr layer = aManager->CreateCanvasLayer(); + if (!layer) { + NS_WARNING("CreateCanvasLayer failed!"); + return nullptr; + } + + LayerUserData* userData = nullptr; + layer->SetUserData(&sOffscreenCanvasLayerUserDataDummy, userData); + layer->SetAsyncRenderer(GetAsyncCanvasRenderer()); + layer->Updated(); + return layer.forget(); + } + + return nullptr; } bool -HTMLCanvasElement::ShouldForceInactiveLayer(LayerManager *aManager) +HTMLCanvasElement::ShouldForceInactiveLayer(LayerManager* aManager) { - return !mCurrentContext || mCurrentContext->ShouldForceInactiveLayer(aManager); + if (mCurrentContext) { + return mCurrentContext->ShouldForceInactiveLayer(aManager); + } + + if (mOffscreenCanvas) { + // TODO: We should handle offscreen canvas case. + return false; + } + + return true; } void @@ -1252,6 +1201,92 @@ HTMLCanvasElement::GetAsyncCanvasRenderer() return mAsyncCanvasRenderer; } +void +HTMLCanvasElement::OnVisibilityChange() +{ + if (OwnerDoc()->Hidden()) { + return; + } + + if (mOffscreenCanvas) { + class Runnable final : public nsCancelableRunnable + { + public: + Runnable(AsyncCanvasRenderer* aRenderer) + : mRenderer(aRenderer) + {} + + NS_IMETHOD Run() + { + if (mRenderer && mRenderer->mContext) { + mRenderer->mContext->OnVisibilityChange(); + } + + return NS_OK; + } + + void Revoke() + { + mRenderer = nullptr; + } + + private: + nsRefPtr mRenderer; + }; + + nsRefPtr runnable = new Runnable(mAsyncCanvasRenderer); + if (mAsyncCanvasRenderer->mActiveThread) { + mAsyncCanvasRenderer->mActiveThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL); + } + return; + } + + if (mCurrentContext) { + mCurrentContext->OnVisibilityChange(); + } +} + +void +HTMLCanvasElement::OnMemoryPressure() +{ + if (mOffscreenCanvas) { + class Runnable final : public nsCancelableRunnable + { + public: + Runnable(AsyncCanvasRenderer* aRenderer) + : mRenderer(aRenderer) + {} + + NS_IMETHOD Run() + { + if (mRenderer && mRenderer->mContext) { + mRenderer->mContext->OnMemoryPressure(); + } + + return NS_OK; + } + + void Revoke() + { + mRenderer = nullptr; + } + + private: + nsRefPtr mRenderer; + }; + + nsRefPtr runnable = new Runnable(mAsyncCanvasRenderer); + if (mAsyncCanvasRenderer->mActiveThread) { + mAsyncCanvasRenderer->mActiveThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL); + } + return; + } + + if (mCurrentContext) { + mCurrentContext->OnMemoryPressure(); + } +} + /* static */ void HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer) { diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h index 8c12c98dd28b..129ec0fe2c4f 100644 --- a/dom/html/HTMLCanvasElement.h +++ b/dom/html/HTMLCanvasElement.h @@ -8,12 +8,15 @@ #include "mozilla/Attributes.h" #include "mozilla/WeakPtr.h" +#include "nsIDOMEventListener.h" #include "nsIDOMHTMLCanvasElement.h" +#include "nsIObserver.h" #include "nsGenericHTMLElement.h" #include "nsGkAtoms.h" #include "nsSize.h" #include "nsError.h" +#include "mozilla/dom/CanvasRenderingContextHelper.h" #include "mozilla/gfx/Rect.h" class nsICanvasRenderingContextInternal; @@ -21,6 +24,8 @@ class nsITimerCallback; namespace mozilla { +class WebGLContext; + namespace layers { class AsyncCanvasRenderer; class CanvasLayer; @@ -36,14 +41,33 @@ class CanvasCaptureMediaStream; class File; class FileCallback; class HTMLCanvasPrintState; +class OffscreenCanvas; class PrintCallback; class RequestedFrameRefreshObserver; -enum class CanvasContextType : uint8_t { - NoContext, - Canvas2D, - WebGL1, - WebGL2 +// Listen visibilitychange and memory-pressure event and inform +// context when event is fired. +class HTMLCanvasElementObserver final : public nsIObserver + , public nsIDOMEventListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + NS_DECL_NSIDOMEVENTLISTENER + + explicit HTMLCanvasElementObserver(HTMLCanvasElement* aElement); + void Destroy(); + + void RegisterVisibilityChangeEvent(); + void UnregisterVisibilityChangeEvent(); + + void RegisterMemoryPressureEvent(); + void UnregisterMemoryPressureEvent(); + +private: + ~HTMLCanvasElementObserver(); + + HTMLCanvasElement* mElement; }; /* @@ -85,7 +109,8 @@ protected: }; class HTMLCanvasElement final : public nsGenericHTMLElement, - public nsIDOMHTMLCanvasElement + public nsIDOMHTMLCanvasElement, + public CanvasRenderingContextHelper { enum { DEFAULT_CANVAS_WIDTH = 300, @@ -118,6 +143,11 @@ public: } void SetHeight(uint32_t aHeight, ErrorResult& aRv) { + if (mOffscreenCanvas) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + SetUnsignedIntAttr(nsGkAtoms::height, aHeight, aRv); } uint32_t Width() @@ -126,30 +156,45 @@ public: } void SetWidth(uint32_t aWidth, ErrorResult& aRv) { + if (mOffscreenCanvas) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + SetUnsignedIntAttr(nsGkAtoms::width, aWidth, aRv); } - already_AddRefed + + virtual already_AddRefed GetContext(JSContext* aCx, const nsAString& aContextId, JS::Handle aContextOptions, - ErrorResult& aRv); + ErrorResult& aRv) override; + void ToDataURL(JSContext* aCx, const nsAString& aType, JS::Handle aParams, nsAString& aDataURL, ErrorResult& aRv) { aRv = ToDataURL(aType, aParams, aCx, aDataURL); } + void ToBlob(JSContext* aCx, FileCallback& aCallback, const nsAString& aType, JS::Handle aParams, ErrorResult& aRv); + OffscreenCanvas* TransferControlToOffscreen(ErrorResult& aRv); + bool MozOpaque() const { return GetBoolAttr(nsGkAtoms::moz_opaque); } void SetMozOpaque(bool aValue, ErrorResult& aRv) { + if (mOffscreenCanvas) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + SetHTMLBoolAttr(nsGkAtoms::moz_opaque, aValue, aRv); } already_AddRefed MozGetAsFile(const nsAString& aName, @@ -206,6 +251,7 @@ public: * across its entire area. */ bool GetIsOpaque(); + virtual bool GetOpaqueAttr() override; virtual already_AddRefed GetSurfaceSnapshot(bool* aPremultAlpha = nullptr); @@ -284,6 +330,10 @@ public: nsresult GetContext(const nsAString& aContextId, nsISupports** aContext); + void OnVisibilityChange(); + + void OnMemoryPressure(); + static void SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer); protected: @@ -291,14 +341,11 @@ protected: virtual JSObject* WrapNode(JSContext* aCx, JS::Handle aGivenProto) override; - nsIntSize GetWidthHeight(); + virtual nsIntSize GetWidthHeight() override; + + virtual already_AddRefed + CreateContext(CanvasContextType aContextType) override; - nsresult UpdateContext(JSContext* aCx, JS::Handle options); - nsresult ParseParams(JSContext* aCx, - const nsAString& aType, - const JS::Value& aEncoderOptions, - nsAString& aParams, - bool* usingCustomParseOptions); nsresult ExtractData(nsAString& aType, const nsAString& aOptions, nsIInputStream** aStream); @@ -313,14 +360,14 @@ protected: AsyncCanvasRenderer* GetAsyncCanvasRenderer(); - CanvasContextType mCurrentContextType; nsRefPtr mOriginalCanvas; nsRefPtr mPrintCallback; - nsCOMPtr mCurrentContext; nsRefPtr mPrintState; nsTArray> mRequestedFrameListeners; nsRefPtr mRequestedFrameRefreshObserver; nsRefPtr mAsyncCanvasRenderer; + nsRefPtr mOffscreenCanvas; + nsRefPtr mContextObserver; public: // Record whether this canvas should be write-only or not. diff --git a/dom/webidl/HTMLCanvasElement.webidl b/dom/webidl/HTMLCanvasElement.webidl index 18d46edf8b5a..dde7841a5e0b 100644 --- a/dom/webidl/HTMLCanvasElement.webidl +++ b/dom/webidl/HTMLCanvasElement.webidl @@ -46,6 +46,13 @@ partial interface HTMLCanvasElement { CanvasCaptureMediaStream captureStream(optional double frameRate); }; +// For OffscreenCanvas +// Reference: https://wiki.whatwg.org/wiki/OffscreenCanvas +partial interface HTMLCanvasElement { + [Pref="gfx.offscreencanvas.enabled", Throws] + OffscreenCanvas transferControlToOffscreen(); +}; + [ChromeOnly] interface MozCanvasPrintState { diff --git a/dom/webidl/OffscreenCanvas.webidl b/dom/webidl/OffscreenCanvas.webidl new file mode 100644 index 000000000000..592ac6e14fe6 --- /dev/null +++ b/dom/webidl/OffscreenCanvas.webidl @@ -0,0 +1,28 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * For more information on this interface, please see + * https://wiki.whatwg.org/wiki/OffscreenCanvas + * + * Current implementation focus on transfer canvas from main thread to worker. + * So there are some spec doesn't implement, such as [Constructor], toBlob() and + * transferToImageBitmap in OffscreenCanvas. Bug 1172796 will implement + * remaining spec. + */ + +[Exposed=(Window,Worker), + Func="mozilla::dom::OffscreenCanvas::PrefEnabled"] +interface OffscreenCanvas : EventTarget { + [Pure, SetterThrows] + attribute unsigned long width; + [Pure, SetterThrows] + attribute unsigned long height; + + [Throws] + nsISupports? getContext(DOMString contextId, + optional any contextOptions = null); +}; + +// OffscreenCanvas implements Transferable; diff --git a/dom/webidl/WebGLRenderingContext.webidl b/dom/webidl/WebGLRenderingContext.webidl index 1421a0020f8e..3ab31d10a372 100644 --- a/dom/webidl/WebGLRenderingContext.webidl +++ b/dom/webidl/WebGLRenderingContext.webidl @@ -45,24 +45,38 @@ dictionary WebGLContextAttributes { boolean failIfMajorPerformanceCaveat = false; }; +[Exposed=(Window,Worker), + Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLBuffer { }; +[Exposed=(Window,Worker), + Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLFramebuffer { }; +[Exposed=(Window,Worker), + Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLProgram { }; +[Exposed=(Window,Worker), + Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLRenderbuffer { }; +[Exposed=(Window,Worker), + Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLShader { }; +[Exposed=(Window,Worker), + Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLTexture { }; +[Exposed=(Window,Worker), + Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLUniformLocation { }; @@ -70,18 +84,24 @@ interface WebGLUniformLocation { interface WebGLVertexArrayObjectOES { }; +[Exposed=(Window,Worker), + Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLActiveInfo { readonly attribute GLint size; readonly attribute GLenum type; readonly attribute DOMString name; }; +[Exposed=(Window,Worker), + Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLShaderPrecisionFormat { readonly attribute GLint rangeMin; readonly attribute GLint rangeMax; readonly attribute GLint precision; }; +[Exposed=(Window,Worker), + Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLRenderingContext { /* ClearBufferMask */ @@ -504,7 +524,7 @@ interface WebGLRenderingContext { const GLenum BROWSER_DEFAULT_WEBGL = 0x9244; // The canvas might actually be null in some cases, apparently. - readonly attribute HTMLCanvasElement? canvas; + readonly attribute (HTMLCanvasElement or OffscreenCanvas)? canvas; readonly attribute GLsizei drawingBufferWidth; readonly attribute GLsizei drawingBufferHeight; @@ -766,6 +786,14 @@ interface WebGLRenderingContext { void viewport(GLint x, GLint y, GLsizei width, GLsizei height); }; +// For OffscreenCanvas +// Reference: https://wiki.whatwg.org/wiki/OffscreenCanvas +[Exposed=(Window,Worker)] +partial interface WebGLRenderingContext { + [Func="mozilla::dom::OffscreenCanvas::PrefEnabled"] + void commit(); +}; + /*[Constructor(DOMString type, optional WebGLContextEventInit eventInit)] interface WebGLContextEvent : Event { readonly attribute DOMString statusMessage; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 0477391a4eb3..17c7d0be3224 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -344,6 +344,7 @@ WEBIDL_FILES = [ 'OfflineAudioCompletionEvent.webidl', 'OfflineAudioContext.webidl', 'OfflineResourceList.webidl', + 'OffscreenCanvas.webidl', 'OscillatorNode.webidl', 'PaintRequest.webidl', 'PaintRequestList.webidl', diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp index 42d7b95f51cd..4f2a715699b7 100644 --- a/gfx/gl/GLLibraryEGL.cpp +++ b/gfx/gl/GLLibraryEGL.cpp @@ -5,6 +5,7 @@ #include "GLLibraryEGL.h" #include "gfxCrashReporterUtils.h" +#include "gfxUtils.h" #include "mozilla/Preferences.h" #include "mozilla/Assertions.h" #include "nsDirectoryServiceDefs.h" @@ -128,7 +129,9 @@ static bool IsAccelAngleSupported(const nsCOMPtr& gfxInfo) { int32_t angleSupport; - gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBGL_ANGLE, &angleSupport); + gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, + nsIGfxInfo::FEATURE_WEBGL_ANGLE, + &angleSupport); return (angleSupport == nsIGfxInfo::FEATURE_STATUS_OK); } diff --git a/gfx/layers/AsyncCanvasRenderer.h b/gfx/layers/AsyncCanvasRenderer.h index 049443ea84b9..a5af5fea7bfa 100644 --- a/gfx/layers/AsyncCanvasRenderer.h +++ b/gfx/layers/AsyncCanvasRenderer.h @@ -9,8 +9,10 @@ #include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/RefPtr.h" // for nsAutoPtr, nsRefPtr, etc +#include "nsCOMPtr.h" // for nsCOMPtr class nsICanvasRenderingContextInternal; +class nsIThread; namespace mozilla { @@ -82,6 +84,7 @@ public: // canvas' surface texture destructor will deref and destroy it too early RefPtr mGLContext; + nsCOMPtr mActiveThread; private: virtual ~AsyncCanvasRenderer(); diff --git a/gfx/src/gfxCrashReporterUtils.cpp b/gfx/src/gfxCrashReporterUtils.cpp index 69f9cf5074bc..670fe23e2e3a 100644 --- a/gfx/src/gfxCrashReporterUtils.cpp +++ b/gfx/src/gfxCrashReporterUtils.cpp @@ -84,6 +84,22 @@ public: } }; +class AppendAppNotesRunnable : public nsCancelableRunnable { +public: + explicit AppendAppNotesRunnable(nsAutoCString aFeatureStr) + : mFeatureString(aFeatureStr) + { + } + + NS_IMETHOD Run() override { + CrashReporter::AppendAppNotesToCrashReport(mFeatureString); + return NS_OK; + } + +private: + nsCString mFeatureString; +}; + void ScopedGfxFeatureReporter::WriteAppNote(char statusChar) { @@ -102,7 +118,8 @@ ScopedGfxFeatureReporter::WriteAppNote(char statusChar) if (!gFeaturesAlreadyReported->Contains(featureString)) { gFeaturesAlreadyReported->AppendElement(featureString); - CrashReporter::AppendAppNotesToCrashReport(featureString); + nsCOMPtr r = new AppendAppNotesRunnable(featureString); + NS_DispatchToMainThread(r); } } diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 6059111c19da..e0f660d12eb1 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -244,6 +244,7 @@ private: DECL_GFX_PREF(Live, "gfx.layerscope.port", LayerScopePort, int32_t, 23456); // Note that "gfx.logging.level" is defined in Logging.h DECL_GFX_PREF(Once, "gfx.logging.crash.length", GfxLoggingCrashLength, uint32_t, 6); + DECL_GFX_PREF(Live, "gfx.offscreencanvas.enabled", OffscreenCanvasEnabled, bool, false); DECL_GFX_PREF(Live, "gfx.perf-warnings.enabled", PerfWarnings, bool, false); DECL_GFX_PREF(Live, "gfx.SurfaceTexture.detach.enabled", SurfaceTextureDetachEnabled, bool, true); DECL_GFX_PREF(Live, "gfx.testing.device-reset", DeviceResetForTesting, int32_t, 0); @@ -387,12 +388,32 @@ private: DECL_GFX_PREF(Live, "test.mousescroll", MouseScrollTestingEnabled, bool, false); DECL_GFX_PREF(Live, "ui.click_hold_context_menus.delay", UiClickHoldContextMenusDelay, int32_t, 500); - DECL_GFX_PREF(Once, "webgl.angle.force-d3d11", WebGLANGLEForceD3D11, bool, false); - DECL_GFX_PREF(Once, "webgl.angle.try-d3d11", WebGLANGLETryD3D11, bool, false); + + // WebGL (for pref access from Worker threads) + DECL_GFX_PREF(Live, "webgl.all-angle-options", WebGLAllANGLEOptions, bool, false); + DECL_GFX_PREF(Live, "webgl.angle.force-d3d11", WebGLANGLEForceD3D11, bool, false); + DECL_GFX_PREF(Live, "webgl.angle.try-d3d11", WebGLANGLETryD3D11, bool, false); DECL_GFX_PREF(Once, "webgl.angle.force-warp", WebGLANGLEForceWARP, bool, false); + DECL_GFX_PREF(Live, "webgl.bypass-shader-validation", WebGLBypassShaderValidator, bool, true); + DECL_GFX_PREF(Live, "webgl.can-lose-context-in-foreground", WebGLCanLoseContextInForeground, bool, true); + DECL_GFX_PREF(Live, "webgl.default-no-alpha", WebGLDefaultNoAlpha, bool, false); + DECL_GFX_PREF(Live, "webgl.disable-angle", WebGLDisableANGLE, bool, false); + DECL_GFX_PREF(Live, "webgl.disable-extensions", WebGLDisableExtensions, bool, false); + DECL_GFX_PREF(Live, "webgl.disable-fail-if-major-performance-caveat", WebGLDisableFailIfMajorPerformanceCaveat, bool, false); - DECL_GFX_PREF(Once, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false); + DECL_GFX_PREF(Live, "webgl.disabled", WebGLDisabled, bool, false); + + DECL_GFX_PREF(Live, "webgl.enable-draft-extensions", WebGLDraftExtensionsEnabled, bool, false); + DECL_GFX_PREF(Live, "webgl.enable-privileged-extensions", WebGLPrivilegedExtensionsEnabled, bool, false); + DECL_GFX_PREF(Live, "webgl.force-enabled", WebGLForceEnabled, bool, false); + DECL_GFX_PREF(Live, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false); + DECL_GFX_PREF(Live, "webgl.lose-context-on-memory-pressure", WebGLLoseContextOnMemoryPressure, bool, false); + DECL_GFX_PREF(Live, "webgl.max-warnings-per-context", WebGLMaxWarningsPerContext, uint32_t, 32); + DECL_GFX_PREF(Live, "webgl.min_capability_mode", WebGLMinCapabilityMode, bool, false); + DECL_GFX_PREF(Live, "webgl.msaa-force", WebGLForceMSAA, bool, false); + DECL_GFX_PREF(Live, "webgl.prefer-16bpp", WebGLPrefer16bpp, bool, false); + DECL_GFX_PREF(Live, "webgl.restore-context-when-visible", WebGLRestoreWhenVisible, bool, true); // WARNING: // Please make sure that you've added your new preference to the list above in alphabetical order. diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index 2aea00695ebe..421b3dc58b70 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -12,6 +12,8 @@ #include "gfxDrawable.h" #include "imgIEncoder.h" #include "mozilla/Base64.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/WorkerRunnable.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/DataSurfaceHelpers.h" #include "mozilla/gfx/Logging.h" @@ -21,6 +23,7 @@ #include "nsComponentManagerUtils.h" #include "nsIClipboardHelper.h" #include "nsIFile.h" +#include "nsIGfxInfo.h" #include "nsIPresShell.h" #include "nsPresContext.h" #include "nsRegion.h" @@ -1543,6 +1546,62 @@ gfxUtils::CopyAsDataURI(DrawTarget* aDT) } } +class GetFeatureStatusRunnable final : public dom::workers::WorkerMainThreadRunnable +{ +public: + GetFeatureStatusRunnable(dom::workers::WorkerPrivate* workerPrivate, + const nsCOMPtr& gfxInfo, + int32_t feature, + int32_t* status) + : WorkerMainThreadRunnable(workerPrivate) + , mGfxInfo(gfxInfo) + , mFeature(feature) + , mStatus(status) + , mNSResult(NS_OK) + { + } + + bool MainThreadRun() override + { + if (mGfxInfo) { + mNSResult = mGfxInfo->GetFeatureStatus(mFeature, mStatus); + } + return true; + } + + nsresult GetNSResult() const + { + return mNSResult; + } + +protected: + ~GetFeatureStatusRunnable() {} + +private: + nsCOMPtr mGfxInfo; + int32_t mFeature; + int32_t* mStatus; + nsresult mNSResult; +}; + +/* static */ nsresult +gfxUtils::ThreadSafeGetFeatureStatus(const nsCOMPtr& gfxInfo, + int32_t feature, int32_t* status) +{ + if (!NS_IsMainThread()) { + dom::workers::WorkerPrivate* workerPrivate = + dom::workers::GetCurrentThreadWorkerPrivate(); + nsRefPtr runnable = + new GetFeatureStatusRunnable(workerPrivate, gfxInfo, feature, status); + + runnable->Dispatch(workerPrivate->GetJSContext()); + + return runnable->GetNSResult(); + } + + return gfxInfo->GetFeatureStatus(feature, status); +} + /* static */ bool gfxUtils::DumpDisplayList() { return gfxPrefs::LayoutDumpDisplayList(); diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index c1bfcc734c0d..8464d2a32cae 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -17,6 +17,7 @@ class gfxASurface; class gfxDrawable; +class nsIGfxInfo; class nsIntRegion; class nsIPresShell; @@ -281,6 +282,10 @@ public: static nsCString GetAsDataURI(DrawTarget* aDT); static nsCString GetAsLZ4Base64Str(DataSourceSurface* aSourceSurface); + static nsresult ThreadSafeGetFeatureStatus(const nsCOMPtr& gfxInfo, + int32_t feature, + int32_t* status); + /** * Copy to the clipboard as a PNG encoded Data URL. */ diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index a678a18314a0..e4ba2ac7baa4 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -272,6 +272,7 @@ GENERATED_FILES = [ ] LOCAL_INCLUDES += [ + '/dom/workers', '/dom/xml', ] diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 000c6fa970a2..ae589f113b5e 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4165,6 +4165,8 @@ pref("webgl.angle.force-d3d11", false); pref("webgl.angle.force-warp", false); #endif +pref("gfx.offscreencanvas.enabled", false); + #ifdef MOZ_WIDGET_GONK pref("gfx.gralloc.fence-with-readpixels", false); #endif From 5bfbf77ee0ef4bfcfc19f55bafae9d4175c2be09 Mon Sep 17 00:00:00 2001 From: Morris Tseng Date: Tue, 29 Sep 2015 11:51:24 +0100 Subject: [PATCH 028/104] Bug 709490 - Part 3: Transfer OffscreenCanvas from mainthread to workers., r=baku, r=sfink --- dom/base/StructuredCloneHelper.cpp | 50 ++++++++++++++++++++++++++++++ dom/base/StructuredCloneTags.h | 3 ++ js/public/StructuredClone.h | 9 ++++-- js/src/vm/StructuredClone.cpp | 26 +++++++++++++--- 4 files changed, 80 insertions(+), 8 deletions(-) diff --git a/dom/base/StructuredCloneHelper.cpp b/dom/base/StructuredCloneHelper.cpp index 7975e42e1bdc..baad651b0a01 100644 --- a/dom/base/StructuredCloneHelper.cpp +++ b/dom/base/StructuredCloneHelper.cpp @@ -21,6 +21,8 @@ #include "mozilla/dom/StructuredClone.h" #include "mozilla/dom/MessagePort.h" #include "mozilla/dom/MessagePortBinding.h" +#include "mozilla/dom/OffscreenCanvas.h" +#include "mozilla/dom/OffscreenCanvasBinding.h" #include "mozilla/dom/PMessagePort.h" #include "mozilla/dom/StructuredCloneTags.h" #include "mozilla/dom/SubtleCryptoBinding.h" @@ -1062,6 +1064,25 @@ StructuredCloneHelper::ReadTransferCallback(JSContext* aCx, return true; } + if (aTag == SCTAG_DOM_CANVAS) { + MOZ_ASSERT(mContext == SameProcessSameThread || + mContext == SameProcessDifferentThread); + MOZ_ASSERT(aContent); + OffscreenCanvasCloneData* data = + static_cast(aContent); + nsRefPtr canvas = OffscreenCanvas::CreateFromCloneData(data); + delete data; + + JS::Rooted value(aCx); + if (!GetOrCreateDOMReflector(aCx, canvas, &value)) { + JS_ClearPendingException(aCx); + return false; + } + + aReturnObject.set(&value.toObject()); + return true; + } + return false; } @@ -1093,6 +1114,24 @@ StructuredCloneHelper::WriteTransferCallback(JSContext* aCx, return true; } + + if (mContext == SameProcessSameThread || + mContext == SameProcessDifferentThread) { + OffscreenCanvas* canvas = nullptr; + rv = UNWRAP_OBJECT(OffscreenCanvas, aObj, canvas); + if (NS_SUCCEEDED(rv)) { + MOZ_ASSERT(canvas); + + *aExtraData = 0; + *aTag = SCTAG_DOM_CANVAS; + *aOwnership = JS::SCTAG_TMO_CUSTOM; + *aContent = canvas->ToCloneData(); + MOZ_ASSERT(*aContent); + canvas->SetNeutered(); + + return true; + } + } } return false; @@ -1110,6 +1149,17 @@ StructuredCloneHelper::FreeTransferCallback(uint32_t aTag, MOZ_ASSERT(!aContent); MOZ_ASSERT(aExtraData < mPortIdentifiers.Length()); MessagePort::ForceClose(mPortIdentifiers[aExtraData]); + return; + } + + if (aTag == SCTAG_DOM_CANVAS) { + MOZ_ASSERT(mContext == SameProcessSameThread || + mContext == SameProcessDifferentThread); + MOZ_ASSERT(aContent); + OffscreenCanvasCloneData* data = + static_cast(aContent); + delete data; + return; } } diff --git a/dom/base/StructuredCloneTags.h b/dom/base/StructuredCloneTags.h index fe6ccdf371f7..f1fec533d4d6 100644 --- a/dom/base/StructuredCloneTags.h +++ b/dom/base/StructuredCloneTags.h @@ -48,6 +48,9 @@ enum StructuredCloneTags { SCTAG_DOM_FORMDATA, + // This tag is for OffscreenCanvas. + SCTAG_DOM_CANVAS, + SCTAG_DOM_MAX }; diff --git a/js/public/StructuredClone.h b/js/public/StructuredClone.h index e95b4ef8345c..fb72fb3ed6c9 100644 --- a/js/public/StructuredClone.h +++ b/js/public/StructuredClone.h @@ -195,17 +195,20 @@ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) { void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); // Copy some memory. It will be automatically freed by the destructor. - bool copy(const uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION); + bool copy(const uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION, + const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr); // Adopt some memory. It will be automatically freed by the destructor. // data must have been allocated by the JS engine (e.g., extracted via // JSAutoStructuredCloneBuffer::steal). - void adopt(uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION); + void adopt(uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION, + const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr); // Release the buffer and transfer ownership to the caller. The caller is // responsible for calling JS_ClearStructuredClone or feeding the memory // back to JSAutoStructuredCloneBuffer::adopt. - void steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp=nullptr); + void steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp=nullptr, + const JSStructuredCloneCallbacks** callbacks=nullptr, void** closure=nullptr); // Abandon ownership of any transferable objects stored in the buffer, // without freeing the buffer itself. Useful when copying the data out into diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 00c916eb73db..505b3198e6c0 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -2054,7 +2054,7 @@ JS_StructuredClone(JSContext* cx, HandleValue value, MutableHandleValue vp, JSAutoStructuredCloneBuffer::JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other) { ownTransferables_ = other.ownTransferables_; - other.steal(&data_, &nbytes_, &version_); + other.steal(&data_, &nbytes_, &version_, &callbacks_, &closure_); } JSAutoStructuredCloneBuffer& @@ -2063,7 +2063,7 @@ JSAutoStructuredCloneBuffer::operator=(JSAutoStructuredCloneBuffer&& other) MOZ_ASSERT(&other != this); clear(); ownTransferables_ = other.ownTransferables_; - other.steal(&data_, &nbytes_, &version_); + other.steal(&data_, &nbytes_, &version_, &callbacks_, &closure_); return *this; } @@ -2088,7 +2088,9 @@ JSAutoStructuredCloneBuffer::clear(const JSStructuredCloneCallbacks* optionalCal } bool -JSAutoStructuredCloneBuffer::copy(const uint64_t* srcData, size_t nbytes, uint32_t version) +JSAutoStructuredCloneBuffer::copy(const uint64_t* srcData, size_t nbytes, uint32_t version, + const JSStructuredCloneCallbacks* callbacks, + void* closure) { // transferable objects cannot be copied if (StructuredCloneHasTransferObjects(data_, nbytes_)) @@ -2104,31 +2106,45 @@ JSAutoStructuredCloneBuffer::copy(const uint64_t* srcData, size_t nbytes, uint32 data_ = newData; nbytes_ = nbytes; version_ = version; + callbacks_ = callbacks; + closure_ = closure; ownTransferables_ = NoTransferables; return true; } void -JSAutoStructuredCloneBuffer::adopt(uint64_t* data, size_t nbytes, uint32_t version) +JSAutoStructuredCloneBuffer::adopt(uint64_t* data, size_t nbytes, uint32_t version, + const JSStructuredCloneCallbacks* callbacks, + void* closure) { clear(); data_ = data; nbytes_ = nbytes; version_ = version; + callbacks_ = callbacks; + closure_ = closure; ownTransferables_ = OwnsTransferablesIfAny; } void -JSAutoStructuredCloneBuffer::steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp) +JSAutoStructuredCloneBuffer::steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp, + const JSStructuredCloneCallbacks** callbacks, + void** closure) { *datap = data_; *nbytesp = nbytes_; if (versionp) *versionp = version_; + if (callbacks) + *callbacks = callbacks_; + if (closure) + *closure = closure_; data_ = nullptr; nbytes_ = 0; version_ = 0; + callbacks_ = 0; + closure_ = 0; ownTransferables_ = NoTransferables; } From 90b7efb407909be45e691227de36bd1d7d9ffb7a Mon Sep 17 00:00:00 2001 From: Morris Tseng Date: Tue, 29 Sep 2015 11:51:24 +0100 Subject: [PATCH 029/104] Bug 709490 - Part 4: Mochitests for offscreencanvas, r=baku, r=jgilbert --- dom/canvas/test/mochitest.ini | 18 ++ dom/canvas/test/offscreencanvas.js | 274 ++++++++++++++++++ dom/canvas/test/offscreencanvas_neuter.js | 1 + .../offscreencanvas_serviceworker_inner.html | 32 ++ .../test_offscreencanvas_basic_webgl.html | 48 +++ .../test/test_offscreencanvas_many.html | 67 +++++ .../test/test_offscreencanvas_neuter.html | 78 +++++ .../test_offscreencanvas_serviceworker.html | 46 +++ .../test_offscreencanvas_sharedworker.html | 47 +++ .../test/test_offscreencanvas_sizechange.html | 41 +++ .../test/test_offscreencanvas_subworker.html | 90 ++++++ 11 files changed, 742 insertions(+) create mode 100644 dom/canvas/test/offscreencanvas.js create mode 100644 dom/canvas/test/offscreencanvas_neuter.js create mode 100644 dom/canvas/test/offscreencanvas_serviceworker_inner.html create mode 100644 dom/canvas/test/test_offscreencanvas_basic_webgl.html create mode 100644 dom/canvas/test/test_offscreencanvas_many.html create mode 100644 dom/canvas/test/test_offscreencanvas_neuter.html create mode 100644 dom/canvas/test/test_offscreencanvas_serviceworker.html create mode 100644 dom/canvas/test/test_offscreencanvas_sharedworker.html create mode 100644 dom/canvas/test/test_offscreencanvas_sizechange.html create mode 100644 dom/canvas/test/test_offscreencanvas_subworker.html diff --git a/dom/canvas/test/mochitest.ini b/dom/canvas/test/mochitest.ini index ffee4bbb26d5..12b23e2df386 100644 --- a/dom/canvas/test/mochitest.ini +++ b/dom/canvas/test/mochitest.ini @@ -27,6 +27,9 @@ support-files = imagebitmap_on_worker.js imagebitmap_structuredclone.js imagebitmap_structuredclone_iframe.html + offscreencanvas.js + offscreencanvas_neuter.js + offscreencanvas_serviceworker_inner.html [test_2d.clearRect.image.offscreen.html] [test_2d.clip.winding.html] @@ -261,3 +264,18 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # bug 1040965 [test_createPattern_broken.html] [test_setlinedash.html] [test_filter.html] +[test_offscreencanvas_basic_webgl.html] +tags = offscreencanvas +[test_offscreencanvas_sharedworker.html] +tags = offscreencanvas +[test_offscreencanvas_serviceworker.html] +tags = offscreencanvas +skip-if = buildapp == 'b2g' +[test_offscreencanvas_neuter.html] +tags = offscreencanvas +[test_offscreencanvas_many.html] +tags = offscreencanvas +[test_offscreencanvas_sizechange.html] +tags = offscreencanvas +[test_offscreencanvas_subworker.html] +tags = offscreencanvas diff --git a/dom/canvas/test/offscreencanvas.js b/dom/canvas/test/offscreencanvas.js new file mode 100644 index 000000000000..584954c3ef71 --- /dev/null +++ b/dom/canvas/test/offscreencanvas.js @@ -0,0 +1,274 @@ +/* WebWorker for test_offscreencanvas_*.html */ +var port = null; + +function ok(expect, msg) { + if (port) { + port.postMessage({type: "test", result: !!expect, name: msg}); + } else { + postMessage({type: "test", result: !!expect, name: msg}); + } +} + +function finish() { + if (port) { + port.postMessage({type: "finish"}); + } else { + postMessage({type: "finish"}); + } +} + +//-------------------------------------------------------------------- +// WebGL Drawing Functions +//-------------------------------------------------------------------- +function createDrawFunc(canvas) { + var gl; + + try { + gl = canvas.getContext("experimental-webgl"); + } catch (e) {} + + if (!gl) { + ok(false, "WebGL is unavailable"); + return null; + } + + var vertSrc = "attribute vec2 position; \ + void main(void) { \ + gl_Position = vec4(position, 0.0, 1.0); \ + }"; + + var fragSrc = "precision mediump float; \ + void main(void) { \ + gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); \ + }"; + + // Returns a valid shader, or null on errors. + var createShader = function(src, t) { + var shader = gl.createShader(t); + + gl.shaderSource(shader, src); + gl.compileShader(shader); + + return shader; + }; + + var createProgram = function(vsSrc, fsSrc) { + var vs = createShader(vsSrc, gl.VERTEX_SHADER); + var fs = createShader(fsSrc, gl.FRAGMENT_SHADER); + + var prog = gl.createProgram(); + gl.attachShader(prog, vs); + gl.attachShader(prog, fs); + gl.linkProgram(prog); + + if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) { + var str = "Shader program linking failed:"; + str += "\nShader program info log:\n" + gl.getProgramInfoLog(prog); + str += "\n\nVert shader log:\n" + gl.getShaderInfoLog(vs); + str += "\n\nFrag shader log:\n" + gl.getShaderInfoLog(fs); + console.log(str); + ok(false, "Shader program linking failed"); + return null; + } + + return prog; + }; + + gl.disable(gl.DEPTH_TEST); + + var program = createProgram(vertSrc, fragSrc); + ok(program, "Creating shader program"); + + program.positionAttr = gl.getAttribLocation(program, "position"); + ok(program.positionAttr >= 0, "position attribute should be valid"); + + var vertCoordArr = new Float32Array([ + -1, -1, + 1, -1, + -1, 1, + 1, 1, + ]); + var vertCoordBuff = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertCoordBuff); + gl.bufferData(gl.ARRAY_BUFFER, vertCoordArr, gl.STATIC_DRAW); + + var checkGLError = function(prefix, refValue) { + if (!refValue) { + refValue = 0; + } + + var error = gl.getError(); + ok(error == refValue, + prefix + 'gl.getError should be 0x' + refValue.toString(16) + + ', was 0x' + error.toString(16) + '.'); + }; + + var testPixel = function(x, y, refData, infoString) { + var pixel = new Uint8Array(4); + gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel); + + var pixelMatches = pixel[0] == refData[0] && + pixel[1] == refData[1] && + pixel[2] == refData[2] && + pixel[3] == refData[3]; + ok(pixelMatches, infoString); + }; + + var preDraw = function(prefix) { + gl.clearColor(1.0, 0.0, 0.0, 1.0); + gl.clear(gl.COLOR_BUFFER_BIT); + + testPixel(0, 0, [255, 0, 0, 255], prefix + 'Should be red before drawing.'); + }; + + var postDraw = function(prefix) { + testPixel(0, 0, [0, 255, 0, 255], prefix + 'Should be green after drawing.'); + }; + + gl.useProgram(program); + gl.enableVertexAttribArray(program.position); + gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0); + + // Start drawing + checkGLError('after setup'); + + return function(prefix) { + if (prefix) { + prefix = "[" + prefix + "] "; + } else { + prefix = ""; + } + + gl.viewport(0, 0, canvas.width, canvas.height); + + preDraw(prefix); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + postDraw(prefix); + checkGLError(prefix); + }; +} + +/* entry point */ +function entryFunction(testStr, subtests, offscreenCanvas) { + var test = testStr; + var canvas = offscreenCanvas; + + if (test != "subworker") { + ok(canvas, "Canvas successfully transfered to worker"); + ok(canvas.getContext, "Canvas has getContext"); + + ok(canvas.width == 64, "OffscreenCanvas width should be 64"); + ok(canvas.height == 64, "OffscreenCanvas height should be 64"); + } + + var draw; + + //------------------------------------------------------------------------ + // Basic WebGL test + //------------------------------------------------------------------------ + if (test == "webgl") { + draw = createDrawFunc(canvas); + if (!draw) { + finish(); + return; + } + + var count = 0; + var iid = setInterval(function() { + if (count++ > 20) { + clearInterval(iid); + ok(true, "Worker is done"); + finish(); + return; + } + draw("loop " +count); + }, 0); + } + //------------------------------------------------------------------------ + // Canvas Size Change from Worker + //------------------------------------------------------------------------ + else if (test == "webgl_changesize") { + draw = createDrawFunc(canvas); + if (!draw) { + finish(); + return; + } + + draw("64x64"); + + setTimeout(function() { + canvas.width = 128; + canvas.height = 128; + draw("Increased to 128x128"); + + setTimeout(function() { + canvas.width = 32; + canvas.width = 32; + draw("Decreased to 32x32"); + + setTimeout(function() { + canvas.width = 64; + canvas.height = 64; + draw("Increased to 64x64"); + + ok(true, "Worker is done"); + finish(); + }, 0); + }, 0); + }, 0); + } + //------------------------------------------------------------------------ + // Using OffscreenCanvas from sub workers + //------------------------------------------------------------------------ + else if (test == "subworker") { + /* subworker tests take a list of tests to run on children */ + var stillRunning = 0; + subtests.forEach(function (subtest) { + ++stillRunning; + var subworker = new Worker('offscreencanvas.js'); + subworker.onmessage = function(evt) { + /* report finish to parent when all children are finished */ + if (evt.data.type == "finish") { + subworker.terminate(); + if (--stillRunning == 0) { + ok(true, "Worker is done"); + finish(); + } + return; + } + /* relay all other messages to parent */ + postMessage(evt.data); + }; + + var findTransferables = function(t) { + if (t.test == "subworker") { + var result = []; + t.subtests.forEach(function(test) { + result = result.concat(findTransferables(test)); + }); + + return result; + } else { + return [t.canvas]; + } + }; + + subworker.postMessage(subtest, findTransferables(subtest)); + }); + } +}; + +onmessage = function(evt) { + port = evt.ports[0]; + entryFunction(evt.data.test, evt.data.subtests, evt.data.canvas); +}; + +onconnect = function(evt) { + port = evt.ports[0]; + + port.addEventListener('message', function(evt) { + entryFunction(evt.data.test, evt.data.subtests, evt.data.canvas); + }); + + port.start(); +}; diff --git a/dom/canvas/test/offscreencanvas_neuter.js b/dom/canvas/test/offscreencanvas_neuter.js new file mode 100644 index 000000000000..30648d740a15 --- /dev/null +++ b/dom/canvas/test/offscreencanvas_neuter.js @@ -0,0 +1 @@ +/* empty worker for test_offscreencanvas_disable.html */ diff --git a/dom/canvas/test/offscreencanvas_serviceworker_inner.html b/dom/canvas/test/offscreencanvas_serviceworker_inner.html new file mode 100644 index 000000000000..b153f9524a1c --- /dev/null +++ b/dom/canvas/test/offscreencanvas_serviceworker_inner.html @@ -0,0 +1,32 @@ + + + +WebGL in OffscreenCanvas + + + + + + diff --git a/dom/canvas/test/test_offscreencanvas_basic_webgl.html b/dom/canvas/test/test_offscreencanvas_basic_webgl.html new file mode 100644 index 000000000000..dd3ac21e748b --- /dev/null +++ b/dom/canvas/test/test_offscreencanvas_basic_webgl.html @@ -0,0 +1,48 @@ + + + +WebGL in OffscreenCanvas + + + + + + + + diff --git a/dom/canvas/test/test_offscreencanvas_many.html b/dom/canvas/test/test_offscreencanvas_many.html new file mode 100644 index 000000000000..6bf2680c50b2 --- /dev/null +++ b/dom/canvas/test/test_offscreencanvas_many.html @@ -0,0 +1,67 @@ + + + +WebGL in OffscreenCanvas + + + + + + + + diff --git a/dom/canvas/test/test_offscreencanvas_neuter.html b/dom/canvas/test/test_offscreencanvas_neuter.html new file mode 100644 index 000000000000..2af080c7c1ef --- /dev/null +++ b/dom/canvas/test/test_offscreencanvas_neuter.html @@ -0,0 +1,78 @@ + + + +OffscreenCanvas: Test neutering + + + + + + + + diff --git a/dom/canvas/test/test_offscreencanvas_serviceworker.html b/dom/canvas/test/test_offscreencanvas_serviceworker.html new file mode 100644 index 000000000000..c5cfb93db1a3 --- /dev/null +++ b/dom/canvas/test/test_offscreencanvas_serviceworker.html @@ -0,0 +1,46 @@ + + + +WebGL in OffscreenCanvas + + + + + + + diff --git a/dom/canvas/test/test_offscreencanvas_sharedworker.html b/dom/canvas/test/test_offscreencanvas_sharedworker.html new file mode 100644 index 000000000000..28d7ce37c8a3 --- /dev/null +++ b/dom/canvas/test/test_offscreencanvas_sharedworker.html @@ -0,0 +1,47 @@ + + + +WebGL in OffscreenCanvas + + + + + + + + diff --git a/dom/canvas/test/test_offscreencanvas_sizechange.html b/dom/canvas/test/test_offscreencanvas_sizechange.html new file mode 100644 index 000000000000..cecbac348349 --- /dev/null +++ b/dom/canvas/test/test_offscreencanvas_sizechange.html @@ -0,0 +1,41 @@ + + + +WebGL in OffscreenCanvas + + + + + + + + diff --git a/dom/canvas/test/test_offscreencanvas_subworker.html b/dom/canvas/test/test_offscreencanvas_subworker.html new file mode 100644 index 000000000000..b3fbae821c9a --- /dev/null +++ b/dom/canvas/test/test_offscreencanvas_subworker.html @@ -0,0 +1,90 @@ + + + +OffscreenCanvas: Test subworkers + + + + + + + + From bfd37a1ffcb5308a042950540262462a1cc21d1a Mon Sep 17 00:00:00 2001 From: Morris Tseng Date: Tue, 29 Sep 2015 11:51:24 +0100 Subject: [PATCH 030/104] Bug 709490 - Part 5: Add interfaces test, r=ehsan --- .../mochitest/general/test_interfaces.html | 2 ++ dom/workers/test/test_worker_interfaces.js | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 948e8cb943f6..5ebd8541fccd 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -872,6 +872,8 @@ var interfaceNamesInGlobalScope = "Notification", // IMPORTANT: Do not change this list without review from a DOM peer! "NotifyPaintEvent", +// IMPORTANT: Do not change this list without review from a DOM peer! + {name: "OffscreenCanvas", disabled: true}, // IMPORTANT: Do not change this list without review from a DOM peer! "OfflineAudioCompletionEvent", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js index 1af06353495e..506669c09fde 100644 --- a/dom/workers/test/test_worker_interfaces.js +++ b/dom/workers/test/test_worker_interfaces.js @@ -155,6 +155,8 @@ var interfaceNamesInGlobalScope = "MessagePort", // IMPORTANT: Do not change this list without review from a DOM peer! "Notification", +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "OffscreenCanvas", disabled: true }, // IMPORTANT: Do not change this list without review from a DOM peer! "Performance", // IMPORTANT: Do not change this list without review from a DOM peer! @@ -189,6 +191,26 @@ var interfaceNamesInGlobalScope = "URL", // IMPORTANT: Do not change this list without review from a DOM peer! "URLSearchParams", +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "WebGLActiveInfo", disabled: true }, +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "WebGLBuffer", disabled: true }, +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "WebGLFramebuffer", disabled: true }, +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "WebGLProgram", disabled: true }, +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "WebGLRenderbuffer", disabled: true }, +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "WebGLRenderingContext", disabled: true }, +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "WebGLShader", disabled: true }, +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "WebGLShaderPrecisionFormat", disabled: true }, +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "WebGLTexture", disabled: true }, +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "WebGLUniformLocation", disabled: true }, // IMPORTANT: Do not change this list without review from a DOM peer! "WebSocket", // IMPORTANT: Do not change this list without review from a DOM peer! From 2b5f7394c937abaf2e9abcca79cbf41384900d55 Mon Sep 17 00:00:00 2001 From: Morris Tseng Date: Tue, 29 Sep 2015 11:51:24 +0100 Subject: [PATCH 031/104] Bug 709490 - Part 6: Add frame ID to CanvasClient so compositor could update frame correctly, r=roc --- gfx/layers/LayerTreeInvalidation.cpp | 31 +++++++++++++++++++++++++++- gfx/layers/client/CanvasClient.cpp | 2 ++ gfx/layers/client/CanvasClient.h | 12 ++++++++++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/gfx/layers/LayerTreeInvalidation.cpp b/gfx/layers/LayerTreeInvalidation.cpp index 8c2a45921cf6..65ea0b9f48e0 100644 --- a/gfx/layers/LayerTreeInvalidation.cpp +++ b/gfx/layers/LayerTreeInvalidation.cpp @@ -385,7 +385,7 @@ struct ColorLayerProperties : public LayerPropertiesBase IntRect mBounds; }; -static ImageHost* GetImageHost(ImageLayer* aLayer) +static ImageHost* GetImageHost(Layer* aLayer) { LayerComposite* composite = aLayer->AsLayerComposite(); if (composite) { @@ -465,6 +465,34 @@ struct ImageLayerProperties : public LayerPropertiesBase bool mIsMask; }; +struct CanvasLayerProperties : public LayerPropertiesBase +{ + explicit CanvasLayerProperties(CanvasLayer* aCanvas) + : LayerPropertiesBase(aCanvas) + , mImageHost(GetImageHost(aCanvas)) + { + mFrameID = mImageHost ? mImageHost->GetFrameID() : -1; + } + + virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback, + bool& aGeometryChanged) + { + CanvasLayer* canvasLayer = static_cast(mLayer.get()); + + ImageHost* host = GetImageHost(canvasLayer); + if (host && host->GetFrameID() != mFrameID) { + aGeometryChanged = true; + + return NewTransformedBounds(); + } + + return IntRect(); + } + + nsRefPtr mImageHost; + int32_t mFrameID; +}; + UniquePtr CloneLayerTreePropertiesInternal(Layer* aRoot, bool aIsMask /* = false */) { @@ -483,6 +511,7 @@ CloneLayerTreePropertiesInternal(Layer* aRoot, bool aIsMask /* = false */) case Layer::TYPE_IMAGE: return MakeUnique(static_cast(aRoot), aIsMask); case Layer::TYPE_CANVAS: + return MakeUnique(static_cast(aRoot)); case Layer::TYPE_READBACK: case Layer::TYPE_SHADOW: case Layer::TYPE_PAINTED: diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index b6f0b5dabebb..765c9e17b55a 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -125,6 +125,7 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) CompositableForwarder::TimedTextureClient* t = textures.AppendElement(); t->mTextureClient = mBuffer; t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mBuffer->GetSize()); + t->mFrameID = mFrameID; GetForwarder()->UseTextures(this, textures); mBuffer->SyncWithObject(GetForwarder()->GetSyncObject()); } @@ -459,6 +460,7 @@ CanvasClientSharedSurface::Updated() CompositableForwarder::TimedTextureClient* t = textures.AppendElement(); t->mTextureClient = mFront; t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mFront->GetSize()); + t->mFrameID = mFrameID; forwarder->UseTextures(this, textures); } diff --git a/gfx/layers/client/CanvasClient.h b/gfx/layers/client/CanvasClient.h index 539ff85cbb67..7a8a17485156 100644 --- a/gfx/layers/client/CanvasClient.h +++ b/gfx/layers/client/CanvasClient.h @@ -57,6 +57,7 @@ public: CanvasClient(CompositableForwarder* aFwd, TextureFlags aFlags) : CompositableClient(aFwd, aFlags) + , mFrameID(0) { mTextureFlags = aFlags; } @@ -67,9 +68,18 @@ public: virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) = 0; + virtual bool AddTextureClient(TextureClient* aTexture) override + { + ++mFrameID; + return CompositableClient::AddTextureClient(aTexture); + } + virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) {} virtual void Updated() { } + +protected: + int32_t mFrameID; }; // Used for 2D canvases and WebGL canvas on non-GL systems where readback is requried. @@ -97,7 +107,7 @@ public: virtual bool AddTextureClient(TextureClient* aTexture) override { MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags); - return CompositableClient::AddTextureClient(aTexture); + return CanvasClient::AddTextureClient(aTexture); } virtual void OnDetach() override From c5927f2daea867efa5a903a3c74c3d10fa96e076 Mon Sep 17 00:00:00 2001 From: Morris Tseng Date: Tue, 29 Sep 2015 11:51:25 +0100 Subject: [PATCH 032/104] Bug 709490 - Part 7: If layer is not available, fallback to BasicCanvasLayer, r=roc --- dom/base/ImageEncoder.cpp | 13 ++- dom/base/ImageEncoder.h | 5 +- dom/canvas/OffscreenCanvas.cpp | 78 ++++++++++----- dom/canvas/OffscreenCanvas.h | 13 +++ dom/canvas/WebGLContext.cpp | 57 +++-------- dom/canvas/test/mochitest.ini | 3 + dom/canvas/test/offscreencanvas.js | 25 +++++ dom/canvas/test/offscreencanvas_mask.svg | 11 +++ .../test_offscreencanvas_basic_webgl.html | 14 +++ ...test_offscreencanvas_dynamic_fallback.html | 80 +++++++++++++++ dom/html/HTMLCanvasElement.cpp | 56 +++++++++-- dom/html/HTMLCanvasElement.h | 5 + gfx/gl/GLReadTexImageHelper.cpp | 8 +- gfx/gl/GLReadTexImageHelper.h | 3 + gfx/layers/AsyncCanvasRenderer.cpp | 99 ++++++++++++++++++- gfx/layers/AsyncCanvasRenderer.h | 61 +++++++++++- gfx/layers/CopyableCanvasLayer.cpp | 15 +-- gfx/layers/Layers.cpp | 6 -- gfx/layers/Layers.h | 6 +- gfx/layers/basic/BasicCanvasLayer.cpp | 1 + gfx/thebes/gfxUtils.cpp | 64 ++++++++++++ gfx/thebes/gfxUtils.h | 12 +++ 22 files changed, 534 insertions(+), 101 deletions(-) create mode 100644 dom/canvas/test/offscreencanvas_mask.svg create mode 100644 dom/canvas/test/test_offscreencanvas_dynamic_fallback.html diff --git a/dom/base/ImageEncoder.cpp b/dom/base/ImageEncoder.cpp index 366d26ef117d..74dff8734e46 100644 --- a/dom/base/ImageEncoder.cpp +++ b/dom/base/ImageEncoder.cpp @@ -8,6 +8,7 @@ #include "mozilla/dom/CanvasRenderingContext2D.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/DataSurfaceHelpers.h" +#include "mozilla/layers/AsyncCanvasRenderer.h" #include "mozilla/RefPtr.h" #include "mozilla/SyncRunnable.h" #include "mozilla/unused.h" @@ -165,6 +166,7 @@ public: mSize, mImage, nullptr, + nullptr, getter_AddRefs(stream), mEncoder); @@ -178,6 +180,7 @@ public: mSize, mImage, nullptr, + nullptr, getter_AddRefs(stream), mEncoder); } @@ -234,6 +237,7 @@ ImageEncoder::ExtractData(nsAString& aType, const nsAString& aOptions, const nsIntSize aSize, nsICanvasRenderingContextInternal* aContext, + layers::AsyncCanvasRenderer* aRenderer, nsIInputStream** aStream) { nsCOMPtr encoder = ImageEncoder::GetImageEncoder(aType); @@ -242,10 +246,9 @@ ImageEncoder::ExtractData(nsAString& aType, } return ExtractDataInternal(aType, aOptions, nullptr, 0, aSize, nullptr, - aContext, aStream, encoder); + aContext, aRenderer, aStream, encoder); } - /* static */ nsresult ImageEncoder::ExtractDataFromLayersImageAsync(nsAString& aType, @@ -341,6 +344,7 @@ ImageEncoder::ExtractDataInternal(const nsAString& aType, const nsIntSize aSize, layers::Image* aImage, nsICanvasRenderingContextInternal* aContext, + layers::AsyncCanvasRenderer* aRenderer, nsIInputStream** aStream, imgIEncoder* aEncoder) { @@ -366,6 +370,11 @@ ImageEncoder::ExtractDataInternal(const nsAString& aType, rv = aContext->GetInputStream(encoderType.get(), nsPromiseFlatString(aOptions).get(), getter_AddRefs(imgStream)); + } else if (aRenderer) { + NS_ConvertUTF16toUTF8 encoderType(aType); + rv = aRenderer->GetInputStream(encoderType.get(), + nsPromiseFlatString(aOptions).get(), + getter_AddRefs(imgStream)); } else if (aImage) { // It is safe to convert PlanarYCbCr format from YUV to RGB off-main-thread. // Other image formats could have problem to convert format off-main-thread. diff --git a/dom/base/ImageEncoder.h b/dom/base/ImageEncoder.h index fe3522daff55..a38bbd209140 100644 --- a/dom/base/ImageEncoder.h +++ b/dom/base/ImageEncoder.h @@ -19,6 +19,7 @@ class nsICanvasRenderingContextInternal; namespace mozilla { namespace layers { +class AsyncCanvasRenderer; class Image; } // namespace layers @@ -40,6 +41,7 @@ public: const nsAString& aOptions, const nsIntSize aSize, nsICanvasRenderingContextInternal* aContext, + layers::AsyncCanvasRenderer* aRenderer, nsIInputStream** aStream); // Extracts data asynchronously. aType may change to "image/png" if we had to @@ -84,7 +86,7 @@ public: nsIInputStream** aStream); private: - // When called asynchronously, aContext is null. + // When called asynchronously, aContext and aRenderer are null. static nsresult ExtractDataInternal(const nsAString& aType, const nsAString& aOptions, @@ -93,6 +95,7 @@ private: const nsIntSize aSize, layers::Image* aImage, nsICanvasRenderingContextInternal* aContext, + layers::AsyncCanvasRenderer* aRenderer, nsIInputStream** aStream, imgIEncoder* aEncoder); diff --git a/dom/canvas/OffscreenCanvas.cpp b/dom/canvas/OffscreenCanvas.cpp index 8489ca9e2803..79e4806d7521 100644 --- a/dom/canvas/OffscreenCanvas.cpp +++ b/dom/canvas/OffscreenCanvas.cpp @@ -23,10 +23,12 @@ namespace dom { OffscreenCanvasCloneData::OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer, uint32_t aWidth, uint32_t aHeight, + layers::LayersBackend aCompositorBackend, bool aNeutered) : mRenderer(aRenderer) , mWidth(aWidth) , mHeight(aHeight) + , mCompositorBackendType(aCompositorBackend) , mNeutered(aNeutered) { } @@ -37,26 +39,20 @@ OffscreenCanvasCloneData::~OffscreenCanvasCloneData() OffscreenCanvas::OffscreenCanvas(uint32_t aWidth, uint32_t aHeight, + layers::LayersBackend aCompositorBackend, layers::AsyncCanvasRenderer* aRenderer) : mAttrDirty(false) , mNeutered(false) , mWidth(aWidth) , mHeight(aHeight) + , mCompositorBackendType(aCompositorBackend) , mCanvasClient(nullptr) , mCanvasRenderer(aRenderer) {} OffscreenCanvas::~OffscreenCanvas() { - if (mCanvasRenderer) { - mCanvasRenderer->SetCanvasClient(nullptr); - mCanvasRenderer->mContext = nullptr; - mCanvasRenderer->mActiveThread = nullptr; - } - - if (mCanvasClient) { - ImageBridgeChild::DispatchReleaseCanvasClient(mCanvasClient); - } + ClearResources(); } OffscreenCanvas* @@ -72,6 +68,26 @@ OffscreenCanvas::WrapObject(JSContext* aCx, return OffscreenCanvasBinding::Wrap(aCx, this, aGivenProto); } +void +OffscreenCanvas::ClearResources() +{ + if (mCanvasClient) { + mCanvasClient->Clear(); + ImageBridgeChild::DispatchReleaseCanvasClient(mCanvasClient); + mCanvasClient = nullptr; + + if (mCanvasRenderer) { + nsCOMPtr activeThread = mCanvasRenderer->GetActiveThread(); + MOZ_RELEASE_ASSERT(activeThread); + MOZ_RELEASE_ASSERT(activeThread == NS_GetCurrentThread()); + mCanvasRenderer->SetCanvasClient(nullptr); + mCanvasRenderer->mContext = nullptr; + mCanvasRenderer->mGLContext = nullptr; + mCanvasRenderer->ResetActiveThread(); + } + } +} + already_AddRefed OffscreenCanvas::GetContext(JSContext* aCx, const nsAString& aContextId, @@ -103,26 +119,34 @@ OffscreenCanvas::GetContext(JSContext* aCx, aContextOptions, aRv); - if (mCanvasRenderer && mCurrentContext && ImageBridgeChild::IsCreated()) { - TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT; + if (!mCurrentContext) { + return nullptr; + } - mCanvasClient = ImageBridgeChild::GetSingleton()-> - CreateCanvasClient(CanvasClient::CanvasClientTypeShSurf, flags).take(); - mCanvasRenderer->SetCanvasClient(mCanvasClient); - gl::GLContext* gl = static_cast(mCurrentContext.get())->GL(); + if (mCanvasRenderer) { + WebGLContext* webGL = static_cast(mCurrentContext.get()); + gl::GLContext* gl = webGL->GL(); mCanvasRenderer->mContext = mCurrentContext; - mCanvasRenderer->mActiveThread = NS_GetCurrentThread(); + mCanvasRenderer->SetActiveThread(); mCanvasRenderer->mGLContext = gl; + mCanvasRenderer->SetIsAlphaPremultiplied(webGL->IsPremultAlpha() || !gl->Caps().alpha); - gl::GLScreenBuffer* screen = gl->Screen(); - gl::SurfaceCaps caps = screen->mCaps; - auto forwarder = mCanvasClient->GetForwarder(); + if (ImageBridgeChild::IsCreated()) { + TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT; + mCanvasClient = ImageBridgeChild::GetSingleton()-> + CreateCanvasClient(CanvasClient::CanvasClientTypeShSurf, flags).take(); + mCanvasRenderer->SetCanvasClient(mCanvasClient); - UniquePtr factory = - gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags); + gl::GLScreenBuffer* screen = gl->Screen(); + gl::SurfaceCaps caps = screen->mCaps; + auto forwarder = mCanvasClient->GetForwarder(); - if (factory) - screen->Morph(Move(factory)); + UniquePtr factory = + gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags); + + if (factory) + screen->Morph(Move(factory)); + } } return result; @@ -157,6 +181,7 @@ OffscreenCanvas::CommitFrameToCompositor() } if (mCanvasRenderer && mCanvasRenderer->mGLContext) { + mCanvasRenderer->NotifyElementAboutInvalidation(); ImageBridgeChild::GetSingleton()-> UpdateAsyncCanvasRenderer(mCanvasRenderer); } @@ -165,8 +190,8 @@ OffscreenCanvas::CommitFrameToCompositor() OffscreenCanvasCloneData* OffscreenCanvas::ToCloneData() { - return new OffscreenCanvasCloneData(mCanvasRenderer, mWidth, - mHeight, mNeutered); + return new OffscreenCanvasCloneData(mCanvasRenderer, mWidth, mHeight, + mCompositorBackendType, mNeutered); } /* static */ already_AddRefed @@ -174,7 +199,8 @@ OffscreenCanvas::CreateFromCloneData(OffscreenCanvasCloneData* aData) { MOZ_ASSERT(aData); nsRefPtr wc = - new OffscreenCanvas(aData->mWidth, aData->mHeight, aData->mRenderer); + new OffscreenCanvas(aData->mWidth, aData->mHeight, + aData->mCompositorBackendType, aData->mRenderer); if (aData->mNeutered) { wc->SetNeutered(); } diff --git a/dom/canvas/OffscreenCanvas.h b/dom/canvas/OffscreenCanvas.h index f2bddd0af01c..cdad6bcce8e7 100644 --- a/dom/canvas/OffscreenCanvas.h +++ b/dom/canvas/OffscreenCanvas.h @@ -8,6 +8,7 @@ #define MOZILLA_DOM_OFFSCREENCANVAS_H_ #include "mozilla/DOMEventTargetHelper.h" +#include "mozilla/layers/LayersTypes.h" #include "mozilla/RefPtr.h" #include "CanvasRenderingContextHelper.h" #include "nsCycleCollectionParticipant.h" @@ -33,12 +34,14 @@ struct OffscreenCanvasCloneData final { OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer, uint32_t aWidth, uint32_t aHeight, + layers::LayersBackend aCompositorBackend, bool aNeutered); ~OffscreenCanvasCloneData(); RefPtr mRenderer; uint32_t mWidth; uint32_t mHeight; + layers::LayersBackend mCompositorBackendType; bool mNeutered; }; @@ -51,6 +54,7 @@ public: OffscreenCanvas(uint32_t aWidth, uint32_t aHeight, + layers::LayersBackend aCompositorBackend, layers::AsyncCanvasRenderer* aRenderer); OffscreenCanvas* GetParentObject() const; @@ -58,6 +62,8 @@ public: virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + void ClearResources(); + uint32_t Width() const { return mWidth; @@ -141,6 +147,11 @@ public: return mNeutered; } + layers::LayersBackend GetCompositorBackendType() const + { + return mCompositorBackendType; + } + private: ~OffscreenCanvas(); @@ -156,6 +167,8 @@ private: uint32_t mWidth; uint32_t mHeight; + layers::LayersBackend mCompositorBackendType; + layers::CanvasClient* mCanvasClient; RefPtr mCanvasRenderer; }; diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 61996962d814..82cfe5be87d5 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -1066,32 +1066,8 @@ WebGLContext::GetImageBuffer(uint8_t** out_imageBuffer, int32_t* out_format) RefPtr dataSurface = snapshot->GetDataSurface(); - DataSourceSurface::MappedSurface map; - if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) - return; - - uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4]; - if (!imageBuffer) { - dataSurface->Unmap(); - return; - } - memcpy(imageBuffer, map.mData, mWidth * mHeight * 4); - - dataSurface->Unmap(); - - int32_t format = imgIEncoder::INPUT_FORMAT_HOSTARGB; - if (!mOptions.premultipliedAlpha) { - // We need to convert to INPUT_FORMAT_RGBA, otherwise - // we are automatically considered premult, and unpremult'd. - // Yes, it is THAT silly. - // Except for different lossy conversions by color, - // we could probably just change the label, and not change the data. - gfxUtils::ConvertBGRAtoRGBA(imageBuffer, mWidth * mHeight * 4); - format = imgIEncoder::INPUT_FORMAT_RGBA; - } - - *out_imageBuffer = imageBuffer; - *out_format = format; + return gfxUtils::GetImageBuffer(dataSurface, mOptions.premultipliedAlpha, + out_imageBuffer, out_format); } NS_IMETHODIMP @@ -1103,20 +1079,18 @@ WebGLContext::GetInputStream(const char* mimeType, if (!gl) return NS_ERROR_FAILURE; - nsCString enccid("@mozilla.org/image/encoder;2?type="); - enccid += mimeType; - nsCOMPtr encoder = do_CreateInstance(enccid.get()); - if (!encoder) + // Use GetSurfaceSnapshot() to make sure that appropriate y-flip gets applied + bool premult; + RefPtr snapshot = + GetSurfaceSnapshot(mOptions.premultipliedAlpha ? nullptr : &premult); + if (!snapshot) return NS_ERROR_FAILURE; - nsAutoArrayPtr imageBuffer; - int32_t format = 0; - GetImageBuffer(getter_Transfers(imageBuffer), &format); - if (!imageBuffer) - return NS_ERROR_FAILURE; + MOZ_ASSERT(mOptions.premultipliedAlpha || !premult, "We must get unpremult when we ask for it!"); - return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer, format, - encoder, encoderOptions, out_stream); + RefPtr dataSurface = snapshot->GetDataSurface(); + return gfxUtils::GetInputStream(dataSurface, mOptions.premultipliedAlpha, mimeType, + encoderOptions, out_stream); } void @@ -1236,11 +1210,12 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder, layers::LayersBackend WebGLContext::GetCompositorBackendType() const { - nsIWidget* docWidget = nsContentUtils::WidgetForDocument(mCanvasElement->OwnerDoc()); - if (docWidget) { - layers::LayerManager* layerManager = docWidget->GetLayerManager(); - return layerManager->GetCompositorBackendType(); + if (mCanvasElement) { + return mCanvasElement->GetCompositorBackendType(); + } else if (mOffscreenCanvas) { + return mOffscreenCanvas->GetCompositorBackendType(); } + return LayersBackend::LAYERS_NONE; } diff --git a/dom/canvas/test/mochitest.ini b/dom/canvas/test/mochitest.ini index 12b23e2df386..01565543a663 100644 --- a/dom/canvas/test/mochitest.ini +++ b/dom/canvas/test/mochitest.ini @@ -28,6 +28,7 @@ support-files = imagebitmap_structuredclone.js imagebitmap_structuredclone_iframe.html offscreencanvas.js + offscreencanvas_mask.svg offscreencanvas_neuter.js offscreencanvas_serviceworker_inner.html @@ -266,6 +267,8 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # bug 1040965 [test_filter.html] [test_offscreencanvas_basic_webgl.html] tags = offscreencanvas +[test_offscreencanvas_dynamic_fallback.html] +tags = offscreencanvas [test_offscreencanvas_sharedworker.html] tags = offscreencanvas [test_offscreencanvas_serviceworker.html] diff --git a/dom/canvas/test/offscreencanvas.js b/dom/canvas/test/offscreencanvas.js index 584954c3ef71..6dec8220f462 100644 --- a/dom/canvas/test/offscreencanvas.js +++ b/dom/canvas/test/offscreencanvas.js @@ -17,6 +17,14 @@ function finish() { } } +function drawCount(count) { + if (port) { + port.postMessage({type: "draw", count: count}); + } else { + postMessage({type: "draw", count: count}); + } +} + //-------------------------------------------------------------------- // WebGL Drawing Functions //-------------------------------------------------------------------- @@ -144,6 +152,7 @@ function createDrawFunc(canvas) { preDraw(prefix); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); postDraw(prefix); + gl.commit(); checkGLError(prefix); }; } @@ -185,6 +194,22 @@ function entryFunction(testStr, subtests, offscreenCanvas) { }, 0); } //------------------------------------------------------------------------ + // Test dynamic fallback + //------------------------------------------------------------------------ + else if (test == "webgl_fallback") { + draw = createDrawFunc(canvas); + if (!draw) { + return; + } + + var count = 0; + var iid = setInterval(function() { + ++count; + draw("loop " + count); + drawCount(count); + }, 0); + } + //------------------------------------------------------------------------ // Canvas Size Change from Worker //------------------------------------------------------------------------ else if (test == "webgl_changesize") { diff --git a/dom/canvas/test/offscreencanvas_mask.svg b/dom/canvas/test/offscreencanvas_mask.svg new file mode 100644 index 000000000000..34347b68b37b --- /dev/null +++ b/dom/canvas/test/offscreencanvas_mask.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/dom/canvas/test/test_offscreencanvas_basic_webgl.html b/dom/canvas/test/test_offscreencanvas_basic_webgl.html index dd3ac21e748b..55b186812050 100644 --- a/dom/canvas/test/test_offscreencanvas_basic_webgl.html +++ b/dom/canvas/test/test_offscreencanvas_basic_webgl.html @@ -7,10 +7,23 @@ + + + + + + + + diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp index e37569ec210a..288903a5133c 100644 --- a/dom/html/HTMLCanvasElement.cpp +++ b/dom/html/HTMLCanvasElement.cpp @@ -350,6 +350,7 @@ NS_IMPL_ISUPPORTS(HTMLCanvasElementObserver, nsIObserver) HTMLCanvasElement::HTMLCanvasElement(already_AddRefed& aNodeInfo) : nsGenericHTMLElement(aNodeInfo), + mResetLayer(true) , mWriteOnly(false) { } @@ -690,6 +691,7 @@ HTMLCanvasElement::ExtractData(nsAString& aType, aOptions, GetSize(), mCurrentContext, + mAsyncCanvasRenderer, aStream); } @@ -773,7 +775,10 @@ HTMLCanvasElement::TransferControlToOffscreen(ErrorResult& aRv) renderer->SetWidth(sz.width); renderer->SetHeight(sz.height); - mOffscreenCanvas = new OffscreenCanvas(sz.width, sz.height, renderer); + mOffscreenCanvas = new OffscreenCanvas(sz.width, + sz.height, + GetCompositorBackendType(), + renderer); mContextObserver = new HTMLCanvasElementObserver(this); } else { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); @@ -1042,7 +1047,8 @@ HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder, } if (mOffscreenCanvas) { - if (aOldLayer && aOldLayer->HasUserData(&sOffscreenCanvasLayerUserDataDummy)) { + if (!mResetLayer && + aOldLayer && aOldLayer->HasUserData(&sOffscreenCanvasLayerUserDataDummy)) { nsRefPtr ret = aOldLayer; return ret.forget(); } @@ -1055,7 +1061,12 @@ HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder, LayerUserData* userData = nullptr; layer->SetUserData(&sOffscreenCanvasLayerUserDataDummy, userData); - layer->SetAsyncRenderer(GetAsyncCanvasRenderer()); + + CanvasLayer::Data data; + data.mRenderer = GetAsyncCanvasRenderer(); + data.mSize = GetWidthHeight(); + layer->Initialize(data); + layer->Updated(); return layer.forget(); } @@ -1201,6 +1212,18 @@ HTMLCanvasElement::GetAsyncCanvasRenderer() return mAsyncCanvasRenderer; } +layers::LayersBackend +HTMLCanvasElement::GetCompositorBackendType() const +{ + nsIWidget* docWidget = nsContentUtils::WidgetForDocument(OwnerDoc()); + if (docWidget) { + layers::LayerManager* layerManager = docWidget->GetLayerManager(); + return layerManager->GetCompositorBackendType(); + } + + return LayersBackend::LAYERS_NONE; +} + void HTMLCanvasElement::OnVisibilityChange() { @@ -1235,8 +1258,9 @@ HTMLCanvasElement::OnVisibilityChange() }; nsRefPtr runnable = new Runnable(mAsyncCanvasRenderer); - if (mAsyncCanvasRenderer->mActiveThread) { - mAsyncCanvasRenderer->mActiveThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL); + nsCOMPtr activeThread = mAsyncCanvasRenderer->GetActiveThread(); + if (activeThread) { + activeThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL); } return; } @@ -1276,8 +1300,9 @@ HTMLCanvasElement::OnMemoryPressure() }; nsRefPtr runnable = new Runnable(mAsyncCanvasRenderer); - if (mAsyncCanvasRenderer->mActiveThread) { - mAsyncCanvasRenderer->mActiveThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL); + nsCOMPtr activeThread = mAsyncCanvasRenderer->GetActiveThread(); + if (activeThread) { + activeThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL); } return; } @@ -1295,6 +1320,10 @@ HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer return; } + if (element->GetWidthHeight() == aRenderer->GetSize()) { + return; + } + gfx::IntSize asyncCanvasSize = aRenderer->GetSize(); ErrorResult rv; @@ -1307,6 +1336,19 @@ HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer if (rv.Failed()) { NS_WARNING("Failed to set height attribute to a canvas element asynchronously."); } + + element->mResetLayer = true; +} + +/* static */ void +HTMLCanvasElement::InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer) +{ + HTMLCanvasElement *element = aRenderer->mHTMLCanvasElement; + if (!element) { + return; + } + + element->InvalidateCanvasContent(nullptr); } } // namespace dom diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h index 129ec0fe2c4f..c149c5aa55d5 100644 --- a/dom/html/HTMLCanvasElement.h +++ b/dom/html/HTMLCanvasElement.h @@ -18,6 +18,7 @@ #include "mozilla/dom/CanvasRenderingContextHelper.h" #include "mozilla/gfx/Rect.h" +#include "mozilla/layers/LayersTypes.h" class nsICanvasRenderingContextInternal; class nsITimerCallback; @@ -330,11 +331,14 @@ public: nsresult GetContext(const nsAString& aContextId, nsISupports** aContext); + layers::LayersBackend GetCompositorBackendType() const; + void OnVisibilityChange(); void OnMemoryPressure(); static void SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer); + static void InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer); protected: virtual ~HTMLCanvasElement(); @@ -360,6 +364,7 @@ protected: AsyncCanvasRenderer* GetAsyncCanvasRenderer(); + bool mResetLayer; nsRefPtr mOriginalCanvas; nsRefPtr mPrintCallback; nsRefPtr mPrintState; diff --git a/gfx/gl/GLReadTexImageHelper.cpp b/gfx/gl/GLReadTexImageHelper.cpp index d93b4914937f..0efea4c92eec 100644 --- a/gfx/gl/GLReadTexImageHelper.cpp +++ b/gfx/gl/GLReadTexImageHelper.cpp @@ -533,8 +533,8 @@ ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest) #endif } -static already_AddRefed -YInvertImageSurface(DataSourceSurface* aSurf) +already_AddRefed +YInvertImageSurface(gfx::DataSourceSurface* aSurf) { RefPtr temp = Factory::CreateDataSourceSurfaceWithStride(aSurf->GetSize(), @@ -560,8 +560,8 @@ YInvertImageSurface(DataSourceSurface* aSurf) return nullptr; } - dt->SetTransform(Matrix::Translation(0.0, aSurf->GetSize().height) * - Matrix::Scaling(1.0, -1.0)); + dt->SetTransform(Matrix::Scaling(1.0, -1.0) * + Matrix::Translation(0.0, aSurf->GetSize().height)); Rect rect(0, 0, aSurf->GetSize().width, aSurf->GetSize().height); dt->DrawSurface(aSurf, rect, rect, DrawSurfaceOptions(), DrawOptions(1.0, CompositionOp::OP_SOURCE, AntialiasMode::NONE)); diff --git a/gfx/gl/GLReadTexImageHelper.h b/gfx/gl/GLReadTexImageHelper.h index 821c003a96a1..7adc4edba482 100644 --- a/gfx/gl/GLReadTexImageHelper.h +++ b/gfx/gl/GLReadTexImageHelper.h @@ -34,6 +34,9 @@ void ReadPixelsIntoDataSurface(GLContext* aGL, already_AddRefed ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat); +already_AddRefed +YInvertImageSurface(gfx::DataSourceSurface* aSurf); + class GLReadTexImageHelper final { // The GLContext is the sole owner of the GLBlitHelper. diff --git a/gfx/layers/AsyncCanvasRenderer.cpp b/gfx/layers/AsyncCanvasRenderer.cpp index 951188b75418..755da24a6c9e 100644 --- a/gfx/layers/AsyncCanvasRenderer.cpp +++ b/gfx/layers/AsyncCanvasRenderer.cpp @@ -8,8 +8,12 @@ #include "gfxUtils.h" #include "GLContext.h" +#include "GLReadTexImageHelper.h" +#include "GLScreenBuffer.h" #include "mozilla/dom/HTMLCanvasElement.h" #include "mozilla/layers/CanvasClient.h" +#include "mozilla/layers/TextureClientSharedSurface.h" +#include "mozilla/ReentrantMonitor.h" #include "nsIRunnable.h" #include "nsThreadUtils.h" @@ -17,10 +21,15 @@ namespace mozilla { namespace layers { AsyncCanvasRenderer::AsyncCanvasRenderer() - : mWidth(0) + : mHTMLCanvasElement(nullptr) + , mContext(nullptr) + , mGLContext(nullptr) + , mIsAlphaPremultiplied(true) + , mWidth(0) , mHeight(0) , mCanvasClientAsyncID(0) , mCanvasClient(nullptr) + , mMutex("AsyncCanvasRenderer::mMutex") { MOZ_COUNT_CTOR(AsyncCanvasRenderer); } @@ -65,6 +74,41 @@ AsyncCanvasRenderer::NotifyElementAboutAttributesChanged() } } +void +AsyncCanvasRenderer::NotifyElementAboutInvalidation() +{ + class Runnable final : public nsRunnable + { + public: + Runnable(AsyncCanvasRenderer* aRenderer) + : mRenderer(aRenderer) + {} + + NS_IMETHOD Run() + { + if (mRenderer) { + dom::HTMLCanvasElement::InvalidateFromAsyncCanvasRenderer(mRenderer); + } + + return NS_OK; + } + + void Revoke() + { + mRenderer = nullptr; + } + + private: + nsRefPtr mRenderer; + }; + + nsRefPtr runnable = new Runnable(this); + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to dispatch a runnable to the main-thread."); + } +} + void AsyncCanvasRenderer::SetCanvasClient(CanvasClient* aClient) { @@ -76,5 +120,58 @@ AsyncCanvasRenderer::SetCanvasClient(CanvasClient* aClient) } } +void +AsyncCanvasRenderer::SetActiveThread() +{ + MutexAutoLock lock(mMutex); + mActiveThread = NS_GetCurrentThread(); +} + +void +AsyncCanvasRenderer::ResetActiveThread() +{ + MutexAutoLock lock(mMutex); + mActiveThread = nullptr; +} + +already_AddRefed +AsyncCanvasRenderer::GetActiveThread() +{ + MutexAutoLock lock(mMutex); + nsCOMPtr result = mActiveThread; + return result.forget(); +} + +already_AddRefed +AsyncCanvasRenderer::UpdateTarget() +{ + // This function will be implemented in a later patch. + return nullptr; +} + +already_AddRefed +AsyncCanvasRenderer::GetSurface() +{ + MOZ_ASSERT(NS_IsMainThread()); + return UpdateTarget(); +} + +nsresult +AsyncCanvasRenderer::GetInputStream(const char *aMimeType, + const char16_t *aEncoderOptions, + nsIInputStream **aStream) +{ + MOZ_ASSERT(NS_IsMainThread()); + RefPtr surface = GetSurface(); + if (!surface) { + return NS_ERROR_FAILURE; + } + + // Handle y flip. + RefPtr dataSurf = gl::YInvertImageSurface(surface); + + return gfxUtils::GetInputStream(dataSurf, false, aMimeType, aEncoderOptions, aStream); +} + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/AsyncCanvasRenderer.h b/gfx/layers/AsyncCanvasRenderer.h index a5af5fea7bfa..993669141bef 100644 --- a/gfx/layers/AsyncCanvasRenderer.h +++ b/gfx/layers/AsyncCanvasRenderer.h @@ -7,15 +7,22 @@ #ifndef MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_ #define MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_ +#include "LayersTypes.h" #include "mozilla/gfx/Point.h" // for IntSize +#include "mozilla/Mutex.h" #include "mozilla/RefPtr.h" // for nsAutoPtr, nsRefPtr, etc #include "nsCOMPtr.h" // for nsCOMPtr class nsICanvasRenderingContextInternal; +class nsIInputStream; class nsIThread; namespace mozilla { +namespace gfx { +class DataSourceSurface; +} + namespace gl { class GLContext; } @@ -36,8 +43,13 @@ class CanvasClient; * Each HTMLCanvasElement object is responsible for creating * AsyncCanvasRenderer object. Once Canvas is transfered to worker, * OffscreenCanvas will keep reference pointer of this object. - * This object will pass to ImageBridgeChild for submitting frames to - * Compositor. + * + * Sometimes main thread needs AsyncCanvasRenderer's result, such as layers + * fallback to BasicLayerManager or calling toDataURL in Javascript. Simply call + * GetSurface() in main thread will readback the result to mSurface. + * + * If layers backend is LAYERS_CLIENT, this object will pass to ImageBridgeChild + * for submitting frames to Compositor. */ class AsyncCanvasRenderer final { @@ -47,6 +59,7 @@ public: AsyncCanvasRenderer(); void NotifyElementAboutAttributesChanged(); + void NotifyElementAboutInvalidation(); void SetCanvasClient(CanvasClient* aClient); @@ -60,6 +73,28 @@ public: mHeight = aHeight; } + void SetIsAlphaPremultiplied(bool aIsAlphaPremultiplied) + { + mIsAlphaPremultiplied = aIsAlphaPremultiplied; + } + + // Active thread means the thread which spawns GLContext. + void SetActiveThread(); + void ResetActiveThread(); + + // This will readback surface and return the surface + // in the DataSourceSurface. + // Can be called in main thread only. + already_AddRefed GetSurface(); + + // Readback current WebGL's content and convert it to InputStream. This + // function called GetSurface implicitly and GetSurface handles only get + // called in the main thread. So this function can be called in main thread. + nsresult + GetInputStream(const char *aMimeType, + const char16_t *aEncoderOptions, + nsIInputStream **aStream); + gfx::IntSize GetSize() const { return gfx::IntSize(mWidth, mHeight); @@ -75,26 +110,44 @@ public: return mCanvasClient; } + already_AddRefed GetActiveThread(); + // The lifetime is controllered by HTMLCanvasElement. + // Only accessed in main thread. dom::HTMLCanvasElement* mHTMLCanvasElement; + // Only accessed in active thread. nsICanvasRenderingContextInternal* mContext; // We need to keep a reference to the context around here, otherwise the // canvas' surface texture destructor will deref and destroy it too early + // Only accessed in active thread. RefPtr mGLContext; - - nsCOMPtr mActiveThread; private: virtual ~AsyncCanvasRenderer(); + // Readback current WebGL's content and return it as DataSourceSurface. + already_AddRefed UpdateTarget(); + + bool mIsAlphaPremultiplied; + uint32_t mWidth; uint32_t mHeight; uint64_t mCanvasClientAsyncID; // The lifetime of this pointer is controlled by OffscreenCanvas + // Can be accessed in active thread and ImageBridge thread. + // But we never accessed it at the same time on both thread. So no + // need to protect this member. CanvasClient* mCanvasClient; + + + // Protect non thread-safe objects. + Mutex mMutex; + + // Can be accessed in any thread, need protect by mutex. + nsCOMPtr mActiveThread; }; } // namespace layers diff --git a/gfx/layers/CopyableCanvasLayer.cpp b/gfx/layers/CopyableCanvasLayer.cpp index 22acc69e26f4..0fad0aa3668b 100644 --- a/gfx/layers/CopyableCanvasLayer.cpp +++ b/gfx/layers/CopyableCanvasLayer.cpp @@ -64,6 +64,9 @@ CopyableCanvasLayer::Initialize(const Data& aData) } } else if (aData.mBufferProvider) { mBufferProvider = aData.mBufferProvider; + } else if (aData.mRenderer) { + mAsyncRenderer = aData.mRenderer; + mOriginPos = gl::OriginPos::BottomLeft; } else { MOZ_CRASH("CanvasLayer created without mSurface, mDrawTarget or mGLContext?"); } @@ -80,11 +83,9 @@ CopyableCanvasLayer::IsDataValid(const Data& aData) void CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) { - if (!mBufferProvider && !mGLContext) { - return; - } - - if (mBufferProvider) { + if (mAsyncRenderer) { + mSurface = mAsyncRenderer->GetSurface(); + } else if (mBufferProvider) { mSurface = mBufferProvider->GetSnapshot(); } @@ -99,10 +100,12 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) return; } - if (mBufferProvider) { + if (mBufferProvider || mAsyncRenderer) { return; } + MOZ_ASSERT(mGLContext); + SharedSurface* frontbuffer = nullptr; if (mGLFrontbuffer) { frontbuffer = mGLFrontbuffer.get(); diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index f20214175186..7a2c5c630296 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -2118,12 +2118,6 @@ CanvasLayer::CanvasLayer(LayerManager* aManager, void* aImplData) CanvasLayer::~CanvasLayer() {} -void -CanvasLayer::SetAsyncRenderer(AsyncCanvasRenderer *aAsyncRenderer) -{ - mAsyncRenderer = aAsyncRenderer; -} - void CanvasLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix) { diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 6d7c0b507523..7f7b94042da2 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -2269,15 +2269,17 @@ public: Data() : mBufferProvider(nullptr) , mGLContext(nullptr) + , mRenderer(nullptr) , mFrontbufferGLTex(0) , mSize(0,0) , mHasAlpha(false) , mIsGLAlphaPremult(true) { } - // One of these two must be specified for Canvas2D, but never both + // One of these three must be specified for Canvas2D, but never more than one PersistentBufferProvider* mBufferProvider; // A BufferProvider for the Canvas contents mozilla::gl::GLContext* mGLContext; // or this, for GL. + AsyncCanvasRenderer* mRenderer; // or this, for OffscreenCanvas // Frontbuffer override uint32_t mFrontbufferGLTex; @@ -2398,8 +2400,6 @@ public: return !!mAsyncRenderer; } - void SetAsyncRenderer(AsyncCanvasRenderer *aAsyncRenderer); - protected: CanvasLayer(LayerManager* aManager, void* aImplData); virtual ~CanvasLayer(); diff --git a/gfx/layers/basic/BasicCanvasLayer.cpp b/gfx/layers/basic/BasicCanvasLayer.cpp index 080d4b79efa5..f6f0788764bc 100644 --- a/gfx/layers/basic/BasicCanvasLayer.cpp +++ b/gfx/layers/basic/BasicCanvasLayer.cpp @@ -4,6 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "BasicCanvasLayer.h" +#include "AsyncCanvasRenderer.h" #include "basic/BasicLayers.h" // for BasicLayerManager #include "basic/BasicLayersImpl.h" // for GetEffectiveOperator #include "mozilla/mozalloc.h" // for operator new diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index 421b3dc58b70..6821bc2f2701 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -12,6 +12,7 @@ #include "gfxDrawable.h" #include "imgIEncoder.h" #include "mozilla/Base64.h" +#include "mozilla/dom/ImageEncoder.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerRunnable.h" #include "mozilla/gfx/2D.h" @@ -1546,6 +1547,69 @@ gfxUtils::CopyAsDataURI(DrawTarget* aDT) } } +/* static */ void +gfxUtils::GetImageBuffer(gfx::DataSourceSurface* aSurface, + bool aIsAlphaPremultiplied, + uint8_t** outImageBuffer, + int32_t* outFormat) +{ + *outImageBuffer = nullptr; + *outFormat = 0; + + DataSourceSurface::MappedSurface map; + if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) + return; + + uint32_t bufferSize = aSurface->GetSize().width * aSurface->GetSize().height * 4; + uint8_t* imageBuffer = new (fallible) uint8_t[bufferSize]; + if (!imageBuffer) { + aSurface->Unmap(); + return; + } + memcpy(imageBuffer, map.mData, bufferSize); + + aSurface->Unmap(); + + int32_t format = imgIEncoder::INPUT_FORMAT_HOSTARGB; + if (!aIsAlphaPremultiplied) { + // We need to convert to INPUT_FORMAT_RGBA, otherwise + // we are automatically considered premult, and unpremult'd. + // Yes, it is THAT silly. + // Except for different lossy conversions by color, + // we could probably just change the label, and not change the data. + gfxUtils::ConvertBGRAtoRGBA(imageBuffer, bufferSize); + format = imgIEncoder::INPUT_FORMAT_RGBA; + } + + *outImageBuffer = imageBuffer; + *outFormat = format; +} + +/* static */ nsresult +gfxUtils::GetInputStream(gfx::DataSourceSurface* aSurface, + bool aIsAlphaPremultiplied, + const char* aMimeType, + const char16_t* aEncoderOptions, + nsIInputStream** outStream) +{ + nsCString enccid("@mozilla.org/image/encoder;2?type="); + enccid += aMimeType; + nsCOMPtr encoder = do_CreateInstance(enccid.get()); + if (!encoder) + return NS_ERROR_FAILURE; + + nsAutoArrayPtr imageBuffer; + int32_t format = 0; + GetImageBuffer(aSurface, aIsAlphaPremultiplied, getter_Transfers(imageBuffer), &format); + if (!imageBuffer) + return NS_ERROR_FAILURE; + + return dom::ImageEncoder::GetInputStream(aSurface->GetSize().width, + aSurface->GetSize().height, + imageBuffer, format, + encoder, aEncoderOptions, outStream); +} + class GetFeatureStatusRunnable final : public dom::workers::WorkerMainThreadRunnable { public: diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index 8464d2a32cae..c5c29fe08bda 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -17,6 +17,7 @@ class gfxASurface; class gfxDrawable; +class nsIInputStream; class nsIGfxInfo; class nsIntRegion; class nsIPresShell; @@ -282,6 +283,17 @@ public: static nsCString GetAsDataURI(DrawTarget* aDT); static nsCString GetAsLZ4Base64Str(DataSourceSurface* aSourceSurface); + static void GetImageBuffer(DataSourceSurface* aSurface, + bool aIsAlphaPremultiplied, + uint8_t** outImageBuffer, + int32_t* outFormat); + + static nsresult GetInputStream(DataSourceSurface* aSurface, + bool aIsAlphaPremultiplied, + const char* aMimeType, + const char16_t* aEncoderOptions, + nsIInputStream** outStream); + static nsresult ThreadSafeGetFeatureStatus(const nsCOMPtr& gfxInfo, int32_t feature, int32_t* status); From 173c50c5559dec167e7238810d96199d37791139 Mon Sep 17 00:00:00 2001 From: Morris Tseng Date: Tue, 29 Sep 2015 11:51:25 +0100 Subject: [PATCH 033/104] Bug 709490 - Part 8: Copy to a temp texture when readback from IOSurface, r=jgilbert --- gfx/gl/GLContext.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 5a1172ecfcdb..ef0ce36053c4 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -2650,6 +2650,7 @@ GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest) } GLuint tempFB = 0; + GLuint tempTex = 0; { ScopedBindFramebuffer autoFB(this); @@ -2681,6 +2682,24 @@ GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest) MOZ_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE); } + if (src->NeedsIndirectReads()) { + fGenTextures(1, &tempTex); + { + ScopedBindTexture autoTex(this, tempTex); + + GLenum format = src->mHasAlpha ? LOCAL_GL_RGBA + : LOCAL_GL_RGB; + auto width = src->mSize.width; + auto height = src->mSize.height; + fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, format, 0, 0, width, + height, 0); + } + + fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_COLOR_ATTACHMENT0, + LOCAL_GL_TEXTURE_2D, tempTex, 0); + } + ReadPixelsIntoDataSurface(this, dest); src->ProducerReadRelease(); @@ -2689,6 +2708,10 @@ GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest) if (tempFB) fDeleteFramebuffers(1, &tempFB); + if (tempTex) { + fDeleteTextures(1, &tempTex); + } + if (needsSwap) { src->UnlockProd(); if (prev) From 7c548ee466540005ea4bae6dedac72b3b5c417d6 Mon Sep 17 00:00:00 2001 From: Morris Tseng Date: Tue, 29 Sep 2015 11:51:25 +0100 Subject: [PATCH 034/104] Bug 709490 - Part 9: Readback without blocking main thread, r=jgilbert --- gfx/gl/GLLibraryEGL.cpp | 30 +++++++ gfx/gl/GLLibraryEGL.h | 12 +++ gfx/gl/GLReadTexImageHelper.cpp | 44 ++++++---- gfx/gl/GLReadTexImageHelper.h | 18 ++-- gfx/gl/SharedSurface.h | 5 ++ gfx/gl/SharedSurfaceANGLE.cpp | 132 +++++++++++++++++++++++++++++ gfx/gl/SharedSurfaceANGLE.h | 2 + gfx/gl/SharedSurfaceEGL.cpp | 9 +- gfx/gl/SharedSurfaceEGL.h | 2 + gfx/gl/SharedSurfaceGLX.cpp | 33 ++++++++ gfx/gl/SharedSurfaceGLX.h | 2 + gfx/gl/SharedSurfaceGralloc.cpp | 53 ++++++++++++ gfx/gl/SharedSurfaceGralloc.h | 2 + gfx/gl/SharedSurfaceIO.cpp | 25 ++++++ gfx/gl/SharedSurfaceIO.h | 2 + gfx/layers/AsyncCanvasRenderer.cpp | 108 ++++++++++++++++++++++- gfx/layers/AsyncCanvasRenderer.h | 13 +++ gfx/layers/client/CanvasClient.cpp | 9 ++ 18 files changed, 477 insertions(+), 24 deletions(-) diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp index 4f2a715699b7..a78be99d7f16 100644 --- a/gfx/gl/GLLibraryEGL.cpp +++ b/gfx/gl/GLLibraryEGL.cpp @@ -15,13 +15,17 @@ #ifdef XP_WIN #include "nsWindowsHelpers.h" #endif +#include "OGLShaderProgram.h" #include "prenv.h" #include "GLContext.h" +#include "GLContextProvider.h" #include "gfxPrefs.h" +#include "ScopedGLHelpers.h" namespace mozilla { namespace gl { +StaticMutex GLLibraryEGL::sMutex; GLLibraryEGL sEGLLibrary; #ifdef MOZ_B2G ThreadLocal GLLibraryEGL::sCurrentContext; @@ -148,6 +152,32 @@ GetAndInitDisplay(GLLibraryEGL& egl, void* displayType) return display; } +bool +GLLibraryEGL::ReadbackEGLImage(EGLImage image, gfx::DataSourceSurface* out_surface) +{ + StaticMutexAutoUnlock lock(sMutex); + if (!mReadbackGL) { + mReadbackGL = gl::GLContextProvider::CreateHeadless(gl::CreateContextFlags::NONE); + } + + ScopedTexture destTex(mReadbackGL); + const GLuint target = LOCAL_GL_TEXTURE_EXTERNAL; + ScopedBindTexture autoTex(mReadbackGL, destTex.Texture(), target); + mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); + mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); + mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST); + mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST); + mReadbackGL->fEGLImageTargetTexture2D(target, image); + + ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(target, + out_surface->GetFormat()); + int shaderConfig = config.mFeatures; + mReadbackGL->ReadTexImageHelper()->ReadTexImage(out_surface, 0, target, + out_surface->GetSize(), shaderConfig); + + return true; +} + bool GLLibraryEGL::EnsureInitialized(bool forceAccel) { diff --git a/gfx/gl/GLLibraryEGL.h b/gfx/gl/GLLibraryEGL.h index 37ccc3d9d232..1f42a951a758 100644 --- a/gfx/gl/GLLibraryEGL.h +++ b/gfx/gl/GLLibraryEGL.h @@ -10,6 +10,7 @@ #endif #include "GLLibraryLoader.h" +#include "mozilla/StaticMutex.h" #include "mozilla/ThreadLocal.h" #include "nsIFile.h" #include "GeckoProfiler.h" @@ -52,6 +53,11 @@ #endif namespace mozilla { + +namespace gfx { +class DataSourceSurface; +} + namespace gl { #undef BEFORE_GL_CALL @@ -94,6 +100,8 @@ namespace gl { #define AFTER_GL_CALL #endif +class GLContext; + class GLLibraryEGL { public: @@ -478,6 +486,8 @@ public: return IsExtensionSupported(EXT_create_context_robustness); } + bool ReadbackEGLImage(EGLImage image, gfx::DataSourceSurface* out_surface); + bool EnsureInitialized(bool forceAccel = false); void DumpEGLConfig(EGLConfig cfg); @@ -603,9 +613,11 @@ private: bool mInitialized; PRLibrary* mEGLLibrary; EGLDisplay mEGLDisplay; + RefPtr mReadbackGL; bool mIsANGLE; bool mIsWARP; + static StaticMutex sMutex; }; extern GLLibraryEGL sEGLLibrary; diff --git a/gfx/gl/GLReadTexImageHelper.cpp b/gfx/gl/GLReadTexImageHelper.cpp index 0efea4c92eec..7e43d8b350b1 100644 --- a/gfx/gl/GLReadTexImageHelper.cpp +++ b/gfx/gl/GLReadTexImageHelper.cpp @@ -214,7 +214,7 @@ GetActualReadFormats(GLContext* gl, } } -static void +void SwapRAndBComponents(DataSourceSurface* surf) { DataSourceSurface::MappedSurface map; @@ -614,8 +614,7 @@ ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, SurfaceFormat aFo #define CLEANUP_IF_GLERROR_OCCURRED(x) \ if (DidGLErrorOccur(x)) { \ - isurf = nullptr; \ - break; \ + return false; \ } already_AddRefed @@ -624,6 +623,31 @@ GLReadTexImageHelper::ReadTexImage(GLuint aTextureId, const gfx::IntSize& aSize, /* ShaderConfigOGL.mFeature */ int aConfig, bool aYInvert) +{ + /* Allocate resulting image surface */ + int32_t stride = aSize.width * BytesPerPixel(SurfaceFormat::R8G8B8A8); + RefPtr isurf = + Factory::CreateDataSourceSurfaceWithStride(aSize, + SurfaceFormat::R8G8B8A8, + stride); + if (NS_WARN_IF(!isurf)) { + return nullptr; + } + + if (!ReadTexImage(isurf, aTextureId, aTextureTarget, aSize, aConfig, aYInvert)) { + return nullptr; + } + + return isurf.forget(); +} + +bool +GLReadTexImageHelper::ReadTexImage(DataSourceSurface* aDest, + GLuint aTextureId, + GLenum aTextureTarget, + const gfx::IntSize& aSize, + /* ShaderConfigOGL.mFeature */ int aConfig, + bool aYInvert) { MOZ_ASSERT(aTextureTarget == LOCAL_GL_TEXTURE_2D || aTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL || @@ -631,16 +655,6 @@ GLReadTexImageHelper::ReadTexImage(GLuint aTextureId, mGL->MakeCurrent(); - /* Allocate resulting image surface */ - int32_t stride = aSize.width * BytesPerPixel(SurfaceFormat::R8G8B8A8); - RefPtr isurf = - Factory::CreateDataSourceSurfaceWithStride(aSize, - SurfaceFormat::R8G8B8A8, - stride); - if (NS_WARN_IF(!isurf)) { - return nullptr; - } - GLint oldrb, oldfb, oldprog, oldTexUnit, oldTex; GLuint rb, fb; @@ -737,7 +751,7 @@ GLReadTexImageHelper::ReadTexImage(GLuint aTextureId, CLEANUP_IF_GLERROR_OCCURRED("when drawing texture"); /* Read-back draw results */ - ReadPixelsIntoDataSurface(mGL, isurf); + ReadPixelsIntoDataSurface(mGL, aDest); CLEANUP_IF_GLERROR_OCCURRED("when reading pixels into surface"); } while (false); @@ -756,7 +770,7 @@ GLReadTexImageHelper::ReadTexImage(GLuint aTextureId, if (oldTexUnit != LOCAL_GL_TEXTURE0) mGL->fActiveTexture(oldTexUnit); - return isurf.forget(); + return true; } #undef CLEANUP_IF_GLERROR_OCCURRED diff --git a/gfx/gl/GLReadTexImageHelper.h b/gfx/gl/GLReadTexImageHelper.h index 7adc4edba482..685afcf270c1 100644 --- a/gfx/gl/GLReadTexImageHelper.h +++ b/gfx/gl/GLReadTexImageHelper.h @@ -37,6 +37,9 @@ ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceForma already_AddRefed YInvertImageSurface(gfx::DataSourceSurface* aSurf); +void +SwapRAndBComponents(gfx::DataSourceSurface* surf); + class GLReadTexImageHelper final { // The GLContext is the sole owner of the GLBlitHelper. @@ -68,12 +71,17 @@ public: * passed as int to eliminate including LayerManagerOGLProgram.h here. */ already_AddRefed ReadTexImage(GLuint aTextureId, - GLenum aTextureTarget, - const gfx::IntSize& aSize, - /* ShaderProgramType */ int aShaderProgram, - bool aYInvert = false); - + GLenum aTextureTarget, + const gfx::IntSize& aSize, + /* ShaderProgramType */ int aShaderProgram, + bool aYInvert = false); + bool ReadTexImage(gfx::DataSourceSurface* aDest, + GLuint aTextureId, + GLenum aTextureTarget, + const gfx::IntSize& aSize, + int aShaderProgram, + bool aYInvert = false); }; } // namespace gl diff --git a/gfx/gl/SharedSurface.h b/gfx/gl/SharedSurface.h index 217cac05b23d..0e98689acf01 100644 --- a/gfx/gl/SharedSurface.h +++ b/gfx/gl/SharedSurface.h @@ -34,6 +34,7 @@ class nsIThread; namespace mozilla { namespace gfx { +class DataSourceSurface; class DrawTarget; } // namespace gfx @@ -200,6 +201,10 @@ public: } virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) = 0; + + virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) { + return false; + } }; template diff --git a/gfx/gl/SharedSurfaceANGLE.cpp b/gfx/gl/SharedSurfaceANGLE.cpp index 381ba8ee8dda..9b8c444f6d7f 100644 --- a/gfx/gl/SharedSurfaceANGLE.cpp +++ b/gfx/gl/SharedSurfaceANGLE.cpp @@ -273,6 +273,138 @@ SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor(layers::SurfaceDescriptor* c return true; } +class ScopedLockTexture final +{ +public: + explicit ScopedLockTexture(ID3D11Texture2D* texture, bool* succeeded) + : mIsLocked(false) + , mTexture(texture) + { + MOZ_ASSERT(mTexture); + MOZ_ASSERT(succeeded); + *succeeded = false; + + HRESULT hr; + mTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mMutex)); + if (mMutex) { + hr = mMutex->AcquireSync(0, 10000); + if (hr == WAIT_TIMEOUT) { + MOZ_CRASH(); + } + + if (FAILED(hr)) { + NS_WARNING("Failed to lock the texture"); + return; + } + } + + ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11Device(); + device->GetImmediateContext(byRef(mDeviceContext)); + + mTexture->GetDesc(&mDesc); + mDesc.BindFlags = 0; + mDesc.Usage = D3D11_USAGE_STAGING; + mDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + mDesc.MiscFlags = 0; + + hr = device->CreateTexture2D(&mDesc, nullptr, byRef(mCopiedTexture)); + + if (FAILED(hr)) { + return; + } + + mDeviceContext->CopyResource(mCopiedTexture, mTexture); + + hr = mDeviceContext->Map(mCopiedTexture, 0, D3D11_MAP_READ, 0, &mSubresource); + if (FAILED(hr)) { + return; + } + + *succeeded = true; + mIsLocked = true; + } + + ~ScopedLockTexture() + { + mDeviceContext->Unmap(mCopiedTexture, 0); + if (mMutex) { + HRESULT hr = mMutex->ReleaseSync(0); + if (FAILED(hr)) { + NS_WARNING("Failed to unlock the texture"); + } + } + mIsLocked = false; + } + + bool mIsLocked; + RefPtr mTexture; + RefPtr mCopiedTexture; + RefPtr mMutex; + RefPtr mDeviceContext; + D3D11_TEXTURE2D_DESC mDesc; + D3D11_MAPPED_SUBRESOURCE mSubresource; +}; + +bool +SharedSurface_ANGLEShareHandle::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) +{ + MOZ_ASSERT(out_surface); + RefPtr tex; + ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11Device(); + HRESULT hr = device->OpenSharedResource(mShareHandle, + __uuidof(ID3D11Texture2D), + (void**)(ID3D11Texture2D**)byRef(tex)); + + if (FAILED(hr)) { + return false; + } + + bool succeeded = false; + ScopedLockTexture scopedLock(tex, &succeeded); + if (!succeeded) { + return false; + } + + const uint8_t* data = reinterpret_cast(scopedLock.mSubresource.pData); + uint32_t srcStride = scopedLock.mSubresource.RowPitch; + + gfx::DataSourceSurface::ScopedMap map(out_surface, gfx::DataSourceSurface::WRITE); + if (!map.IsMapped()) { + return false; + } + + if (map.GetStride() == srcStride) { + memcpy(map.GetData(), data, out_surface->GetSize().height * map.GetStride()); + } else { + const uint8_t bytesPerPixel = BytesPerPixel(out_surface->GetFormat()); + for (int32_t i = 0; i < out_surface->GetSize().height; i++) { + memcpy(map.GetData() + i * map.GetStride(), + data + i * srcStride, + bytesPerPixel * out_surface->GetSize().width); + } + } + + DXGI_FORMAT srcFormat = scopedLock.mDesc.Format; + MOZ_ASSERT(srcFormat == DXGI_FORMAT_B8G8R8A8_UNORM || + srcFormat == DXGI_FORMAT_B8G8R8X8_UNORM || + srcFormat == DXGI_FORMAT_R8G8B8A8_UNORM); + bool isSrcRGB = srcFormat == DXGI_FORMAT_R8G8B8A8_UNORM; + + gfx::SurfaceFormat destFormat = out_surface->GetFormat(); + MOZ_ASSERT(destFormat == gfx::SurfaceFormat::R8G8B8X8 || + destFormat == gfx::SurfaceFormat::R8G8B8A8 || + destFormat == gfx::SurfaceFormat::B8G8R8X8 || + destFormat == gfx::SurfaceFormat::B8G8R8A8); + bool isDestRGB = destFormat == gfx::SurfaceFormat::R8G8B8X8 || + destFormat == gfx::SurfaceFormat::R8G8B8A8; + + if (isSrcRGB != isDestRGB) { + SwapRAndBComponents(out_surface); + } + + return true; +} + //////////////////////////////////////////////////////////////////////////////// // Factory diff --git a/gfx/gl/SharedSurfaceANGLE.h b/gfx/gl/SharedSurfaceANGLE.h index 3dcab9d04332..f37b50ed9881 100644 --- a/gfx/gl/SharedSurfaceANGLE.h +++ b/gfx/gl/SharedSurfaceANGLE.h @@ -81,6 +81,8 @@ public: } virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override; + + virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override; }; diff --git a/gfx/gl/SharedSurfaceEGL.cpp b/gfx/gl/SharedSurfaceEGL.cpp index ca3f18dfb298..f4391cd0fbde 100644 --- a/gfx/gl/SharedSurfaceEGL.cpp +++ b/gfx/gl/SharedSurfaceEGL.cpp @@ -10,7 +10,6 @@ #include "GLLibraryEGL.h" #include "GLReadTexImageHelper.h" #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc -#include "ScopedGLHelpers.h" #include "SharedSurface.h" #include "TextureGarbageBin.h" @@ -213,6 +212,14 @@ SharedSurface_EGLImage::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out return true; } +bool +SharedSurface_EGLImage::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) +{ + MOZ_ASSERT(out_surface); + MOZ_ASSERT(NS_IsMainThread()); + return sEGLLibrary.ReadbackEGLImage(mImage, out_surface); +} + //////////////////////////////////////////////////////////////////////// /*static*/ UniquePtr diff --git a/gfx/gl/SharedSurfaceEGL.h b/gfx/gl/SharedSurfaceEGL.h index 0184887e0015..7dd847ef6f1f 100644 --- a/gfx/gl/SharedSurfaceEGL.h +++ b/gfx/gl/SharedSurfaceEGL.h @@ -79,6 +79,8 @@ public: void AcquireConsumerTexture(GLContext* consGL, GLuint* out_texture, GLuint* out_target); virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override; + + virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override; }; diff --git a/gfx/gl/SharedSurfaceGLX.cpp b/gfx/gl/SharedSurfaceGLX.cpp index ecf8320ff7c3..e91630c22ea0 100644 --- a/gfx/gl/SharedSurfaceGLX.cpp +++ b/gfx/gl/SharedSurfaceGLX.cpp @@ -9,6 +9,7 @@ #include "GLContextProvider.h" #include "GLContextGLX.h" #include "GLScreenBuffer.h" +#include "mozilla/gfx/SourceSurfaceCairo.h" #include "mozilla/layers/LayersSurfaces.h" #include "mozilla/layers/ShadowLayerUtilsX11.h" #include "mozilla/layers/ISurfaceAllocator.h" @@ -83,6 +84,38 @@ SharedSurface_GLXDrawable::ToSurfaceDescriptor(layers::SurfaceDescriptor* const return true; } +bool +SharedSurface_GLXDrawable::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) +{ + MOZ_ASSERT(out_surface); + RefPtr dataSurf = + new gfx::DataSourceSurfaceCairo(mXlibSurface->CairoSurface()); + + gfx::DataSourceSurface::ScopedMap mapSrc(dataSurf, gfx::DataSourceSurface::READ); + if (!mapSrc.IsMapped()) { + return false; + } + + gfx::DataSourceSurface::ScopedMap mapDest(out_surface, gfx::DataSourceSurface::WRITE); + if (!mapDest.IsMapped()) { + return false; + } + + if (mapDest.GetStride() == mapSrc.GetStride()) { + memcpy(mapDest.GetData(), + mapSrc.GetData(), + out_surface->GetSize().height * mapDest.GetStride()); + } else { + for (int32_t i = 0; i < dataSurf->GetSize().height; i++) { + memcpy(mapDest.GetData() + i * mapDest.GetStride(), + mapSrc.GetData() + i * mapSrc.GetStride(), + std::min(mapSrc.GetStride(), mapDest.GetStride())); + } + } + + return true; +} + /* static */ UniquePtr SurfaceFactory_GLXDrawable::Create(GLContext* prodGL, diff --git a/gfx/gl/SharedSurfaceGLX.h b/gfx/gl/SharedSurfaceGLX.h index 1822fba4d718..528c223400b6 100644 --- a/gfx/gl/SharedSurfaceGLX.h +++ b/gfx/gl/SharedSurfaceGLX.h @@ -32,6 +32,8 @@ public: virtual void UnlockProdImpl() override; virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override; + + virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override; private: SharedSurface_GLXDrawable(GLContext* gl, const gfx::IntSize& size, diff --git a/gfx/gl/SharedSurfaceGralloc.cpp b/gfx/gl/SharedSurfaceGralloc.cpp index ba957c401275..87c285ca1351 100644 --- a/gfx/gl/SharedSurfaceGralloc.cpp +++ b/gfx/gl/SharedSurfaceGralloc.cpp @@ -283,5 +283,58 @@ SharedSurface_Gralloc::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_ return mTextureClient->ToSurfaceDescriptor(*out_descriptor); } +bool +SharedSurface_Gralloc::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) +{ + MOZ_ASSERT(out_surface); + sp buffer = mTextureClient->GetGraphicBuffer(); + + const uint8_t* grallocData = nullptr; + auto result = buffer->lock( + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, + const_cast(reinterpret_cast(&grallocData)) + ); + + if (result == BAD_VALUE) { + return false; + } + + gfx::DataSourceSurface::ScopedMap map(out_surface, gfx::DataSourceSurface::WRITE); + if (!map.IsMapped()) { + buffer->unlock(); + return false; + } + + uint32_t stride = buffer->getStride() * android::bytesPerPixel(buffer->getPixelFormat()); + uint32_t height = buffer->getHeight(); + uint32_t width = buffer->getWidth(); + for (uint32_t i = 0; i < height; i++) { + memcpy(map.GetData() + i * map.GetStride(), + grallocData + i * stride, width * 4); + } + + buffer->unlock(); + + android::PixelFormat srcFormat = buffer->getPixelFormat(); + MOZ_ASSERT(srcFormat == PIXEL_FORMAT_RGBA_8888 || + srcFormat == PIXEL_FORMAT_BGRA_8888 || + srcFormat == PIXEL_FORMAT_RGBX_8888); + bool isSrcRGB = srcFormat == PIXEL_FORMAT_RGBA_8888 || + srcFormat == PIXEL_FORMAT_RGBX_8888; + + gfx::SurfaceFormat destFormat = out_surface->GetFormat(); + MOZ_ASSERT(destFormat == gfx::SurfaceFormat::R8G8B8X8 || + destFormat == gfx::SurfaceFormat::R8G8B8A8 || + destFormat == gfx::SurfaceFormat::B8G8R8X8 || + destFormat == gfx::SurfaceFormat::B8G8R8A8); + bool isDestRGB = destFormat == gfx::SurfaceFormat::R8G8B8X8 || + destFormat == gfx::SurfaceFormat::R8G8B8A8; + + if (isSrcRGB != isDestRGB) { + SwapRAndBComponents(out_surface); + } + return true; +} + } // namespace gl } // namespace mozilla diff --git a/gfx/gl/SharedSurfaceGralloc.h b/gfx/gl/SharedSurfaceGralloc.h index 14097224cde3..d19e33c461d8 100644 --- a/gfx/gl/SharedSurfaceGralloc.h +++ b/gfx/gl/SharedSurfaceGralloc.h @@ -75,6 +75,8 @@ public: } virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override; + + virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override; }; class SurfaceFactory_Gralloc diff --git a/gfx/gl/SharedSurfaceIO.cpp b/gfx/gl/SharedSurfaceIO.cpp index e50b8d8f0c32..2154327daf38 100644 --- a/gfx/gl/SharedSurfaceIO.cpp +++ b/gfx/gl/SharedSurfaceIO.cpp @@ -182,6 +182,31 @@ SharedSurface_IOSurface::ToSurfaceDescriptor(layers::SurfaceDescriptor* const ou return true; } +bool +SharedSurface_IOSurface::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) +{ + MOZ_ASSERT(out_surface); + mIOSurf->Lock(); + size_t bytesPerRow = mIOSurf->GetBytesPerRow(); + size_t ioWidth = mIOSurf->GetDevicePixelWidth(); + size_t ioHeight = mIOSurf->GetDevicePixelHeight(); + + const unsigned char* ioData = (unsigned char*)mIOSurf->GetBaseAddress(); + gfx::DataSourceSurface::ScopedMap map(out_surface, gfx::DataSourceSurface::WRITE); + if (!map.IsMapped()) { + mIOSurf->Unlock(); + return false; + } + + for (size_t i = 0; i < ioHeight; i++) { + memcpy(map.GetData() + i * map.GetStride(), + ioData + i * bytesPerRow, ioWidth * 4); + } + + mIOSurf->Unlock(); + return true; +} + //////////////////////////////////////////////////////////////////////// // SurfaceFactory_IOSurface diff --git a/gfx/gl/SharedSurfaceIO.h b/gfx/gl/SharedSurfaceIO.h index 3976b5787f05..fe787ef9cf1d 100644 --- a/gfx/gl/SharedSurfaceIO.h +++ b/gfx/gl/SharedSurfaceIO.h @@ -68,6 +68,8 @@ public: } virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override; + + virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override; }; class SurfaceFactory_IOSurface : public SurfaceFactory diff --git a/gfx/layers/AsyncCanvasRenderer.cpp b/gfx/layers/AsyncCanvasRenderer.cpp index 755da24a6c9e..8c7ed428cf86 100644 --- a/gfx/layers/AsyncCanvasRenderer.cpp +++ b/gfx/layers/AsyncCanvasRenderer.cpp @@ -12,6 +12,7 @@ #include "GLScreenBuffer.h" #include "mozilla/dom/HTMLCanvasElement.h" #include "mozilla/layers/CanvasClient.h" +#include "mozilla/layers/TextureClient.h" #include "mozilla/layers/TextureClientSharedSurface.h" #include "mozilla/ReentrantMonitor.h" #include "nsIRunnable.h" @@ -142,18 +143,119 @@ AsyncCanvasRenderer::GetActiveThread() return result.forget(); } +void +AsyncCanvasRenderer::CopyFromTextureClient(TextureClient* aTextureClient) +{ + MutexAutoLock lock(mMutex); + RefPtr buffer = static_cast(aTextureClient); + if (!buffer->Lock(layers::OpenMode::OPEN_READ)) { + return; + } + + const gfx::IntSize& size = aTextureClient->GetSize(); + // This buffer would be used later for content rendering. So we choose + // B8G8R8A8 format here. + const gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8; + // Avoid to create buffer every time. + if (!mSurfaceForBasic || + size != mSurfaceForBasic->GetSize() || + format != mSurfaceForBasic->GetFormat()) + { + uint32_t stride = gfx::GetAlignedStride<8>(size.width * BytesPerPixel(format)); + mSurfaceForBasic = gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride); + } + + const uint8_t* lockedBytes = buffer->GetLockedData(); + gfx::DataSourceSurface::ScopedMap map(mSurfaceForBasic, + gfx::DataSourceSurface::MapType::WRITE); + if (!map.IsMapped()) { + buffer->Unlock(); + return; + } + + memcpy(map.GetData(), lockedBytes, map.GetStride() * mSurfaceForBasic->GetSize().height); + buffer->Unlock(); + + if (mSurfaceForBasic->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 || + mSurfaceForBasic->GetFormat() == gfx::SurfaceFormat::R8G8B8X8) { + gl::SwapRAndBComponents(mSurfaceForBasic); + } +} + already_AddRefed AsyncCanvasRenderer::UpdateTarget() { - // This function will be implemented in a later patch. - return nullptr; + if (!mGLContext) { + return nullptr; + } + + gl::SharedSurface* frontbuffer = nullptr; + gl::GLScreenBuffer* screen = mGLContext->Screen(); + const auto& front = screen->Front(); + if (front) { + frontbuffer = front->Surf(); + } + + if (!frontbuffer) { + return nullptr; + } + + if (frontbuffer->mType == gl::SharedSurfaceType::Basic) { + return nullptr; + } + + const gfx::IntSize& size = frontbuffer->mSize; + // This buffer would be used later for content rendering. So we choose + // B8G8R8A8 format here. + const gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8; + uint32_t stride = gfx::GetAlignedStride<8>(size.width * BytesPerPixel(format)); + RefPtr surface = + gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride); + + + if (NS_WARN_IF(!surface)) { + return nullptr; + } + + if (!frontbuffer->ReadbackBySharedHandle(surface)) { + return nullptr; + } + + bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied; + if (needsPremult) { + gfxUtils::PremultiplyDataSurface(surface, surface); + } + + return surface.forget(); } already_AddRefed AsyncCanvasRenderer::GetSurface() { MOZ_ASSERT(NS_IsMainThread()); - return UpdateTarget(); + MutexAutoLock lock(mMutex); + if (mSurfaceForBasic) { + // Since SourceSurface isn't thread-safe, we need copy to a new SourceSurface. + RefPtr result = + gfx::Factory::CreateDataSourceSurfaceWithStride(mSurfaceForBasic->GetSize(), + mSurfaceForBasic->GetFormat(), + mSurfaceForBasic->Stride()); + + gfx::DataSourceSurface::ScopedMap srcMap(mSurfaceForBasic, gfx::DataSourceSurface::READ); + gfx::DataSourceSurface::ScopedMap dstMap(result, gfx::DataSourceSurface::WRITE); + + if (NS_WARN_IF(!srcMap.IsMapped()) || + NS_WARN_IF(!dstMap.IsMapped())) { + return nullptr; + } + + memcpy(dstMap.GetData(), + srcMap.GetData(), + srcMap.GetStride() * mSurfaceForBasic->GetSize().height); + return result.forget(); + } else { + return UpdateTarget(); + } } nsresult diff --git a/gfx/layers/AsyncCanvasRenderer.h b/gfx/layers/AsyncCanvasRenderer.h index 993669141bef..6a84b0703528 100644 --- a/gfx/layers/AsyncCanvasRenderer.h +++ b/gfx/layers/AsyncCanvasRenderer.h @@ -34,6 +34,7 @@ class HTMLCanvasElement; namespace layers { class CanvasClient; +class TextureClient; /** * Since HTMLCanvasElement and OffscreenCanvas are not thread-safe, we create @@ -87,6 +88,12 @@ public: // Can be called in main thread only. already_AddRefed GetSurface(); + // For SharedSurface_Basic case, before the frame sending to the compositor, + // we readback it to a texture client because SharedSurface_Basic cannot shared. + // We don't want to readback it again here, so just copy the content of that + // texture client here to avoid readback again. + void CopyFromTextureClient(TextureClient *aClient); + // Readback current WebGL's content and convert it to InputStream. This // function called GetSurface implicitly and GetSurface handles only get // called in the main thread. So this function can be called in main thread. @@ -142,6 +149,12 @@ private: // need to protect this member. CanvasClient* mCanvasClient; + // When backend is LAYER_BASIC and SharedSurface type is Basic. + // CanvasClient will readback the GLContext to a TextureClient + // in order to send frame to compositor. To avoid readback again, + // we copy from this TextureClient to this mSurfaceForBasic directly + // by calling CopyFromTextureClient(). + RefPtr mSurfaceForBasic; // Protect non thread-safe objects. Mutex mMutex; diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index 765c9e17b55a..5b722c63aaa3 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -411,6 +411,15 @@ CanvasClientSharedSurface::UpdateRenderer(gfx::IntSize aSize, Renderer& aRendere auto layersBackend = shadowForwarder->GetCompositorBackendType(); mReadbackClient = TexClientFromReadback(surf, forwarder, flags, layersBackend); + if (asyncRenderer) { + // Above codes will readback the GLContext to mReadbackClient + // in order to send frame to compositor. We copy from this + // TextureClient directly by calling CopyFromTextureClient(). + // Therefore, if main-thread want the content of GLContext, + // it don't have to readback it again. + asyncRenderer->CopyFromTextureClient(mReadbackClient); + } + newFront = mReadbackClient; } else { mReadbackClient = nullptr; From d99c93a009872ba51ed64a2f6fb7716c09c57670 Mon Sep 17 00:00:00 2001 From: Morris Tseng Date: Tue, 29 Sep 2015 11:51:25 +0100 Subject: [PATCH 035/104] Bug 709490 - Part 10: Using mechanism in RuntimeService to get pref in worker thread instead of gfxPref, r=baku --- dom/canvas/OffscreenCanvas.cpp | 8 +++++++- dom/workers/RuntimeService.cpp | 10 ++++++++++ dom/workers/WorkerPrivate.h | 7 +++++++ dom/workers/Workers.h | 1 + gfx/thebes/gfxPrefs.h | 1 - 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/dom/canvas/OffscreenCanvas.cpp b/dom/canvas/OffscreenCanvas.cpp index 79e4806d7521..a0144823d81a 100644 --- a/dom/canvas/OffscreenCanvas.cpp +++ b/dom/canvas/OffscreenCanvas.cpp @@ -210,7 +210,13 @@ OffscreenCanvas::CreateFromCloneData(OffscreenCanvasCloneData* aData) /* static */ bool OffscreenCanvas::PrefEnabled(JSContext* aCx, JSObject* aObj) { - return gfxPrefs::OffscreenCanvasEnabled(); + if (NS_IsMainThread()) { + return Preferences::GetBool("gfx.offscreencanvas.enabled"); + } else { + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + return workerPrivate->OffscreenCanvasEnabled(); + } } /* static */ bool diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 4564ee98b0de..1d5228483808 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -170,6 +170,7 @@ static_assert(MAX_WORKERS_PER_DOMAIN >= 1, #define PREF_INTERCEPTION_OPAQUE_ENABLED "dom.serviceWorkers.interception.opaque.enabled" #define PREF_PUSH_ENABLED "dom.push.enabled" #define PREF_REQUESTCONTEXT_ENABLED "dom.requestcontext.enabled" +#define PREF_OFFSCREENCANVAS_ENABLED "gfx.offscreencanvas.enabled" namespace { @@ -1968,6 +1969,10 @@ RuntimeService::Init() WorkerPrefChanged, PREF_REQUESTCONTEXT_ENABLED, reinterpret_cast(WORKERPREF_REQUESTCONTEXT))) || + NS_FAILED(Preferences::RegisterCallbackAndCall( + WorkerPrefChanged, + PREF_OFFSCREENCANVAS_ENABLED, + reinterpret_cast(WORKERPREF_OFFSCREENCANVAS))) || NS_FAILED(Preferences::RegisterCallback(LoadRuntimeOptions, PREF_JS_OPTIONS_PREFIX, nullptr)) || @@ -2207,6 +2212,10 @@ RuntimeService::Cleanup() WorkerPrefChanged, PREF_REQUESTCONTEXT_ENABLED, reinterpret_cast(WORKERPREF_REQUESTCONTEXT))) || + NS_FAILED(Preferences::UnregisterCallback( + WorkerPrefChanged, + PREF_OFFSCREENCANVAS_ENABLED, + reinterpret_cast(WORKERPREF_OFFSCREENCANVAS))) || #if DUMP_CONTROLLED_BY_PREF NS_FAILED(Preferences::UnregisterCallback( WorkerPrefChanged, @@ -2768,6 +2777,7 @@ RuntimeService::WorkerPrefChanged(const char* aPrefName, void* aClosure) case WORKERPREF_SERVICEWORKERS_TESTING: case WORKERPREF_PUSH: case WORKERPREF_REQUESTCONTEXT: + case WORKERPREF_OFFSCREENCANVAS: sDefaultPreferences[key] = Preferences::GetBool(aPrefName, false); break; diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index d11e97f45409..79c98411a819 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -1313,6 +1313,13 @@ public: return mPreferences[WORKERPREF_REQUESTCONTEXT]; } + bool + OffscreenCanvasEnabled() const + { + AssertIsOnWorkerThread(); + return mPreferences[WORKERPREF_OFFSCREENCANVAS]; + } + bool OnLine() const { diff --git a/dom/workers/Workers.h b/dom/workers/Workers.h index 7ac053c3a258..95e0ebd82906 100644 --- a/dom/workers/Workers.h +++ b/dom/workers/Workers.h @@ -209,6 +209,7 @@ enum WorkerPreference WORKERPREF_PERFORMANCE_LOGGING_ENABLED, // dom.performance.enable_user_timing_logging WORKERPREF_PUSH, // dom.push.enabled WORKERPREF_REQUESTCONTEXT, // dom.requestcontext.enabled + WORKERPREF_OFFSCREENCANVAS, // gfx.offscreencanvas.enabled WORKERPREF_COUNT }; diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index e0f660d12eb1..ab2f6bb9aa08 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -244,7 +244,6 @@ private: DECL_GFX_PREF(Live, "gfx.layerscope.port", LayerScopePort, int32_t, 23456); // Note that "gfx.logging.level" is defined in Logging.h DECL_GFX_PREF(Once, "gfx.logging.crash.length", GfxLoggingCrashLength, uint32_t, 6); - DECL_GFX_PREF(Live, "gfx.offscreencanvas.enabled", OffscreenCanvasEnabled, bool, false); DECL_GFX_PREF(Live, "gfx.perf-warnings.enabled", PerfWarnings, bool, false); DECL_GFX_PREF(Live, "gfx.SurfaceTexture.detach.enabled", SurfaceTextureDetachEnabled, bool, true); DECL_GFX_PREF(Live, "gfx.testing.device-reset", DeviceResetForTesting, int32_t, 0); From 6912bd6a092b425bd17666ef283204855194189e Mon Sep 17 00:00:00 2001 From: Morris Tseng Date: Tue, 29 Sep 2015 11:51:26 +0100 Subject: [PATCH 036/104] Bug 709490 - Part 11: Diabled test_offscreencanvas_many.html on gonk, android, windows and linux, r=jgilbert --- dom/canvas/test/mochitest.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dom/canvas/test/mochitest.ini b/dom/canvas/test/mochitest.ini index 01565543a663..b0de5bee3bdb 100644 --- a/dom/canvas/test/mochitest.ini +++ b/dom/canvas/test/mochitest.ini @@ -278,7 +278,9 @@ skip-if = buildapp == 'b2g' tags = offscreencanvas [test_offscreencanvas_many.html] tags = offscreencanvas +skip-if = (toolkit == 'android' || toolkit == 'gonk' || toolkit == 'windows' || toolkit == 'gtk2' || toolkit == 'gtk3') [test_offscreencanvas_sizechange.html] tags = offscreencanvas [test_offscreencanvas_subworker.html] tags = offscreencanvas +skip-if = (toolkit == 'android' || toolkit == 'gonk' || toolkit == 'windows' || toolkit == 'gtk2' || toolkit == 'gtk3') From 745da49b7b9555b053860f818591399c196343ce Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 29 Sep 2015 12:54:54 +0100 Subject: [PATCH 037/104] Bug 709490 - Part 12 - explicit CTORs for a couple of runnables, CLOSED TREE --- gfx/layers/AsyncCanvasRenderer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gfx/layers/AsyncCanvasRenderer.cpp b/gfx/layers/AsyncCanvasRenderer.cpp index 8c7ed428cf86..f8a35572a7bf 100644 --- a/gfx/layers/AsyncCanvasRenderer.cpp +++ b/gfx/layers/AsyncCanvasRenderer.cpp @@ -46,7 +46,7 @@ AsyncCanvasRenderer::NotifyElementAboutAttributesChanged() class Runnable final : public nsRunnable { public: - Runnable(AsyncCanvasRenderer* aRenderer) + explicit Runnable(AsyncCanvasRenderer* aRenderer) : mRenderer(aRenderer) {} @@ -81,7 +81,7 @@ AsyncCanvasRenderer::NotifyElementAboutInvalidation() class Runnable final : public nsRunnable { public: - Runnable(AsyncCanvasRenderer* aRenderer) + explicit Runnable(AsyncCanvasRenderer* aRenderer) : mRenderer(aRenderer) {} From 3b7a3c96c41f54630d0cab945aedf5275bbb2918 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Tue, 29 Sep 2015 13:58:35 +0200 Subject: [PATCH 038/104] Backed out 2 changesets (bug 1205983) for memory leaks on a CLOSED TREE Backed out changeset f2c49c0ab84f (bug 1205983) Backed out changeset a81630dba992 (bug 1205983) --- editor/composer/nsEditorSpellCheck.cpp | 7 + editor/composer/test/chrome.ini | 1 - editor/composer/test/test_bug1205983.html | 122 ------------------ editor/composer/test/test_bug697981.html | 5 - editor/libeditor/nsEditor.cpp | 71 ++++++++++ editor/libeditor/nsEditor.h | 8 ++ editor/libeditor/nsEditorEventListener.cpp | 4 + editor/nsIEditorSpellCheck.idl | 8 +- editor/txtsvc/nsISpellChecker.h | 6 + .../spellcheck/hunspell/glue/mozHunspell.cpp | 21 +-- .../idl/mozISpellCheckingEngine.idl | 2 + .../spellcheck/src/mozInlineSpellChecker.cpp | 6 +- extensions/spellcheck/src/mozSpellChecker.cpp | 25 ++++ extensions/spellcheck/src/mozSpellChecker.h | 1 + .../chrome/test_add_remove_dictionaries.xul | 12 +- 15 files changed, 150 insertions(+), 149 deletions(-) delete mode 100644 editor/composer/test/test_bug1205983.html diff --git a/editor/composer/nsEditorSpellCheck.cpp b/editor/composer/nsEditorSpellCheck.cpp index f20a66f9e538..c9292b9796bf 100644 --- a/editor/composer/nsEditorSpellCheck.cpp +++ b/editor/composer/nsEditorSpellCheck.cpp @@ -636,6 +636,13 @@ nsEditorSpellCheck::SetCurrentDictionary(const nsAString& aDictionary) return mSpellChecker->SetCurrentDictionary(aDictionary); } +NS_IMETHODIMP +nsEditorSpellCheck::CheckCurrentDictionary() +{ + mSpellChecker->CheckCurrentDictionary(); + return NS_OK; +} + NS_IMETHODIMP nsEditorSpellCheck::UninitSpellChecker() { diff --git a/editor/composer/test/chrome.ini b/editor/composer/test/chrome.ini index cbf01740a71a..6ae8cae9038e 100644 --- a/editor/composer/test/chrome.ini +++ b/editor/composer/test/chrome.ini @@ -9,4 +9,3 @@ skip-if = buildapp == 'b2g' || os == 'android' [test_bug717433.html] [test_bug1204147.html] [test_bug1200533.html] -[test_bug1205983.html] diff --git a/editor/composer/test/test_bug1205983.html b/editor/composer/test/test_bug1205983.html deleted file mode 100644 index 58f0f7a1857c..000000000000 --- a/editor/composer/test/test_bug1205983.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - - Test for Bug 1205983 - - - - -Mozilla Bug 1205983 -

- - -
German heute ist ein guter Tag
- - -
-
-
- - diff --git a/editor/composer/test/test_bug697981.html b/editor/composer/test/test_bug697981.html index 96cc5942498f..ba9778e0a8ee 100644 --- a/editor/composer/test/test_bug697981.html +++ b/editor/composer/test/test_bug697981.html @@ -98,11 +98,6 @@ function enFocus() { // Remove the fake de_DE dictionary again. hunspell.removeDirectory(de_DE); - // Focus again, so the spelling gets updated, but before we need to kill the focus handler. - elem_de.onfocus = null; - elem_de.blur(); - elem_de.focus(); - // After removal, the de_DE editor should refresh the spelling with en-US. onSpellCheck(elem_de, function () { spellchecker = inlineSpellChecker.spellChecker; diff --git a/editor/libeditor/nsEditor.cpp b/editor/libeditor/nsEditor.cpp index d4557baf5453..bbf97f051416 100644 --- a/editor/libeditor/nsEditor.cpp +++ b/editor/libeditor/nsEditor.cpp @@ -24,6 +24,7 @@ #include "PlaceholderTxn.h" // for PlaceholderTxn #include "SplitNodeTxn.h" // for SplitNodeTxn #include "mozFlushType.h" // for mozFlushType::Flush_Frames +#include "mozISpellCheckingEngine.h" #include "mozInlineSpellChecker.h" // for mozInlineSpellChecker #include "mozilla/CheckedInt.h" // for CheckedInt #include "mozilla/IMEStateManager.h" // for IMEStateManager @@ -78,6 +79,7 @@ #include "nsIInlineSpellChecker.h" // for nsIInlineSpellChecker, etc #include "nsNameSpaceManager.h" // for kNameSpaceID_None, etc #include "nsINode.h" // for nsINode, etc +#include "nsIObserverService.h" // for nsIObserverService #include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc #include "nsIPresShell.h" // for nsIPresShell #include "nsISelectionController.h" // for nsISelectionController, etc @@ -146,6 +148,7 @@ nsEditor::nsEditor() , mDispatchInputEvent(true) , mIsInEditAction(false) , mHidingCaret(false) +, mObservingDictionaryUpdates(false) { } @@ -201,6 +204,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEditor) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsIEditorIMESupport) NS_INTERFACE_MAP_ENTRY(nsIEditor) + NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditor) NS_INTERFACE_MAP_END @@ -300,6 +304,13 @@ nsEditor::PostCreate() // update the UI with our state NotifyDocumentListeners(eDocumentCreated); NotifyDocumentListeners(eDocumentStateChanged); + + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->AddObserver(this, + SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION, + false); + } } // update nsTextStateManager and caret if we have focus @@ -437,6 +448,14 @@ nsEditor::PreDestroy(bool aDestroyingFrames) IMEStateManager::OnEditorDestroying(this); + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->RemoveObserver(this, + SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION); + obs->RemoveObserver(this, + SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION); + } + // Let spellchecker clean up its observers etc. It is important not to // actually free the spellchecker here, since the spellchecker could have // caused flush notifications, which could have gotten here if a textbox @@ -1295,6 +1314,35 @@ NS_IMETHODIMP nsEditor::GetInlineSpellChecker(bool autoCreate, return NS_OK; } +NS_IMETHODIMP nsEditor::Observe(nsISupports* aSubj, const char *aTopic, + const char16_t *aData) +{ + NS_ASSERTION(!strcmp(aTopic, + SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION) || + !strcmp(aTopic, + SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION), + "Unexpected observer topic"); + + // When mozInlineSpellChecker::CanEnableInlineSpellChecking changes + SyncRealTimeSpell(); + + // When nsIEditorSpellCheck::GetCurrentDictionary changes + if (mInlineSpellChecker) { + // Do the right thing in the spellchecker, if the dictionary is no longer + // available. This will not set a new dictionary. + nsCOMPtr editorSpellCheck; + mInlineSpellChecker->GetSpellChecker(getter_AddRefs(editorSpellCheck)); + if (editorSpellCheck) { + editorSpellCheck->CheckCurrentDictionary(); + } + + // update the inline spell checker to reflect the new current dictionary + mInlineSpellChecker->SpellCheckRange(nullptr); // causes recheck + } + + return NS_OK; +} + NS_IMETHODIMP nsEditor::SyncRealTimeSpell() { bool enable = GetDesiredSpellCheckState(); @@ -5158,6 +5206,29 @@ nsEditor::OnFocus(nsIDOMEventTarget* aFocusEventTarget) } } +void +nsEditor::StartWatchingDictionaryChanges() +{ + if (!mObservingDictionaryUpdates) { + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->AddObserver(this, SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION, false); + } + mObservingDictionaryUpdates = true; + } +} + +void +nsEditor::StopWatchingDictionaryChanges() +{ + // Removing an observer that wasn't added doesn't cause any harm. + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->RemoveObserver(this, SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION); + } + mObservingDictionaryUpdates = false; +} + NS_IMETHODIMP nsEditor::GetSuppressDispatchingInputEvent(bool *aSuppressed) { diff --git a/editor/libeditor/nsEditor.h b/editor/libeditor/nsEditor.h index 4873838fca30..31d2416cd995 100644 --- a/editor/libeditor/nsEditor.h +++ b/editor/libeditor/nsEditor.h @@ -140,6 +140,7 @@ inline bool operator!(const EditAction& aOp) class nsEditor : public nsIEditor, public nsIEditorIMESupport, public nsSupportsWeakReference, + public nsIObserver, public nsIPhonetic { public: @@ -187,6 +188,9 @@ public: /* ------------ nsIEditorIMESupport methods -------------- */ NS_DECL_NSIEDITORIMESUPPORT + /* ------------ nsIObserver methods -------------- */ + NS_DECL_NSIOBSERVER + // nsIPhonetic NS_DECL_NSIPHONETIC @@ -245,6 +249,9 @@ public: void SwitchTextDirectionTo(uint32_t aDirection); + void StartWatchingDictionaryChanges(); + void StopWatchingDictionaryChanges(); + protected: nsresult DetermineCurrentDirection(); void FireInputEvent(); @@ -887,6 +894,7 @@ protected: bool mDispatchInputEvent; bool mIsInEditAction; // true while the instance is handling an edit action bool mHidingCaret; // whether caret is hidden forcibly. + bool mObservingDictionaryUpdates; // whether the editor is observing dictionary changes. friend bool NSCanUnload(nsISupports* serviceMgr); friend class nsAutoTxnsConserveSelection; diff --git a/editor/libeditor/nsEditorEventListener.cpp b/editor/libeditor/nsEditorEventListener.cpp index e3010bff30d4..86e107404de7 100644 --- a/editor/libeditor/nsEditorEventListener.cpp +++ b/editor/libeditor/nsEditorEventListener.cpp @@ -1114,6 +1114,8 @@ nsEditorEventListener::Focus(nsIDOMEvent* aEvent) } } + mEditor->StartWatchingDictionaryChanges(); + mEditor->OnFocus(target); nsCOMPtr ps = GetPresShell(); @@ -1130,6 +1132,8 @@ nsEditorEventListener::Blur(nsIDOMEvent* aEvent) { NS_ENSURE_TRUE(aEvent, NS_OK); + mEditor->StopWatchingDictionaryChanges(); + // check if something else is focused. If another element is focused, then // we should not change the selection. nsIFocusManager* fm = nsFocusManager::GetFocusManager(); diff --git a/editor/nsIEditorSpellCheck.idl b/editor/nsIEditorSpellCheck.idl index adf4a0a03444..5a8d1be95ea7 100644 --- a/editor/nsIEditorSpellCheck.idl +++ b/editor/nsIEditorSpellCheck.idl @@ -9,10 +9,16 @@ interface nsIEditor; interface nsITextServicesFilter; interface nsIEditorSpellCheckCallback; -[scriptable, uuid(a171c25f-e4a8-4d08-adef-b797e6377bdc)] +[scriptable, uuid(dd32ef3b-a7d8-43d1-9617-5f2dddbe29eb)] interface nsIEditorSpellCheck : nsISupports { + /** + * Call this on any change in installed dictionaries to ensure that the spell + * checker is not using a current dictionary which is no longer available. + */ + void checkCurrentDictionary(); + /** * Returns true if we can enable spellchecking. If there are no available * dictionaries, this will return false. diff --git a/editor/txtsvc/nsISpellChecker.h b/editor/txtsvc/nsISpellChecker.h index cafc725bec93..c63f57091274 100644 --- a/editor/txtsvc/nsISpellChecker.h +++ b/editor/txtsvc/nsISpellChecker.h @@ -114,6 +114,12 @@ public: * empty string, spellchecker will be disabled. */ NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary) = 0; + + /** + * Call this on any change in installed dictionaries to ensure that the spell + * checker is not using a current dictionary which is no longer available. + */ + NS_IMETHOD CheckCurrentDictionary() = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsISpellChecker, NS_ISPELLCHECKER_IID) diff --git a/extensions/spellcheck/hunspell/glue/mozHunspell.cpp b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp index ddf3a58b3b7c..3b66cac1324d 100644 --- a/extensions/spellcheck/hunspell/glue/mozHunspell.cpp +++ b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp @@ -160,6 +160,12 @@ NS_IMETHODIMP mozHunspell::SetDictionary(const char16_t *aDictionary) mDecoder = nullptr; mEncoder = nullptr; + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->NotifyObservers(nullptr, + SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION, + nullptr); + } return NS_OK; } @@ -220,6 +226,13 @@ NS_IMETHODIMP mozHunspell::SetDictionary(const char16_t *aDictionary) else mLanguage = Substring(mDictionary, 0, pos); + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->NotifyObservers(nullptr, + SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION, + nullptr); + } + return NS_OK; } @@ -591,19 +604,11 @@ NS_IMETHODIMP mozHunspell::RemoveDirectory(nsIFile *aDir) { mDynamicDirectories.RemoveObject(aDir); LoadDictionaryList(true); - -#ifdef MOZ_THUNDERBIRD - /* - * This notification is needed for Thunderbird. Thunderbird derives the dictionary - * from the document's "lang" attribute. If a dictionary is removed, - * we need to change the "lang" attribute. - */ nsCOMPtr obs = mozilla::services::GetObserverService(); if (obs) { obs->NotifyObservers(nullptr, SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION, nullptr); } -#endif return NS_OK; } diff --git a/extensions/spellcheck/idl/mozISpellCheckingEngine.idl b/extensions/spellcheck/idl/mozISpellCheckingEngine.idl index c5f7db4210a5..c124bb8bca85 100644 --- a/extensions/spellcheck/idl/mozISpellCheckingEngine.idl +++ b/extensions/spellcheck/idl/mozISpellCheckingEngine.idl @@ -102,6 +102,8 @@ interface mozISpellCheckingEngine : nsISupports { #define DICTIONARY_SEARCH_DIRECTORY "DictD" #define DICTIONARY_SEARCH_DIRECTORY_LIST "DictDL" +#define SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION \ + "spellcheck-dictionary-update" #define SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION \ "spellcheck-dictionary-remove" %} diff --git a/extensions/spellcheck/src/mozInlineSpellChecker.cpp b/extensions/spellcheck/src/mozInlineSpellChecker.cpp index a9fcb3041050..89c0546d326d 100644 --- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp +++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp @@ -2021,8 +2021,10 @@ nsresult mozInlineSpellChecker::CurrentDictionaryUpdated() currentDictionary.Truncate(); } - nsresult rv = SpellCheckRange(nullptr); - NS_ENSURE_SUCCESS(rv, rv); + if (!mPreviousDictionary.Equals(currentDictionary)) { + nsresult rv = SpellCheckRange(nullptr); + NS_ENSURE_SUCCESS(rv, rv); + } return NS_OK; } diff --git a/extensions/spellcheck/src/mozSpellChecker.cpp b/extensions/spellcheck/src/mozSpellChecker.cpp index c695efb863ab..adc34f2898ac 100644 --- a/extensions/spellcheck/src/mozSpellChecker.cpp +++ b/extensions/spellcheck/src/mozSpellChecker.cpp @@ -428,6 +428,31 @@ mozSpellChecker::SetCurrentDictionary(const nsAString &aDictionary) return NS_ERROR_NOT_AVAILABLE; } +NS_IMETHODIMP +mozSpellChecker::CheckCurrentDictionary() +{ + // If the current dictionary has been uninstalled, we need to stop using it. + // This happens when there is a current engine, but that engine has no + // current dictionary. + + if (!mSpellCheckingEngine) { + // We didn't have a current dictionary + return NS_OK; + } + + nsXPIDLString dictname; + mSpellCheckingEngine->GetDictionary(getter_Copies(dictname)); + + if (!dictname.IsEmpty()) { + // We still have a current dictionary + return NS_OK; + } + + // We had a current dictionary, but it has gone, so we cannot use it anymore. + mSpellCheckingEngine = nullptr; + return NS_OK; +} + nsresult mozSpellChecker::SetupDoc(int32_t *outBlockOffset) { diff --git a/extensions/spellcheck/src/mozSpellChecker.h b/extensions/spellcheck/src/mozSpellChecker.h index 883dee38d76e..d60b5ac26d21 100644 --- a/extensions/spellcheck/src/mozSpellChecker.h +++ b/extensions/spellcheck/src/mozSpellChecker.h @@ -48,6 +48,7 @@ public: NS_IMETHOD GetDictionaryList(nsTArray *aDictionaryList) override; NS_IMETHOD GetCurrentDictionary(nsAString &aDictionary) override; NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary) override; + NS_IMETHOD CheckCurrentDictionary() override; void DeleteRemoteEngine() { mEngine = nullptr; diff --git a/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul b/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul index 7375c744409f..7fed54acf024 100644 --- a/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul +++ b/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul @@ -82,25 +82,17 @@ function RunTest() { // select map dictionary setCurrentDictionary(editor, "maputf"); - // Focus again, so the spelling gets updated. - textbox.blur(); - textbox.focus(); - onSpellCheck(textbox, function () { // test that map dictionary is in use - is(getMisspelledWords(editor), "created" + "imply" + "tomorrow" + "qwertyu", "map misspellings (1)"); + is(getMisspelledWords(editor), "created" + "imply" + "tomorrow" + "qwertyu", "map misspellings"); is(getCurrentDictionary(editor), "maputf", "current dictionary"); // uninstall map dictionary hunspell.removeDirectory(map); - // Focus again, so the spelling gets updated. - textbox.blur(); - textbox.focus(); - onSpellCheck(textbox, function () { // test that map dictionary is not in use - isnot(getMisspelledWords(editor), "created" + "imply" + "tomorrow" + "qwertyu", "map misspellings (2)"); + isnot(getMisspelledWords(editor), "created" + "imply" + "tomorrow" + "qwertyu", "map misspellings"); isnot(getCurrentDictionary(editor), "maputf", "current dictionary"); // test that base dictionary is available and map dictionary is unavailable From 5d6ef8e35506e8f2a1f9c2fe8a34420dda542445 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Tue, 29 Sep 2015 09:04:06 -0400 Subject: [PATCH 039/104] Bug 1179826 - re-enable test_ipc.html for dom/media. r=padenot --- dom/media/tests/mochitest/ipc/mochitest.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/media/tests/mochitest/ipc/mochitest.ini b/dom/media/tests/mochitest/ipc/mochitest.ini index 976343a26833..21a6d91a4230 100644 --- a/dom/media/tests/mochitest/ipc/mochitest.ini +++ b/dom/media/tests/mochitest/ipc/mochitest.ini @@ -6,4 +6,4 @@ support-files = skip-if = e10s [test_ipc.html] -skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || os == 'win' #bug 910661 # b2g(nested ipc not working) b2g-debug(debug-only failure) b2g-desktop(nested ipc not working)(win : Bug 1179826) +skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #bug 910661 # b2g(nested ipc not working) b2g-debug(debug-only failure) b2g-desktop(nested ipc not working) From bf1fcf2bb63bfb7f1d0c25b7ac108890272baa77 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 29 Sep 2015 14:13:13 +0100 Subject: [PATCH 040/104] Bug 709490 - Part 13 - explicit CTORs for a couple of runnables, CLOSED TREE --- dom/html/HTMLCanvasElement.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp index 288903a5133c..218c938b3b9e 100644 --- a/dom/html/HTMLCanvasElement.cpp +++ b/dom/html/HTMLCanvasElement.cpp @@ -1235,7 +1235,7 @@ HTMLCanvasElement::OnVisibilityChange() class Runnable final : public nsCancelableRunnable { public: - Runnable(AsyncCanvasRenderer* aRenderer) + explicit Runnable(AsyncCanvasRenderer* aRenderer) : mRenderer(aRenderer) {} @@ -1277,7 +1277,7 @@ HTMLCanvasElement::OnMemoryPressure() class Runnable final : public nsCancelableRunnable { public: - Runnable(AsyncCanvasRenderer* aRenderer) + explicit Runnable(AsyncCanvasRenderer* aRenderer) : mRenderer(aRenderer) {} From 7bd6711292154bb0ac44e56afebf698b6ba4095e Mon Sep 17 00:00:00 2001 From: Gijs Kruitbosch Date: Tue, 29 Sep 2015 09:21:12 -0400 Subject: [PATCH 041/104] Bug 1207084 - addendum: fix operator== for nsCSSValueTokenStream, implied-r=heycam --HG-- extra : commitid : D5IOMZ3yab0 extra : rebase_source : 44941f108bc6953310c817ac19189cb9b275761f --- layout/style/nsCSSValue.h | 1 + 1 file changed, 1 insertion(+) diff --git a/layout/style/nsCSSValue.h b/layout/style/nsCSSValue.h index 225dd9061438..9a4eee2ba048 100644 --- a/layout/style/nsCSSValue.h +++ b/layout/style/nsCSSValue.h @@ -1493,6 +1493,7 @@ public: return mPropertyID == aOther.mPropertyID && mShorthandPropertyID == aOther.mShorthandPropertyID && mTokenStream.Equals(aOther.mTokenStream) && + mLevel == aOther.mLevel && (mBaseURI == aOther.mBaseURI || (mBaseURI && aOther.mBaseURI && NS_SUCCEEDED(mBaseURI->Equals(aOther.mBaseURI, &eq)) && From 149731329998a6fccc2b1aa80ac2cd7a344ef14b Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Tue, 22 Sep 2015 08:45:00 -0400 Subject: [PATCH 042/104] Bug 1207090 - Expose TCPSocket to chrome contexts. r=bz --- dom/network/TCPServerSocket.cpp | 6 +-- dom/network/TCPSocket.cpp | 24 +++++++-- dom/network/TCPSocket.h | 7 +-- dom/network/moz.build | 1 + dom/network/tests/chrome.ini | 7 +++ dom/network/tests/tcpsocket_test.jsm | 13 +++++ ...st_tcpsocket_client_and_server_basics.html | 13 +++++ ...test_tcpsocket_client_and_server_basics.js | 50 ++++++++++--------- dom/network/tests/test_tcpsocket_jsm.html | 25 ++++++++++ dom/webidl/TCPServerSocket.webidl | 5 +- dom/webidl/TCPServerSocketEvent.webidl | 5 +- dom/webidl/TCPSocket.webidl | 5 +- dom/webidl/TCPSocketErrorEvent.webidl | 6 +-- dom/webidl/TCPSocketEvent.webidl | 5 +- 14 files changed, 120 insertions(+), 52 deletions(-) create mode 100644 dom/network/tests/chrome.ini create mode 100644 dom/network/tests/tcpsocket_test.jsm create mode 100644 dom/network/tests/test_tcpsocket_jsm.html diff --git a/dom/network/TCPServerSocket.cpp b/dom/network/TCPServerSocket.cpp index 7aefd7c9fbd6..ecf724689799 100644 --- a/dom/network/TCPServerSocket.cpp +++ b/dom/network/TCPServerSocket.cpp @@ -123,7 +123,7 @@ void TCPServerSocket::FireEvent(const nsAString& aType, TCPSocket* aSocket) { AutoJSAPI api; - api.Init(GetOwner()); + api.Init(GetOwnerGlobal()); TCPServerSocketEventInit init; init.mBubbles = false; @@ -144,7 +144,7 @@ TCPServerSocket::FireEvent(const nsAString& aType, TCPSocket* aSocket) NS_IMETHODIMP TCPServerSocket::OnSocketAccepted(nsIServerSocket* aServer, nsISocketTransport* aTransport) { - nsCOMPtr global = do_QueryInterface(GetOwner()); + nsCOMPtr global = GetOwnerGlobal(); nsRefPtr socket = TCPSocket::CreateAcceptedSocket(global, aTransport, mUseArrayBuffers); if (mServerBridgeParent) { socket->SetAppIdAndBrowser(mServerBridgeParent->GetAppId(), @@ -175,7 +175,7 @@ TCPServerSocket::OnStopListening(nsIServerSocket* aServer, nsresult aStatus) nsresult TCPServerSocket::AcceptChildSocket(TCPSocketChild* aSocketChild) { - nsCOMPtr global = do_QueryInterface(GetOwner()); + nsCOMPtr global = GetOwnerGlobal(); NS_ENSURE_TRUE(global, NS_ERROR_FAILURE); nsRefPtr socket = TCPSocket::CreateAcceptedSocket(global, aSocketChild, mUseArrayBuffers); NS_ENSURE_TRUE(socket, NS_ERROR_FAILURE); diff --git a/dom/network/TCPSocket.cpp b/dom/network/TCPSocket.cpp index cc978c2d5f58..73e0e1b2fa79 100644 --- a/dom/network/TCPSocket.cpp +++ b/dom/network/TCPSocket.cpp @@ -493,7 +493,7 @@ TCPSocket::FireEvent(const nsAString& aType) } AutoJSAPI api; - if (NS_WARN_IF(!api.Init(GetOwner()))) { + if (NS_WARN_IF(!api.Init(GetOwnerGlobal()))) { return NS_ERROR_FAILURE; } JS::Rooted val(api.cx()); @@ -505,7 +505,7 @@ TCPSocket::FireDataArrayEvent(const nsAString& aType, const InfallibleTArray& buffer) { AutoJSAPI api; - if (NS_WARN_IF(!api.Init(GetOwner()))) { + if (NS_WARN_IF(!api.Init(GetOwnerGlobal()))) { return NS_ERROR_FAILURE; } JSContext* cx = api.cx(); @@ -523,7 +523,7 @@ TCPSocket::FireDataStringEvent(const nsAString& aType, const nsACString& aString) { AutoJSAPI api; - if (NS_WARN_IF(!api.Init(GetOwner()))) { + if (NS_WARN_IF(!api.Init(GetOwnerGlobal()))) { return NS_ERROR_FAILURE; } JSContext* cx = api.cx(); @@ -1034,7 +1034,7 @@ TCPSocket::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInput } AutoJSAPI api; - if (!api.Init(GetOwner())) { + if (!api.Init(GetOwnerGlobal())) { return NS_ERROR_FAILURE; } JSContext* cx = api.cx(); @@ -1057,7 +1057,7 @@ TCPSocket::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInput } AutoJSAPI api; - if (!api.Init(GetOwner())) { + if (!api.Init(GetOwnerGlobal())) { return NS_ERROR_FAILURE; } JSContext* cx = api.cx(); @@ -1189,3 +1189,17 @@ TCPSocket::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aD return NS_OK; } + +/* static */ +bool +TCPSocket::ShouldTCPSocketExist(JSContext* aCx, JSObject* aGlobal) +{ + JS::Rooted global(aCx, aGlobal); + if (nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(global))) { + return true; + } + + const char* const perms[] = { "tcp-socket", nullptr }; + return Preferences::GetBool("dom.mozTCPSocket.enabled") && + CheckAnyPermissions(aCx, global, perms); +} diff --git a/dom/network/TCPSocket.h b/dom/network/TCPSocket.h index b3c692325924..10bc181b1ef0 100644 --- a/dom/network/TCPSocket.h +++ b/dom/network/TCPSocket.h @@ -88,13 +88,10 @@ public: NS_DECL_NSIOBSERVER NS_DECL_NSITCPSOCKETCALLBACK - nsPIDOMWindow* GetParentObject() const - { - return GetOwner(); - } - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + static bool ShouldTCPSocketExist(JSContext* aCx, JSObject* aGlobal); + void GetHost(nsAString& aHost); uint32_t Port(); bool Ssl(); diff --git a/dom/network/moz.build b/dom/network/moz.build index 7ad57f99e4a0..b42c30734f84 100644 --- a/dom/network/moz.build +++ b/dom/network/moz.build @@ -9,6 +9,7 @@ DIRS += ['interfaces'] if CONFIG['MOZ_B2G_RIL']: XPCSHELL_TESTS_MANIFESTS += ['tests/unit_stats/xpcshell.ini'] +MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini'] MOCHITEST_MANIFESTS += ['tests/mochitest.ini'] EXPORTS.mozilla.dom += [ diff --git a/dom/network/tests/chrome.ini b/dom/network/tests/chrome.ini new file mode 100644 index 000000000000..7e2485643b42 --- /dev/null +++ b/dom/network/tests/chrome.ini @@ -0,0 +1,7 @@ +[DEFAULT] +support-files = + tcpsocket_test.jsm + test_tcpsocket_client_and_server_basics.js + add_task.js + +[test_tcpsocket_jsm.html] \ No newline at end of file diff --git a/dom/network/tests/tcpsocket_test.jsm b/dom/network/tests/tcpsocket_test.jsm new file mode 100644 index 000000000000..367833af344d --- /dev/null +++ b/dom/network/tests/tcpsocket_test.jsm @@ -0,0 +1,13 @@ +this.EXPORTED_SYMBOLS = ['createSocket', 'createServer', 'enablePrefsAndPermissions']; + +this.createSocket = function(host, port, options) { + return new TCPSocket(host, port, options); +} + +this.createServer = function(port, options, backlog) { + return new TCPServerSocket(port, options, backlog); +} + +this.enablePrefsAndPermissions = function() { + return false; +} diff --git a/dom/network/tests/test_tcpsocket_client_and_server_basics.html b/dom/network/tests/test_tcpsocket_client_and_server_basics.html index bff6071f3ca5..99e8e88d8e09 100644 --- a/dom/network/tests/test_tcpsocket_client_and_server_basics.html +++ b/dom/network/tests/test_tcpsocket_client_and_server_basics.html @@ -13,6 +13,19 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1084245 + diff --git a/dom/network/tests/test_tcpsocket_client_and_server_basics.js b/dom/network/tests/test_tcpsocket_client_and_server_basics.js index d3aa43b19e6f..69854276b0e1 100644 --- a/dom/network/tests/test_tcpsocket_client_and_server_basics.js +++ b/dom/network/tests/test_tcpsocket_client_and_server_basics.js @@ -153,18 +153,20 @@ function defer() { function* test_basics() { - // Enable our use of TCPSocket - let prefDeferred = defer(); - SpecialPowers.pushPrefEnv( - { set: [ ['dom.mozTCPSocket.enabled', true] ] }, - prefDeferred.resolve); - yield prefDeferred.promise; + if (enablePrefsAndPermissions()) { + // Enable our use of TCPSocket + let prefDeferred = defer(); + SpecialPowers.pushPrefEnv( + { set: [ ['dom.mozTCPSocket.enabled', true] ] }, + prefDeferred.resolve); + yield prefDeferred.promise; - let permDeferred = defer(); - SpecialPowers.pushPermissions( - [ { type: 'tcp-socket', allow: true, context: document } ], - permDeferred.resolve); - yield permDeferred.promise; + let permDeferred = defer(); + SpecialPowers.pushPermissions( + [ { type: 'tcp-socket', allow: true, context: document } ], + permDeferred.resolve); + yield permDeferred.promise; + } // See bug 903830; in e10s mode we never get to find out the localPort if we // let it pick a free port by choosing 0. This is the same port the xpcshell @@ -172,15 +174,15 @@ function* test_basics() { let serverPort = 8085; // - Start up a listening socket. - let listeningServer = new TCPServerSocket(serverPort, - { binaryType: 'arraybuffer' }, - SERVER_BACKLOG); + let listeningServer = createServer(serverPort, + { binaryType: 'arraybuffer' }, + SERVER_BACKLOG); let connectedPromise = waitForConnection(listeningServer); // -- Open a connection to the server - let clientSocket = new TCPSocket('127.0.0.1', serverPort, - { binaryType: 'arraybuffer' }); + let clientSocket = createSocket('127.0.0.1', serverPort, + { binaryType: 'arraybuffer' }); let clientQueue = listenForEventsOnSocket(clientSocket, 'client'); // (the client connects) @@ -286,8 +288,8 @@ function* test_basics() { // -- Re-establish connection connectedPromise = waitForConnection(listeningServer); - clientSocket = new TCPSocket('127.0.0.1', serverPort, - { binaryType: 'arraybuffer' }); + clientSocket = createSocket('127.0.0.1', serverPort, + { binaryType: 'arraybuffer' }); clientQueue = listenForEventsOnSocket(clientSocket, 'client'); is((yield clientQueue.waitForEvent()).type, 'open', 'got open event'); @@ -313,8 +315,8 @@ function* test_basics() { // -- Re-establish connection connectedPromise = waitForConnection(listeningServer); - clientSocket = new TCPSocket('127.0.0.1', serverPort, - { binaryType: 'arraybuffer' }); + clientSocket = createSocket('127.0.0.1', serverPort, + { binaryType: 'arraybuffer' }); clientQueue = listenForEventsOnSocket(clientSocket, 'client'); is((yield clientQueue.waitForEvent()).type, 'open', 'got open event'); @@ -347,8 +349,8 @@ function* test_basics() { // -- Re-establish connection connectedPromise = waitForConnection(listeningServer); - clientSocket = new TCPSocket('127.0.0.1', serverPort, - { binaryType: 'string' }); + clientSocket = createSocket('127.0.0.1', serverPort, + { binaryType: 'string' }); clientQueue = listenForEventsOnSocket(clientSocket, 'client'); is((yield clientQueue.waitForEvent()).type, 'open', 'got open event'); @@ -375,8 +377,8 @@ function* test_basics() { listeningServer.close(); // - try and connect, get an error - clientSocket = new TCPSocket('127.0.0.1', serverPort, - { binaryType: 'arraybuffer' }); + clientSocket = createSocket('127.0.0.1', serverPort, + { binaryType: 'arraybuffer' }); clientQueue = listenForEventsOnSocket(clientSocket, 'client'); is((yield clientQueue.waitForEvent()).type, 'error', 'fail to connect'); is(clientSocket.readyState, 'closed', diff --git a/dom/network/tests/test_tcpsocket_jsm.html b/dom/network/tests/test_tcpsocket_jsm.html new file mode 100644 index 000000000000..508c3c956948 --- /dev/null +++ b/dom/network/tests/test_tcpsocket_jsm.html @@ -0,0 +1,25 @@ + + + + + + Test for 1207090 + + + + + + + +Mozilla Bug 1207090 +

+ +
+
+
+ + diff --git a/dom/webidl/TCPServerSocket.webidl b/dom/webidl/TCPServerSocket.webidl index e629fa32a86c..06d6689d2d00 100644 --- a/dom/webidl/TCPServerSocket.webidl +++ b/dom/webidl/TCPServerSocket.webidl @@ -14,9 +14,8 @@ dictionary ServerSocketOptions { }; [Constructor(unsigned short port, optional ServerSocketOptions options, optional unsigned short backlog = 0), - Pref="dom.mozTCPSocket.enabled", - CheckAnyPermissions="tcp-socket", - Exposed=Window] + Func="mozilla::dom::TCPSocket::ShouldTCPSocketExist", + Exposed=(Window,System)] interface TCPServerSocket : EventTarget { /** * The port of this server socket object. diff --git a/dom/webidl/TCPServerSocketEvent.webidl b/dom/webidl/TCPServerSocketEvent.webidl index 0842d8553db7..f133ae7812f8 100644 --- a/dom/webidl/TCPServerSocketEvent.webidl +++ b/dom/webidl/TCPServerSocketEvent.webidl @@ -4,9 +4,8 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ [Constructor(DOMString type, optional TCPServerSocketEventInit eventInitDict), - Pref="dom.mozTCPSocket.enabled", - CheckAnyPermissions="tcp-socket", - Exposed=Window] + Func="mozilla::dom::TCPSocket::ShouldTCPSocketExist", + Exposed=(Window,System)] interface TCPServerSocketEvent : Event { readonly attribute TCPSocket socket; }; diff --git a/dom/webidl/TCPSocket.webidl b/dom/webidl/TCPSocket.webidl index 0f8378ea2d02..db0336979791 100644 --- a/dom/webidl/TCPSocket.webidl +++ b/dom/webidl/TCPSocket.webidl @@ -40,9 +40,8 @@ interface LegacyMozTCPSocket { }; [Constructor(DOMString host, unsigned short port, optional SocketOptions options), - Pref="dom.mozTCPSocket.enabled", - CheckAnyPermissions="tcp-socket", - Exposed=Window] + Func="mozilla::dom::TCPSocket::ShouldTCPSocketExist", + Exposed=(Window,System)] interface TCPSocket : EventTarget { /** * Upgrade an insecure connection to use TLS. Throws if the ready state is not OPEN. diff --git a/dom/webidl/TCPSocketErrorEvent.webidl b/dom/webidl/TCPSocketErrorEvent.webidl index f8aa919ca80f..a4c98da6c4aa 100644 --- a/dom/webidl/TCPSocketErrorEvent.webidl +++ b/dom/webidl/TCPSocketErrorEvent.webidl @@ -9,9 +9,9 @@ * - if there's an error connecting to the host */ -[Pref="dom.mozTCPSocket.enabled", - CheckAnyPermissions="tcp-socket", - Constructor(DOMString type, optional TCPSocketErrorEventInit eventInitDict)] +[Func="mozilla::dom::TCPSocket::ShouldTCPSocketExist", + Constructor(DOMString type, optional TCPSocketErrorEventInit eventInitDict), + Exposed=(Window,System)] interface TCPSocketErrorEvent : Event { readonly attribute DOMString name; readonly attribute DOMString message; diff --git a/dom/webidl/TCPSocketEvent.webidl b/dom/webidl/TCPSocketEvent.webidl index f7d82f5f2e78..6a3d6851df4d 100644 --- a/dom/webidl/TCPSocketEvent.webidl +++ b/dom/webidl/TCPSocketEvent.webidl @@ -10,9 +10,8 @@ */ [Constructor(DOMString type, optional TCPSocketEventInit eventInitDict), - Pref="dom.mozTCPSocket.enabled", - CheckAnyPermissions="tcp-socket", - Exposed=Window] + Func="mozilla::dom::TCPSocket::ShouldTCPSocketExist", + Exposed=(Window,System)] interface TCPSocketEvent : Event { /** * If the event is a "data" event, data will be the bytes read from the network; From 9a6999d3f8d323e58ea7d8505bb4691db9fa69ed Mon Sep 17 00:00:00 2001 From: Armen Zambrano Gasparnian Date: Tue, 29 Sep 2015 10:00:27 -0400 Subject: [PATCH 043/104] Bug 1127449 - For Mozharness' developer's mode do not store the LDAP password unencrypted. NPOTB. DONTBUILD. r=sfink In Mozharness we support a developer mode which is capable of downloading artifacts from the Release Engineering LDAP protected artifacts. The credentials are stored for developers convenience unencrypted in a plain text. This is not wanted by most developers. In this patch we make sure that the password is prompted of the user once but we do not store on disk. --HG-- extra : commitid : GKEIU0I0xgr extra : rebase_source : 428a112417de2cb0b5c8d9b759f5a3eda3764408 --- .../mozharness/lib/python/authentication.py | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/testing/mozharness/mozharness/lib/python/authentication.py b/testing/mozharness/mozharness/lib/python/authentication.py index 26efc1abee8f..2e5f83f373ad 100644 --- a/testing/mozharness/mozharness/lib/python/authentication.py +++ b/testing/mozharness/mozharness/lib/python/authentication.py @@ -10,11 +10,15 @@ import os CREDENTIALS_PATH = os.path.expanduser("~/.mozilla/credentials.cfg") DIRNAME = os.path.dirname(CREDENTIALS_PATH) +LDAP_PASSWORD = None def get_credentials(): - """ Returns credentials for http access either from - disk or directly from the user (which we store) + """ Returns http credentials. + + The user's email address is stored on disk (for convenience in the future) + while the password is requested from the user on first invocation. """ + global LDAP_PASSWORD if not os.path.exists(DIRNAME): os.makedirs(DIRNAME) @@ -23,19 +27,24 @@ def get_credentials(): content = file_handler.read().splitlines() https_username = content[0].strip() - https_password = content[1].strip() + + if len(content) > 1: + # We want to remove files which contain the password + os.remove(CREDENTIALS_PATH) else: https_username = \ raw_input("Please enter your full LDAP email address: ") - https_password = getpass.getpass() with open(CREDENTIALS_PATH, "w+") as file_handler: file_handler.write("%s\n" % https_username) - file_handler.write("%s\n" % https_password) os.chmod(CREDENTIALS_PATH, 0600) - return https_username, https_password + if not LDAP_PASSWORD: + print "Please enter your LDAP password (we won't store it):" + LDAP_PASSWORD = getpass.getpass() + + return https_username, LDAP_PASSWORD def get_credentials_path(): if os.path.isfile(CREDENTIALS_PATH): From f47dc3beb8dc2d2b4481e10be699c194738edacd Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 28 Sep 2015 12:33:49 +0200 Subject: [PATCH 044/104] Bug 1206520: Create an option to throw on asm.js validation failures; r=luke --HG-- extra : commitid : 52Qc5TbN56w extra : rebase_source : ce652ea6554c60c5d635898bfdab065812608c03 extra : histedit_source : f68c609cc4b81c42c30a180f28ff4abd70176b14 --- js/src/asmjs/AsmJSValidate.cpp | 6 +++++- js/src/frontend/TokenStream.cpp | 5 ++++- js/src/jit-test/lib/asm.js | 8 ++++---- js/src/jsapi.cpp | 2 ++ js/src/jsapi.h | 14 ++++++++++++++ js/src/shell/js.cpp | 6 ++++++ 6 files changed, 35 insertions(+), 6 deletions(-) diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 92987a90e53f..55ffa08cbe20 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -8182,7 +8182,11 @@ CheckModule(ExclusiveContext* cx, AsmJSParser& parser, ParseNode* stmtList, static bool Warn(AsmJSParser& parser, int errorNumber, const char* str) { - parser.reportNoOffset(ParseWarning, /* strict = */ false, errorNumber, str ? str : ""); + ParseReportKind reportKind = parser.options().throwOnAsmJSValidationFailureOption && + errorNumber == JSMSG_USE_ASM_TYPE_FAIL + ? ParseError + : ParseWarning; + parser.reportNoOffset(reportKind, /* strict = */ false, errorNumber, str ? str : ""); return false; } diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 764af05b3f0f..8b24da477305 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -772,7 +772,10 @@ TokenStream::reportAsmJSError(uint32_t offset, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); + unsigned flags = options().throwOnAsmJSValidationFailureOption + ? JSREPORT_ERROR + : JSREPORT_WARNING; + reportCompileErrorNumberVA(offset, flags, errorNumber, args); va_end(args); } diff --git a/js/src/jit-test/lib/asm.js b/js/src/jit-test/lib/asm.js index a505dc392702..4724912556ea 100644 --- a/js/src/jit-test/lib/asm.js +++ b/js/src/jit-test/lib/asm.js @@ -77,9 +77,9 @@ function assertAsmTypeFail() // Verify no error is thrown with warnings off Function.apply(null, arguments); - // Turn on warnings-as-errors - var oldOpts = options("werror"); - assertEq(oldOpts.indexOf("werror"), -1); + // Turn on throwing on validation errors + var oldOpts = options("throw_on_asmjs_validation_failure"); + assertEq(oldOpts.indexOf("throw_on_asmjs_validation_failure"), -1); // Verify an error is thrown var caught = false; @@ -94,7 +94,7 @@ function assertAsmTypeFail() throw new Error("Didn't catch the type failure error"); // Turn warnings-as-errors back off - options("werror"); + options("throw_on_asmjs_validation_failure"); } function assertAsmLinkFail(f) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 9a19d5485e02..aa2b0c562f37 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3830,6 +3830,7 @@ JS::TransitiveCompileOptions::copyPODTransitiveOptions(const TransitiveCompileOp extraWarningsOption = rhs.extraWarningsOption; werrorOption = rhs.werrorOption; asmJSOption = rhs.asmJSOption; + throwOnAsmJSValidationFailureOption = rhs.throwOnAsmJSValidationFailureOption; forceAsync = rhs.forceAsync; installedFile = rhs.installedFile; sourceIsLazy = rhs.sourceIsLazy; @@ -3952,6 +3953,7 @@ JS::CompileOptions::CompileOptions(JSContext* cx, JSVersion version) extraWarningsOption = cx->compartment()->options().extraWarnings(cx); werrorOption = cx->runtime()->options().werror(); asmJSOption = cx->runtime()->options().asmJS(); + throwOnAsmJSValidationFailureOption = cx->runtime()->options().throwOnAsmJSValidationFailure(); } enum SyntacticScopeOption { HasSyntacticScope, HasNonSyntacticScope }; diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 739f7473ad89..b937970a3100 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1151,6 +1151,7 @@ class JS_PUBLIC_API(RuntimeOptions) { : baseline_(true), ion_(true), asmJS_(true), + throwOnAsmJSValidationFailure_(false), nativeRegExp_(true), unboxedArrays_(false), asyncStack_(true), @@ -1191,6 +1192,16 @@ class JS_PUBLIC_API(RuntimeOptions) { return *this; } + bool throwOnAsmJSValidationFailure() const { return throwOnAsmJSValidationFailure_; } + RuntimeOptions& setThrowOnAsmJSValidationFailure(bool flag) { + throwOnAsmJSValidationFailure_ = flag; + return *this; + } + RuntimeOptions& toggleThrowOnAsmJSValidationFailure() { + throwOnAsmJSValidationFailure_ = !throwOnAsmJSValidationFailure_; + return *this; + } + bool nativeRegExp() const { return nativeRegExp_; } RuntimeOptions& setNativeRegExp(bool flag) { nativeRegExp_ = flag; @@ -1249,6 +1260,7 @@ class JS_PUBLIC_API(RuntimeOptions) { bool baseline_ : 1; bool ion_ : 1; bool asmJS_ : 1; + bool throwOnAsmJSValidationFailure_ : 1; bool nativeRegExp_ : 1; bool unboxedArrays_ : 1; bool asyncStack_ : 1; @@ -3361,6 +3373,7 @@ class JS_FRIEND_API(TransitiveCompileOptions) extraWarningsOption(false), werrorOption(false), asmJSOption(false), + throwOnAsmJSValidationFailureOption(false), forceAsync(false), installedFile(false), sourceIsLazy(false), @@ -3395,6 +3408,7 @@ class JS_FRIEND_API(TransitiveCompileOptions) bool extraWarningsOption; bool werrorOption; bool asmJSOption; + bool throwOnAsmJSValidationFailureOption; bool forceAsync; bool installedFile; // 'true' iff pre-compiling js file in packaged app bool sourceIsLazy; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index ee297cb3e21f..e5b398c64765 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -714,6 +714,8 @@ Options(JSContext* cx, unsigned argc, Value* vp) JS::RuntimeOptionsRef(cx).toggleExtraWarnings(); else if (strcmp(opt.ptr(), "werror") == 0) JS::RuntimeOptionsRef(cx).toggleWerror(); + else if (strcmp(opt.ptr(), "throw_on_asmjs_validation_failure") == 0) + JS::RuntimeOptionsRef(cx).toggleThrowOnAsmJSValidationFailure(); else if (strcmp(opt.ptr(), "strict_mode") == 0) JS::RuntimeOptionsRef(cx).toggleStrictMode(); else { @@ -736,6 +738,10 @@ Options(JSContext* cx, unsigned argc, Value* vp) names = JS_sprintf_append(names, "%s%s", found ? "," : "", "werror"); found = true; } + if (names && oldRuntimeOptions.throwOnAsmJSValidationFailure()) { + names = JS_sprintf_append(names, "%s%s", found ? "," : "", "throw_on_asmjs_validation_failure"); + found = true; + } if (names && oldRuntimeOptions.strictMode()) { names = JS_sprintf_append(names, "%s%s", found ? "," : "", "strict_mode"); found = true; From 26ee0d3f6bc4735bd06a70cec26bcd09dd03f813 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 28 Sep 2015 12:40:03 +0200 Subject: [PATCH 045/104] Bug 1206520: Add about:config prefs to enable throwing on asm.js validation failures; r=bz --HG-- extra : commitid : 1mieasAF71F extra : rebase_source : b7b9d3aae9158b12b75cf9f29203925265b0510f extra : amend_source : 2c625d7ffa6c9b6f7ac48dcfc347c0119b459579 extra : histedit_source : 05e9b9b9cabf675bd4c742c8fe1d3b02735819c2 --- dom/workers/RuntimeService.cpp | 2 ++ js/xpconnect/src/XPCJSRuntime.cpp | 3 +++ modules/libpref/init/all.js | 1 + 3 files changed, 6 insertions(+) diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 1d5228483808..7a1749558d59 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -356,6 +356,8 @@ LoadRuntimeOptions(const char* aPrefName, void* /* aClosure */) // Runtime options. JS::RuntimeOptions runtimeOptions; runtimeOptions.setAsmJS(GetWorkerPref(NS_LITERAL_CSTRING("asmjs"))) + .setThrowOnAsmJSValidationFailure(GetWorkerPref( + NS_LITERAL_CSTRING("throw_on_asmjs_validation_failure"))) .setBaseline(GetWorkerPref(NS_LITERAL_CSTRING("baselinejit"))) .setIon(GetWorkerPref(NS_LITERAL_CSTRING("ion"))) .setNativeRegExp(GetWorkerPref(NS_LITERAL_CSTRING("native_regexp"))) diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 740bf09c6aa1..2c844987bd0c 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -1513,6 +1513,8 @@ ReloadPrefsCallback(const char* pref, void* data) bool useBaseline = Preferences::GetBool(JS_OPTIONS_DOT_STR "baselinejit") && !safeMode; bool useIon = Preferences::GetBool(JS_OPTIONS_DOT_STR "ion") && !safeMode; bool useAsmJS = Preferences::GetBool(JS_OPTIONS_DOT_STR "asmjs") && !safeMode; + bool throwOnAsmJSValidationFailure = Preferences::GetBool(JS_OPTIONS_DOT_STR + "throw_on_asmjs_validation_failure"); bool useNativeRegExp = Preferences::GetBool(JS_OPTIONS_DOT_STR "native_regexp") && !safeMode; bool parallelParsing = Preferences::GetBool(JS_OPTIONS_DOT_STR "parallel_parsing"); @@ -1536,6 +1538,7 @@ ReloadPrefsCallback(const char* pref, void* data) JS::RuntimeOptionsRef(rt).setBaseline(useBaseline) .setIon(useIon) .setAsmJS(useAsmJS) + .setThrowOnAsmJSValidationFailure(throwOnAsmJSValidationFailure) .setNativeRegExp(useNativeRegExp) .setAsyncStack(useAsyncStack) .setWerror(werror) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index ae589f113b5e..2505d262224e 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1118,6 +1118,7 @@ pref("javascript.options.asyncstack", true); #else pref("javascript.options.asyncstack", false); #endif +pref("javascript.options.throw_on_asmjs_validation_failure", false); pref("javascript.options.ion.offthread_compilation", true); // This preference instructs the JS engine to discard the // source of any privileged JS after compilation. This saves From dd395e30236b1c73ea29c2fb263584df18601b07 Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Tue, 29 Sep 2015 16:39:14 +0200 Subject: [PATCH 046/104] Bug 1208833: Disable DWrite when D2D device creation fails. r=dvander --- gfx/thebes/gfxWindowsPlatform.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 04b267488830..b6c6c16839c4 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -2444,6 +2444,7 @@ gfxWindowsPlatform::InitializeD2D() // Initialize D2D 1.0. VerifyD2DDevice(gfxPrefs::Direct2DForceEnabled()); if (!mD3D10Device) { + mDWriteFactory = nullptr; mD2DStatus = FeatureStatus::Failed; return; } From 21840c31cf71927149da7fbdfb8264356752009a Mon Sep 17 00:00:00 2001 From: Kannan Vijayan Date: Tue, 29 Sep 2015 10:41:55 -0400 Subject: [PATCH 047/104] Bug 1209193 - Cache PR_GetNumberOfProcessors when checking to do off-main-thread script compilation. r=luke --- dom/base/nsScriptLoader.cpp | 15 ++++++++++++++- dom/base/nsScriptLoader.h | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index 7120bfca3457..ad1e992e5faa 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -114,6 +114,7 @@ nsScriptLoadRequestList::Contains(nsScriptLoadRequest* aElem) nsScriptLoader::nsScriptLoader(nsIDocument *aDocument) : mDocument(aDocument), mBlockerCount(0), + mNumberOfProcessors(0), mEnabled(true), mDeferEnabled(false), mDocumentParsingDone(false), @@ -1503,6 +1504,18 @@ nsScriptLoader::ContinueParserAsync(nsScriptLoadRequest* aParserBlockingRequest) aParserBlockingRequest->mElement->ContinueParserAsync(); } +uint32_t +nsScriptLoader::NumberOfProcessors() +{ + if (mNumberOfProcessors > 0) + return mNumberOfProcessors; + + int32_t numProcs = PR_GetNumberOfProcessors(); + if (numProcs > 0) + mNumberOfProcessors = numProcs; + return mNumberOfProcessors; +} + nsresult nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest, nsIStreamLoader* aLoader, @@ -1589,7 +1602,7 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest, aRequest->mProgress = nsScriptLoadRequest::Progress_DoneLoading; // If this is currently blocking the parser, attempt to compile it off-main-thread. - if (aRequest == mParserBlockingRequest && (PR_GetNumberOfProcessors() > 1)) { + if (aRequest == mParserBlockingRequest && (NumberOfProcessors() > 1)) { nsresult rv = AttemptAsyncScriptCompile(aRequest); if (rv == NS_OK) { NS_ASSERTION(aRequest->mProgress == nsScriptLoadRequest::Progress_Compiling, diff --git a/dom/base/nsScriptLoader.h b/dom/base/nsScriptLoader.h index b3be883f5cd9..5601e8bf54c0 100644 --- a/dom/base/nsScriptLoader.h +++ b/dom/base/nsScriptLoader.h @@ -487,6 +487,7 @@ private: JS::Handle aScopeChain, JS::CompileOptions *aOptions); + uint32_t NumberOfProcessors(); nsresult PrepareLoadedRequest(nsScriptLoadRequest* aRequest, nsIStreamLoader* aLoader, nsresult aStatus, @@ -530,6 +531,7 @@ private: // XXXbz do we want to cycle-collect these or something? Not sure. nsTArray< nsRefPtr > mPendingChildLoaders; uint32_t mBlockerCount; + uint32_t mNumberOfProcessors; bool mEnabled; bool mDeferEnabled; bool mDocumentParsingDone; From 9b595ca6344cf4cd1c2199e46cb4cd07d9377191 Mon Sep 17 00:00:00 2001 From: Sotaro Ikeda Date: Tue, 29 Sep 2015 07:49:41 -0700 Subject: [PATCH 048/104] Bug 1186793 - Replace nsBaseHashtable::EnumerateRead() calls in gfx/ with iterators r=njn --- gfx/ipc/GfxMessageUtils.h | 82 ++++++++++++++------------------- gfx/src/FilterSupport.cpp | 97 +++++++++++++-------------------------- gfx/src/FilterSupport.h | 6 ++- 3 files changed, 70 insertions(+), 115 deletions(-) diff --git a/gfx/ipc/GfxMessageUtils.h b/gfx/ipc/GfxMessageUtils.h index 744907970ba5..ccafabbb5c1e 100644 --- a/gfx/ipc/GfxMessageUtils.h +++ b/gfx/ipc/GfxMessageUtils.h @@ -892,51 +892,6 @@ struct ParamTraits } }; -struct MessageAndAttributeMap -{ - Message* msg; - const mozilla::gfx::AttributeMap& map; -}; - -static bool -WriteAttribute(mozilla::gfx::AttributeName aName, - mozilla::gfx::AttributeType aType, - void* aUserData) -{ - MessageAndAttributeMap* msgAndMap = - static_cast(aUserData); - - WriteParam(msgAndMap->msg, aType); - WriteParam(msgAndMap->msg, aName); - - switch (aType) { - -#define HANDLE_TYPE(typeName) \ - case mozilla::gfx::AttributeType::e##typeName: \ - WriteParam(msgAndMap->msg, msgAndMap->map.Get##typeName(aName)); \ - break; - - HANDLE_TYPE(Bool) - HANDLE_TYPE(Uint) - HANDLE_TYPE(Float) - HANDLE_TYPE(Size) - HANDLE_TYPE(IntSize) - HANDLE_TYPE(IntPoint) - HANDLE_TYPE(Matrix) - HANDLE_TYPE(Matrix5x4) - HANDLE_TYPE(Point3D) - HANDLE_TYPE(Color) - HANDLE_TYPE(AttributeMap) - HANDLE_TYPE(Floats) - -#undef HANDLE_TYPE - - default: - MOZ_CRASH("unhandled attribute type"); - } - return true; -} - template <> struct ParamTraits { @@ -945,8 +900,41 @@ struct ParamTraits static void Write(Message* aMsg, const paramType& aParam) { WriteParam(aMsg, aParam.Count()); - MessageAndAttributeMap msgAndMap = { aMsg, aParam }; - aParam.EnumerateRead(WriteAttribute, &msgAndMap); + for (auto iter = aParam.ConstIter(); !iter.Done(); iter.Next()) { + mozilla::gfx::AttributeName name = + mozilla::gfx::AttributeName(iter.Key()); + mozilla::gfx::AttributeType type = + mozilla::gfx::AttributeMap::GetType(iter.UserData()); + + WriteParam(aMsg, type); + WriteParam(aMsg, name); + + switch (type) { + +#define CASE_TYPE(typeName) \ + case mozilla::gfx::AttributeType::e##typeName: \ + WriteParam(aMsg, aParam.Get##typeName(name)); \ + break; + + CASE_TYPE(Bool) + CASE_TYPE(Uint) + CASE_TYPE(Float) + CASE_TYPE(Size) + CASE_TYPE(IntSize) + CASE_TYPE(IntPoint) + CASE_TYPE(Matrix) + CASE_TYPE(Matrix5x4) + CASE_TYPE(Point3D) + CASE_TYPE(Color) + CASE_TYPE(AttributeMap) + CASE_TYPE(Floats) + +#undef CASE_TYPE + + default: + MOZ_CRASH("unhandled attribute type"); + } + } } static bool Read(const Message* aMsg, void** aIter, paramType* aResult) diff --git a/gfx/src/FilterSupport.cpp b/gfx/src/FilterSupport.cpp index 5b1a82453ded..8ff67f95720e 100644 --- a/gfx/src/FilterSupport.cpp +++ b/gfx/src/FilterSupport.cpp @@ -2045,20 +2045,13 @@ AttributeMap::~AttributeMap() { } -static PLDHashOperator -CopyAttribute(const uint32_t& aAttributeName, - Attribute* aAttribute, - void* aAttributes) -{ - typedef nsClassHashtable Map; - Map* map = static_cast(aAttributes); - map->Put(aAttributeName, new Attribute(*aAttribute)); - return PL_DHASH_NEXT; -} - AttributeMap::AttributeMap(const AttributeMap& aOther) { - aOther.mMap.EnumerateRead(CopyAttribute, &mMap); + for (auto iter = aOther.mMap.Iter(); !iter.Done(); iter.Next()) { + const uint32_t& attributeName = iter.Key(); + Attribute* attribute = iter.UserData(); + mMap.Put(attributeName, new Attribute(*attribute)); + } } AttributeMap& @@ -2066,34 +2059,15 @@ AttributeMap::operator=(const AttributeMap& aOther) { if (this != &aOther) { mMap.Clear(); - aOther.mMap.EnumerateRead(CopyAttribute, &mMap); + for (auto iter = aOther.mMap.Iter(); !iter.Done(); iter.Next()) { + const uint32_t& attributeName = iter.Key(); + Attribute* attribute = iter.UserData(); + mMap.Put(attributeName, new Attribute(*attribute)); + } } return *this; } -namespace { - struct MatchingMap { - typedef nsClassHashtable Map; - const Map& map; - bool matches; - }; -} // namespace - -static PLDHashOperator -CheckAttributeEquality(const uint32_t& aAttributeName, - Attribute* aAttribute, - void* aMatchingMap) -{ - MatchingMap& matchingMap = *static_cast(aMatchingMap); - Attribute* matchingAttribute = matchingMap.map.Get(aAttributeName); - if (!matchingAttribute || - *matchingAttribute != *aAttribute) { - matchingMap.matches = false; - return PL_DHASH_STOP; - } - return PL_DHASH_NEXT; -} - bool AttributeMap::operator==(const AttributeMap& aOther) const { @@ -2101,37 +2075,16 @@ AttributeMap::operator==(const AttributeMap& aOther) const return false; } - MatchingMap matchingMap = { mMap, true }; - aOther.mMap.EnumerateRead(CheckAttributeEquality, &matchingMap); - return matchingMap.matches; -} + for (auto iter = aOther.mMap.Iter(); !iter.Done(); iter.Next()) { + const uint32_t& attributeName = iter.Key(); + Attribute* attribute = iter.UserData(); + Attribute* matchingAttribute = mMap.Get(attributeName); + if (!matchingAttribute || *matchingAttribute != *attribute) { + return false; + } + } -namespace { - struct HandlerWithUserData - { - AttributeMap::AttributeHandleCallback handler; - void* userData; - }; -} // namespace - -static PLDHashOperator -PassAttributeToHandleCallback(const uint32_t& aAttributeName, - Attribute* aAttribute, - void* aHandlerWithUserData) -{ - HandlerWithUserData* handlerWithUserData = - static_cast(aHandlerWithUserData); - return handlerWithUserData->handler(AttributeName(aAttributeName), - aAttribute->Type(), - handlerWithUserData->userData) ? - PL_DHASH_NEXT : PL_DHASH_STOP; -} - -void -AttributeMap::EnumerateRead(AttributeMap::AttributeHandleCallback aCallback, void* aUserData) const -{ - HandlerWithUserData handlerWithUserData = { aCallback, aUserData }; - mMap.EnumerateRead(PassAttributeToHandleCallback, &handlerWithUserData); + return true; } uint32_t @@ -2140,6 +2093,18 @@ AttributeMap::Count() const return mMap.Count(); } +nsClassHashtable::Iterator +AttributeMap::ConstIter() const +{ + return mMap.ConstIter(); +} + +/* static */ AttributeType +AttributeMap::GetType(FilterAttribute* aAttribute) +{ + return aAttribute->Type(); +} + #define MAKE_ATTRIBUTE_HANDLERS_BASIC(type, typeLabel, defaultValue) \ type \ AttributeMap::Get##typeLabel(AttributeName aName) const { \ diff --git a/gfx/src/FilterSupport.h b/gfx/src/FilterSupport.h index baaf898c57d4..f601e3987993 100644 --- a/gfx/src/FilterSupport.h +++ b/gfx/src/FilterSupport.h @@ -221,10 +221,12 @@ public: AttributeMap GetAttributeMap(AttributeName aName) const; const nsTArray& GetFloats(AttributeName aName) const; - typedef bool (*AttributeHandleCallback)(AttributeName aName, AttributeType aType, void* aUserData); - void EnumerateRead(AttributeHandleCallback aCallback, void* aUserData) const; uint32_t Count() const; + nsClassHashtable::Iterator ConstIter() const; + + static AttributeType GetType(FilterAttribute* aAttribute); + private: mutable nsClassHashtable mMap; }; From 009f917c62be240644af7d8697b1124c598a3aae Mon Sep 17 00:00:00 2001 From: Heiher Date: Wed, 30 Sep 2015 07:02:57 +0800 Subject: [PATCH 049/104] Bug 1209528 - IonMonkey: MIPS32: Add suffix 'f' for constant float32. r=arai --- js/src/jit/mips32/CodeGenerator-mips32.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) --- js/src/jit/mips32/CodeGenerator-mips32.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/js/src/jit/mips32/CodeGenerator-mips32.cpp b/js/src/jit/mips32/CodeGenerator-mips32.cpp index db71c3bccd39..bf3ee6f9c021 100644 --- a/js/src/jit/mips32/CodeGenerator-mips32.cpp +++ b/js/src/jit/mips32/CodeGenerator-mips32.cpp @@ -278,7 +278,7 @@ CodeGeneratorMIPS::visitMinMaxF(LMinMaxF* ins) // Check for zero. masm.bind(&equal); - masm.loadConstantFloat32(0.0, ScratchFloat32Reg); + masm.loadConstantFloat32(0.0f, ScratchFloat32Reg); // First wasn't 0 or -0, so just return it. masm.ma_bc1s(first, ScratchFloat32Reg, &done, Assembler::DoubleNotEqualOrUnordered, ShortJump); @@ -1104,7 +1104,7 @@ CodeGeneratorMIPS::visitFloorF(LFloorF* lir) Label skipCheck, done; // If Nan, 0 or -0 check for bailout - masm.loadConstantFloat32(0.0, scratch); + masm.loadConstantFloat32(0.0f, scratch); masm.ma_bc1s(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump); // If binary value is not zero, it is NaN or -0, so we bail. @@ -1264,7 +1264,7 @@ CodeGeneratorMIPS::visitRoundF(LRoundF* lir) masm.loadConstantFloat32(0.5, temp); // Branch to a slow path for negative inputs. Doesn't catch NaN or -0. - masm.loadConstantFloat32(0.0, scratch); + masm.loadConstantFloat32(0.0f, scratch); masm.ma_bc1s(input, scratch, &negative, Assembler::DoubleLessThan, ShortJump); // If Nan, 0 or -0 check for bailout @@ -1475,7 +1475,7 @@ CodeGeneratorMIPS::visitTestFAndBranch(LTestFAndBranch* test) MBasicBlock* ifTrue = test->ifTrue(); MBasicBlock* ifFalse = test->ifFalse(); - masm.loadConstantFloat32(0.0, ScratchFloat32Reg); + masm.loadConstantFloat32(0.0f, ScratchFloat32Reg); // If 0, or NaN, the result is false. if (isNextBlock(ifFalse->lir())) { @@ -1700,7 +1700,7 @@ CodeGeneratorMIPS::visitNotF(LNotF* ins) Register dest = ToRegister(ins->output()); Label falsey, done; - masm.loadConstantFloat32(0.0, ScratchFloat32Reg); + masm.loadConstantFloat32(0.0f, ScratchFloat32Reg); masm.ma_bc1s(in, ScratchFloat32Reg, &falsey, Assembler::DoubleEqualOrUnordered, ShortJump); masm.move32(Imm32(0), dest); From 80b101df19561ccb9e3a1e686f21fb4841357e5e Mon Sep 17 00:00:00 2001 From: Heiher Date: Wed, 30 Sep 2015 07:03:03 +0800 Subject: [PATCH 050/104] Bug 1205229 - IonMonkey: MIPS32: Make more CodeGenerator functions can be shared. r=nbp --- js/src/jit/mips32/CodeGenerator-mips32.cpp | 9 +++++---- js/src/jit/mips32/CodeGenerator-mips32.h | 7 +++++-- 2 files changed, 10 insertions(+), 6 deletions(-) --- js/src/jit/mips32/CodeGenerator-mips32.cpp | 9 +++++---- js/src/jit/mips32/CodeGenerator-mips32.h | 7 +++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/js/src/jit/mips32/CodeGenerator-mips32.cpp b/js/src/jit/mips32/CodeGenerator-mips32.cpp index bf3ee6f9c021..da3efa7eaf2a 100644 --- a/js/src/jit/mips32/CodeGenerator-mips32.cpp +++ b/js/src/jit/mips32/CodeGenerator-mips32.cpp @@ -135,7 +135,8 @@ CodeGeneratorMIPS::visitCompareAndBranch(LCompareAndBranch* comp) emitBranch(ToRegister(comp->left()), ToRegister(comp->right()), cond, comp->ifTrue(), comp->ifFalse()); } else { - emitBranch(ToRegister(comp->left()), ToAddress(comp->right()), cond, + masm.load32(ToAddress(comp->right()), ScratchRegister); + emitBranch(ToRegister(comp->left()), ScratchRegister, cond, comp->ifTrue(), comp->ifFalse()); } } @@ -1744,7 +1745,7 @@ CodeGeneratorMIPS::visitGuardClass(LGuardClass* guard) Register tmp = ToRegister(guard->tempInt()); masm.loadObjClass(obj, tmp); - bailoutCmpPtr(Assembler::NotEqual, tmp, Imm32((uint32_t)guard->mir()->getClass()), + bailoutCmpPtr(Assembler::NotEqual, tmp, ImmPtr(guard->mir()->getClass()), guard->snapshot()); } @@ -2079,8 +2080,8 @@ CodeGeneratorMIPS::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins) Register out = ToRegister(ins->output()); unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias; - BaseIndex source(GlobalReg, index, TimesFour, addr); - masm.load32(source, out); + BaseIndex source(GlobalReg, index, ScalePointer, addr); + masm.loadPtr(source, out); } void diff --git a/js/src/jit/mips32/CodeGenerator-mips32.h b/js/src/jit/mips32/CodeGenerator-mips32.h index 1e56d0ade080..bfe90bb6500d 100644 --- a/js/src/jit/mips32/CodeGenerator-mips32.h +++ b/js/src/jit/mips32/CodeGenerator-mips32.h @@ -35,7 +35,7 @@ class CodeGeneratorMIPS : public CodeGeneratorShared template void bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) { Label skip; - masm.ma_b(lhs, rhs, &skip, Assembler::InvertCondition(c), ShortJump); + masm.branch32(Assembler::InvertCondition(c), lhs, rhs, &skip); bailout(snapshot); masm.bind(&skip); } @@ -56,7 +56,10 @@ class CodeGeneratorMIPS : public CodeGeneratorShared } template void bailoutCmpPtr(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) { - bailoutCmp32(c, lhs, rhs, snapshot); + Label skip; + masm.branchPtr(Assembler::InvertCondition(c), lhs, rhs, &skip); + bailout(snapshot); + masm.bind(&skip); } void bailoutTestPtr(Assembler::Condition c, Register lhs, Register rhs, LSnapshot* snapshot) { Label bail; From b64039b81e8701063c9087ce3d2d16a6ef689c16 Mon Sep 17 00:00:00 2001 From: Heiher Date: Wed, 30 Sep 2015 07:03:10 +0800 Subject: [PATCH 051/104] Bug 1205232 - IonMonkey: MIPS32: Fix rounding of big negative float32 values in Ion. r=bbouvier --- js/src/jit/mips32/CodeGenerator-mips32.cpp | 32 ++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) --- js/src/jit/mips32/CodeGenerator-mips32.cpp | 32 ++++++++++++++++------ 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/js/src/jit/mips32/CodeGenerator-mips32.cpp b/js/src/jit/mips32/CodeGenerator-mips32.cpp index da3efa7eaf2a..f60dc0786e9c 100644 --- a/js/src/jit/mips32/CodeGenerator-mips32.cpp +++ b/js/src/jit/mips32/CodeGenerator-mips32.cpp @@ -1202,8 +1202,8 @@ CodeGeneratorMIPS::visitRound(LRound* lir) Label bail, negative, end, skipCheck; - // Load 0.5 in the temp register. - masm.loadConstantDouble(0.5, temp); + // Load biggest number less than 0.5 in the temp register. + masm.loadConstantDouble(GetBiggestNumberLessThan(0.5), temp); // Branch to a slow path for negative inputs. Doesn't catch NaN or -0. masm.loadConstantDouble(0.0, scratch); @@ -1221,8 +1221,7 @@ CodeGeneratorMIPS::visitRound(LRound* lir) masm.ma_b(&end, ShortJump); masm.bind(&skipCheck); - masm.loadConstantDouble(0.5, scratch); - masm.addDouble(input, scratch); + masm.as_addd(scratch, input, temp); masm.as_floorwd(scratch, scratch); masm.moveFromDoubleLo(scratch, output); @@ -1234,6 +1233,15 @@ CodeGeneratorMIPS::visitRound(LRound* lir) // Input is negative, but isn't -0. masm.bind(&negative); + + // Inputs in ]-0.5; 0] need to be added 0.5, other negative inputs need to + // be added the biggest double less than 0.5. + Label loadJoin; + masm.loadConstantDouble(-0.5, scratch); + masm.branchDouble(Assembler::DoubleLessThan, input, scratch, &loadJoin); + masm.loadConstantDouble(0.5, temp); + masm.bind(&loadJoin); + masm.addDouble(input, temp); // If input + 0.5 >= 0, input is a negative number >= -0.5 and the @@ -1261,8 +1269,8 @@ CodeGeneratorMIPS::visitRoundF(LRoundF* lir) Label bail, negative, end, skipCheck; - // Load 0.5 in the temp register. - masm.loadConstantFloat32(0.5, temp); + // Load biggest number less than 0.5 in the temp register. + masm.loadConstantFloat32(GetBiggestNumberLessThan(0.5f), temp); // Branch to a slow path for negative inputs. Doesn't catch NaN or -0. masm.loadConstantFloat32(0.0f, scratch); @@ -1280,8 +1288,7 @@ CodeGeneratorMIPS::visitRoundF(LRoundF* lir) masm.ma_b(&end, ShortJump); masm.bind(&skipCheck); - masm.loadConstantFloat32(0.5, scratch); - masm.as_adds(scratch, input, scratch); + masm.as_adds(scratch, input, temp); masm.as_floorws(scratch, scratch); masm.moveFromFloat32(scratch, output); @@ -1293,6 +1300,15 @@ CodeGeneratorMIPS::visitRoundF(LRoundF* lir) // Input is negative, but isn't -0. masm.bind(&negative); + + // Inputs in ]-0.5; 0] need to be added 0.5, other negative inputs need to + // be added the biggest double less than 0.5. + Label loadJoin; + masm.loadConstantFloat32(-0.5f, scratch); + masm.branchFloat(Assembler::DoubleLessThan, input, scratch, &loadJoin); + masm.loadConstantFloat32(0.5f, temp); + masm.bind(&loadJoin); + masm.as_adds(temp, input, temp); // If input + 0.5 >= 0, input is a negative number >= -0.5 and the From 9ae9d645eddac4adef456e6be3fbb0e270f8aaa0 Mon Sep 17 00:00:00 2001 From: Heiher Date: Wed, 30 Sep 2015 07:03:21 +0800 Subject: [PATCH 052/104] Bug 1205135 - IonMonkey: MIPS: Split shareable code to mips-shared in CodeGenerator-mips32. r=nbp --- .../CodeGenerator-mips-shared.cpp} | 440 +---- .../CodeGenerator-mips-shared.h} | 55 +- js/src/jit/mips32/CodeGenerator-mips32.cpp | 1887 +------------------- js/src/jit/mips32/CodeGenerator-mips32.h | 236 +-- js/src/moz.build | 1 + 5 files changed, 118 insertions(+), 2501 deletions(-) copy js/src/jit/{mips32/CodeGenerator-mips32.cpp => mips-shared/CodeGenerator-mips-shared.cpp} (81%) copy js/src/jit/{mips32/CodeGenerator-mips32.h => mips-shared/CodeGenerator-mips-shared.h} (81%) --HG-- rename : js/src/jit/mips32/CodeGenerator-mips32.cpp => js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp rename : js/src/jit/mips32/CodeGenerator-mips32.h => js/src/jit/mips-shared/CodeGenerator-mips-shared.h --- .../mips-shared/CodeGenerator-mips-shared.cpp | 1869 +++++++++++++++++ .../mips-shared/CodeGenerator-mips-shared.h | 258 +++ js/src/jit/mips32/CodeGenerator-mips32.cpp | 1845 ---------------- js/src/jit/mips32/CodeGenerator-mips32.h | 236 +-- js/src/moz.build | 1 + 5 files changed, 2133 insertions(+), 2076 deletions(-) create mode 100644 js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp create mode 100644 js/src/jit/mips-shared/CodeGenerator-mips-shared.h diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp new file mode 100644 index 000000000000..3aadaac05e3f --- /dev/null +++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp @@ -0,0 +1,1869 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jit/mips-shared/CodeGenerator-mips-shared.h" + +#include "mozilla/MathAlgorithms.h" + +#include "jscntxt.h" +#include "jscompartment.h" +#include "jsnum.h" + +#include "jit/CodeGenerator.h" +#include "jit/JitCompartment.h" +#include "jit/JitFrames.h" +#include "jit/MIR.h" +#include "jit/MIRGraph.h" +#include "js/Conversions.h" +#include "vm/Shape.h" +#include "vm/TraceLogging.h" + +#include "jsscriptinlines.h" + +#include "jit/MacroAssembler-inl.h" +#include "jit/shared/CodeGenerator-shared-inl.h" + +using namespace js; +using namespace js::jit; + +using mozilla::FloorLog2; +using mozilla::NegativeInfinity; +using JS::GenericNaN; +using JS::ToInt32; + +// inline +Address +CodeGeneratorMIPSShared::ToAddress(const LAllocation& a) +{ + MOZ_ASSERT(a.isMemory()); + int32_t offset = ToStackOffset(&a); + + return Address(StackPointer, offset); +} + +// inline +Address +CodeGeneratorMIPSShared::ToAddress(const LAllocation* a) +{ + return ToAddress(*a); +} + + +// shared +CodeGeneratorMIPSShared::CodeGeneratorMIPSShared(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm) + : CodeGeneratorShared(gen, graph, masm) +{ +} + +void +CodeGeneratorMIPSShared::branchToBlock(Assembler::FloatFormat fmt, FloatRegister lhs, FloatRegister rhs, + MBasicBlock* mir, Assembler::DoubleCondition cond) +{ + // Skip past trivial blocks. + mir = skipTrivialBlocks(mir); + + Label* label = mir->lir()->label(); + if (Label* oolEntry = labelForBackedgeWithImplicitCheck(mir)) { + // Note: the backedge is initially a jump to the next instruction. + // It will be patched to the target block's label during link(). + RepatchLabel rejoin; + + CodeOffsetJump backedge; + Label skip; + if (fmt == Assembler::DoubleFloat) + masm.ma_bc1d(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump); + else + masm.ma_bc1s(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump); + + backedge = masm.backedgeJump(&rejoin); + masm.bind(&rejoin); + masm.bind(&skip); + + if (!patchableBackedges_.append(PatchableBackedgeInfo(backedge, label, oolEntry))) + MOZ_CRASH(); + } else { + if (fmt == Assembler::DoubleFloat) + masm.branchDouble(cond, lhs, rhs, mir->lir()->label()); + else + masm.branchFloat(cond, lhs, rhs, mir->lir()->label()); + } +} + +void +OutOfLineBailout::accept(CodeGeneratorMIPSShared* codegen) +{ + codegen->visitOutOfLineBailout(this); +} + +void +CodeGeneratorMIPSShared::visitTestIAndBranch(LTestIAndBranch* test) +{ + const LAllocation* opd = test->getOperand(0); + MBasicBlock* ifTrue = test->ifTrue(); + MBasicBlock* ifFalse = test->ifFalse(); + + emitBranch(ToRegister(opd), Imm32(0), Assembler::NonZero, ifTrue, ifFalse); +} + +void +CodeGeneratorMIPSShared::visitCompare(LCompare* comp) +{ + Assembler::Condition cond = JSOpToCondition(comp->mir()->compareType(), comp->jsop()); + const LAllocation* left = comp->getOperand(0); + const LAllocation* right = comp->getOperand(1); + const LDefinition* def = comp->getDef(0); + + if (right->isConstant()) + masm.cmp32Set(cond, ToRegister(left), Imm32(ToInt32(right)), ToRegister(def)); + else if (right->isGeneralReg()) + masm.cmp32Set(cond, ToRegister(left), ToRegister(right), ToRegister(def)); + else + masm.cmp32Set(cond, ToRegister(left), ToAddress(right), ToRegister(def)); +} + +void +CodeGeneratorMIPSShared::visitCompareAndBranch(LCompareAndBranch* comp) +{ + Assembler::Condition cond = JSOpToCondition(comp->cmpMir()->compareType(), comp->jsop()); + if (comp->right()->isConstant()) { + emitBranch(ToRegister(comp->left()), Imm32(ToInt32(comp->right())), cond, + comp->ifTrue(), comp->ifFalse()); + } else if (comp->right()->isGeneralReg()) { + emitBranch(ToRegister(comp->left()), ToRegister(comp->right()), cond, + comp->ifTrue(), comp->ifFalse()); + } else { + masm.load32(ToAddress(comp->right()), ScratchRegister); + emitBranch(ToRegister(comp->left()), ScratchRegister, cond, + comp->ifTrue(), comp->ifFalse()); + } +} + +bool +CodeGeneratorMIPSShared::generateOutOfLineCode() +{ + if (!CodeGeneratorShared::generateOutOfLineCode()) + return false; + + if (deoptLabel_.used()) { + // All non-table-based bailouts will go here. + masm.bind(&deoptLabel_); + + // Push the frame size, so the handler can recover the IonScript. + // Frame size is stored in 'ra' and pushed by GenerateBailoutThunk + // We have to use 'ra' because generateBailoutTable will implicitly do + // the same. + masm.move32(Imm32(frameSize()), ra); + + JitCode* handler = gen->jitRuntime()->getGenericBailoutHandler(); + + masm.branch(handler); + } + + return true; +} + +void +CodeGeneratorMIPSShared::bailoutFrom(Label* label, LSnapshot* snapshot) +{ + if (masm.bailed()) + return; + + MOZ_ASSERT(label->used()); + MOZ_ASSERT(!label->bound()); + + encode(snapshot); + + // Though the assembler doesn't track all frame pushes, at least make sure + // the known value makes sense. We can't use bailout tables if the stack + // isn't properly aligned to the static frame size. + MOZ_ASSERT_IF(frameClass_ != FrameSizeClass::None(), + frameClass_.frameSize() == masm.framePushed()); + + // We don't use table bailouts because retargeting is easier this way. + InlineScriptTree* tree = snapshot->mir()->block()->trackedTree(); + OutOfLineBailout* ool = new(alloc()) OutOfLineBailout(snapshot, masm.framePushed()); + addOutOfLineCode(ool, new(alloc()) BytecodeSite(tree, tree->script()->code())); + + masm.retarget(label, ool->entry()); +} + +void +CodeGeneratorMIPSShared::bailout(LSnapshot* snapshot) +{ + Label label; + masm.jump(&label); + bailoutFrom(&label, snapshot); +} + +void +CodeGeneratorMIPSShared::visitOutOfLineBailout(OutOfLineBailout* ool) +{ + // Push snapshotOffset and make sure stack is aligned. + masm.subPtr(Imm32(2 * sizeof(void*)), StackPointer); + masm.storePtr(ImmWord(ool->snapshot()->snapshotOffset()), Address(StackPointer, 0)); + + masm.jump(&deoptLabel_); +} + +void +CodeGeneratorMIPSShared::visitMinMaxD(LMinMaxD* ins) +{ + FloatRegister first = ToFloatRegister(ins->first()); + FloatRegister second = ToFloatRegister(ins->second()); + FloatRegister output = ToFloatRegister(ins->output()); + + MOZ_ASSERT(first == output); + + Assembler::DoubleCondition cond = ins->mir()->isMax() + ? Assembler::DoubleLessThanOrEqual + : Assembler::DoubleGreaterThanOrEqual; + Label nan, equal, returnSecond, done; + + // First or second is NaN, result is NaN. + masm.ma_bc1d(first, second, &nan, Assembler::DoubleUnordered, ShortJump); + // Make sure we handle -0 and 0 right. + masm.ma_bc1d(first, second, &equal, Assembler::DoubleEqual, ShortJump); + masm.ma_bc1d(first, second, &returnSecond, cond, ShortJump); + masm.ma_b(&done, ShortJump); + + // Check for zero. + masm.bind(&equal); + masm.loadConstantDouble(0.0, ScratchDoubleReg); + // First wasn't 0 or -0, so just return it. + masm.ma_bc1d(first, ScratchDoubleReg, &done, Assembler::DoubleNotEqualOrUnordered, ShortJump); + + // So now both operands are either -0 or 0. + if (ins->mir()->isMax()) { + // -0 + -0 = -0 and -0 + 0 = 0. + masm.addDouble(second, first); + } else { + masm.negateDouble(first); + masm.subDouble(second, first); + masm.negateDouble(first); + } + masm.ma_b(&done, ShortJump); + + masm.bind(&nan); + masm.loadConstantDouble(GenericNaN(), output); + masm.ma_b(&done, ShortJump); + + masm.bind(&returnSecond); + masm.moveDouble(second, output); + + masm.bind(&done); +} + +void +CodeGeneratorMIPSShared::visitMinMaxF(LMinMaxF* ins) +{ + FloatRegister first = ToFloatRegister(ins->first()); + FloatRegister second = ToFloatRegister(ins->second()); + FloatRegister output = ToFloatRegister(ins->output()); + + MOZ_ASSERT(first == output); + + Assembler::DoubleCondition cond = ins->mir()->isMax() + ? Assembler::DoubleLessThanOrEqual + : Assembler::DoubleGreaterThanOrEqual; + Label nan, equal, returnSecond, done; + + // First or second is NaN, result is NaN. + masm.ma_bc1s(first, second, &nan, Assembler::DoubleUnordered, ShortJump); + // Make sure we handle -0 and 0 right. + masm.ma_bc1s(first, second, &equal, Assembler::DoubleEqual, ShortJump); + masm.ma_bc1s(first, second, &returnSecond, cond, ShortJump); + masm.ma_b(&done, ShortJump); + + // Check for zero. + masm.bind(&equal); + masm.loadConstantFloat32(0.0f, ScratchFloat32Reg); + // First wasn't 0 or -0, so just return it. + masm.ma_bc1s(first, ScratchFloat32Reg, &done, Assembler::DoubleNotEqualOrUnordered, ShortJump); + + // So now both operands are either -0 or 0. + if (ins->mir()->isMax()) { + // -0 + -0 = -0 and -0 + 0 = 0. + masm.as_adds(first, first, second); + } else { + masm.as_negs(first, first); + masm.as_subs(first, first, second); + masm.as_negs(first, first); + } + masm.ma_b(&done, ShortJump); + + masm.bind(&nan); + masm.loadConstantFloat32(GenericNaN(), output); + masm.ma_b(&done, ShortJump); + masm.bind(&returnSecond); + masm.as_movs(output, second); + + masm.bind(&done); +} + +void +CodeGeneratorMIPSShared::visitAbsD(LAbsD* ins) +{ + FloatRegister input = ToFloatRegister(ins->input()); + MOZ_ASSERT(input == ToFloatRegister(ins->output())); + masm.as_absd(input, input); +} + +void +CodeGeneratorMIPSShared::visitAbsF(LAbsF* ins) +{ + FloatRegister input = ToFloatRegister(ins->input()); + MOZ_ASSERT(input == ToFloatRegister(ins->output())); + masm.as_abss(input, input); +} + +void +CodeGeneratorMIPSShared::visitSqrtD(LSqrtD* ins) +{ + FloatRegister input = ToFloatRegister(ins->input()); + FloatRegister output = ToFloatRegister(ins->output()); + masm.as_sqrtd(output, input); +} + +void +CodeGeneratorMIPSShared::visitSqrtF(LSqrtF* ins) +{ + FloatRegister input = ToFloatRegister(ins->input()); + FloatRegister output = ToFloatRegister(ins->output()); + masm.as_sqrts(output, input); +} + +void +CodeGeneratorMIPSShared::visitAddI(LAddI* ins) +{ + const LAllocation* lhs = ins->getOperand(0); + const LAllocation* rhs = ins->getOperand(1); + const LDefinition* dest = ins->getDef(0); + + MOZ_ASSERT(rhs->isConstant() || rhs->isGeneralReg()); + + // If there is no snapshot, we don't need to check for overflow + if (!ins->snapshot()) { + if (rhs->isConstant()) + masm.ma_addu(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs))); + else + masm.as_addu(ToRegister(dest), ToRegister(lhs), ToRegister(rhs)); + return; + } + + Label overflow; + if (rhs->isConstant()) + masm.ma_addTestOverflow(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)), &overflow); + else + masm.ma_addTestOverflow(ToRegister(dest), ToRegister(lhs), ToRegister(rhs), &overflow); + + bailoutFrom(&overflow, ins->snapshot()); +} + +void +CodeGeneratorMIPSShared::visitSubI(LSubI* ins) +{ + const LAllocation* lhs = ins->getOperand(0); + const LAllocation* rhs = ins->getOperand(1); + const LDefinition* dest = ins->getDef(0); + + MOZ_ASSERT(rhs->isConstant() || rhs->isGeneralReg()); + + // If there is no snapshot, we don't need to check for overflow + if (!ins->snapshot()) { + if (rhs->isConstant()) + masm.ma_subu(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs))); + else + masm.as_subu(ToRegister(dest), ToRegister(lhs), ToRegister(rhs)); + return; + } + + Label overflow; + if (rhs->isConstant()) + masm.ma_subTestOverflow(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)), &overflow); + else + masm.ma_subTestOverflow(ToRegister(dest), ToRegister(lhs), ToRegister(rhs), &overflow); + + bailoutFrom(&overflow, ins->snapshot()); +} + +void +CodeGeneratorMIPSShared::visitMulI(LMulI* ins) +{ + const LAllocation* lhs = ins->lhs(); + const LAllocation* rhs = ins->rhs(); + Register dest = ToRegister(ins->output()); + MMul* mul = ins->mir(); + + MOZ_ASSERT_IF(mul->mode() == MMul::Integer, !mul->canBeNegativeZero() && !mul->canOverflow()); + + if (rhs->isConstant()) { + int32_t constant = ToInt32(rhs); + Register src = ToRegister(lhs); + + // Bailout on -0.0 + if (mul->canBeNegativeZero() && constant <= 0) { + Assembler::Condition cond = (constant == 0) ? Assembler::LessThan : Assembler::Equal; + bailoutCmp32(cond, src, Imm32(0), ins->snapshot()); + } + + switch (constant) { + case -1: + if (mul->canOverflow()) + bailoutCmp32(Assembler::Equal, src, Imm32(INT32_MIN), ins->snapshot()); + + masm.ma_negu(dest, src); + break; + case 0: + masm.move32(Imm32(0), dest); + break; + case 1: + masm.move32(src, dest); + break; + case 2: + if (mul->canOverflow()) { + Label mulTwoOverflow; + masm.ma_addTestOverflow(dest, src, src, &mulTwoOverflow); + + bailoutFrom(&mulTwoOverflow, ins->snapshot()); + } else { + masm.as_addu(dest, src, src); + } + break; + default: + uint32_t shift = FloorLog2(constant); + + if (!mul->canOverflow() && (constant > 0)) { + // If it cannot overflow, we can do lots of optimizations. + uint32_t rest = constant - (1 << shift); + + // See if the constant has one bit set, meaning it can be + // encoded as a bitshift. + if ((1 << shift) == constant) { + masm.ma_sll(dest, src, Imm32(shift)); + return; + } + + // If the constant cannot be encoded as (1<canOverflow() && (constant > 0) && (src != dest)) { + // To stay on the safe side, only optimize things that are a + // power of 2. + + if ((1 << shift) == constant) { + // dest = lhs * pow(2, shift) + masm.ma_sll(dest, src, Imm32(shift)); + // At runtime, check (lhs == dest >> shift), if this does + // not hold, some bits were lost due to overflow, and the + // computation should be resumed as a double. + masm.ma_sra(ScratchRegister, dest, Imm32(shift)); + bailoutCmp32(Assembler::NotEqual, src, ScratchRegister, ins->snapshot()); + return; + } + } + + if (mul->canOverflow()) { + Label mulConstOverflow; + masm.ma_mul_branch_overflow(dest, ToRegister(lhs), Imm32(ToInt32(rhs)), + &mulConstOverflow); + + bailoutFrom(&mulConstOverflow, ins->snapshot()); + } else { + masm.ma_mult(src, Imm32(ToInt32(rhs))); + masm.as_mflo(dest); + } + break; + } + } else { + Label multRegOverflow; + + if (mul->canOverflow()) { + masm.ma_mul_branch_overflow(dest, ToRegister(lhs), ToRegister(rhs), &multRegOverflow); + bailoutFrom(&multRegOverflow, ins->snapshot()); + } else { + masm.as_mult(ToRegister(lhs), ToRegister(rhs)); + masm.as_mflo(dest); + } + + if (mul->canBeNegativeZero()) { + Label done; + masm.ma_b(dest, dest, &done, Assembler::NonZero, ShortJump); + + // Result is -0 if lhs or rhs is negative. + // In that case result must be double value so bailout + Register scratch = SecondScratchReg; + masm.as_or(scratch, ToRegister(lhs), ToRegister(rhs)); + bailoutCmp32(Assembler::Signed, scratch, scratch, ins->snapshot()); + + masm.bind(&done); + } + } +} + +void +CodeGeneratorMIPSShared::visitDivI(LDivI* ins) +{ + // Extract the registers from this instruction + Register lhs = ToRegister(ins->lhs()); + Register rhs = ToRegister(ins->rhs()); + Register dest = ToRegister(ins->output()); + Register temp = ToRegister(ins->getTemp(0)); + MDiv* mir = ins->mir(); + + Label done; + + // Handle divide by zero. + if (mir->canBeDivideByZero()) { + if (mir->canTruncateInfinities()) { + // Truncated division by zero is zero (Infinity|0 == 0) + Label notzero; + masm.ma_b(rhs, rhs, ¬zero, Assembler::NonZero, ShortJump); + masm.move32(Imm32(0), dest); + masm.ma_b(&done, ShortJump); + masm.bind(¬zero); + } else { + MOZ_ASSERT(mir->fallible()); + bailoutCmp32(Assembler::Zero, rhs, rhs, ins->snapshot()); + } + } + + // Handle an integer overflow exception from -2147483648 / -1. + if (mir->canBeNegativeOverflow()) { + Label notMinInt; + masm.move32(Imm32(INT32_MIN), temp); + masm.ma_b(lhs, temp, ¬MinInt, Assembler::NotEqual, ShortJump); + + masm.move32(Imm32(-1), temp); + if (mir->canTruncateOverflow()) { + // (-INT32_MIN)|0 == INT32_MIN + Label skip; + masm.ma_b(rhs, temp, &skip, Assembler::NotEqual, ShortJump); + masm.move32(Imm32(INT32_MIN), dest); + masm.ma_b(&done, ShortJump); + masm.bind(&skip); + } else { + MOZ_ASSERT(mir->fallible()); + bailoutCmp32(Assembler::Equal, rhs, temp, ins->snapshot()); + } + masm.bind(¬MinInt); + } + + // Handle negative 0. (0/-Y) + if (!mir->canTruncateNegativeZero() && mir->canBeNegativeZero()) { + Label nonzero; + masm.ma_b(lhs, lhs, &nonzero, Assembler::NonZero, ShortJump); + bailoutCmp32(Assembler::LessThan, rhs, Imm32(0), ins->snapshot()); + masm.bind(&nonzero); + } + // Note: above safety checks could not be verified as Ion seems to be + // smarter and requires double arithmetic in such cases. + + // All regular. Lets call div. + if (mir->canTruncateRemainder()) { + masm.as_div(lhs, rhs); + masm.as_mflo(dest); + } else { + MOZ_ASSERT(mir->fallible()); + + Label remainderNonZero; + masm.ma_div_branch_overflow(dest, lhs, rhs, &remainderNonZero); + bailoutFrom(&remainderNonZero, ins->snapshot()); + } + + masm.bind(&done); +} + +void +CodeGeneratorMIPSShared::visitDivPowTwoI(LDivPowTwoI* ins) +{ + Register lhs = ToRegister(ins->numerator()); + Register dest = ToRegister(ins->output()); + Register tmp = ToRegister(ins->getTemp(0)); + int32_t shift = ins->shift(); + + if (shift != 0) { + MDiv* mir = ins->mir(); + if (!mir->isTruncated()) { + // If the remainder is going to be != 0, bailout since this must + // be a double. + masm.ma_sll(tmp, lhs, Imm32(32 - shift)); + bailoutCmp32(Assembler::NonZero, tmp, tmp, ins->snapshot()); + } + + if (!mir->canBeNegativeDividend()) { + // Numerator is unsigned, so needs no adjusting. Do the shift. + masm.ma_sra(dest, lhs, Imm32(shift)); + return; + } + + // Adjust the value so that shifting produces a correctly rounded result + // when the numerator is negative. See 10-1 "Signed Division by a Known + // Power of 2" in Henry S. Warren, Jr.'s Hacker's Delight. + if (shift > 1) { + masm.ma_sra(tmp, lhs, Imm32(31)); + masm.ma_srl(tmp, tmp, Imm32(32 - shift)); + masm.add32(lhs, tmp); + } else { + masm.ma_srl(tmp, lhs, Imm32(32 - shift)); + masm.add32(lhs, tmp); + } + + // Do the shift. + masm.ma_sra(dest, tmp, Imm32(shift)); + } else { + masm.move32(lhs, dest); + } +} + +void +CodeGeneratorMIPSShared::visitModI(LModI* ins) +{ + // Extract the registers from this instruction + Register lhs = ToRegister(ins->lhs()); + Register rhs = ToRegister(ins->rhs()); + Register dest = ToRegister(ins->output()); + Register callTemp = ToRegister(ins->callTemp()); + MMod* mir = ins->mir(); + Label done, prevent; + + masm.move32(lhs, callTemp); + + // Prevent INT_MIN % -1; + // The integer division will give INT_MIN, but we want -(double)INT_MIN. + if (mir->canBeNegativeDividend()) { + masm.ma_b(lhs, Imm32(INT_MIN), &prevent, Assembler::NotEqual, ShortJump); + if (mir->isTruncated()) { + // (INT_MIN % -1)|0 == 0 + Label skip; + masm.ma_b(rhs, Imm32(-1), &skip, Assembler::NotEqual, ShortJump); + masm.move32(Imm32(0), dest); + masm.ma_b(&done, ShortJump); + masm.bind(&skip); + } else { + MOZ_ASSERT(mir->fallible()); + bailoutCmp32(Assembler::Equal, rhs, Imm32(-1), ins->snapshot()); + } + masm.bind(&prevent); + } + + // 0/X (with X < 0) is bad because both of these values *should* be + // doubles, and the result should be -0.0, which cannot be represented in + // integers. X/0 is bad because it will give garbage (or abort), when it + // should give either \infty, -\infty or NAN. + + // Prevent 0 / X (with X < 0) and X / 0 + // testing X / Y. Compare Y with 0. + // There are three cases: (Y < 0), (Y == 0) and (Y > 0) + // If (Y < 0), then we compare X with 0, and bail if X == 0 + // If (Y == 0), then we simply want to bail. + // if (Y > 0), we don't bail. + + if (mir->canBeDivideByZero()) { + if (mir->isTruncated()) { + Label skip; + masm.ma_b(rhs, Imm32(0), &skip, Assembler::NotEqual, ShortJump); + masm.move32(Imm32(0), dest); + masm.ma_b(&done, ShortJump); + masm.bind(&skip); + } else { + MOZ_ASSERT(mir->fallible()); + bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot()); + } + } + + if (mir->canBeNegativeDividend()) { + Label notNegative; + masm.ma_b(rhs, Imm32(0), ¬Negative, Assembler::GreaterThan, ShortJump); + if (mir->isTruncated()) { + // NaN|0 == 0 and (0 % -X)|0 == 0 + Label skip; + masm.ma_b(lhs, Imm32(0), &skip, Assembler::NotEqual, ShortJump); + masm.move32(Imm32(0), dest); + masm.ma_b(&done, ShortJump); + masm.bind(&skip); + } else { + MOZ_ASSERT(mir->fallible()); + bailoutCmp32(Assembler::Equal, lhs, Imm32(0), ins->snapshot()); + } + masm.bind(¬Negative); + } + + masm.as_div(lhs, rhs); + masm.as_mfhi(dest); + + // If X%Y == 0 and X < 0, then we *actually* wanted to return -0.0 + if (mir->canBeNegativeDividend()) { + if (mir->isTruncated()) { + // -0.0|0 == 0 + } else { + MOZ_ASSERT(mir->fallible()); + // See if X < 0 + masm.ma_b(dest, Imm32(0), &done, Assembler::NotEqual, ShortJump); + bailoutCmp32(Assembler::Signed, callTemp, Imm32(0), ins->snapshot()); + } + } + masm.bind(&done); +} + +void +CodeGeneratorMIPSShared::visitModPowTwoI(LModPowTwoI* ins) +{ + Register in = ToRegister(ins->getOperand(0)); + Register out = ToRegister(ins->getDef(0)); + MMod* mir = ins->mir(); + Label negative, done; + + masm.move32(in, out); + masm.ma_b(in, in, &done, Assembler::Zero, ShortJump); + // Switch based on sign of the lhs. + // Positive numbers are just a bitmask + masm.ma_b(in, in, &negative, Assembler::Signed, ShortJump); + { + masm.and32(Imm32((1 << ins->shift()) - 1), out); + masm.ma_b(&done, ShortJump); + } + + // Negative numbers need a negate, bitmask, negate + { + masm.bind(&negative); + masm.neg32(out); + masm.and32(Imm32((1 << ins->shift()) - 1), out); + masm.neg32(out); + } + if (mir->canBeNegativeDividend()) { + if (!mir->isTruncated()) { + MOZ_ASSERT(mir->fallible()); + bailoutCmp32(Assembler::Equal, out, zero, ins->snapshot()); + } else { + // -0|0 == 0 + } + } + masm.bind(&done); +} + +void +CodeGeneratorMIPSShared::visitModMaskI(LModMaskI* ins) +{ + Register src = ToRegister(ins->getOperand(0)); + Register dest = ToRegister(ins->getDef(0)); + Register tmp0 = ToRegister(ins->getTemp(0)); + Register tmp1 = ToRegister(ins->getTemp(1)); + MMod* mir = ins->mir(); + + if (!mir->isTruncated() && mir->canBeNegativeDividend()) { + MOZ_ASSERT(mir->fallible()); + + Label bail; + masm.ma_mod_mask(src, dest, tmp0, tmp1, ins->shift(), &bail); + bailoutFrom(&bail, ins->snapshot()); + } else { + masm.ma_mod_mask(src, dest, tmp0, tmp1, ins->shift(), nullptr); + } +} + +void +CodeGeneratorMIPSShared::visitBitNotI(LBitNotI* ins) +{ + const LAllocation* input = ins->getOperand(0); + const LDefinition* dest = ins->getDef(0); + MOZ_ASSERT(!input->isConstant()); + + masm.ma_not(ToRegister(dest), ToRegister(input)); +} + +void +CodeGeneratorMIPSShared::visitBitOpI(LBitOpI* ins) +{ + const LAllocation* lhs = ins->getOperand(0); + const LAllocation* rhs = ins->getOperand(1); + const LDefinition* dest = ins->getDef(0); + // all of these bitops should be either imm32's, or integer registers. + switch (ins->bitop()) { + case JSOP_BITOR: + if (rhs->isConstant()) + masm.ma_or(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs))); + else + masm.as_or(ToRegister(dest), ToRegister(lhs), ToRegister(rhs)); + break; + case JSOP_BITXOR: + if (rhs->isConstant()) + masm.ma_xor(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs))); + else + masm.as_xor(ToRegister(dest), ToRegister(lhs), ToRegister(rhs)); + break; + case JSOP_BITAND: + if (rhs->isConstant()) + masm.ma_and(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs))); + else + masm.as_and(ToRegister(dest), ToRegister(lhs), ToRegister(rhs)); + break; + default: + MOZ_CRASH("unexpected binary opcode"); + } +} + +void +CodeGeneratorMIPSShared::visitShiftI(LShiftI* ins) +{ + Register lhs = ToRegister(ins->lhs()); + const LAllocation* rhs = ins->rhs(); + Register dest = ToRegister(ins->output()); + + if (rhs->isConstant()) { + int32_t shift = ToInt32(rhs) & 0x1F; + switch (ins->bitop()) { + case JSOP_LSH: + if (shift) + masm.ma_sll(dest, lhs, Imm32(shift)); + else + masm.move32(lhs, dest); + break; + case JSOP_RSH: + if (shift) + masm.ma_sra(dest, lhs, Imm32(shift)); + else + masm.move32(lhs, dest); + break; + case JSOP_URSH: + if (shift) { + masm.ma_srl(dest, lhs, Imm32(shift)); + } else { + // x >>> 0 can overflow. + masm.move32(lhs, dest); + if (ins->mir()->toUrsh()->fallible()) + bailoutCmp32(Assembler::LessThan, dest, Imm32(0), ins->snapshot()); + } + break; + default: + MOZ_CRASH("Unexpected shift op"); + } + } else { + // The shift amounts should be AND'ed into the 0-31 range + masm.ma_and(dest, ToRegister(rhs), Imm32(0x1F)); + + switch (ins->bitop()) { + case JSOP_LSH: + masm.ma_sll(dest, lhs, dest); + break; + case JSOP_RSH: + masm.ma_sra(dest, lhs, dest); + break; + case JSOP_URSH: + masm.ma_srl(dest, lhs, dest); + if (ins->mir()->toUrsh()->fallible()) { + // x >>> 0 can overflow. + bailoutCmp32(Assembler::LessThan, dest, Imm32(0), ins->snapshot()); + } + break; + default: + MOZ_CRASH("Unexpected shift op"); + } + } +} + +void +CodeGeneratorMIPSShared::visitUrshD(LUrshD* ins) +{ + Register lhs = ToRegister(ins->lhs()); + Register temp = ToRegister(ins->temp()); + + const LAllocation* rhs = ins->rhs(); + FloatRegister out = ToFloatRegister(ins->output()); + + if (rhs->isConstant()) { + masm.ma_srl(temp, lhs, Imm32(ToInt32(rhs))); + } else { + masm.ma_srl(temp, lhs, ToRegister(rhs)); + } + + masm.convertUInt32ToDouble(temp, out); +} + +void +CodeGeneratorMIPSShared::visitClzI(LClzI* ins) +{ + Register input = ToRegister(ins->input()); + Register output = ToRegister(ins->output()); + + masm.as_clz(output, input); +} + +void +CodeGeneratorMIPSShared::visitPowHalfD(LPowHalfD* ins) +{ + FloatRegister input = ToFloatRegister(ins->input()); + FloatRegister output = ToFloatRegister(ins->output()); + + Label done, skip; + + // Masm.pow(-Infinity, 0.5) == Infinity. + masm.loadConstantDouble(NegativeInfinity(), ScratchDoubleReg); + masm.ma_bc1d(input, ScratchDoubleReg, &skip, Assembler::DoubleNotEqualOrUnordered, ShortJump); + masm.as_negd(output, ScratchDoubleReg); + masm.ma_b(&done, ShortJump); + + masm.bind(&skip); + // Math.pow(-0, 0.5) == 0 == Math.pow(0, 0.5). + // Adding 0 converts any -0 to 0. + masm.loadConstantDouble(0.0, ScratchDoubleReg); + masm.as_addd(output, input, ScratchDoubleReg); + masm.as_sqrtd(output, output); + + masm.bind(&done); +} + +MoveOperand +CodeGeneratorMIPSShared::toMoveOperand(LAllocation a) const +{ + if (a.isGeneralReg()) + return MoveOperand(ToRegister(a)); + if (a.isFloatReg()) { + return MoveOperand(ToFloatRegister(a)); + } + int32_t offset = ToStackOffset(a); + MOZ_ASSERT((offset & 3) == 0); + + return MoveOperand(StackPointer, offset); +} + +void +CodeGeneratorMIPSShared::visitMathD(LMathD* math) +{ + const LAllocation* src1 = math->getOperand(0); + const LAllocation* src2 = math->getOperand(1); + const LDefinition* output = math->getDef(0); + + switch (math->jsop()) { + case JSOP_ADD: + masm.as_addd(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); + break; + case JSOP_SUB: + masm.as_subd(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); + break; + case JSOP_MUL: + masm.as_muld(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); + break; + case JSOP_DIV: + masm.as_divd(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); + break; + default: + MOZ_CRASH("unexpected opcode"); + } +} + +void +CodeGeneratorMIPSShared::visitMathF(LMathF* math) +{ + const LAllocation* src1 = math->getOperand(0); + const LAllocation* src2 = math->getOperand(1); + const LDefinition* output = math->getDef(0); + + switch (math->jsop()) { + case JSOP_ADD: + masm.as_adds(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); + break; + case JSOP_SUB: + masm.as_subs(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); + break; + case JSOP_MUL: + masm.as_muls(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); + break; + case JSOP_DIV: + masm.as_divs(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); + break; + default: + MOZ_CRASH("unexpected opcode"); + } +} + +void +CodeGeneratorMIPSShared::visitFloor(LFloor* lir) +{ + FloatRegister input = ToFloatRegister(lir->input()); + FloatRegister scratch = ScratchDoubleReg; + Register output = ToRegister(lir->output()); + + Label skipCheck, done; + + // If Nan, 0 or -0 check for bailout + masm.loadConstantDouble(0.0, scratch); + masm.ma_bc1d(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump); + + // If high part is not zero, it is NaN or -0, so we bail. + masm.moveFromDoubleHi(input, SecondScratchReg); + bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()); + + // Input was zero, so return zero. + masm.move32(Imm32(0), output); + masm.ma_b(&done, ShortJump); + + masm.bind(&skipCheck); + masm.as_floorwd(scratch, input); + masm.moveFromDoubleLo(scratch, output); + + bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); + bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()); + + masm.bind(&done); +} + +void +CodeGeneratorMIPSShared::visitFloorF(LFloorF* lir) +{ + FloatRegister input = ToFloatRegister(lir->input()); + FloatRegister scratch = ScratchFloat32Reg; + Register output = ToRegister(lir->output()); + + Label skipCheck, done; + + // If Nan, 0 or -0 check for bailout + masm.loadConstantFloat32(0.0f, scratch); + masm.ma_bc1s(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump); + + // If binary value is not zero, it is NaN or -0, so we bail. + masm.moveFromDoubleLo(input, SecondScratchReg); + bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()); + + // Input was zero, so return zero. + masm.move32(Imm32(0), output); + masm.ma_b(&done, ShortJump); + + masm.bind(&skipCheck); + masm.as_floorws(scratch, input); + masm.moveFromDoubleLo(scratch, output); + + bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); + bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()); + + masm.bind(&done); +} + +void +CodeGeneratorMIPSShared::visitCeil(LCeil* lir) +{ + FloatRegister input = ToFloatRegister(lir->input()); + FloatRegister scratch = ScratchDoubleReg; + Register output = ToRegister(lir->output()); + + Label performCeil, done; + + // If x < -1 or x > 0 then perform ceil. + masm.loadConstantDouble(0, scratch); + masm.branchDouble(Assembler::DoubleGreaterThan, input, scratch, &performCeil); + masm.loadConstantDouble(-1, scratch); + masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, scratch, &performCeil); + + // If high part is not zero, the input was not 0, so we bail. + masm.moveFromDoubleHi(input, SecondScratchReg); + bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()); + + // Input was zero, so return zero. + masm.move32(Imm32(0), output); + masm.ma_b(&done, ShortJump); + + masm.bind(&performCeil); + masm.as_ceilwd(scratch, input); + masm.moveFromDoubleLo(scratch, output); + + bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); + bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()); + + masm.bind(&done); +} + +void +CodeGeneratorMIPSShared::visitCeilF(LCeilF* lir) +{ + FloatRegister input = ToFloatRegister(lir->input()); + FloatRegister scratch = ScratchFloat32Reg; + Register output = ToRegister(lir->output()); + + Label performCeil, done; + + // If x < -1 or x > 0 then perform ceil. + masm.loadConstantFloat32(0, scratch); + masm.branchFloat(Assembler::DoubleGreaterThan, input, scratch, &performCeil); + masm.loadConstantFloat32(-1, scratch); + masm.branchFloat(Assembler::DoubleLessThanOrEqual, input, scratch, &performCeil); + + // If binary value is not zero, the input was not 0, so we bail. + masm.moveFromFloat32(input, SecondScratchReg); + bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()); + + // Input was zero, so return zero. + masm.move32(Imm32(0), output); + masm.ma_b(&done, ShortJump); + + masm.bind(&performCeil); + masm.as_ceilws(scratch, input); + masm.moveFromFloat32(scratch, output); + + bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); + bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()); + + masm.bind(&done); +} + +void +CodeGeneratorMIPSShared::visitRound(LRound* lir) +{ + FloatRegister input = ToFloatRegister(lir->input()); + FloatRegister temp = ToFloatRegister(lir->temp()); + FloatRegister scratch = ScratchDoubleReg; + Register output = ToRegister(lir->output()); + + Label bail, negative, end, skipCheck; + + // Load biggest number less than 0.5 in the temp register. + masm.loadConstantDouble(GetBiggestNumberLessThan(0.5), temp); + + // Branch to a slow path for negative inputs. Doesn't catch NaN or -0. + masm.loadConstantDouble(0.0, scratch); + masm.ma_bc1d(input, scratch, &negative, Assembler::DoubleLessThan, ShortJump); + + // If Nan, 0 or -0 check for bailout + masm.ma_bc1d(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump); + + // If high part is not zero, it is NaN or -0, so we bail. + masm.moveFromDoubleHi(input, SecondScratchReg); + bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()); + + // Input was zero, so return zero. + masm.move32(Imm32(0), output); + masm.ma_b(&end, ShortJump); + + masm.bind(&skipCheck); + masm.as_addd(scratch, input, temp); + masm.as_floorwd(scratch, scratch); + + masm.moveFromDoubleLo(scratch, output); + + bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); + bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()); + + masm.jump(&end); + + // Input is negative, but isn't -0. + masm.bind(&negative); + + // Inputs in ]-0.5; 0] need to be added 0.5, other negative inputs need to + // be added the biggest double less than 0.5. + Label loadJoin; + masm.loadConstantDouble(-0.5, scratch); + masm.branchDouble(Assembler::DoubleLessThan, input, scratch, &loadJoin); + masm.loadConstantDouble(0.5, temp); + masm.bind(&loadJoin); + + masm.addDouble(input, temp); + + // If input + 0.5 >= 0, input is a negative number >= -0.5 and the + // result is -0. + masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, temp, scratch, &bail); + bailoutFrom(&bail, lir->snapshot()); + + // Truncate and round toward zero. + // This is off-by-one for everything but integer-valued inputs. + masm.as_floorwd(scratch, temp); + masm.moveFromDoubleLo(scratch, output); + + bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); + + masm.bind(&end); +} + +void +CodeGeneratorMIPSShared::visitRoundF(LRoundF* lir) +{ + FloatRegister input = ToFloatRegister(lir->input()); + FloatRegister temp = ToFloatRegister(lir->temp()); + FloatRegister scratch = ScratchFloat32Reg; + Register output = ToRegister(lir->output()); + + Label bail, negative, end, skipCheck; + + // Load biggest number less than 0.5 in the temp register. + masm.loadConstantFloat32(GetBiggestNumberLessThan(0.5f), temp); + + // Branch to a slow path for negative inputs. Doesn't catch NaN or -0. + masm.loadConstantFloat32(0.0f, scratch); + masm.ma_bc1s(input, scratch, &negative, Assembler::DoubleLessThan, ShortJump); + + // If Nan, 0 or -0 check for bailout + masm.ma_bc1s(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump); + + // If binary value is not zero, it is NaN or -0, so we bail. + masm.moveFromFloat32(input, SecondScratchReg); + bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()); + + // Input was zero, so return zero. + masm.move32(Imm32(0), output); + masm.ma_b(&end, ShortJump); + + masm.bind(&skipCheck); + masm.as_adds(scratch, input, temp); + masm.as_floorws(scratch, scratch); + + masm.moveFromFloat32(scratch, output); + + bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); + bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()); + + masm.jump(&end); + + // Input is negative, but isn't -0. + masm.bind(&negative); + + // Inputs in ]-0.5; 0] need to be added 0.5, other negative inputs need to + // be added the biggest double less than 0.5. + Label loadJoin; + masm.loadConstantFloat32(-0.5f, scratch); + masm.branchFloat(Assembler::DoubleLessThan, input, scratch, &loadJoin); + masm.loadConstantFloat32(0.5f, temp); + masm.bind(&loadJoin); + + masm.as_adds(temp, input, temp); + + // If input + 0.5 >= 0, input is a negative number >= -0.5 and the + // result is -0. + masm.branchFloat(Assembler::DoubleGreaterThanOrEqual, temp, scratch, &bail); + bailoutFrom(&bail, lir->snapshot()); + + // Truncate and round toward zero. + // This is off-by-one for everything but integer-valued inputs. + masm.as_floorws(scratch, temp); + masm.moveFromFloat32(scratch, output); + + bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); + + masm.bind(&end); +} + +void +CodeGeneratorMIPSShared::visitTruncateDToInt32(LTruncateDToInt32* ins) +{ + emitTruncateDouble(ToFloatRegister(ins->input()), ToRegister(ins->output()), + ins->mir()); +} + +void +CodeGeneratorMIPSShared::visitTruncateFToInt32(LTruncateFToInt32* ins) +{ + emitTruncateFloat32(ToFloatRegister(ins->input()), ToRegister(ins->output()), + ins->mir()); +} + +void +CodeGeneratorMIPSShared::visitValue(LValue* value) +{ + const ValueOperand out = ToOutValue(value); + + masm.moveValue(value->value(), out); +} + +void +CodeGeneratorMIPSShared::visitDouble(LDouble* ins) +{ + const LDefinition* out = ins->getDef(0); + + masm.loadConstantDouble(ins->getDouble(), ToFloatRegister(out)); +} + +void +CodeGeneratorMIPSShared::visitFloat32(LFloat32* ins) +{ + const LDefinition* out = ins->getDef(0); + masm.loadConstantFloat32(ins->getFloat(), ToFloatRegister(out)); +} + +void +CodeGeneratorMIPSShared::visitTestDAndBranch(LTestDAndBranch* test) +{ + FloatRegister input = ToFloatRegister(test->input()); + + MBasicBlock* ifTrue = test->ifTrue(); + MBasicBlock* ifFalse = test->ifFalse(); + + masm.loadConstantDouble(0.0, ScratchDoubleReg); + // If 0, or NaN, the result is false. + + if (isNextBlock(ifFalse->lir())) { + branchToBlock(Assembler::DoubleFloat, input, ScratchDoubleReg, ifTrue, + Assembler::DoubleNotEqual); + } else { + branchToBlock(Assembler::DoubleFloat, input, ScratchDoubleReg, ifFalse, + Assembler::DoubleEqualOrUnordered); + jumpToBlock(ifTrue); + } +} + +void +CodeGeneratorMIPSShared::visitTestFAndBranch(LTestFAndBranch* test) +{ + FloatRegister input = ToFloatRegister(test->input()); + + MBasicBlock* ifTrue = test->ifTrue(); + MBasicBlock* ifFalse = test->ifFalse(); + + masm.loadConstantFloat32(0.0f, ScratchFloat32Reg); + // If 0, or NaN, the result is false. + + if (isNextBlock(ifFalse->lir())) { + branchToBlock(Assembler::SingleFloat, input, ScratchFloat32Reg, ifTrue, + Assembler::DoubleNotEqual); + } else { + branchToBlock(Assembler::SingleFloat, input, ScratchFloat32Reg, ifFalse, + Assembler::DoubleEqualOrUnordered); + jumpToBlock(ifTrue); + } +} + +void +CodeGeneratorMIPSShared::visitCompareD(LCompareD* comp) +{ + FloatRegister lhs = ToFloatRegister(comp->left()); + FloatRegister rhs = ToFloatRegister(comp->right()); + Register dest = ToRegister(comp->output()); + + Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop()); + masm.ma_cmp_set_double(dest, lhs, rhs, cond); +} + +void +CodeGeneratorMIPSShared::visitCompareF(LCompareF* comp) +{ + FloatRegister lhs = ToFloatRegister(comp->left()); + FloatRegister rhs = ToFloatRegister(comp->right()); + Register dest = ToRegister(comp->output()); + + Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop()); + masm.ma_cmp_set_float32(dest, lhs, rhs, cond); +} + +void +CodeGeneratorMIPSShared::visitCompareDAndBranch(LCompareDAndBranch* comp) +{ + FloatRegister lhs = ToFloatRegister(comp->left()); + FloatRegister rhs = ToFloatRegister(comp->right()); + + Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->cmpMir()->jsop()); + MBasicBlock* ifTrue = comp->ifTrue(); + MBasicBlock* ifFalse = comp->ifFalse(); + + if (isNextBlock(ifFalse->lir())) { + branchToBlock(Assembler::DoubleFloat, lhs, rhs, ifTrue, cond); + } else { + branchToBlock(Assembler::DoubleFloat, lhs, rhs, ifFalse, + Assembler::InvertCondition(cond)); + jumpToBlock(ifTrue); + } +} + +void +CodeGeneratorMIPSShared::visitCompareFAndBranch(LCompareFAndBranch* comp) +{ + FloatRegister lhs = ToFloatRegister(comp->left()); + FloatRegister rhs = ToFloatRegister(comp->right()); + + Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->cmpMir()->jsop()); + MBasicBlock* ifTrue = comp->ifTrue(); + MBasicBlock* ifFalse = comp->ifFalse(); + + if (isNextBlock(ifFalse->lir())) { + branchToBlock(Assembler::SingleFloat, lhs, rhs, ifTrue, cond); + } else { + branchToBlock(Assembler::SingleFloat, lhs, rhs, ifFalse, + Assembler::InvertCondition(cond)); + jumpToBlock(ifTrue); + } +} + +void +CodeGeneratorMIPSShared::visitBitAndAndBranch(LBitAndAndBranch* lir) +{ + if (lir->right()->isConstant()) + masm.ma_and(ScratchRegister, ToRegister(lir->left()), Imm32(ToInt32(lir->right()))); + else + masm.as_and(ScratchRegister, ToRegister(lir->left()), ToRegister(lir->right())); + emitBranch(ScratchRegister, ScratchRegister, Assembler::NonZero, lir->ifTrue(), + lir->ifFalse()); +} + +void +CodeGeneratorMIPSShared::visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble* lir) +{ + masm.convertUInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output())); +} + +void +CodeGeneratorMIPSShared::visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32* lir) +{ + masm.convertUInt32ToFloat32(ToRegister(lir->input()), ToFloatRegister(lir->output())); +} + +void +CodeGeneratorMIPSShared::visitNotI(LNotI* ins) +{ + masm.cmp32Set(Assembler::Equal, ToRegister(ins->input()), Imm32(0), + ToRegister(ins->output())); +} + +void +CodeGeneratorMIPSShared::visitNotD(LNotD* ins) +{ + // Since this operation is not, we want to set a bit if + // the double is falsey, which means 0.0, -0.0 or NaN. + FloatRegister in = ToFloatRegister(ins->input()); + Register dest = ToRegister(ins->output()); + + Label falsey, done; + masm.loadConstantDouble(0.0, ScratchDoubleReg); + masm.ma_bc1d(in, ScratchDoubleReg, &falsey, Assembler::DoubleEqualOrUnordered, ShortJump); + + masm.move32(Imm32(0), dest); + masm.ma_b(&done, ShortJump); + + masm.bind(&falsey); + masm.move32(Imm32(1), dest); + + masm.bind(&done); +} + +void +CodeGeneratorMIPSShared::visitNotF(LNotF* ins) +{ + // Since this operation is not, we want to set a bit if + // the float32 is falsey, which means 0.0, -0.0 or NaN. + FloatRegister in = ToFloatRegister(ins->input()); + Register dest = ToRegister(ins->output()); + + Label falsey, done; + masm.loadConstantFloat32(0.0f, ScratchFloat32Reg); + masm.ma_bc1s(in, ScratchFloat32Reg, &falsey, Assembler::DoubleEqualOrUnordered, ShortJump); + + masm.move32(Imm32(0), dest); + masm.ma_b(&done, ShortJump); + + masm.bind(&falsey); + masm.move32(Imm32(1), dest); + + masm.bind(&done); +} + +void +CodeGeneratorMIPSShared::visitGuardShape(LGuardShape* guard) +{ + Register obj = ToRegister(guard->input()); + Register tmp = ToRegister(guard->tempInt()); + + masm.loadPtr(Address(obj, JSObject::offsetOfShape()), tmp); + bailoutCmpPtr(Assembler::NotEqual, tmp, ImmGCPtr(guard->mir()->shape()), + guard->snapshot()); +} + +void +CodeGeneratorMIPSShared::visitGuardObjectGroup(LGuardObjectGroup* guard) +{ + Register obj = ToRegister(guard->input()); + Register tmp = ToRegister(guard->tempInt()); + MOZ_ASSERT(obj != tmp); + + masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), tmp); + Assembler::Condition cond = guard->mir()->bailOnEquality() + ? Assembler::Equal + : Assembler::NotEqual; + bailoutCmpPtr(cond, tmp, ImmGCPtr(guard->mir()->group()), guard->snapshot()); +} + +void +CodeGeneratorMIPSShared::visitGuardClass(LGuardClass* guard) +{ + Register obj = ToRegister(guard->input()); + Register tmp = ToRegister(guard->tempInt()); + + masm.loadObjClass(obj, tmp); + bailoutCmpPtr(Assembler::NotEqual, tmp, ImmPtr(guard->mir()->getClass()), + guard->snapshot()); +} + +void +CodeGeneratorMIPSShared::generateInvalidateEpilogue() +{ + // Ensure that there is enough space in the buffer for the OsiPoint + // patching to occur. Otherwise, we could overwrite the invalidation + // epilogue. + for (size_t i = 0; i < sizeof(void*); i += Assembler::NopSize()) + masm.nop(); + + masm.bind(&invalidate_); + + // Push the return address of the point that we bailed out at to the stack + masm.Push(ra); + + // Push the Ion script onto the stack (when we determine what that + // pointer is). + invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1))); + JitCode* thunk = gen->jitRuntime()->getInvalidationThunk(); + + masm.branch(thunk); + + // We should never reach this point in JIT code -- the invalidation thunk + // should pop the invalidated JS frame and return directly to its caller. + masm.assumeUnreachable("Should have returned directly to its caller instead of here."); +} + +void +CodeGeneratorMIPSShared::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins) +{ + MOZ_CRASH("NYI"); +} + +void +CodeGeneratorMIPSShared::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins) +{ + MOZ_CRASH("NYI"); +} + +void +CodeGeneratorMIPSShared::visitAsmJSCall(LAsmJSCall* ins) +{ + emitAsmJSCall(ins); +} + +void +CodeGeneratorMIPSShared::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins) +{ + const MAsmJSLoadHeap* mir = ins->mir(); + const LAllocation* ptr = ins->ptr(); + const LDefinition* out = ins->output(); + + bool isSigned; + int size; + bool isFloat = false; + switch (mir->accessType()) { + case Scalar::Int8: isSigned = true; size = 8; break; + case Scalar::Uint8: isSigned = false; size = 8; break; + case Scalar::Int16: isSigned = true; size = 16; break; + case Scalar::Uint16: isSigned = false; size = 16; break; + case Scalar::Int32: isSigned = true; size = 32; break; + case Scalar::Uint32: isSigned = false; size = 32; break; + case Scalar::Float64: isFloat = true; size = 64; break; + case Scalar::Float32: isFloat = true; size = 32; break; + default: MOZ_CRASH("unexpected array type"); + } + + if (ptr->isConstant()) { + MOZ_ASSERT(!mir->needsBoundsCheck()); + int32_t ptrImm = ptr->toConstant()->toInt32(); + MOZ_ASSERT(ptrImm >= 0); + if (isFloat) { + if (size == 32) { + masm.loadFloat32(Address(HeapReg, ptrImm), ToFloatRegister(out)); + } else { + masm.loadDouble(Address(HeapReg, ptrImm), ToFloatRegister(out)); + } + } else { + masm.ma_load(ToRegister(out), Address(HeapReg, ptrImm), + static_cast(size), isSigned ? SignExtend : ZeroExtend); + } + return; + } + + Register ptrReg = ToRegister(ptr); + + if (!mir->needsBoundsCheck()) { + if (isFloat) { + if (size == 32) { + masm.loadFloat32(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out)); + } else { + masm.loadDouble(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out)); + } + } else { + masm.ma_load(ToRegister(out), BaseIndex(HeapReg, ptrReg, TimesOne), + static_cast(size), isSigned ? SignExtend : ZeroExtend); + } + return; + } + + BufferOffset bo = masm.ma_BoundsCheck(ScratchRegister); + + Label done, outOfRange; + masm.ma_b(ptrReg, ScratchRegister, &outOfRange, Assembler::AboveOrEqual, ShortJump); + // Offset is ok, let's load value. + if (isFloat) { + if (size == 32) + masm.loadFloat32(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out)); + else + masm.loadDouble(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out)); + } else { + masm.ma_load(ToRegister(out), BaseIndex(HeapReg, ptrReg, TimesOne), + static_cast(size), isSigned ? SignExtend : ZeroExtend); + } + masm.ma_b(&done, ShortJump); + masm.bind(&outOfRange); + // Offset is out of range. Load default values. + if (isFloat) { + if (size == 32) + masm.loadFloat32(Address(GlobalReg, AsmJSNaN32GlobalDataOffset - AsmJSGlobalRegBias), + ToFloatRegister(out)); + else + masm.loadDouble(Address(GlobalReg, AsmJSNaN64GlobalDataOffset - AsmJSGlobalRegBias), + ToFloatRegister(out)); + } else { + if (mir->isAtomicAccess()) + masm.ma_b(gen->outOfBoundsLabel()); + else + masm.move32(Imm32(0), ToRegister(out)); + } + masm.bind(&done); + + masm.append(AsmJSHeapAccess(bo.getOffset())); +} + +void +CodeGeneratorMIPSShared::visitAsmJSStoreHeap(LAsmJSStoreHeap* ins) +{ + const MAsmJSStoreHeap* mir = ins->mir(); + const LAllocation* value = ins->value(); + const LAllocation* ptr = ins->ptr(); + + bool isSigned; + int size; + bool isFloat = false; + switch (mir->accessType()) { + case Scalar::Int8: isSigned = true; size = 8; break; + case Scalar::Uint8: isSigned = false; size = 8; break; + case Scalar::Int16: isSigned = true; size = 16; break; + case Scalar::Uint16: isSigned = false; size = 16; break; + case Scalar::Int32: isSigned = true; size = 32; break; + case Scalar::Uint32: isSigned = false; size = 32; break; + case Scalar::Float64: isFloat = true; size = 64; break; + case Scalar::Float32: isFloat = true; size = 32; break; + default: MOZ_CRASH("unexpected array type"); + } + + if (ptr->isConstant()) { + MOZ_ASSERT(!mir->needsBoundsCheck()); + int32_t ptrImm = ptr->toConstant()->toInt32(); + MOZ_ASSERT(ptrImm >= 0); + + if (isFloat) { + if (size == 32) { + masm.storeFloat32(ToFloatRegister(value), Address(HeapReg, ptrImm)); + } else { + masm.storeDouble(ToFloatRegister(value), Address(HeapReg, ptrImm)); + } + } else { + masm.ma_store(ToRegister(value), Address(HeapReg, ptrImm), + static_cast(size), isSigned ? SignExtend : ZeroExtend); + } + return; + } + + Register ptrReg = ToRegister(ptr); + Address dstAddr(ptrReg, 0); + + if (!mir->needsBoundsCheck()) { + if (isFloat) { + if (size == 32) { + masm.storeFloat32(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne)); + } else + masm.storeDouble(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne)); + } else { + masm.ma_store(ToRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne), + static_cast(size), isSigned ? SignExtend : ZeroExtend); + } + return; + } + + BufferOffset bo = masm.ma_BoundsCheck(ScratchRegister); + + Label done, outOfRange; + masm.ma_b(ptrReg, ScratchRegister, &outOfRange, Assembler::AboveOrEqual, ShortJump); + + // Offset is ok, let's store value. + if (isFloat) { + if (size == 32) { + masm.storeFloat32(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne)); + } else + masm.storeDouble(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne)); + } else { + masm.ma_store(ToRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne), + static_cast(size), isSigned ? SignExtend : ZeroExtend); + } + masm.ma_b(&done, ShortJump); + masm.bind(&outOfRange); + // Offset is out of range. + if (mir->isAtomicAccess()) + masm.ma_b(gen->outOfBoundsLabel()); + masm.bind(&done); + + masm.append(AsmJSHeapAccess(bo.getOffset())); +} + +void +CodeGeneratorMIPSShared::visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins) +{ + MOZ_CRASH("NYI"); +} + +void +CodeGeneratorMIPSShared::visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins) +{ + MOZ_CRASH("NYI"); +} + +void +CodeGeneratorMIPSShared::visitAsmJSPassStackArg(LAsmJSPassStackArg* ins) +{ + const MAsmJSPassStackArg* mir = ins->mir(); + if (ins->arg()->isConstant()) { + masm.storePtr(ImmWord(ToInt32(ins->arg())), Address(StackPointer, mir->spOffset())); + } else { + if (ins->arg()->isGeneralReg()) { + masm.storePtr(ToRegister(ins->arg()), Address(StackPointer, mir->spOffset())); + } else { + masm.storeDouble(ToFloatRegister(ins->arg()).doubleOverlay(), + Address(StackPointer, mir->spOffset())); + } + } +} + +void +CodeGeneratorMIPSShared::visitUDivOrMod(LUDivOrMod* ins) +{ + Register lhs = ToRegister(ins->lhs()); + Register rhs = ToRegister(ins->rhs()); + Register output = ToRegister(ins->output()); + Label done; + + // Prevent divide by zero. + if (ins->canBeDivideByZero()) { + if (ins->mir()->isTruncated()) { + // Infinity|0 == 0 + Label notzero; + masm.ma_b(rhs, rhs, ¬zero, Assembler::NonZero, ShortJump); + masm.move32(Imm32(0), output); + masm.ma_b(&done, ShortJump); + masm.bind(¬zero); + } else { + bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot()); + } + } + + masm.as_divu(lhs, rhs); + masm.as_mfhi(output); + + // If the remainder is > 0, bailout since this must be a double. + if (ins->mir()->isDiv()) { + if (!ins->mir()->toDiv()->canTruncateRemainder()) + bailoutCmp32(Assembler::NonZero, output, output, ins->snapshot()); + // Get quotient + masm.as_mflo(output); + } + + if (!ins->mir()->isTruncated()) + bailoutCmp32(Assembler::LessThan, output, Imm32(0), ins->snapshot()); + + masm.bind(&done); +} + +void +CodeGeneratorMIPSShared::visitEffectiveAddress(LEffectiveAddress* ins) +{ + const MEffectiveAddress* mir = ins->mir(); + Register base = ToRegister(ins->base()); + Register index = ToRegister(ins->index()); + Register output = ToRegister(ins->output()); + + BaseIndex address(base, index, mir->scale(), mir->displacement()); + masm.computeEffectiveAddress(address, output); +} + +void +CodeGeneratorMIPSShared::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins) +{ + const MAsmJSLoadGlobalVar* mir = ins->mir(); + unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias; + if (mir->type() == MIRType_Int32) + masm.load32(Address(GlobalReg, addr), ToRegister(ins->output())); + else if (mir->type() == MIRType_Float32) + masm.loadFloat32(Address(GlobalReg, addr), ToFloatRegister(ins->output())); + else + masm.loadDouble(Address(GlobalReg, addr), ToFloatRegister(ins->output())); +} + +void +CodeGeneratorMIPSShared::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins) +{ + const MAsmJSStoreGlobalVar* mir = ins->mir(); + + MOZ_ASSERT(IsNumberType(mir->value()->type())); + unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias; + if (mir->value()->type() == MIRType_Int32) + masm.store32(ToRegister(ins->value()), Address(GlobalReg, addr)); + else if (mir->value()->type() == MIRType_Float32) + masm.storeFloat32(ToFloatRegister(ins->value()), Address(GlobalReg, addr)); + else + masm.storeDouble(ToFloatRegister(ins->value()), Address(GlobalReg, addr)); +} + +void +CodeGeneratorMIPSShared::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins) +{ + const MAsmJSLoadFuncPtr* mir = ins->mir(); + + Register index = ToRegister(ins->index()); + Register out = ToRegister(ins->output()); + unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias; + + BaseIndex source(GlobalReg, index, ScalePointer, addr); + masm.loadPtr(source, out); +} + +void +CodeGeneratorMIPSShared::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins) +{ + const MAsmJSLoadFFIFunc* mir = ins->mir(); + masm.loadPtr(Address(GlobalReg, mir->globalDataOffset() - AsmJSGlobalRegBias), + ToRegister(ins->output())); +} + +void +CodeGeneratorMIPSShared::visitNegI(LNegI* ins) +{ + Register input = ToRegister(ins->input()); + Register output = ToRegister(ins->output()); + + masm.ma_negu(output, input); +} + +void +CodeGeneratorMIPSShared::visitNegD(LNegD* ins) +{ + FloatRegister input = ToFloatRegister(ins->input()); + FloatRegister output = ToFloatRegister(ins->output()); + + masm.as_negd(output, input); +} + +void +CodeGeneratorMIPSShared::visitNegF(LNegF* ins) +{ + FloatRegister input = ToFloatRegister(ins->input()); + FloatRegister output = ToFloatRegister(ins->output()); + + masm.as_negs(output, input); +} diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.h b/js/src/jit/mips-shared/CodeGenerator-mips-shared.h new file mode 100644 index 000000000000..29391ddf4fb7 --- /dev/null +++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.h @@ -0,0 +1,258 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_mips_shared_CodeGenerator_mips_shared_h +#define jit_mips_shared_CodeGenerator_mips_shared_h + +#include "jit/shared/CodeGenerator-shared.h" + +namespace js { +namespace jit { + +class OutOfLineBailout; +class OutOfLineTableSwitch; + +class CodeGeneratorMIPSShared : public CodeGeneratorShared +{ + friend class MoveResolverMIPS; + + CodeGeneratorMIPSShared* thisFromCtor() { + return this; + } + + protected: + NonAssertingLabel deoptLabel_; + + inline Address ToAddress(const LAllocation& a); + inline Address ToAddress(const LAllocation* a); + + MoveOperand toMoveOperand(LAllocation a) const; + + template + void bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) { + Label skip; + masm.branch32(Assembler::InvertCondition(c), lhs, rhs, &skip); + bailout(snapshot); + masm.bind(&skip); + } + template + void bailoutCmp32(Assembler::Condition c, Operand lhs, T rhs, LSnapshot* snapshot) { + if (lhs.getTag() == Operand::REG) + bailoutCmp32(c, lhs.toReg(), rhs, snapshot); + else if (lhs.getTag() == Operand::MEM) + bailoutCmp32(c, lhs.toAddress(), rhs, snapshot); + else + MOZ_CRASH("Invalid operand tag."); + } + template + void bailoutTest32(Assembler::Condition c, Register lhs, T rhs, LSnapshot* snapshot) { + Label bail; + masm.branchTest32(c, lhs, rhs, &bail); + bailoutFrom(&bail, snapshot); + } + template + void bailoutCmpPtr(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) { + Label skip; + masm.branchPtr(Assembler::InvertCondition(c), lhs, rhs, &skip); + bailout(snapshot); + masm.bind(&skip); + } + void bailoutTestPtr(Assembler::Condition c, Register lhs, Register rhs, LSnapshot* snapshot) { + Label bail; + masm.branchTestPtr(c, lhs, rhs, &bail); + bailoutFrom(&bail, snapshot); + } + void bailoutIfFalseBool(Register reg, LSnapshot* snapshot) { + Label bail; + masm.branchTest32(Assembler::Zero, reg, Imm32(0xFF), &bail); + bailoutFrom(&bail, snapshot); + } + + void bailoutFrom(Label* label, LSnapshot* snapshot); + void bailout(LSnapshot* snapshot); + + protected: + bool generateOutOfLineCode(); + + template + void branchToBlock(Register lhs, T rhs, MBasicBlock* mir, Assembler::Condition cond) + { + mir = skipTrivialBlocks(mir); + + Label* label = mir->lir()->label(); + if (Label* oolEntry = labelForBackedgeWithImplicitCheck(mir)) { + // Note: the backedge is initially a jump to the next instruction. + // It will be patched to the target block's label during link(). + RepatchLabel rejoin; + CodeOffsetJump backedge; + Label skip; + + masm.ma_b(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump); + backedge = masm.backedgeJump(&rejoin); + masm.bind(&rejoin); + masm.bind(&skip); + + if (!patchableBackedges_.append(PatchableBackedgeInfo(backedge, label, oolEntry))) + MOZ_CRASH(); + } else { + masm.ma_b(lhs, rhs, label, cond); + } + } + void branchToBlock(Assembler::FloatFormat fmt, FloatRegister lhs, FloatRegister rhs, + MBasicBlock* mir, Assembler::DoubleCondition cond); + + // Emits a branch that directs control flow to the true block if |cond| is + // true, and the false block if |cond| is false. + template + void emitBranch(Register lhs, T rhs, Assembler::Condition cond, + MBasicBlock* mirTrue, MBasicBlock* mirFalse) + { + if (isNextBlock(mirFalse->lir())) { + branchToBlock(lhs, rhs, mirTrue, cond); + } else { + branchToBlock(lhs, rhs, mirFalse, Assembler::InvertCondition(cond)); + jumpToBlock(mirTrue); + } + } + void testZeroEmitBranch(Assembler::Condition cond, Register reg, + MBasicBlock* ifTrue, MBasicBlock* ifFalse) + { + emitBranch(reg, Imm32(0), cond, ifTrue, ifFalse); + } + + public: + // Instruction visitors. + virtual void visitMinMaxD(LMinMaxD* ins); + virtual void visitMinMaxF(LMinMaxF* ins); + virtual void visitAbsD(LAbsD* ins); + virtual void visitAbsF(LAbsF* ins); + virtual void visitSqrtD(LSqrtD* ins); + virtual void visitSqrtF(LSqrtF* ins); + virtual void visitAddI(LAddI* ins); + virtual void visitSubI(LSubI* ins); + virtual void visitBitNotI(LBitNotI* ins); + virtual void visitBitOpI(LBitOpI* ins); + + virtual void visitMulI(LMulI* ins); + + virtual void visitDivI(LDivI* ins); + virtual void visitDivPowTwoI(LDivPowTwoI* ins); + virtual void visitModI(LModI* ins); + virtual void visitModPowTwoI(LModPowTwoI* ins); + virtual void visitModMaskI(LModMaskI* ins); + virtual void visitPowHalfD(LPowHalfD* ins); + virtual void visitShiftI(LShiftI* ins); + virtual void visitUrshD(LUrshD* ins); + + virtual void visitClzI(LClzI* ins); + + virtual void visitTestIAndBranch(LTestIAndBranch* test); + virtual void visitCompare(LCompare* comp); + virtual void visitCompareAndBranch(LCompareAndBranch* comp); + virtual void visitTestDAndBranch(LTestDAndBranch* test); + virtual void visitTestFAndBranch(LTestFAndBranch* test); + virtual void visitCompareD(LCompareD* comp); + virtual void visitCompareF(LCompareF* comp); + virtual void visitCompareDAndBranch(LCompareDAndBranch* comp); + virtual void visitCompareFAndBranch(LCompareFAndBranch* comp); + virtual void visitBitAndAndBranch(LBitAndAndBranch* lir); + virtual void visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble* lir); + virtual void visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32* lir); + virtual void visitNotI(LNotI* ins); + virtual void visitNotD(LNotD* ins); + virtual void visitNotF(LNotF* ins); + + virtual void visitMathD(LMathD* math); + virtual void visitMathF(LMathF* math); + virtual void visitFloor(LFloor* lir); + virtual void visitFloorF(LFloorF* lir); + virtual void visitCeil(LCeil* lir); + virtual void visitCeilF(LCeilF* lir); + virtual void visitRound(LRound* lir); + virtual void visitRoundF(LRoundF* lir); + virtual void visitTruncateDToInt32(LTruncateDToInt32* ins); + virtual void visitTruncateFToInt32(LTruncateFToInt32* ins); + + // Out of line visitors. + void visitOutOfLineBailout(OutOfLineBailout* ool); + protected: + virtual ValueOperand ToOutValue(LInstruction* ins) = 0; + + public: + CodeGeneratorMIPSShared(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm); + + void visitValue(LValue* value); + void visitDouble(LDouble* ins); + void visitFloat32(LFloat32* ins); + + void visitGuardShape(LGuardShape* guard); + void visitGuardObjectGroup(LGuardObjectGroup* guard); + void visitGuardClass(LGuardClass* guard); + + void visitNegI(LNegI* lir); + void visitNegD(LNegD* lir); + void visitNegF(LNegF* lir); + void visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins); + void visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins); + void visitAsmJSCall(LAsmJSCall* ins); + void visitAsmJSLoadHeap(LAsmJSLoadHeap* ins); + void visitAsmJSStoreHeap(LAsmJSStoreHeap* ins); + void visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins); + void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins); + void visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins); + void visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins); + void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins); + void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins); + + void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins); + + void generateInvalidateEpilogue(); + + protected: + void visitEffectiveAddress(LEffectiveAddress* ins); + void visitUDivOrMod(LUDivOrMod* ins); + + public: + // Unimplemented SIMD instructions + void visitSimdSplatX4(LSimdSplatX4* lir) { MOZ_CRASH("NYI"); } + void visitInt32x4(LInt32x4* ins) { MOZ_CRASH("NYI"); } + void visitFloat32x4(LFloat32x4* ins) { MOZ_CRASH("NYI"); } + void visitSimdReinterpretCast(LSimdReinterpretCast* ins) { MOZ_CRASH("NYI"); } + void visitSimdExtractElementI(LSimdExtractElementI* ins) { MOZ_CRASH("NYI"); } + void visitSimdExtractElementF(LSimdExtractElementF* ins) { MOZ_CRASH("NYI"); } + void visitSimdSignMaskX4(LSimdSignMaskX4* ins) { MOZ_CRASH("NYI"); } + void visitSimdBinaryCompIx4(LSimdBinaryCompIx4* lir) { MOZ_CRASH("NYI"); } + void visitSimdBinaryCompFx4(LSimdBinaryCompFx4* lir) { MOZ_CRASH("NYI"); } + void visitSimdBinaryArithIx4(LSimdBinaryArithIx4* lir) { MOZ_CRASH("NYI"); } + void visitSimdBinaryArithFx4(LSimdBinaryArithFx4* lir) { MOZ_CRASH("NYI"); } + void visitSimdBinaryBitwiseX4(LSimdBinaryBitwiseX4* lir) { MOZ_CRASH("NYI"); } + void visitSimdGeneralShuffleI(LSimdGeneralShuffleI* lir) { MOZ_CRASH("NYI"); } + void visitSimdGeneralShuffleF(LSimdGeneralShuffleF* lir) { MOZ_CRASH("NYI"); } +}; + +// An out-of-line bailout thunk. +class OutOfLineBailout : public OutOfLineCodeBase +{ + LSnapshot* snapshot_; + uint32_t frameSize_; + + public: + OutOfLineBailout(LSnapshot* snapshot, uint32_t frameSize) + : snapshot_(snapshot), + frameSize_(frameSize) + { } + + void accept(CodeGeneratorMIPSShared* codegen); + + LSnapshot* snapshot() const { + return snapshot_; + } +}; + +} // namespace jit +} // namespace js + +#endif /* jit_mips_shared_CodeGenerator_mips_shared_h */ diff --git a/js/src/jit/mips32/CodeGenerator-mips32.cpp b/js/src/jit/mips32/CodeGenerator-mips32.cpp index f60dc0786e9c..f469463fda76 100644 --- a/js/src/jit/mips32/CodeGenerator-mips32.cpp +++ b/js/src/jit/mips32/CodeGenerator-mips32.cpp @@ -8,10 +8,6 @@ #include "mozilla/MathAlgorithms.h" -#include "jscntxt.h" -#include "jscompartment.h" -#include "jsnum.h" - #include "jit/CodeGenerator.h" #include "jit/JitCompartment.h" #include "jit/JitFrames.h" @@ -21,924 +17,12 @@ #include "vm/Shape.h" #include "vm/TraceLogging.h" -#include "jsscriptinlines.h" - #include "jit/MacroAssembler-inl.h" #include "jit/shared/CodeGenerator-shared-inl.h" using namespace js; using namespace js::jit; -using mozilla::FloorLog2; -using mozilla::NegativeInfinity; -using JS::GenericNaN; -using JS::ToInt32; - -// inline -Address -CodeGeneratorMIPS::ToAddress(const LAllocation& a) -{ - MOZ_ASSERT(a.isMemory()); - int32_t offset = ToStackOffset(&a); - - return Address(StackPointer, offset); -} - -// inline -Address -CodeGeneratorMIPS::ToAddress(const LAllocation* a) -{ - return ToAddress(*a); -} - - -// shared -CodeGeneratorMIPS::CodeGeneratorMIPS(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm) - : CodeGeneratorShared(gen, graph, masm) -{ -} - -void -CodeGeneratorMIPS::branchToBlock(Assembler::FloatFormat fmt, FloatRegister lhs, FloatRegister rhs, - MBasicBlock* mir, Assembler::DoubleCondition cond) -{ - // Skip past trivial blocks. - mir = skipTrivialBlocks(mir); - - Label* label = mir->lir()->label(); - if (Label* oolEntry = labelForBackedgeWithImplicitCheck(mir)) { - // Note: the backedge is initially a jump to the next instruction. - // It will be patched to the target block's label during link(). - RepatchLabel rejoin; - - CodeOffsetJump backedge; - Label skip; - if (fmt == Assembler::DoubleFloat) - masm.ma_bc1d(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump); - else - masm.ma_bc1s(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump); - - backedge = masm.backedgeJump(&rejoin); - masm.bind(&rejoin); - masm.bind(&skip); - - if (!patchableBackedges_.append(PatchableBackedgeInfo(backedge, label, oolEntry))) - MOZ_CRASH(); - } else { - if (fmt == Assembler::DoubleFloat) - masm.branchDouble(cond, lhs, rhs, mir->lir()->label()); - else - masm.branchFloat(cond, lhs, rhs, mir->lir()->label()); - } -} - -void -OutOfLineBailout::accept(CodeGeneratorMIPS* codegen) -{ - codegen->visitOutOfLineBailout(this); -} - -void -CodeGeneratorMIPS::visitTestIAndBranch(LTestIAndBranch* test) -{ - const LAllocation* opd = test->getOperand(0); - MBasicBlock* ifTrue = test->ifTrue(); - MBasicBlock* ifFalse = test->ifFalse(); - - emitBranch(ToRegister(opd), Imm32(0), Assembler::NonZero, ifTrue, ifFalse); -} - -void -CodeGeneratorMIPS::visitCompare(LCompare* comp) -{ - Assembler::Condition cond = JSOpToCondition(comp->mir()->compareType(), comp->jsop()); - const LAllocation* left = comp->getOperand(0); - const LAllocation* right = comp->getOperand(1); - const LDefinition* def = comp->getDef(0); - - if (right->isConstant()) - masm.cmp32Set(cond, ToRegister(left), Imm32(ToInt32(right)), ToRegister(def)); - else if (right->isGeneralReg()) - masm.cmp32Set(cond, ToRegister(left), ToRegister(right), ToRegister(def)); - else - masm.cmp32Set(cond, ToRegister(left), ToAddress(right), ToRegister(def)); -} - -void -CodeGeneratorMIPS::visitCompareAndBranch(LCompareAndBranch* comp) -{ - Assembler::Condition cond = JSOpToCondition(comp->cmpMir()->compareType(), comp->jsop()); - if (comp->right()->isConstant()) { - emitBranch(ToRegister(comp->left()), Imm32(ToInt32(comp->right())), cond, - comp->ifTrue(), comp->ifFalse()); - } else if (comp->right()->isGeneralReg()) { - emitBranch(ToRegister(comp->left()), ToRegister(comp->right()), cond, - comp->ifTrue(), comp->ifFalse()); - } else { - masm.load32(ToAddress(comp->right()), ScratchRegister); - emitBranch(ToRegister(comp->left()), ScratchRegister, cond, - comp->ifTrue(), comp->ifFalse()); - } -} - -bool -CodeGeneratorMIPS::generateOutOfLineCode() -{ - if (!CodeGeneratorShared::generateOutOfLineCode()) - return false; - - if (deoptLabel_.used()) { - // All non-table-based bailouts will go here. - masm.bind(&deoptLabel_); - - // Push the frame size, so the handler can recover the IonScript. - // Frame size is stored in 'ra' and pushed by GenerateBailoutThunk - // We have to use 'ra' because generateBailoutTable will implicitly do - // the same. - masm.move32(Imm32(frameSize()), ra); - - JitCode* handler = gen->jitRuntime()->getGenericBailoutHandler(); - - masm.branch(handler); - } - - return true; -} - -void -CodeGeneratorMIPS::bailoutFrom(Label* label, LSnapshot* snapshot) -{ - if (masm.bailed()) - return; - - MOZ_ASSERT(label->used()); - MOZ_ASSERT(!label->bound()); - - encode(snapshot); - - // Though the assembler doesn't track all frame pushes, at least make sure - // the known value makes sense. We can't use bailout tables if the stack - // isn't properly aligned to the static frame size. - MOZ_ASSERT_IF(frameClass_ != FrameSizeClass::None(), - frameClass_.frameSize() == masm.framePushed()); - - // We don't use table bailouts because retargeting is easier this way. - InlineScriptTree* tree = snapshot->mir()->block()->trackedTree(); - OutOfLineBailout* ool = new(alloc()) OutOfLineBailout(snapshot, masm.framePushed()); - addOutOfLineCode(ool, new(alloc()) BytecodeSite(tree, tree->script()->code())); - - masm.retarget(label, ool->entry()); -} - -void -CodeGeneratorMIPS::bailout(LSnapshot* snapshot) -{ - Label label; - masm.jump(&label); - bailoutFrom(&label, snapshot); -} - -void -CodeGeneratorMIPS::visitOutOfLineBailout(OutOfLineBailout* ool) -{ - // Push snapshotOffset and make sure stack is aligned. - masm.subPtr(Imm32(2 * sizeof(void*)), StackPointer); - masm.storePtr(ImmWord(ool->snapshot()->snapshotOffset()), Address(StackPointer, 0)); - - masm.jump(&deoptLabel_); -} - -void -CodeGeneratorMIPS::visitMinMaxD(LMinMaxD* ins) -{ - FloatRegister first = ToFloatRegister(ins->first()); - FloatRegister second = ToFloatRegister(ins->second()); - FloatRegister output = ToFloatRegister(ins->output()); - - MOZ_ASSERT(first == output); - - Assembler::DoubleCondition cond = ins->mir()->isMax() - ? Assembler::DoubleLessThanOrEqual - : Assembler::DoubleGreaterThanOrEqual; - Label nan, equal, returnSecond, done; - - // First or second is NaN, result is NaN. - masm.ma_bc1d(first, second, &nan, Assembler::DoubleUnordered, ShortJump); - // Make sure we handle -0 and 0 right. - masm.ma_bc1d(first, second, &equal, Assembler::DoubleEqual, ShortJump); - masm.ma_bc1d(first, second, &returnSecond, cond, ShortJump); - masm.ma_b(&done, ShortJump); - - // Check for zero. - masm.bind(&equal); - masm.loadConstantDouble(0.0, ScratchDoubleReg); - // First wasn't 0 or -0, so just return it. - masm.ma_bc1d(first, ScratchDoubleReg, &done, Assembler::DoubleNotEqualOrUnordered, ShortJump); - - // So now both operands are either -0 or 0. - if (ins->mir()->isMax()) { - // -0 + -0 = -0 and -0 + 0 = 0. - masm.addDouble(second, first); - } else { - masm.negateDouble(first); - masm.subDouble(second, first); - masm.negateDouble(first); - } - masm.ma_b(&done, ShortJump); - - masm.bind(&nan); - masm.loadConstantDouble(GenericNaN(), output); - masm.ma_b(&done, ShortJump); - - masm.bind(&returnSecond); - masm.moveDouble(second, output); - - masm.bind(&done); -} - -void -CodeGeneratorMIPS::visitMinMaxF(LMinMaxF* ins) -{ - FloatRegister first = ToFloatRegister(ins->first()); - FloatRegister second = ToFloatRegister(ins->second()); - FloatRegister output = ToFloatRegister(ins->output()); - - MOZ_ASSERT(first == output); - - Assembler::DoubleCondition cond = ins->mir()->isMax() - ? Assembler::DoubleLessThanOrEqual - : Assembler::DoubleGreaterThanOrEqual; - Label nan, equal, returnSecond, done; - - // First or second is NaN, result is NaN. - masm.ma_bc1s(first, second, &nan, Assembler::DoubleUnordered, ShortJump); - // Make sure we handle -0 and 0 right. - masm.ma_bc1s(first, second, &equal, Assembler::DoubleEqual, ShortJump); - masm.ma_bc1s(first, second, &returnSecond, cond, ShortJump); - masm.ma_b(&done, ShortJump); - - // Check for zero. - masm.bind(&equal); - masm.loadConstantFloat32(0.0f, ScratchFloat32Reg); - // First wasn't 0 or -0, so just return it. - masm.ma_bc1s(first, ScratchFloat32Reg, &done, Assembler::DoubleNotEqualOrUnordered, ShortJump); - - // So now both operands are either -0 or 0. - if (ins->mir()->isMax()) { - // -0 + -0 = -0 and -0 + 0 = 0. - masm.as_adds(first, first, second); - } else { - masm.as_negs(first, first); - masm.as_subs(first, first, second); - masm.as_negs(first, first); - } - masm.ma_b(&done, ShortJump); - - masm.bind(&nan); - masm.loadConstantFloat32(GenericNaN(), output); - masm.ma_b(&done, ShortJump); - masm.bind(&returnSecond); - masm.as_movs(output, second); - - masm.bind(&done); -} - -void -CodeGeneratorMIPS::visitAbsD(LAbsD* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - MOZ_ASSERT(input == ToFloatRegister(ins->output())); - masm.as_absd(input, input); -} - -void -CodeGeneratorMIPS::visitAbsF(LAbsF* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - MOZ_ASSERT(input == ToFloatRegister(ins->output())); - masm.as_abss(input, input); -} - -void -CodeGeneratorMIPS::visitSqrtD(LSqrtD* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - FloatRegister output = ToFloatRegister(ins->output()); - masm.as_sqrtd(output, input); -} - -void -CodeGeneratorMIPS::visitSqrtF(LSqrtF* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - FloatRegister output = ToFloatRegister(ins->output()); - masm.as_sqrts(output, input); -} - -void -CodeGeneratorMIPS::visitAddI(LAddI* ins) -{ - const LAllocation* lhs = ins->getOperand(0); - const LAllocation* rhs = ins->getOperand(1); - const LDefinition* dest = ins->getDef(0); - - MOZ_ASSERT(rhs->isConstant() || rhs->isGeneralReg()); - - // If there is no snapshot, we don't need to check for overflow - if (!ins->snapshot()) { - if (rhs->isConstant()) - masm.ma_addu(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs))); - else - masm.as_addu(ToRegister(dest), ToRegister(lhs), ToRegister(rhs)); - return; - } - - Label overflow; - if (rhs->isConstant()) - masm.ma_addTestOverflow(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)), &overflow); - else - masm.ma_addTestOverflow(ToRegister(dest), ToRegister(lhs), ToRegister(rhs), &overflow); - - bailoutFrom(&overflow, ins->snapshot()); -} - -void -CodeGeneratorMIPS::visitSubI(LSubI* ins) -{ - const LAllocation* lhs = ins->getOperand(0); - const LAllocation* rhs = ins->getOperand(1); - const LDefinition* dest = ins->getDef(0); - - MOZ_ASSERT(rhs->isConstant() || rhs->isGeneralReg()); - - // If there is no snapshot, we don't need to check for overflow - if (!ins->snapshot()) { - if (rhs->isConstant()) - masm.ma_subu(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs))); - else - masm.as_subu(ToRegister(dest), ToRegister(lhs), ToRegister(rhs)); - return; - } - - Label overflow; - if (rhs->isConstant()) - masm.ma_subTestOverflow(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)), &overflow); - else - masm.ma_subTestOverflow(ToRegister(dest), ToRegister(lhs), ToRegister(rhs), &overflow); - - bailoutFrom(&overflow, ins->snapshot()); -} - -void -CodeGeneratorMIPS::visitMulI(LMulI* ins) -{ - const LAllocation* lhs = ins->lhs(); - const LAllocation* rhs = ins->rhs(); - Register dest = ToRegister(ins->output()); - MMul* mul = ins->mir(); - - MOZ_ASSERT_IF(mul->mode() == MMul::Integer, !mul->canBeNegativeZero() && !mul->canOverflow()); - - if (rhs->isConstant()) { - int32_t constant = ToInt32(rhs); - Register src = ToRegister(lhs); - - // Bailout on -0.0 - if (mul->canBeNegativeZero() && constant <= 0) { - Assembler::Condition cond = (constant == 0) ? Assembler::LessThan : Assembler::Equal; - bailoutCmp32(cond, src, Imm32(0), ins->snapshot()); - } - - switch (constant) { - case -1: - if (mul->canOverflow()) - bailoutCmp32(Assembler::Equal, src, Imm32(INT32_MIN), ins->snapshot()); - - masm.ma_negu(dest, src); - break; - case 0: - masm.move32(Imm32(0), dest); - break; - case 1: - masm.move32(src, dest); - break; - case 2: - if (mul->canOverflow()) { - Label mulTwoOverflow; - masm.ma_addTestOverflow(dest, src, src, &mulTwoOverflow); - - bailoutFrom(&mulTwoOverflow, ins->snapshot()); - } else { - masm.as_addu(dest, src, src); - } - break; - default: - uint32_t shift = FloorLog2(constant); - - if (!mul->canOverflow() && (constant > 0)) { - // If it cannot overflow, we can do lots of optimizations. - uint32_t rest = constant - (1 << shift); - - // See if the constant has one bit set, meaning it can be - // encoded as a bitshift. - if ((1 << shift) == constant) { - masm.ma_sll(dest, src, Imm32(shift)); - return; - } - - // If the constant cannot be encoded as (1<canOverflow() && (constant > 0) && (src != dest)) { - // To stay on the safe side, only optimize things that are a - // power of 2. - - if ((1 << shift) == constant) { - // dest = lhs * pow(2, shift) - masm.ma_sll(dest, src, Imm32(shift)); - // At runtime, check (lhs == dest >> shift), if this does - // not hold, some bits were lost due to overflow, and the - // computation should be resumed as a double. - masm.ma_sra(ScratchRegister, dest, Imm32(shift)); - bailoutCmp32(Assembler::NotEqual, src, ScratchRegister, ins->snapshot()); - return; - } - } - - if (mul->canOverflow()) { - Label mulConstOverflow; - masm.ma_mul_branch_overflow(dest, ToRegister(lhs), Imm32(ToInt32(rhs)), - &mulConstOverflow); - - bailoutFrom(&mulConstOverflow, ins->snapshot()); - } else { - masm.ma_mult(src, Imm32(ToInt32(rhs))); - masm.as_mflo(dest); - } - break; - } - } else { - Label multRegOverflow; - - if (mul->canOverflow()) { - masm.ma_mul_branch_overflow(dest, ToRegister(lhs), ToRegister(rhs), &multRegOverflow); - bailoutFrom(&multRegOverflow, ins->snapshot()); - } else { - masm.as_mult(ToRegister(lhs), ToRegister(rhs)); - masm.as_mflo(dest); - } - - if (mul->canBeNegativeZero()) { - Label done; - masm.ma_b(dest, dest, &done, Assembler::NonZero, ShortJump); - - // Result is -0 if lhs or rhs is negative. - // In that case result must be double value so bailout - Register scratch = SecondScratchReg; - masm.as_or(scratch, ToRegister(lhs), ToRegister(rhs)); - bailoutCmp32(Assembler::Signed, scratch, scratch, ins->snapshot()); - - masm.bind(&done); - } - } -} - -void -CodeGeneratorMIPS::visitDivI(LDivI* ins) -{ - // Extract the registers from this instruction - Register lhs = ToRegister(ins->lhs()); - Register rhs = ToRegister(ins->rhs()); - Register dest = ToRegister(ins->output()); - Register temp = ToRegister(ins->getTemp(0)); - MDiv* mir = ins->mir(); - - Label done; - - // Handle divide by zero. - if (mir->canBeDivideByZero()) { - if (mir->canTruncateInfinities()) { - // Truncated division by zero is zero (Infinity|0 == 0) - Label notzero; - masm.ma_b(rhs, rhs, ¬zero, Assembler::NonZero, ShortJump); - masm.move32(Imm32(0), dest); - masm.ma_b(&done, ShortJump); - masm.bind(¬zero); - } else { - MOZ_ASSERT(mir->fallible()); - bailoutCmp32(Assembler::Zero, rhs, rhs, ins->snapshot()); - } - } - - // Handle an integer overflow exception from -2147483648 / -1. - if (mir->canBeNegativeOverflow()) { - Label notMinInt; - masm.move32(Imm32(INT32_MIN), temp); - masm.ma_b(lhs, temp, ¬MinInt, Assembler::NotEqual, ShortJump); - - masm.move32(Imm32(-1), temp); - if (mir->canTruncateOverflow()) { - // (-INT32_MIN)|0 == INT32_MIN - Label skip; - masm.ma_b(rhs, temp, &skip, Assembler::NotEqual, ShortJump); - masm.move32(Imm32(INT32_MIN), dest); - masm.ma_b(&done, ShortJump); - masm.bind(&skip); - } else { - MOZ_ASSERT(mir->fallible()); - bailoutCmp32(Assembler::Equal, rhs, temp, ins->snapshot()); - } - masm.bind(¬MinInt); - } - - // Handle negative 0. (0/-Y) - if (!mir->canTruncateNegativeZero() && mir->canBeNegativeZero()) { - Label nonzero; - masm.ma_b(lhs, lhs, &nonzero, Assembler::NonZero, ShortJump); - bailoutCmp32(Assembler::LessThan, rhs, Imm32(0), ins->snapshot()); - masm.bind(&nonzero); - } - // Note: above safety checks could not be verified as Ion seems to be - // smarter and requires double arithmetic in such cases. - - // All regular. Lets call div. - if (mir->canTruncateRemainder()) { - masm.as_div(lhs, rhs); - masm.as_mflo(dest); - } else { - MOZ_ASSERT(mir->fallible()); - - Label remainderNonZero; - masm.ma_div_branch_overflow(dest, lhs, rhs, &remainderNonZero); - bailoutFrom(&remainderNonZero, ins->snapshot()); - } - - masm.bind(&done); -} - -void -CodeGeneratorMIPS::visitDivPowTwoI(LDivPowTwoI* ins) -{ - Register lhs = ToRegister(ins->numerator()); - Register dest = ToRegister(ins->output()); - Register tmp = ToRegister(ins->getTemp(0)); - int32_t shift = ins->shift(); - - if (shift != 0) { - MDiv* mir = ins->mir(); - if (!mir->isTruncated()) { - // If the remainder is going to be != 0, bailout since this must - // be a double. - masm.ma_sll(tmp, lhs, Imm32(32 - shift)); - bailoutCmp32(Assembler::NonZero, tmp, tmp, ins->snapshot()); - } - - if (!mir->canBeNegativeDividend()) { - // Numerator is unsigned, so needs no adjusting. Do the shift. - masm.ma_sra(dest, lhs, Imm32(shift)); - return; - } - - // Adjust the value so that shifting produces a correctly rounded result - // when the numerator is negative. See 10-1 "Signed Division by a Known - // Power of 2" in Henry S. Warren, Jr.'s Hacker's Delight. - if (shift > 1) { - masm.ma_sra(tmp, lhs, Imm32(31)); - masm.ma_srl(tmp, tmp, Imm32(32 - shift)); - masm.add32(lhs, tmp); - } else { - masm.ma_srl(tmp, lhs, Imm32(32 - shift)); - masm.add32(lhs, tmp); - } - - // Do the shift. - masm.ma_sra(dest, tmp, Imm32(shift)); - } else { - masm.move32(lhs, dest); - } -} - -void -CodeGeneratorMIPS::visitModI(LModI* ins) -{ - // Extract the registers from this instruction - Register lhs = ToRegister(ins->lhs()); - Register rhs = ToRegister(ins->rhs()); - Register dest = ToRegister(ins->output()); - Register callTemp = ToRegister(ins->callTemp()); - MMod* mir = ins->mir(); - Label done, prevent; - - masm.move32(lhs, callTemp); - - // Prevent INT_MIN % -1; - // The integer division will give INT_MIN, but we want -(double)INT_MIN. - if (mir->canBeNegativeDividend()) { - masm.ma_b(lhs, Imm32(INT_MIN), &prevent, Assembler::NotEqual, ShortJump); - if (mir->isTruncated()) { - // (INT_MIN % -1)|0 == 0 - Label skip; - masm.ma_b(rhs, Imm32(-1), &skip, Assembler::NotEqual, ShortJump); - masm.move32(Imm32(0), dest); - masm.ma_b(&done, ShortJump); - masm.bind(&skip); - } else { - MOZ_ASSERT(mir->fallible()); - bailoutCmp32(Assembler::Equal, rhs, Imm32(-1), ins->snapshot()); - } - masm.bind(&prevent); - } - - // 0/X (with X < 0) is bad because both of these values *should* be - // doubles, and the result should be -0.0, which cannot be represented in - // integers. X/0 is bad because it will give garbage (or abort), when it - // should give either \infty, -\infty or NAN. - - // Prevent 0 / X (with X < 0) and X / 0 - // testing X / Y. Compare Y with 0. - // There are three cases: (Y < 0), (Y == 0) and (Y > 0) - // If (Y < 0), then we compare X with 0, and bail if X == 0 - // If (Y == 0), then we simply want to bail. - // if (Y > 0), we don't bail. - - if (mir->canBeDivideByZero()) { - if (mir->isTruncated()) { - Label skip; - masm.ma_b(rhs, Imm32(0), &skip, Assembler::NotEqual, ShortJump); - masm.move32(Imm32(0), dest); - masm.ma_b(&done, ShortJump); - masm.bind(&skip); - } else { - MOZ_ASSERT(mir->fallible()); - bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot()); - } - } - - if (mir->canBeNegativeDividend()) { - Label notNegative; - masm.ma_b(rhs, Imm32(0), ¬Negative, Assembler::GreaterThan, ShortJump); - if (mir->isTruncated()) { - // NaN|0 == 0 and (0 % -X)|0 == 0 - Label skip; - masm.ma_b(lhs, Imm32(0), &skip, Assembler::NotEqual, ShortJump); - masm.move32(Imm32(0), dest); - masm.ma_b(&done, ShortJump); - masm.bind(&skip); - } else { - MOZ_ASSERT(mir->fallible()); - bailoutCmp32(Assembler::Equal, lhs, Imm32(0), ins->snapshot()); - } - masm.bind(¬Negative); - } - - masm.as_div(lhs, rhs); - masm.as_mfhi(dest); - - // If X%Y == 0 and X < 0, then we *actually* wanted to return -0.0 - if (mir->canBeNegativeDividend()) { - if (mir->isTruncated()) { - // -0.0|0 == 0 - } else { - MOZ_ASSERT(mir->fallible()); - // See if X < 0 - masm.ma_b(dest, Imm32(0), &done, Assembler::NotEqual, ShortJump); - bailoutCmp32(Assembler::Signed, callTemp, Imm32(0), ins->snapshot()); - } - } - masm.bind(&done); -} - -void -CodeGeneratorMIPS::visitModPowTwoI(LModPowTwoI* ins) -{ - Register in = ToRegister(ins->getOperand(0)); - Register out = ToRegister(ins->getDef(0)); - MMod* mir = ins->mir(); - Label negative, done; - - masm.move32(in, out); - masm.ma_b(in, in, &done, Assembler::Zero, ShortJump); - // Switch based on sign of the lhs. - // Positive numbers are just a bitmask - masm.ma_b(in, in, &negative, Assembler::Signed, ShortJump); - { - masm.and32(Imm32((1 << ins->shift()) - 1), out); - masm.ma_b(&done, ShortJump); - } - - // Negative numbers need a negate, bitmask, negate - { - masm.bind(&negative); - masm.neg32(out); - masm.and32(Imm32((1 << ins->shift()) - 1), out); - masm.neg32(out); - } - if (mir->canBeNegativeDividend()) { - if (!mir->isTruncated()) { - MOZ_ASSERT(mir->fallible()); - bailoutCmp32(Assembler::Equal, out, zero, ins->snapshot()); - } else { - // -0|0 == 0 - } - } - masm.bind(&done); -} - -void -CodeGeneratorMIPS::visitModMaskI(LModMaskI* ins) -{ - Register src = ToRegister(ins->getOperand(0)); - Register dest = ToRegister(ins->getDef(0)); - Register tmp0 = ToRegister(ins->getTemp(0)); - Register tmp1 = ToRegister(ins->getTemp(1)); - MMod* mir = ins->mir(); - - if (!mir->isTruncated() && mir->canBeNegativeDividend()) { - MOZ_ASSERT(mir->fallible()); - - Label bail; - masm.ma_mod_mask(src, dest, tmp0, tmp1, ins->shift(), &bail); - bailoutFrom(&bail, ins->snapshot()); - } else { - masm.ma_mod_mask(src, dest, tmp0, tmp1, ins->shift(), nullptr); - } -} - -void -CodeGeneratorMIPS::visitBitNotI(LBitNotI* ins) -{ - const LAllocation* input = ins->getOperand(0); - const LDefinition* dest = ins->getDef(0); - MOZ_ASSERT(!input->isConstant()); - - masm.ma_not(ToRegister(dest), ToRegister(input)); -} - -void -CodeGeneratorMIPS::visitBitOpI(LBitOpI* ins) -{ - const LAllocation* lhs = ins->getOperand(0); - const LAllocation* rhs = ins->getOperand(1); - const LDefinition* dest = ins->getDef(0); - // all of these bitops should be either imm32's, or integer registers. - switch (ins->bitop()) { - case JSOP_BITOR: - if (rhs->isConstant()) - masm.ma_or(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs))); - else - masm.as_or(ToRegister(dest), ToRegister(lhs), ToRegister(rhs)); - break; - case JSOP_BITXOR: - if (rhs->isConstant()) - masm.ma_xor(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs))); - else - masm.as_xor(ToRegister(dest), ToRegister(lhs), ToRegister(rhs)); - break; - case JSOP_BITAND: - if (rhs->isConstant()) - masm.ma_and(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs))); - else - masm.as_and(ToRegister(dest), ToRegister(lhs), ToRegister(rhs)); - break; - default: - MOZ_CRASH("unexpected binary opcode"); - } -} - -void -CodeGeneratorMIPS::visitShiftI(LShiftI* ins) -{ - Register lhs = ToRegister(ins->lhs()); - const LAllocation* rhs = ins->rhs(); - Register dest = ToRegister(ins->output()); - - if (rhs->isConstant()) { - int32_t shift = ToInt32(rhs) & 0x1F; - switch (ins->bitop()) { - case JSOP_LSH: - if (shift) - masm.ma_sll(dest, lhs, Imm32(shift)); - else - masm.move32(lhs, dest); - break; - case JSOP_RSH: - if (shift) - masm.ma_sra(dest, lhs, Imm32(shift)); - else - masm.move32(lhs, dest); - break; - case JSOP_URSH: - if (shift) { - masm.ma_srl(dest, lhs, Imm32(shift)); - } else { - // x >>> 0 can overflow. - masm.move32(lhs, dest); - if (ins->mir()->toUrsh()->fallible()) - bailoutCmp32(Assembler::LessThan, dest, Imm32(0), ins->snapshot()); - } - break; - default: - MOZ_CRASH("Unexpected shift op"); - } - } else { - // The shift amounts should be AND'ed into the 0-31 range - masm.ma_and(dest, ToRegister(rhs), Imm32(0x1F)); - - switch (ins->bitop()) { - case JSOP_LSH: - masm.ma_sll(dest, lhs, dest); - break; - case JSOP_RSH: - masm.ma_sra(dest, lhs, dest); - break; - case JSOP_URSH: - masm.ma_srl(dest, lhs, dest); - if (ins->mir()->toUrsh()->fallible()) { - // x >>> 0 can overflow. - bailoutCmp32(Assembler::LessThan, dest, Imm32(0), ins->snapshot()); - } - break; - default: - MOZ_CRASH("Unexpected shift op"); - } - } -} - -void -CodeGeneratorMIPS::visitUrshD(LUrshD* ins) -{ - Register lhs = ToRegister(ins->lhs()); - Register temp = ToRegister(ins->temp()); - - const LAllocation* rhs = ins->rhs(); - FloatRegister out = ToFloatRegister(ins->output()); - - if (rhs->isConstant()) { - masm.ma_srl(temp, lhs, Imm32(ToInt32(rhs))); - } else { - masm.ma_srl(temp, lhs, ToRegister(rhs)); - } - - masm.convertUInt32ToDouble(temp, out); -} - -void -CodeGeneratorMIPS::visitClzI(LClzI* ins) -{ - Register input = ToRegister(ins->input()); - Register output = ToRegister(ins->output()); - - masm.as_clz(output, input); -} - -void -CodeGeneratorMIPS::visitPowHalfD(LPowHalfD* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - FloatRegister output = ToFloatRegister(ins->output()); - - Label done, skip; - - // Masm.pow(-Infinity, 0.5) == Infinity. - masm.loadConstantDouble(NegativeInfinity(), ScratchDoubleReg); - masm.ma_bc1d(input, ScratchDoubleReg, &skip, Assembler::DoubleNotEqualOrUnordered, ShortJump); - masm.as_negd(output, ScratchDoubleReg); - masm.ma_b(&done, ShortJump); - - masm.bind(&skip); - // Math.pow(-0, 0.5) == 0 == Math.pow(0, 0.5). - // Adding 0 converts any -0 to 0. - masm.loadConstantDouble(0.0, ScratchDoubleReg); - masm.as_addd(output, input, ScratchDoubleReg); - masm.as_sqrtd(output, output); - - masm.bind(&done); -} - -MoveOperand -CodeGeneratorMIPS::toMoveOperand(LAllocation a) const -{ - if (a.isGeneralReg()) - return MoveOperand(ToRegister(a)); - if (a.isFloatReg()) { - return MoveOperand(ToFloatRegister(a)); - } - int32_t offset = ToStackOffset(a); - MOZ_ASSERT((offset & 3) == 0); - - return MoveOperand(StackPointer, offset); -} - class js::jit::OutOfLineTableSwitch : public OutOfLineCodeBase { MTableSwitch* mir_; @@ -1014,332 +98,6 @@ CodeGeneratorMIPS::emitTableSwitchDispatch(MTableSwitch* mir, Register index, masm.branch(address); } -void -CodeGeneratorMIPS::visitMathD(LMathD* math) -{ - const LAllocation* src1 = math->getOperand(0); - const LAllocation* src2 = math->getOperand(1); - const LDefinition* output = math->getDef(0); - - switch (math->jsop()) { - case JSOP_ADD: - masm.as_addd(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); - break; - case JSOP_SUB: - masm.as_subd(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); - break; - case JSOP_MUL: - masm.as_muld(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); - break; - case JSOP_DIV: - masm.as_divd(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); - break; - default: - MOZ_CRASH("unexpected opcode"); - } -} - -void -CodeGeneratorMIPS::visitMathF(LMathF* math) -{ - const LAllocation* src1 = math->getOperand(0); - const LAllocation* src2 = math->getOperand(1); - const LDefinition* output = math->getDef(0); - - switch (math->jsop()) { - case JSOP_ADD: - masm.as_adds(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); - break; - case JSOP_SUB: - masm.as_subs(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); - break; - case JSOP_MUL: - masm.as_muls(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); - break; - case JSOP_DIV: - masm.as_divs(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); - break; - default: - MOZ_CRASH("unexpected opcode"); - } -} - -void -CodeGeneratorMIPS::visitFloor(LFloor* lir) -{ - FloatRegister input = ToFloatRegister(lir->input()); - FloatRegister scratch = ScratchDoubleReg; - Register output = ToRegister(lir->output()); - - Label skipCheck, done; - - // If Nan, 0 or -0 check for bailout - masm.loadConstantDouble(0.0, scratch); - masm.ma_bc1d(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump); - - // If high part is not zero, it is NaN or -0, so we bail. - masm.moveFromDoubleHi(input, SecondScratchReg); - bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()); - - // Input was zero, so return zero. - masm.move32(Imm32(0), output); - masm.ma_b(&done, ShortJump); - - masm.bind(&skipCheck); - masm.as_floorwd(scratch, input); - masm.moveFromDoubleLo(scratch, output); - - bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); - bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()); - - masm.bind(&done); -} - -void -CodeGeneratorMIPS::visitFloorF(LFloorF* lir) -{ - FloatRegister input = ToFloatRegister(lir->input()); - FloatRegister scratch = ScratchFloat32Reg; - Register output = ToRegister(lir->output()); - - Label skipCheck, done; - - // If Nan, 0 or -0 check for bailout - masm.loadConstantFloat32(0.0f, scratch); - masm.ma_bc1s(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump); - - // If binary value is not zero, it is NaN or -0, so we bail. - masm.moveFromDoubleLo(input, SecondScratchReg); - bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()); - - // Input was zero, so return zero. - masm.move32(Imm32(0), output); - masm.ma_b(&done, ShortJump); - - masm.bind(&skipCheck); - masm.as_floorws(scratch, input); - masm.moveFromDoubleLo(scratch, output); - - bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); - bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()); - - masm.bind(&done); -} - -void -CodeGeneratorMIPS::visitCeil(LCeil* lir) -{ - FloatRegister input = ToFloatRegister(lir->input()); - FloatRegister scratch = ScratchDoubleReg; - Register output = ToRegister(lir->output()); - - Label performCeil, done; - - // If x < -1 or x > 0 then perform ceil. - masm.loadConstantDouble(0, scratch); - masm.branchDouble(Assembler::DoubleGreaterThan, input, scratch, &performCeil); - masm.loadConstantDouble(-1, scratch); - masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, scratch, &performCeil); - - // If high part is not zero, the input was not 0, so we bail. - masm.moveFromDoubleHi(input, SecondScratchReg); - bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()); - - // Input was zero, so return zero. - masm.move32(Imm32(0), output); - masm.ma_b(&done, ShortJump); - - masm.bind(&performCeil); - masm.as_ceilwd(scratch, input); - masm.moveFromDoubleLo(scratch, output); - - bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); - bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()); - - masm.bind(&done); -} - -void -CodeGeneratorMIPS::visitCeilF(LCeilF* lir) -{ - FloatRegister input = ToFloatRegister(lir->input()); - FloatRegister scratch = ScratchFloat32Reg; - Register output = ToRegister(lir->output()); - - Label performCeil, done; - - // If x < -1 or x > 0 then perform ceil. - masm.loadConstantFloat32(0, scratch); - masm.branchFloat(Assembler::DoubleGreaterThan, input, scratch, &performCeil); - masm.loadConstantFloat32(-1, scratch); - masm.branchFloat(Assembler::DoubleLessThanOrEqual, input, scratch, &performCeil); - - // If binary value is not zero, the input was not 0, so we bail. - masm.moveFromFloat32(input, SecondScratchReg); - bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()); - - // Input was zero, so return zero. - masm.move32(Imm32(0), output); - masm.ma_b(&done, ShortJump); - - masm.bind(&performCeil); - masm.as_ceilws(scratch, input); - masm.moveFromFloat32(scratch, output); - - bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); - bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()); - - masm.bind(&done); -} - -void -CodeGeneratorMIPS::visitRound(LRound* lir) -{ - FloatRegister input = ToFloatRegister(lir->input()); - FloatRegister temp = ToFloatRegister(lir->temp()); - FloatRegister scratch = ScratchDoubleReg; - Register output = ToRegister(lir->output()); - - Label bail, negative, end, skipCheck; - - // Load biggest number less than 0.5 in the temp register. - masm.loadConstantDouble(GetBiggestNumberLessThan(0.5), temp); - - // Branch to a slow path for negative inputs. Doesn't catch NaN or -0. - masm.loadConstantDouble(0.0, scratch); - masm.ma_bc1d(input, scratch, &negative, Assembler::DoubleLessThan, ShortJump); - - // If Nan, 0 or -0 check for bailout - masm.ma_bc1d(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump); - - // If high part is not zero, it is NaN or -0, so we bail. - masm.moveFromDoubleHi(input, SecondScratchReg); - bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()); - - // Input was zero, so return zero. - masm.move32(Imm32(0), output); - masm.ma_b(&end, ShortJump); - - masm.bind(&skipCheck); - masm.as_addd(scratch, input, temp); - masm.as_floorwd(scratch, scratch); - - masm.moveFromDoubleLo(scratch, output); - - bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); - bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()); - - masm.jump(&end); - - // Input is negative, but isn't -0. - masm.bind(&negative); - - // Inputs in ]-0.5; 0] need to be added 0.5, other negative inputs need to - // be added the biggest double less than 0.5. - Label loadJoin; - masm.loadConstantDouble(-0.5, scratch); - masm.branchDouble(Assembler::DoubleLessThan, input, scratch, &loadJoin); - masm.loadConstantDouble(0.5, temp); - masm.bind(&loadJoin); - - masm.addDouble(input, temp); - - // If input + 0.5 >= 0, input is a negative number >= -0.5 and the - // result is -0. - masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, temp, scratch, &bail); - bailoutFrom(&bail, lir->snapshot()); - - // Truncate and round toward zero. - // This is off-by-one for everything but integer-valued inputs. - masm.as_floorwd(scratch, temp); - masm.moveFromDoubleLo(scratch, output); - - bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); - - masm.bind(&end); -} - -void -CodeGeneratorMIPS::visitRoundF(LRoundF* lir) -{ - FloatRegister input = ToFloatRegister(lir->input()); - FloatRegister temp = ToFloatRegister(lir->temp()); - FloatRegister scratch = ScratchFloat32Reg; - Register output = ToRegister(lir->output()); - - Label bail, negative, end, skipCheck; - - // Load biggest number less than 0.5 in the temp register. - masm.loadConstantFloat32(GetBiggestNumberLessThan(0.5f), temp); - - // Branch to a slow path for negative inputs. Doesn't catch NaN or -0. - masm.loadConstantFloat32(0.0f, scratch); - masm.ma_bc1s(input, scratch, &negative, Assembler::DoubleLessThan, ShortJump); - - // If Nan, 0 or -0 check for bailout - masm.ma_bc1s(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump); - - // If binary value is not zero, it is NaN or -0, so we bail. - masm.moveFromFloat32(input, SecondScratchReg); - bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()); - - // Input was zero, so return zero. - masm.move32(Imm32(0), output); - masm.ma_b(&end, ShortJump); - - masm.bind(&skipCheck); - masm.as_adds(scratch, input, temp); - masm.as_floorws(scratch, scratch); - - masm.moveFromFloat32(scratch, output); - - bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); - bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()); - - masm.jump(&end); - - // Input is negative, but isn't -0. - masm.bind(&negative); - - // Inputs in ]-0.5; 0] need to be added 0.5, other negative inputs need to - // be added the biggest double less than 0.5. - Label loadJoin; - masm.loadConstantFloat32(-0.5f, scratch); - masm.branchFloat(Assembler::DoubleLessThan, input, scratch, &loadJoin); - masm.loadConstantFloat32(0.5f, temp); - masm.bind(&loadJoin); - - masm.as_adds(temp, input, temp); - - // If input + 0.5 >= 0, input is a negative number >= -0.5 and the - // result is -0. - masm.branchFloat(Assembler::DoubleGreaterThanOrEqual, temp, scratch, &bail); - bailoutFrom(&bail, lir->snapshot()); - - // Truncate and round toward zero. - // This is off-by-one for everything but integer-valued inputs. - masm.as_floorws(scratch, temp); - masm.moveFromFloat32(scratch, output); - - bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()); - - masm.bind(&end); -} - -void -CodeGeneratorMIPS::visitTruncateDToInt32(LTruncateDToInt32* ins) -{ - emitTruncateDouble(ToFloatRegister(ins->input()), ToRegister(ins->output()), - ins->mir()); -} - -void -CodeGeneratorMIPS::visitTruncateFToInt32(LTruncateFToInt32* ins) -{ - emitTruncateFloat32(ToFloatRegister(ins->input()), ToRegister(ins->output()), - ins->mir()); -} - static const uint32_t FrameSizes[] = { 128, 256, 512, 1024 }; FrameSizeClass @@ -1392,14 +150,6 @@ CodeGeneratorMIPS::ToTempValue(LInstruction* ins, size_t pos) return ValueOperand(typeReg, payloadReg); } -void -CodeGeneratorMIPS::visitValue(LValue* value) -{ - const ValueOperand out = ToOutValue(value); - - masm.moveValue(value->value(), out); -} - void CodeGeneratorMIPS::visitBox(LBox* box) { @@ -1442,129 +192,12 @@ CodeGeneratorMIPS::visitUnbox(LUnbox* unbox) } } -void -CodeGeneratorMIPS::visitDouble(LDouble* ins) -{ - const LDefinition* out = ins->getDef(0); - - masm.loadConstantDouble(ins->getDouble(), ToFloatRegister(out)); -} - -void -CodeGeneratorMIPS::visitFloat32(LFloat32* ins) -{ - const LDefinition* out = ins->getDef(0); - masm.loadConstantFloat32(ins->getFloat(), ToFloatRegister(out)); -} - Register CodeGeneratorMIPS::splitTagForTest(const ValueOperand& value) { return value.typeReg(); } -void -CodeGeneratorMIPS::visitTestDAndBranch(LTestDAndBranch* test) -{ - FloatRegister input = ToFloatRegister(test->input()); - - MBasicBlock* ifTrue = test->ifTrue(); - MBasicBlock* ifFalse = test->ifFalse(); - - masm.loadConstantDouble(0.0, ScratchDoubleReg); - // If 0, or NaN, the result is false. - - if (isNextBlock(ifFalse->lir())) { - branchToBlock(Assembler::DoubleFloat, input, ScratchDoubleReg, ifTrue, - Assembler::DoubleNotEqual); - } else { - branchToBlock(Assembler::DoubleFloat, input, ScratchDoubleReg, ifFalse, - Assembler::DoubleEqualOrUnordered); - jumpToBlock(ifTrue); - } -} - -void -CodeGeneratorMIPS::visitTestFAndBranch(LTestFAndBranch* test) -{ - FloatRegister input = ToFloatRegister(test->input()); - - MBasicBlock* ifTrue = test->ifTrue(); - MBasicBlock* ifFalse = test->ifFalse(); - - masm.loadConstantFloat32(0.0f, ScratchFloat32Reg); - // If 0, or NaN, the result is false. - - if (isNextBlock(ifFalse->lir())) { - branchToBlock(Assembler::SingleFloat, input, ScratchFloat32Reg, ifTrue, - Assembler::DoubleNotEqual); - } else { - branchToBlock(Assembler::SingleFloat, input, ScratchFloat32Reg, ifFalse, - Assembler::DoubleEqualOrUnordered); - jumpToBlock(ifTrue); - } -} - -void -CodeGeneratorMIPS::visitCompareD(LCompareD* comp) -{ - FloatRegister lhs = ToFloatRegister(comp->left()); - FloatRegister rhs = ToFloatRegister(comp->right()); - Register dest = ToRegister(comp->output()); - - Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop()); - masm.ma_cmp_set_double(dest, lhs, rhs, cond); -} - -void -CodeGeneratorMIPS::visitCompareF(LCompareF* comp) -{ - FloatRegister lhs = ToFloatRegister(comp->left()); - FloatRegister rhs = ToFloatRegister(comp->right()); - Register dest = ToRegister(comp->output()); - - Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop()); - masm.ma_cmp_set_float32(dest, lhs, rhs, cond); -} - -void -CodeGeneratorMIPS::visitCompareDAndBranch(LCompareDAndBranch* comp) -{ - FloatRegister lhs = ToFloatRegister(comp->left()); - FloatRegister rhs = ToFloatRegister(comp->right()); - - Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->cmpMir()->jsop()); - MBasicBlock* ifTrue = comp->ifTrue(); - MBasicBlock* ifFalse = comp->ifFalse(); - - if (isNextBlock(ifFalse->lir())) { - branchToBlock(Assembler::DoubleFloat, lhs, rhs, ifTrue, cond); - } else { - branchToBlock(Assembler::DoubleFloat, lhs, rhs, ifFalse, - Assembler::InvertCondition(cond)); - jumpToBlock(ifTrue); - } -} - -void -CodeGeneratorMIPS::visitCompareFAndBranch(LCompareFAndBranch* comp) -{ - FloatRegister lhs = ToFloatRegister(comp->left()); - FloatRegister rhs = ToFloatRegister(comp->right()); - - Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->cmpMir()->jsop()); - MBasicBlock* ifTrue = comp->ifTrue(); - MBasicBlock* ifFalse = comp->ifFalse(); - - if (isNextBlock(ifFalse->lir())) { - branchToBlock(Assembler::SingleFloat, lhs, rhs, ifTrue, cond); - } else { - branchToBlock(Assembler::SingleFloat, lhs, rhs, ifFalse, - Assembler::InvertCondition(cond)); - jumpToBlock(ifTrue); - } -} - void CodeGeneratorMIPS::visitCompareB(LCompareB* lir) { @@ -1657,484 +290,6 @@ CodeGeneratorMIPS::visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir) emitBranch(lhs.payloadReg(), rhs.payloadReg(), cond, lir->ifTrue(), lir->ifFalse()); } -void -CodeGeneratorMIPS::visitBitAndAndBranch(LBitAndAndBranch* lir) -{ - if (lir->right()->isConstant()) - masm.ma_and(ScratchRegister, ToRegister(lir->left()), Imm32(ToInt32(lir->right()))); - else - masm.as_and(ScratchRegister, ToRegister(lir->left()), ToRegister(lir->right())); - emitBranch(ScratchRegister, ScratchRegister, Assembler::NonZero, lir->ifTrue(), - lir->ifFalse()); -} - -void -CodeGeneratorMIPS::visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble* lir) -{ - masm.convertUInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output())); -} - -void -CodeGeneratorMIPS::visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32* lir) -{ - masm.convertUInt32ToFloat32(ToRegister(lir->input()), ToFloatRegister(lir->output())); -} - -void -CodeGeneratorMIPS::visitNotI(LNotI* ins) -{ - masm.cmp32Set(Assembler::Equal, ToRegister(ins->input()), Imm32(0), - ToRegister(ins->output())); -} - -void -CodeGeneratorMIPS::visitNotD(LNotD* ins) -{ - // Since this operation is not, we want to set a bit if - // the double is falsey, which means 0.0, -0.0 or NaN. - FloatRegister in = ToFloatRegister(ins->input()); - Register dest = ToRegister(ins->output()); - - Label falsey, done; - masm.loadConstantDouble(0.0, ScratchDoubleReg); - masm.ma_bc1d(in, ScratchDoubleReg, &falsey, Assembler::DoubleEqualOrUnordered, ShortJump); - - masm.move32(Imm32(0), dest); - masm.ma_b(&done, ShortJump); - - masm.bind(&falsey); - masm.move32(Imm32(1), dest); - - masm.bind(&done); -} - -void -CodeGeneratorMIPS::visitNotF(LNotF* ins) -{ - // Since this operation is not, we want to set a bit if - // the float32 is falsey, which means 0.0, -0.0 or NaN. - FloatRegister in = ToFloatRegister(ins->input()); - Register dest = ToRegister(ins->output()); - - Label falsey, done; - masm.loadConstantFloat32(0.0f, ScratchFloat32Reg); - masm.ma_bc1s(in, ScratchFloat32Reg, &falsey, Assembler::DoubleEqualOrUnordered, ShortJump); - - masm.move32(Imm32(0), dest); - masm.ma_b(&done, ShortJump); - - masm.bind(&falsey); - masm.move32(Imm32(1), dest); - - masm.bind(&done); -} - -void -CodeGeneratorMIPS::visitGuardShape(LGuardShape* guard) -{ - Register obj = ToRegister(guard->input()); - Register tmp = ToRegister(guard->tempInt()); - - masm.loadPtr(Address(obj, JSObject::offsetOfShape()), tmp); - bailoutCmpPtr(Assembler::NotEqual, tmp, ImmGCPtr(guard->mir()->shape()), - guard->snapshot()); -} - -void -CodeGeneratorMIPS::visitGuardObjectGroup(LGuardObjectGroup* guard) -{ - Register obj = ToRegister(guard->input()); - Register tmp = ToRegister(guard->tempInt()); - MOZ_ASSERT(obj != tmp); - - masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), tmp); - Assembler::Condition cond = guard->mir()->bailOnEquality() - ? Assembler::Equal - : Assembler::NotEqual; - bailoutCmpPtr(cond, tmp, ImmGCPtr(guard->mir()->group()), guard->snapshot()); -} - -void -CodeGeneratorMIPS::visitGuardClass(LGuardClass* guard) -{ - Register obj = ToRegister(guard->input()); - Register tmp = ToRegister(guard->tempInt()); - - masm.loadObjClass(obj, tmp); - bailoutCmpPtr(Assembler::NotEqual, tmp, ImmPtr(guard->mir()->getClass()), - guard->snapshot()); -} - -void -CodeGeneratorMIPS::generateInvalidateEpilogue() -{ - // Ensure that there is enough space in the buffer for the OsiPoint - // patching to occur. Otherwise, we could overwrite the invalidation - // epilogue. - for (size_t i = 0; i < sizeof(void*); i += Assembler::NopSize()) - masm.nop(); - - masm.bind(&invalidate_); - - // Push the return address of the point that we bailed out at to the stack - masm.Push(ra); - - // Push the Ion script onto the stack (when we determine what that - // pointer is). - invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1))); - JitCode* thunk = gen->jitRuntime()->getInvalidationThunk(); - - masm.branch(thunk); - - // We should never reach this point in JIT code -- the invalidation thunk - // should pop the invalidated JS frame and return directly to its caller. - masm.assumeUnreachable("Should have returned directly to its caller instead of here."); -} - -void -CodeGeneratorMIPS::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins) -{ - MOZ_CRASH("NYI"); -} - -void -CodeGeneratorMIPS::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins) -{ - MOZ_CRASH("NYI"); -} - -void -CodeGeneratorMIPS::visitAsmJSCall(LAsmJSCall* ins) -{ - emitAsmJSCall(ins); -} - -void -CodeGeneratorMIPS::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins) -{ - const MAsmJSLoadHeap* mir = ins->mir(); - const LAllocation* ptr = ins->ptr(); - const LDefinition* out = ins->output(); - - bool isSigned; - int size; - bool isFloat = false; - switch (mir->accessType()) { - case Scalar::Int8: isSigned = true; size = 8; break; - case Scalar::Uint8: isSigned = false; size = 8; break; - case Scalar::Int16: isSigned = true; size = 16; break; - case Scalar::Uint16: isSigned = false; size = 16; break; - case Scalar::Int32: isSigned = true; size = 32; break; - case Scalar::Uint32: isSigned = false; size = 32; break; - case Scalar::Float64: isFloat = true; size = 64; break; - case Scalar::Float32: isFloat = true; size = 32; break; - default: MOZ_CRASH("unexpected array type"); - } - - if (ptr->isConstant()) { - MOZ_ASSERT(!mir->needsBoundsCheck()); - int32_t ptrImm = ptr->toConstant()->toInt32(); - MOZ_ASSERT(ptrImm >= 0); - if (isFloat) { - if (size == 32) { - masm.loadFloat32(Address(HeapReg, ptrImm), ToFloatRegister(out)); - } else { - masm.loadDouble(Address(HeapReg, ptrImm), ToFloatRegister(out)); - } - } else { - masm.ma_load(ToRegister(out), Address(HeapReg, ptrImm), - static_cast(size), isSigned ? SignExtend : ZeroExtend); - } - return; - } - - Register ptrReg = ToRegister(ptr); - - if (!mir->needsBoundsCheck()) { - if (isFloat) { - if (size == 32) { - masm.loadFloat32(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out)); - } else { - masm.loadDouble(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out)); - } - } else { - masm.ma_load(ToRegister(out), BaseIndex(HeapReg, ptrReg, TimesOne), - static_cast(size), isSigned ? SignExtend : ZeroExtend); - } - return; - } - - BufferOffset bo = masm.ma_BoundsCheck(ScratchRegister); - - Label done, outOfRange; - masm.ma_b(ptrReg, ScratchRegister, &outOfRange, Assembler::AboveOrEqual, ShortJump); - // Offset is ok, let's load value. - if (isFloat) { - if (size == 32) - masm.loadFloat32(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out)); - else - masm.loadDouble(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out)); - } else { - masm.ma_load(ToRegister(out), BaseIndex(HeapReg, ptrReg, TimesOne), - static_cast(size), isSigned ? SignExtend : ZeroExtend); - } - masm.ma_b(&done, ShortJump); - masm.bind(&outOfRange); - // Offset is out of range. Load default values. - if (isFloat) { - if (size == 32) - masm.loadFloat32(Address(GlobalReg, AsmJSNaN32GlobalDataOffset - AsmJSGlobalRegBias), - ToFloatRegister(out)); - else - masm.loadDouble(Address(GlobalReg, AsmJSNaN64GlobalDataOffset - AsmJSGlobalRegBias), - ToFloatRegister(out)); - } else { - if (mir->isAtomicAccess()) - masm.ma_b(gen->outOfBoundsLabel()); - else - masm.move32(Imm32(0), ToRegister(out)); - } - masm.bind(&done); - - masm.append(AsmJSHeapAccess(bo.getOffset())); -} - -void -CodeGeneratorMIPS::visitAsmJSStoreHeap(LAsmJSStoreHeap* ins) -{ - const MAsmJSStoreHeap* mir = ins->mir(); - const LAllocation* value = ins->value(); - const LAllocation* ptr = ins->ptr(); - - bool isSigned; - int size; - bool isFloat = false; - switch (mir->accessType()) { - case Scalar::Int8: isSigned = true; size = 8; break; - case Scalar::Uint8: isSigned = false; size = 8; break; - case Scalar::Int16: isSigned = true; size = 16; break; - case Scalar::Uint16: isSigned = false; size = 16; break; - case Scalar::Int32: isSigned = true; size = 32; break; - case Scalar::Uint32: isSigned = false; size = 32; break; - case Scalar::Float64: isFloat = true; size = 64; break; - case Scalar::Float32: isFloat = true; size = 32; break; - default: MOZ_CRASH("unexpected array type"); - } - - if (ptr->isConstant()) { - MOZ_ASSERT(!mir->needsBoundsCheck()); - int32_t ptrImm = ptr->toConstant()->toInt32(); - MOZ_ASSERT(ptrImm >= 0); - - if (isFloat) { - if (size == 32) { - masm.storeFloat32(ToFloatRegister(value), Address(HeapReg, ptrImm)); - } else { - masm.storeDouble(ToFloatRegister(value), Address(HeapReg, ptrImm)); - } - } else { - masm.ma_store(ToRegister(value), Address(HeapReg, ptrImm), - static_cast(size), isSigned ? SignExtend : ZeroExtend); - } - return; - } - - Register ptrReg = ToRegister(ptr); - Address dstAddr(ptrReg, 0); - - if (!mir->needsBoundsCheck()) { - if (isFloat) { - if (size == 32) { - masm.storeFloat32(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne)); - } else - masm.storeDouble(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne)); - } else { - masm.ma_store(ToRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne), - static_cast(size), isSigned ? SignExtend : ZeroExtend); - } - return; - } - - BufferOffset bo = masm.ma_BoundsCheck(ScratchRegister); - - Label done, outOfRange; - masm.ma_b(ptrReg, ScratchRegister, &outOfRange, Assembler::AboveOrEqual, ShortJump); - - // Offset is ok, let's store value. - if (isFloat) { - if (size == 32) { - masm.storeFloat32(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne)); - } else - masm.storeDouble(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne)); - } else { - masm.ma_store(ToRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne), - static_cast(size), isSigned ? SignExtend : ZeroExtend); - } - masm.ma_b(&done, ShortJump); - masm.bind(&outOfRange); - // Offset is out of range. - if (mir->isAtomicAccess()) - masm.ma_b(gen->outOfBoundsLabel()); - masm.bind(&done); - - masm.append(AsmJSHeapAccess(bo.getOffset())); -} - -void -CodeGeneratorMIPS::visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins) -{ - MOZ_CRASH("NYI"); -} - -void -CodeGeneratorMIPS::visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins) -{ - MOZ_CRASH("NYI"); -} - -void -CodeGeneratorMIPS::visitAsmJSPassStackArg(LAsmJSPassStackArg* ins) -{ - const MAsmJSPassStackArg* mir = ins->mir(); - if (ins->arg()->isConstant()) { - masm.storePtr(ImmWord(ToInt32(ins->arg())), Address(StackPointer, mir->spOffset())); - } else { - if (ins->arg()->isGeneralReg()) { - masm.storePtr(ToRegister(ins->arg()), Address(StackPointer, mir->spOffset())); - } else { - masm.storeDouble(ToFloatRegister(ins->arg()).doubleOverlay(0), - Address(StackPointer, mir->spOffset())); - } - } -} - -void -CodeGeneratorMIPS::visitUDivOrMod(LUDivOrMod* ins) -{ - Register lhs = ToRegister(ins->lhs()); - Register rhs = ToRegister(ins->rhs()); - Register output = ToRegister(ins->output()); - Label done; - - // Prevent divide by zero. - if (ins->canBeDivideByZero()) { - if (ins->mir()->isTruncated()) { - // Infinity|0 == 0 - Label notzero; - masm.ma_b(rhs, rhs, ¬zero, Assembler::NonZero, ShortJump); - masm.move32(Imm32(0), output); - masm.ma_b(&done, ShortJump); - masm.bind(¬zero); - } else { - bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot()); - } - } - - masm.as_divu(lhs, rhs); - masm.as_mfhi(output); - - // If the remainder is > 0, bailout since this must be a double. - if (ins->mir()->isDiv()) { - if (!ins->mir()->toDiv()->canTruncateRemainder()) - bailoutCmp32(Assembler::NonZero, output, output, ins->snapshot()); - // Get quotient - masm.as_mflo(output); - } - - if (!ins->mir()->isTruncated()) - bailoutCmp32(Assembler::LessThan, output, Imm32(0), ins->snapshot()); - - masm.bind(&done); -} - -void -CodeGeneratorMIPS::visitEffectiveAddress(LEffectiveAddress* ins) -{ - const MEffectiveAddress* mir = ins->mir(); - Register base = ToRegister(ins->base()); - Register index = ToRegister(ins->index()); - Register output = ToRegister(ins->output()); - - BaseIndex address(base, index, mir->scale(), mir->displacement()); - masm.computeEffectiveAddress(address, output); -} - -void -CodeGeneratorMIPS::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins) -{ - const MAsmJSLoadGlobalVar* mir = ins->mir(); - unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias; - if (mir->type() == MIRType_Int32) - masm.load32(Address(GlobalReg, addr), ToRegister(ins->output())); - else if (mir->type() == MIRType_Float32) - masm.loadFloat32(Address(GlobalReg, addr), ToFloatRegister(ins->output())); - else - masm.loadDouble(Address(GlobalReg, addr), ToFloatRegister(ins->output())); -} - -void -CodeGeneratorMIPS::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins) -{ - const MAsmJSStoreGlobalVar* mir = ins->mir(); - - MOZ_ASSERT(IsNumberType(mir->value()->type())); - unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias; - if (mir->value()->type() == MIRType_Int32) - masm.store32(ToRegister(ins->value()), Address(GlobalReg, addr)); - else if (mir->value()->type() == MIRType_Float32) - masm.storeFloat32(ToFloatRegister(ins->value()), Address(GlobalReg, addr)); - else - masm.storeDouble(ToFloatRegister(ins->value()), Address(GlobalReg, addr)); -} - -void -CodeGeneratorMIPS::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins) -{ - const MAsmJSLoadFuncPtr* mir = ins->mir(); - - Register index = ToRegister(ins->index()); - Register out = ToRegister(ins->output()); - unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias; - - BaseIndex source(GlobalReg, index, ScalePointer, addr); - masm.loadPtr(source, out); -} - -void -CodeGeneratorMIPS::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins) -{ - const MAsmJSLoadFFIFunc* mir = ins->mir(); - masm.loadPtr(Address(GlobalReg, mir->globalDataOffset() - AsmJSGlobalRegBias), - ToRegister(ins->output())); -} - -void -CodeGeneratorMIPS::visitNegI(LNegI* ins) -{ - Register input = ToRegister(ins->input()); - Register output = ToRegister(ins->output()); - - masm.ma_negu(output, input); -} - -void -CodeGeneratorMIPS::visitNegD(LNegD* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - FloatRegister output = ToFloatRegister(ins->output()); - - masm.as_negd(output, input); -} - -void -CodeGeneratorMIPS::visitNegF(LNegF* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - FloatRegister output = ToFloatRegister(ins->output()); - - masm.as_negs(output, input); -} - void CodeGeneratorMIPS::setReturnDoubleRegs(LiveRegisterSet* regs) { diff --git a/js/src/jit/mips32/CodeGenerator-mips32.h b/js/src/jit/mips32/CodeGenerator-mips32.h index bfe90bb6500d..329c03efbfb3 100644 --- a/js/src/jit/mips32/CodeGenerator-mips32.h +++ b/js/src/jit/mips32/CodeGenerator-mips32.h @@ -7,117 +7,14 @@ #ifndef jit_mips32_CodeGenerator_mips32_h #define jit_mips32_CodeGenerator_mips32_h -#include "jit/mips32/Assembler-mips32.h" -#include "jit/shared/CodeGenerator-shared.h" +#include "jit/mips-shared/CodeGenerator-mips-shared.h" namespace js { namespace jit { -class OutOfLineBailout; -class OutOfLineTableSwitch; - -class CodeGeneratorMIPS : public CodeGeneratorShared +class CodeGeneratorMIPS : public CodeGeneratorMIPSShared { - friend class MoveResolverMIPS; - - CodeGeneratorMIPS* thisFromCtor() { - return this; - } - protected: - NonAssertingLabel deoptLabel_; - - inline Address ToAddress(const LAllocation& a); - inline Address ToAddress(const LAllocation* a); - - MoveOperand toMoveOperand(LAllocation a) const; - - template - void bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) { - Label skip; - masm.branch32(Assembler::InvertCondition(c), lhs, rhs, &skip); - bailout(snapshot); - masm.bind(&skip); - } - template - void bailoutCmp32(Assembler::Condition c, Operand lhs, T rhs, LSnapshot* snapshot) { - if (lhs.getTag() == Operand::REG) - bailoutCmp32(c, lhs.toReg(), rhs, snapshot); - else if (lhs.getTag() == Operand::MEM) - bailoutCmp32(c, lhs.toAddress(), rhs, snapshot); - else - MOZ_CRASH("Invalid operand tag."); - } - template - void bailoutTest32(Assembler::Condition c, Register lhs, T rhs, LSnapshot* snapshot) { - Label bail; - masm.branchTest32(c, lhs, rhs, &bail); - bailoutFrom(&bail, snapshot); - } - template - void bailoutCmpPtr(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) { - Label skip; - masm.branchPtr(Assembler::InvertCondition(c), lhs, rhs, &skip); - bailout(snapshot); - masm.bind(&skip); - } - void bailoutTestPtr(Assembler::Condition c, Register lhs, Register rhs, LSnapshot* snapshot) { - Label bail; - masm.branchTestPtr(c, lhs, rhs, &bail); - bailoutFrom(&bail, snapshot); - } - void bailoutIfFalseBool(Register reg, LSnapshot* snapshot) { - Label bail; - masm.branchTest32(Assembler::Zero, reg, Imm32(0xFF), &bail); - bailoutFrom(&bail, snapshot); - } - - void bailoutFrom(Label* label, LSnapshot* snapshot); - void bailout(LSnapshot* snapshot); - - protected: - bool generateOutOfLineCode(); - - template - void branchToBlock(Register lhs, T rhs, MBasicBlock* mir, Assembler::Condition cond) - { - mir = skipTrivialBlocks(mir); - - Label* label = mir->lir()->label(); - if (Label* oolEntry = labelForBackedgeWithImplicitCheck(mir)) { - // Note: the backedge is initially a jump to the next instruction. - // It will be patched to the target block's label during link(). - RepatchLabel rejoin; - CodeOffsetJump backedge; - Label skip; - - masm.ma_b(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump); - backedge = masm.backedgeJump(&rejoin); - masm.bind(&rejoin); - masm.bind(&skip); - - if (!patchableBackedges_.append(PatchableBackedgeInfo(backedge, label, oolEntry))) - MOZ_CRASH(); - } else { - masm.ma_b(lhs, rhs, label, cond); - } - } - void branchToBlock(Assembler::FloatFormat fmt, FloatRegister lhs, FloatRegister rhs, - MBasicBlock* mir, Assembler::DoubleCondition cond); - - // Emits a branch that directs control flow to the true block if |cond| is - // true, and the false block if |cond| is false. - template - void emitBranch(Register lhs, T rhs, Assembler::Condition cond, - MBasicBlock* mirTrue, MBasicBlock* mirFalse) - { - if (isNextBlock(mirFalse->lir())) { - branchToBlock(lhs, rhs, mirTrue, cond); - } else { - branchToBlock(lhs, rhs, mirFalse, Assembler::InvertCondition(cond)); - jumpToBlock(mirTrue); - } - } void testNullEmitBranch(Assembler::Condition cond, const ValueOperand& value, MBasicBlock* ifTrue, MBasicBlock* ifFalse) { @@ -133,75 +30,17 @@ class CodeGeneratorMIPS : public CodeGeneratorShared { emitBranch(value.typeReg(), (Imm32)ImmType(JSVAL_TYPE_OBJECT), cond, ifTrue, ifFalse); } - void testZeroEmitBranch(Assembler::Condition cond, Register reg, - MBasicBlock* ifTrue, MBasicBlock* ifFalse) - { - emitBranch(reg, Imm32(0), cond, ifTrue, ifFalse); - } void emitTableSwitchDispatch(MTableSwitch* mir, Register index, Register base); public: - // Instruction visitors. - virtual void visitMinMaxD(LMinMaxD* ins); - virtual void visitMinMaxF(LMinMaxF* ins); - virtual void visitAbsD(LAbsD* ins); - virtual void visitAbsF(LAbsF* ins); - virtual void visitSqrtD(LSqrtD* ins); - virtual void visitSqrtF(LSqrtF* ins); - virtual void visitAddI(LAddI* ins); - virtual void visitSubI(LSubI* ins); - virtual void visitBitNotI(LBitNotI* ins); - virtual void visitBitOpI(LBitOpI* ins); - - virtual void visitMulI(LMulI* ins); - - virtual void visitDivI(LDivI* ins); - virtual void visitDivPowTwoI(LDivPowTwoI* ins); - virtual void visitModI(LModI* ins); - virtual void visitModPowTwoI(LModPowTwoI* ins); - virtual void visitModMaskI(LModMaskI* ins); - virtual void visitPowHalfD(LPowHalfD* ins); - virtual void visitShiftI(LShiftI* ins); - virtual void visitUrshD(LUrshD* ins); - - virtual void visitClzI(LClzI* ins); - - virtual void visitTestIAndBranch(LTestIAndBranch* test); - virtual void visitCompare(LCompare* comp); - virtual void visitCompareAndBranch(LCompareAndBranch* comp); - virtual void visitTestDAndBranch(LTestDAndBranch* test); - virtual void visitTestFAndBranch(LTestFAndBranch* test); - virtual void visitCompareD(LCompareD* comp); - virtual void visitCompareF(LCompareF* comp); - virtual void visitCompareDAndBranch(LCompareDAndBranch* comp); - virtual void visitCompareFAndBranch(LCompareFAndBranch* comp); virtual void visitCompareB(LCompareB* lir); virtual void visitCompareBAndBranch(LCompareBAndBranch* lir); virtual void visitCompareBitwise(LCompareBitwise* lir); virtual void visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir); - virtual void visitBitAndAndBranch(LBitAndAndBranch* lir); - virtual void visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble* lir); - virtual void visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32* lir); - virtual void visitNotI(LNotI* ins); - virtual void visitNotD(LNotD* ins); - virtual void visitNotF(LNotF* ins); - - virtual void visitMathD(LMathD* math); - virtual void visitMathF(LMathF* math); - virtual void visitFloor(LFloor* lir); - virtual void visitFloorF(LFloorF* lir); - virtual void visitCeil(LCeil* lir); - virtual void visitCeilF(LCeilF* lir); - virtual void visitRound(LRound* lir); - virtual void visitRoundF(LRoundF* lir); - virtual void visitTruncateDToInt32(LTruncateDToInt32* ins); - virtual void visitTruncateFToInt32(LTruncateFToInt32* ins); // Out of line visitors. - void visitOutOfLineBailout(OutOfLineBailout* ool); void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool); - protected: ValueOperand ToValue(LInstruction* ins, size_t pos); ValueOperand ToOutValue(LInstruction* ins); @@ -211,84 +50,19 @@ class CodeGeneratorMIPS : public CodeGeneratorShared Register splitTagForTest(const ValueOperand& value); public: - CodeGeneratorMIPS(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm); + CodeGeneratorMIPS(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm) + : CodeGeneratorMIPSShared(gen, graph, masm) + { } public: void visitBox(LBox* box); void visitBoxFloatingPoint(LBoxFloatingPoint* box); void visitUnbox(LUnbox* unbox); - void visitValue(LValue* value); - void visitDouble(LDouble* ins); - void visitFloat32(LFloat32* ins); - - void visitGuardShape(LGuardShape* guard); - void visitGuardObjectGroup(LGuardObjectGroup* guard); - void visitGuardClass(LGuardClass* guard); - - void visitNegI(LNegI* lir); - void visitNegD(LNegD* lir); - void visitNegF(LNegF* lir); - void visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins); - void visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins); - void visitAsmJSCall(LAsmJSCall* ins); - void visitAsmJSLoadHeap(LAsmJSLoadHeap* ins); - void visitAsmJSStoreHeap(LAsmJSStoreHeap* ins); - void visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins); - void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins); - void visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins); - void visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins); - void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins); - void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins); - - void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins); - - void generateInvalidateEpilogue(); - void setReturnDoubleRegs(LiveRegisterSet* regs); - - protected: - void visitEffectiveAddress(LEffectiveAddress* ins); - void visitUDivOrMod(LUDivOrMod* ins); - - public: - // Unimplemented SIMD instructions - void visitSimdSplatX4(LSimdSplatX4* lir) { MOZ_CRASH("NYI"); } - void visitInt32x4(LInt32x4* ins) { MOZ_CRASH("NYI"); } - void visitFloat32x4(LFloat32x4* ins) { MOZ_CRASH("NYI"); } - void visitSimdReinterpretCast(LSimdReinterpretCast* ins) { MOZ_CRASH("NYI"); } - void visitSimdExtractElementI(LSimdExtractElementI* ins) { MOZ_CRASH("NYI"); } - void visitSimdExtractElementF(LSimdExtractElementF* ins) { MOZ_CRASH("NYI"); } - void visitSimdSignMaskX4(LSimdSignMaskX4* ins) { MOZ_CRASH("NYI"); } - void visitSimdBinaryCompIx4(LSimdBinaryCompIx4* lir) { MOZ_CRASH("NYI"); } - void visitSimdBinaryCompFx4(LSimdBinaryCompFx4* lir) { MOZ_CRASH("NYI"); } - void visitSimdBinaryArithIx4(LSimdBinaryArithIx4* lir) { MOZ_CRASH("NYI"); } - void visitSimdBinaryArithFx4(LSimdBinaryArithFx4* lir) { MOZ_CRASH("NYI"); } - void visitSimdBinaryBitwiseX4(LSimdBinaryBitwiseX4* lir) { MOZ_CRASH("NYI"); } - void visitSimdGeneralShuffleI(LSimdGeneralShuffleI* lir) { MOZ_CRASH("NYI"); } - void visitSimdGeneralShuffleF(LSimdGeneralShuffleF* lir) { MOZ_CRASH("NYI"); } }; typedef CodeGeneratorMIPS CodeGeneratorSpecific; -// An out-of-line bailout thunk. -class OutOfLineBailout : public OutOfLineCodeBase -{ - LSnapshot* snapshot_; - uint32_t frameSize_; - - public: - OutOfLineBailout(LSnapshot* snapshot, uint32_t frameSize) - : snapshot_(snapshot), - frameSize_(frameSize) - { } - - void accept(CodeGeneratorMIPS* codegen); - - LSnapshot* snapshot() const { - return snapshot_; - } -}; - } // namespace jit } // namespace js diff --git a/js/src/moz.build b/js/src/moz.build index 7f2ea6ce811c..24ab58746af0 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -481,6 +481,7 @@ elif CONFIG['JS_CODEGEN_MIPS32']: 'jit/mips-shared/Bailouts-mips-shared.cpp', 'jit/mips-shared/BaselineCompiler-mips-shared.cpp', 'jit/mips-shared/BaselineIC-mips-shared.cpp', + 'jit/mips-shared/CodeGenerator-mips-shared.cpp', 'jit/mips-shared/Lowering-mips-shared.cpp', 'jit/mips-shared/MoveEmitter-mips-shared.cpp', ] From e4df89eefffd39ce2677cc08710214f7ace57679 Mon Sep 17 00:00:00 2001 From: Heiher Date: Wed, 30 Sep 2015 07:03:30 +0800 Subject: [PATCH 053/104] Bug 1205566 - IonMonkey: MIPS: bailoutCmp32/Ptr optimization. r=nbp --- js/src/jit/mips-shared/CodeGenerator-mips-shared.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) --- js/src/jit/mips-shared/CodeGenerator-mips-shared.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.h b/js/src/jit/mips-shared/CodeGenerator-mips-shared.h index 29391ddf4fb7..ce06b14eb08a 100644 --- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.h +++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.h @@ -33,10 +33,9 @@ class CodeGeneratorMIPSShared : public CodeGeneratorShared template void bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) { - Label skip; - masm.branch32(Assembler::InvertCondition(c), lhs, rhs, &skip); - bailout(snapshot); - masm.bind(&skip); + Label bail; + masm.branch32(c, lhs, rhs, &bail); + bailoutFrom(&bail, snapshot); } template void bailoutCmp32(Assembler::Condition c, Operand lhs, T rhs, LSnapshot* snapshot) { @@ -55,10 +54,9 @@ class CodeGeneratorMIPSShared : public CodeGeneratorShared } template void bailoutCmpPtr(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) { - Label skip; - masm.branchPtr(Assembler::InvertCondition(c), lhs, rhs, &skip); - bailout(snapshot); - masm.bind(&skip); + Label bail; + masm.branchPtr(c, lhs, rhs, &bail); + bailoutFrom(&bail, snapshot); } void bailoutTestPtr(Assembler::Condition c, Register lhs, Register rhs, LSnapshot* snapshot) { Label bail; From 0d0b280146a351ab2547dfde766ad465dd1ce681 Mon Sep 17 00:00:00 2001 From: Eitan Isaacson Date: Tue, 29 Sep 2015 11:17:40 -0400 Subject: [PATCH 054/104] Bug 1003464 - Support Web Speech API synthesis via speech-dispatcher. r=kdavis --- configure.in | 15 + dom/media/webspeech/synth/moz.build | 12 +- .../synth/speechd/SpeechDispatcherModule.cpp | 56 ++ .../synth/speechd/SpeechDispatcherService.cpp | 557 ++++++++++++++++++ .../synth/speechd/SpeechDispatcherService.h | 62 ++ dom/media/webspeech/synth/speechd/moz.build | 13 + 6 files changed, 712 insertions(+), 3 deletions(-) create mode 100644 dom/media/webspeech/synth/speechd/SpeechDispatcherModule.cpp create mode 100644 dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp create mode 100644 dom/media/webspeech/synth/speechd/SpeechDispatcherService.h create mode 100644 dom/media/webspeech/synth/speechd/moz.build diff --git a/configure.in b/configure.in index f0d2a7407b6e..c8e3bd7d1071 100644 --- a/configure.in +++ b/configure.in @@ -4780,6 +4780,21 @@ then fi AC_SUBST(MOZ_ENABLE_DBUS) +dnl ======================================================== +dnl = speech-dispatcher support +dnl ======================================================== + +if test "$MOZ_ENABLE_GTK" -o "$MOZ_ENABLE_QT" +then + MOZ_SYNTH_SPEECHD=1 + + MOZ_ARG_DISABLE_BOOL(synth-speechd, + [ --disable-synth-speechd Disable speech-dispatcher support ], + MOZ_SYNTH_SPEECHD=, + MOZ_SYNTH_SPEECHD=1) +fi +AC_SUBST(MOZ_SYNTH_SPEECHD) + dnl ======================================================== dnl = Enable Android History instead of Places dnl ======================================================== diff --git a/dom/media/webspeech/synth/moz.build b/dom/media/webspeech/synth/moz.build index 1d6e01d107ea..b3dce2a7cc1b 100644 --- a/dom/media/webspeech/synth/moz.build +++ b/dom/media/webspeech/synth/moz.build @@ -41,10 +41,16 @@ if CONFIG['MOZ_WEBSPEECH']: 'test/nsFakeSynthServices.cpp' ] + DIRS = [] + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': - DIRS = ['windows'] - elif CONFIG['MOZ_SYNTH_PICO']: - DIRS = ['pico'] + DIRS += ['windows'] + + if CONFIG['MOZ_SYNTH_SPEECHD']: + DIRS += ['speechd'] + + if CONFIG['MOZ_SYNTH_PICO']: + DIRS += ['pico'] IPDL_SOURCES += [ 'ipc/PSpeechSynthesis.ipdl', diff --git a/dom/media/webspeech/synth/speechd/SpeechDispatcherModule.cpp b/dom/media/webspeech/synth/speechd/SpeechDispatcherModule.cpp new file mode 100644 index 000000000000..deed7c1d29b4 --- /dev/null +++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherModule.cpp @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/ModuleUtils.h" +#include "nsIClassInfoImpl.h" +#include "SpeechDispatcherService.h" + +using namespace mozilla::dom; + +#define SPEECHDISPATCHERSERVICE_CID \ + {0x8817b1cf, 0x5ada, 0x43bf, {0xbd, 0x73, 0x60, 0x76, 0x57, 0x70, 0x3d, 0x0d}} + +#define SPEECHDISPATCHERSERVICE_CONTRACTID "@mozilla.org/synthspeechdispatcher;1" + +// Defines SpeechDispatcherServiceConstructor +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(SpeechDispatcherService, + SpeechDispatcherService::GetInstanceForService) + +// Defines kSPEECHDISPATCHERSERVICE_CID +NS_DEFINE_NAMED_CID(SPEECHDISPATCHERSERVICE_CID); + +static const mozilla::Module::CIDEntry kCIDs[] = { + { &kSPEECHDISPATCHERSERVICE_CID, true, nullptr, SpeechDispatcherServiceConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kContracts[] = { + { SPEECHDISPATCHERSERVICE_CONTRACTID, &kSPEECHDISPATCHERSERVICE_CID }, + { nullptr } +}; + +static const mozilla::Module::CategoryEntry kCategories[] = { + { "profile-after-change", "SpeechDispatcher Speech Synth", SPEECHDISPATCHERSERVICE_CONTRACTID }, + { nullptr } +}; + +static void +UnloadSpeechDispatcherModule() +{ + SpeechDispatcherService::Shutdown(); +} + +static const mozilla::Module kModule = { + mozilla::Module::kVersion, + kCIDs, + kContracts, + kCategories, + nullptr, + nullptr, + UnloadSpeechDispatcherModule +}; + +NSMODULE_DEFN(synthspeechdispatcher) = &kModule; diff --git a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp new file mode 100644 index 000000000000..765c17f8fc38 --- /dev/null +++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp @@ -0,0 +1,557 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SpeechDispatcherService.h" + +#include "mozilla/dom/nsSpeechTask.h" +#include "mozilla/dom/nsSynthVoiceRegistry.h" +#include "mozilla/Preferences.h" +#include "nsEscape.h" +#include "nsISupports.h" +#include "nsPrintfCString.h" +#include "nsReadableUtils.h" +#include "nsServiceManagerUtils.h" +#include "nsThreadUtils.h" +#include "prlink.h" + +#define URI_PREFIX "urn:moz-tts:sapi:" + +// Some structures for libspeechd +typedef enum { + SPD_EVENT_BEGIN, + SPD_EVENT_END, + SPD_EVENT_INDEX_MARK, + SPD_EVENT_CANCEL, + SPD_EVENT_PAUSE, + SPD_EVENT_RESUME +} SPDNotificationType; + +typedef enum { + SPD_BEGIN = 1, + SPD_END = 2, + SPD_INDEX_MARKS = 4, + SPD_CANCEL = 8, + SPD_PAUSE = 16, + SPD_RESUME = 32, + + SPD_ALL = 0x3f +} SPDNotification; + +typedef enum { + SPD_MODE_SINGLE = 0, + SPD_MODE_THREADED = 1 +} SPDConnectionMode; + +typedef void (*SPDCallback) (size_t msg_id, size_t client_id, + SPDNotificationType state); + +typedef void (*SPDCallbackIM) (size_t msg_id, size_t client_id, + SPDNotificationType state, char* index_mark); + +struct SPDConnection +{ + SPDCallback callback_begin; + SPDCallback callback_end; + SPDCallback callback_cancel; + SPDCallback callback_pause; + SPDCallback callback_resume; + SPDCallbackIM callback_im; + + /* partial, more private fields in structure */ +}; + +struct SPDVoice +{ + char* name; + char* language; + char* variant; +}; + +typedef enum { + SPD_IMPORTANT = 1, + SPD_MESSAGE = 2, + SPD_TEXT = 3, + SPD_NOTIFICATION = 4, + SPD_PROGRESS = 5 +} SPDPriority; + +#define SPEECHD_FUNCTIONS \ + FUNC(spd_open, SPDConnection*, (const char*, const char*, const char*, SPDConnectionMode)) \ + FUNC(spd_close, void, (SPDConnection*)) \ + FUNC(spd_list_synthesis_voices, SPDVoice**, (SPDConnection*)) \ + FUNC(spd_say, int, (SPDConnection*, SPDPriority, const char*)) \ + FUNC(spd_cancel, int, (SPDConnection*)) \ + FUNC(spd_set_volume, int, (SPDConnection*, int)) \ + FUNC(spd_set_voice_rate, int, (SPDConnection*, int)) \ + FUNC(spd_set_voice_pitch, int, (SPDConnection*, int)) \ + FUNC(spd_set_synthesis_voice, int, (SPDConnection*, const char*)) \ + FUNC(spd_set_notification_on, int, (SPDConnection*, SPDNotification)) + +#define FUNC(name, type, params) \ + typedef type (*_##name##_fn) params; \ + static _##name##_fn _##name; + +SPEECHD_FUNCTIONS + +#undef FUNC + +#define spd_open _spd_open +#define spd_close _spd_close +#define spd_list_synthesis_voices _spd_list_synthesis_voices +#define spd_say _spd_say +#define spd_cancel _spd_cancel +#define spd_set_volume _spd_set_volume +#define spd_set_voice_rate _spd_set_voice_rate +#define spd_set_voice_pitch _spd_set_voice_pitch +#define spd_set_synthesis_voice _spd_set_synthesis_voice +#define spd_set_notification_on _spd_set_notification_on + +static PRLibrary* speechdLib = nullptr; + +typedef void (*nsSpeechDispatcherFunc)(); +struct nsSpeechDispatcherDynamicFunction +{ + const char* functionName; + nsSpeechDispatcherFunc* function; +}; + +namespace mozilla { +namespace dom { + +StaticRefPtr SpeechDispatcherService::sSingleton; + +class SpeechDispatcherVoice +{ +public: + + SpeechDispatcherVoice(const nsAString& aName, const nsAString& aLanguage) + : mName(aName), mLanguage(aLanguage) {} + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SpeechDispatcherVoice) + + // Voice name + nsString mName; + + // Voice language, in BCP-47 syntax + nsString mLanguage; + +private: + ~SpeechDispatcherVoice() {} +}; + + +class SpeechDispatcherCallback final : public nsISpeechTaskCallback +{ +public: + SpeechDispatcherCallback(nsISpeechTask* aTask, SpeechDispatcherService* aService) + : mTask(aTask) + , mService(aService) {} + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(SpeechDispatcherCallback, nsISpeechTaskCallback) + + NS_DECL_NSISPEECHTASKCALLBACK + + bool OnSpeechEvent(SPDNotificationType state); + +private: + ~SpeechDispatcherCallback() { } + + // This pointer is used to dispatch events + nsCOMPtr mTask; + + // By holding a strong reference to the service we guarantee that it won't be + // destroyed before this runnable. + nsRefPtr mService; + + TimeStamp mStartTime; +}; + +NS_IMPL_CYCLE_COLLECTION(SpeechDispatcherCallback, mTask); + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechDispatcherCallback) + NS_INTERFACE_MAP_ENTRY(nsISpeechTaskCallback) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechTaskCallback) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechDispatcherCallback) +NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechDispatcherCallback) + +NS_IMETHODIMP +SpeechDispatcherCallback::OnPause() +{ + // XXX: Speech dispatcher does not pause immediately, but waits for the speech + // to reach an index mark so that it could resume from that offset. + // There is no support for word or sentence boundaries, so index marks would + // only occur in explicit SSML marks, and we don't support that yet. + // What in actuality happens, is that if you call spd_pause(), it will speak + // the utterance in its entirety, dispatch an end event, and then put speechd + // in a 'paused' state. Since it is after the utterance ended, we don't get + // that state change, and our speech api is in an unrecoverable state. + // So, since it is useless anyway, I am not implementing pause. + return NS_OK; +} + +NS_IMETHODIMP +SpeechDispatcherCallback::OnResume() +{ + // XXX: Unsupported, see OnPause(). + return NS_OK; +} + +NS_IMETHODIMP +SpeechDispatcherCallback::OnCancel() +{ + if (spd_cancel(mService->mSpeechdClient) < 0) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_IMETHODIMP +SpeechDispatcherCallback::OnVolumeChanged(float aVolume) +{ + // XXX: This currently does not change the volume mid-utterance, but it + // doesn't do anything bad either. So we could put this here with the hopes + // that speechd supports this in the future. + if (spd_set_volume(mService->mSpeechdClient, static_cast(aVolume * 100)) < 0) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +bool +SpeechDispatcherCallback::OnSpeechEvent(SPDNotificationType state) +{ + bool remove = false; + + switch (state) { + case SPD_EVENT_BEGIN: + mStartTime = TimeStamp::Now(); + mTask->DispatchStart(); + break; + + case SPD_EVENT_PAUSE: + mTask->DispatchPause((TimeStamp::Now() - mStartTime).ToSeconds(), 0); + break; + + case SPD_EVENT_RESUME: + mTask->DispatchResume((TimeStamp::Now() - mStartTime).ToSeconds(), 0); + break; + + case SPD_EVENT_CANCEL: + case SPD_EVENT_END: + mTask->DispatchEnd((TimeStamp::Now() - mStartTime).ToSeconds(), 0); + remove = true; + break; + + case SPD_EVENT_INDEX_MARK: + // Not yet supported + break; + + default: + break; + } + + return remove; +} + +static void +speechd_cb(size_t msg_id, size_t client_id, SPDNotificationType state) +{ + SpeechDispatcherService* service = SpeechDispatcherService::GetInstance(false); + + if (service) { + NS_DispatchToMainThread( + NS_NewRunnableMethodWithArgs( + service, &SpeechDispatcherService::EventNotify, + static_cast(msg_id), state)); + } +} + + +NS_INTERFACE_MAP_BEGIN(SpeechDispatcherService) + NS_INTERFACE_MAP_ENTRY(nsISpeechService) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechService) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(SpeechDispatcherService) +NS_IMPL_RELEASE(SpeechDispatcherService) + +SpeechDispatcherService::SpeechDispatcherService() + : mInitialized(false) + , mSpeechdClient(nullptr) +{ + if (!Preferences::GetBool("media.webspeech.synth.enabled") || + Preferences::GetBool("media.webspeech.synth.test")) { + return; + } + + // While speech dispatcher has a "threaded" mode, only spd_say() is async. + // Since synchronous socket i/o could impact startup time, we do + // initialization in a separate thread. + DebugOnly rv = NS_NewNamedThread("speechd init", + getter_AddRefs(mInitThread)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + rv = mInitThread->Dispatch( + NS_NewRunnableMethod(this, &SpeechDispatcherService::Init), NS_DISPATCH_NORMAL); + MOZ_ASSERT(NS_SUCCEEDED(rv)); +} + +SpeechDispatcherService::~SpeechDispatcherService() +{ + if (mInitThread) { + mInitThread->Shutdown(); + } + + if (mSpeechdClient) { + spd_close(mSpeechdClient); + } +} + +void +SpeechDispatcherService::Init() +{ +#define FUNC(name, type, params) { #name, (nsSpeechDispatcherFunc *)&_##name }, + static const nsSpeechDispatcherDynamicFunction kSpeechDispatcherSymbols[] = { + SPEECHD_FUNCTIONS + }; +#undef FUNC + + MOZ_ASSERT(!mInitialized); + + speechdLib = PR_LoadLibrary("libspeechd.so.2"); + + if (!speechdLib) { + NS_WARNING("Failed to load speechd library"); + return; + } + + for (uint32_t i = 0; i < ArrayLength(kSpeechDispatcherSymbols); i++) { + *kSpeechDispatcherSymbols[i].function = + PR_FindFunctionSymbol(speechdLib, kSpeechDispatcherSymbols[i].functionName); + + if (!*kSpeechDispatcherSymbols[i].function) { + NS_WARNING(nsPrintfCString("Failed to find speechd symbol for'%s'", + kSpeechDispatcherSymbols[i].functionName).get()); + return; + } + } + + mSpeechdClient = spd_open("firefox", "web speech api", "who", SPD_MODE_THREADED); + + // Get all the voices from sapi and register in the SynthVoiceRegistry + SPDVoice** list = spd_list_synthesis_voices(mSpeechdClient); + + mSpeechdClient->callback_begin = speechd_cb; + mSpeechdClient->callback_end = speechd_cb; + mSpeechdClient->callback_cancel = speechd_cb; + mSpeechdClient->callback_pause = speechd_cb; + mSpeechdClient->callback_resume = speechd_cb; + + spd_set_notification_on(mSpeechdClient, SPD_BEGIN); + spd_set_notification_on(mSpeechdClient, SPD_END); + spd_set_notification_on(mSpeechdClient, SPD_CANCEL); + + if (list != NULL) { + for (int i = 0; list[i]; i++) { + nsAutoString uri; + + uri.AssignLiteral(URI_PREFIX); + nsAutoCString name; + NS_EscapeURL(list[i]->name, -1, esc_OnlyNonASCII | esc_AlwaysCopy, name); + uri.Append(NS_ConvertUTF8toUTF16(name));; + uri.AppendLiteral("?"); + + nsAutoCString lang(list[i]->language); + + if (strcmp(list[i]->variant, "none") != 0) { + // In speech dispatcher, the variant will usually be the locale subtag + // with another, non-standard suptag after it. We keep the first one + // and convert it to uppercase. + const char* v = list[i]->variant; + const char* hyphen = strchr(v, '-'); + nsDependentCSubstring variant(v, hyphen ? hyphen - v : strlen(v)); + ToUpperCase(variant); + + // eSpeak uses UK which is not a valid region subtag in BCP47. + if (variant.Equals("UK")) { + variant.AssignLiteral("GB"); + } + + lang.AppendLiteral("-"); + lang.Append(variant); + } + + uri.Append(NS_ConvertUTF8toUTF16(lang)); + + mVoices.Put(uri, new SpeechDispatcherVoice( + NS_ConvertUTF8toUTF16(list[i]->name), + NS_ConvertUTF8toUTF16(lang))); + } + } + + NS_DispatchToMainThread(NS_NewRunnableMethod(this, &SpeechDispatcherService::RegisterVoices)); + + //mInitialized = true; +} + +struct VoiceTraverserData +{ + SpeechDispatcherService* mService; + nsSynthVoiceRegistry* mRegistry; +}; + +// private methods + +static PLDHashOperator +AddVoiceTraverser(const nsAString& aUri, + nsRefPtr& aVoice, + void* aUserArg) +{ + VoiceTraverserData* data = static_cast(aUserArg); + + // This service can only speak one utterance at a time, se we set + // aQueuesUtterances to true in order to track global state and schedule + // access to this service. + DebugOnly rv = data->mRegistry->AddVoice(data->mService, aUri, + aVoice->mName, aVoice->mLanguage, + aVoice->mName.EqualsLiteral("default"), true); + + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to add voice"); + + return PL_DHASH_NEXT; +} + +void +SpeechDispatcherService::RegisterVoices() +{ + VoiceTraverserData data = { this, nsSynthVoiceRegistry::GetInstance() }; + mVoices.Enumerate(AddVoiceTraverser, &data); + + mInitThread->Shutdown(); + mInitThread = nullptr; + + mInitialized = true; +} + +// TODO: Support SSML +NS_IMETHODIMP +SpeechDispatcherService::Speak(const nsAString& aText, const nsAString& aUri, + float aVolume, float aRate, float aPitch, + nsISpeechTask* aTask) +{ + if (NS_WARN_IF(!mInitialized)) { + return NS_ERROR_NOT_AVAILABLE; + } + + nsRefPtr callback = + new SpeechDispatcherCallback(aTask, this); + + bool found = false; + SpeechDispatcherVoice* voice = mVoices.GetWeak(aUri, &found); + + if(NS_WARN_IF(!(found))) { + return NS_ERROR_NOT_AVAILABLE; + } + + spd_set_synthesis_voice(mSpeechdClient, + NS_ConvertUTF16toUTF8(voice->mName).get()); + + // We provide a volume of 0.0 to 1.0, speech-dispatcher expects 0 - 100. + spd_set_volume(mSpeechdClient, static_cast(aVolume * 100)); + + // We provide a rate of 0.1 to 10 with 1 being default. + // speech-dispatcher expects -100 to 100 with 0 being default. + int rate = 0; + + if (aRate > 1) { + rate = static_cast((aRate - 1) * 10); + } else if (aRate <= 1) { + rate = static_cast((aRate - 1) * (100/0.9)); + } + + spd_set_voice_rate(mSpeechdClient, rate); + + // We provide a pitch of 0 to 2 with 1 being the default. + // speech-dispatcher expects -100 to 100 with 0 being default. + spd_set_voice_pitch(mSpeechdClient, static_cast((aPitch - 1) * 100)); + + // The last three parameters don't matter for an indirect service + nsresult rv = aTask->Setup(callback, 0, 0, 0); + + if (NS_FAILED(rv)) { + return rv; + } + + int msg_id = spd_say(mSpeechdClient, SPD_MESSAGE, NS_ConvertUTF16toUTF8(aText).get()); + + if (msg_id < 0) { + return NS_ERROR_FAILURE; + } + + mCallbacks.Put(msg_id, callback); + + return NS_OK; +} + +NS_IMETHODIMP +SpeechDispatcherService::GetServiceType(SpeechServiceType* aServiceType) +{ + *aServiceType = nsISpeechService::SERVICETYPE_INDIRECT_AUDIO; + return NS_OK; +} + +SpeechDispatcherService* +SpeechDispatcherService::GetInstance(bool create) +{ + if (XRE_GetProcessType() != GeckoProcessType_Default) { + MOZ_ASSERT(false, + "SpeechDispatcherService can only be started on main gecko process"); + return nullptr; + } + + if (!sSingleton && create) { + sSingleton = new SpeechDispatcherService(); + } + + return sSingleton; +} + +already_AddRefed +SpeechDispatcherService::GetInstanceForService() +{ + MOZ_ASSERT(NS_IsMainThread()); + nsRefPtr sapiService = GetInstance(); + return sapiService.forget(); +} + +void +SpeechDispatcherService::EventNotify(uint32_t aMsgId, uint32_t aState) +{ + SpeechDispatcherCallback* callback = mCallbacks.GetWeak(aMsgId); + + if (callback) { + if (callback->OnSpeechEvent((SPDNotificationType)aState)) { + mCallbacks.Remove(aMsgId); + } + } +} + +void +SpeechDispatcherService::Shutdown() +{ + if (!sSingleton) { + return; + } + + sSingleton = nullptr; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h new file mode 100644 index 000000000000..0bfa97fe16ea --- /dev/null +++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_SpeechDispatcherService_h +#define mozilla_dom_SpeechDispatcherService_h + +#include "mozilla/StaticPtr.h" +#include "nsAutoPtr.h" +#include "nsISpeechService.h" +#include "nsIThread.h" +#include "nsRefPtrHashtable.h" +#include "nsTArray.h" + +struct SPDConnection; + +namespace mozilla { +namespace dom { + +class SpeechDispatcherCallback; +class SpeechDispatcherVoice; + +class SpeechDispatcherService final : public nsISpeechService +{ + friend class SpeechDispatcherCallback; +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSISPEECHSERVICE + + SpeechDispatcherService(); + void Init(); + + void EventNotify(uint32_t aMsgId, uint32_t aState); + + static SpeechDispatcherService* GetInstance(bool create = true); + static already_AddRefed GetInstanceForService(); + + static void Shutdown(); + + static StaticRefPtr sSingleton; + +private: + virtual ~SpeechDispatcherService(); + + void RegisterVoices(); + + bool mInitialized; + + SPDConnection* mSpeechdClient; + + nsRefPtrHashtable mCallbacks; + + nsCOMPtr mInitThread; + + nsRefPtrHashtable mVoices; +}; + +} // namespace dom +} // namespace mozilla +#endif diff --git a/dom/media/webspeech/synth/speechd/moz.build b/dom/media/webspeech/synth/speechd/moz.build new file mode 100644 index 000000000000..3d8c8c015c05 --- /dev/null +++ b/dom/media/webspeech/synth/speechd/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'SpeechDispatcherModule.cpp', + 'SpeechDispatcherService.cpp' +] +include('/ipc/chromium/chromium-config.mozbuild') + +FINAL_LIBRARY = 'xul' From 116d238f3550960ee279a4eaf321f7cb2c02a601 Mon Sep 17 00:00:00 2001 From: Heiher Date: Wed, 30 Sep 2015 07:26:59 +0800 Subject: [PATCH 055/104] Bug 1209553 - IonMonkey: MIPS: Add suffix 'f' for constant float32. r=arai --- js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) --- js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp index 3aadaac05e3f..8baad73d8a1c 100644 --- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp +++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp @@ -1094,9 +1094,9 @@ CodeGeneratorMIPSShared::visitCeilF(LCeilF* lir) Label performCeil, done; // If x < -1 or x > 0 then perform ceil. - masm.loadConstantFloat32(0, scratch); + masm.loadConstantFloat32(0.0f, scratch); masm.branchFloat(Assembler::DoubleGreaterThan, input, scratch, &performCeil); - masm.loadConstantFloat32(-1, scratch); + masm.loadConstantFloat32(-1.0f, scratch); masm.branchFloat(Assembler::DoubleLessThanOrEqual, input, scratch, &performCeil); // If binary value is not zero, the input was not 0, so we bail. From 354672cfd185691658b20a9b771dfcfe3ed27c5d Mon Sep 17 00:00:00 2001 From: Trevor Saunders Date: Mon, 28 Sep 2015 13:34:35 -0400 Subject: [PATCH 056/104] bug 1208779 - null check aAccessible in GetChildIDFor() for 32 bit as well as 64 bit windows r=davidb --- accessible/windows/msaa/AccessibleWrap.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/accessible/windows/msaa/AccessibleWrap.cpp b/accessible/windows/msaa/AccessibleWrap.cpp index 1273a783fc54..1534aefbdaee 100644 --- a/accessible/windows/msaa/AccessibleWrap.cpp +++ b/accessible/windows/msaa/AccessibleWrap.cpp @@ -1294,8 +1294,12 @@ AccessibleWrap::GetChildIDFor(Accessible* aAccessible) // so that the 3rd party application can call back and get the IAccessible // the event occurred on. + if (!aAccessible) { + return 0; + } + #ifdef _WIN64 - if (!aAccessible || (!aAccessible->Document() && !aAccessible->IsProxy())) + if (!aAccessible->Document() && !aAccessible->IsProxy()) return 0; uint32_t* id = & static_cast(aAccessible)->mID; From 66b3673ccc82f0713c641fa5e89554d5e6291a25 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 29 Sep 2015 16:36:36 +0100 Subject: [PATCH 057/104] Bug 1209461 - Remove compilation warnings in nsFrameMessageManager, r=smaug --- dom/base/nsFrameMessageManager.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index 3af6e003723e..4c4086440b4f 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -1806,25 +1806,21 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript( if (!JS::Compile(cx, options, srcBuf, &script)) { return; } - } else { - // We're going to run these against some non-global scope. - if (!JS::CompileForNonSyntacticScope(cx, options, srcBuf, &script)) { - return; - } + // We're going to run these against some non-global scope. + } else if (!JS::CompileForNonSyntacticScope(cx, options, srcBuf, &script)) { + return; } + MOZ_ASSERT(script); aScriptp.set(script); nsAutoCString scheme; uri->GetScheme(scheme); // We don't cache data: scripts! if (aShouldCache && !scheme.EqualsLiteral("data")) { - nsMessageManagerScriptHolder* holder; - // Root the object also for caching. - if (script) { - holder = new nsMessageManagerScriptHolder(cx, script, aRunInGlobalScope); - } + nsMessageManagerScriptHolder* holder = + new nsMessageManagerScriptHolder(cx, script, aRunInGlobalScope); sCachedScripts->Put(aURL, holder); } } From 347e167d56c2191d3cdc5264ba765b6da9fbadb2 Mon Sep 17 00:00:00 2001 From: Michael Layzell Date: Mon, 28 Sep 2015 18:49:11 -0400 Subject: [PATCH 058/104] Bug 1209329 - Improve comments about about: URIs in nsContentUtils::InternalStorageAllowedForPrincipal, r=bholley --- dom/base/nsContentUtils.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 886169c32cdf..ee904a3e3eaf 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -8161,6 +8161,26 @@ nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal, // About URIs are allowed to access storage, even if they don't have chrome // privileges. If this is not desired, than the consumer will have to // implement their own restriction functionality. + // + // This is due to backwards-compatibility and the state of storage access before + // the introducton of nsContentUtils::InternalStorageAllowedForPrincipal: + // + // BEFORE: + // localStorage, caches: allowed in 3rd-party iframes always + // IndexedDB: allowed in 3rd-party iframes only if 3rd party URI is an about: + // URI within a specific whitelist + // + // AFTER: + // localStorage, caches: allowed in 3rd-party iframes by default. Preference + // can be set to disable in 3rd-party, which will not disallow in about: URIs. + // IndexedDB: allowed in 3rd-party iframes by default. Preference can be set to + // disable in 3rd-party, which will disallow in about: URIs, unless they are + // within a specific whitelist. + // + // This means that behavior for storage with internal about: URIs should not be + // affected, which is desireable due to the lack of automated testing for about: + // URIs with these preferences set, and the importance of the correct functioning + // of these URIs even with custom preferences. nsCOMPtr uri; nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri)); if (NS_SUCCEEDED(rv) && uri) { From 8631de9c2b9387fbec374928ccf6e8ee3e420506 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Tue, 29 Sep 2015 08:57:36 -0700 Subject: [PATCH 059/104] Backed out 13 changesets (bug 709490) for android webgl-color-test.html failures Backed out changeset 5be7514914b6 (bug 709490) Backed out changeset 04b6f94fbe8a (bug 709490) Backed out changeset 00c0e85dd8cd (bug 709490) Backed out changeset 221385b7b81a (bug 709490) Backed out changeset ecc38c18734f (bug 709490) Backed out changeset 22878c936384 (bug 709490) Backed out changeset 0edcbb60eee3 (bug 709490) Backed out changeset 5feceec2014b (bug 709490) Backed out changeset 835b655cb873 (bug 709490) Backed out changeset 6fbb4a3f8cf7 (bug 709490) Backed out changeset a5f8646fa156 (bug 709490) Backed out changeset 2ae1386916b3 (bug 709490) Backed out changeset 6b29a2a0a8fb (bug 709490) --- dom/base/ImageEncoder.cpp | 13 +- dom/base/ImageEncoder.h | 5 +- dom/base/StructuredCloneHelper.cpp | 50 -- dom/base/StructuredCloneTags.h | 3 - dom/canvas/CanvasRenderingContextHelper.cpp | 264 -------- dom/canvas/CanvasRenderingContextHelper.h | 71 -- dom/canvas/CanvasUtils.cpp | 35 - dom/canvas/CanvasUtils.h | 1 - dom/canvas/OffscreenCanvas.cpp | 242 ------- dom/canvas/OffscreenCanvas.h | 179 ----- dom/canvas/WebGLContext.cpp | 399 ++++++----- dom/canvas/WebGLContext.h | 43 +- dom/canvas/WebGLContextExtensions.cpp | 14 +- dom/canvas/WebGLContextGL.cpp | 5 +- dom/canvas/WebGLContextLossHandler.cpp | 119 ---- dom/canvas/WebGLContextLossHandler.h | 5 +- dom/canvas/WebGLContextReporter.cpp | 2 + dom/canvas/WebGLContextValidate.cpp | 19 +- dom/canvas/WebGLMemoryTracker.cpp | 2 + dom/canvas/WebGLShaderValidator.cpp | 3 +- dom/canvas/moz.build | 5 - .../nsICanvasRenderingContextInternal.h | 15 +- dom/canvas/test/mochitest.ini | 23 - dom/canvas/test/offscreencanvas.js | 299 --------- dom/canvas/test/offscreencanvas_mask.svg | 11 - dom/canvas/test/offscreencanvas_neuter.js | 1 - .../offscreencanvas_serviceworker_inner.html | 32 - .../test_offscreencanvas_basic_webgl.html | 62 -- ...test_offscreencanvas_dynamic_fallback.html | 80 --- .../test/test_offscreencanvas_many.html | 67 -- .../test/test_offscreencanvas_neuter.html | 78 --- .../test_offscreencanvas_serviceworker.html | 46 -- .../test_offscreencanvas_sharedworker.html | 47 -- .../test/test_offscreencanvas_sizechange.html | 41 -- .../test/test_offscreencanvas_subworker.html | 90 --- dom/html/HTMLCanvasElement.cpp | 631 +++++++----------- dom/html/HTMLCanvasElement.h | 93 +-- .../mochitest/general/test_interfaces.html | 2 - dom/webidl/HTMLCanvasElement.webidl | 7 - dom/webidl/OffscreenCanvas.webidl | 28 - dom/webidl/WebGLRenderingContext.webidl | 30 +- dom/webidl/moz.build | 1 - dom/workers/RuntimeService.cpp | 10 - dom/workers/WorkerPrivate.h | 7 - dom/workers/Workers.h | 1 - dom/workers/test/test_worker_interfaces.js | 22 - gfx/gl/GLContext.cpp | 23 - gfx/gl/GLLibraryEGL.cpp | 35 +- gfx/gl/GLLibraryEGL.h | 12 - gfx/gl/GLReadTexImageHelper.cpp | 52 +- gfx/gl/GLReadTexImageHelper.h | 21 +- gfx/gl/GLScreenBuffer.cpp | 69 +- gfx/gl/GLScreenBuffer.h | 7 - gfx/gl/SharedSurface.cpp | 6 +- gfx/gl/SharedSurface.h | 7 - gfx/gl/SharedSurfaceANGLE.cpp | 132 ---- gfx/gl/SharedSurfaceANGLE.h | 2 - gfx/gl/SharedSurfaceEGL.cpp | 9 +- gfx/gl/SharedSurfaceEGL.h | 2 - gfx/gl/SharedSurfaceGLX.cpp | 33 - gfx/gl/SharedSurfaceGLX.h | 2 - gfx/gl/SharedSurfaceGralloc.cpp | 53 -- gfx/gl/SharedSurfaceGralloc.h | 2 - gfx/gl/SharedSurfaceIO.cpp | 25 - gfx/gl/SharedSurfaceIO.h | 2 - gfx/layers/AsyncCanvasRenderer.cpp | 279 -------- gfx/layers/AsyncCanvasRenderer.h | 169 ----- gfx/layers/CopyableCanvasLayer.cpp | 9 +- gfx/layers/LayerTreeInvalidation.cpp | 31 +- gfx/layers/Layers.cpp | 14 - gfx/layers/Layers.h | 22 +- gfx/layers/basic/BasicCanvasLayer.cpp | 1 - gfx/layers/client/CanvasClient.cpp | 94 +-- gfx/layers/client/CanvasClient.h | 67 +- gfx/layers/client/ClientCanvasLayer.cpp | 86 ++- gfx/layers/client/ClientCanvasLayer.h | 1 + gfx/layers/client/TextureClient.cpp | 1 - gfx/layers/ipc/ImageBridgeChild.cpp | 135 +--- gfx/layers/ipc/ImageBridgeChild.h | 10 - gfx/layers/ipc/PImageBridge.ipdl | 2 +- gfx/layers/moz.build | 2 - gfx/src/gfxCrashReporterUtils.cpp | 19 +- gfx/thebes/gfxPrefs.h | 26 +- gfx/thebes/gfxUtils.cpp | 123 ---- gfx/thebes/gfxUtils.h | 17 - gfx/thebes/moz.build | 1 - js/public/StructuredClone.h | 9 +- js/src/vm/StructuredClone.cpp | 26 +- modules/libpref/init/all.js | 2 - 89 files changed, 705 insertions(+), 4138 deletions(-) delete mode 100644 dom/canvas/CanvasRenderingContextHelper.cpp delete mode 100644 dom/canvas/CanvasRenderingContextHelper.h delete mode 100644 dom/canvas/OffscreenCanvas.cpp delete mode 100644 dom/canvas/OffscreenCanvas.h delete mode 100644 dom/canvas/test/offscreencanvas.js delete mode 100644 dom/canvas/test/offscreencanvas_mask.svg delete mode 100644 dom/canvas/test/offscreencanvas_neuter.js delete mode 100644 dom/canvas/test/offscreencanvas_serviceworker_inner.html delete mode 100644 dom/canvas/test/test_offscreencanvas_basic_webgl.html delete mode 100644 dom/canvas/test/test_offscreencanvas_dynamic_fallback.html delete mode 100644 dom/canvas/test/test_offscreencanvas_many.html delete mode 100644 dom/canvas/test/test_offscreencanvas_neuter.html delete mode 100644 dom/canvas/test/test_offscreencanvas_serviceworker.html delete mode 100644 dom/canvas/test/test_offscreencanvas_sharedworker.html delete mode 100644 dom/canvas/test/test_offscreencanvas_sizechange.html delete mode 100644 dom/canvas/test/test_offscreencanvas_subworker.html delete mode 100644 dom/webidl/OffscreenCanvas.webidl delete mode 100644 gfx/layers/AsyncCanvasRenderer.cpp delete mode 100644 gfx/layers/AsyncCanvasRenderer.h diff --git a/dom/base/ImageEncoder.cpp b/dom/base/ImageEncoder.cpp index 74dff8734e46..366d26ef117d 100644 --- a/dom/base/ImageEncoder.cpp +++ b/dom/base/ImageEncoder.cpp @@ -8,7 +8,6 @@ #include "mozilla/dom/CanvasRenderingContext2D.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/DataSurfaceHelpers.h" -#include "mozilla/layers/AsyncCanvasRenderer.h" #include "mozilla/RefPtr.h" #include "mozilla/SyncRunnable.h" #include "mozilla/unused.h" @@ -166,7 +165,6 @@ public: mSize, mImage, nullptr, - nullptr, getter_AddRefs(stream), mEncoder); @@ -180,7 +178,6 @@ public: mSize, mImage, nullptr, - nullptr, getter_AddRefs(stream), mEncoder); } @@ -237,7 +234,6 @@ ImageEncoder::ExtractData(nsAString& aType, const nsAString& aOptions, const nsIntSize aSize, nsICanvasRenderingContextInternal* aContext, - layers::AsyncCanvasRenderer* aRenderer, nsIInputStream** aStream) { nsCOMPtr encoder = ImageEncoder::GetImageEncoder(aType); @@ -246,9 +242,10 @@ ImageEncoder::ExtractData(nsAString& aType, } return ExtractDataInternal(aType, aOptions, nullptr, 0, aSize, nullptr, - aContext, aRenderer, aStream, encoder); + aContext, aStream, encoder); } + /* static */ nsresult ImageEncoder::ExtractDataFromLayersImageAsync(nsAString& aType, @@ -344,7 +341,6 @@ ImageEncoder::ExtractDataInternal(const nsAString& aType, const nsIntSize aSize, layers::Image* aImage, nsICanvasRenderingContextInternal* aContext, - layers::AsyncCanvasRenderer* aRenderer, nsIInputStream** aStream, imgIEncoder* aEncoder) { @@ -370,11 +366,6 @@ ImageEncoder::ExtractDataInternal(const nsAString& aType, rv = aContext->GetInputStream(encoderType.get(), nsPromiseFlatString(aOptions).get(), getter_AddRefs(imgStream)); - } else if (aRenderer) { - NS_ConvertUTF16toUTF8 encoderType(aType); - rv = aRenderer->GetInputStream(encoderType.get(), - nsPromiseFlatString(aOptions).get(), - getter_AddRefs(imgStream)); } else if (aImage) { // It is safe to convert PlanarYCbCr format from YUV to RGB off-main-thread. // Other image formats could have problem to convert format off-main-thread. diff --git a/dom/base/ImageEncoder.h b/dom/base/ImageEncoder.h index a38bbd209140..fe3522daff55 100644 --- a/dom/base/ImageEncoder.h +++ b/dom/base/ImageEncoder.h @@ -19,7 +19,6 @@ class nsICanvasRenderingContextInternal; namespace mozilla { namespace layers { -class AsyncCanvasRenderer; class Image; } // namespace layers @@ -41,7 +40,6 @@ public: const nsAString& aOptions, const nsIntSize aSize, nsICanvasRenderingContextInternal* aContext, - layers::AsyncCanvasRenderer* aRenderer, nsIInputStream** aStream); // Extracts data asynchronously. aType may change to "image/png" if we had to @@ -86,7 +84,7 @@ public: nsIInputStream** aStream); private: - // When called asynchronously, aContext and aRenderer are null. + // When called asynchronously, aContext is null. static nsresult ExtractDataInternal(const nsAString& aType, const nsAString& aOptions, @@ -95,7 +93,6 @@ private: const nsIntSize aSize, layers::Image* aImage, nsICanvasRenderingContextInternal* aContext, - layers::AsyncCanvasRenderer* aRenderer, nsIInputStream** aStream, imgIEncoder* aEncoder); diff --git a/dom/base/StructuredCloneHelper.cpp b/dom/base/StructuredCloneHelper.cpp index baad651b0a01..7975e42e1bdc 100644 --- a/dom/base/StructuredCloneHelper.cpp +++ b/dom/base/StructuredCloneHelper.cpp @@ -21,8 +21,6 @@ #include "mozilla/dom/StructuredClone.h" #include "mozilla/dom/MessagePort.h" #include "mozilla/dom/MessagePortBinding.h" -#include "mozilla/dom/OffscreenCanvas.h" -#include "mozilla/dom/OffscreenCanvasBinding.h" #include "mozilla/dom/PMessagePort.h" #include "mozilla/dom/StructuredCloneTags.h" #include "mozilla/dom/SubtleCryptoBinding.h" @@ -1064,25 +1062,6 @@ StructuredCloneHelper::ReadTransferCallback(JSContext* aCx, return true; } - if (aTag == SCTAG_DOM_CANVAS) { - MOZ_ASSERT(mContext == SameProcessSameThread || - mContext == SameProcessDifferentThread); - MOZ_ASSERT(aContent); - OffscreenCanvasCloneData* data = - static_cast(aContent); - nsRefPtr canvas = OffscreenCanvas::CreateFromCloneData(data); - delete data; - - JS::Rooted value(aCx); - if (!GetOrCreateDOMReflector(aCx, canvas, &value)) { - JS_ClearPendingException(aCx); - return false; - } - - aReturnObject.set(&value.toObject()); - return true; - } - return false; } @@ -1114,24 +1093,6 @@ StructuredCloneHelper::WriteTransferCallback(JSContext* aCx, return true; } - - if (mContext == SameProcessSameThread || - mContext == SameProcessDifferentThread) { - OffscreenCanvas* canvas = nullptr; - rv = UNWRAP_OBJECT(OffscreenCanvas, aObj, canvas); - if (NS_SUCCEEDED(rv)) { - MOZ_ASSERT(canvas); - - *aExtraData = 0; - *aTag = SCTAG_DOM_CANVAS; - *aOwnership = JS::SCTAG_TMO_CUSTOM; - *aContent = canvas->ToCloneData(); - MOZ_ASSERT(*aContent); - canvas->SetNeutered(); - - return true; - } - } } return false; @@ -1149,17 +1110,6 @@ StructuredCloneHelper::FreeTransferCallback(uint32_t aTag, MOZ_ASSERT(!aContent); MOZ_ASSERT(aExtraData < mPortIdentifiers.Length()); MessagePort::ForceClose(mPortIdentifiers[aExtraData]); - return; - } - - if (aTag == SCTAG_DOM_CANVAS) { - MOZ_ASSERT(mContext == SameProcessSameThread || - mContext == SameProcessDifferentThread); - MOZ_ASSERT(aContent); - OffscreenCanvasCloneData* data = - static_cast(aContent); - delete data; - return; } } diff --git a/dom/base/StructuredCloneTags.h b/dom/base/StructuredCloneTags.h index f1fec533d4d6..fe6ccdf371f7 100644 --- a/dom/base/StructuredCloneTags.h +++ b/dom/base/StructuredCloneTags.h @@ -48,9 +48,6 @@ enum StructuredCloneTags { SCTAG_DOM_FORMDATA, - // This tag is for OffscreenCanvas. - SCTAG_DOM_CANVAS, - SCTAG_DOM_MAX }; diff --git a/dom/canvas/CanvasRenderingContextHelper.cpp b/dom/canvas/CanvasRenderingContextHelper.cpp deleted file mode 100644 index 0c498b7d525b..000000000000 --- a/dom/canvas/CanvasRenderingContextHelper.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "CanvasRenderingContextHelper.h" -#include "ImageEncoder.h" -#include "mozilla/dom/CanvasRenderingContext2D.h" -#include "mozilla/Telemetry.h" -#include "nsContentUtils.h" -#include "nsDOMJSUtils.h" -#include "nsIScriptContext.h" -#include "nsJSUtils.h" -#include "WebGL1Context.h" -#include "WebGL2Context.h" - -namespace mozilla { -namespace dom { - -void -CanvasRenderingContextHelper::ToBlob(JSContext* aCx, - nsIGlobalObject* aGlobal, - FileCallback& aCallback, - const nsAString& aType, - JS::Handle aParams, - ErrorResult& aRv) -{ - nsAutoString type; - nsContentUtils::ASCIIToLower(aType, type); - - nsAutoString params; - bool usingCustomParseOptions; - aRv = ParseParams(aCx, type, aParams, params, &usingCustomParseOptions); - if (aRv.Failed()) { - return; - } - -#ifdef DEBUG - if (mCurrentContext) { - // We disallow canvases of width or height zero, and set them to 1, so - // we will have a discrepancy with the sizes of the canvas and the context. - // That discrepancy is OK, the rest are not. - nsIntSize elementSize = GetWidthHeight(); - MOZ_ASSERT(elementSize.width == mCurrentContext->GetWidth() || - (elementSize.width == 0 && mCurrentContext->GetWidth() == 1)); - MOZ_ASSERT(elementSize.height == mCurrentContext->GetHeight() || - (elementSize.height == 0 && mCurrentContext->GetHeight() == 1)); - } -#endif - - uint8_t* imageBuffer = nullptr; - int32_t format = 0; - if (mCurrentContext) { - mCurrentContext->GetImageBuffer(&imageBuffer, &format); - } - - // Encoder callback when encoding is complete. - class EncodeCallback : public EncodeCompleteCallback - { - public: - EncodeCallback(nsIGlobalObject* aGlobal, FileCallback* aCallback) - : mGlobal(aGlobal) - , mFileCallback(aCallback) {} - - // This is called on main thread. - nsresult ReceiveBlob(already_AddRefed aBlob) - { - nsRefPtr blob = aBlob; - - ErrorResult rv; - uint64_t size = blob->GetSize(rv); - if (rv.Failed()) { - rv.SuppressException(); - } else { - AutoJSAPI jsapi; - if (jsapi.Init(mGlobal)) { - JS_updateMallocCounter(jsapi.cx(), size); - } - } - - nsRefPtr newBlob = Blob::Create(mGlobal, blob->Impl()); - - mFileCallback->Call(*newBlob, rv); - - mGlobal = nullptr; - mFileCallback = nullptr; - - return rv.StealNSResult(); - } - - nsCOMPtr mGlobal; - nsRefPtr mFileCallback; - }; - - nsRefPtr callback = - new EncodeCallback(aGlobal, &aCallback); - - aRv = ImageEncoder::ExtractDataAsync(type, - params, - usingCustomParseOptions, - imageBuffer, - format, - GetWidthHeight(), - callback); -} - -already_AddRefed -CanvasRenderingContextHelper::CreateContext(CanvasContextType aContextType) -{ - MOZ_ASSERT(aContextType != CanvasContextType::NoContext); - nsRefPtr ret; - - switch (aContextType) { - case CanvasContextType::NoContext: - break; - - case CanvasContextType::Canvas2D: - Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1); - ret = new CanvasRenderingContext2D(); - break; - - case CanvasContextType::WebGL1: - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1); - - ret = WebGL1Context::Create(); - if (!ret) - return nullptr; - - break; - - case CanvasContextType::WebGL2: - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1); - - ret = WebGL2Context::Create(); - if (!ret) - return nullptr; - - break; - } - MOZ_ASSERT(ret); - - return ret.forget(); -} - -already_AddRefed -CanvasRenderingContextHelper::GetContext(JSContext* aCx, - const nsAString& aContextId, - JS::Handle aContextOptions, - ErrorResult& aRv) -{ - CanvasContextType contextType; - if (!CanvasUtils::GetCanvasContextType(aContextId, &contextType)) - return nullptr; - - if (!mCurrentContext) { - // This canvas doesn't have a context yet. - nsRefPtr context; - context = CreateContext(contextType); - if (!context) { - return nullptr; - } - - // Ensure that the context participates in CC. Note that returning a - // CC participant from QI doesn't addref. - nsXPCOMCycleCollectionParticipant* cp = nullptr; - CallQueryInterface(context, &cp); - if (!cp) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - mCurrentContext = context.forget(); - mCurrentContextType = contextType; - - aRv = UpdateContext(aCx, aContextOptions); - if (aRv.Failed()) { - aRv = NS_OK; // See bug 645792 - return nullptr; - } - } else { - // We already have a context of some type. - if (contextType != mCurrentContextType) - return nullptr; - } - - nsCOMPtr context = mCurrentContext; - return context.forget(); -} - -nsresult -CanvasRenderingContextHelper::UpdateContext(JSContext* aCx, - JS::Handle aNewContextOptions) -{ - if (!mCurrentContext) - return NS_OK; - - nsIntSize sz = GetWidthHeight(); - - nsCOMPtr currentContext = mCurrentContext; - - nsresult rv = currentContext->SetIsOpaque(GetOpaqueAttr()); - if (NS_FAILED(rv)) { - mCurrentContext = nullptr; - return rv; - } - - rv = currentContext->SetContextOptions(aCx, aNewContextOptions); - if (NS_FAILED(rv)) { - mCurrentContext = nullptr; - return rv; - } - - rv = currentContext->SetDimensions(sz.width, sz.height); - if (NS_FAILED(rv)) { - mCurrentContext = nullptr; - } - - return rv; -} - -nsresult -CanvasRenderingContextHelper::ParseParams(JSContext* aCx, - const nsAString& aType, - const JS::Value& aEncoderOptions, - nsAString& outParams, - bool* const outUsingCustomParseOptions) -{ - // Quality parameter is only valid for the image/jpeg MIME type - if (aType.EqualsLiteral("image/jpeg")) { - if (aEncoderOptions.isNumber()) { - double quality = aEncoderOptions.toNumber(); - // Quality must be between 0.0 and 1.0, inclusive - if (quality >= 0.0 && quality <= 1.0) { - outParams.AppendLiteral("quality="); - outParams.AppendInt(NS_lround(quality * 100.0)); - } - } - } - - // If we haven't parsed the aParams check for proprietary options. - // The proprietary option -moz-parse-options will take a image lib encoder - // parse options string as is and pass it to the encoder. - *outUsingCustomParseOptions = false; - if (outParams.Length() == 0 && aEncoderOptions.isString()) { - NS_NAMED_LITERAL_STRING(mozParseOptions, "-moz-parse-options:"); - nsAutoJSString paramString; - if (!paramString.init(aCx, aEncoderOptions.toString())) { - return NS_ERROR_FAILURE; - } - if (StringBeginsWith(paramString, mozParseOptions)) { - nsDependentSubstring parseOptions = Substring(paramString, - mozParseOptions.Length(), - paramString.Length() - - mozParseOptions.Length()); - outParams.Append(parseOptions); - *outUsingCustomParseOptions = true; - } - } - - return NS_OK; -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/canvas/CanvasRenderingContextHelper.h b/dom/canvas/CanvasRenderingContextHelper.h deleted file mode 100644 index 89cf9e8b3cc8..000000000000 --- a/dom/canvas/CanvasRenderingContextHelper.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_ -#define MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_ - -#include "mozilla/dom/BindingDeclarations.h" -#include "nsSize.h" - -class nsICanvasRenderingContextInternal; -class nsIGlobalObject; - -namespace mozilla { - -class ErrorResult; - -namespace dom { - -class FileCallback; - -enum class CanvasContextType : uint8_t { - NoContext, - Canvas2D, - WebGL1, - WebGL2 -}; - -/** - * Povides common RenderingContext functionality used by both OffscreenCanvas - * and HTMLCanvasElement. - */ -class CanvasRenderingContextHelper -{ -public: - virtual already_AddRefed - GetContext(JSContext* aCx, - const nsAString& aContextId, - JS::Handle aContextOptions, - ErrorResult& aRv); - - virtual bool GetOpaqueAttr() = 0; - -protected: - virtual nsresult UpdateContext(JSContext* aCx, - JS::Handle aNewContextOptions); - - virtual nsresult ParseParams(JSContext* aCx, - const nsAString& aType, - const JS::Value& aEncoderOptions, - nsAString& outParams, - bool* const outCustomParseOptions); - - void ToBlob(JSContext* aCx, nsIGlobalObject* global, FileCallback& aCallback, - const nsAString& aType, JS::Handle aParams, - ErrorResult& aRv); - - virtual already_AddRefed - CreateContext(CanvasContextType aContextType); - - virtual nsIntSize GetWidthHeight() = 0; - - CanvasContextType mCurrentContextType; - nsCOMPtr mCurrentContext; -}; - -} // namespace dom -} // namespace mozilla - -#endif // MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_ diff --git a/dom/canvas/CanvasUtils.cpp b/dom/canvas/CanvasUtils.cpp index 9d258c01f706..04fec40e8c60 100644 --- a/dom/canvas/CanvasUtils.cpp +++ b/dom/canvas/CanvasUtils.cpp @@ -23,47 +23,12 @@ #include "CanvasUtils.h" #include "mozilla/gfx/Matrix.h" -#include "WebGL2Context.h" using namespace mozilla::gfx; namespace mozilla { namespace CanvasUtils { -bool -GetCanvasContextType(const nsAString& str, dom::CanvasContextType* const out_type) -{ - if (str.EqualsLiteral("2d")) { - *out_type = dom::CanvasContextType::Canvas2D; - return true; - } - - if (str.EqualsLiteral("experimental-webgl")) { - *out_type = dom::CanvasContextType::WebGL1; - return true; - } - -#ifdef MOZ_WEBGL_CONFORMANT - if (str.EqualsLiteral("webgl")) { - /* WebGL 1.0, $2.1 "Context Creation": - * If the user agent supports both the webgl and experimental-webgl - * canvas context types, they shall be treated as aliases. - */ - *out_type = dom::CanvasContextType::WebGL1; - return true; - } -#endif - - if (WebGL2Context::IsSupported()) { - if (str.EqualsLiteral("webgl2")) { - *out_type = dom::CanvasContextType::WebGL2; - return true; - } - } - - return false; -} - /** * This security check utility might be called from an source that never taints * others. For example, while painting a CanvasPattern, which is created from an diff --git a/dom/canvas/CanvasUtils.h b/dom/canvas/CanvasUtils.h index b1237b69e6ff..044b847053e9 100644 --- a/dom/canvas/CanvasUtils.h +++ b/dom/canvas/CanvasUtils.h @@ -21,7 +21,6 @@ class HTMLCanvasElement; namespace CanvasUtils { -bool GetCanvasContextType(const nsAString& str, dom::CanvasContextType* const out_type); // Check that the rectangle [x,y,w,h] is a subrectangle of [0,0,realWidth,realHeight] diff --git a/dom/canvas/OffscreenCanvas.cpp b/dom/canvas/OffscreenCanvas.cpp deleted file mode 100644 index a0144823d81a..000000000000 --- a/dom/canvas/OffscreenCanvas.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "OffscreenCanvas.h" - -#include "mozilla/dom/OffscreenCanvasBinding.h" -#include "mozilla/dom/WorkerPrivate.h" -#include "mozilla/layers/AsyncCanvasRenderer.h" -#include "mozilla/layers/CanvasClient.h" -#include "mozilla/layers/ImageBridgeChild.h" -#include "mozilla/Telemetry.h" -#include "CanvasRenderingContext2D.h" -#include "CanvasUtils.h" -#include "GLScreenBuffer.h" -#include "WebGL1Context.h" -#include "WebGL2Context.h" - -namespace mozilla { -namespace dom { - -OffscreenCanvasCloneData::OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer, - uint32_t aWidth, uint32_t aHeight, - layers::LayersBackend aCompositorBackend, - bool aNeutered) - : mRenderer(aRenderer) - , mWidth(aWidth) - , mHeight(aHeight) - , mCompositorBackendType(aCompositorBackend) - , mNeutered(aNeutered) -{ -} - -OffscreenCanvasCloneData::~OffscreenCanvasCloneData() -{ -} - -OffscreenCanvas::OffscreenCanvas(uint32_t aWidth, - uint32_t aHeight, - layers::LayersBackend aCompositorBackend, - layers::AsyncCanvasRenderer* aRenderer) - : mAttrDirty(false) - , mNeutered(false) - , mWidth(aWidth) - , mHeight(aHeight) - , mCompositorBackendType(aCompositorBackend) - , mCanvasClient(nullptr) - , mCanvasRenderer(aRenderer) -{} - -OffscreenCanvas::~OffscreenCanvas() -{ - ClearResources(); -} - -OffscreenCanvas* -OffscreenCanvas::GetParentObject() const -{ - return nullptr; -} - -JSObject* -OffscreenCanvas::WrapObject(JSContext* aCx, - JS::Handle aGivenProto) -{ - return OffscreenCanvasBinding::Wrap(aCx, this, aGivenProto); -} - -void -OffscreenCanvas::ClearResources() -{ - if (mCanvasClient) { - mCanvasClient->Clear(); - ImageBridgeChild::DispatchReleaseCanvasClient(mCanvasClient); - mCanvasClient = nullptr; - - if (mCanvasRenderer) { - nsCOMPtr activeThread = mCanvasRenderer->GetActiveThread(); - MOZ_RELEASE_ASSERT(activeThread); - MOZ_RELEASE_ASSERT(activeThread == NS_GetCurrentThread()); - mCanvasRenderer->SetCanvasClient(nullptr); - mCanvasRenderer->mContext = nullptr; - mCanvasRenderer->mGLContext = nullptr; - mCanvasRenderer->ResetActiveThread(); - } - } -} - -already_AddRefed -OffscreenCanvas::GetContext(JSContext* aCx, - const nsAString& aContextId, - JS::Handle aContextOptions, - ErrorResult& aRv) -{ - if (mNeutered) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - // We only support WebGL in workers for now - CanvasContextType contextType; - if (!CanvasUtils::GetCanvasContextType(aContextId, &contextType)) { - aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); - return nullptr; - } - - if (!(contextType == CanvasContextType::WebGL1 || - contextType == CanvasContextType::WebGL2)) - { - aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); - return nullptr; - } - - already_AddRefed result = - CanvasRenderingContextHelper::GetContext(aCx, - aContextId, - aContextOptions, - aRv); - - if (!mCurrentContext) { - return nullptr; - } - - if (mCanvasRenderer) { - WebGLContext* webGL = static_cast(mCurrentContext.get()); - gl::GLContext* gl = webGL->GL(); - mCanvasRenderer->mContext = mCurrentContext; - mCanvasRenderer->SetActiveThread(); - mCanvasRenderer->mGLContext = gl; - mCanvasRenderer->SetIsAlphaPremultiplied(webGL->IsPremultAlpha() || !gl->Caps().alpha); - - if (ImageBridgeChild::IsCreated()) { - TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT; - mCanvasClient = ImageBridgeChild::GetSingleton()-> - CreateCanvasClient(CanvasClient::CanvasClientTypeShSurf, flags).take(); - mCanvasRenderer->SetCanvasClient(mCanvasClient); - - gl::GLScreenBuffer* screen = gl->Screen(); - gl::SurfaceCaps caps = screen->mCaps; - auto forwarder = mCanvasClient->GetForwarder(); - - UniquePtr factory = - gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags); - - if (factory) - screen->Morph(Move(factory)); - } - } - - return result; -} - -already_AddRefed -OffscreenCanvas::CreateContext(CanvasContextType aContextType) -{ - nsRefPtr ret = - CanvasRenderingContextHelper::CreateContext(aContextType); - - ret->SetOffscreenCanvas(this); - return ret.forget(); -} - -void -OffscreenCanvas::CommitFrameToCompositor() -{ - // The attributes has changed, we have to notify main - // thread to change canvas size. - if (mAttrDirty) { - if (mCanvasRenderer) { - mCanvasRenderer->SetWidth(mWidth); - mCanvasRenderer->SetHeight(mHeight); - mCanvasRenderer->NotifyElementAboutAttributesChanged(); - } - mAttrDirty = false; - } - - if (mCurrentContext) { - static_cast(mCurrentContext.get())->PresentScreenBuffer(); - } - - if (mCanvasRenderer && mCanvasRenderer->mGLContext) { - mCanvasRenderer->NotifyElementAboutInvalidation(); - ImageBridgeChild::GetSingleton()-> - UpdateAsyncCanvasRenderer(mCanvasRenderer); - } -} - -OffscreenCanvasCloneData* -OffscreenCanvas::ToCloneData() -{ - return new OffscreenCanvasCloneData(mCanvasRenderer, mWidth, mHeight, - mCompositorBackendType, mNeutered); -} - -/* static */ already_AddRefed -OffscreenCanvas::CreateFromCloneData(OffscreenCanvasCloneData* aData) -{ - MOZ_ASSERT(aData); - nsRefPtr wc = - new OffscreenCanvas(aData->mWidth, aData->mHeight, - aData->mCompositorBackendType, aData->mRenderer); - if (aData->mNeutered) { - wc->SetNeutered(); - } - return wc.forget(); -} - -/* static */ bool -OffscreenCanvas::PrefEnabled(JSContext* aCx, JSObject* aObj) -{ - if (NS_IsMainThread()) { - return Preferences::GetBool("gfx.offscreencanvas.enabled"); - } else { - WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); - MOZ_ASSERT(workerPrivate); - return workerPrivate->OffscreenCanvasEnabled(); - } -} - -/* static */ bool -OffscreenCanvas::PrefEnabledOnWorkerThread(JSContext* aCx, JSObject* aObj) -{ - if (NS_IsMainThread()) { - return true; - } - - return PrefEnabled(aCx, aObj); -} - -NS_IMPL_CYCLE_COLLECTION_INHERITED(OffscreenCanvas, DOMEventTargetHelper, mCurrentContext) - -NS_IMPL_ADDREF_INHERITED(OffscreenCanvas, DOMEventTargetHelper) -NS_IMPL_RELEASE_INHERITED(OffscreenCanvas, DOMEventTargetHelper) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(OffscreenCanvas) - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) - -} // namespace dom -} // namespace mozilla diff --git a/dom/canvas/OffscreenCanvas.h b/dom/canvas/OffscreenCanvas.h deleted file mode 100644 index cdad6bcce8e7..000000000000 --- a/dom/canvas/OffscreenCanvas.h +++ /dev/null @@ -1,179 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MOZILLA_DOM_OFFSCREENCANVAS_H_ -#define MOZILLA_DOM_OFFSCREENCANVAS_H_ - -#include "mozilla/DOMEventTargetHelper.h" -#include "mozilla/layers/LayersTypes.h" -#include "mozilla/RefPtr.h" -#include "CanvasRenderingContextHelper.h" -#include "nsCycleCollectionParticipant.h" - -struct JSContext; - -namespace mozilla { - -class ErrorResult; - -namespace layers { -class AsyncCanvasRenderer; -class CanvasClient; -} // namespace layers - -namespace dom { - -// This is helper class for transferring OffscreenCanvas to worker thread. -// Because OffscreenCanvas is not thread-safe. So we cannot pass Offscreen- -// Canvas to worker thread directly. Thus, we create this helper class and -// store necessary data in it then pass it to worker thread. -struct OffscreenCanvasCloneData final -{ - OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer, - uint32_t aWidth, uint32_t aHeight, - layers::LayersBackend aCompositorBackend, - bool aNeutered); - ~OffscreenCanvasCloneData(); - - RefPtr mRenderer; - uint32_t mWidth; - uint32_t mHeight; - layers::LayersBackend mCompositorBackendType; - bool mNeutered; -}; - -class OffscreenCanvas final : public DOMEventTargetHelper - , public CanvasRenderingContextHelper -{ -public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(OffscreenCanvas, DOMEventTargetHelper) - - OffscreenCanvas(uint32_t aWidth, - uint32_t aHeight, - layers::LayersBackend aCompositorBackend, - layers::AsyncCanvasRenderer* aRenderer); - - OffscreenCanvas* GetParentObject() const; - - virtual JSObject* WrapObject(JSContext* aCx, - JS::Handle aGivenProto) override; - - void ClearResources(); - - uint32_t Width() const - { - return mWidth; - } - - uint32_t Height() const - { - return mHeight; - } - - void SetWidth(uint32_t aWidth, ErrorResult& aRv) - { - if (mNeutered) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - if (mWidth != aWidth) { - mWidth = aWidth; - CanvasAttrChanged(); - } - } - - void SetHeight(uint32_t aHeight, ErrorResult& aRv) - { - if (mNeutered) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - if (mHeight != aHeight) { - mHeight = aHeight; - CanvasAttrChanged(); - } - } - - nsICanvasRenderingContextInternal* GetContext() const - { - return mCurrentContext; - } - - static already_AddRefed - CreateFromCloneData(OffscreenCanvasCloneData* aData); - - static bool PrefEnabled(JSContext* aCx, JSObject* aObj); - - // Return true on main-thread, and return gfx.offscreencanvas.enabled - // on worker thread. - static bool PrefEnabledOnWorkerThread(JSContext* aCx, JSObject* aObj); - - OffscreenCanvasCloneData* ToCloneData(); - - void CommitFrameToCompositor(); - - virtual bool GetOpaqueAttr() override - { - return false; - } - - virtual nsIntSize GetWidthHeight() override - { - return nsIntSize(mWidth, mHeight); - } - - virtual already_AddRefed - CreateContext(CanvasContextType aContextType) override; - - virtual already_AddRefed - GetContext(JSContext* aCx, - const nsAString& aContextId, - JS::Handle aContextOptions, - ErrorResult& aRv) override; - - void SetNeutered() - { - mNeutered = true; - } - - bool IsNeutered() const - { - return mNeutered; - } - - layers::LayersBackend GetCompositorBackendType() const - { - return mCompositorBackendType; - } - -private: - ~OffscreenCanvas(); - - void CanvasAttrChanged() - { - mAttrDirty = true; - UpdateContext(nullptr, JS::NullHandleValue); - } - - bool mAttrDirty; - bool mNeutered; - - uint32_t mWidth; - uint32_t mHeight; - - layers::LayersBackend mCompositorBackendType; - - layers::CanvasClient* mCanvasClient; - RefPtr mCanvasRenderer; -}; - -} // namespace dom -} // namespace mozilla - -#endif // MOZILLA_DOM_OFFSCREENCANVAS_H_ diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 82cfe5be87d5..f86094c60b20 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -22,7 +22,6 @@ #include "ImageEncoder.h" #include "Layers.h" #include "mozilla/dom/BindingUtils.h" -#include "mozilla/dom/Event.h" #include "mozilla/dom/HTMLVideoElement.h" #include "mozilla/dom/ImageData.h" #include "mozilla/EnumeratedArrayCycleCollection.h" @@ -80,6 +79,125 @@ using namespace mozilla::gfx; using namespace mozilla::gl; using namespace mozilla::layers; +WebGLObserver::WebGLObserver(WebGLContext* webgl) + : mWebGL(webgl) +{ +} + +WebGLObserver::~WebGLObserver() +{ +} + +void +WebGLObserver::Destroy() +{ + UnregisterMemoryPressureEvent(); + UnregisterVisibilityChangeEvent(); + mWebGL = nullptr; +} + +void +WebGLObserver::RegisterVisibilityChangeEvent() +{ + if (!mWebGL) + return; + + HTMLCanvasElement* canvas = mWebGL->GetCanvas(); + MOZ_ASSERT(canvas); + + if (canvas) { + nsIDocument* document = canvas->OwnerDoc(); + + document->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), + this, true, false); + } +} + +void +WebGLObserver::UnregisterVisibilityChangeEvent() +{ + if (!mWebGL) + return; + + HTMLCanvasElement* canvas = mWebGL->GetCanvas(); + + if (canvas) { + nsIDocument* document = canvas->OwnerDoc(); + + document->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"), + this, true); + } +} + +void +WebGLObserver::RegisterMemoryPressureEvent() +{ + if (!mWebGL) + return; + + nsCOMPtr observerService = + mozilla::services::GetObserverService(); + + MOZ_ASSERT(observerService); + + if (observerService) + observerService->AddObserver(this, "memory-pressure", false); +} + +void +WebGLObserver::UnregisterMemoryPressureEvent() +{ + if (!mWebGL) + return; + + nsCOMPtr observerService = + mozilla::services::GetObserverService(); + + // Do not assert on observerService here. This might be triggered by + // the cycle collector at a late enough time, that XPCOM services are + // no longer available. See bug 1029504. + if (observerService) + observerService->RemoveObserver(this, "memory-pressure"); +} + +NS_IMETHODIMP +WebGLObserver::Observe(nsISupports*, const char* topic, const char16_t*) +{ + if (!mWebGL || strcmp(topic, "memory-pressure")) { + return NS_OK; + } + + bool wantToLoseContext = mWebGL->mLoseContextOnMemoryPressure; + + if (!mWebGL->mCanLoseContextInForeground && + ProcessPriorityManager::CurrentProcessIsForeground()) + { + wantToLoseContext = false; + } + + if (wantToLoseContext) + mWebGL->ForceLoseContext(); + + return NS_OK; +} + +NS_IMETHODIMP +WebGLObserver::HandleEvent(nsIDOMEvent* event) +{ + nsAutoString type; + event->GetType(type); + if (!mWebGL || !type.EqualsLiteral("visibilitychange")) + return NS_OK; + + HTMLCanvasElement* canvas = mWebGL->GetCanvas(); + MOZ_ASSERT(canvas); + + if (canvas && !canvas->OwnerDoc()->Hidden()) + mWebGL->ForceRestoreContext(); + + return NS_OK; +} + WebGLContextOptions::WebGLContextOptions() : alpha(true) , depth(true) @@ -90,7 +208,7 @@ WebGLContextOptions::WebGLContextOptions() , failIfMajorPerformanceCaveat(false) { // Set default alpha state based on preference. - if (gfxPrefs::WebGLDefaultNoAlpha()) + if (Preferences::GetBool("webgl.default-no-alpha", false)) alpha = false; } @@ -164,10 +282,7 @@ WebGLContext::WebGLContext() mPixelStorePackAlignment = 4; mPixelStoreUnpackAlignment = 4; - if (NS_IsMainThread()) { - // XXX mtseng: bug 709490, not thread safe - WebGLMemoryTracker::AddWebGLContext(this); - } + WebGLMemoryTracker::AddWebGLContext(this); mAllowContextRestore = true; mLastLossWasSimulated = false; @@ -181,12 +296,15 @@ WebGLContext::WebGLContext() mAlreadyWarnedAboutFakeVertexAttrib0 = false; mAlreadyWarnedAboutViewportLargerThanDest = false; - mMaxWarnings = gfxPrefs::WebGLMaxWarningsPerContext(); + mMaxWarnings = Preferences::GetInt("webgl.max-warnings-per-context", 32); if (mMaxWarnings < -1) { GenerateWarning("webgl.max-warnings-per-context size is too large (seems like a negative value wrapped)"); mMaxWarnings = 0; } + mContextObserver = new WebGLObserver(this); + MOZ_RELEASE_ASSERT(mContextObserver, "Can't alloc WebGLContextObserver"); + mLastUseIndex = 0; InvalidateBufferFetching(); @@ -201,12 +319,10 @@ WebGLContext::WebGLContext() WebGLContext::~WebGLContext() { RemovePostRefreshObserver(); + mContextObserver->Destroy(); DestroyResourcesAndContext(); - if (NS_IsMainThread()) { - // XXX mtseng: bug 709490, not thread safe - WebGLMemoryTracker::RemoveWebGLContext(this); - } + WebGLMemoryTracker::RemoveWebGLContext(this); mContextLossHandler->DisableTimer(); mContextLossHandler = nullptr; @@ -215,6 +331,8 @@ WebGLContext::~WebGLContext() void WebGLContext::DestroyResourcesAndContext() { + mContextObserver->UnregisterMemoryPressureEvent(); + if (!gl) return; @@ -313,35 +431,6 @@ WebGLContext::Invalidate() mCanvasElement->InvalidateCanvasContent(nullptr); } -void -WebGLContext::OnVisibilityChange() -{ - if (!IsContextLost()) { - return; - } - - if (!mRestoreWhenVisible || mLastLossWasSimulated) { - return; - } - - ForceRestoreContext(); -} - -void -WebGLContext::OnMemoryPressure() -{ - bool shouldLoseContext = mLoseContextOnMemoryPressure; - - if (!mCanLoseContextInForeground && - ProcessPriorityManager::CurrentProcessIsForeground()) - { - shouldLoseContext = false; - } - - if (shouldLoseContext) - ForceLoseContext(); -} - // // nsICanvasRenderingContextInternal // @@ -426,7 +515,7 @@ static bool IsFeatureInBlacklist(const nsCOMPtr& gfxInfo, int32_t feature) { int32_t status; - if (!NS_SUCCEEDED(gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, feature, &status))) + if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(feature, &status))) return false; return status != nsIGfxInfo::FEATURE_STATUS_OK; @@ -437,29 +526,19 @@ HasAcceleratedLayers(const nsCOMPtr& gfxInfo) { int32_t status; - gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, - nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, - &status); + gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status); if (status) return true; - gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, - nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS, - &status); + gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS, &status); if (status) return true; - gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, - nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS, - &status); + gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS, &status); if (status) return true; - gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, - nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, - &status); + gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status); if (status) return true; - gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, - nsIGfxInfo::FEATURE_OPENGL_LAYERS, - &status); + gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status); if (status) return true; @@ -516,14 +595,11 @@ BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl) // we should really have this behind a // |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but // for now it's just behind a pref for testing/evaluation. - baseCaps.bpp16 = gfxPrefs::WebGLPrefer16bpp(); + baseCaps.bpp16 = Preferences::GetBool("webgl.prefer-16bpp", false); #ifdef MOZ_WIDGET_GONK do { auto canvasElement = webgl->GetCanvas(); - if (!canvasElement) - break; - auto ownerDoc = canvasElement->OwnerDoc(); nsIWidget* docWidget = nsContentUtils::WidgetForDocument(ownerDoc); if (!docWidget) @@ -544,7 +620,7 @@ BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl) // Done with baseCaps construction. - bool forceAllowAA = gfxPrefs::WebGLForceMSAA(); + bool forceAllowAA = Preferences::GetBool("webgl.msaa-force", false); nsCOMPtr gfxInfo = services::GetGfxInfo(); if (!forceAllowAA && IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA)) @@ -664,7 +740,7 @@ bool WebGLContext::CreateAndInitGL(bool forceEnabled) { bool preferEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL"); - bool disableANGLE = gfxPrefs::WebGLDisableANGLE(); + bool disableANGLE = Preferences::GetBool("webgl.disable-angle", false); if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) disableANGLE = true; @@ -745,6 +821,10 @@ WebGLContext::ResizeBackbuffer(uint32_t requestedWidth, NS_IMETHODIMP WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) { + // Early error return cases + if (!GetCanvas()) + return NS_ERROR_FAILURE; + if (signedWidth < 0 || signedHeight < 0) { GenerateWarning("Canvas size is too large (seems like a negative value wrapped)"); return NS_ERROR_OUT_OF_MEMORY; @@ -754,10 +834,7 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) uint32_t height = signedHeight; // Early success return cases - - // May have a OffscreenCanvas instead of an HTMLCanvasElement - if (GetCanvas()) - GetCanvas()->InvalidateCanvas(); + GetCanvas()->InvalidateCanvas(); // Zero-sized surfaces can cause problems. if (width == 0) @@ -830,7 +907,10 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) // pick up the old generation. ++mGeneration; - bool disabled = gfxPrefs::WebGLDisabled(); + // Get some prefs for some preferred/overriden things + NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE); + + bool disabled = Preferences::GetBool("webgl.disabled", false); // TODO: When we have software webgl support we should use that instead. disabled |= gfxPlatform::InSafeMode(); @@ -853,7 +933,7 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) } // Alright, now let's start trying. - bool forceEnabled = gfxPrefs::WebGLForceEnabled(); + bool forceEnabled = Preferences::GetBool("webgl.force-enabled", false); ScopedGfxFeatureReporter reporter("WebGL", forceEnabled); MOZ_ASSERT(!gl); @@ -974,11 +1054,6 @@ WebGLContext::LoseOldestWebGLContextIfLimitExceeded() #endif MOZ_ASSERT(kMaxWebGLContextsPerPrincipal < kMaxWebGLContexts); - if (!NS_IsMainThread()) { - // XXX mtseng: bug 709490, WebGLMemoryTracker is not thread safe. - return; - } - // it's important to update the index on a new context before losing old contexts, // otherwise new unused contexts would all have index 0 and we couldn't distinguish older ones // when choosing which one to lose first. @@ -1066,8 +1141,32 @@ WebGLContext::GetImageBuffer(uint8_t** out_imageBuffer, int32_t* out_format) RefPtr dataSurface = snapshot->GetDataSurface(); - return gfxUtils::GetImageBuffer(dataSurface, mOptions.premultipliedAlpha, - out_imageBuffer, out_format); + DataSourceSurface::MappedSurface map; + if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) + return; + + uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4]; + if (!imageBuffer) { + dataSurface->Unmap(); + return; + } + memcpy(imageBuffer, map.mData, mWidth * mHeight * 4); + + dataSurface->Unmap(); + + int32_t format = imgIEncoder::INPUT_FORMAT_HOSTARGB; + if (!mOptions.premultipliedAlpha) { + // We need to convert to INPUT_FORMAT_RGBA, otherwise + // we are automatically considered premult, and unpremult'd. + // Yes, it is THAT silly. + // Except for different lossy conversions by color, + // we could probably just change the label, and not change the data. + gfxUtils::ConvertBGRAtoRGBA(imageBuffer, mWidth * mHeight * 4); + format = imgIEncoder::INPUT_FORMAT_RGBA; + } + + *out_imageBuffer = imageBuffer; + *out_format = format; } NS_IMETHODIMP @@ -1079,18 +1178,20 @@ WebGLContext::GetInputStream(const char* mimeType, if (!gl) return NS_ERROR_FAILURE; - // Use GetSurfaceSnapshot() to make sure that appropriate y-flip gets applied - bool premult; - RefPtr snapshot = - GetSurfaceSnapshot(mOptions.premultipliedAlpha ? nullptr : &premult); - if (!snapshot) + nsCString enccid("@mozilla.org/image/encoder;2?type="); + enccid += mimeType; + nsCOMPtr encoder = do_CreateInstance(enccid.get()); + if (!encoder) return NS_ERROR_FAILURE; - MOZ_ASSERT(mOptions.premultipliedAlpha || !premult, "We must get unpremult when we ask for it!"); + nsAutoArrayPtr imageBuffer; + int32_t format = 0; + GetImageBuffer(getter_Transfers(imageBuffer), &format); + if (!imageBuffer) + return NS_ERROR_FAILURE; - RefPtr dataSurface = snapshot->GetDataSurface(); - return gfxUtils::GetInputStream(dataSurface, mOptions.premultipliedAlpha, mimeType, - encoderOptions, out_stream); + return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer, format, + encoder, encoderOptions, out_stream); } void @@ -1169,26 +1270,25 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder, } WebGLContextUserData* userData = nullptr; - if (builder->IsPaintingToWindow() && mCanvasElement) { - // Make the layer tell us whenever a transaction finishes (including - // the current transaction), so we can clear our invalidation state and - // start invalidating again. We need to do this for the layer that is - // being painted to a window (there shouldn't be more than one at a time, - // and if there is, flushing the invalidation state more often than - // necessary is harmless). + if (builder->IsPaintingToWindow()) { + // Make the layer tell us whenever a transaction finishes (including + // the current transaction), so we can clear our invalidation state and + // start invalidating again. We need to do this for the layer that is + // being painted to a window (there shouldn't be more than one at a time, + // and if there is, flushing the invalidation state more often than + // necessary is harmless). - // The layer will be destroyed when we tear down the presentation - // (at the latest), at which time this userData will be destroyed, - // releasing the reference to the element. - // The userData will receive DidTransactionCallbacks, which flush the - // the invalidation state to indicate that the canvas is up to date. - userData = new WebGLContextUserData(mCanvasElement); - canvasLayer->SetDidTransactionCallback( - WebGLContextUserData::DidTransactionCallback, userData); - canvasLayer->SetPreTransactionCallback( - WebGLContextUserData::PreTransactionCallback, userData); + // The layer will be destroyed when we tear down the presentation + // (at the latest), at which time this userData will be destroyed, + // releasing the reference to the element. + // The userData will receive DidTransactionCallbacks, which flush the + // the invalidation state to indicate that the canvas is up to date. + userData = new WebGLContextUserData(mCanvasElement); + canvasLayer->SetDidTransactionCallback( + WebGLContextUserData::DidTransactionCallback, userData); + canvasLayer->SetPreTransactionCallback( + WebGLContextUserData::PreTransactionCallback, userData); } - canvasLayer->SetUserData(&gWebGLLayerUserData, userData); CanvasLayer::Data data; @@ -1210,36 +1310,14 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder, layers::LayersBackend WebGLContext::GetCompositorBackendType() const { - if (mCanvasElement) { - return mCanvasElement->GetCompositorBackendType(); - } else if (mOffscreenCanvas) { - return mOffscreenCanvas->GetCompositorBackendType(); + nsIWidget* docWidget = nsContentUtils::WidgetForDocument(mCanvasElement->OwnerDoc()); + if (docWidget) { + layers::LayerManager* layerManager = docWidget->GetLayerManager(); + return layerManager->GetCompositorBackendType(); } - return LayersBackend::LAYERS_NONE; } -void -WebGLContext::Commit() -{ - if (mOffscreenCanvas) { - mOffscreenCanvas->CommitFrameToCompositor(); - } -} - -void -WebGLContext::GetCanvas(Nullable& retval) -{ - if (mCanvasElement) { - MOZ_RELEASE_ASSERT(!mOffscreenCanvas); - retval.SetValue().SetAsHTMLCanvasElement() = mCanvasElement; - } else if (mOffscreenCanvas) { - retval.SetValue().SetAsOffscreenCanvas() = mOffscreenCanvas; - } else { - retval.SetNull(); - } -} - void WebGLContext::GetContextAttributes(dom::Nullable& retval) { @@ -1548,7 +1626,7 @@ WebGLContext::RunContextLossTimer() mContextLossHandler->RunTimer(); } -class UpdateContextLossStatusTask : public nsCancelableRunnable +class UpdateContextLossStatusTask : public nsRunnable { nsRefPtr mWebGL; @@ -1559,16 +1637,10 @@ public: } NS_IMETHOD Run() { - if (mWebGL) - mWebGL->UpdateContextLossStatus(); + mWebGL->UpdateContextLossStatus(); return NS_OK; } - - NS_IMETHOD Cancel() { - mWebGL = nullptr; - return NS_OK; - } }; void @@ -1595,7 +1667,7 @@ WebGLContext::EnqueueUpdateContextLossStatus() void WebGLContext::UpdateContextLossStatus() { - if (!mCanvasElement && !mOffscreenCanvas) { + if (!mCanvasElement) { // the canvas is gone. That happens when the page was closed before we got // this timer event. In this case, there's nothing to do here, just don't crash. return; @@ -1623,23 +1695,12 @@ WebGLContext::UpdateContextLossStatus() // callback, so do that now. bool useDefaultHandler; - - if (mCanvasElement) { - nsContentUtils::DispatchTrustedEvent( - mCanvasElement->OwnerDoc(), - static_cast(mCanvasElement), - NS_LITERAL_STRING("webglcontextlost"), - true, - true, - &useDefaultHandler); - } else { - // OffscreenCanvas case - nsRefPtr event = new Event(mOffscreenCanvas, nullptr, nullptr); - event->InitEvent(NS_LITERAL_STRING("webglcontextlost"), true, true); - event->SetTrusted(true); - mOffscreenCanvas->DispatchEvent(event, &useDefaultHandler); - } - + nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(), + static_cast(mCanvasElement), + NS_LITERAL_STRING("webglcontextlost"), + true, + true, + &useDefaultHandler); // We sent the callback, so we're just 'regular lost' now. mContextStatus = ContextLost; // If we're told to use the default handler, it means the script @@ -1691,22 +1752,11 @@ WebGLContext::UpdateContextLossStatus() // Revival! mContextStatus = ContextNotLost; - - if (mCanvasElement) { - nsContentUtils::DispatchTrustedEvent( - mCanvasElement->OwnerDoc(), - static_cast(mCanvasElement), - NS_LITERAL_STRING("webglcontextrestored"), - true, - true); - } else { - nsRefPtr event = new Event(mOffscreenCanvas, nullptr, nullptr); - event->InitEvent(NS_LITERAL_STRING("webglcontextrestored"), true, true); - event->SetTrusted(true); - bool unused; - mOffscreenCanvas->DispatchEvent(event, &unused); - } - + nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(), + static_cast(mCanvasElement), + NS_LITERAL_STRING("webglcontextrestored"), + true, + true); mEmitContextLostErrorOnce = true; return; } @@ -1724,6 +1774,12 @@ WebGLContext::ForceLoseContext(bool simulateLosing) DestroyResourcesAndContext(); mLastLossWasSimulated = simulateLosing; + // Register visibility change observer to defer the context restoring. + // Restore the context when the app is visible. + if (mRestoreWhenVisible && !mLastLossWasSimulated) { + mContextObserver->RegisterVisibilityChangeEvent(); + } + // Queue up a task, since we know the status changed. EnqueueUpdateContextLossStatus(); } @@ -1735,6 +1791,8 @@ WebGLContext::ForceRestoreContext() mContextStatus = ContextLostAwaitingRestore; mAllowContextRestore = true; // Hey, you did say 'force'. + mContextObserver->UnregisterVisibilityChangeEvent(); + // Queue up a task, since we know the status changed. EnqueueUpdateContextLossStatus(); } @@ -1869,7 +1927,6 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext) NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext, mCanvasElement, - mOffscreenCanvas, mExtensions, mBound2DTextures, mBoundCubeMapTextures, diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index b19bc06efd83..6c1ff727e4ed 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -40,11 +40,7 @@ // Generated #include "nsIDOMEventListener.h" #include "nsIDOMWebGLRenderingContext.h" -#include "nsICanvasRenderingContextInternal.h" #include "nsIObserver.h" -#include "mozilla/dom/HTMLCanvasElement.h" -#include "nsWrapperCache.h" -#include "nsLayoutUtils.h" class nsIDocShell; @@ -84,6 +80,7 @@ class WebGLContextLossHandler; class WebGLBuffer; class WebGLExtensionBase; class WebGLFramebuffer; +class WebGLObserver; class WebGLProgram; class WebGLQuery; class WebGLRenderbuffer; @@ -98,7 +95,6 @@ class WebGLVertexArray; namespace dom { class Element; class ImageData; -class OwningHTMLCanvasElementOrOffscreenCanvas; struct WebGLContextAttributes; template struct Nullable; } // namespace dom @@ -188,6 +184,7 @@ class WebGLContext friend class WebGLExtensionLoseContext; friend class WebGLExtensionVertexArray; friend class WebGLMemoryTracker; + friend class WebGLObserver; enum { UNPACK_FLIP_Y_WEBGL = 0x9240, @@ -217,9 +214,6 @@ public: NS_DECL_NSIDOMWEBGLRENDERINGCONTEXT - virtual void OnVisibilityChange() override; - virtual void OnMemoryPressure() override; - // nsICanvasRenderingContextInternal #ifdef DEBUG virtual int32_t GetWidth() const override; @@ -368,11 +362,8 @@ public: void AssertCachedBindings(); void AssertCachedState(); - dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; } - // WebIDL WebGLRenderingContext API - void Commit(); - void GetCanvas(Nullable& retval); + dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; } GLsizei DrawingBufferWidth() const { return IsContextLost() ? 0 : mWidth; } GLsizei DrawingBufferHeight() const { return IsContextLost() ? 0 : mHeight; @@ -1518,6 +1509,8 @@ protected: ForceDiscreteGPUHelperCGL mForceDiscreteGPUHelper; #endif + nsRefPtr mContextObserver; + public: // console logging helpers void GenerateWarning(const char* fmt, ...); @@ -1622,6 +1615,32 @@ WebGLContext::ValidateObject(const char* info, ObjectType* object) return ValidateObjectAssumeNonNull(info, object); } +// Listen visibilitychange and memory-pressure event for context lose/restore +class WebGLObserver final + : public nsIObserver + , public nsIDOMEventListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + NS_DECL_NSIDOMEVENTLISTENER + + explicit WebGLObserver(WebGLContext* webgl); + + void Destroy(); + + void RegisterVisibilityChangeEvent(); + void UnregisterVisibilityChangeEvent(); + + void RegisterMemoryPressureEvent(); + void UnregisterMemoryPressureEvent(); + +private: + ~WebGLObserver(); + + WebGLContext* mWebGL; +}; + size_t RoundUpToMultipleOf(size_t value, size_t multiple); bool diff --git a/dom/canvas/WebGLContextExtensions.cpp b/dom/canvas/WebGLContextExtensions.cpp index 39b3ebd64713..79040e1a4111 100644 --- a/dom/canvas/WebGLContextExtensions.cpp +++ b/dom/canvas/WebGLContextExtensions.cpp @@ -6,7 +6,6 @@ #include "WebGLContext.h" #include "WebGLContextUtils.h" #include "WebGLExtensions.h" -#include "gfxPrefs.h" #include "GLContext.h" #include "nsString.h" @@ -75,15 +74,12 @@ bool WebGLContext::IsExtensionSupported(JSContext* cx, // Chrome contexts need access to debug information even when // webgl.disable-extensions is set. This is used in the graphics - // section of about:support - if (NS_IsMainThread() && - xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) { + // section of about:support. + if (xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) allowPrivilegedExts = true; - } - if (gfxPrefs::WebGLPrivilegedExtensionsEnabled()) { + if (Preferences::GetBool("webgl.enable-privileged-extensions", false)) allowPrivilegedExts = true; - } if (allowPrivilegedExts) { switch (ext) { @@ -185,7 +181,9 @@ WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const break; } - if (gfxPrefs::WebGLDraftExtensionsEnabled() || IsWebGL2()) { + if (Preferences::GetBool("webgl.enable-draft-extensions", false) || + IsWebGL2()) + { switch (ext) { case WebGLExtensionID::EXT_disjoint_timer_query: return WebGLExtensionDisjointTimerQuery::IsSupported(this); diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index 53bd8d8e8ea5..10cc59e4d4ef 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -1390,10 +1390,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, if (IsContextLost()) return; - if (mCanvasElement && - mCanvasElement->IsWriteOnly() && - !nsContentUtils::IsCallerChrome()) - { + if (mCanvasElement->IsWriteOnly() && !nsContentUtils::IsCallerChrome()) { GenerateWarning("readPixels: Not allowed"); return rv.Throw(NS_ERROR_DOM_SECURITY_ERR); } diff --git a/dom/canvas/WebGLContextLossHandler.cpp b/dom/canvas/WebGLContextLossHandler.cpp index ddffbe994864..3cc1af031492 100644 --- a/dom/canvas/WebGLContextLossHandler.cpp +++ b/dom/canvas/WebGLContextLossHandler.cpp @@ -8,103 +8,15 @@ #include "nsITimer.h" #include "nsThreadUtils.h" #include "WebGLContext.h" -#include "mozilla/dom/WorkerPrivate.h" namespace mozilla { -// ------------------------------------------------------------------- -// Begin worker specific code -// ------------------------------------------------------------------- - -// On workers we can only dispatch CancelableRunnables, so we have to wrap the -// timer's EventTarget to use our own cancelable runnable - -class ContextLossWorkerEventTarget final : public nsIEventTarget -{ -public: - explicit ContextLossWorkerEventTarget(nsIEventTarget* aEventTarget) - : mEventTarget(aEventTarget) - { - MOZ_ASSERT(aEventTarget); - } - - NS_DECL_NSIEVENTTARGET - NS_DECL_THREADSAFE_ISUPPORTS - -protected: - ~ContextLossWorkerEventTarget() {} - -private: - nsCOMPtr mEventTarget; -}; - -class ContextLossWorkerRunnable final : public nsICancelableRunnable -{ -public: - explicit ContextLossWorkerRunnable(nsIRunnable* aRunnable) - : mRunnable(aRunnable) - { - } - - NS_DECL_NSICANCELABLERUNNABLE - NS_DECL_THREADSAFE_ISUPPORTS - - NS_FORWARD_NSIRUNNABLE(mRunnable->) - -protected: - ~ContextLossWorkerRunnable() {} - -private: - nsCOMPtr mRunnable; -}; - -NS_IMPL_ISUPPORTS(ContextLossWorkerEventTarget, nsIEventTarget, - nsISupports) - -NS_IMETHODIMP -ContextLossWorkerEventTarget::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags) -{ - nsCOMPtr event(aEvent); - return Dispatch(event.forget(), aFlags); -} - -NS_IMETHODIMP -ContextLossWorkerEventTarget::Dispatch(already_AddRefed&& aEvent, - uint32_t aFlags) -{ - nsCOMPtr eventRef(aEvent); - nsRefPtr wrappedEvent = - new ContextLossWorkerRunnable(eventRef); - return mEventTarget->Dispatch(wrappedEvent, aFlags); -} - -NS_IMETHODIMP -ContextLossWorkerEventTarget::IsOnCurrentThread(bool* aResult) -{ - return mEventTarget->IsOnCurrentThread(aResult); -} - -NS_IMPL_ISUPPORTS(ContextLossWorkerRunnable, nsICancelableRunnable, - nsIRunnable) - -NS_IMETHODIMP -ContextLossWorkerRunnable::Cancel() -{ - mRunnable = nullptr; - return NS_OK; -} - -// ------------------------------------------------------------------- -// End worker-specific code -// ------------------------------------------------------------------- - WebGLContextLossHandler::WebGLContextLossHandler(WebGLContext* webgl) : mWeakWebGL(webgl) , mTimer(do_CreateInstance(NS_TIMER_CONTRACTID)) , mIsTimerRunning(false) , mShouldRunTimerAgain(false) , mIsDisabled(false) - , mFeatureAdded(false) #ifdef DEBUG , mThread(NS_GetCurrentThread()) #endif @@ -178,17 +90,6 @@ WebGLContextLossHandler::RunTimer() return; } - if (!NS_IsMainThread()) { - dom::workers::WorkerPrivate* workerPrivate = - dom::workers::GetCurrentThreadWorkerPrivate(); - nsCOMPtr target = workerPrivate->GetEventTarget(); - mTimer->SetTarget(new ContextLossWorkerEventTarget(target)); - if (!mFeatureAdded) { - workerPrivate->AddFeature(workerPrivate->GetJSContext(), this); - mFeatureAdded = true; - } - } - StartTimer(1000); mIsTimerRunning = true; @@ -203,14 +104,6 @@ WebGLContextLossHandler::DisableTimer() mIsDisabled = true; - if (mFeatureAdded) { - dom::workers::WorkerPrivate* workerPrivate = - dom::workers::GetCurrentThreadWorkerPrivate(); - MOZ_RELEASE_ASSERT(workerPrivate); - workerPrivate->RemoveFeature(workerPrivate->GetJSContext(), this); - mFeatureAdded = false; - } - // We can't just Cancel() the timer, as sometimes we end up // receiving a callback after calling Cancel(). This could cause us // to receive the callback after object destruction. @@ -223,16 +116,4 @@ WebGLContextLossHandler::DisableTimer() mTimer->SetDelay(0); } -bool -WebGLContextLossHandler::Notify(JSContext* aCx, dom::workers::Status aStatus) -{ - bool isWorkerRunning = aStatus < dom::workers::Closing; - if (!isWorkerRunning && mIsTimerRunning) { - mIsTimerRunning = false; - this->Release(); - } - - return true; -} - } // namespace mozilla diff --git a/dom/canvas/WebGLContextLossHandler.h b/dom/canvas/WebGLContextLossHandler.h index 70d8c671fad5..0769de910535 100644 --- a/dom/canvas/WebGLContextLossHandler.h +++ b/dom/canvas/WebGLContextLossHandler.h @@ -10,7 +10,6 @@ #include "mozilla/WeakPtr.h" #include "nsCOMPtr.h" #include "nsISupportsImpl.h" -#include "WorkerFeature.h" class nsIThread; class nsITimer; @@ -18,14 +17,13 @@ class nsITimer; namespace mozilla { class WebGLContext; -class WebGLContextLossHandler : public dom::workers::WorkerFeature +class WebGLContextLossHandler { WeakPtr mWeakWebGL; nsCOMPtr mTimer; bool mIsTimerRunning; bool mShouldRunTimerAgain; bool mIsDisabled; - bool mFeatureAdded; DebugOnly mThread; public: @@ -35,7 +33,6 @@ public: void RunTimer(); void DisableTimer(); - bool Notify(JSContext* aCx, dom::workers::Status aStatus) override; protected: ~WebGLContextLossHandler(); diff --git a/dom/canvas/WebGLContextReporter.cpp b/dom/canvas/WebGLContextReporter.cpp index 4aab34a079c3..d257d9662b4f 100644 --- a/dom/canvas/WebGLContextReporter.cpp +++ b/dom/canvas/WebGLContextReporter.cpp @@ -9,6 +9,8 @@ namespace mozilla { +NS_IMPL_ISUPPORTS(WebGLObserver, nsIObserver) + NS_IMETHODIMP WebGLMemoryTracker::CollectReports(nsIHandleReportCallback* handleReport, nsISupports* data, bool) diff --git a/dom/canvas/WebGLContextValidate.cpp b/dom/canvas/WebGLContextValidate.cpp index 29dedac8f98a..ff366b1b74ab 100644 --- a/dom/canvas/WebGLContextValidate.cpp +++ b/dom/canvas/WebGLContextValidate.cpp @@ -8,7 +8,6 @@ #include #include "angle/ShaderLang.h" #include "CanvasUtils.h" -#include "gfxPrefs.h" #include "GLContext.h" #include "jsfriendapi.h" #include "mozilla/CheckedInt.h" @@ -1666,11 +1665,11 @@ WebGLContext::InitAndValidateGL() return false; } - mMinCapability = gfxPrefs::WebGLMinCapabilityMode(); - mDisableExtensions = gfxPrefs::WebGLDisableExtensions(); - mLoseContextOnMemoryPressure = gfxPrefs::WebGLLoseContextOnMemoryPressure(); - mCanLoseContextInForeground = gfxPrefs::WebGLCanLoseContextInForeground(); - mRestoreWhenVisible = gfxPrefs::WebGLRestoreWhenVisible(); + mMinCapability = Preferences::GetBool("webgl.min_capability_mode", false); + mDisableExtensions = Preferences::GetBool("webgl.disable-extensions", false); + mLoseContextOnMemoryPressure = Preferences::GetBool("webgl.lose-context-on-memory-pressure", false); + mCanLoseContextInForeground = Preferences::GetBool("webgl.can-lose-context-in-foreground", true); + mRestoreWhenVisible = Preferences::GetBool("webgl.restore-context-when-visible", true); if (MinCapabilityMode()) mDisableFragHighP = true; @@ -1879,7 +1878,10 @@ WebGLContext::InitAndValidateGL() #endif // Check the shader validator pref - mBypassShaderValidation = gfxPrefs::WebGLBypassShaderValidator(); + NS_ENSURE_TRUE(Preferences::GetRootBranch(), false); + + mBypassShaderValidation = Preferences::GetBool("webgl.bypass-shader-validation", + mBypassShaderValidation); // initialize shader translator if (!ShInitialize()) { @@ -1935,6 +1937,9 @@ WebGLContext::InitAndValidateGL() mDefaultVertexArray->BindVertexArray(); } + if (mLoseContextOnMemoryPressure) + mContextObserver->RegisterMemoryPressureEvent(); + return true; } diff --git a/dom/canvas/WebGLMemoryTracker.cpp b/dom/canvas/WebGLMemoryTracker.cpp index 5bc4b31fb5d9..b13d9d7c43bd 100644 --- a/dom/canvas/WebGLMemoryTracker.cpp +++ b/dom/canvas/WebGLMemoryTracker.cpp @@ -16,6 +16,8 @@ namespace mozilla { +NS_IMPL_ISUPPORTS(WebGLObserver, nsIObserver) + NS_IMETHODIMP WebGLMemoryTracker::CollectReports(nsIHandleReportCallback* handleReport, nsISupports* data, bool) diff --git a/dom/canvas/WebGLShaderValidator.cpp b/dom/canvas/WebGLShaderValidator.cpp index 5553ad8f72ec..4f8741547270 100644 --- a/dom/canvas/WebGLShaderValidator.cpp +++ b/dom/canvas/WebGLShaderValidator.cpp @@ -6,7 +6,6 @@ #include "WebGLShaderValidator.h" #include "angle/ShaderLang.h" -#include "gfxPrefs.h" #include "GLContext.h" #include "mozilla/Preferences.h" #include "MurmurHash3.h" @@ -44,7 +43,7 @@ ChooseValidatorCompileOptions(const ShBuiltInResources& resources, options |= SH_LIMIT_EXPRESSION_COMPLEXITY; } - if (gfxPrefs::WebGLAllANGLEOptions()) { + if (Preferences::GetBool("webgl.all-angle-options", false)) { return options | SH_VALIDATE_LOOP_INDEXING | SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX | diff --git a/dom/canvas/moz.build b/dom/canvas/moz.build index 762741b22f7d..39288fe6be89 100644 --- a/dom/canvas/moz.build +++ b/dom/canvas/moz.build @@ -28,12 +28,10 @@ EXPORTS.mozilla.dom += [ 'CanvasPath.h', 'CanvasPattern.h', 'CanvasRenderingContext2D.h', - 'CanvasRenderingContextHelper.h', 'CanvasUtils.h', 'ImageBitmap.h', 'ImageBitmapSource.h', 'ImageData.h', - 'OffscreenCanvas.h', 'TextMetrics.h', 'WebGLVertexArrayObject.h', ] @@ -42,13 +40,11 @@ EXPORTS.mozilla.dom += [ UNIFIED_SOURCES += [ 'CanvasImageCache.cpp', 'CanvasRenderingContext2D.cpp', - 'CanvasRenderingContextHelper.cpp', 'CanvasUtils.cpp', 'DocumentRendererChild.cpp', 'DocumentRendererParent.cpp', 'ImageBitmap.cpp', 'ImageData.cpp', - 'OffscreenCanvas.cpp', ] # WebGL Sources @@ -154,7 +150,6 @@ LOCAL_INCLUDES += [ '/dom/base', '/dom/html', '/dom/svg', - '/dom/workers', '/dom/xul', '/gfx/gl', '/image', diff --git a/dom/canvas/nsICanvasRenderingContextInternal.h b/dom/canvas/nsICanvasRenderingContextInternal.h index 820b1d5d1314..ec62bd97a493 100644 --- a/dom/canvas/nsICanvasRenderingContextInternal.h +++ b/dom/canvas/nsICanvasRenderingContextInternal.h @@ -12,13 +12,12 @@ #include "nsIDocShell.h" #include "nsRefreshDriver.h" #include "mozilla/dom/HTMLCanvasElement.h" -#include "mozilla/dom/OffscreenCanvas.h" #include "GraphicsFilter.h" #include "mozilla/RefPtr.h" #define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \ -{ 0xb84f2fed, 0x9d4b, 0x430b, \ - { 0xbd, 0xfb, 0x85, 0x57, 0x8a, 0xc2, 0xb4, 0x4b } } +{ 0x3cc9e801, 0x1806, 0x4ff6, \ + { 0x86, 0x14, 0xf9, 0xd0, 0xf4, 0xfb, 0x3b, 0x08 } } class gfxASurface; class nsDisplayListBuilder; @@ -81,11 +80,6 @@ public: return mCanvasElement; } - void SetOffscreenCanvas(mozilla::dom::OffscreenCanvas* aOffscreenCanvas) - { - mOffscreenCanvas = aOffscreenCanvas; - } - #ifdef DEBUG // Useful for testing virtual int32_t GetWidth() const = 0; @@ -160,10 +154,6 @@ public: // Given a point, return hit region ID if it exists or an empty string if it doesn't virtual nsString GetHitRegion(const mozilla::gfx::Point& point) { return nsString(); } - virtual void OnVisibilityChange() {} - - virtual void OnMemoryPressure() {} - // // shmem support // @@ -176,7 +166,6 @@ public: protected: nsRefPtr mCanvasElement; - nsRefPtr mOffscreenCanvas; nsRefPtr mRefreshDriver; }; diff --git a/dom/canvas/test/mochitest.ini b/dom/canvas/test/mochitest.ini index b0de5bee3bdb..ffee4bbb26d5 100644 --- a/dom/canvas/test/mochitest.ini +++ b/dom/canvas/test/mochitest.ini @@ -27,10 +27,6 @@ support-files = imagebitmap_on_worker.js imagebitmap_structuredclone.js imagebitmap_structuredclone_iframe.html - offscreencanvas.js - offscreencanvas_mask.svg - offscreencanvas_neuter.js - offscreencanvas_serviceworker_inner.html [test_2d.clearRect.image.offscreen.html] [test_2d.clip.winding.html] @@ -265,22 +261,3 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # bug 1040965 [test_createPattern_broken.html] [test_setlinedash.html] [test_filter.html] -[test_offscreencanvas_basic_webgl.html] -tags = offscreencanvas -[test_offscreencanvas_dynamic_fallback.html] -tags = offscreencanvas -[test_offscreencanvas_sharedworker.html] -tags = offscreencanvas -[test_offscreencanvas_serviceworker.html] -tags = offscreencanvas -skip-if = buildapp == 'b2g' -[test_offscreencanvas_neuter.html] -tags = offscreencanvas -[test_offscreencanvas_many.html] -tags = offscreencanvas -skip-if = (toolkit == 'android' || toolkit == 'gonk' || toolkit == 'windows' || toolkit == 'gtk2' || toolkit == 'gtk3') -[test_offscreencanvas_sizechange.html] -tags = offscreencanvas -[test_offscreencanvas_subworker.html] -tags = offscreencanvas -skip-if = (toolkit == 'android' || toolkit == 'gonk' || toolkit == 'windows' || toolkit == 'gtk2' || toolkit == 'gtk3') diff --git a/dom/canvas/test/offscreencanvas.js b/dom/canvas/test/offscreencanvas.js deleted file mode 100644 index 6dec8220f462..000000000000 --- a/dom/canvas/test/offscreencanvas.js +++ /dev/null @@ -1,299 +0,0 @@ -/* WebWorker for test_offscreencanvas_*.html */ -var port = null; - -function ok(expect, msg) { - if (port) { - port.postMessage({type: "test", result: !!expect, name: msg}); - } else { - postMessage({type: "test", result: !!expect, name: msg}); - } -} - -function finish() { - if (port) { - port.postMessage({type: "finish"}); - } else { - postMessage({type: "finish"}); - } -} - -function drawCount(count) { - if (port) { - port.postMessage({type: "draw", count: count}); - } else { - postMessage({type: "draw", count: count}); - } -} - -//-------------------------------------------------------------------- -// WebGL Drawing Functions -//-------------------------------------------------------------------- -function createDrawFunc(canvas) { - var gl; - - try { - gl = canvas.getContext("experimental-webgl"); - } catch (e) {} - - if (!gl) { - ok(false, "WebGL is unavailable"); - return null; - } - - var vertSrc = "attribute vec2 position; \ - void main(void) { \ - gl_Position = vec4(position, 0.0, 1.0); \ - }"; - - var fragSrc = "precision mediump float; \ - void main(void) { \ - gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); \ - }"; - - // Returns a valid shader, or null on errors. - var createShader = function(src, t) { - var shader = gl.createShader(t); - - gl.shaderSource(shader, src); - gl.compileShader(shader); - - return shader; - }; - - var createProgram = function(vsSrc, fsSrc) { - var vs = createShader(vsSrc, gl.VERTEX_SHADER); - var fs = createShader(fsSrc, gl.FRAGMENT_SHADER); - - var prog = gl.createProgram(); - gl.attachShader(prog, vs); - gl.attachShader(prog, fs); - gl.linkProgram(prog); - - if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) { - var str = "Shader program linking failed:"; - str += "\nShader program info log:\n" + gl.getProgramInfoLog(prog); - str += "\n\nVert shader log:\n" + gl.getShaderInfoLog(vs); - str += "\n\nFrag shader log:\n" + gl.getShaderInfoLog(fs); - console.log(str); - ok(false, "Shader program linking failed"); - return null; - } - - return prog; - }; - - gl.disable(gl.DEPTH_TEST); - - var program = createProgram(vertSrc, fragSrc); - ok(program, "Creating shader program"); - - program.positionAttr = gl.getAttribLocation(program, "position"); - ok(program.positionAttr >= 0, "position attribute should be valid"); - - var vertCoordArr = new Float32Array([ - -1, -1, - 1, -1, - -1, 1, - 1, 1, - ]); - var vertCoordBuff = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, vertCoordBuff); - gl.bufferData(gl.ARRAY_BUFFER, vertCoordArr, gl.STATIC_DRAW); - - var checkGLError = function(prefix, refValue) { - if (!refValue) { - refValue = 0; - } - - var error = gl.getError(); - ok(error == refValue, - prefix + 'gl.getError should be 0x' + refValue.toString(16) + - ', was 0x' + error.toString(16) + '.'); - }; - - var testPixel = function(x, y, refData, infoString) { - var pixel = new Uint8Array(4); - gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel); - - var pixelMatches = pixel[0] == refData[0] && - pixel[1] == refData[1] && - pixel[2] == refData[2] && - pixel[3] == refData[3]; - ok(pixelMatches, infoString); - }; - - var preDraw = function(prefix) { - gl.clearColor(1.0, 0.0, 0.0, 1.0); - gl.clear(gl.COLOR_BUFFER_BIT); - - testPixel(0, 0, [255, 0, 0, 255], prefix + 'Should be red before drawing.'); - }; - - var postDraw = function(prefix) { - testPixel(0, 0, [0, 255, 0, 255], prefix + 'Should be green after drawing.'); - }; - - gl.useProgram(program); - gl.enableVertexAttribArray(program.position); - gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0); - - // Start drawing - checkGLError('after setup'); - - return function(prefix) { - if (prefix) { - prefix = "[" + prefix + "] "; - } else { - prefix = ""; - } - - gl.viewport(0, 0, canvas.width, canvas.height); - - preDraw(prefix); - gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); - postDraw(prefix); - gl.commit(); - checkGLError(prefix); - }; -} - -/* entry point */ -function entryFunction(testStr, subtests, offscreenCanvas) { - var test = testStr; - var canvas = offscreenCanvas; - - if (test != "subworker") { - ok(canvas, "Canvas successfully transfered to worker"); - ok(canvas.getContext, "Canvas has getContext"); - - ok(canvas.width == 64, "OffscreenCanvas width should be 64"); - ok(canvas.height == 64, "OffscreenCanvas height should be 64"); - } - - var draw; - - //------------------------------------------------------------------------ - // Basic WebGL test - //------------------------------------------------------------------------ - if (test == "webgl") { - draw = createDrawFunc(canvas); - if (!draw) { - finish(); - return; - } - - var count = 0; - var iid = setInterval(function() { - if (count++ > 20) { - clearInterval(iid); - ok(true, "Worker is done"); - finish(); - return; - } - draw("loop " +count); - }, 0); - } - //------------------------------------------------------------------------ - // Test dynamic fallback - //------------------------------------------------------------------------ - else if (test == "webgl_fallback") { - draw = createDrawFunc(canvas); - if (!draw) { - return; - } - - var count = 0; - var iid = setInterval(function() { - ++count; - draw("loop " + count); - drawCount(count); - }, 0); - } - //------------------------------------------------------------------------ - // Canvas Size Change from Worker - //------------------------------------------------------------------------ - else if (test == "webgl_changesize") { - draw = createDrawFunc(canvas); - if (!draw) { - finish(); - return; - } - - draw("64x64"); - - setTimeout(function() { - canvas.width = 128; - canvas.height = 128; - draw("Increased to 128x128"); - - setTimeout(function() { - canvas.width = 32; - canvas.width = 32; - draw("Decreased to 32x32"); - - setTimeout(function() { - canvas.width = 64; - canvas.height = 64; - draw("Increased to 64x64"); - - ok(true, "Worker is done"); - finish(); - }, 0); - }, 0); - }, 0); - } - //------------------------------------------------------------------------ - // Using OffscreenCanvas from sub workers - //------------------------------------------------------------------------ - else if (test == "subworker") { - /* subworker tests take a list of tests to run on children */ - var stillRunning = 0; - subtests.forEach(function (subtest) { - ++stillRunning; - var subworker = new Worker('offscreencanvas.js'); - subworker.onmessage = function(evt) { - /* report finish to parent when all children are finished */ - if (evt.data.type == "finish") { - subworker.terminate(); - if (--stillRunning == 0) { - ok(true, "Worker is done"); - finish(); - } - return; - } - /* relay all other messages to parent */ - postMessage(evt.data); - }; - - var findTransferables = function(t) { - if (t.test == "subworker") { - var result = []; - t.subtests.forEach(function(test) { - result = result.concat(findTransferables(test)); - }); - - return result; - } else { - return [t.canvas]; - } - }; - - subworker.postMessage(subtest, findTransferables(subtest)); - }); - } -}; - -onmessage = function(evt) { - port = evt.ports[0]; - entryFunction(evt.data.test, evt.data.subtests, evt.data.canvas); -}; - -onconnect = function(evt) { - port = evt.ports[0]; - - port.addEventListener('message', function(evt) { - entryFunction(evt.data.test, evt.data.subtests, evt.data.canvas); - }); - - port.start(); -}; diff --git a/dom/canvas/test/offscreencanvas_mask.svg b/dom/canvas/test/offscreencanvas_mask.svg deleted file mode 100644 index 34347b68b37b..000000000000 --- a/dom/canvas/test/offscreencanvas_mask.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/dom/canvas/test/offscreencanvas_neuter.js b/dom/canvas/test/offscreencanvas_neuter.js deleted file mode 100644 index 30648d740a15..000000000000 --- a/dom/canvas/test/offscreencanvas_neuter.js +++ /dev/null @@ -1 +0,0 @@ -/* empty worker for test_offscreencanvas_disable.html */ diff --git a/dom/canvas/test/offscreencanvas_serviceworker_inner.html b/dom/canvas/test/offscreencanvas_serviceworker_inner.html deleted file mode 100644 index b153f9524a1c..000000000000 --- a/dom/canvas/test/offscreencanvas_serviceworker_inner.html +++ /dev/null @@ -1,32 +0,0 @@ - - - -WebGL in OffscreenCanvas - - - - - - diff --git a/dom/canvas/test/test_offscreencanvas_basic_webgl.html b/dom/canvas/test/test_offscreencanvas_basic_webgl.html deleted file mode 100644 index 55b186812050..000000000000 --- a/dom/canvas/test/test_offscreencanvas_basic_webgl.html +++ /dev/null @@ -1,62 +0,0 @@ - - - -WebGL in OffscreenCanvas - - - - - - - - - diff --git a/dom/canvas/test/test_offscreencanvas_dynamic_fallback.html b/dom/canvas/test/test_offscreencanvas_dynamic_fallback.html deleted file mode 100644 index 8e4f0f8deafe..000000000000 --- a/dom/canvas/test/test_offscreencanvas_dynamic_fallback.html +++ /dev/null @@ -1,80 +0,0 @@ - - - -WebGL in OffscreenCanvas - - - - - - - - diff --git a/dom/canvas/test/test_offscreencanvas_many.html b/dom/canvas/test/test_offscreencanvas_many.html deleted file mode 100644 index 6bf2680c50b2..000000000000 --- a/dom/canvas/test/test_offscreencanvas_many.html +++ /dev/null @@ -1,67 +0,0 @@ - - - -WebGL in OffscreenCanvas - - - - - - - - diff --git a/dom/canvas/test/test_offscreencanvas_neuter.html b/dom/canvas/test/test_offscreencanvas_neuter.html deleted file mode 100644 index 2af080c7c1ef..000000000000 --- a/dom/canvas/test/test_offscreencanvas_neuter.html +++ /dev/null @@ -1,78 +0,0 @@ - - - -OffscreenCanvas: Test neutering - - - - - - - - diff --git a/dom/canvas/test/test_offscreencanvas_serviceworker.html b/dom/canvas/test/test_offscreencanvas_serviceworker.html deleted file mode 100644 index c5cfb93db1a3..000000000000 --- a/dom/canvas/test/test_offscreencanvas_serviceworker.html +++ /dev/null @@ -1,46 +0,0 @@ - - - -WebGL in OffscreenCanvas - - - - - - - diff --git a/dom/canvas/test/test_offscreencanvas_sharedworker.html b/dom/canvas/test/test_offscreencanvas_sharedworker.html deleted file mode 100644 index 28d7ce37c8a3..000000000000 --- a/dom/canvas/test/test_offscreencanvas_sharedworker.html +++ /dev/null @@ -1,47 +0,0 @@ - - - -WebGL in OffscreenCanvas - - - - - - - - diff --git a/dom/canvas/test/test_offscreencanvas_sizechange.html b/dom/canvas/test/test_offscreencanvas_sizechange.html deleted file mode 100644 index cecbac348349..000000000000 --- a/dom/canvas/test/test_offscreencanvas_sizechange.html +++ /dev/null @@ -1,41 +0,0 @@ - - - -WebGL in OffscreenCanvas - - - - - - - - diff --git a/dom/canvas/test/test_offscreencanvas_subworker.html b/dom/canvas/test/test_offscreencanvas_subworker.html deleted file mode 100644 index b3fbae821c9a..000000000000 --- a/dom/canvas/test/test_offscreencanvas_subworker.html +++ /dev/null @@ -1,90 +0,0 @@ - - - -OffscreenCanvas: Test subworkers - - - - - - - - diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp index 218c938b3b9e..f816f39a17c9 100644 --- a/dom/html/HTMLCanvasElement.cpp +++ b/dom/html/HTMLCanvasElement.cpp @@ -19,10 +19,8 @@ #include "mozilla/dom/File.h" #include "mozilla/dom/HTMLCanvasElementBinding.h" #include "mozilla/dom/MouseEvent.h" -#include "mozilla/dom/OffscreenCanvas.h" #include "mozilla/EventDispatcher.h" #include "mozilla/gfx/Rect.h" -#include "mozilla/layers/AsyncCanvasRenderer.h" #include "mozilla/MouseEvents.h" #include "mozilla/Preferences.h" #include "mozilla/Telemetry.h" @@ -241,135 +239,18 @@ HTMLCanvasPrintState::NotifyDone() // --------------------------------------------------------------------------- -HTMLCanvasElementObserver::HTMLCanvasElementObserver(HTMLCanvasElement* aElement) - : mElement(aElement) -{ - RegisterVisibilityChangeEvent(); - RegisterMemoryPressureEvent(); -} - -HTMLCanvasElementObserver::~HTMLCanvasElementObserver() -{ - Destroy(); -} - -void -HTMLCanvasElementObserver::Destroy() -{ - UnregisterMemoryPressureEvent(); - UnregisterVisibilityChangeEvent(); - mElement = nullptr; -} - -void -HTMLCanvasElementObserver::RegisterVisibilityChangeEvent() -{ - if (!mElement) { - return; - } - - nsIDocument* document = mElement->OwnerDoc(); - document->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), - this, true, false); -} - -void -HTMLCanvasElementObserver::UnregisterVisibilityChangeEvent() -{ - if (!mElement) { - return; - } - - nsIDocument* document = mElement->OwnerDoc(); - document->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"), - this, true); -} - -void -HTMLCanvasElementObserver::RegisterMemoryPressureEvent() -{ - if (!mElement) { - return; - } - - nsCOMPtr observerService = - mozilla::services::GetObserverService(); - - MOZ_ASSERT(observerService); - - if (observerService) - observerService->AddObserver(this, "memory-pressure", false); -} - -void -HTMLCanvasElementObserver::UnregisterMemoryPressureEvent() -{ - if (!mElement) { - return; - } - - nsCOMPtr observerService = - mozilla::services::GetObserverService(); - - // Do not assert on observerService here. This might be triggered by - // the cycle collector at a late enough time, that XPCOM services are - // no longer available. See bug 1029504. - if (observerService) - observerService->RemoveObserver(this, "memory-pressure"); -} - -NS_IMETHODIMP -HTMLCanvasElementObserver::Observe(nsISupports*, const char* aTopic, const char16_t*) -{ - if (!mElement || strcmp(aTopic, "memory-pressure")) { - return NS_OK; - } - - mElement->OnMemoryPressure(); - - return NS_OK; -} - -NS_IMETHODIMP -HTMLCanvasElementObserver::HandleEvent(nsIDOMEvent* aEvent) -{ - nsAutoString type; - aEvent->GetType(type); - if (!mElement || !type.EqualsLiteral("visibilitychange")) { - return NS_OK; - } - - mElement->OnVisibilityChange(); - - return NS_OK; -} - -NS_IMPL_ISUPPORTS(HTMLCanvasElementObserver, nsIObserver) - -// --------------------------------------------------------------------------- - HTMLCanvasElement::HTMLCanvasElement(already_AddRefed& aNodeInfo) : nsGenericHTMLElement(aNodeInfo), - mResetLayer(true) , mWriteOnly(false) { } HTMLCanvasElement::~HTMLCanvasElement() { - if (mContextObserver) { - mContextObserver->Destroy(); - mContextObserver = nullptr; - } - ResetPrintCallback(); if (mRequestedFrameRefreshObserver) { mRequestedFrameRefreshObserver->DetachFromRefreshDriver(); } - - if (mAsyncCanvasRenderer) { - mAsyncCanvasRenderer->mHTMLCanvasElement = nullptr; - } } NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement, nsGenericHTMLElement, @@ -391,22 +272,6 @@ HTMLCanvasElement::WrapNode(JSContext* aCx, JS::Handle aGivenProto) return HTMLCanvasElementBinding::Wrap(aCx, this, aGivenProto); } -already_AddRefed -HTMLCanvasElement::CreateContext(CanvasContextType aContextType) -{ - nsRefPtr ret = - CanvasRenderingContextHelper::CreateContext(aContextType); - - // Add Observer for webgl canvas. - if (aContextType == CanvasContextType::WebGL1 || - aContextType == CanvasContextType::WebGL2) { - mContextObserver = new HTMLCanvasElementObserver(this); - } - - ret->SetCanvasElement(this); - return ret.forget(); -} - nsIntSize HTMLCanvasElement::GetWidthHeight() { @@ -691,10 +556,51 @@ HTMLCanvasElement::ExtractData(nsAString& aType, aOptions, GetSize(), mCurrentContext, - mAsyncCanvasRenderer, aStream); } +nsresult +HTMLCanvasElement::ParseParams(JSContext* aCx, + const nsAString& aType, + const JS::Value& aEncoderOptions, + nsAString& aParams, + bool* usingCustomParseOptions) +{ + // Quality parameter is only valid for the image/jpeg MIME type + if (aType.EqualsLiteral("image/jpeg")) { + if (aEncoderOptions.isNumber()) { + double quality = aEncoderOptions.toNumber(); + // Quality must be between 0.0 and 1.0, inclusive + if (quality >= 0.0 && quality <= 1.0) { + aParams.AppendLiteral("quality="); + aParams.AppendInt(NS_lround(quality * 100.0)); + } + } + } + + // If we haven't parsed the aParams check for proprietary options. + // The proprietary option -moz-parse-options will take a image lib encoder + // parse options string as is and pass it to the encoder. + *usingCustomParseOptions = false; + if (aParams.Length() == 0 && aEncoderOptions.isString()) { + NS_NAMED_LITERAL_STRING(mozParseOptions, "-moz-parse-options:"); + nsAutoJSString paramString; + if (!paramString.init(aCx, aEncoderOptions.toString())) { + return NS_ERROR_FAILURE; + } + if (StringBeginsWith(paramString, mozParseOptions)) { + nsDependentSubstring parseOptions = Substring(paramString, + mozParseOptions.Length(), + paramString.Length() - + mozParseOptions.Length()); + aParams.Append(parseOptions); + *usingCustomParseOptions = true; + } + } + + return NS_OK; +} + nsresult HTMLCanvasElement::ToDataURLImpl(JSContext* aCx, const nsAString& aMimeType, @@ -753,38 +659,83 @@ HTMLCanvasElement::ToBlob(JSContext* aCx, return; } + nsAutoString type; + nsContentUtils::ASCIIToLower(aType, type); + + nsAutoString params; + bool usingCustomParseOptions; + aRv = ParseParams(aCx, type, aParams, params, &usingCustomParseOptions); + if (aRv.Failed()) { + return; + } + +#ifdef DEBUG + if (mCurrentContext) { + // We disallow canvases of width or height zero, and set them to 1, so + // we will have a discrepancy with the sizes of the canvas and the context. + // That discrepancy is OK, the rest are not. + nsIntSize elementSize = GetWidthHeight(); + MOZ_ASSERT(elementSize.width == mCurrentContext->GetWidth() || + (elementSize.width == 0 && mCurrentContext->GetWidth() == 1)); + MOZ_ASSERT(elementSize.height == mCurrentContext->GetHeight() || + (elementSize.height == 0 && mCurrentContext->GetHeight() == 1)); + } +#endif + + uint8_t* imageBuffer = nullptr; + int32_t format = 0; + if (mCurrentContext) { + mCurrentContext->GetImageBuffer(&imageBuffer, &format); + } + + // Encoder callback when encoding is complete. + class EncodeCallback : public EncodeCompleteCallback + { + public: + EncodeCallback(nsIGlobalObject* aGlobal, FileCallback* aCallback) + : mGlobal(aGlobal) + , mFileCallback(aCallback) {} + + // This is called on main thread. + nsresult ReceiveBlob(already_AddRefed aBlob) + { + nsRefPtr blob = aBlob; + + ErrorResult rv; + uint64_t size = blob->GetSize(rv); + if (rv.Failed()) { + rv.SuppressException(); + } else { + AutoJSAPI jsapi; + if (jsapi.Init(mGlobal)) { + JS_updateMallocCounter(jsapi.cx(), size); + } + } + + nsRefPtr newBlob = Blob::Create(mGlobal, blob->Impl()); + + mFileCallback->Call(*newBlob, rv); + + mGlobal = nullptr; + mFileCallback = nullptr; + + return rv.StealNSResult(); + } + + nsCOMPtr mGlobal; + nsRefPtr mFileCallback; + }; + nsCOMPtr global = OwnerDoc()->GetScopeObject(); MOZ_ASSERT(global); - - CanvasRenderingContextHelper::ToBlob(aCx, global, aCallback, aType, - aParams, aRv); - -} - -OffscreenCanvas* -HTMLCanvasElement::TransferControlToOffscreen(ErrorResult& aRv) -{ - if (mCurrentContext) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return nullptr; - } - - if (!mOffscreenCanvas) { - nsIntSize sz = GetWidthHeight(); - nsRefPtr renderer = GetAsyncCanvasRenderer(); - renderer->SetWidth(sz.width); - renderer->SetHeight(sz.height); - - mOffscreenCanvas = new OffscreenCanvas(sz.width, - sz.height, - GetCompositorBackendType(), - renderer); - mContextObserver = new HTMLCanvasElementObserver(this); - } else { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - } - - return mOffscreenCanvas; + nsRefPtr callback = new EncodeCallback(global, &aCallback); + aRv = ImageEncoder::ExtractDataAsync(type, + params, + usingCustomParseOptions, + imageBuffer, + format, + GetSize(), + callback); } already_AddRefed @@ -855,6 +806,76 @@ HTMLCanvasElement::MozGetAsBlobImpl(const nsAString& aName, return NS_OK; } +static bool +GetCanvasContextType(const nsAString& str, CanvasContextType* const out_type) +{ + if (str.EqualsLiteral("2d")) { + *out_type = CanvasContextType::Canvas2D; + return true; + } + + if (str.EqualsLiteral("experimental-webgl")) { + *out_type = CanvasContextType::WebGL1; + return true; + } + +#ifdef MOZ_WEBGL_CONFORMANT + if (str.EqualsLiteral("webgl")) { + /* WebGL 1.0, $2.1 "Context Creation": + * If the user agent supports both the webgl and experimental-webgl + * canvas context types, they shall be treated as aliases. + */ + *out_type = CanvasContextType::WebGL1; + return true; + } +#endif + + if (WebGL2Context::IsSupported()) { + if (str.EqualsLiteral("webgl2")) { + *out_type = CanvasContextType::WebGL2; + return true; + } + } + + return false; +} + +static already_AddRefed +CreateContextForCanvas(CanvasContextType contextType, HTMLCanvasElement* canvas) +{ + MOZ_ASSERT(contextType != CanvasContextType::NoContext); + nsRefPtr ret; + + switch (contextType) { + case CanvasContextType::NoContext: + break; + case CanvasContextType::Canvas2D: + Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1); + ret = new CanvasRenderingContext2D(); + break; + + case CanvasContextType::WebGL1: + Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1); + + ret = WebGL1Context::Create(); + if (!ret) + return nullptr; + break; + + case CanvasContextType::WebGL2: + Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1); + + ret = WebGL2Context::Create(); + if (!ret) + return nullptr; + break; + } + MOZ_ASSERT(ret); + + ret->SetCanvasElement(canvas); + return ret.forget(); +} + nsresult HTMLCanvasElement::GetContext(const nsAString& aContextId, nsISupports** aContext) @@ -868,14 +889,45 @@ already_AddRefed HTMLCanvasElement::GetContext(JSContext* aCx, const nsAString& aContextId, JS::Handle aContextOptions, - ErrorResult& aRv) + ErrorResult& rv) { - if (mOffscreenCanvas) { + CanvasContextType contextType; + if (!GetCanvasContextType(aContextId, &contextType)) return nullptr; + + if (!mCurrentContext) { + // This canvas doesn't have a context yet. + + nsRefPtr context; + context = CreateContextForCanvas(contextType, this); + if (!context) + return nullptr; + + // Ensure that the context participates in CC. Note that returning a + // CC participant from QI doesn't addref. + nsXPCOMCycleCollectionParticipant* cp = nullptr; + CallQueryInterface(context, &cp); + if (!cp) { + rv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + mCurrentContext = context.forget(); + mCurrentContextType = contextType; + + rv = UpdateContext(aCx, aContextOptions); + if (rv.Failed()) { + rv = NS_OK; // See bug 645792 + return nullptr; + } + } else { + // We already have a context of some type. + if (contextType != mCurrentContextType) + return nullptr; } - return CanvasRenderingContextHelper::GetContext(aCx, aContextId, - aContextOptions, aRv); + nsCOMPtr context = mCurrentContext; + return context.forget(); } NS_IMETHODIMP @@ -897,7 +949,7 @@ HTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId, // This canvas doesn't have a context yet. nsRefPtr context; - context = CreateContext(contextType); + context = CreateContextForCanvas(contextType, this); if (!context) { *aContext = nullptr; return NS_OK; @@ -919,6 +971,36 @@ HTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId, return NS_OK; } +nsresult +HTMLCanvasElement::UpdateContext(JSContext* aCx, JS::Handle aNewContextOptions) +{ + if (!mCurrentContext) + return NS_OK; + + nsIntSize sz = GetWidthHeight(); + + nsCOMPtr currentContext = mCurrentContext; + + nsresult rv = currentContext->SetIsOpaque(HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque)); + if (NS_FAILED(rv)) { + mCurrentContext = nullptr; + return rv; + } + + rv = currentContext->SetContextOptions(aCx, aNewContextOptions); + if (NS_FAILED(rv)) { + mCurrentContext = nullptr; + return rv; + } + + rv = currentContext->SetDimensions(sz.width, sz.height); + if (NS_FAILED(rv)) { + mCurrentContext = nullptr; + return rv; + } + + return rv; +} nsIntSize HTMLCanvasElement::GetSize() @@ -1022,12 +1104,6 @@ HTMLCanvasElement::GetIsOpaque() return mCurrentContext->GetIsOpaque(); } - return GetOpaqueAttr(); -} - -bool -HTMLCanvasElement::GetOpaqueAttr() -{ return HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque); } @@ -1036,57 +1112,16 @@ HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder, CanvasLayer *aOldLayer, LayerManager *aManager) { - // The address of sOffscreenCanvasLayerUserDataDummy is used as the user - // data key for retained LayerManagers managed by FrameLayerBuilder. - // We don't much care about what value in it, so just assign a dummy - // value for it. - static uint8_t sOffscreenCanvasLayerUserDataDummy = 0; + if (!mCurrentContext) + return nullptr; - if (mCurrentContext) { - return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager); - } - - if (mOffscreenCanvas) { - if (!mResetLayer && - aOldLayer && aOldLayer->HasUserData(&sOffscreenCanvasLayerUserDataDummy)) { - nsRefPtr ret = aOldLayer; - return ret.forget(); - } - - nsRefPtr layer = aManager->CreateCanvasLayer(); - if (!layer) { - NS_WARNING("CreateCanvasLayer failed!"); - return nullptr; - } - - LayerUserData* userData = nullptr; - layer->SetUserData(&sOffscreenCanvasLayerUserDataDummy, userData); - - CanvasLayer::Data data; - data.mRenderer = GetAsyncCanvasRenderer(); - data.mSize = GetWidthHeight(); - layer->Initialize(data); - - layer->Updated(); - return layer.forget(); - } - - return nullptr; + return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager); } bool -HTMLCanvasElement::ShouldForceInactiveLayer(LayerManager* aManager) +HTMLCanvasElement::ShouldForceInactiveLayer(LayerManager *aManager) { - if (mCurrentContext) { - return mCurrentContext->ShouldForceInactiveLayer(aManager); - } - - if (mOffscreenCanvas) { - // TODO: We should handle offscreen canvas case. - return false; - } - - return true; + return !mCurrentContext || mCurrentContext->ShouldForceInactiveLayer(aManager); } void @@ -1201,155 +1236,5 @@ HTMLCanvasElement::GetSurfaceSnapshot(bool* aPremultAlpha) return mCurrentContext->GetSurfaceSnapshot(aPremultAlpha); } -AsyncCanvasRenderer* -HTMLCanvasElement::GetAsyncCanvasRenderer() -{ - if (!mAsyncCanvasRenderer) { - mAsyncCanvasRenderer = new AsyncCanvasRenderer(); - mAsyncCanvasRenderer->mHTMLCanvasElement = this; - } - - return mAsyncCanvasRenderer; -} - -layers::LayersBackend -HTMLCanvasElement::GetCompositorBackendType() const -{ - nsIWidget* docWidget = nsContentUtils::WidgetForDocument(OwnerDoc()); - if (docWidget) { - layers::LayerManager* layerManager = docWidget->GetLayerManager(); - return layerManager->GetCompositorBackendType(); - } - - return LayersBackend::LAYERS_NONE; -} - -void -HTMLCanvasElement::OnVisibilityChange() -{ - if (OwnerDoc()->Hidden()) { - return; - } - - if (mOffscreenCanvas) { - class Runnable final : public nsCancelableRunnable - { - public: - explicit Runnable(AsyncCanvasRenderer* aRenderer) - : mRenderer(aRenderer) - {} - - NS_IMETHOD Run() - { - if (mRenderer && mRenderer->mContext) { - mRenderer->mContext->OnVisibilityChange(); - } - - return NS_OK; - } - - void Revoke() - { - mRenderer = nullptr; - } - - private: - nsRefPtr mRenderer; - }; - - nsRefPtr runnable = new Runnable(mAsyncCanvasRenderer); - nsCOMPtr activeThread = mAsyncCanvasRenderer->GetActiveThread(); - if (activeThread) { - activeThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL); - } - return; - } - - if (mCurrentContext) { - mCurrentContext->OnVisibilityChange(); - } -} - -void -HTMLCanvasElement::OnMemoryPressure() -{ - if (mOffscreenCanvas) { - class Runnable final : public nsCancelableRunnable - { - public: - explicit Runnable(AsyncCanvasRenderer* aRenderer) - : mRenderer(aRenderer) - {} - - NS_IMETHOD Run() - { - if (mRenderer && mRenderer->mContext) { - mRenderer->mContext->OnMemoryPressure(); - } - - return NS_OK; - } - - void Revoke() - { - mRenderer = nullptr; - } - - private: - nsRefPtr mRenderer; - }; - - nsRefPtr runnable = new Runnable(mAsyncCanvasRenderer); - nsCOMPtr activeThread = mAsyncCanvasRenderer->GetActiveThread(); - if (activeThread) { - activeThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL); - } - return; - } - - if (mCurrentContext) { - mCurrentContext->OnMemoryPressure(); - } -} - -/* static */ void -HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer) -{ - HTMLCanvasElement *element = aRenderer->mHTMLCanvasElement; - if (!element) { - return; - } - - if (element->GetWidthHeight() == aRenderer->GetSize()) { - return; - } - - gfx::IntSize asyncCanvasSize = aRenderer->GetSize(); - - ErrorResult rv; - element->SetUnsignedIntAttr(nsGkAtoms::width, asyncCanvasSize.width, rv); - if (rv.Failed()) { - NS_WARNING("Failed to set width attribute to a canvas element asynchronously."); - } - - element->SetUnsignedIntAttr(nsGkAtoms::height, asyncCanvasSize.height, rv); - if (rv.Failed()) { - NS_WARNING("Failed to set height attribute to a canvas element asynchronously."); - } - - element->mResetLayer = true; -} - -/* static */ void -HTMLCanvasElement::InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer) -{ - HTMLCanvasElement *element = aRenderer->mHTMLCanvasElement; - if (!element) { - return; - } - - element->InvalidateCanvasContent(nullptr); -} - } // namespace dom } // namespace mozilla diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h index c149c5aa55d5..dc76df89d903 100644 --- a/dom/html/HTMLCanvasElement.h +++ b/dom/html/HTMLCanvasElement.h @@ -8,27 +8,20 @@ #include "mozilla/Attributes.h" #include "mozilla/WeakPtr.h" -#include "nsIDOMEventListener.h" #include "nsIDOMHTMLCanvasElement.h" -#include "nsIObserver.h" #include "nsGenericHTMLElement.h" #include "nsGkAtoms.h" #include "nsSize.h" #include "nsError.h" -#include "mozilla/dom/CanvasRenderingContextHelper.h" #include "mozilla/gfx/Rect.h" -#include "mozilla/layers/LayersTypes.h" class nsICanvasRenderingContextInternal; class nsITimerCallback; namespace mozilla { -class WebGLContext; - namespace layers { -class AsyncCanvasRenderer; class CanvasLayer; class Image; class LayerManager; @@ -42,33 +35,14 @@ class CanvasCaptureMediaStream; class File; class FileCallback; class HTMLCanvasPrintState; -class OffscreenCanvas; class PrintCallback; class RequestedFrameRefreshObserver; -// Listen visibilitychange and memory-pressure event and inform -// context when event is fired. -class HTMLCanvasElementObserver final : public nsIObserver - , public nsIDOMEventListener -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - NS_DECL_NSIDOMEVENTLISTENER - - explicit HTMLCanvasElementObserver(HTMLCanvasElement* aElement); - void Destroy(); - - void RegisterVisibilityChangeEvent(); - void UnregisterVisibilityChangeEvent(); - - void RegisterMemoryPressureEvent(); - void UnregisterMemoryPressureEvent(); - -private: - ~HTMLCanvasElementObserver(); - - HTMLCanvasElement* mElement; +enum class CanvasContextType : uint8_t { + NoContext, + Canvas2D, + WebGL1, + WebGL2 }; /* @@ -110,15 +84,13 @@ protected: }; class HTMLCanvasElement final : public nsGenericHTMLElement, - public nsIDOMHTMLCanvasElement, - public CanvasRenderingContextHelper + public nsIDOMHTMLCanvasElement { enum { DEFAULT_CANVAS_WIDTH = 300, DEFAULT_CANVAS_HEIGHT = 150 }; - typedef layers::AsyncCanvasRenderer AsyncCanvasRenderer; typedef layers::CanvasLayer CanvasLayer; typedef layers::LayerManager LayerManager; @@ -144,11 +116,6 @@ public: } void SetHeight(uint32_t aHeight, ErrorResult& aRv) { - if (mOffscreenCanvas) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - SetUnsignedIntAttr(nsGkAtoms::height, aHeight, aRv); } uint32_t Width() @@ -157,45 +124,30 @@ public: } void SetWidth(uint32_t aWidth, ErrorResult& aRv) { - if (mOffscreenCanvas) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - SetUnsignedIntAttr(nsGkAtoms::width, aWidth, aRv); } - - virtual already_AddRefed + already_AddRefed GetContext(JSContext* aCx, const nsAString& aContextId, JS::Handle aContextOptions, - ErrorResult& aRv) override; - + ErrorResult& aRv); void ToDataURL(JSContext* aCx, const nsAString& aType, JS::Handle aParams, nsAString& aDataURL, ErrorResult& aRv) { aRv = ToDataURL(aType, aParams, aCx, aDataURL); } - void ToBlob(JSContext* aCx, FileCallback& aCallback, const nsAString& aType, JS::Handle aParams, ErrorResult& aRv); - OffscreenCanvas* TransferControlToOffscreen(ErrorResult& aRv); - bool MozOpaque() const { return GetBoolAttr(nsGkAtoms::moz_opaque); } void SetMozOpaque(bool aValue, ErrorResult& aRv) { - if (mOffscreenCanvas) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - SetHTMLBoolAttr(nsGkAtoms::moz_opaque, aValue, aRv); } already_AddRefed MozGetAsFile(const nsAString& aName, @@ -252,7 +204,6 @@ public: * across its entire area. */ bool GetIsOpaque(); - virtual bool GetOpaqueAttr() override; virtual already_AddRefed GetSurfaceSnapshot(bool* aPremultAlpha = nullptr); @@ -331,25 +282,19 @@ public: nsresult GetContext(const nsAString& aContextId, nsISupports** aContext); - layers::LayersBackend GetCompositorBackendType() const; - - void OnVisibilityChange(); - - void OnMemoryPressure(); - - static void SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer); - static void InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer); - protected: virtual ~HTMLCanvasElement(); virtual JSObject* WrapNode(JSContext* aCx, JS::Handle aGivenProto) override; - virtual nsIntSize GetWidthHeight() override; - - virtual already_AddRefed - CreateContext(CanvasContextType aContextType) override; + nsIntSize GetWidthHeight(); + nsresult UpdateContext(JSContext* aCx, JS::Handle options); + nsresult ParseParams(JSContext* aCx, + const nsAString& aType, + const JS::Value& aEncoderOptions, + nsAString& aParams, + bool* usingCustomParseOptions); nsresult ExtractData(nsAString& aType, const nsAString& aOptions, nsIInputStream** aStream); @@ -362,17 +307,13 @@ protected: nsISupports** aResult); void CallPrintCallback(); - AsyncCanvasRenderer* GetAsyncCanvasRenderer(); - - bool mResetLayer; + CanvasContextType mCurrentContextType; nsRefPtr mOriginalCanvas; nsRefPtr mPrintCallback; + nsCOMPtr mCurrentContext; nsRefPtr mPrintState; nsTArray> mRequestedFrameListeners; nsRefPtr mRequestedFrameRefreshObserver; - nsRefPtr mAsyncCanvasRenderer; - nsRefPtr mOffscreenCanvas; - nsRefPtr mContextObserver; public: // Record whether this canvas should be write-only or not. diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 5ebd8541fccd..948e8cb943f6 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -872,8 +872,6 @@ var interfaceNamesInGlobalScope = "Notification", // IMPORTANT: Do not change this list without review from a DOM peer! "NotifyPaintEvent", -// IMPORTANT: Do not change this list without review from a DOM peer! - {name: "OffscreenCanvas", disabled: true}, // IMPORTANT: Do not change this list without review from a DOM peer! "OfflineAudioCompletionEvent", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/webidl/HTMLCanvasElement.webidl b/dom/webidl/HTMLCanvasElement.webidl index dde7841a5e0b..18d46edf8b5a 100644 --- a/dom/webidl/HTMLCanvasElement.webidl +++ b/dom/webidl/HTMLCanvasElement.webidl @@ -46,13 +46,6 @@ partial interface HTMLCanvasElement { CanvasCaptureMediaStream captureStream(optional double frameRate); }; -// For OffscreenCanvas -// Reference: https://wiki.whatwg.org/wiki/OffscreenCanvas -partial interface HTMLCanvasElement { - [Pref="gfx.offscreencanvas.enabled", Throws] - OffscreenCanvas transferControlToOffscreen(); -}; - [ChromeOnly] interface MozCanvasPrintState { diff --git a/dom/webidl/OffscreenCanvas.webidl b/dom/webidl/OffscreenCanvas.webidl deleted file mode 100644 index 592ac6e14fe6..000000000000 --- a/dom/webidl/OffscreenCanvas.webidl +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * For more information on this interface, please see - * https://wiki.whatwg.org/wiki/OffscreenCanvas - * - * Current implementation focus on transfer canvas from main thread to worker. - * So there are some spec doesn't implement, such as [Constructor], toBlob() and - * transferToImageBitmap in OffscreenCanvas. Bug 1172796 will implement - * remaining spec. - */ - -[Exposed=(Window,Worker), - Func="mozilla::dom::OffscreenCanvas::PrefEnabled"] -interface OffscreenCanvas : EventTarget { - [Pure, SetterThrows] - attribute unsigned long width; - [Pure, SetterThrows] - attribute unsigned long height; - - [Throws] - nsISupports? getContext(DOMString contextId, - optional any contextOptions = null); -}; - -// OffscreenCanvas implements Transferable; diff --git a/dom/webidl/WebGLRenderingContext.webidl b/dom/webidl/WebGLRenderingContext.webidl index 3ab31d10a372..1421a0020f8e 100644 --- a/dom/webidl/WebGLRenderingContext.webidl +++ b/dom/webidl/WebGLRenderingContext.webidl @@ -45,38 +45,24 @@ dictionary WebGLContextAttributes { boolean failIfMajorPerformanceCaveat = false; }; -[Exposed=(Window,Worker), - Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLBuffer { }; -[Exposed=(Window,Worker), - Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLFramebuffer { }; -[Exposed=(Window,Worker), - Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLProgram { }; -[Exposed=(Window,Worker), - Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLRenderbuffer { }; -[Exposed=(Window,Worker), - Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLShader { }; -[Exposed=(Window,Worker), - Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLTexture { }; -[Exposed=(Window,Worker), - Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLUniformLocation { }; @@ -84,24 +70,18 @@ interface WebGLUniformLocation { interface WebGLVertexArrayObjectOES { }; -[Exposed=(Window,Worker), - Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLActiveInfo { readonly attribute GLint size; readonly attribute GLenum type; readonly attribute DOMString name; }; -[Exposed=(Window,Worker), - Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLShaderPrecisionFormat { readonly attribute GLint rangeMin; readonly attribute GLint rangeMax; readonly attribute GLint precision; }; -[Exposed=(Window,Worker), - Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"] interface WebGLRenderingContext { /* ClearBufferMask */ @@ -524,7 +504,7 @@ interface WebGLRenderingContext { const GLenum BROWSER_DEFAULT_WEBGL = 0x9244; // The canvas might actually be null in some cases, apparently. - readonly attribute (HTMLCanvasElement or OffscreenCanvas)? canvas; + readonly attribute HTMLCanvasElement? canvas; readonly attribute GLsizei drawingBufferWidth; readonly attribute GLsizei drawingBufferHeight; @@ -786,14 +766,6 @@ interface WebGLRenderingContext { void viewport(GLint x, GLint y, GLsizei width, GLsizei height); }; -// For OffscreenCanvas -// Reference: https://wiki.whatwg.org/wiki/OffscreenCanvas -[Exposed=(Window,Worker)] -partial interface WebGLRenderingContext { - [Func="mozilla::dom::OffscreenCanvas::PrefEnabled"] - void commit(); -}; - /*[Constructor(DOMString type, optional WebGLContextEventInit eventInit)] interface WebGLContextEvent : Event { readonly attribute DOMString statusMessage; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 17c7d0be3224..0477391a4eb3 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -344,7 +344,6 @@ WEBIDL_FILES = [ 'OfflineAudioCompletionEvent.webidl', 'OfflineAudioContext.webidl', 'OfflineResourceList.webidl', - 'OffscreenCanvas.webidl', 'OscillatorNode.webidl', 'PaintRequest.webidl', 'PaintRequestList.webidl', diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 7a1749558d59..d4c683be6949 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -170,7 +170,6 @@ static_assert(MAX_WORKERS_PER_DOMAIN >= 1, #define PREF_INTERCEPTION_OPAQUE_ENABLED "dom.serviceWorkers.interception.opaque.enabled" #define PREF_PUSH_ENABLED "dom.push.enabled" #define PREF_REQUESTCONTEXT_ENABLED "dom.requestcontext.enabled" -#define PREF_OFFSCREENCANVAS_ENABLED "gfx.offscreencanvas.enabled" namespace { @@ -1971,10 +1970,6 @@ RuntimeService::Init() WorkerPrefChanged, PREF_REQUESTCONTEXT_ENABLED, reinterpret_cast(WORKERPREF_REQUESTCONTEXT))) || - NS_FAILED(Preferences::RegisterCallbackAndCall( - WorkerPrefChanged, - PREF_OFFSCREENCANVAS_ENABLED, - reinterpret_cast(WORKERPREF_OFFSCREENCANVAS))) || NS_FAILED(Preferences::RegisterCallback(LoadRuntimeOptions, PREF_JS_OPTIONS_PREFIX, nullptr)) || @@ -2214,10 +2209,6 @@ RuntimeService::Cleanup() WorkerPrefChanged, PREF_REQUESTCONTEXT_ENABLED, reinterpret_cast(WORKERPREF_REQUESTCONTEXT))) || - NS_FAILED(Preferences::UnregisterCallback( - WorkerPrefChanged, - PREF_OFFSCREENCANVAS_ENABLED, - reinterpret_cast(WORKERPREF_OFFSCREENCANVAS))) || #if DUMP_CONTROLLED_BY_PREF NS_FAILED(Preferences::UnregisterCallback( WorkerPrefChanged, @@ -2779,7 +2770,6 @@ RuntimeService::WorkerPrefChanged(const char* aPrefName, void* aClosure) case WORKERPREF_SERVICEWORKERS_TESTING: case WORKERPREF_PUSH: case WORKERPREF_REQUESTCONTEXT: - case WORKERPREF_OFFSCREENCANVAS: sDefaultPreferences[key] = Preferences::GetBool(aPrefName, false); break; diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 79c98411a819..d11e97f45409 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -1313,13 +1313,6 @@ public: return mPreferences[WORKERPREF_REQUESTCONTEXT]; } - bool - OffscreenCanvasEnabled() const - { - AssertIsOnWorkerThread(); - return mPreferences[WORKERPREF_OFFSCREENCANVAS]; - } - bool OnLine() const { diff --git a/dom/workers/Workers.h b/dom/workers/Workers.h index 95e0ebd82906..7ac053c3a258 100644 --- a/dom/workers/Workers.h +++ b/dom/workers/Workers.h @@ -209,7 +209,6 @@ enum WorkerPreference WORKERPREF_PERFORMANCE_LOGGING_ENABLED, // dom.performance.enable_user_timing_logging WORKERPREF_PUSH, // dom.push.enabled WORKERPREF_REQUESTCONTEXT, // dom.requestcontext.enabled - WORKERPREF_OFFSCREENCANVAS, // gfx.offscreencanvas.enabled WORKERPREF_COUNT }; diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js index 506669c09fde..1af06353495e 100644 --- a/dom/workers/test/test_worker_interfaces.js +++ b/dom/workers/test/test_worker_interfaces.js @@ -155,8 +155,6 @@ var interfaceNamesInGlobalScope = "MessagePort", // IMPORTANT: Do not change this list without review from a DOM peer! "Notification", -// IMPORTANT: Do not change this list without review from a DOM peer! - { name: "OffscreenCanvas", disabled: true }, // IMPORTANT: Do not change this list without review from a DOM peer! "Performance", // IMPORTANT: Do not change this list without review from a DOM peer! @@ -191,26 +189,6 @@ var interfaceNamesInGlobalScope = "URL", // IMPORTANT: Do not change this list without review from a DOM peer! "URLSearchParams", -// IMPORTANT: Do not change this list without review from a DOM peer! - { name: "WebGLActiveInfo", disabled: true }, -// IMPORTANT: Do not change this list without review from a DOM peer! - { name: "WebGLBuffer", disabled: true }, -// IMPORTANT: Do not change this list without review from a DOM peer! - { name: "WebGLFramebuffer", disabled: true }, -// IMPORTANT: Do not change this list without review from a DOM peer! - { name: "WebGLProgram", disabled: true }, -// IMPORTANT: Do not change this list without review from a DOM peer! - { name: "WebGLRenderbuffer", disabled: true }, -// IMPORTANT: Do not change this list without review from a DOM peer! - { name: "WebGLRenderingContext", disabled: true }, -// IMPORTANT: Do not change this list without review from a DOM peer! - { name: "WebGLShader", disabled: true }, -// IMPORTANT: Do not change this list without review from a DOM peer! - { name: "WebGLShaderPrecisionFormat", disabled: true }, -// IMPORTANT: Do not change this list without review from a DOM peer! - { name: "WebGLTexture", disabled: true }, -// IMPORTANT: Do not change this list without review from a DOM peer! - { name: "WebGLUniformLocation", disabled: true }, // IMPORTANT: Do not change this list without review from a DOM peer! "WebSocket", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index ef0ce36053c4..5a1172ecfcdb 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -2650,7 +2650,6 @@ GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest) } GLuint tempFB = 0; - GLuint tempTex = 0; { ScopedBindFramebuffer autoFB(this); @@ -2682,24 +2681,6 @@ GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest) MOZ_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE); } - if (src->NeedsIndirectReads()) { - fGenTextures(1, &tempTex); - { - ScopedBindTexture autoTex(this, tempTex); - - GLenum format = src->mHasAlpha ? LOCAL_GL_RGBA - : LOCAL_GL_RGB; - auto width = src->mSize.width; - auto height = src->mSize.height; - fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, format, 0, 0, width, - height, 0); - } - - fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_TEXTURE_2D, tempTex, 0); - } - ReadPixelsIntoDataSurface(this, dest); src->ProducerReadRelease(); @@ -2708,10 +2689,6 @@ GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest) if (tempFB) fDeleteFramebuffers(1, &tempFB); - if (tempTex) { - fDeleteTextures(1, &tempTex); - } - if (needsSwap) { src->UnlockProd(); if (prev) diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp index a78be99d7f16..42d7b95f51cd 100644 --- a/gfx/gl/GLLibraryEGL.cpp +++ b/gfx/gl/GLLibraryEGL.cpp @@ -5,7 +5,6 @@ #include "GLLibraryEGL.h" #include "gfxCrashReporterUtils.h" -#include "gfxUtils.h" #include "mozilla/Preferences.h" #include "mozilla/Assertions.h" #include "nsDirectoryServiceDefs.h" @@ -15,17 +14,13 @@ #ifdef XP_WIN #include "nsWindowsHelpers.h" #endif -#include "OGLShaderProgram.h" #include "prenv.h" #include "GLContext.h" -#include "GLContextProvider.h" #include "gfxPrefs.h" -#include "ScopedGLHelpers.h" namespace mozilla { namespace gl { -StaticMutex GLLibraryEGL::sMutex; GLLibraryEGL sEGLLibrary; #ifdef MOZ_B2G ThreadLocal GLLibraryEGL::sCurrentContext; @@ -133,9 +128,7 @@ static bool IsAccelAngleSupported(const nsCOMPtr& gfxInfo) { int32_t angleSupport; - gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, - nsIGfxInfo::FEATURE_WEBGL_ANGLE, - &angleSupport); + gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBGL_ANGLE, &angleSupport); return (angleSupport == nsIGfxInfo::FEATURE_STATUS_OK); } @@ -152,32 +145,6 @@ GetAndInitDisplay(GLLibraryEGL& egl, void* displayType) return display; } -bool -GLLibraryEGL::ReadbackEGLImage(EGLImage image, gfx::DataSourceSurface* out_surface) -{ - StaticMutexAutoUnlock lock(sMutex); - if (!mReadbackGL) { - mReadbackGL = gl::GLContextProvider::CreateHeadless(gl::CreateContextFlags::NONE); - } - - ScopedTexture destTex(mReadbackGL); - const GLuint target = LOCAL_GL_TEXTURE_EXTERNAL; - ScopedBindTexture autoTex(mReadbackGL, destTex.Texture(), target); - mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); - mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); - mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST); - mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST); - mReadbackGL->fEGLImageTargetTexture2D(target, image); - - ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(target, - out_surface->GetFormat()); - int shaderConfig = config.mFeatures; - mReadbackGL->ReadTexImageHelper()->ReadTexImage(out_surface, 0, target, - out_surface->GetSize(), shaderConfig); - - return true; -} - bool GLLibraryEGL::EnsureInitialized(bool forceAccel) { diff --git a/gfx/gl/GLLibraryEGL.h b/gfx/gl/GLLibraryEGL.h index 1f42a951a758..37ccc3d9d232 100644 --- a/gfx/gl/GLLibraryEGL.h +++ b/gfx/gl/GLLibraryEGL.h @@ -10,7 +10,6 @@ #endif #include "GLLibraryLoader.h" -#include "mozilla/StaticMutex.h" #include "mozilla/ThreadLocal.h" #include "nsIFile.h" #include "GeckoProfiler.h" @@ -53,11 +52,6 @@ #endif namespace mozilla { - -namespace gfx { -class DataSourceSurface; -} - namespace gl { #undef BEFORE_GL_CALL @@ -100,8 +94,6 @@ namespace gl { #define AFTER_GL_CALL #endif -class GLContext; - class GLLibraryEGL { public: @@ -486,8 +478,6 @@ public: return IsExtensionSupported(EXT_create_context_robustness); } - bool ReadbackEGLImage(EGLImage image, gfx::DataSourceSurface* out_surface); - bool EnsureInitialized(bool forceAccel = false); void DumpEGLConfig(EGLConfig cfg); @@ -613,11 +603,9 @@ private: bool mInitialized; PRLibrary* mEGLLibrary; EGLDisplay mEGLDisplay; - RefPtr mReadbackGL; bool mIsANGLE; bool mIsWARP; - static StaticMutex sMutex; }; extern GLLibraryEGL sEGLLibrary; diff --git a/gfx/gl/GLReadTexImageHelper.cpp b/gfx/gl/GLReadTexImageHelper.cpp index 7e43d8b350b1..d93b4914937f 100644 --- a/gfx/gl/GLReadTexImageHelper.cpp +++ b/gfx/gl/GLReadTexImageHelper.cpp @@ -214,7 +214,7 @@ GetActualReadFormats(GLContext* gl, } } -void +static void SwapRAndBComponents(DataSourceSurface* surf) { DataSourceSurface::MappedSurface map; @@ -533,8 +533,8 @@ ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest) #endif } -already_AddRefed -YInvertImageSurface(gfx::DataSourceSurface* aSurf) +static already_AddRefed +YInvertImageSurface(DataSourceSurface* aSurf) { RefPtr temp = Factory::CreateDataSourceSurfaceWithStride(aSurf->GetSize(), @@ -560,8 +560,8 @@ YInvertImageSurface(gfx::DataSourceSurface* aSurf) return nullptr; } - dt->SetTransform(Matrix::Scaling(1.0, -1.0) * - Matrix::Translation(0.0, aSurf->GetSize().height)); + dt->SetTransform(Matrix::Translation(0.0, aSurf->GetSize().height) * + Matrix::Scaling(1.0, -1.0)); Rect rect(0, 0, aSurf->GetSize().width, aSurf->GetSize().height); dt->DrawSurface(aSurf, rect, rect, DrawSurfaceOptions(), DrawOptions(1.0, CompositionOp::OP_SOURCE, AntialiasMode::NONE)); @@ -614,7 +614,8 @@ ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, SurfaceFormat aFo #define CLEANUP_IF_GLERROR_OCCURRED(x) \ if (DidGLErrorOccur(x)) { \ - return false; \ + isurf = nullptr; \ + break; \ } already_AddRefed @@ -623,31 +624,6 @@ GLReadTexImageHelper::ReadTexImage(GLuint aTextureId, const gfx::IntSize& aSize, /* ShaderConfigOGL.mFeature */ int aConfig, bool aYInvert) -{ - /* Allocate resulting image surface */ - int32_t stride = aSize.width * BytesPerPixel(SurfaceFormat::R8G8B8A8); - RefPtr isurf = - Factory::CreateDataSourceSurfaceWithStride(aSize, - SurfaceFormat::R8G8B8A8, - stride); - if (NS_WARN_IF(!isurf)) { - return nullptr; - } - - if (!ReadTexImage(isurf, aTextureId, aTextureTarget, aSize, aConfig, aYInvert)) { - return nullptr; - } - - return isurf.forget(); -} - -bool -GLReadTexImageHelper::ReadTexImage(DataSourceSurface* aDest, - GLuint aTextureId, - GLenum aTextureTarget, - const gfx::IntSize& aSize, - /* ShaderConfigOGL.mFeature */ int aConfig, - bool aYInvert) { MOZ_ASSERT(aTextureTarget == LOCAL_GL_TEXTURE_2D || aTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL || @@ -655,6 +631,16 @@ GLReadTexImageHelper::ReadTexImage(DataSourceSurface* aDest, mGL->MakeCurrent(); + /* Allocate resulting image surface */ + int32_t stride = aSize.width * BytesPerPixel(SurfaceFormat::R8G8B8A8); + RefPtr isurf = + Factory::CreateDataSourceSurfaceWithStride(aSize, + SurfaceFormat::R8G8B8A8, + stride); + if (NS_WARN_IF(!isurf)) { + return nullptr; + } + GLint oldrb, oldfb, oldprog, oldTexUnit, oldTex; GLuint rb, fb; @@ -751,7 +737,7 @@ GLReadTexImageHelper::ReadTexImage(DataSourceSurface* aDest, CLEANUP_IF_GLERROR_OCCURRED("when drawing texture"); /* Read-back draw results */ - ReadPixelsIntoDataSurface(mGL, aDest); + ReadPixelsIntoDataSurface(mGL, isurf); CLEANUP_IF_GLERROR_OCCURRED("when reading pixels into surface"); } while (false); @@ -770,7 +756,7 @@ GLReadTexImageHelper::ReadTexImage(DataSourceSurface* aDest, if (oldTexUnit != LOCAL_GL_TEXTURE0) mGL->fActiveTexture(oldTexUnit); - return true; + return isurf.forget(); } #undef CLEANUP_IF_GLERROR_OCCURRED diff --git a/gfx/gl/GLReadTexImageHelper.h b/gfx/gl/GLReadTexImageHelper.h index 685afcf270c1..821c003a96a1 100644 --- a/gfx/gl/GLReadTexImageHelper.h +++ b/gfx/gl/GLReadTexImageHelper.h @@ -34,12 +34,6 @@ void ReadPixelsIntoDataSurface(GLContext* aGL, already_AddRefed ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat); -already_AddRefed -YInvertImageSurface(gfx::DataSourceSurface* aSurf); - -void -SwapRAndBComponents(gfx::DataSourceSurface* surf); - class GLReadTexImageHelper final { // The GLContext is the sole owner of the GLBlitHelper. @@ -71,17 +65,12 @@ public: * passed as int to eliminate including LayerManagerOGLProgram.h here. */ already_AddRefed ReadTexImage(GLuint aTextureId, - GLenum aTextureTarget, - const gfx::IntSize& aSize, - /* ShaderProgramType */ int aShaderProgram, - bool aYInvert = false); + GLenum aTextureTarget, + const gfx::IntSize& aSize, + /* ShaderProgramType */ int aShaderProgram, + bool aYInvert = false); + - bool ReadTexImage(gfx::DataSourceSurface* aDest, - GLuint aTextureId, - GLenum aTextureTarget, - const gfx::IntSize& aSize, - int aShaderProgram, - bool aYInvert = false); }; } // namespace gl diff --git a/gfx/gl/GLScreenBuffer.cpp b/gfx/gl/GLScreenBuffer.cpp index f6490911d2af..d02876868ee2 100755 --- a/gfx/gl/GLScreenBuffer.cpp +++ b/gfx/gl/GLScreenBuffer.cpp @@ -10,32 +10,18 @@ #include "GLContext.h" #include "GLBlitHelper.h" #include "GLReadTexImageHelper.h" -#include "SharedSurfaceEGL.h" #include "SharedSurfaceGL.h" -#include "ScopedGLHelpers.h" -#include "gfx2DGlue.h" -#include "../layers/ipc/ShadowLayers.h" -#include "mozilla/layers/CompositableForwarder.h" -#include "mozilla/layers/TextureClientSharedSurface.h" - -#ifdef XP_WIN -#include "SharedSurfaceANGLE.h" // for SurfaceFactory_ANGLEShareHandle -#include "gfxWindowsPlatform.h" -#endif - #ifdef MOZ_WIDGET_GONK #include "SharedSurfaceGralloc.h" #include "nsXULAppAPI.h" #endif - #ifdef XP_MACOSX #include "SharedSurfaceIO.h" #endif - -#ifdef GL_PROVIDER_GLX -#include "GLXLibrary.h" -#include "SharedSurfaceGLX.h" -#endif +#include "ScopedGLHelpers.h" +#include "gfx2DGlue.h" +#include "../layers/ipc/ShadowLayers.h" +#include "mozilla/layers/TextureClientSharedSurface.h" namespace mozilla { namespace gl { @@ -65,53 +51,6 @@ GLScreenBuffer::Create(GLContext* gl, return Move(ret); } -/* static */ UniquePtr -GLScreenBuffer::CreateFactory(GLContext* gl, - const SurfaceCaps& caps, - const RefPtr& forwarder, - const layers::TextureFlags& flags) -{ - UniquePtr factory = nullptr; - if (!gfxPrefs::WebGLForceLayersReadback()) { - switch (forwarder->GetCompositorBackendType()) { - case mozilla::layers::LayersBackend::LAYERS_OPENGL: { -#if defined(XP_MACOSX) - factory = SurfaceFactory_IOSurface::Create(gl, caps, forwarder, flags); -#elif defined(MOZ_WIDGET_GONK) - factory = MakeUnique(gl, caps, forwarder, flags); -#elif defined(GL_PROVIDER_GLX) - if (sGLXLibrary.UseSurfaceSharing()) - factory = SurfaceFactory_GLXDrawable::Create(gl, caps, forwarder, flags); -#else - if (gl->GetContextType() == GLContextType::EGL) { - if (XRE_IsParentProcess()) { - factory = SurfaceFactory_EGLImage::Create(gl, caps, forwarder, flags); - } - } -#endif - break; - } - case mozilla::layers::LayersBackend::LAYERS_D3D11: { -#ifdef XP_WIN - // Enable surface sharing only if ANGLE and compositing devices - // are both WARP or both not WARP - if (gl->IsANGLE() && - (gl->IsWARP() == gfxWindowsPlatform::GetPlatform()->IsWARP()) && - gfxWindowsPlatform::GetPlatform()->CompositorD3D11TextureSharingWorks()) - { - factory = SurfaceFactory_ANGLEShareHandle::Create(gl, caps, forwarder, flags); - } -#endif - break; - } - default: - break; - } - } - - return factory; -} - GLScreenBuffer::GLScreenBuffer(GLContext* gl, const SurfaceCaps& caps, UniquePtr factory) diff --git a/gfx/gl/GLScreenBuffer.h b/gfx/gl/GLScreenBuffer.h index 2b31500cebfb..15edad69250b 100644 --- a/gfx/gl/GLScreenBuffer.h +++ b/gfx/gl/GLScreenBuffer.h @@ -25,7 +25,6 @@ namespace mozilla { namespace layers { -class CompositableForwarder; class SharedSurfaceTextureClient; } // namespace layers @@ -134,12 +133,6 @@ public: const gfx::IntSize& size, const SurfaceCaps& caps); - static UniquePtr - CreateFactory(GLContext* gl, - const SurfaceCaps& caps, - const RefPtr& forwarder, - const layers::TextureFlags& flags); - protected: GLContext* const mGL; // Owns us. public: diff --git a/gfx/gl/SharedSurface.cpp b/gfx/gl/SharedSurface.cpp index 5631be1772e3..634cc794a731 100644 --- a/gfx/gl/SharedSurface.cpp +++ b/gfx/gl/SharedSurface.cpp @@ -311,7 +311,6 @@ SurfaceFactory::SurfaceFactory(SharedSurfaceType type, GLContext* gl, , mAllocator(allocator) , mFlags(flags) , mFormats(gl->ChooseGLFormats(caps)) - , mMutex("SurfaceFactor::mMutex") { ChooseBufferBits(mCaps, &mDrawCaps, &mReadCaps); } @@ -369,7 +368,6 @@ SurfaceFactory::StartRecycling(layers::SharedSurfaceTextureClient* tc) void SurfaceFactory::StopRecycling(layers::SharedSurfaceTextureClient* tc) { - MutexAutoLock autoLock(mMutex); // Must clear before releasing ref. tc->ClearRecycleCallback(); @@ -381,8 +379,11 @@ SurfaceFactory::StopRecycling(layers::SharedSurfaceTextureClient* tc) /*static*/ void SurfaceFactory::RecycleCallback(layers::TextureClient* rawTC, void* rawFactory) { + MOZ_ASSERT(NS_IsMainThread()); + RefPtr tc; tc = static_cast(rawTC); + SurfaceFactory* factory = static_cast(rawFactory); if (tc->mSurf->mCanRecycle) { @@ -398,7 +399,6 @@ bool SurfaceFactory::Recycle(layers::SharedSurfaceTextureClient* texClient) { MOZ_ASSERT(texClient); - MutexAutoLock autoLock(mMutex); if (mRecycleFreePool.size() >= 2) { return false; diff --git a/gfx/gl/SharedSurface.h b/gfx/gl/SharedSurface.h index 0e98689acf01..8c25ac7063d1 100644 --- a/gfx/gl/SharedSurface.h +++ b/gfx/gl/SharedSurface.h @@ -24,7 +24,6 @@ #include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" #include "mozilla/gfx/Point.h" -#include "mozilla/Mutex.h" #include "mozilla/UniquePtr.h" #include "mozilla/WeakPtr.h" #include "ScopedGLHelpers.h" @@ -34,7 +33,6 @@ class nsIThread; namespace mozilla { namespace gfx { -class DataSourceSurface; class DrawTarget; } // namespace gfx @@ -201,10 +199,6 @@ public: } virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) = 0; - - virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) { - return false; - } }; template @@ -304,7 +298,6 @@ public: const RefPtr mAllocator; const layers::TextureFlags mFlags; const GLFormats mFormats; - Mutex mMutex; protected: SurfaceCaps mDrawCaps; SurfaceCaps mReadCaps; diff --git a/gfx/gl/SharedSurfaceANGLE.cpp b/gfx/gl/SharedSurfaceANGLE.cpp index 9b8c444f6d7f..381ba8ee8dda 100644 --- a/gfx/gl/SharedSurfaceANGLE.cpp +++ b/gfx/gl/SharedSurfaceANGLE.cpp @@ -273,138 +273,6 @@ SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor(layers::SurfaceDescriptor* c return true; } -class ScopedLockTexture final -{ -public: - explicit ScopedLockTexture(ID3D11Texture2D* texture, bool* succeeded) - : mIsLocked(false) - , mTexture(texture) - { - MOZ_ASSERT(mTexture); - MOZ_ASSERT(succeeded); - *succeeded = false; - - HRESULT hr; - mTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mMutex)); - if (mMutex) { - hr = mMutex->AcquireSync(0, 10000); - if (hr == WAIT_TIMEOUT) { - MOZ_CRASH(); - } - - if (FAILED(hr)) { - NS_WARNING("Failed to lock the texture"); - return; - } - } - - ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11Device(); - device->GetImmediateContext(byRef(mDeviceContext)); - - mTexture->GetDesc(&mDesc); - mDesc.BindFlags = 0; - mDesc.Usage = D3D11_USAGE_STAGING; - mDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - mDesc.MiscFlags = 0; - - hr = device->CreateTexture2D(&mDesc, nullptr, byRef(mCopiedTexture)); - - if (FAILED(hr)) { - return; - } - - mDeviceContext->CopyResource(mCopiedTexture, mTexture); - - hr = mDeviceContext->Map(mCopiedTexture, 0, D3D11_MAP_READ, 0, &mSubresource); - if (FAILED(hr)) { - return; - } - - *succeeded = true; - mIsLocked = true; - } - - ~ScopedLockTexture() - { - mDeviceContext->Unmap(mCopiedTexture, 0); - if (mMutex) { - HRESULT hr = mMutex->ReleaseSync(0); - if (FAILED(hr)) { - NS_WARNING("Failed to unlock the texture"); - } - } - mIsLocked = false; - } - - bool mIsLocked; - RefPtr mTexture; - RefPtr mCopiedTexture; - RefPtr mMutex; - RefPtr mDeviceContext; - D3D11_TEXTURE2D_DESC mDesc; - D3D11_MAPPED_SUBRESOURCE mSubresource; -}; - -bool -SharedSurface_ANGLEShareHandle::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) -{ - MOZ_ASSERT(out_surface); - RefPtr tex; - ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11Device(); - HRESULT hr = device->OpenSharedResource(mShareHandle, - __uuidof(ID3D11Texture2D), - (void**)(ID3D11Texture2D**)byRef(tex)); - - if (FAILED(hr)) { - return false; - } - - bool succeeded = false; - ScopedLockTexture scopedLock(tex, &succeeded); - if (!succeeded) { - return false; - } - - const uint8_t* data = reinterpret_cast(scopedLock.mSubresource.pData); - uint32_t srcStride = scopedLock.mSubresource.RowPitch; - - gfx::DataSourceSurface::ScopedMap map(out_surface, gfx::DataSourceSurface::WRITE); - if (!map.IsMapped()) { - return false; - } - - if (map.GetStride() == srcStride) { - memcpy(map.GetData(), data, out_surface->GetSize().height * map.GetStride()); - } else { - const uint8_t bytesPerPixel = BytesPerPixel(out_surface->GetFormat()); - for (int32_t i = 0; i < out_surface->GetSize().height; i++) { - memcpy(map.GetData() + i * map.GetStride(), - data + i * srcStride, - bytesPerPixel * out_surface->GetSize().width); - } - } - - DXGI_FORMAT srcFormat = scopedLock.mDesc.Format; - MOZ_ASSERT(srcFormat == DXGI_FORMAT_B8G8R8A8_UNORM || - srcFormat == DXGI_FORMAT_B8G8R8X8_UNORM || - srcFormat == DXGI_FORMAT_R8G8B8A8_UNORM); - bool isSrcRGB = srcFormat == DXGI_FORMAT_R8G8B8A8_UNORM; - - gfx::SurfaceFormat destFormat = out_surface->GetFormat(); - MOZ_ASSERT(destFormat == gfx::SurfaceFormat::R8G8B8X8 || - destFormat == gfx::SurfaceFormat::R8G8B8A8 || - destFormat == gfx::SurfaceFormat::B8G8R8X8 || - destFormat == gfx::SurfaceFormat::B8G8R8A8); - bool isDestRGB = destFormat == gfx::SurfaceFormat::R8G8B8X8 || - destFormat == gfx::SurfaceFormat::R8G8B8A8; - - if (isSrcRGB != isDestRGB) { - SwapRAndBComponents(out_surface); - } - - return true; -} - //////////////////////////////////////////////////////////////////////////////// // Factory diff --git a/gfx/gl/SharedSurfaceANGLE.h b/gfx/gl/SharedSurfaceANGLE.h index f37b50ed9881..3dcab9d04332 100644 --- a/gfx/gl/SharedSurfaceANGLE.h +++ b/gfx/gl/SharedSurfaceANGLE.h @@ -81,8 +81,6 @@ public: } virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override; - - virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override; }; diff --git a/gfx/gl/SharedSurfaceEGL.cpp b/gfx/gl/SharedSurfaceEGL.cpp index f4391cd0fbde..ca3f18dfb298 100644 --- a/gfx/gl/SharedSurfaceEGL.cpp +++ b/gfx/gl/SharedSurfaceEGL.cpp @@ -10,6 +10,7 @@ #include "GLLibraryEGL.h" #include "GLReadTexImageHelper.h" #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc +#include "ScopedGLHelpers.h" #include "SharedSurface.h" #include "TextureGarbageBin.h" @@ -212,14 +213,6 @@ SharedSurface_EGLImage::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out return true; } -bool -SharedSurface_EGLImage::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) -{ - MOZ_ASSERT(out_surface); - MOZ_ASSERT(NS_IsMainThread()); - return sEGLLibrary.ReadbackEGLImage(mImage, out_surface); -} - //////////////////////////////////////////////////////////////////////// /*static*/ UniquePtr diff --git a/gfx/gl/SharedSurfaceEGL.h b/gfx/gl/SharedSurfaceEGL.h index 7dd847ef6f1f..0184887e0015 100644 --- a/gfx/gl/SharedSurfaceEGL.h +++ b/gfx/gl/SharedSurfaceEGL.h @@ -79,8 +79,6 @@ public: void AcquireConsumerTexture(GLContext* consGL, GLuint* out_texture, GLuint* out_target); virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override; - - virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override; }; diff --git a/gfx/gl/SharedSurfaceGLX.cpp b/gfx/gl/SharedSurfaceGLX.cpp index e91630c22ea0..ecf8320ff7c3 100644 --- a/gfx/gl/SharedSurfaceGLX.cpp +++ b/gfx/gl/SharedSurfaceGLX.cpp @@ -9,7 +9,6 @@ #include "GLContextProvider.h" #include "GLContextGLX.h" #include "GLScreenBuffer.h" -#include "mozilla/gfx/SourceSurfaceCairo.h" #include "mozilla/layers/LayersSurfaces.h" #include "mozilla/layers/ShadowLayerUtilsX11.h" #include "mozilla/layers/ISurfaceAllocator.h" @@ -84,38 +83,6 @@ SharedSurface_GLXDrawable::ToSurfaceDescriptor(layers::SurfaceDescriptor* const return true; } -bool -SharedSurface_GLXDrawable::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) -{ - MOZ_ASSERT(out_surface); - RefPtr dataSurf = - new gfx::DataSourceSurfaceCairo(mXlibSurface->CairoSurface()); - - gfx::DataSourceSurface::ScopedMap mapSrc(dataSurf, gfx::DataSourceSurface::READ); - if (!mapSrc.IsMapped()) { - return false; - } - - gfx::DataSourceSurface::ScopedMap mapDest(out_surface, gfx::DataSourceSurface::WRITE); - if (!mapDest.IsMapped()) { - return false; - } - - if (mapDest.GetStride() == mapSrc.GetStride()) { - memcpy(mapDest.GetData(), - mapSrc.GetData(), - out_surface->GetSize().height * mapDest.GetStride()); - } else { - for (int32_t i = 0; i < dataSurf->GetSize().height; i++) { - memcpy(mapDest.GetData() + i * mapDest.GetStride(), - mapSrc.GetData() + i * mapSrc.GetStride(), - std::min(mapSrc.GetStride(), mapDest.GetStride())); - } - } - - return true; -} - /* static */ UniquePtr SurfaceFactory_GLXDrawable::Create(GLContext* prodGL, diff --git a/gfx/gl/SharedSurfaceGLX.h b/gfx/gl/SharedSurfaceGLX.h index 528c223400b6..1822fba4d718 100644 --- a/gfx/gl/SharedSurfaceGLX.h +++ b/gfx/gl/SharedSurfaceGLX.h @@ -32,8 +32,6 @@ public: virtual void UnlockProdImpl() override; virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override; - - virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override; private: SharedSurface_GLXDrawable(GLContext* gl, const gfx::IntSize& size, diff --git a/gfx/gl/SharedSurfaceGralloc.cpp b/gfx/gl/SharedSurfaceGralloc.cpp index 87c285ca1351..ba957c401275 100644 --- a/gfx/gl/SharedSurfaceGralloc.cpp +++ b/gfx/gl/SharedSurfaceGralloc.cpp @@ -283,58 +283,5 @@ SharedSurface_Gralloc::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_ return mTextureClient->ToSurfaceDescriptor(*out_descriptor); } -bool -SharedSurface_Gralloc::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) -{ - MOZ_ASSERT(out_surface); - sp buffer = mTextureClient->GetGraphicBuffer(); - - const uint8_t* grallocData = nullptr; - auto result = buffer->lock( - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, - const_cast(reinterpret_cast(&grallocData)) - ); - - if (result == BAD_VALUE) { - return false; - } - - gfx::DataSourceSurface::ScopedMap map(out_surface, gfx::DataSourceSurface::WRITE); - if (!map.IsMapped()) { - buffer->unlock(); - return false; - } - - uint32_t stride = buffer->getStride() * android::bytesPerPixel(buffer->getPixelFormat()); - uint32_t height = buffer->getHeight(); - uint32_t width = buffer->getWidth(); - for (uint32_t i = 0; i < height; i++) { - memcpy(map.GetData() + i * map.GetStride(), - grallocData + i * stride, width * 4); - } - - buffer->unlock(); - - android::PixelFormat srcFormat = buffer->getPixelFormat(); - MOZ_ASSERT(srcFormat == PIXEL_FORMAT_RGBA_8888 || - srcFormat == PIXEL_FORMAT_BGRA_8888 || - srcFormat == PIXEL_FORMAT_RGBX_8888); - bool isSrcRGB = srcFormat == PIXEL_FORMAT_RGBA_8888 || - srcFormat == PIXEL_FORMAT_RGBX_8888; - - gfx::SurfaceFormat destFormat = out_surface->GetFormat(); - MOZ_ASSERT(destFormat == gfx::SurfaceFormat::R8G8B8X8 || - destFormat == gfx::SurfaceFormat::R8G8B8A8 || - destFormat == gfx::SurfaceFormat::B8G8R8X8 || - destFormat == gfx::SurfaceFormat::B8G8R8A8); - bool isDestRGB = destFormat == gfx::SurfaceFormat::R8G8B8X8 || - destFormat == gfx::SurfaceFormat::R8G8B8A8; - - if (isSrcRGB != isDestRGB) { - SwapRAndBComponents(out_surface); - } - return true; -} - } // namespace gl } // namespace mozilla diff --git a/gfx/gl/SharedSurfaceGralloc.h b/gfx/gl/SharedSurfaceGralloc.h index d19e33c461d8..14097224cde3 100644 --- a/gfx/gl/SharedSurfaceGralloc.h +++ b/gfx/gl/SharedSurfaceGralloc.h @@ -75,8 +75,6 @@ public: } virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override; - - virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override; }; class SurfaceFactory_Gralloc diff --git a/gfx/gl/SharedSurfaceIO.cpp b/gfx/gl/SharedSurfaceIO.cpp index 2154327daf38..e50b8d8f0c32 100644 --- a/gfx/gl/SharedSurfaceIO.cpp +++ b/gfx/gl/SharedSurfaceIO.cpp @@ -182,31 +182,6 @@ SharedSurface_IOSurface::ToSurfaceDescriptor(layers::SurfaceDescriptor* const ou return true; } -bool -SharedSurface_IOSurface::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) -{ - MOZ_ASSERT(out_surface); - mIOSurf->Lock(); - size_t bytesPerRow = mIOSurf->GetBytesPerRow(); - size_t ioWidth = mIOSurf->GetDevicePixelWidth(); - size_t ioHeight = mIOSurf->GetDevicePixelHeight(); - - const unsigned char* ioData = (unsigned char*)mIOSurf->GetBaseAddress(); - gfx::DataSourceSurface::ScopedMap map(out_surface, gfx::DataSourceSurface::WRITE); - if (!map.IsMapped()) { - mIOSurf->Unlock(); - return false; - } - - for (size_t i = 0; i < ioHeight; i++) { - memcpy(map.GetData() + i * map.GetStride(), - ioData + i * bytesPerRow, ioWidth * 4); - } - - mIOSurf->Unlock(); - return true; -} - //////////////////////////////////////////////////////////////////////// // SurfaceFactory_IOSurface diff --git a/gfx/gl/SharedSurfaceIO.h b/gfx/gl/SharedSurfaceIO.h index fe787ef9cf1d..3976b5787f05 100644 --- a/gfx/gl/SharedSurfaceIO.h +++ b/gfx/gl/SharedSurfaceIO.h @@ -68,8 +68,6 @@ public: } virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override; - - virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override; }; class SurfaceFactory_IOSurface : public SurfaceFactory diff --git a/gfx/layers/AsyncCanvasRenderer.cpp b/gfx/layers/AsyncCanvasRenderer.cpp deleted file mode 100644 index f8a35572a7bf..000000000000 --- a/gfx/layers/AsyncCanvasRenderer.cpp +++ /dev/null @@ -1,279 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "AsyncCanvasRenderer.h" - -#include "gfxUtils.h" -#include "GLContext.h" -#include "GLReadTexImageHelper.h" -#include "GLScreenBuffer.h" -#include "mozilla/dom/HTMLCanvasElement.h" -#include "mozilla/layers/CanvasClient.h" -#include "mozilla/layers/TextureClient.h" -#include "mozilla/layers/TextureClientSharedSurface.h" -#include "mozilla/ReentrantMonitor.h" -#include "nsIRunnable.h" -#include "nsThreadUtils.h" - -namespace mozilla { -namespace layers { - -AsyncCanvasRenderer::AsyncCanvasRenderer() - : mHTMLCanvasElement(nullptr) - , mContext(nullptr) - , mGLContext(nullptr) - , mIsAlphaPremultiplied(true) - , mWidth(0) - , mHeight(0) - , mCanvasClientAsyncID(0) - , mCanvasClient(nullptr) - , mMutex("AsyncCanvasRenderer::mMutex") -{ - MOZ_COUNT_CTOR(AsyncCanvasRenderer); -} - -AsyncCanvasRenderer::~AsyncCanvasRenderer() -{ - MOZ_COUNT_DTOR(AsyncCanvasRenderer); -} - -void -AsyncCanvasRenderer::NotifyElementAboutAttributesChanged() -{ - class Runnable final : public nsRunnable - { - public: - explicit Runnable(AsyncCanvasRenderer* aRenderer) - : mRenderer(aRenderer) - {} - - NS_IMETHOD Run() - { - if (mRenderer) { - dom::HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(mRenderer); - } - - return NS_OK; - } - - void Revoke() - { - mRenderer = nullptr; - } - - private: - nsRefPtr mRenderer; - }; - - nsRefPtr runnable = new Runnable(this); - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to dispatch a runnable to the main-thread."); - } -} - -void -AsyncCanvasRenderer::NotifyElementAboutInvalidation() -{ - class Runnable final : public nsRunnable - { - public: - explicit Runnable(AsyncCanvasRenderer* aRenderer) - : mRenderer(aRenderer) - {} - - NS_IMETHOD Run() - { - if (mRenderer) { - dom::HTMLCanvasElement::InvalidateFromAsyncCanvasRenderer(mRenderer); - } - - return NS_OK; - } - - void Revoke() - { - mRenderer = nullptr; - } - - private: - nsRefPtr mRenderer; - }; - - nsRefPtr runnable = new Runnable(this); - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to dispatch a runnable to the main-thread."); - } -} - -void -AsyncCanvasRenderer::SetCanvasClient(CanvasClient* aClient) -{ - mCanvasClient = aClient; - if (aClient) { - mCanvasClientAsyncID = aClient->GetAsyncID(); - } else { - mCanvasClientAsyncID = 0; - } -} - -void -AsyncCanvasRenderer::SetActiveThread() -{ - MutexAutoLock lock(mMutex); - mActiveThread = NS_GetCurrentThread(); -} - -void -AsyncCanvasRenderer::ResetActiveThread() -{ - MutexAutoLock lock(mMutex); - mActiveThread = nullptr; -} - -already_AddRefed -AsyncCanvasRenderer::GetActiveThread() -{ - MutexAutoLock lock(mMutex); - nsCOMPtr result = mActiveThread; - return result.forget(); -} - -void -AsyncCanvasRenderer::CopyFromTextureClient(TextureClient* aTextureClient) -{ - MutexAutoLock lock(mMutex); - RefPtr buffer = static_cast(aTextureClient); - if (!buffer->Lock(layers::OpenMode::OPEN_READ)) { - return; - } - - const gfx::IntSize& size = aTextureClient->GetSize(); - // This buffer would be used later for content rendering. So we choose - // B8G8R8A8 format here. - const gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8; - // Avoid to create buffer every time. - if (!mSurfaceForBasic || - size != mSurfaceForBasic->GetSize() || - format != mSurfaceForBasic->GetFormat()) - { - uint32_t stride = gfx::GetAlignedStride<8>(size.width * BytesPerPixel(format)); - mSurfaceForBasic = gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride); - } - - const uint8_t* lockedBytes = buffer->GetLockedData(); - gfx::DataSourceSurface::ScopedMap map(mSurfaceForBasic, - gfx::DataSourceSurface::MapType::WRITE); - if (!map.IsMapped()) { - buffer->Unlock(); - return; - } - - memcpy(map.GetData(), lockedBytes, map.GetStride() * mSurfaceForBasic->GetSize().height); - buffer->Unlock(); - - if (mSurfaceForBasic->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 || - mSurfaceForBasic->GetFormat() == gfx::SurfaceFormat::R8G8B8X8) { - gl::SwapRAndBComponents(mSurfaceForBasic); - } -} - -already_AddRefed -AsyncCanvasRenderer::UpdateTarget() -{ - if (!mGLContext) { - return nullptr; - } - - gl::SharedSurface* frontbuffer = nullptr; - gl::GLScreenBuffer* screen = mGLContext->Screen(); - const auto& front = screen->Front(); - if (front) { - frontbuffer = front->Surf(); - } - - if (!frontbuffer) { - return nullptr; - } - - if (frontbuffer->mType == gl::SharedSurfaceType::Basic) { - return nullptr; - } - - const gfx::IntSize& size = frontbuffer->mSize; - // This buffer would be used later for content rendering. So we choose - // B8G8R8A8 format here. - const gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8; - uint32_t stride = gfx::GetAlignedStride<8>(size.width * BytesPerPixel(format)); - RefPtr surface = - gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride); - - - if (NS_WARN_IF(!surface)) { - return nullptr; - } - - if (!frontbuffer->ReadbackBySharedHandle(surface)) { - return nullptr; - } - - bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied; - if (needsPremult) { - gfxUtils::PremultiplyDataSurface(surface, surface); - } - - return surface.forget(); -} - -already_AddRefed -AsyncCanvasRenderer::GetSurface() -{ - MOZ_ASSERT(NS_IsMainThread()); - MutexAutoLock lock(mMutex); - if (mSurfaceForBasic) { - // Since SourceSurface isn't thread-safe, we need copy to a new SourceSurface. - RefPtr result = - gfx::Factory::CreateDataSourceSurfaceWithStride(mSurfaceForBasic->GetSize(), - mSurfaceForBasic->GetFormat(), - mSurfaceForBasic->Stride()); - - gfx::DataSourceSurface::ScopedMap srcMap(mSurfaceForBasic, gfx::DataSourceSurface::READ); - gfx::DataSourceSurface::ScopedMap dstMap(result, gfx::DataSourceSurface::WRITE); - - if (NS_WARN_IF(!srcMap.IsMapped()) || - NS_WARN_IF(!dstMap.IsMapped())) { - return nullptr; - } - - memcpy(dstMap.GetData(), - srcMap.GetData(), - srcMap.GetStride() * mSurfaceForBasic->GetSize().height); - return result.forget(); - } else { - return UpdateTarget(); - } -} - -nsresult -AsyncCanvasRenderer::GetInputStream(const char *aMimeType, - const char16_t *aEncoderOptions, - nsIInputStream **aStream) -{ - MOZ_ASSERT(NS_IsMainThread()); - RefPtr surface = GetSurface(); - if (!surface) { - return NS_ERROR_FAILURE; - } - - // Handle y flip. - RefPtr dataSurf = gl::YInvertImageSurface(surface); - - return gfxUtils::GetInputStream(dataSurf, false, aMimeType, aEncoderOptions, aStream); -} - -} // namespace layers -} // namespace mozilla diff --git a/gfx/layers/AsyncCanvasRenderer.h b/gfx/layers/AsyncCanvasRenderer.h deleted file mode 100644 index 6a84b0703528..000000000000 --- a/gfx/layers/AsyncCanvasRenderer.h +++ /dev/null @@ -1,169 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_ -#define MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_ - -#include "LayersTypes.h" -#include "mozilla/gfx/Point.h" // for IntSize -#include "mozilla/Mutex.h" -#include "mozilla/RefPtr.h" // for nsAutoPtr, nsRefPtr, etc -#include "nsCOMPtr.h" // for nsCOMPtr - -class nsICanvasRenderingContextInternal; -class nsIInputStream; -class nsIThread; - -namespace mozilla { - -namespace gfx { -class DataSourceSurface; -} - -namespace gl { -class GLContext; -} - -namespace dom { -class HTMLCanvasElement; -} - -namespace layers { - -class CanvasClient; -class TextureClient; - -/** - * Since HTMLCanvasElement and OffscreenCanvas are not thread-safe, we create - * AsyncCanvasRenderer which is thread-safe wrapper object for communicating - * among main, worker and ImageBridgeChild threads. - * - * Each HTMLCanvasElement object is responsible for creating - * AsyncCanvasRenderer object. Once Canvas is transfered to worker, - * OffscreenCanvas will keep reference pointer of this object. - * - * Sometimes main thread needs AsyncCanvasRenderer's result, such as layers - * fallback to BasicLayerManager or calling toDataURL in Javascript. Simply call - * GetSurface() in main thread will readback the result to mSurface. - * - * If layers backend is LAYERS_CLIENT, this object will pass to ImageBridgeChild - * for submitting frames to Compositor. - */ -class AsyncCanvasRenderer final -{ - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncCanvasRenderer) - -public: - AsyncCanvasRenderer(); - - void NotifyElementAboutAttributesChanged(); - void NotifyElementAboutInvalidation(); - - void SetCanvasClient(CanvasClient* aClient); - - void SetWidth(uint32_t aWidth) - { - mWidth = aWidth; - } - - void SetHeight(uint32_t aHeight) - { - mHeight = aHeight; - } - - void SetIsAlphaPremultiplied(bool aIsAlphaPremultiplied) - { - mIsAlphaPremultiplied = aIsAlphaPremultiplied; - } - - // Active thread means the thread which spawns GLContext. - void SetActiveThread(); - void ResetActiveThread(); - - // This will readback surface and return the surface - // in the DataSourceSurface. - // Can be called in main thread only. - already_AddRefed GetSurface(); - - // For SharedSurface_Basic case, before the frame sending to the compositor, - // we readback it to a texture client because SharedSurface_Basic cannot shared. - // We don't want to readback it again here, so just copy the content of that - // texture client here to avoid readback again. - void CopyFromTextureClient(TextureClient *aClient); - - // Readback current WebGL's content and convert it to InputStream. This - // function called GetSurface implicitly and GetSurface handles only get - // called in the main thread. So this function can be called in main thread. - nsresult - GetInputStream(const char *aMimeType, - const char16_t *aEncoderOptions, - nsIInputStream **aStream); - - gfx::IntSize GetSize() const - { - return gfx::IntSize(mWidth, mHeight); - } - - uint64_t GetCanvasClientAsyncID() const - { - return mCanvasClientAsyncID; - } - - CanvasClient* GetCanvasClient() const - { - return mCanvasClient; - } - - already_AddRefed GetActiveThread(); - - // The lifetime is controllered by HTMLCanvasElement. - // Only accessed in main thread. - dom::HTMLCanvasElement* mHTMLCanvasElement; - - // Only accessed in active thread. - nsICanvasRenderingContextInternal* mContext; - - // We need to keep a reference to the context around here, otherwise the - // canvas' surface texture destructor will deref and destroy it too early - // Only accessed in active thread. - RefPtr mGLContext; -private: - - virtual ~AsyncCanvasRenderer(); - - // Readback current WebGL's content and return it as DataSourceSurface. - already_AddRefed UpdateTarget(); - - bool mIsAlphaPremultiplied; - - uint32_t mWidth; - uint32_t mHeight; - uint64_t mCanvasClientAsyncID; - - // The lifetime of this pointer is controlled by OffscreenCanvas - // Can be accessed in active thread and ImageBridge thread. - // But we never accessed it at the same time on both thread. So no - // need to protect this member. - CanvasClient* mCanvasClient; - - // When backend is LAYER_BASIC and SharedSurface type is Basic. - // CanvasClient will readback the GLContext to a TextureClient - // in order to send frame to compositor. To avoid readback again, - // we copy from this TextureClient to this mSurfaceForBasic directly - // by calling CopyFromTextureClient(). - RefPtr mSurfaceForBasic; - - // Protect non thread-safe objects. - Mutex mMutex; - - // Can be accessed in any thread, need protect by mutex. - nsCOMPtr mActiveThread; -}; - -} // namespace layers -} // namespace mozilla - -#endif // MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_ diff --git a/gfx/layers/CopyableCanvasLayer.cpp b/gfx/layers/CopyableCanvasLayer.cpp index 0fad0aa3668b..be171b4bcb23 100644 --- a/gfx/layers/CopyableCanvasLayer.cpp +++ b/gfx/layers/CopyableCanvasLayer.cpp @@ -64,9 +64,6 @@ CopyableCanvasLayer::Initialize(const Data& aData) } } else if (aData.mBufferProvider) { mBufferProvider = aData.mBufferProvider; - } else if (aData.mRenderer) { - mAsyncRenderer = aData.mRenderer; - mOriginPos = gl::OriginPos::BottomLeft; } else { MOZ_CRASH("CanvasLayer created without mSurface, mDrawTarget or mGLContext?"); } @@ -83,9 +80,7 @@ CopyableCanvasLayer::IsDataValid(const Data& aData) void CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) { - if (mAsyncRenderer) { - mSurface = mAsyncRenderer->GetSurface(); - } else if (mBufferProvider) { + if (mBufferProvider) { mSurface = mBufferProvider->GetSnapshot(); } @@ -100,7 +95,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) return; } - if (mBufferProvider || mAsyncRenderer) { + if (mBufferProvider) { return; } diff --git a/gfx/layers/LayerTreeInvalidation.cpp b/gfx/layers/LayerTreeInvalidation.cpp index 65ea0b9f48e0..8c2a45921cf6 100644 --- a/gfx/layers/LayerTreeInvalidation.cpp +++ b/gfx/layers/LayerTreeInvalidation.cpp @@ -385,7 +385,7 @@ struct ColorLayerProperties : public LayerPropertiesBase IntRect mBounds; }; -static ImageHost* GetImageHost(Layer* aLayer) +static ImageHost* GetImageHost(ImageLayer* aLayer) { LayerComposite* composite = aLayer->AsLayerComposite(); if (composite) { @@ -465,34 +465,6 @@ struct ImageLayerProperties : public LayerPropertiesBase bool mIsMask; }; -struct CanvasLayerProperties : public LayerPropertiesBase -{ - explicit CanvasLayerProperties(CanvasLayer* aCanvas) - : LayerPropertiesBase(aCanvas) - , mImageHost(GetImageHost(aCanvas)) - { - mFrameID = mImageHost ? mImageHost->GetFrameID() : -1; - } - - virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback, - bool& aGeometryChanged) - { - CanvasLayer* canvasLayer = static_cast(mLayer.get()); - - ImageHost* host = GetImageHost(canvasLayer); - if (host && host->GetFrameID() != mFrameID) { - aGeometryChanged = true; - - return NewTransformedBounds(); - } - - return IntRect(); - } - - nsRefPtr mImageHost; - int32_t mFrameID; -}; - UniquePtr CloneLayerTreePropertiesInternal(Layer* aRoot, bool aIsMask /* = false */) { @@ -511,7 +483,6 @@ CloneLayerTreePropertiesInternal(Layer* aRoot, bool aIsMask /* = false */) case Layer::TYPE_IMAGE: return MakeUnique(static_cast(aRoot), aIsMask); case Layer::TYPE_CANVAS: - return MakeUnique(static_cast(aRoot)); case Layer::TYPE_READBACK: case Layer::TYPE_SHADOW: case Layer::TYPE_PAINTED: diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index 7a2c5c630296..a815d5c114e6 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -25,7 +25,6 @@ #include "mozilla/gfx/2D.h" // for DrawTarget #include "mozilla/gfx/BaseSize.h" // for BaseSize #include "mozilla/gfx/Matrix.h" // for Matrix4x4 -#include "mozilla/layers/AsyncCanvasRenderer.h" #include "mozilla/layers/Compositor.h" // for Compositor #include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite @@ -2105,19 +2104,6 @@ ColorLayer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent) layer->set_color(mColor.ToABGR()); } -CanvasLayer::CanvasLayer(LayerManager* aManager, void* aImplData) - : Layer(aManager, aImplData) - , mPreTransCallback(nullptr) - , mPreTransCallbackData(nullptr) - , mPostTransCallback(nullptr) - , mPostTransCallbackData(nullptr) - , mFilter(GraphicsFilter::FILTER_GOOD) - , mDirty(false) -{} - -CanvasLayer::~CanvasLayer() -{} - void CanvasLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix) { diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 7f7b94042da2..88238216f065 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -74,7 +74,6 @@ namespace layers { class Animation; class AnimationData; -class AsyncCanvasRenderer; class AsyncPanZoomController; class ClientLayerManager; class Layer; @@ -2269,17 +2268,15 @@ public: Data() : mBufferProvider(nullptr) , mGLContext(nullptr) - , mRenderer(nullptr) , mFrontbufferGLTex(0) , mSize(0,0) , mHasAlpha(false) , mIsGLAlphaPremult(true) { } - // One of these three must be specified for Canvas2D, but never more than one + // One of these two must be specified for Canvas2D, but never both PersistentBufferProvider* mBufferProvider; // A BufferProvider for the Canvas contents mozilla::gl::GLContext* mGLContext; // or this, for GL. - AsyncCanvasRenderer* mRenderer; // or this, for OffscreenCanvas // Frontbuffer override uint32_t mFrontbufferGLTex; @@ -2395,14 +2392,16 @@ public: ComputeEffectiveTransformForMaskLayers(aTransformToSurface); } - bool GetIsAsyncRenderer() const - { - return !!mAsyncRenderer; - } - protected: - CanvasLayer(LayerManager* aManager, void* aImplData); - virtual ~CanvasLayer(); + CanvasLayer(LayerManager* aManager, void* aImplData) + : Layer(aManager, aImplData) + , mPreTransCallback(nullptr) + , mPreTransCallbackData(nullptr) + , mPostTransCallback(nullptr) + , mPostTransCallbackData(nullptr) + , mFilter(GraphicsFilter::FILTER_GOOD) + , mDirty(false) + {} virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override; @@ -2424,7 +2423,6 @@ protected: DidTransactionCallback mPostTransCallback; void* mPostTransCallbackData; GraphicsFilter mFilter; - nsRefPtr mAsyncRenderer; private: /** diff --git a/gfx/layers/basic/BasicCanvasLayer.cpp b/gfx/layers/basic/BasicCanvasLayer.cpp index f6f0788764bc..080d4b79efa5 100644 --- a/gfx/layers/basic/BasicCanvasLayer.cpp +++ b/gfx/layers/basic/BasicCanvasLayer.cpp @@ -4,7 +4,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "BasicCanvasLayer.h" -#include "AsyncCanvasRenderer.h" #include "basic/BasicLayers.h" // for BasicLayerManager #include "basic/BasicLayersImpl.h" // for GetEffectiveOperator #include "mozilla/mozalloc.h" // for operator new diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index 5b722c63aaa3..cd2222c60236 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -13,7 +13,6 @@ #include "gfxPlatform.h" // for gfxPlatform #include "GLReadTexImageHelper.h" #include "mozilla/gfx/BaseSize.h" // for BaseSize -#include "mozilla/layers/AsyncCanvasRenderer.h" #include "mozilla/layers/CompositableForwarder.h" #include "mozilla/layers/CompositorChild.h" // for CompositorChild #include "mozilla/layers/GrallocTextureClient.h" @@ -39,32 +38,14 @@ CanvasClient::CreateCanvasClient(CanvasClientType aType, switch (aType) { case CanvasClientTypeShSurf: return MakeAndAddRef(aForwarder, aFlags); - case CanvasClientAsync: - return MakeAndAddRef(aForwarder, aFlags); + break; + default: return MakeAndAddRef(aForwarder, aFlags); break; } } -void -CanvasClientBridge::UpdateAsync(AsyncCanvasRenderer* aRenderer) -{ - if (!GetForwarder() || !mLayer || !aRenderer || - !aRenderer->GetCanvasClient()) { - return; - } - - uint64_t asyncID = aRenderer->GetCanvasClientAsyncID(); - if (asyncID == 0 || mAsyncID == asyncID) { - return; - } - - static_cast(GetForwarder()) - ->AttachAsyncCompositable(asyncID, mLayer); - mAsyncID = asyncID; -} - void CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) { @@ -125,7 +106,6 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) CompositableForwarder::TimedTextureClient* t = textures.AppendElement(); t->mTextureClient = mBuffer; t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mBuffer->GetSize()); - t->mFrameID = mFrameID; GetForwarder()->UseTextures(this, textures); mBuffer->SyncWithObject(GetForwarder()->GetSyncObject()); } @@ -341,38 +321,13 @@ CloneSurface(gl::SharedSurface* src, gl::SurfaceFactory* factory) void CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) { - Renderer renderer; - renderer.construct(aLayer); - UpdateRenderer(aSize, renderer); -} - -void -CanvasClientSharedSurface::UpdateAsync(AsyncCanvasRenderer* aRenderer) -{ - Renderer renderer; - renderer.construct(aRenderer); - UpdateRenderer(aRenderer->GetSize(), renderer); -} - -void -CanvasClientSharedSurface::UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer) -{ - GLContext* gl = nullptr; - ClientCanvasLayer* layer = nullptr; - AsyncCanvasRenderer* asyncRenderer = nullptr; - if (aRenderer.constructed()) { - layer = aRenderer.ref(); - gl = layer->mGLContext; - } else { - asyncRenderer = aRenderer.ref(); - gl = asyncRenderer->mGLContext; - } + auto gl = aLayer->mGLContext; gl->MakeCurrent(); RefPtr newFront; - if (layer && layer->mGLFrontbuffer) { - mShSurfClient = CloneSurface(layer->mGLFrontbuffer.get(), layer->mFactory.get()); + if (aLayer->mGLFrontbuffer) { + mShSurfClient = CloneSurface(aLayer->mGLFrontbuffer.get(), aLayer->mFactory.get()); if (!mShSurfClient) { gfxCriticalError() << "Invalid canvas front buffer"; return; @@ -396,30 +351,14 @@ CanvasClientSharedSurface::UpdateRenderer(gfx::IntSize aSize, Renderer& aRendere bool needsReadback = (surf->mType == SharedSurfaceType::Basic); if (needsReadback) { - TextureFlags flags = TextureFlags::IMMUTABLE; - - CompositableForwarder* shadowForwarder = nullptr; - if (layer) { - flags |= layer->Flags(); - shadowForwarder = layer->ClientManager()->AsShadowForwarder(); - } else { - MOZ_ASSERT(asyncRenderer); - flags |= mTextureFlags; - shadowForwarder = GetForwarder(); - } + TextureFlags flags = aLayer->Flags() | + TextureFlags::IMMUTABLE; + auto manager = aLayer->ClientManager(); + auto shadowForwarder = manager->AsShadowForwarder(); auto layersBackend = shadowForwarder->GetCompositorBackendType(); mReadbackClient = TexClientFromReadback(surf, forwarder, flags, layersBackend); - if (asyncRenderer) { - // Above codes will readback the GLContext to mReadbackClient - // in order to send frame to compositor. We copy from this - // TextureClient directly by calling CopyFromTextureClient(). - // Therefore, if main-thread want the content of GLContext, - // it don't have to readback it again. - asyncRenderer->CopyFromTextureClient(mReadbackClient); - } - newFront = mReadbackClient; } else { mReadbackClient = nullptr; @@ -432,14 +371,6 @@ CanvasClientSharedSurface::UpdateRenderer(gfx::IntSize aSize, Renderer& aRendere return; } - mNewFront = newFront; -} - -void -CanvasClientSharedSurface::Updated() -{ - auto forwarder = GetForwarder(); - #ifndef MOZ_WIDGET_GONK if (mFront) { if (mFront->GetFlags() & TextureFlags::RECYCLE) { @@ -454,13 +385,12 @@ CanvasClientSharedSurface::Updated() // - Call RemoveTexture() after newFront's UseTextures() call. // It could improve performance of Host side's EGL handling on gonk AutoRemoveTexture autoRemove(this); - if (mFront && mFront != mNewFront) { + if (mFront && mFront != newFront) { autoRemove.mTexture = mFront; } #endif - mFront = mNewFront; - mNewFront = nullptr; + mFront = newFront; // Add the new TexClient. MOZ_ALWAYS_TRUE( AddTextureClient(mFront) ); @@ -469,7 +399,6 @@ CanvasClientSharedSurface::Updated() CompositableForwarder::TimedTextureClient* t = textures.AppendElement(); t->mTextureClient = mFront; t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mFront->GetSize()); - t->mFrameID = mFrameID; forwarder->UseTextures(this, textures); } @@ -477,7 +406,6 @@ void CanvasClientSharedSurface::ClearSurfaces() { mFront = nullptr; - mNewFront = nullptr; mShSurfClient = nullptr; mReadbackClient = nullptr; } diff --git a/gfx/layers/client/CanvasClient.h b/gfx/layers/client/CanvasClient.h index 7a8a17485156..5bdeb7f3f2be 100644 --- a/gfx/layers/client/CanvasClient.h +++ b/gfx/layers/client/CanvasClient.h @@ -13,11 +13,6 @@ #include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor #include "mozilla/layers/TextureClient.h" // for TextureClient, etc - -// Fix X11 header brain damage that conflicts with MaybeOneOf::None -#undef None -#include "mozilla/MaybeOneOf.h" - #include "mozilla/mozalloc.h" // for operator delete #include "mozilla/gfx/Point.h" // for IntSize @@ -26,10 +21,8 @@ namespace mozilla { namespace layers { -class AsyncCanvasRenderer; class ClientCanvasLayer; class CompositableForwarder; -class ShadowableLayer; class SharedSurfaceTextureClient; /** @@ -38,8 +31,6 @@ class SharedSurfaceTextureClient; class CanvasClient : public CompositableClient { public: - typedef MaybeOneOf Renderer; - /** * Creates, configures, and returns a new canvas client. If necessary, a * message will be sent to the compositor to create a corresponding image @@ -49,7 +40,6 @@ public: CanvasClientSurface, CanvasClientGLContext, CanvasClientTypeShSurf, - CanvasClientAsync, // webgl on workers }; static already_AddRefed CreateCanvasClient(CanvasClientType aType, CompositableForwarder* aFwd, @@ -57,7 +47,6 @@ public: CanvasClient(CompositableForwarder* aFwd, TextureFlags aFlags) : CompositableClient(aFwd, aFlags) - , mFrameID(0) { mTextureFlags = aFlags; } @@ -68,18 +57,7 @@ public: virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) = 0; - virtual bool AddTextureClient(TextureClient* aTexture) override - { - ++mFrameID; - return CompositableClient::AddTextureClient(aTexture); - } - - virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) {} - virtual void Updated() { } - -protected: - int32_t mFrameID; }; // Used for 2D canvases and WebGL canvas on non-GL systems where readback is requried. @@ -107,7 +85,7 @@ public: virtual bool AddTextureClient(TextureClient* aTexture) override { MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags); - return CanvasClient::AddTextureClient(aTexture); + return CompositableClient::AddTextureClient(aTexture); } virtual void OnDetach() override @@ -133,7 +111,6 @@ private: RefPtr mShSurfClient; RefPtr mReadbackClient; RefPtr mFront; - RefPtr mNewFront; void ClearSurfaces(); @@ -153,54 +130,12 @@ public: virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) override; - void UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer); - - virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) override; - - virtual void Updated() override; virtual void OnDetach() override { ClearSurfaces(); } }; -/** - * Used for OMT uploads using the image bridge protocol. - * Actual CanvasClient is on the ImageBridgeChild thread, so we - * only forward its AsyncID here - */ -class CanvasClientBridge final : public CanvasClient -{ -public: - CanvasClientBridge(CompositableForwarder* aLayerForwarder, - TextureFlags aFlags) - : CanvasClient(aLayerForwarder, aFlags) - , mAsyncID(0) - , mLayer(nullptr) - { - } - - TextureInfo GetTextureInfo() const override - { - return TextureInfo(CompositableType::IMAGE); - } - - virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) override - { - } - - virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) override; - - void SetLayer(ShadowableLayer* aLayer) - { - mLayer = aLayer; - } - -protected: - uint64_t mAsyncID; - ShadowableLayer* mLayer; -}; - } // namespace layers } // namespace mozilla diff --git a/gfx/layers/client/ClientCanvasLayer.cpp b/gfx/layers/client/ClientCanvasLayer.cpp index 1c9b1bc17bdf..0e1fcdf6c503 100644 --- a/gfx/layers/client/ClientCanvasLayer.cpp +++ b/gfx/layers/client/ClientCanvasLayer.cpp @@ -11,7 +11,6 @@ #include "SharedSurfaceGL.h" // for SurfaceFactory_GLTexture, etc #include "ClientLayerManager.h" // for ClientLayerManager, etc #include "mozilla/gfx/Point.h" // for IntSize -#include "mozilla/layers/AsyncCanvasRenderer.h" #include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/LayersTypes.h" #include "nsCOMPtr.h" // for already_AddRefed @@ -20,6 +19,24 @@ #include "nsXULAppAPI.h" // for XRE_GetProcessType, etc #include "gfxPrefs.h" // for WebGLForceLayersReadback +#ifdef XP_WIN +#include "SharedSurfaceANGLE.h" // for SurfaceFactory_ANGLEShareHandle +#include "gfxWindowsPlatform.h" +#endif + +#ifdef MOZ_WIDGET_GONK +#include "SharedSurfaceGralloc.h" +#endif + +#ifdef XP_MACOSX +#include "SharedSurfaceIO.h" +#endif + +#ifdef GL_PROVIDER_GLX +#include "GLXLibrary.h" +#include "SharedSurfaceGLX.h" +#endif + using namespace mozilla::gfx; using namespace mozilla::gl; @@ -65,7 +82,46 @@ ClientCanvasLayer::Initialize(const Data& aData) mFlags |= TextureFlags::NON_PREMULTIPLIED; } - UniquePtr factory = GLScreenBuffer::CreateFactory(mGLContext, caps, forwarder, mFlags); + UniquePtr factory; + + if (!gfxPrefs::WebGLForceLayersReadback()) { + switch (forwarder->GetCompositorBackendType()) { + case mozilla::layers::LayersBackend::LAYERS_OPENGL: { +#if defined(XP_MACOSX) + factory = SurfaceFactory_IOSurface::Create(mGLContext, caps, forwarder, mFlags); +#elif defined(MOZ_WIDGET_GONK) + factory = MakeUnique(mGLContext, caps, forwarder, mFlags); +#elif defined(GL_PROVIDER_GLX) + if (sGLXLibrary.UseSurfaceSharing()) + factory = SurfaceFactory_GLXDrawable::Create(mGLContext, caps, forwarder, mFlags); +#else + if (mGLContext->GetContextType() == GLContextType::EGL) { + if (XRE_IsParentProcess()) { + factory = SurfaceFactory_EGLImage::Create(mGLContext, caps, forwarder, + mFlags); + } + } +#endif + break; + } + case mozilla::layers::LayersBackend::LAYERS_D3D11: { +#ifdef XP_WIN + // Enable surface sharing only if ANGLE and compositing devices + // are both WARP or both not WARP + if (mGLContext->IsANGLE() && + (mGLContext->IsWARP() == gfxWindowsPlatform::GetPlatform()->IsWARP()) && + gfxWindowsPlatform::GetPlatform()->CompositorD3D11TextureSharingWorks()) + { + factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, caps, forwarder, + mFlags); + } +#endif + break; + } + default: + break; + } + } if (mGLFrontbuffer) { // We're using a source other than the one in the default screen. @@ -89,6 +145,11 @@ ClientCanvasLayer::RenderLayer() RenderMaskLayers(this); + if (!IsDirty()) { + return; + } + Painted(); + if (!mCanvasClient) { TextureFlags flags = TextureFlags::IMMEDIATE_UPLOAD; if (mOriginPos == gl::OriginPos::BottomLeft) { @@ -111,24 +172,11 @@ ClientCanvasLayer::RenderLayer() return; } if (HasShadow()) { - if (mAsyncRenderer) { - static_cast(mCanvasClient.get())->SetLayer(this); - } else { - mCanvasClient->Connect(); - ClientManager()->AsShadowForwarder()->Attach(mCanvasClient, this); - } + mCanvasClient->Connect(); + ClientManager()->AsShadowForwarder()->Attach(mCanvasClient, this); } } - if (mCanvasClient && mAsyncRenderer) { - mCanvasClient->UpdateAsync(mAsyncRenderer); - } - - if (!IsDirty()) { - return; - } - Painted(); - FirePreTransactionCallback(); mCanvasClient->Update(gfx::IntSize(mBounds.width, mBounds.height), this); @@ -141,10 +189,6 @@ ClientCanvasLayer::RenderLayer() CanvasClient::CanvasClientType ClientCanvasLayer::GetCanvasClientType() { - if (mAsyncRenderer) { - return CanvasClient::CanvasClientAsync; - } - if (mGLContext) { return CanvasClient::CanvasClientTypeShSurf; } diff --git a/gfx/layers/client/ClientCanvasLayer.h b/gfx/layers/client/ClientCanvasLayer.h index d2308197b17e..9167a1d2b3b1 100644 --- a/gfx/layers/client/ClientCanvasLayer.h +++ b/gfx/layers/client/ClientCanvasLayer.h @@ -97,6 +97,7 @@ protected: TextureFlags mFlags; + friend class DeprecatedCanvasClient2D; friend class CanvasClient2D; friend class CanvasClientSharedSurface; }; diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 3e04121ea471..c97f6727b743 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -169,7 +169,6 @@ TextureChild::ActorDestroy(ActorDestroyReason why) { if (mTextureClient) { mTextureClient->mActor = nullptr; - mTextureClient->mAllocator = nullptr; } mWaitForRecycle = nullptr; mKeep = nullptr; diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index 231b3ada0b1a..06cb4ca773dc 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -21,7 +21,6 @@ #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc #include "mozilla/ipc/Transport.h" // for Transport #include "mozilla/gfx/Point.h" // for IntSize -#include "mozilla/layers/AsyncCanvasRenderer.h" #include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager #include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild #include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc @@ -232,19 +231,6 @@ static void CreateImageClientSync(RefPtr* result, barrier->NotifyAll(); } -// dispatched function -static void CreateCanvasClientSync(ReentrantMonitor* aBarrier, - CanvasClient::CanvasClientType aType, - TextureFlags aFlags, - RefPtr* const outResult, - bool* aDone) -{ - ReentrantMonitorAutoEnter autoMon(*aBarrier); - *outResult = sImageBridgeChildSingleton->CreateCanvasClientNow(aType, aFlags); - *aDone = true; - aBarrier->NotifyAll(); -} - static void ConnectImageBridge(ImageBridgeChild * child, ImageBridgeParent * parent) { MessageLoop *parentMsgLoop = parent->GetMessageLoop(); @@ -283,14 +269,9 @@ ImageBridgeChild::Connect(CompositableClient* aCompositable, MOZ_ASSERT(aCompositable); MOZ_ASSERT(!mShuttingDown); uint64_t id = 0; - - PImageContainerChild* imageContainerChild = nullptr; - if (aImageContainer) - imageContainerChild = aImageContainer->GetPImageContainerChild(); - PCompositableChild* child = SendPCompositableConstructor(aCompositable->GetTextureInfo(), - imageContainerChild, &id); + aImageContainer->GetPImageContainerChild(), &id); MOZ_ASSERT(child); aCompositable->InitIPDLActor(child, id); } @@ -393,35 +374,6 @@ void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient, NewRunnableFunction(&ReleaseImageClientNow, aClient, aChild)); } -static void ReleaseCanvasClientNow(CanvasClient* aClient) -{ - MOZ_ASSERT(InImageBridgeChildThread()); - aClient->Release(); -} - -// static -void ImageBridgeChild::DispatchReleaseCanvasClient(CanvasClient* aClient) -{ - if (!aClient) { - return; - } - - if (!IsCreated()) { - // CompositableClient::Release should normally happen in the ImageBridgeChild - // thread because it usually generate some IPDL messages. - // However, if we take this branch it means that the ImageBridgeChild - // has already shut down, along with the CompositableChild, which means no - // message will be sent and it is safe to run this code from any thread. - MOZ_ASSERT(aClient->GetIPDLActor() == nullptr); - aClient->Release(); - return; - } - - sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - FROM_HERE, - NewRunnableFunction(&ReleaseCanvasClientNow, aClient)); -} - static void ReleaseTextureClientNow(TextureClient* aClient) { MOZ_ASSERT(InImageBridgeChildThread()); @@ -460,7 +412,7 @@ static void UpdateImageClientNow(ImageClient* aClient, ImageContainer* aContaine sImageBridgeChildSingleton->EndTransaction(); } -// static +//static void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient, ImageContainer* aContainer) { @@ -480,51 +432,6 @@ void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient, nsRefPtr >(&UpdateImageClientNow, aClient, aContainer)); } -static void UpdateAsyncCanvasRendererSync(AsyncCanvasRenderer* aWrapper, - ReentrantMonitor* aBarrier, - bool* const outDone) -{ - ImageBridgeChild::UpdateAsyncCanvasRendererNow(aWrapper); - - ReentrantMonitorAutoEnter autoMon(*aBarrier); - *outDone = true; - aBarrier->NotifyAll(); -} - -// static -void ImageBridgeChild::UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aWrapper) -{ - aWrapper->GetCanvasClient()->UpdateAsync(aWrapper); - - if (InImageBridgeChildThread()) { - UpdateAsyncCanvasRendererNow(aWrapper); - return; - } - - ReentrantMonitor barrier("UpdateAsyncCanvasRenderer Lock"); - ReentrantMonitorAutoEnter autoMon(barrier); - bool done = false; - - sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - FROM_HERE, - NewRunnableFunction(&UpdateAsyncCanvasRendererSync, aWrapper, &barrier, &done)); - - // should stop the thread until the CanvasClient has been created on - // the other thread - while (!done) { - barrier.Wait(); - } -} - -// static -void ImageBridgeChild::UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aWrapper) -{ - MOZ_ASSERT(aWrapper); - sImageBridgeChildSingleton->BeginTransaction(); - aWrapper->GetCanvasClient()->Updated(); - sImageBridgeChildSingleton->EndTransaction(); -} - static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer, AsyncTransactionWaiter* aWaiter) { @@ -542,7 +449,7 @@ static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer, aWaiter->DecrementWaitCount(); } -// static +//static void ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer) { @@ -798,42 +705,6 @@ ImageBridgeChild::CreateImageClientNow(CompositableType aType, return client.forget(); } -already_AddRefed -ImageBridgeChild::CreateCanvasClient(CanvasClient::CanvasClientType aType, - TextureFlags aFlag) -{ - if (InImageBridgeChildThread()) { - return CreateCanvasClientNow(aType, aFlag); - } - ReentrantMonitor barrier("CreateCanvasClient Lock"); - ReentrantMonitorAutoEnter autoMon(barrier); - bool done = false; - - RefPtr result = nullptr; - GetMessageLoop()->PostTask(FROM_HERE, - NewRunnableFunction(&CreateCanvasClientSync, - &barrier, aType, aFlag, &result, &done)); - // should stop the thread until the CanvasClient has been created on the - // other thread - while (!done) { - barrier.Wait(); - } - return result.forget(); -} - -already_AddRefed -ImageBridgeChild::CreateCanvasClientNow(CanvasClient::CanvasClientType aType, - TextureFlags aFlag) -{ - RefPtr client - = CanvasClient::CreateCanvasClient(aType, this, aFlag); - MOZ_ASSERT(client, "failed to create CanvasClient"); - if (client) { - client->Connect(); - } - return client.forget(); -} - bool ImageBridgeChild::AllocUnsafeShmem(size_t aSize, ipc::SharedMemory::SharedMemoryType aType, diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h index c3b37aa19591..8d4f6c087b01 100644 --- a/gfx/layers/ipc/ImageBridgeChild.h +++ b/gfx/layers/ipc/ImageBridgeChild.h @@ -12,7 +12,6 @@ #include "mozilla/RefPtr.h" // for already_AddRefed #include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc #include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTrackerHolder -#include "mozilla/layers/CanvasClient.h" #include "mozilla/layers/CompositableForwarder.h" #include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/PImageBridgeChild.h" @@ -33,7 +32,6 @@ class Shmem; namespace layers { -class AsyncCanvasRenderer; class AsyncTransactionTracker; class ImageClient; class ImageContainer; @@ -212,20 +210,12 @@ public: ImageContainer* aImageContainer); already_AddRefed CreateImageClientNow(CompositableType aType, ImageContainer* aImageContainer); - already_AddRefed CreateCanvasClient(CanvasClient::CanvasClientType aType, - TextureFlags aFlag); - already_AddRefed CreateCanvasClientNow(CanvasClient::CanvasClientType aType, - TextureFlags aFlag); static void DispatchReleaseImageClient(ImageClient* aClient, PImageContainerChild* aChild = nullptr); - static void DispatchReleaseCanvasClient(CanvasClient* aClient); static void DispatchReleaseTextureClient(TextureClient* aClient); static void DispatchImageClientUpdate(ImageClient* aClient, ImageContainer* aContainer); - static void UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aClient); - static void UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aClient); - /** * Flush all Images sent to CompositableHost. */ diff --git a/gfx/layers/ipc/PImageBridge.ipdl b/gfx/layers/ipc/PImageBridge.ipdl index 9f32993c6565..99a4a704407f 100644 --- a/gfx/layers/ipc/PImageBridge.ipdl +++ b/gfx/layers/ipc/PImageBridge.ipdl @@ -58,7 +58,7 @@ parent: sync Stop(); sync PCompositable(TextureInfo aInfo, - nullable PImageContainer aImageContainer) returns (uint64_t id); + PImageContainer aImageContainer) returns (uint64_t id); async PTexture(SurfaceDescriptor aSharedData, TextureFlags aTextureFlags); async PMediaSystemResourceManager(); async PImageContainer(); diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 37fcf8d5f216..5ce9a5863b88 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -107,7 +107,6 @@ EXPORTS.mozilla.layers += [ 'apz/util/ChromeProcessController.h', 'apz/util/DoubleTapToZoom.h', 'apz/util/InputAPZContext.h', - 'AsyncCanvasRenderer.h', 'AtomicRefCountedWithFinalize.h', 'AxisPhysicsModel.h', 'AxisPhysicsMSDModel.h', @@ -253,7 +252,6 @@ UNIFIED_SOURCES += [ 'apz/util/ChromeProcessController.cpp', 'apz/util/DoubleTapToZoom.cpp', 'apz/util/InputAPZContext.cpp', - 'AsyncCanvasRenderer.cpp', 'AxisPhysicsModel.cpp', 'AxisPhysicsMSDModel.cpp', 'basic/BasicCanvasLayer.cpp', diff --git a/gfx/src/gfxCrashReporterUtils.cpp b/gfx/src/gfxCrashReporterUtils.cpp index 670fe23e2e3a..69f9cf5074bc 100644 --- a/gfx/src/gfxCrashReporterUtils.cpp +++ b/gfx/src/gfxCrashReporterUtils.cpp @@ -84,22 +84,6 @@ public: } }; -class AppendAppNotesRunnable : public nsCancelableRunnable { -public: - explicit AppendAppNotesRunnable(nsAutoCString aFeatureStr) - : mFeatureString(aFeatureStr) - { - } - - NS_IMETHOD Run() override { - CrashReporter::AppendAppNotesToCrashReport(mFeatureString); - return NS_OK; - } - -private: - nsCString mFeatureString; -}; - void ScopedGfxFeatureReporter::WriteAppNote(char statusChar) { @@ -118,8 +102,7 @@ ScopedGfxFeatureReporter::WriteAppNote(char statusChar) if (!gFeaturesAlreadyReported->Contains(featureString)) { gFeaturesAlreadyReported->AppendElement(featureString); - nsCOMPtr r = new AppendAppNotesRunnable(featureString); - NS_DispatchToMainThread(r); + CrashReporter::AppendAppNotesToCrashReport(featureString); } } diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index ab2f6bb9aa08..6059111c19da 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -387,32 +387,12 @@ private: DECL_GFX_PREF(Live, "test.mousescroll", MouseScrollTestingEnabled, bool, false); DECL_GFX_PREF(Live, "ui.click_hold_context_menus.delay", UiClickHoldContextMenusDelay, int32_t, 500); - - // WebGL (for pref access from Worker threads) - DECL_GFX_PREF(Live, "webgl.all-angle-options", WebGLAllANGLEOptions, bool, false); - DECL_GFX_PREF(Live, "webgl.angle.force-d3d11", WebGLANGLEForceD3D11, bool, false); - DECL_GFX_PREF(Live, "webgl.angle.try-d3d11", WebGLANGLETryD3D11, bool, false); + DECL_GFX_PREF(Once, "webgl.angle.force-d3d11", WebGLANGLEForceD3D11, bool, false); + DECL_GFX_PREF(Once, "webgl.angle.try-d3d11", WebGLANGLETryD3D11, bool, false); DECL_GFX_PREF(Once, "webgl.angle.force-warp", WebGLANGLEForceWARP, bool, false); - DECL_GFX_PREF(Live, "webgl.bypass-shader-validation", WebGLBypassShaderValidator, bool, true); - DECL_GFX_PREF(Live, "webgl.can-lose-context-in-foreground", WebGLCanLoseContextInForeground, bool, true); - DECL_GFX_PREF(Live, "webgl.default-no-alpha", WebGLDefaultNoAlpha, bool, false); - DECL_GFX_PREF(Live, "webgl.disable-angle", WebGLDisableANGLE, bool, false); - DECL_GFX_PREF(Live, "webgl.disable-extensions", WebGLDisableExtensions, bool, false); - DECL_GFX_PREF(Live, "webgl.disable-fail-if-major-performance-caveat", WebGLDisableFailIfMajorPerformanceCaveat, bool, false); - DECL_GFX_PREF(Live, "webgl.disabled", WebGLDisabled, bool, false); - - DECL_GFX_PREF(Live, "webgl.enable-draft-extensions", WebGLDraftExtensionsEnabled, bool, false); - DECL_GFX_PREF(Live, "webgl.enable-privileged-extensions", WebGLPrivilegedExtensionsEnabled, bool, false); - DECL_GFX_PREF(Live, "webgl.force-enabled", WebGLForceEnabled, bool, false); - DECL_GFX_PREF(Live, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false); - DECL_GFX_PREF(Live, "webgl.lose-context-on-memory-pressure", WebGLLoseContextOnMemoryPressure, bool, false); - DECL_GFX_PREF(Live, "webgl.max-warnings-per-context", WebGLMaxWarningsPerContext, uint32_t, 32); - DECL_GFX_PREF(Live, "webgl.min_capability_mode", WebGLMinCapabilityMode, bool, false); - DECL_GFX_PREF(Live, "webgl.msaa-force", WebGLForceMSAA, bool, false); - DECL_GFX_PREF(Live, "webgl.prefer-16bpp", WebGLPrefer16bpp, bool, false); - DECL_GFX_PREF(Live, "webgl.restore-context-when-visible", WebGLRestoreWhenVisible, bool, true); + DECL_GFX_PREF(Once, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false); // WARNING: // Please make sure that you've added your new preference to the list above in alphabetical order. diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index 6821bc2f2701..2aea00695ebe 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -12,9 +12,6 @@ #include "gfxDrawable.h" #include "imgIEncoder.h" #include "mozilla/Base64.h" -#include "mozilla/dom/ImageEncoder.h" -#include "mozilla/dom/WorkerPrivate.h" -#include "mozilla/dom/WorkerRunnable.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/DataSurfaceHelpers.h" #include "mozilla/gfx/Logging.h" @@ -24,7 +21,6 @@ #include "nsComponentManagerUtils.h" #include "nsIClipboardHelper.h" #include "nsIFile.h" -#include "nsIGfxInfo.h" #include "nsIPresShell.h" #include "nsPresContext.h" #include "nsRegion.h" @@ -1547,125 +1543,6 @@ gfxUtils::CopyAsDataURI(DrawTarget* aDT) } } -/* static */ void -gfxUtils::GetImageBuffer(gfx::DataSourceSurface* aSurface, - bool aIsAlphaPremultiplied, - uint8_t** outImageBuffer, - int32_t* outFormat) -{ - *outImageBuffer = nullptr; - *outFormat = 0; - - DataSourceSurface::MappedSurface map; - if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) - return; - - uint32_t bufferSize = aSurface->GetSize().width * aSurface->GetSize().height * 4; - uint8_t* imageBuffer = new (fallible) uint8_t[bufferSize]; - if (!imageBuffer) { - aSurface->Unmap(); - return; - } - memcpy(imageBuffer, map.mData, bufferSize); - - aSurface->Unmap(); - - int32_t format = imgIEncoder::INPUT_FORMAT_HOSTARGB; - if (!aIsAlphaPremultiplied) { - // We need to convert to INPUT_FORMAT_RGBA, otherwise - // we are automatically considered premult, and unpremult'd. - // Yes, it is THAT silly. - // Except for different lossy conversions by color, - // we could probably just change the label, and not change the data. - gfxUtils::ConvertBGRAtoRGBA(imageBuffer, bufferSize); - format = imgIEncoder::INPUT_FORMAT_RGBA; - } - - *outImageBuffer = imageBuffer; - *outFormat = format; -} - -/* static */ nsresult -gfxUtils::GetInputStream(gfx::DataSourceSurface* aSurface, - bool aIsAlphaPremultiplied, - const char* aMimeType, - const char16_t* aEncoderOptions, - nsIInputStream** outStream) -{ - nsCString enccid("@mozilla.org/image/encoder;2?type="); - enccid += aMimeType; - nsCOMPtr encoder = do_CreateInstance(enccid.get()); - if (!encoder) - return NS_ERROR_FAILURE; - - nsAutoArrayPtr imageBuffer; - int32_t format = 0; - GetImageBuffer(aSurface, aIsAlphaPremultiplied, getter_Transfers(imageBuffer), &format); - if (!imageBuffer) - return NS_ERROR_FAILURE; - - return dom::ImageEncoder::GetInputStream(aSurface->GetSize().width, - aSurface->GetSize().height, - imageBuffer, format, - encoder, aEncoderOptions, outStream); -} - -class GetFeatureStatusRunnable final : public dom::workers::WorkerMainThreadRunnable -{ -public: - GetFeatureStatusRunnable(dom::workers::WorkerPrivate* workerPrivate, - const nsCOMPtr& gfxInfo, - int32_t feature, - int32_t* status) - : WorkerMainThreadRunnable(workerPrivate) - , mGfxInfo(gfxInfo) - , mFeature(feature) - , mStatus(status) - , mNSResult(NS_OK) - { - } - - bool MainThreadRun() override - { - if (mGfxInfo) { - mNSResult = mGfxInfo->GetFeatureStatus(mFeature, mStatus); - } - return true; - } - - nsresult GetNSResult() const - { - return mNSResult; - } - -protected: - ~GetFeatureStatusRunnable() {} - -private: - nsCOMPtr mGfxInfo; - int32_t mFeature; - int32_t* mStatus; - nsresult mNSResult; -}; - -/* static */ nsresult -gfxUtils::ThreadSafeGetFeatureStatus(const nsCOMPtr& gfxInfo, - int32_t feature, int32_t* status) -{ - if (!NS_IsMainThread()) { - dom::workers::WorkerPrivate* workerPrivate = - dom::workers::GetCurrentThreadWorkerPrivate(); - nsRefPtr runnable = - new GetFeatureStatusRunnable(workerPrivate, gfxInfo, feature, status); - - runnable->Dispatch(workerPrivate->GetJSContext()); - - return runnable->GetNSResult(); - } - - return gfxInfo->GetFeatureStatus(feature, status); -} - /* static */ bool gfxUtils::DumpDisplayList() { return gfxPrefs::LayoutDumpDisplayList(); diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index c5c29fe08bda..c1bfcc734c0d 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -17,8 +17,6 @@ class gfxASurface; class gfxDrawable; -class nsIInputStream; -class nsIGfxInfo; class nsIntRegion; class nsIPresShell; @@ -283,21 +281,6 @@ public: static nsCString GetAsDataURI(DrawTarget* aDT); static nsCString GetAsLZ4Base64Str(DataSourceSurface* aSourceSurface); - static void GetImageBuffer(DataSourceSurface* aSurface, - bool aIsAlphaPremultiplied, - uint8_t** outImageBuffer, - int32_t* outFormat); - - static nsresult GetInputStream(DataSourceSurface* aSurface, - bool aIsAlphaPremultiplied, - const char* aMimeType, - const char16_t* aEncoderOptions, - nsIInputStream** outStream); - - static nsresult ThreadSafeGetFeatureStatus(const nsCOMPtr& gfxInfo, - int32_t feature, - int32_t* status); - /** * Copy to the clipboard as a PNG encoded Data URL. */ diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index e4ba2ac7baa4..a678a18314a0 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -272,7 +272,6 @@ GENERATED_FILES = [ ] LOCAL_INCLUDES += [ - '/dom/workers', '/dom/xml', ] diff --git a/js/public/StructuredClone.h b/js/public/StructuredClone.h index fb72fb3ed6c9..e95b4ef8345c 100644 --- a/js/public/StructuredClone.h +++ b/js/public/StructuredClone.h @@ -195,20 +195,17 @@ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) { void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); // Copy some memory. It will be automatically freed by the destructor. - bool copy(const uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION, - const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr); + bool copy(const uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION); // Adopt some memory. It will be automatically freed by the destructor. // data must have been allocated by the JS engine (e.g., extracted via // JSAutoStructuredCloneBuffer::steal). - void adopt(uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION, - const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr); + void adopt(uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION); // Release the buffer and transfer ownership to the caller. The caller is // responsible for calling JS_ClearStructuredClone or feeding the memory // back to JSAutoStructuredCloneBuffer::adopt. - void steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp=nullptr, - const JSStructuredCloneCallbacks** callbacks=nullptr, void** closure=nullptr); + void steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp=nullptr); // Abandon ownership of any transferable objects stored in the buffer, // without freeing the buffer itself. Useful when copying the data out into diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 505b3198e6c0..00c916eb73db 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -2054,7 +2054,7 @@ JS_StructuredClone(JSContext* cx, HandleValue value, MutableHandleValue vp, JSAutoStructuredCloneBuffer::JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other) { ownTransferables_ = other.ownTransferables_; - other.steal(&data_, &nbytes_, &version_, &callbacks_, &closure_); + other.steal(&data_, &nbytes_, &version_); } JSAutoStructuredCloneBuffer& @@ -2063,7 +2063,7 @@ JSAutoStructuredCloneBuffer::operator=(JSAutoStructuredCloneBuffer&& other) MOZ_ASSERT(&other != this); clear(); ownTransferables_ = other.ownTransferables_; - other.steal(&data_, &nbytes_, &version_, &callbacks_, &closure_); + other.steal(&data_, &nbytes_, &version_); return *this; } @@ -2088,9 +2088,7 @@ JSAutoStructuredCloneBuffer::clear(const JSStructuredCloneCallbacks* optionalCal } bool -JSAutoStructuredCloneBuffer::copy(const uint64_t* srcData, size_t nbytes, uint32_t version, - const JSStructuredCloneCallbacks* callbacks, - void* closure) +JSAutoStructuredCloneBuffer::copy(const uint64_t* srcData, size_t nbytes, uint32_t version) { // transferable objects cannot be copied if (StructuredCloneHasTransferObjects(data_, nbytes_)) @@ -2106,45 +2104,31 @@ JSAutoStructuredCloneBuffer::copy(const uint64_t* srcData, size_t nbytes, uint32 data_ = newData; nbytes_ = nbytes; version_ = version; - callbacks_ = callbacks; - closure_ = closure; ownTransferables_ = NoTransferables; return true; } void -JSAutoStructuredCloneBuffer::adopt(uint64_t* data, size_t nbytes, uint32_t version, - const JSStructuredCloneCallbacks* callbacks, - void* closure) +JSAutoStructuredCloneBuffer::adopt(uint64_t* data, size_t nbytes, uint32_t version) { clear(); data_ = data; nbytes_ = nbytes; version_ = version; - callbacks_ = callbacks; - closure_ = closure; ownTransferables_ = OwnsTransferablesIfAny; } void -JSAutoStructuredCloneBuffer::steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp, - const JSStructuredCloneCallbacks** callbacks, - void** closure) +JSAutoStructuredCloneBuffer::steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp) { *datap = data_; *nbytesp = nbytes_; if (versionp) *versionp = version_; - if (callbacks) - *callbacks = callbacks_; - if (closure) - *closure = closure_; data_ = nullptr; nbytes_ = 0; version_ = 0; - callbacks_ = 0; - closure_ = 0; ownTransferables_ = NoTransferables; } diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 2505d262224e..987c9a0d802e 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4166,8 +4166,6 @@ pref("webgl.angle.force-d3d11", false); pref("webgl.angle.force-warp", false); #endif -pref("gfx.offscreencanvas.enabled", false); - #ifdef MOZ_WIDGET_GONK pref("gfx.gralloc.fence-with-readpixels", false); #endif From 042c2e23718e324fd980ab5b1124b03916424a13 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 29 Sep 2015 09:03:14 -0700 Subject: [PATCH 060/104] Bug 1204863 - Ignore frames from self-hosted scripts; r=shu --- js/src/doc/Debugger/Debugger-API.md | 4 ++++ js/src/jit-test/tests/debug/bug-1204863.js | 5 +++++ js/src/vm/Debugger.cpp | 10 ++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 js/src/jit-test/tests/debug/bug-1204863.js diff --git a/js/src/doc/Debugger/Debugger-API.md b/js/src/doc/Debugger/Debugger-API.md index 3703c5d45f5d..10f6ebf895fb 100644 --- a/js/src/doc/Debugger/Debugger-API.md +++ b/js/src/doc/Debugger/Debugger-API.md @@ -37,6 +37,10 @@ it ought not to introduce security holes, so in principle it could be made available to content as well; but it is hard to justify the security risks of the additional attack surface. +The `Debugger` API cannot currently observe self-hosted JavaScript. This is not +inherent in the API's design, but simply that the self-hosting infrastructure +isn't prepared for the kind of invasions the `Debugger` API can perform. + ## Debugger Instances and Shadow Objects diff --git a/js/src/jit-test/tests/debug/bug-1204863.js b/js/src/jit-test/tests/debug/bug-1204863.js new file mode 100644 index 000000000000..aa7d59c66cd7 --- /dev/null +++ b/js/src/jit-test/tests/debug/bug-1204863.js @@ -0,0 +1,5 @@ +var dbg = newGlobal().Debugger(this); +dbg.onExceptionUnwind = function (frame, exc) { + return { return:"sproon" }; +}; +Intl.Collator.supportedLocalesOf([2]); diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index f55cb24db7e6..66fc69449607 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -455,6 +455,7 @@ Debugger::getScriptFrameWithIter(JSContext* cx, AbstractFramePtr frame, const ScriptFrameIter* maybeIter, MutableHandleValue vp) { MOZ_ASSERT_IF(maybeIter, maybeIter->abstractFramePtr() == frame); + MOZ_ASSERT(!frame.script()->selfHosted()); FrameMap::AddPtr p = frames.lookupForAdd(frame); if (!p) { @@ -726,6 +727,10 @@ Debugger::slowPathOnExceptionUnwind(JSContext* cx, AbstractFramePtr frame) if (cx->isThrowingOverRecursed() || cx->isThrowingOutOfMemory()) return JSTRAP_CONTINUE; + // The Debugger API mustn't muck with frames from self-hosted scripts. + if (frame.script()->selfHosted()) + return JSTRAP_CONTINUE; + RootedValue rval(cx); JSTrapStatus status = dispatchHook( cx, @@ -5265,8 +5270,9 @@ Debugger::observesScript(JSScript* script) const { if (!enabled) return false; - return observesGlobal(&script->global()) && (!script->selfHosted() || - SelfHostedFramesVisible()); + // Don't ever observe self-hosted scripts: the Debugger API can break + // self-hosted invariants. + return observesGlobal(&script->global()) && !script->selfHosted(); } /* static */ bool From c20cbbbfaea8e9ad171c36ba653e89889c1bc0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Pag=C3=A8s?= Date: Fri, 25 Sep 2015 22:39:03 +0200 Subject: [PATCH 061/104] Bug 1195288 - consider using python webserver for production talos. r=jmaher Always use an in-process webserver, removing the need for apache - and hopefuly providing better accuracy for numbers. This means that we know have to copy the pagesets in the talos dir on harness. On windows, some pagesets paths were too long due to that, so the solution is to replace "page_load_test" with "tests". --HG-- rename : testing/talos/talos/page_load_test/a11y/a11y.js => testing/talos/talos/tests/a11y/a11y.js rename : testing/talos/talos/page_load_test/a11y/a11y.manifest => testing/talos/talos/tests/a11y/a11y.manifest rename : testing/talos/talos/page_load_test/a11y/dhtml.html => testing/talos/talos/tests/a11y/dhtml.html rename : testing/talos/talos/page_load_test/a11y/tablemutation.html => testing/talos/talos/tests/a11y/tablemutation.html rename : testing/talos/talos/page_load_test/canvasmark/HelveticaNeueLTStd-Lt.otf => testing/talos/talos/tests/canvasmark/HelveticaNeueLTStd-Lt.otf rename : testing/talos/talos/page_load_test/canvasmark/HelveticaNeueLTStd-Md.otf => testing/talos/talos/tests/canvasmark/HelveticaNeueLTStd-Md.otf rename : testing/talos/talos/page_load_test/canvasmark/canvasmark.manifest => testing/talos/talos/tests/canvasmark/canvasmark.manifest rename : testing/talos/talos/page_load_test/canvasmark/images/asteroid1.png => testing/talos/talos/tests/canvasmark/images/asteroid1.png rename : testing/talos/talos/page_load_test/canvasmark/images/asteroid2.png => testing/talos/talos/tests/canvasmark/images/asteroid2.png rename : testing/talos/talos/page_load_test/canvasmark/images/asteroid3.png => testing/talos/talos/tests/canvasmark/images/asteroid3.png rename : testing/talos/talos/page_load_test/canvasmark/images/asteroid4.png => testing/talos/talos/tests/canvasmark/images/asteroid4.png rename : testing/talos/talos/page_load_test/canvasmark/images/bg3_1.jpg => testing/talos/talos/tests/canvasmark/images/bg3_1.jpg rename : testing/talos/talos/page_load_test/canvasmark/images/canvasmark2013.jpg => testing/talos/talos/tests/canvasmark/images/canvasmark2013.jpg rename : testing/talos/talos/page_load_test/canvasmark/images/enemyship1.png => testing/talos/talos/tests/canvasmark/images/enemyship1.png rename : testing/talos/talos/page_load_test/canvasmark/images/fruit.jpg => testing/talos/talos/tests/canvasmark/images/fruit.jpg rename : testing/talos/talos/page_load_test/canvasmark/images/player.png => testing/talos/talos/tests/canvasmark/images/player.png rename : testing/talos/talos/page_load_test/canvasmark/images/texture5.png => testing/talos/talos/tests/canvasmark/images/texture5.png rename : testing/talos/talos/page_load_test/canvasmark/index.html => testing/talos/talos/tests/canvasmark/index.html rename : testing/talos/talos/page_load_test/canvasmark/license.txt => testing/talos/talos/tests/canvasmark/license.txt rename : testing/talos/talos/page_load_test/canvasmark/ostrich-black-webfont.woff => testing/talos/talos/tests/canvasmark/ostrich-black-webfont.woff rename : testing/talos/talos/page_load_test/canvasmark/scripts/canvasmark_v6.js => testing/talos/talos/tests/canvasmark/scripts/canvasmark_v6.js rename : testing/talos/talos/page_load_test/canvasmark/scripts/jquery-1.4.2.min.js => testing/talos/talos/tests/canvasmark/scripts/jquery-1.4.2.min.js rename : testing/talos/talos/page_load_test/canvasmark/scripts/k3d-min.js => testing/talos/talos/tests/canvasmark/scripts/k3d-min.js rename : testing/talos/talos/page_load_test/canvasmark/scripts/mathlib-min.js => testing/talos/talos/tests/canvasmark/scripts/mathlib-min.js rename : testing/talos/talos/page_load_test/devtools/addon/chrome.manifest => testing/talos/talos/tests/devtools/addon/chrome.manifest rename : testing/talos/talos/page_load_test/devtools/addon/content/Profiler.js => testing/talos/talos/tests/devtools/addon/content/Profiler.js rename : testing/talos/talos/page_load_test/devtools/addon/content/addon-test-frontend.js => testing/talos/talos/tests/devtools/addon/content/addon-test-frontend.js rename : testing/talos/talos/page_load_test/devtools/addon/content/damp.html => testing/talos/talos/tests/devtools/addon/content/damp.html rename : testing/talos/talos/page_load_test/devtools/addon/content/damp.js => testing/talos/talos/tests/devtools/addon/content/damp.js rename : testing/talos/talos/page_load_test/devtools/addon/content/damp.overlay.xul => testing/talos/talos/tests/devtools/addon/content/damp.overlay.xul rename : testing/talos/talos/page_load_test/devtools/addon/content/framescript.js => testing/talos/talos/tests/devtools/addon/content/framescript.js rename : testing/talos/talos/page_load_test/devtools/addon/content/pages/simple.html => testing/talos/talos/tests/devtools/addon/content/pages/simple.html rename : testing/talos/talos/page_load_test/devtools/addon/install.rdf => testing/talos/talos/tests/devtools/addon/install.rdf rename : testing/talos/talos/page_load_test/devtools/damp.manifest => testing/talos/talos/tests/devtools/damp.manifest rename : testing/talos/talos/page_load_test/dromaeo/JSON.php => testing/talos/talos/tests/dromaeo/JSON.php rename : testing/talos/talos/page_load_test/dromaeo/LICENSE => testing/talos/talos/tests/dromaeo/LICENSE rename : testing/talos/talos/page_load_test/dromaeo/application.css => testing/talos/talos/tests/dromaeo/application.css rename : testing/talos/talos/page_load_test/dromaeo/css.manifest => testing/talos/talos/tests/dromaeo/css.manifest rename : testing/talos/talos/page_load_test/dromaeo/cssquery-dojo.html => testing/talos/talos/tests/dromaeo/cssquery-dojo.html rename : testing/talos/talos/page_load_test/dromaeo/cssquery-ext.html => testing/talos/talos/tests/dromaeo/cssquery-ext.html rename : testing/talos/talos/page_load_test/dromaeo/cssquery-jquery.html => testing/talos/talos/tests/dromaeo/cssquery-jquery.html rename : testing/talos/talos/page_load_test/dromaeo/cssquery-mootools.html => testing/talos/talos/tests/dromaeo/cssquery-mootools.html rename : testing/talos/talos/page_load_test/dromaeo/cssquery-prototype.html => testing/talos/talos/tests/dromaeo/cssquery-prototype.html rename : testing/talos/talos/page_load_test/dromaeo/cssquery-yui.html => testing/talos/talos/tests/dromaeo/cssquery-yui.html rename : testing/talos/talos/page_load_test/dromaeo/dom-attr.html => testing/talos/talos/tests/dromaeo/dom-attr.html rename : testing/talos/talos/page_load_test/dromaeo/dom-modify.html => testing/talos/talos/tests/dromaeo/dom-modify.html rename : testing/talos/talos/page_load_test/dromaeo/dom-query.html => testing/talos/talos/tests/dromaeo/dom-query.html rename : testing/talos/talos/page_load_test/dromaeo/dom-traverse.html => testing/talos/talos/tests/dromaeo/dom-traverse.html rename : testing/talos/talos/page_load_test/dromaeo/dom.manifest => testing/talos/talos/tests/dromaeo/dom.manifest rename : testing/talos/talos/page_load_test/dromaeo/favicon.ico => testing/talos/talos/tests/dromaeo/favicon.ico rename : testing/talos/talos/page_load_test/dromaeo/favicon.png => testing/talos/talos/tests/dromaeo/favicon.png rename : testing/talos/talos/page_load_test/dromaeo/htmlrunner.js => testing/talos/talos/tests/dromaeo/htmlrunner.js rename : testing/talos/talos/page_load_test/dromaeo/ie.css => testing/talos/talos/tests/dromaeo/ie.css rename : testing/talos/talos/page_load_test/dromaeo/images/bg.png => testing/talos/talos/tests/dromaeo/images/bg.png rename : testing/talos/talos/page_load_test/dromaeo/images/clouds.png => testing/talos/talos/tests/dromaeo/images/clouds.png rename : testing/talos/talos/page_load_test/dromaeo/images/clouds2.png => testing/talos/talos/tests/dromaeo/images/clouds2.png rename : testing/talos/talos/page_load_test/dromaeo/images/comets.png => testing/talos/talos/tests/dromaeo/images/comets.png rename : testing/talos/talos/page_load_test/dromaeo/images/dino1.png => testing/talos/talos/tests/dromaeo/images/dino1.png rename : testing/talos/talos/page_load_test/dromaeo/images/dino2.png => testing/talos/talos/tests/dromaeo/images/dino2.png rename : testing/talos/talos/page_load_test/dromaeo/images/dino3.png => testing/talos/talos/tests/dromaeo/images/dino3.png rename : testing/talos/talos/page_load_test/dromaeo/images/dino4.png => testing/talos/talos/tests/dromaeo/images/dino4.png rename : testing/talos/talos/page_load_test/dromaeo/images/dino5.png => testing/talos/talos/tests/dromaeo/images/dino5.png rename : testing/talos/talos/page_load_test/dromaeo/images/dino6.png => testing/talos/talos/tests/dromaeo/images/dino6.png rename : testing/talos/talos/page_load_test/dromaeo/images/dino7.png => testing/talos/talos/tests/dromaeo/images/dino7.png rename : testing/talos/talos/page_load_test/dromaeo/images/dino8.png => testing/talos/talos/tests/dromaeo/images/dino8.png rename : testing/talos/talos/page_load_test/dromaeo/images/left.png => testing/talos/talos/tests/dromaeo/images/left.png rename : testing/talos/talos/page_load_test/dromaeo/images/logo.png => testing/talos/talos/tests/dromaeo/images/logo.png rename : testing/talos/talos/page_load_test/dromaeo/images/logo2.png => testing/talos/talos/tests/dromaeo/images/logo2.png rename : testing/talos/talos/page_load_test/dromaeo/images/logo3.png => testing/talos/talos/tests/dromaeo/images/logo3.png rename : testing/talos/talos/page_load_test/dromaeo/images/right.png => testing/talos/talos/tests/dromaeo/images/right.png rename : testing/talos/talos/page_load_test/dromaeo/images/top.png => testing/talos/talos/tests/dromaeo/images/top.png rename : testing/talos/talos/page_load_test/dromaeo/images/water.png => testing/talos/talos/tests/dromaeo/images/water.png rename : testing/talos/talos/page_load_test/dromaeo/index.html => testing/talos/talos/tests/dromaeo/index.html rename : testing/talos/talos/page_load_test/dromaeo/jquery.js => testing/talos/talos/tests/dromaeo/jquery.js rename : testing/talos/talos/page_load_test/dromaeo/json.js => testing/talos/talos/tests/dromaeo/json.js rename : testing/talos/talos/page_load_test/dromaeo/lib/dojo.js => testing/talos/talos/tests/dromaeo/lib/dojo.js rename : testing/talos/talos/page_load_test/dromaeo/lib/ext-base.js => testing/talos/talos/tests/dromaeo/lib/ext-base.js rename : testing/talos/talos/page_load_test/dromaeo/lib/ext-core.js => testing/talos/talos/tests/dromaeo/lib/ext-core.js rename : testing/talos/talos/page_load_test/dromaeo/lib/jquery.js => testing/talos/talos/tests/dromaeo/lib/jquery.js rename : testing/talos/talos/page_load_test/dromaeo/lib/mootools.js => testing/talos/talos/tests/dromaeo/lib/mootools.js rename : testing/talos/talos/page_load_test/dromaeo/lib/prototype.js => testing/talos/talos/tests/dromaeo/lib/prototype.js rename : testing/talos/talos/page_load_test/dromaeo/lib/yahoo.js => testing/talos/talos/tests/dromaeo/lib/yahoo.js rename : testing/talos/talos/page_load_test/dromaeo/lib/yui-dom.js => testing/talos/talos/tests/dromaeo/lib/yui-dom.js rename : testing/talos/talos/page_load_test/dromaeo/lib/yui-event.js => testing/talos/talos/tests/dromaeo/lib/yui-event.js rename : testing/talos/talos/page_load_test/dromaeo/lib/yui-selector.js => testing/talos/talos/tests/dromaeo/lib/yui-selector.js rename : testing/talos/talos/page_load_test/dromaeo/pngfix.js => testing/talos/talos/tests/dromaeo/pngfix.js rename : testing/talos/talos/page_load_test/dromaeo/reset.css => testing/talos/talos/tests/dromaeo/reset.css rename : testing/talos/talos/page_load_test/dromaeo/store.php => testing/talos/talos/tests/dromaeo/store.php rename : testing/talos/talos/page_load_test/dromaeo/test-head.html => testing/talos/talos/tests/dromaeo/test-head.html rename : testing/talos/talos/page_load_test/dromaeo/test-head.js => testing/talos/talos/tests/dromaeo/test-head.js rename : testing/talos/talos/page_load_test/dromaeo/test-tail.html => testing/talos/talos/tests/dromaeo/test-tail.html rename : testing/talos/talos/page_load_test/dromaeo/test-tail.js => testing/talos/talos/tests/dromaeo/test-tail.js rename : testing/talos/talos/page_load_test/dromaeo/tests/MANIFEST.json => testing/talos/talos/tests/dromaeo/tests/MANIFEST.json rename : testing/talos/talos/page_load_test/dromaeo/tests/cssquery-dojo.html => testing/talos/talos/tests/dromaeo/tests/cssquery-dojo.html rename : testing/talos/talos/page_load_test/dromaeo/tests/cssquery-ext.html => testing/talos/talos/tests/dromaeo/tests/cssquery-ext.html rename : testing/talos/talos/page_load_test/dromaeo/tests/cssquery-jquery.html => testing/talos/talos/tests/dromaeo/tests/cssquery-jquery.html rename : testing/talos/talos/page_load_test/dromaeo/tests/cssquery-mootools.html => testing/talos/talos/tests/dromaeo/tests/cssquery-mootools.html rename : testing/talos/talos/page_load_test/dromaeo/tests/cssquery-prototype.html => testing/talos/talos/tests/dromaeo/tests/cssquery-prototype.html rename : testing/talos/talos/page_load_test/dromaeo/tests/cssquery-yui.html => testing/talos/talos/tests/dromaeo/tests/cssquery-yui.html rename : testing/talos/talos/page_load_test/dromaeo/tests/dom-attr.html => testing/talos/talos/tests/dromaeo/tests/dom-attr.html rename : testing/talos/talos/page_load_test/dromaeo/tests/dom-modify.html => testing/talos/talos/tests/dromaeo/tests/dom-modify.html rename : testing/talos/talos/page_load_test/dromaeo/tests/dom-query.html => testing/talos/talos/tests/dromaeo/tests/dom-query.html rename : testing/talos/talos/page_load_test/dromaeo/tests/dom-traverse.html => testing/talos/talos/tests/dromaeo/tests/dom-traverse.html rename : testing/talos/talos/page_load_test/dromaeo/tests/dromaeo-3d-cube.html => testing/talos/talos/tests/dromaeo/tests/dromaeo-3d-cube.html rename : testing/talos/talos/page_load_test/dromaeo/tests/dromaeo-core-eval.html => testing/talos/talos/tests/dromaeo/tests/dromaeo-core-eval.html rename : testing/talos/talos/page_load_test/dromaeo/tests/dromaeo-object-array.html => testing/talos/talos/tests/dromaeo/tests/dromaeo-object-array.html rename : testing/talos/talos/page_load_test/dromaeo/tests/dromaeo-object-regexp.html => testing/talos/talos/tests/dromaeo/tests/dromaeo-object-regexp.html rename : testing/talos/talos/page_load_test/dromaeo/tests/dromaeo-object-string.html => testing/talos/talos/tests/dromaeo/tests/dromaeo-object-string.html rename : testing/talos/talos/page_load_test/dromaeo/tests/dromaeo-string-base64.html => testing/talos/talos/tests/dromaeo/tests/dromaeo-string-base64.html rename : testing/talos/talos/page_load_test/dromaeo/tests/jslib-attr-jquery.html => testing/talos/talos/tests/dromaeo/tests/jslib-attr-jquery.html rename : testing/talos/talos/page_load_test/dromaeo/tests/jslib-attr-prototype.html => testing/talos/talos/tests/dromaeo/tests/jslib-attr-prototype.html rename : testing/talos/talos/page_load_test/dromaeo/tests/jslib-event-jquery.html => testing/talos/talos/tests/dromaeo/tests/jslib-event-jquery.html rename : testing/talos/talos/page_load_test/dromaeo/tests/jslib-event-prototype.html => testing/talos/talos/tests/dromaeo/tests/jslib-event-prototype.html rename : testing/talos/talos/page_load_test/dromaeo/tests/jslib-modify-jquery.html => testing/talos/talos/tests/dromaeo/tests/jslib-modify-jquery.html rename : testing/talos/talos/page_load_test/dromaeo/tests/jslib-modify-prototype.html => testing/talos/talos/tests/dromaeo/tests/jslib-modify-prototype.html rename : testing/talos/talos/page_load_test/dromaeo/tests/jslib-style-jquery.html => testing/talos/talos/tests/dromaeo/tests/jslib-style-jquery.html rename : testing/talos/talos/page_load_test/dromaeo/tests/jslib-style-prototype.html => testing/talos/talos/tests/dromaeo/tests/jslib-style-prototype.html rename : testing/talos/talos/page_load_test/dromaeo/tests/jslib-traverse-jquery.html => testing/talos/talos/tests/dromaeo/tests/jslib-traverse-jquery.html rename : testing/talos/talos/page_load_test/dromaeo/tests/jslib-traverse-prototype.html => testing/talos/talos/tests/dromaeo/tests/jslib-traverse-prototype.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-3d-morph.html => testing/talos/talos/tests/dromaeo/tests/sunspider-3d-morph.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-3d-raytrace.html => testing/talos/talos/tests/dromaeo/tests/sunspider-3d-raytrace.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-access-binary-trees.html => testing/talos/talos/tests/dromaeo/tests/sunspider-access-binary-trees.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-access-fannkuch.html => testing/talos/talos/tests/dromaeo/tests/sunspider-access-fannkuch.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-access-nbody.html => testing/talos/talos/tests/dromaeo/tests/sunspider-access-nbody.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-access-nsieve.html => testing/talos/talos/tests/dromaeo/tests/sunspider-access-nsieve.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-bitops-3bit-bits-in-byte.html => testing/talos/talos/tests/dromaeo/tests/sunspider-bitops-3bit-bits-in-byte.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-bitops-bits-in-byte.html => testing/talos/talos/tests/dromaeo/tests/sunspider-bitops-bits-in-byte.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-bitops-bitwise-and.html => testing/talos/talos/tests/dromaeo/tests/sunspider-bitops-bitwise-and.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-bitops-nsieve-bits.html => testing/talos/talos/tests/dromaeo/tests/sunspider-bitops-nsieve-bits.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-controlflow-recursive.html => testing/talos/talos/tests/dromaeo/tests/sunspider-controlflow-recursive.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-crypto-aes.html => testing/talos/talos/tests/dromaeo/tests/sunspider-crypto-aes.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-crypto-md5.html => testing/talos/talos/tests/dromaeo/tests/sunspider-crypto-md5.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-crypto-sha1.html => testing/talos/talos/tests/dromaeo/tests/sunspider-crypto-sha1.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-date-format-tofte.html => testing/talos/talos/tests/dromaeo/tests/sunspider-date-format-tofte.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-date-format-xparb.html => testing/talos/talos/tests/dromaeo/tests/sunspider-date-format-xparb.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-math-cordic.html => testing/talos/talos/tests/dromaeo/tests/sunspider-math-cordic.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-math-partial-sums.html => testing/talos/talos/tests/dromaeo/tests/sunspider-math-partial-sums.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-math-spectral-norm.html => testing/talos/talos/tests/dromaeo/tests/sunspider-math-spectral-norm.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-regexp-dna.html => testing/talos/talos/tests/dromaeo/tests/sunspider-regexp-dna.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-string-fasta.html => testing/talos/talos/tests/dromaeo/tests/sunspider-string-fasta.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-string-tagcloud.html => testing/talos/talos/tests/dromaeo/tests/sunspider-string-tagcloud.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-string-unpack-code.html => testing/talos/talos/tests/dromaeo/tests/sunspider-string-unpack-code.html rename : testing/talos/talos/page_load_test/dromaeo/tests/sunspider-string-validate-input.html => testing/talos/talos/tests/dromaeo/tests/sunspider-string-validate-input.html rename : testing/talos/talos/page_load_test/dromaeo/tests/v8-crypto.html => testing/talos/talos/tests/dromaeo/tests/v8-crypto.html rename : testing/talos/talos/page_load_test/dromaeo/tests/v8-deltablue.html => testing/talos/talos/tests/dromaeo/tests/v8-deltablue.html rename : testing/talos/talos/page_load_test/dromaeo/tests/v8-earley-boyer.html => testing/talos/talos/tests/dromaeo/tests/v8-earley-boyer.html rename : testing/talos/talos/page_load_test/dromaeo/tests/v8-raytrace.html => testing/talos/talos/tests/dromaeo/tests/v8-raytrace.html rename : testing/talos/talos/page_load_test/dromaeo/tests/v8-richards.html => testing/talos/talos/tests/dromaeo/tests/v8-richards.html rename : testing/talos/talos/page_load_test/dromaeo/web-style.css => testing/talos/talos/tests/dromaeo/web-style.css rename : testing/talos/talos/page_load_test/dromaeo/webrunner.js => testing/talos/talos/tests/dromaeo/webrunner.js rename : testing/talos/talos/page_load_test/kraken/driver.html => testing/talos/talos/tests/kraken/driver.html rename : testing/talos/talos/page_load_test/kraken/kraken.css => testing/talos/talos/tests/kraken/kraken.css rename : testing/talos/talos/page_load_test/kraken/kraken.manifest => testing/talos/talos/tests/kraken/kraken.manifest rename : testing/talos/talos/page_load_test/kraken/test-contents.js => testing/talos/talos/tests/kraken/test-contents.js rename : testing/talos/talos/page_load_test/kraken/test-prefix.js => testing/talos/talos/tests/kraken/test-prefix.js rename : testing/talos/talos/page_load_test/quit.js => testing/talos/talos/tests/quit.js rename : testing/talos/talos/page_load_test/scroll/drac.htm => testing/talos/talos/tests/scroll/drac.htm rename : testing/talos/talos/page_load_test/scroll/iframe.svg => testing/talos/talos/tests/scroll/iframe.svg rename : testing/talos/talos/page_load_test/scroll/reader.css => testing/talos/talos/tests/scroll/reader.css rename : testing/talos/talos/page_load_test/scroll/reader.htm => testing/talos/talos/tests/scroll/reader.htm rename : testing/talos/talos/page_load_test/scroll/scroll-test.js => testing/talos/talos/tests/scroll/scroll-test.js rename : testing/talos/talos/page_load_test/scroll/scroll.js => testing/talos/talos/tests/scroll/scroll.js rename : testing/talos/talos/page_load_test/scroll/scroll.manifest => testing/talos/talos/tests/scroll/scroll.manifest rename : testing/talos/talos/page_load_test/scroll/strips-single.png => testing/talos/talos/tests/scroll/strips-single.png rename : testing/talos/talos/page_load_test/scroll/strips.png => testing/talos/talos/tests/scroll/strips.png rename : testing/talos/talos/page_load_test/scroll/tiled-downscale.html => testing/talos/talos/tests/scroll/tiled-downscale.html rename : testing/talos/talos/page_load_test/scroll/tiled-fixed-downscale.html => testing/talos/talos/tests/scroll/tiled-fixed-downscale.html rename : testing/talos/talos/page_load_test/scroll/tiled-fixed.html => testing/talos/talos/tests/scroll/tiled-fixed.html rename : testing/talos/talos/page_load_test/scroll/tiled.html => testing/talos/talos/tests/scroll/tiled.html rename : testing/talos/talos/page_load_test/svg_opacity/big-optimizable-group-opacity-2500.svg => testing/talos/talos/tests/svg_opacity/big-optimizable-group-opacity-2500.svg rename : testing/talos/talos/page_load_test/svg_opacity/small-group-opacity-2500.svg => testing/talos/talos/tests/svg_opacity/small-group-opacity-2500.svg rename : testing/talos/talos/page_load_test/svg_opacity/svg_opacity.manifest => testing/talos/talos/tests/svg_opacity/svg_opacity.manifest rename : testing/talos/talos/page_load_test/svgx/composite-scale-opacity.svg => testing/talos/talos/tests/svgx/composite-scale-opacity.svg rename : testing/talos/talos/page_load_test/svgx/composite-scale-rotate-opacity.svg => testing/talos/talos/tests/svgx/composite-scale-rotate-opacity.svg rename : testing/talos/talos/page_load_test/svgx/composite-scale-rotate.svg => testing/talos/talos/tests/svgx/composite-scale-rotate.svg rename : testing/talos/talos/page_load_test/svgx/composite-scale.svg => testing/talos/talos/tests/svgx/composite-scale.svg rename : testing/talos/talos/page_load_test/svgx/gearflowers.svg => testing/talos/talos/tests/svgx/gearflowers.svg rename : testing/talos/talos/page_load_test/svgx/hixie-001.xml => testing/talos/talos/tests/svgx/hixie-001.xml rename : testing/talos/talos/page_load_test/svgx/hixie-002.xml => testing/talos/talos/tests/svgx/hixie-002.xml rename : testing/talos/talos/page_load_test/svgx/hixie-003.xml => testing/talos/talos/tests/svgx/hixie-003.xml rename : testing/talos/talos/page_load_test/svgx/hixie-004.xml => testing/talos/talos/tests/svgx/hixie-004.xml rename : testing/talos/talos/page_load_test/svgx/hixie-005.xml => testing/talos/talos/tests/svgx/hixie-005.xml rename : testing/talos/talos/page_load_test/svgx/hixie-006.xml => testing/talos/talos/tests/svgx/hixie-006.xml rename : testing/talos/talos/page_load_test/svgx/hixie-007.xml => testing/talos/talos/tests/svgx/hixie-007.xml rename : testing/talos/talos/page_load_test/svgx/images/kyoto_1.jpg => testing/talos/talos/tests/svgx/images/kyoto_1.jpg rename : testing/talos/talos/page_load_test/svgx/images/kyoto_2.jpg => testing/talos/talos/tests/svgx/images/kyoto_2.jpg rename : testing/talos/talos/page_load_test/svgx/images/smallcats.gif => testing/talos/talos/tests/svgx/images/smallcats.gif rename : testing/talos/talos/page_load_test/svgx/svgm.manifest => testing/talos/talos/tests/svgx/svgm.manifest rename : testing/talos/talos/page_load_test/svgx/svgx.manifest => testing/talos/talos/tests/svgx/svgx.manifest rename : testing/talos/talos/page_load_test/tabswitch/bootstrap.js => testing/talos/talos/tests/tabswitch/bootstrap.js rename : testing/talos/talos/page_load_test/tabswitch/chrome.manifest => testing/talos/talos/tests/tabswitch/chrome.manifest rename : testing/talos/talos/page_load_test/tabswitch/content/options.xul => testing/talos/talos/tests/tabswitch/content/options.xul rename : testing/talos/talos/page_load_test/tabswitch/content/test.html => testing/talos/talos/tests/tabswitch/content/test.html rename : testing/talos/talos/page_load_test/tabswitch/install.rdf => testing/talos/talos/tests/tabswitch/install.rdf rename : testing/talos/talos/page_load_test/tabswitch/tps.manifest => testing/talos/talos/tests/tabswitch/tps.manifest rename : testing/talos/talos/page_load_test/tart/addon/chrome.manifest => testing/talos/talos/tests/tart/addon/chrome.manifest rename : testing/talos/talos/page_load_test/tart/addon/content/Profiler.js => testing/talos/talos/tests/tart/addon/content/Profiler.js rename : testing/talos/talos/page_load_test/tart/addon/content/blank.icon.html => testing/talos/talos/tests/tart/addon/content/blank.icon.html rename : testing/talos/talos/page_load_test/tart/addon/content/framescript.js => testing/talos/talos/tests/tart/addon/content/framescript.js rename : testing/talos/talos/page_load_test/tart/addon/content/tab-min-width-1px.css => testing/talos/talos/tests/tart/addon/content/tab-min-width-1px.css rename : testing/talos/talos/page_load_test/tart/addon/content/tart.html => testing/talos/talos/tests/tart/addon/content/tart.html rename : testing/talos/talos/page_load_test/tart/addon/content/tart.ico => testing/talos/talos/tests/tart/addon/content/tart.ico rename : testing/talos/talos/page_load_test/tart/addon/content/tart.js => testing/talos/talos/tests/tart/addon/content/tart.js rename : testing/talos/talos/page_load_test/tart/addon/content/tart.overlay.xul => testing/talos/talos/tests/tart/addon/content/tart.overlay.xul rename : testing/talos/talos/page_load_test/tart/addon/install.rdf => testing/talos/talos/tests/tart/addon/install.rdf rename : testing/talos/talos/page_load_test/tart/cart.manifest => testing/talos/talos/tests/tart/cart.manifest rename : testing/talos/talos/page_load_test/tart/tart.manifest => testing/talos/talos/tests/tart/tart.manifest rename : testing/talos/talos/page_load_test/tp5o.html => testing/talos/talos/tests/tp5o.html rename : testing/talos/talos/page_load_test/v8_7/base.js => testing/talos/talos/tests/v8_7/base.js rename : testing/talos/talos/page_load_test/v8_7/crypto.js => testing/talos/talos/tests/v8_7/crypto.js rename : testing/talos/talos/page_load_test/v8_7/deltablue.js => testing/talos/talos/tests/v8_7/deltablue.js rename : testing/talos/talos/page_load_test/v8_7/earley-boyer.js => testing/talos/talos/tests/v8_7/earley-boyer.js rename : testing/talos/talos/page_load_test/v8_7/navier-stokes.js => testing/talos/talos/tests/v8_7/navier-stokes.js rename : testing/talos/talos/page_load_test/v8_7/raytrace.js => testing/talos/talos/tests/v8_7/raytrace.js rename : testing/talos/talos/page_load_test/v8_7/regexp.js => testing/talos/talos/tests/v8_7/regexp.js rename : testing/talos/talos/page_load_test/v8_7/revisions.html => testing/talos/talos/tests/v8_7/revisions.html rename : testing/talos/talos/page_load_test/v8_7/richards.js => testing/talos/talos/tests/v8_7/richards.js rename : testing/talos/talos/page_load_test/v8_7/run.html => testing/talos/talos/tests/v8_7/run.html rename : testing/talos/talos/page_load_test/v8_7/splay.js => testing/talos/talos/tests/v8_7/splay.js rename : testing/talos/talos/page_load_test/v8_7/style.css => testing/talos/talos/tests/v8_7/style.css rename : testing/talos/talos/page_load_test/v8_7/v8-logo.png => testing/talos/talos/tests/v8_7/v8-logo.png rename : testing/talos/talos/page_load_test/v8_7/v8.manifest => testing/talos/talos/tests/v8_7/v8.manifest rename : testing/talos/talos/page_load_test/webgl/benchmarks/terrain/grass.jpeg => testing/talos/talos/tests/webgl/benchmarks/terrain/grass.jpeg rename : testing/talos/talos/page_load_test/webgl/benchmarks/terrain/perftest.html => testing/talos/talos/tests/webgl/benchmarks/terrain/perftest.html rename : testing/talos/talos/page_load_test/webgl/glterrain.manifest => testing/talos/talos/tests/webgl/glterrain.manifest extra : commitid : 1haa389fmD2 extra : rebase_source : 38183bab6d10e6759f8734c5f7a143f2fba75d7b --- .../mozharness/configs/talos/linux_config.py | 2 - .../mozharness/configs/talos/mac_config.py | 2 - .../configs/talos/windows_config.py | 4 - .../mozharness/mozilla/testing/talos.py | 100 +----------------- testing/talos/mach_commands.py | 8 +- testing/talos/talos.json | 28 ++--- testing/talos/talos/cmdline.py | 5 +- testing/talos/talos/config.py | 22 ++-- testing/talos/talos/filter.py | 2 +- testing/talos/talos/generate-tart-xpi.html | 4 +- testing/talos/talos/getInfo.html | 2 +- .../canvasmark/canvasmark.manifest | 3 - .../talos/page_load_test/dromaeo/css.manifest | 6 -- .../talos/page_load_test/dromaeo/dom.manifest | 4 - .../page_load_test/kraken/kraken.manifest | 14 --- .../page_load_test/scroll/scroll.manifest | 6 -- .../svg_opacity/svg_opacity.manifest | 4 - .../talos/page_load_test/svgx/svgm.manifest | 17 --- .../talos/page_load_test/svgx/svgx.manifest | 23 ---- .../talos/page_load_test/v8_7/v8.manifest | 1 - .../page_load_test/webgl/glterrain.manifest | 1 - .../talos/talos/pageloader/chrome/Profiler.js | 4 +- .../talos/talos/pageloader/chrome/tscroll.js | 2 +- testing/talos/talos/run_tests.py | 95 ++++++----------- testing/talos/talos/scripts/Profiler.js | 4 +- .../startup_test/media/html/media_tests.html | 2 +- .../startup_test/sessionrestore/index.html | 2 +- testing/talos/talos/startup_test/tpaint.html | 2 +- .../tresize/addon/content/Profiler.js | 4 +- .../tresize/addon/content/tresize-test.html | 2 +- .../talos/startup_test/tspaint_test.html | 2 +- testing/talos/talos/test.py | 46 ++++---- .../{page_load_test => tests}/a11y/a11y.js | 0 .../a11y/a11y.manifest | 0 .../{page_load_test => tests}/a11y/dhtml.html | 0 .../a11y/tablemutation.html | 0 .../canvasmark/HelveticaNeueLTStd-Lt.otf | Bin .../canvasmark/HelveticaNeueLTStd-Md.otf | Bin .../tests/canvasmark/canvasmark.manifest | 3 + .../canvasmark/images/asteroid1.png | Bin .../canvasmark/images/asteroid2.png | Bin .../canvasmark/images/asteroid3.png | Bin .../canvasmark/images/asteroid4.png | Bin .../canvasmark/images/bg3_1.jpg | Bin .../canvasmark/images/canvasmark2013.jpg | Bin .../canvasmark/images/enemyship1.png | Bin .../canvasmark/images/fruit.jpg | Bin .../canvasmark/images/player.png | Bin .../canvasmark/images/texture5.png | Bin .../canvasmark/index.html | 0 .../canvasmark/license.txt | 0 .../canvasmark/ostrich-black-webfont.woff | Bin .../canvasmark/scripts/canvasmark_v6.js | 0 .../canvasmark/scripts/jquery-1.4.2.min.js | 0 .../canvasmark/scripts/k3d-min.js | 0 .../canvasmark/scripts/mathlib-min.js | 0 .../devtools/addon/chrome.manifest | 0 .../devtools}/addon/content/Profiler.js | 4 +- .../addon/content/addon-test-frontend.js | 0 .../devtools/addon/content/damp.html | 2 +- .../devtools/addon/content/damp.js | 2 +- .../devtools/addon/content/damp.overlay.xul | 0 .../devtools/addon/content/framescript.js | 0 .../devtools/addon/content/pages/simple.html | 0 .../devtools/addon/install.rdf | 0 .../devtools/damp.manifest | 0 .../dromaeo/JSON.php | 0 .../{page_load_test => tests}/dromaeo/LICENSE | 0 .../dromaeo/application.css | 0 .../talos/talos/tests/dromaeo/css.manifest | 6 ++ .../dromaeo/cssquery-dojo.html | 0 .../dromaeo/cssquery-ext.html | 0 .../dromaeo/cssquery-jquery.html | 0 .../dromaeo/cssquery-mootools.html | 0 .../dromaeo/cssquery-prototype.html | 0 .../dromaeo/cssquery-yui.html | 0 .../dromaeo/dom-attr.html | 0 .../dromaeo/dom-modify.html | 0 .../dromaeo/dom-query.html | 0 .../dromaeo/dom-traverse.html | 0 .../talos/talos/tests/dromaeo/dom.manifest | 4 + .../dromaeo/favicon.ico | Bin .../dromaeo/favicon.png | Bin .../dromaeo/htmlrunner.js | 0 .../{page_load_test => tests}/dromaeo/ie.css | 0 .../dromaeo/images/bg.png | Bin .../dromaeo/images/clouds.png | Bin .../dromaeo/images/clouds2.png | Bin .../dromaeo/images/comets.png | Bin .../dromaeo/images/dino1.png | Bin .../dromaeo/images/dino2.png | Bin .../dromaeo/images/dino3.png | Bin .../dromaeo/images/dino4.png | Bin .../dromaeo/images/dino5.png | Bin .../dromaeo/images/dino6.png | Bin .../dromaeo/images/dino7.png | Bin .../dromaeo/images/dino8.png | Bin .../dromaeo/images/left.png | Bin .../dromaeo/images/logo.png | Bin .../dromaeo/images/logo2.png | Bin .../dromaeo/images/logo3.png | Bin .../dromaeo/images/right.png | Bin .../dromaeo/images/top.png | Bin .../dromaeo/images/water.png | Bin .../dromaeo/index.html | 0 .../dromaeo/jquery.js | 0 .../{page_load_test => tests}/dromaeo/json.js | 0 .../dromaeo/lib/dojo.js | 0 .../dromaeo/lib/ext-base.js | 0 .../dromaeo/lib/ext-core.js | 0 .../dromaeo/lib/jquery.js | 0 .../dromaeo/lib/mootools.js | 0 .../dromaeo/lib/prototype.js | 0 .../dromaeo/lib/yahoo.js | 0 .../dromaeo/lib/yui-dom.js | 0 .../dromaeo/lib/yui-event.js | 0 .../dromaeo/lib/yui-selector.js | 0 .../dromaeo/pngfix.js | 0 .../dromaeo/reset.css | 0 .../dromaeo/store.php | 0 .../dromaeo/test-head.html | 0 .../dromaeo/test-head.js | 0 .../dromaeo/test-tail.html | 0 .../dromaeo/test-tail.js | 0 .../dromaeo/tests/MANIFEST.json | 0 .../dromaeo/tests/cssquery-dojo.html | 0 .../dromaeo/tests/cssquery-ext.html | 0 .../dromaeo/tests/cssquery-jquery.html | 0 .../dromaeo/tests/cssquery-mootools.html | 0 .../dromaeo/tests/cssquery-prototype.html | 0 .../dromaeo/tests/cssquery-yui.html | 0 .../dromaeo/tests/dom-attr.html | 0 .../dromaeo/tests/dom-modify.html | 0 .../dromaeo/tests/dom-query.html | 0 .../dromaeo/tests/dom-traverse.html | 0 .../dromaeo/tests/dromaeo-3d-cube.html | 0 .../dromaeo/tests/dromaeo-core-eval.html | 0 .../dromaeo/tests/dromaeo-object-array.html | 0 .../dromaeo/tests/dromaeo-object-regexp.html | 0 .../dromaeo/tests/dromaeo-object-string.html | 0 .../dromaeo/tests/dromaeo-string-base64.html | 0 .../dromaeo/tests/jslib-attr-jquery.html | 0 .../dromaeo/tests/jslib-attr-prototype.html | 0 .../dromaeo/tests/jslib-event-jquery.html | 0 .../dromaeo/tests/jslib-event-prototype.html | 0 .../dromaeo/tests/jslib-modify-jquery.html | 0 .../dromaeo/tests/jslib-modify-prototype.html | 0 .../dromaeo/tests/jslib-style-jquery.html | 0 .../dromaeo/tests/jslib-style-prototype.html | 0 .../dromaeo/tests/jslib-traverse-jquery.html | 0 .../tests/jslib-traverse-prototype.html | 0 .../dromaeo/tests/sunspider-3d-morph.html | 0 .../dromaeo/tests/sunspider-3d-raytrace.html | 0 .../tests/sunspider-access-binary-trees.html | 0 .../tests/sunspider-access-fannkuch.html | 0 .../dromaeo/tests/sunspider-access-nbody.html | 0 .../tests/sunspider-access-nsieve.html | 0 .../sunspider-bitops-3bit-bits-in-byte.html | 0 .../tests/sunspider-bitops-bits-in-byte.html | 0 .../tests/sunspider-bitops-bitwise-and.html | 0 .../tests/sunspider-bitops-nsieve-bits.html | 0 .../sunspider-controlflow-recursive.html | 0 .../dromaeo/tests/sunspider-crypto-aes.html | 0 .../dromaeo/tests/sunspider-crypto-md5.html | 0 .../dromaeo/tests/sunspider-crypto-sha1.html | 0 .../tests/sunspider-date-format-tofte.html | 0 .../tests/sunspider-date-format-xparb.html | 0 .../dromaeo/tests/sunspider-math-cordic.html | 0 .../tests/sunspider-math-partial-sums.html | 0 .../tests/sunspider-math-spectral-norm.html | 0 .../dromaeo/tests/sunspider-regexp-dna.html | 0 .../dromaeo/tests/sunspider-string-fasta.html | 0 .../tests/sunspider-string-tagcloud.html | 0 .../tests/sunspider-string-unpack-code.html | 0 .../sunspider-string-validate-input.html | 0 .../dromaeo/tests/v8-crypto.html | 0 .../dromaeo/tests/v8-deltablue.html | 0 .../dromaeo/tests/v8-earley-boyer.html | 0 .../dromaeo/tests/v8-raytrace.html | 0 .../dromaeo/tests/v8-richards.html | 0 .../dromaeo/web-style.css | 0 .../dromaeo/webrunner.js | 0 .../kraken/driver.html | 0 .../kraken/kraken.css | 0 .../talos/talos/tests/kraken/kraken.manifest | 14 +++ .../kraken/test-contents.js | 0 .../kraken/test-prefix.js | 0 .../talos/{page_load_test => tests}/quit.js | 0 .../{page_load_test => tests}/scroll/drac.htm | 0 .../scroll/iframe.svg | 0 .../scroll/reader.css | 0 .../scroll/reader.htm | 0 .../scroll/scroll-test.js | 2 +- .../scroll/scroll.js | 0 .../talos/talos/tests/scroll/scroll.manifest | 6 ++ .../scroll/strips-single.png | Bin .../scroll/strips.png | Bin .../scroll/tiled-downscale.html | 0 .../scroll/tiled-fixed-downscale.html | 0 .../scroll/tiled-fixed.html | 0 .../scroll/tiled.html | 0 .../big-optimizable-group-opacity-2500.svg | 0 .../svg_opacity/small-group-opacity-2500.svg | 0 .../tests/svg_opacity/svg_opacity.manifest | 4 + .../svgx/composite-scale-opacity.svg | 0 .../svgx/composite-scale-rotate-opacity.svg | 0 .../svgx/composite-scale-rotate.svg | 0 .../svgx/composite-scale.svg | 0 .../svgx/gearflowers.svg | 0 .../svgx/hixie-001.xml | 0 .../svgx/hixie-002.xml | 0 .../svgx/hixie-003.xml | 0 .../svgx/hixie-004.xml | 0 .../svgx/hixie-005.xml | 0 .../svgx/hixie-006.xml | 0 .../svgx/hixie-007.xml | 0 .../svgx/images/kyoto_1.jpg | Bin .../svgx/images/kyoto_2.jpg | Bin .../svgx/images/smallcats.gif | Bin testing/talos/talos/tests/svgx/svgm.manifest | 17 +++ testing/talos/talos/tests/svgx/svgx.manifest | 23 ++++ .../tabswitch/bootstrap.js | 2 +- .../tabswitch/chrome.manifest | 0 .../tabswitch/content/options.xul | 0 .../tabswitch/content/test.html | 0 .../tabswitch/install.rdf | 0 .../tabswitch/tps.manifest | 0 .../tart/addon/chrome.manifest | 0 .../tart}/addon/content/Profiler.js | 4 +- .../tart/addon/content/blank.icon.html | 0 .../tart/addon/content/framescript.js | 0 .../tart/addon/content/tab-min-width-1px.css | 0 .../tart/addon/content/tart.html | 0 .../tart/addon/content/tart.ico | Bin .../tart/addon/content/tart.js | 0 .../tart/addon/content/tart.overlay.xul | 0 .../tart/addon/install.rdf | 0 .../tart/cart.manifest | 0 .../tart/tart.manifest | 0 .../talos/{page_load_test => tests}/tp5o.html | 0 .../{page_load_test => tests}/v8_7/base.js | 0 .../{page_load_test => tests}/v8_7/crypto.js | 0 .../v8_7/deltablue.js | 0 .../v8_7/earley-boyer.js | 0 .../v8_7/navier-stokes.js | 0 .../v8_7/raytrace.js | 0 .../{page_load_test => tests}/v8_7/regexp.js | 0 .../v8_7/revisions.html | 0 .../v8_7/richards.js | 0 .../{page_load_test => tests}/v8_7/run.html | 0 .../{page_load_test => tests}/v8_7/splay.js | 0 .../{page_load_test => tests}/v8_7/style.css | 0 .../v8_7/v8-logo.png | Bin testing/talos/talos/tests/v8_7/v8.manifest | 1 + .../webgl/benchmarks/terrain/grass.jpeg | Bin .../webgl/benchmarks/terrain/perftest.html | 0 .../talos/tests/webgl/glterrain.manifest | 1 + .../talos/talos/xtalos/xperf_whitelist.json | 8 +- 258 files changed, 190 insertions(+), 336 deletions(-) delete mode 100644 testing/talos/talos/page_load_test/canvasmark/canvasmark.manifest delete mode 100644 testing/talos/talos/page_load_test/dromaeo/css.manifest delete mode 100644 testing/talos/talos/page_load_test/dromaeo/dom.manifest delete mode 100644 testing/talos/talos/page_load_test/kraken/kraken.manifest delete mode 100644 testing/talos/talos/page_load_test/scroll/scroll.manifest delete mode 100644 testing/talos/talos/page_load_test/svg_opacity/svg_opacity.manifest delete mode 100644 testing/talos/talos/page_load_test/svgx/svgm.manifest delete mode 100644 testing/talos/talos/page_load_test/svgx/svgx.manifest delete mode 100644 testing/talos/talos/page_load_test/v8_7/v8.manifest delete mode 100644 testing/talos/talos/page_load_test/webgl/glterrain.manifest rename testing/talos/talos/{page_load_test => tests}/a11y/a11y.js (100%) rename testing/talos/talos/{page_load_test => tests}/a11y/a11y.manifest (100%) rename testing/talos/talos/{page_load_test => tests}/a11y/dhtml.html (100%) rename testing/talos/talos/{page_load_test => tests}/a11y/tablemutation.html (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/HelveticaNeueLTStd-Lt.otf (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/HelveticaNeueLTStd-Md.otf (100%) create mode 100644 testing/talos/talos/tests/canvasmark/canvasmark.manifest rename testing/talos/talos/{page_load_test => tests}/canvasmark/images/asteroid1.png (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/images/asteroid2.png (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/images/asteroid3.png (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/images/asteroid4.png (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/images/bg3_1.jpg (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/images/canvasmark2013.jpg (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/images/enemyship1.png (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/images/fruit.jpg (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/images/player.png (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/images/texture5.png (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/index.html (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/license.txt (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/ostrich-black-webfont.woff (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/scripts/canvasmark_v6.js (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/scripts/jquery-1.4.2.min.js (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/scripts/k3d-min.js (100%) rename testing/talos/talos/{page_load_test => tests}/canvasmark/scripts/mathlib-min.js (100%) rename testing/talos/talos/{page_load_test => tests}/devtools/addon/chrome.manifest (100%) rename testing/talos/talos/{page_load_test/tart => tests/devtools}/addon/content/Profiler.js (97%) rename testing/talos/talos/{page_load_test => tests}/devtools/addon/content/addon-test-frontend.js (100%) rename testing/talos/talos/{page_load_test => tests}/devtools/addon/content/damp.html (95%) rename testing/talos/talos/{page_load_test => tests}/devtools/addon/content/damp.js (98%) rename testing/talos/talos/{page_load_test => tests}/devtools/addon/content/damp.overlay.xul (100%) rename testing/talos/talos/{page_load_test => tests}/devtools/addon/content/framescript.js (100%) rename testing/talos/talos/{page_load_test => tests}/devtools/addon/content/pages/simple.html (100%) rename testing/talos/talos/{page_load_test => tests}/devtools/addon/install.rdf (100%) rename testing/talos/talos/{page_load_test => tests}/devtools/damp.manifest (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/JSON.php (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/LICENSE (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/application.css (100%) create mode 100644 testing/talos/talos/tests/dromaeo/css.manifest rename testing/talos/talos/{page_load_test => tests}/dromaeo/cssquery-dojo.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/cssquery-ext.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/cssquery-jquery.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/cssquery-mootools.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/cssquery-prototype.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/cssquery-yui.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/dom-attr.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/dom-modify.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/dom-query.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/dom-traverse.html (100%) create mode 100644 testing/talos/talos/tests/dromaeo/dom.manifest rename testing/talos/talos/{page_load_test => tests}/dromaeo/favicon.ico (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/favicon.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/htmlrunner.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/ie.css (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/bg.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/clouds.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/clouds2.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/comets.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/dino1.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/dino2.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/dino3.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/dino4.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/dino5.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/dino6.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/dino7.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/dino8.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/left.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/logo.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/logo2.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/logo3.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/right.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/top.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/images/water.png (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/index.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/jquery.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/json.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/lib/dojo.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/lib/ext-base.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/lib/ext-core.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/lib/jquery.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/lib/mootools.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/lib/prototype.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/lib/yahoo.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/lib/yui-dom.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/lib/yui-event.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/lib/yui-selector.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/pngfix.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/reset.css (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/store.php (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/test-head.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/test-head.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/test-tail.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/test-tail.js (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/MANIFEST.json (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/cssquery-dojo.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/cssquery-ext.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/cssquery-jquery.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/cssquery-mootools.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/cssquery-prototype.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/cssquery-yui.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/dom-attr.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/dom-modify.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/dom-query.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/dom-traverse.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/dromaeo-3d-cube.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/dromaeo-core-eval.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/dromaeo-object-array.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/dromaeo-object-regexp.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/dromaeo-object-string.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/dromaeo-string-base64.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/jslib-attr-jquery.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/jslib-attr-prototype.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/jslib-event-jquery.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/jslib-event-prototype.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/jslib-modify-jquery.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/jslib-modify-prototype.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/jslib-style-jquery.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/jslib-style-prototype.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/jslib-traverse-jquery.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/jslib-traverse-prototype.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-3d-morph.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-3d-raytrace.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-access-binary-trees.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-access-fannkuch.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-access-nbody.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-access-nsieve.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-bitops-3bit-bits-in-byte.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-bitops-bits-in-byte.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-bitops-bitwise-and.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-bitops-nsieve-bits.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-controlflow-recursive.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-crypto-aes.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-crypto-md5.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-crypto-sha1.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-date-format-tofte.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-date-format-xparb.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-math-cordic.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-math-partial-sums.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-math-spectral-norm.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-regexp-dna.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-string-fasta.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-string-tagcloud.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-string-unpack-code.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/sunspider-string-validate-input.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/v8-crypto.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/v8-deltablue.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/v8-earley-boyer.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/v8-raytrace.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/tests/v8-richards.html (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/web-style.css (100%) rename testing/talos/talos/{page_load_test => tests}/dromaeo/webrunner.js (100%) rename testing/talos/talos/{page_load_test => tests}/kraken/driver.html (100%) rename testing/talos/talos/{page_load_test => tests}/kraken/kraken.css (100%) create mode 100644 testing/talos/talos/tests/kraken/kraken.manifest rename testing/talos/talos/{page_load_test => tests}/kraken/test-contents.js (100%) rename testing/talos/talos/{page_load_test => tests}/kraken/test-prefix.js (100%) rename testing/talos/talos/{page_load_test => tests}/quit.js (100%) rename testing/talos/talos/{page_load_test => tests}/scroll/drac.htm (100%) rename testing/talos/talos/{page_load_test => tests}/scroll/iframe.svg (100%) rename testing/talos/talos/{page_load_test => tests}/scroll/reader.css (100%) rename testing/talos/talos/{page_load_test => tests}/scroll/reader.htm (100%) rename testing/talos/talos/{page_load_test => tests}/scroll/scroll-test.js (98%) rename testing/talos/talos/{page_load_test => tests}/scroll/scroll.js (100%) create mode 100644 testing/talos/talos/tests/scroll/scroll.manifest rename testing/talos/talos/{page_load_test => tests}/scroll/strips-single.png (100%) rename testing/talos/talos/{page_load_test => tests}/scroll/strips.png (100%) rename testing/talos/talos/{page_load_test => tests}/scroll/tiled-downscale.html (100%) rename testing/talos/talos/{page_load_test => tests}/scroll/tiled-fixed-downscale.html (100%) rename testing/talos/talos/{page_load_test => tests}/scroll/tiled-fixed.html (100%) rename testing/talos/talos/{page_load_test => tests}/scroll/tiled.html (100%) rename testing/talos/talos/{page_load_test => tests}/svg_opacity/big-optimizable-group-opacity-2500.svg (100%) rename testing/talos/talos/{page_load_test => tests}/svg_opacity/small-group-opacity-2500.svg (100%) create mode 100644 testing/talos/talos/tests/svg_opacity/svg_opacity.manifest rename testing/talos/talos/{page_load_test => tests}/svgx/composite-scale-opacity.svg (100%) rename testing/talos/talos/{page_load_test => tests}/svgx/composite-scale-rotate-opacity.svg (100%) rename testing/talos/talos/{page_load_test => tests}/svgx/composite-scale-rotate.svg (100%) rename testing/talos/talos/{page_load_test => tests}/svgx/composite-scale.svg (100%) rename testing/talos/talos/{page_load_test => tests}/svgx/gearflowers.svg (100%) rename testing/talos/talos/{page_load_test => tests}/svgx/hixie-001.xml (100%) rename testing/talos/talos/{page_load_test => tests}/svgx/hixie-002.xml (100%) rename testing/talos/talos/{page_load_test => tests}/svgx/hixie-003.xml (100%) rename testing/talos/talos/{page_load_test => tests}/svgx/hixie-004.xml (100%) rename testing/talos/talos/{page_load_test => tests}/svgx/hixie-005.xml (100%) rename testing/talos/talos/{page_load_test => tests}/svgx/hixie-006.xml (100%) rename testing/talos/talos/{page_load_test => tests}/svgx/hixie-007.xml (100%) rename testing/talos/talos/{page_load_test => tests}/svgx/images/kyoto_1.jpg (100%) rename testing/talos/talos/{page_load_test => tests}/svgx/images/kyoto_2.jpg (100%) rename testing/talos/talos/{page_load_test => tests}/svgx/images/smallcats.gif (100%) create mode 100644 testing/talos/talos/tests/svgx/svgm.manifest create mode 100644 testing/talos/talos/tests/svgx/svgx.manifest rename testing/talos/talos/{page_load_test => tests}/tabswitch/bootstrap.js (99%) rename testing/talos/talos/{page_load_test => tests}/tabswitch/chrome.manifest (100%) rename testing/talos/talos/{page_load_test => tests}/tabswitch/content/options.xul (100%) rename testing/talos/talos/{page_load_test => tests}/tabswitch/content/test.html (100%) rename testing/talos/talos/{page_load_test => tests}/tabswitch/install.rdf (100%) rename testing/talos/talos/{page_load_test => tests}/tabswitch/tps.manifest (100%) rename testing/talos/talos/{page_load_test => tests}/tart/addon/chrome.manifest (100%) rename testing/talos/talos/{page_load_test/devtools => tests/tart}/addon/content/Profiler.js (97%) rename testing/talos/talos/{page_load_test => tests}/tart/addon/content/blank.icon.html (100%) rename testing/talos/talos/{page_load_test => tests}/tart/addon/content/framescript.js (100%) rename testing/talos/talos/{page_load_test => tests}/tart/addon/content/tab-min-width-1px.css (100%) rename testing/talos/talos/{page_load_test => tests}/tart/addon/content/tart.html (100%) rename testing/talos/talos/{page_load_test => tests}/tart/addon/content/tart.ico (100%) rename testing/talos/talos/{page_load_test => tests}/tart/addon/content/tart.js (100%) rename testing/talos/talos/{page_load_test => tests}/tart/addon/content/tart.overlay.xul (100%) rename testing/talos/talos/{page_load_test => tests}/tart/addon/install.rdf (100%) rename testing/talos/talos/{page_load_test => tests}/tart/cart.manifest (100%) rename testing/talos/talos/{page_load_test => tests}/tart/tart.manifest (100%) rename testing/talos/talos/{page_load_test => tests}/tp5o.html (100%) rename testing/talos/talos/{page_load_test => tests}/v8_7/base.js (100%) rename testing/talos/talos/{page_load_test => tests}/v8_7/crypto.js (100%) rename testing/talos/talos/{page_load_test => tests}/v8_7/deltablue.js (100%) rename testing/talos/talos/{page_load_test => tests}/v8_7/earley-boyer.js (100%) rename testing/talos/talos/{page_load_test => tests}/v8_7/navier-stokes.js (100%) rename testing/talos/talos/{page_load_test => tests}/v8_7/raytrace.js (100%) rename testing/talos/talos/{page_load_test => tests}/v8_7/regexp.js (100%) rename testing/talos/talos/{page_load_test => tests}/v8_7/revisions.html (100%) rename testing/talos/talos/{page_load_test => tests}/v8_7/richards.js (100%) rename testing/talos/talos/{page_load_test => tests}/v8_7/run.html (100%) rename testing/talos/talos/{page_load_test => tests}/v8_7/splay.js (100%) rename testing/talos/talos/{page_load_test => tests}/v8_7/style.css (100%) rename testing/talos/talos/{page_load_test => tests}/v8_7/v8-logo.png (100%) create mode 100644 testing/talos/talos/tests/v8_7/v8.manifest rename testing/talos/talos/{page_load_test => tests}/webgl/benchmarks/terrain/grass.jpeg (100%) rename testing/talos/talos/{page_load_test => tests}/webgl/benchmarks/terrain/perftest.html (100%) create mode 100644 testing/talos/talos/tests/webgl/glterrain.manifest diff --git a/testing/mozharness/configs/talos/linux_config.py b/testing/mozharness/configs/talos/linux_config.py index c6140d10653d..192de17c61de 100644 --- a/testing/mozharness/configs/talos/linux_config.py +++ b/testing/mozharness/configs/talos/linux_config.py @@ -35,8 +35,6 @@ config = { "install", "run-tests", ], - "python_webserver": False, - "webroot": '%s/../talos-data' % os.getcwd(), "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], diff --git a/testing/mozharness/configs/talos/mac_config.py b/testing/mozharness/configs/talos/mac_config.py index c8dae2574e34..56876dbdd3f0 100644 --- a/testing/mozharness/configs/talos/mac_config.py +++ b/testing/mozharness/configs/talos/mac_config.py @@ -38,8 +38,6 @@ config = { "install", "run-tests", ], - "python_webserver": False, - "webroot": '%s/../talos-data' % os.getcwd(), "run_cmd_checks_enabled": True, "preflight_run_cmd_suites": [ SCREEN_RESOLUTION_CHECK, diff --git a/testing/mozharness/configs/talos/windows_config.py b/testing/mozharness/configs/talos/windows_config.py index 20ba7f76c2d3..50c924c4441d 100644 --- a/testing/mozharness/configs/talos/windows_config.py +++ b/testing/mozharness/configs/talos/windows_config.py @@ -37,10 +37,6 @@ config = { "install", "run-tests", ], - "python_webserver": False, - "webroot": 'c:/slave/talos-data', - # Srsly gly? Ys - "webroot_extract_cmd": r'''c:/mozilla-build/msys/bin/bash -c "PATH=/c/mozilla-build/msys/bin:$PATH tar zx --strip-components=1 -f '%(tarball)s' --wildcards '**/talos/'"''', "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], diff --git a/testing/mozharness/mozharness/mozilla/testing/talos.py b/testing/mozharness/mozharness/mozilla/testing/talos.py index 493354d8238a..95720bc89f6c 100755 --- a/testing/mozharness/mozharness/mozilla/testing/talos.py +++ b/testing/mozharness/mozharness/mozilla/testing/talos.py @@ -157,11 +157,6 @@ class Talos(TestingMixin, MercurialScript, BlobUploadMixin): self.talos_json_config = self.config.get("talos_json_config") self.tests = None self.pagesets_url = None - self.pagesets_parent_dir_path = None - self.pagesets_manifest_path = None - self.abs_pagesets_paths = None - self.pagesets_manifest_filename = None - self.pagesets_manifest_parent_path = None self.sps_profile = self.config.get('sps_profile') self.sps_profile_interval = self.config.get('sps_profile_interval') @@ -270,62 +265,6 @@ class Talos(TestingMixin, MercurialScript, BlobUploadMixin): self.pagesets_url = self.talos_json_config['suites'][self.config['suite']].get('pagesets_url') return self.pagesets_url - def query_pagesets_parent_dir_path(self): - """ We have to copy the pageset into the webroot separately. - - Helper method to avoid hardcodes. - """ - if self.pagesets_parent_dir_path: - return self.pagesets_parent_dir_path - if self.query_talos_json_config(): - self.pagesets_parent_dir_path = self.talos_json_config['suites'][self.config['suite']].get('pagesets_parent_dir_path') - return self.pagesets_parent_dir_path - - def query_pagesets_manifest_path(self): - """ We have to copy the tp manifest from webroot to talos root when - those two directories aren't the same, until bug 795172 is fixed. - - Helper method to avoid hardcodes. - """ - if self.pagesets_manifest_path: - return self.pagesets_manifest_path - if self.query_talos_json_config(): - self.pagesets_manifest_path = self.talos_json_config['suites'][self.config['suite']].get('pagesets_manifest_path') - return self.pagesets_manifest_path - - def query_pagesets_manifest_filename(self): - if self.pagesets_manifest_filename: - return self.pagesets_manifest_filename - else: - manifest_path = self.query_pagesets_manifest_path() - self.pagesets_manifest_filename = os.path.basename(manifest_path) - return self.pagesets_manifest_filename - - def query_pagesets_manifest_parent_path(self): - if self.pagesets_manifest_parent_path: - return self.pagesets_manifest_parent_path - if self.query_talos_json_config(): - manifest_path = self.query_pagesets_manifest_path() - self.pagesets_manifest_parent_path = os.path.dirname(manifest_path) - return self.pagesets_manifest_parent_path - - def query_abs_pagesets_paths(self): - """ Returns a bunch of absolute pagesets directory paths. - We need this to make the dir and copy the manifest to the local dir. - """ - if self.abs_pagesets_paths: - return self.abs_pagesets_paths - else: - paths = {} - manifest_parent_path = self.query_pagesets_manifest_parent_path() - paths['pagesets_manifest_parent'] = os.path.join(self.talos_path, manifest_parent_path) - - manifest_path = self.query_pagesets_manifest_path() - paths['pagesets_manifest'] = os.path.join(self.talos_path, manifest_path) - - self.abs_pagesets_paths = paths - return self.abs_pagesets_paths - def talos_options(self, args=None, **kw): """return options to talos""" # binary path @@ -335,8 +274,6 @@ class Talos(TestingMixin, MercurialScript, BlobUploadMixin): # talos options options = [] - if self.config.get('python_webserver', True): - options.append('--develop') # talos can't gather data if the process name ends with '.exe' if binary_path.endswith('.exe'): binary_path = binary_path[:-4] @@ -376,12 +313,6 @@ class Talos(TestingMixin, MercurialScript, BlobUploadMixin): def populate_webroot(self): """Populate the production test slaves' webroots""" c = self.config - if not c.get('webroot'): - self.fatal("webroot need to be set to populate_webroot!") - self.info("Populating webroot %s..." % c['webroot']) - talos_webdir = os.path.join(c['webroot'], 'talos') - self.mkdir_p(c['webroot'], error_level=FATAL) - self.rmtree(talos_webdir, error_level=FATAL) self.talos_path = os.path.join( self.query_abs_dirs()['abs_work_dir'], 'tests', 'talos' @@ -389,25 +320,12 @@ class Talos(TestingMixin, MercurialScript, BlobUploadMixin): if c.get('run_local'): self.talos_path = os.path.dirname(self.talos_json) - # the apache server needs the talos directory (talos/talos) - # to be in the webroot src_talos_webdir = os.path.join(self.talos_path, 'talos') - self.copytree(src_talos_webdir, talos_webdir) if self.query_pagesets_url(): self.info("Downloading pageset...") - pagesets_path = os.path.join(c['webroot'], self.query_pagesets_parent_dir_path()) - self._download_unzip(self.pagesets_url, pagesets_path) - - # mkdir for the missing manifest directory in talos_repo/talos/page_load_test directory - abs_pagesets_paths = self.query_abs_pagesets_paths() - abs_manifest_parent_path = abs_pagesets_paths['pagesets_manifest_parent'] - self.mkdir_p(abs_manifest_parent_path, error_level=FATAL) - - # copy all the manifest file from unzipped zip file into the manifest dir - src_manifest_file = os.path.join(c['webroot'], self.query_pagesets_manifest_path()) - dest_manifest_file = abs_pagesets_paths['pagesets_manifest'] - self.copyfile(src_manifest_file, dest_manifest_file, error_level=FATAL) + src_talos_pageset = os.path.join(src_talos_webdir, 'tests') + self._download_unzip(self.pagesets_url, src_talos_pageset) # Action methods. {{{1 # clobber defined in BaseScript @@ -452,20 +370,6 @@ class Talos(TestingMixin, MercurialScript, BlobUploadMixin): 'requirements.txt')] ) - def postflight_create_virtualenv(self): - """ This belongs in download_and_install() but requires the - virtualenv to be set up :( - - The real fix here may be a --tpmanifest option for PerfConfigurator. - """ - c = self.config - if not c.get('python_webserver', True) and self.query_pagesets_url(): - pagesets_path = self.query_pagesets_manifest_path() - manifest_source = os.path.join(c['webroot'], pagesets_path) - manifest_target = os.path.join(self.query_python_site_packages_path(), pagesets_path) - self.mkdir_p(os.path.dirname(manifest_target)) - self.copyfile(manifest_source, manifest_target) - def run_tests(self, args=None, **kw): """run Talos tests""" diff --git a/testing/talos/mach_commands.py b/testing/talos/mach_commands.py index ebd321ff1fdb..9832f53e827b 100644 --- a/testing/talos/mach_commands.py +++ b/testing/talos/mach_commands.py @@ -45,7 +45,6 @@ class TalosRunner(MozbuildObject): def init_variables(self, talos_args): self.talos_dir = os.path.join(self.topsrcdir, 'testing', 'talos') - self.talos_webroot = os.path.join(self.topobjdir, 'testing', 'talos') self.mozharness_dir = os.path.join(self.topsrcdir, 'testing', 'mozharness') self.config_dir = os.path.join(self.mozharness_dir, 'configs', 'talos') @@ -79,16 +78,13 @@ class TalosRunner(MozbuildObject): 'create-virtualenv', 'run-tests', ], - 'python_webserver': False, 'talos_extra_options': ['--develop'] + self.talos_args, } def make_args(self): self.args = { - 'config': { - 'webroot': self.talos_webroot, - }, - 'initial_config_file': self.config_file_path, + 'config': {}, + 'initial_config_file': self.config_file_path, } def write_config(self): diff --git a/testing/talos/talos.json b/testing/talos/talos.json index a21ecf7af7cb..90c8d92c9a87 100644 --- a/testing/talos/talos.json +++ b/testing/talos/talos.json @@ -44,29 +44,21 @@ }, "g1": { "tests": ["tp5o_scroll", "glterrain"], - "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip", - "pagesets_parent_dir_path": "talos/page_load_test/", - "pagesets_manifest_path": "talos/page_load_test/tp5n/tp5o.manifest" + "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip" }, "g1-e10s": { "tests": ["tp5o_scroll", "glterrain"], "talos_options": ["--e10s"], - "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip", - "pagesets_parent_dir_path": "talos/page_load_test/", - "pagesets_manifest_path": "talos/page_load_test/tp5n/tp5o.manifest" + "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip" }, "g2": { "tests": ["damp", "tps"], - "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip", - "pagesets_parent_dir_path": "talos/page_load_test/", - "pagesets_manifest_path": "talos/page_load_test/tp5n/tp5o.manifest" + "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip" }, "g2-e10s": { "tests": ["damp", "tps"], "talos_options": ["--e10s"], - "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip", - "pagesets_parent_dir_path": "talos/page_load_test/", - "pagesets_manifest_path": "talos/page_load_test/tp5n/tp5o.manifest" + "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip" }, "g3": { "tests": ["dromaeo_dom"] @@ -83,22 +75,16 @@ }, "tp5o": { "tests": ["tp5o"], - "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip", - "pagesets_parent_dir_path": "talos/page_load_test/", - "pagesets_manifest_path": "talos/page_load_test/tp5n/tp5o.manifest" + "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip" }, "tp5o-e10s": { "tests": ["tp5o"], "talos_options": ["--e10s"], - "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip", - "pagesets_parent_dir_path": "talos/page_load_test/", - "pagesets_manifest_path": "talos/page_load_test/tp5n/tp5o.manifest" + "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip" }, "xperf": { "tests": ["tp5n"], "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip", - "pagesets_parent_dir_path": "talos/page_load_test/", - "pagesets_manifest_path": "talos/page_load_test/tp5n/tp5n.manifest", "talos_options": [ "--xperf_path", "\"c:/Program Files/Microsoft Windows Performance Toolkit/xperf.exe\"" @@ -107,8 +93,6 @@ "xperf-e10s": { "tests": ["tp5n"], "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip", - "pagesets_parent_dir_path": "talos/page_load_test/", - "pagesets_manifest_path": "talos/page_load_test/tp5n/tp5n.manifest", "talos_options": [ "--e10s", "--xperf_path", diff --git a/testing/talos/talos/cmdline.py b/testing/talos/talos/cmdline.py index 46cff2fde4ae..43411b6c5d96 100644 --- a/testing/talos/talos/cmdline.py +++ b/testing/talos/talos/cmdline.py @@ -98,12 +98,11 @@ def create_parser(mach_interface=False): metavar="PREF=VALUE", help="defines an extra user preference") add_arg('--webServer', dest='webserver', - help="address of the webserver hosting the talos files") + help="DEPRECATED") if not mach_interface: add_arg('--develop', action='store_true', default=False, help="useful for running tests on a developer machine." - " Creates a local webserver and doesn't upload to the" - " graph servers.") + " Doesn't upload to the graph servers.") add_arg('--responsiveness', action='store_true', help="turn on responsiveness collection") add_arg("--cycles", type=int, diff --git a/testing/talos/talos/config.py b/testing/talos/talos/config.py index 1c66413ae7e8..e88652c7ebc6 100644 --- a/testing/talos/talos/config.py +++ b/testing/talos/talos/config.py @@ -252,9 +252,15 @@ def fix_xperf(config): @validator -def check_webserver(config): - if config['develop'] and not config['webserver']: - config['webserver'] = 'localhost:15707' +def set_webserver(config): + # pick a free port + import socket + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.bind(('', 0)) + port = sock.getsockname()[1] + sock.close() + + config['webserver'] = 'localhost:%d' % port @validator @@ -338,8 +344,9 @@ def build_manifest(config, manifestName): # write modified manifest lines with open(manifestName + '.develop', 'w') as newHandle: for line in manifestLines: - newHandle.write(line.replace('localhost', - config['webserver'])) + newline = line.replace('localhost', config['webserver']) + newline = newline.replace('page_load_test', 'tests') + newHandle.write(newline) newManifestName = manifestName + '.develop' @@ -368,7 +375,7 @@ def get_test(config, global_overrides, counters, test_instance): # fix up tpmanifest tpmanifest = getattr(test_instance, 'tpmanifest', None) - if tpmanifest and config.get('develop'): + if tpmanifest: test_instance.tpmanifest = \ build_manifest(config, utils.interpolate(tpmanifest)) @@ -405,7 +412,7 @@ def tests(config): def get_browser_config(config): required = ('preferences', 'extensions', 'browser_path', 'browser_wait', - 'extra_args', 'buildid', 'env', 'init_url') + 'extra_args', 'buildid', 'env', 'init_url', 'webserver') optional = {'bcontroller_config': '${talos}/bcontroller.json', 'branch_name': '', 'child_process': 'plugin-container', @@ -417,7 +424,6 @@ def get_browser_config(config): 'symbols_path': None, 'test_name_extension': '', 'test_timeout': 1200, - 'webserver': '', 'xperf_path': None, 'error_filename': None, } diff --git a/testing/talos/talos/filter.py b/testing/talos/talos/filter.py index 06fb25e58b35..88b63777cebd 100644 --- a/testing/talos/talos/filter.py +++ b/testing/talos/talos/filter.py @@ -94,7 +94,7 @@ def dromaeo(series): dromaeo: https://wiki.mozilla.org/Dromaeo, pull the internal calculation out * This is for 'runs/s' based tests, not 'ms' tests. - * chunksize: defined in dromaeo: page_load_test/dromaeo/webrunner.js#l8 + * chunksize: defined in dromaeo: tests/dromaeo/webrunner.js#l8 """ means = [] chunksize = 5 diff --git a/testing/talos/talos/generate-tart-xpi.html b/testing/talos/talos/generate-tart-xpi.html index 69f0f69174ef..ccc1de103bef 100644 --- a/testing/talos/talos/generate-tart-xpi.html +++ b/testing/talos/talos/generate-tart-xpi.html @@ -11,7 +11,7 @@ - + shutdown script diff --git a/testing/talos/talos/page_load_test/canvasmark/canvasmark.manifest b/testing/talos/talos/page_load_test/canvasmark/canvasmark.manifest deleted file mode 100644 index 08f10e00fb74..000000000000 --- a/testing/talos/talos/page_load_test/canvasmark/canvasmark.manifest +++ /dev/null @@ -1,3 +0,0 @@ -% http://localhost/page_load_test/canvasmark/index.html?auto=true - - diff --git a/testing/talos/talos/page_load_test/dromaeo/css.manifest b/testing/talos/talos/page_load_test/dromaeo/css.manifest deleted file mode 100644 index d4e489e78f44..000000000000 --- a/testing/talos/talos/page_load_test/dromaeo/css.manifest +++ /dev/null @@ -1,6 +0,0 @@ -% http://localhost/page_load_test/dromaeo/cssquery-dojo.html -% http://localhost/page_load_test/dromaeo/cssquery-ext.html -% http://localhost/page_load_test/dromaeo/cssquery-jquery.html -% http://localhost/page_load_test/dromaeo/cssquery-mootools.html -% http://localhost/page_load_test/dromaeo/cssquery-prototype.html -% http://localhost/page_load_test/dromaeo/cssquery-yui.html diff --git a/testing/talos/talos/page_load_test/dromaeo/dom.manifest b/testing/talos/talos/page_load_test/dromaeo/dom.manifest deleted file mode 100644 index b1f2099ac580..000000000000 --- a/testing/talos/talos/page_load_test/dromaeo/dom.manifest +++ /dev/null @@ -1,4 +0,0 @@ -% http://localhost/page_load_test/dromaeo/dom-attr.html -% http://localhost/page_load_test/dromaeo/dom-modify.html -% http://localhost/page_load_test/dromaeo/dom-query.html -% http://localhost/page_load_test/dromaeo/dom-traverse.html diff --git a/testing/talos/talos/page_load_test/kraken/kraken.manifest b/testing/talos/talos/page_load_test/kraken/kraken.manifest deleted file mode 100644 index f017c851a75d..000000000000 --- a/testing/talos/talos/page_load_test/kraken/kraken.manifest +++ /dev/null @@ -1,14 +0,0 @@ -% http://localhost/page_load_test/kraken/driver.html?testName=ai-astar -% http://localhost/page_load_test/kraken/driver.html?testName=audio-beat-detection -% http://localhost/page_load_test/kraken/driver.html?testName=audio-dft -% http://localhost/page_load_test/kraken/driver.html?testName=audio-fft -% http://localhost/page_load_test/kraken/driver.html?testName=audio-oscillator -% http://localhost/page_load_test/kraken/driver.html?testName=imaging-gaussian-blur -% http://localhost/page_load_test/kraken/driver.html?testName=imaging-darkroom -% http://localhost/page_load_test/kraken/driver.html?testName=imaging-desaturate -% http://localhost/page_load_test/kraken/driver.html?testName=json-parse-financial -% http://localhost/page_load_test/kraken/driver.html?testName=json-stringify-tinderbox -% http://localhost/page_load_test/kraken/driver.html?testName=stanford-crypto-aes -% http://localhost/page_load_test/kraken/driver.html?testName=stanford-crypto-ccm -% http://localhost/page_load_test/kraken/driver.html?testName=stanford-crypto-pbkdf2 -% http://localhost/page_load_test/kraken/driver.html?testName=stanford-crypto-sha256-iterative diff --git a/testing/talos/talos/page_load_test/scroll/scroll.manifest b/testing/talos/talos/page_load_test/scroll/scroll.manifest deleted file mode 100644 index 1c832dea6c07..000000000000 --- a/testing/talos/talos/page_load_test/scroll/scroll.manifest +++ /dev/null @@ -1,6 +0,0 @@ -% http://localhost/page_load_test/scroll/tiled.html -% http://localhost/page_load_test/scroll/tiled-fixed.html -% http://localhost/page_load_test/scroll/tiled-downscale.html -% http://localhost/page_load_test/scroll/tiled-fixed-downscale.html -% http://localhost/page_load_test/scroll/iframe.svg -% http://localhost/page_load_test/scroll/reader.htm diff --git a/testing/talos/talos/page_load_test/svg_opacity/svg_opacity.manifest b/testing/talos/talos/page_load_test/svg_opacity/svg_opacity.manifest deleted file mode 100644 index ef13cebe9d4e..000000000000 --- a/testing/talos/talos/page_load_test/svg_opacity/svg_opacity.manifest +++ /dev/null @@ -1,4 +0,0 @@ -# opacity tests - -http://localhost/page_load_test/svg_opacity/big-optimizable-group-opacity-2500.svg -http://localhost/page_load_test/svg_opacity/small-group-opacity-2500.svg diff --git a/testing/talos/talos/page_load_test/svgx/svgm.manifest b/testing/talos/talos/page_load_test/svgx/svgm.manifest deleted file mode 100644 index 5c6448cd65db..000000000000 --- a/testing/talos/talos/page_load_test/svgx/svgm.manifest +++ /dev/null @@ -1,17 +0,0 @@ -# gearflowers image -http://localhost/page_load_test/svgx/gearflowers.svg - -# some generic image compositing tests -http://localhost/page_load_test/svgx/composite-scale.svg -http://localhost/page_load_test/svgx/composite-scale-opacity.svg -http://localhost/page_load_test/svgx/composite-scale-rotate.svg -http://localhost/page_load_test/svgx/composite-scale-rotate-opacity.svg - -# Painting multiple complex paths -% http://localhost/page_load_test/svgx/hixie-001.xml -# Painting text -% http://localhost/page_load_test/svgx/hixie-003.xml -# Painting linear gradients -% http://localhost/page_load_test/svgx/hixie-005.xml -# World Map -% http://localhost/page_load_test/svgx/hixie-007.xml diff --git a/testing/talos/talos/page_load_test/svgx/svgx.manifest b/testing/talos/talos/page_load_test/svgx/svgx.manifest deleted file mode 100644 index f37d382f4af2..000000000000 --- a/testing/talos/talos/page_load_test/svgx/svgx.manifest +++ /dev/null @@ -1,23 +0,0 @@ -# gearflowers image -http://localhost/page_load_test/svgx/gearflowers.svg - -# some generic image compositing tests -http://localhost/page_load_test/svgx/composite-scale.svg -http://localhost/page_load_test/svgx/composite-scale-opacity.svg -http://localhost/page_load_test/svgx/composite-scale-rotate.svg -http://localhost/page_load_test/svgx/composite-scale-rotate-opacity.svg - -# Painting multiple complex paths -% http://localhost/page_load_test/svgx/hixie-001.xml -# Painting multiple complex paths with transparency -% http://localhost/page_load_test/svgx/hixie-002.xml -# Painting text -% http://localhost/page_load_test/svgx/hixie-003.xml -# Painting images -% http://localhost/page_load_test/svgx/hixie-004.xml -# Painting linear gradients -% http://localhost/page_load_test/svgx/hixie-005.xml -# Painting radial gradients -% http://localhost/page_load_test/svgx/hixie-006.xml -# World Map -% http://localhost/page_load_test/svgx/hixie-007.xml diff --git a/testing/talos/talos/page_load_test/v8_7/v8.manifest b/testing/talos/talos/page_load_test/v8_7/v8.manifest deleted file mode 100644 index b19e646abd83..000000000000 --- a/testing/talos/talos/page_load_test/v8_7/v8.manifest +++ /dev/null @@ -1 +0,0 @@ -% http://localhost/page_load_test/v8_7/run.html diff --git a/testing/talos/talos/page_load_test/webgl/glterrain.manifest b/testing/talos/talos/page_load_test/webgl/glterrain.manifest deleted file mode 100644 index 4acf70055616..000000000000 --- a/testing/talos/talos/page_load_test/webgl/glterrain.manifest +++ /dev/null @@ -1 +0,0 @@ -% http://localhost/page_load_test/webgl/benchmarks/terrain/perftest.html diff --git a/testing/talos/talos/pageloader/chrome/Profiler.js b/testing/talos/talos/pageloader/chrome/Profiler.js index d21dce8e39c1..bffd50427b83 100644 --- a/testing/talos/talos/pageloader/chrome/Profiler.js +++ b/testing/talos/talos/pageloader/chrome/Profiler.js @@ -5,8 +5,8 @@ // - NOTE: This file is duplicated verbatim at: // - talos/scripts/Profiler.js // - talos/pageloader/chrome/Profiler.js -// - talos/page_load_test/devtools/addon/content/Profiler.js -// - talos/page_load_test/tart/addon/content/Profiler.js +// - talos/tests/devtools/addon/content/Profiler.js +// - talos/tests/tart/addon/content/Profiler.js // - talos/startup_test/tresize/addon/content/Profiler.js // // - Please keep these copies in sync. diff --git a/testing/talos/talos/pageloader/chrome/tscroll.js b/testing/talos/talos/pageloader/chrome/tscroll.js index 22f4fb0d26d4..232c32363326 100644 --- a/testing/talos/talos/pageloader/chrome/tscroll.js +++ b/testing/talos/talos/pageloader/chrome/tscroll.js @@ -1,5 +1,5 @@ // Note: The content from here upto '// End scroll test' is duplicated at: -// - talos/page_load_test/scroll/scroll-test.js +// - talos/tests/scroll/scroll-test.js // - inside talos/pageloader/chrome/tscroll.js // // - Please keep these copies in sync. diff --git a/testing/talos/talos/run_tests.py b/testing/talos/talos/run_tests.py index 53d97a138031..9aff92fa8d7f 100755 --- a/testing/talos/talos/run_tests.py +++ b/testing/talos/talos/run_tests.py @@ -12,8 +12,8 @@ import sys import time import traceback import urllib -import urlparse import utils +import mozhttpd from talos.results import TalosResults from talos.ttest import TTest @@ -68,28 +68,10 @@ def buildCommandLine(test): def setup_webserver(webserver): """use mozhttpd to setup a webserver""" + logging.info("starting webserver on %r" % webserver) - scheme = "http://" - if (webserver.startswith('http://') or - webserver.startswith('chrome://') or - webserver.startswith('file:///')): # noqa - - scheme = "" - elif '://' in webserver: - print "Unable to parse user defined webserver: '%s'" % (webserver) - sys.exit(2) - - url = urlparse.urlparse('%s%s' % (scheme, webserver)) - port = url.port - - if port: - import mozhttpd - return mozhttpd.MozHttpd(host=url.hostname, port=int(port), - docroot=here) - else: - print ("WARNING: unable to start web server without custom port" - " configured") - return None + host, port = webserver.split(':') + return mozhttpd.MozHttpd(host=host, port=int(port), docroot=here) def run_tests(config, browser_config): @@ -120,6 +102,8 @@ def run_tests(config, browser_config): test['cleanup'] = utils.interpolate(test['cleanup']) # pass --no-remote to firefox launch, if --develop is specified + # we do that to allow locally the user to have another running firefox + # instance if browser_config['develop']: browser_config['extra_args'] = '--no-remote' @@ -195,52 +179,41 @@ def run_tests(config, browser_config): ) talos_results.check_output_formats(results_urls) - # setup a webserver, if --develop is specified - httpd = None - if browser_config['develop']: - httpd = setup_webserver(browser_config['webserver']) - if httpd: - httpd.start() + httpd = setup_webserver(browser_config['webserver']) + httpd.start() - # run the tests - timer = utils.Timer() - logging.info("Starting test suite %s", title) - for test in tests: - testname = test['name'] - testtimer = utils.Timer() - logging.info("Starting test %s", testname) + testname = None + try: + # run the tests + timer = utils.Timer() + logging.info("Starting test suite %s", title) + for test in tests: + testname = test['name'] + testtimer = utils.Timer() + logging.info("Starting test %s", testname) - try: mytest = TTest() - if mytest: - talos_results.add(mytest.runTest(browser_config, test)) - else: - logging.error("Error found while running %s", testname) - except TalosRegression: - logging.error("Detected a regression for %s", testname) - if httpd: - httpd.stop() - # by returning 1, we report an orange to buildbot - # http://docs.buildbot.net/latest/developer/results.html - return 1 - except (TalosCrash, TalosError): - # NOTE: if we get into this condition, talos has an internal - # problem and cannot continue - # this will prevent future tests from running - traceback.print_exception(*sys.exc_info()) - if httpd: - httpd.stop() - # indicate a failure to buildbot, turn the job red - return 2 + talos_results.add(mytest.runTest(browser_config, test)) - logging.info("Completed test %s (%s)", testname, testtimer.elapsed()) + logging.info("Completed test %s (%s)", testname, testtimer.elapsed()) + + except TalosRegression: + logging.error("Detected a regression for %s", testname) + # by returning 1, we report an orange to buildbot + # http://docs.buildbot.net/latest/developer/results.html + return 1 + except (TalosCrash, TalosError): + # NOTE: if we get into this condition, talos has an internal + # problem and cannot continue + # this will prevent future tests from running + traceback.print_exception(*sys.exc_info()) + # indicate a failure to buildbot, turn the job red + return 2 + finally: + httpd.stop() logging.info("Completed test suite (%s)", timer.elapsed()) - # stop the webserver if running - if httpd: - httpd.stop() - # output results if results_urls: talos_results.output(results_urls) diff --git a/testing/talos/talos/scripts/Profiler.js b/testing/talos/talos/scripts/Profiler.js index d21dce8e39c1..bffd50427b83 100644 --- a/testing/talos/talos/scripts/Profiler.js +++ b/testing/talos/talos/scripts/Profiler.js @@ -5,8 +5,8 @@ // - NOTE: This file is duplicated verbatim at: // - talos/scripts/Profiler.js // - talos/pageloader/chrome/Profiler.js -// - talos/page_load_test/devtools/addon/content/Profiler.js -// - talos/page_load_test/tart/addon/content/Profiler.js +// - talos/tests/devtools/addon/content/Profiler.js +// - talos/tests/tart/addon/content/Profiler.js // - talos/startup_test/tresize/addon/content/Profiler.js // // - Please keep these copies in sync. diff --git a/testing/talos/talos/startup_test/media/html/media_tests.html b/testing/talos/talos/startup_test/media/html/media_tests.html index 1c58ac8692ec..f8e18df0b247 100644 --- a/testing/talos/talos/startup_test/media/html/media_tests.html +++ b/testing/talos/talos/startup_test/media/html/media_tests.html @@ -17,7 +17,7 @@
- + diff --git a/testing/talos/talos/startup_test/sessionrestore/index.html b/testing/talos/talos/startup_test/sessionrestore/index.html index 3a6320bf9e1a..06ab78933618 100755 --- a/testing/talos/talos/startup_test/sessionrestore/index.html +++ b/testing/talos/talos/startup_test/sessionrestore/index.html @@ -5,7 +5,7 @@ Session Restore Regression Test - + diff --git a/testing/talos/talos/startup_test/tpaint.html b/testing/talos/talos/startup_test/tpaint.html index 1943e5a4d7c0..de8ab614f43a 100644 --- a/testing/talos/talos/startup_test/tpaint.html +++ b/testing/talos/talos/startup_test/tpaint.html @@ -2,7 +2,7 @@ - + - + - +