From 36dd834e0d4745c1a2e146769fc089004365ae3c Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Tue, 17 Jun 2014 10:08:23 +0100 Subject: [PATCH 01/43] Bug 1022031 - Rework gfxPlatform::GetSourceSurfaceForSurface so that it doesn't need to use a Thebes backed gfxContext (Moz2D conversion). r=mattwoodrow --- gfx/2d/moz.build | 1 + gfx/thebes/gfxPlatform.cpp | 142 +++++++++++++++++++++---------------- 2 files changed, 82 insertions(+), 61 deletions(-) diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build index d793b4add1a7..6e979ca6dca4 100644 --- a/gfx/2d/moz.build +++ b/gfx/2d/moz.build @@ -28,6 +28,7 @@ EXPORTS.mozilla.gfx += [ 'Rect.h', 'Scale.h', 'ScaleFactor.h', + 'SourceSurfaceCairo.h', 'Tools.h', 'Types.h', 'UserData.h', diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 757e0390295c..593cff50533c 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -127,6 +127,7 @@ static int gCMSIntent = QCMS_INTENT_DEFAULT; static void ShutdownCMS(); #include "mozilla/gfx/2D.h" +#include "mozilla/gfx/SourceSurfaceCairo.h" using namespace mozilla::gfx; /* Class to listen for pref changes so that chrome code can dynamically @@ -651,34 +652,6 @@ gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface) aSurface->SetData(&kSourceSurface, nullptr, nullptr); } -static TemporaryRef -CopySurface(gfxASurface* aSurface) -{ - const nsIntSize size = aSurface->GetSize(); - gfxImageFormat format = gfxPlatform::GetPlatform()->OptimalFormatForContent(aSurface->GetContentType()); - RefPtr data = - Factory::CreateDataSourceSurface(ToIntSize(size), - ImageFormatToSurfaceFormat(format)); - if (!data) { - return nullptr; - } - - DataSourceSurface::MappedSurface map; - DebugOnly result = data->Map(DataSourceSurface::WRITE, &map); - MOZ_ASSERT(result, "Should always succeed mapping raw data surfaces!"); - - nsRefPtr image = new gfxImageSurface(map.mData, size, map.mStride, format); - nsRefPtr ctx = new gfxContext(image); - - ctx->SetSource(aSurface); - ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - ctx->Paint(); - - data->Unmap(); - - return data; -} - /* static */ TemporaryRef gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface) { @@ -687,9 +660,8 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa } if (!aTarget) { - if (gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget()) { - aTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); - } else { + aTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); + if (!aTarget) { return nullptr; } } @@ -715,6 +687,33 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa format = SurfaceFormat::B8G8R8A8; } + if (aTarget->GetType() == BackendType::CAIRO) { + // If we're going to be used with a CAIRO DrawTarget, then just create a + // SourceSurfaceCairo since we don't know the underlying type of the CAIRO + // DrawTarget and can't pick a better surface type. Doing this also avoids + // readback of aSurface's surface into memory if, for example, aSurface + // wraps an xlib cairo surface (which can be important to avoid a major + // slowdown). + NativeSurface surf; + surf.mFormat = format; + surf.mType = NativeSurfaceType::CAIRO_SURFACE; + surf.mSurface = aSurface->CairoSurface(); + surf.mSize = ToIntSize(aSurface->GetSize()); + // We return here regardless of whether CreateSourceSurfaceFromNativeSurface + // succeeds or not since we don't expect to be able to do any better below + // if it fails. + // + // Note that the returned SourceSurfaceCairo holds a strong reference to + // the cairo_surface_t* that it wraps, which essencially means it holds a + // strong reference to aSurface since aSurface shares its + // cairo_surface_t*'s reference count variable. As a result we can't cache + // srcBuffer on aSurface (see below) since aSurface would then hold a + // strong reference back to srcBuffer, creating a reference loop and a + // memory leak. Not caching is fine since wrapping is cheap enough (no + // copying) so we can just wrap again next time we're called. + return aTarget->CreateSourceSurfaceFromNativeSurface(surf); + } + RefPtr srcBuffer; #ifdef XP_WIN @@ -730,48 +729,69 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa dt->Flush(); } srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf); - } else + } #endif - if (aSurface->CairoSurface() && aTarget->GetType() == BackendType::CAIRO) { - // If this is an xlib cairo surface we don't want to fetch it into memory - // because this is a major slow down. + // Currently no other DrawTarget types implement CreateSourceSurfaceFromNativeSurface + + if (!srcBuffer) { + // If aSurface wraps data, we can create a SourceSurfaceRawData that wraps + // the same data, then optimize it for aTarget: + RefPtr surf = GetWrappedDataSourceSurface(aSurface); + if (surf) { + srcBuffer = aTarget->OptimizeSourceSurface(surf); + if (srcBuffer == surf) { + // GetWrappedDataSourceSurface returns a SourceSurface that holds a + // strong reference to aSurface since it wraps aSurface's data and + // needs it to stay alive. As a result we can't cache srcBuffer on + // aSurface (below) since aSurface would then hold a strong reference + // back to srcBuffer, creating a reference loop and a memory leak. Not + // caching is fine since wrapping is cheap enough (no copying) so we + // can just wrap again next time we're called. + // + // Note that the check below doesn't catch this since srcBuffer will be a + // SourceSurfaceRawData object (even if aSurface is not a gfxImageSurface + // object), which is why we need this separate check. + return srcBuffer.forget(); + } + } + } + + if (!srcBuffer) { + MOZ_ASSERT(aTarget->GetType() != BackendType::CAIRO, + "We already tried CreateSourceSurfaceFromNativeSurface with a " + "DrawTargetCairo above"); + // We've run out of performant options. We now try creating a SourceSurface + // using a temporary DrawTargetCairo and then optimizing it to aTarget's + // actual type. The CreateSourceSurfaceFromNativeSurface() call will + // likely create a DataSourceSurface (possibly involving copying and/or + // readback), and the OptimizeSourceSurface may well copy again and upload + // to the GPU. So, while this code path is rarely hit, hitting it may be + // very slow. NativeSurface surf; surf.mFormat = format; surf.mType = NativeSurfaceType::CAIRO_SURFACE; surf.mSurface = aSurface->CairoSurface(); surf.mSize = ToIntSize(aSurface->GetSize()); - srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf); - + RefPtr drawTarget = + Factory::CreateDrawTarget(BackendType::CAIRO, IntSize(1, 1), format); + srcBuffer = drawTarget->CreateSourceSurfaceFromNativeSurface(surf); if (srcBuffer) { - // It's cheap enough to make a new one so we won't keep it around and - // keeping it creates a cycle. - return srcBuffer.forget(); + srcBuffer = aTarget->OptimizeSourceSurface(srcBuffer); } } if (!srcBuffer) { - nsRefPtr imgSurface = aSurface->GetAsImageSurface(); + return nullptr; + } - RefPtr dataSurf; - - if (imgSurface) { - dataSurf = GetWrappedDataSourceSurface(aSurface); - } else { - dataSurf = CopySurface(aSurface); - } - - if (!dataSurf) { - return nullptr; - } - - srcBuffer = aTarget->OptimizeSourceSurface(dataSurf); - - if (imgSurface && srcBuffer == dataSurf) { - // Our wrapping surface will hold a reference to its image surface. We cause - // a reference cycle if we add it to the cache. And caching it is pretty - // pointless since we'll just wrap it again next use. - return srcBuffer.forget(); - } + if ((srcBuffer->GetType() == SurfaceType::CAIRO && + static_cast(srcBuffer.get())->GetSurface() == + aSurface->CairoSurface()) || + (srcBuffer->GetType() == SurfaceType::CAIRO_IMAGE && + static_cast(srcBuffer.get())->GetSurface() == + aSurface->CairoSurface())) { + // See the "Note that the returned SourceSurfaceCairo..." comment above. + return srcBuffer.forget(); } // Add user data to aSurface so we can cache lookups in the future. From d17937b94f06da9176376025439132813ce4e6cf Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 17 Jun 2014 11:28:41 +0200 Subject: [PATCH 02/43] Bug 1024444 - Fix minor bug with arguments object aliasing and Baseline. r=luke --- js/src/jit-test/tests/baseline/bug1024444.js | 7 +++++++ js/src/vm/ArgumentsObject.cpp | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 js/src/jit-test/tests/baseline/bug1024444.js diff --git a/js/src/jit-test/tests/baseline/bug1024444.js b/js/src/jit-test/tests/baseline/bug1024444.js new file mode 100644 index 000000000000..7ebd93dcdce1 --- /dev/null +++ b/js/src/jit-test/tests/baseline/bug1024444.js @@ -0,0 +1,7 @@ +function f(x) { + x = eval("a = arguments.callee.arguments; 10"); +} +for (var i=0; i<5; i++) { + f(5); + assertEq(a[0], 10); +} diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index 825a6d3f83eb..cd4e45e3d67d 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -156,7 +156,7 @@ struct CopyScriptFrameIterArgs * invalid. */ void maybeForwardToCallObject(JSObject *obj, ArgumentsData *data) { - if (!iter_.isJit()) + if (!iter_.isIon()) ArgumentsObject::MaybeForwardToCallObject(iter_.abstractFramePtr(), obj, data); } }; From 5828fd55f2896e6b542d8675f5bf2f70865f1ff6 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 17 Jun 2014 11:28:44 +0200 Subject: [PATCH 03/43] Bug 1015766 - Add test. r=test --- js/src/jit-test/tests/basic/bug1015766.js | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 js/src/jit-test/tests/basic/bug1015766.js diff --git a/js/src/jit-test/tests/basic/bug1015766.js b/js/src/jit-test/tests/basic/bug1015766.js new file mode 100644 index 000000000000..e76aff7c7a95 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1015766.js @@ -0,0 +1,10 @@ +gczeal(8, 2) +try { + [new String, y] +} catch (e) {} +r = /()/ +try { + "".replace(r, () => { + []() + }); +} catch(e) {} From 4363843ca78d74ec59bc5149747ae1f0f8a0d2c5 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 17 Jun 2014 11:28:46 +0200 Subject: [PATCH 04/43] Bug 1025875 part 1 - Make some frontend code handle Latin1 strings. r=njn --- js/src/frontend/Parser.cpp | 2 +- js/src/frontend/TokenStream.cpp | 78 +++++++++++++++++++++++---------- js/src/frontend/TokenStream.h | 4 ++ 3 files changed, 61 insertions(+), 23 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 278a0530805b..3b71de864831 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -7198,7 +7198,7 @@ Parser::objectLiteral() if (!abortIfSyntaxParser()) return null(); tokenStream.ungetToken(); - if (!tokenStream.checkForKeyword(atom->charsZ(), atom->length(), nullptr)) + if (!tokenStream.checkForKeyword(atom, nullptr)) return null(); PropertyName *name = handler.isName(propname); JS_ASSERT(atom); diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index fca3a28d4207..61d8763f0ff7 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -50,8 +50,9 @@ static const KeywordInfo keywords[] = { // Returns a KeywordInfo for the specified characters, or nullptr if the string // is not a keyword. +template static const KeywordInfo * -FindKeyword(const jschar *s, size_t length) +FindKeyword(const CharT *s, size_t length) { JS_ASSERT(length != 0); @@ -87,30 +88,47 @@ FindKeyword(const jschar *s, size_t length) return nullptr; } +static const KeywordInfo * +FindKeyword(JSLinearString *str) +{ + JS::AutoCheckCannotGC nogc; + return str->hasLatin1Chars() + ? FindKeyword(str->latin1Chars(nogc), str->length()) + : FindKeyword(str->twoByteChars(nogc), str->length()); +} + +template +static bool +IsIdentifier(const CharT *chars, size_t length) +{ + if (length == 0) + return false; + + if (!IsIdentifierStart(*chars)) + return false; + + const CharT *end = chars + length; + while (++chars != end) { + if (!IsIdentifierPart(*chars)) + return false; + } + + return true; +} + bool frontend::IsIdentifier(JSLinearString *str) { - const jschar *chars = str->chars(); - size_t length = str->length(); - - if (length == 0) - return false; - jschar c = *chars; - if (!IsIdentifierStart(c)) - return false; - const jschar *end = chars + length; - while (++chars != end) { - c = *chars; - if (!IsIdentifierPart(c)) - return false; - } - return true; + JS::AutoCheckCannotGC nogc; + return str->hasLatin1Chars() + ? ::IsIdentifier(str->latin1Chars(nogc), str->length()) + : ::IsIdentifier(str->twoByteChars(nogc), str->length()); } bool frontend::IsKeyword(JSLinearString *str) { - return FindKeyword(str->chars(), str->length()) != nullptr; + return FindKeyword(str) != nullptr; } TokenStream::SourceCoords::SourceCoords(ExclusiveContext *cx, uint32_t ln) @@ -962,12 +980,8 @@ TokenStream::putIdentInTokenbuf(const jschar *identStart) } bool -TokenStream::checkForKeyword(const jschar *s, size_t length, TokenKind *ttp) +TokenStream::checkForKeyword(const KeywordInfo *kw, TokenKind *ttp) { - const KeywordInfo *kw = FindKeyword(s, length); - if (!kw) - return true; - if (kw->tokentype == TOK_RESERVED) return reportError(JSMSG_RESERVED_ID, kw->chars); @@ -992,6 +1006,26 @@ TokenStream::checkForKeyword(const jschar *s, size_t length, TokenKind *ttp) return reportStrictModeError(JSMSG_RESERVED_ID, kw->chars); } +bool +TokenStream::checkForKeyword(const jschar *s, size_t length, TokenKind *ttp) +{ + const KeywordInfo *kw = FindKeyword(s, length); + if (!kw) + return true; + + return checkForKeyword(kw, ttp); +} + +bool +TokenStream::checkForKeyword(JSAtom *atom, TokenKind *ttp) +{ + const KeywordInfo *kw = FindKeyword(atom); + if (!kw) + return true; + + return checkForKeyword(kw, ttp); +} + enum FirstCharKind { // A jschar has the 'OneChar' kind if it, by itself, constitutes a valid // token that cannot also be a prefix of a longer token. E.g. ';' has the diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 684da3d9d282..79c36083f76a 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -22,6 +22,8 @@ #include "js/Vector.h" #include "vm/RegExpObject.h" +struct KeywordInfo; + namespace js { namespace frontend { @@ -655,7 +657,9 @@ class MOZ_STACK_CLASS TokenStream // null, report a SyntaxError ("if is a reserved identifier") and return // false. If ttp is non-null, return true with the keyword's TokenKind in // *ttp. + bool checkForKeyword(const KeywordInfo *kw, TokenKind *ttp); bool checkForKeyword(const jschar *s, size_t length, TokenKind *ttp); + bool checkForKeyword(JSAtom *atom, TokenKind *ttp); // This class maps a userbuf offset (which is 0-indexed) to a line number // (which is 1-indexed) and a column index (which is 0-indexed). From 8b96ca48faecc30d021eff9f80d3f731277259d3 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 17 Jun 2014 11:28:48 +0200 Subject: [PATCH 05/43] Bug 1025875 part 2 - Make string.split work with Latin1 strings. r=luke --- js/src/jit-test/tests/latin1/split.js | 24 ++++++++++++++++++++++++ js/src/jsstr.cpp | 6 ++---- 2 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 js/src/jit-test/tests/latin1/split.js diff --git a/js/src/jit-test/tests/latin1/split.js b/js/src/jit-test/tests/latin1/split.js new file mode 100644 index 000000000000..3aa82565821c --- /dev/null +++ b/js/src/jit-test/tests/latin1/split.js @@ -0,0 +1,24 @@ +// Latin1 +var s = toLatin1("abcdef,g,,"); +var res = s.split(toLatin1(",")); +assertEq(res[0], "abcdef"); +assertEq(res[1], "g"); +assertEq(res[2], ""); +assertEq(res[3], ""); + +s = toLatin1("abcdef,gh,,"); +res = s.split("\u1200"); +assertEq(res[0], "abcdef,gh,,"); + +// TwoByte +s = "abcdef\u1200\u1200,g,,"; +res = s.split(","); +assertEq(res[0], "abcdef\u1200\u1200"); +assertEq(res[1], "g"); +assertEq(res[2], ""); +assertEq(res[3], ""); + +res = s.split("\u1200"); +assertEq(res[0], "abcdef"); +assertEq(res[1], ""); +assertEq(res[2], ",g,,"); diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index fb11db597928..f995aefef3c0 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -3704,13 +3704,11 @@ class SplitStringMatcher bool operator()(JSContext *cx, JSLinearString *str, size_t index, SplitMatchResult *res) const { JS_ASSERT(index == 0 || index < str->length()); - const jschar *chars = str->chars(); - int match = StringMatch(chars + index, str->length() - index, - sep->chars(), sep->length()); + int match = StringMatch(str, sep, index); if (match == -1) res->setFailure(); else - res->setResult(sep->length(), index + match + sep->length()); + res->setResult(sep->length(), match + sep->length()); return true; } }; From 6344ccf0e8dd1c4b3ee819987ecd81f67c82bc67 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 17 Jun 2014 11:28:50 +0200 Subject: [PATCH 06/43] Bug 1025875 part 3 - Make CompareStrings and CompareAtoms work with Latin1 strings. r=njn --- js/src/jit-test/tests/latin1/compare.js | 20 ++++++++++++ js/src/jsstr.cpp | 42 ++++++++++++++++--------- js/src/jsstr.h | 7 +++-- 3 files changed, 52 insertions(+), 17 deletions(-) create mode 100644 js/src/jit-test/tests/latin1/compare.js diff --git a/js/src/jit-test/tests/latin1/compare.js b/js/src/jit-test/tests/latin1/compare.js new file mode 100644 index 000000000000..c0203d037508 --- /dev/null +++ b/js/src/jit-test/tests/latin1/compare.js @@ -0,0 +1,20 @@ +function test() { + var arr = [ + toLatin1("abc"), + toLatin1("abcd"), + toLatin1("123\u00ff") + ]; + for (var i = 0; i < arr.length; i++) { + for (var j = 0; j < arr.length; j++) { + var s1 = arr[i]; + var s2 = arr[j]; + var s1tb = "\u1200" + s1; + var s2tb = "\u1200" + s2; + assertEq(s1 < s2, s1tb < s2tb); + assertEq(s1 > s2, s1tb > s2tb); + assertEq(s1 <= s2, s1tb <= s2tb); + assertEq(s1 >= s2, s1tb >= s2tb); + } + } +} +test(); diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index f995aefef3c0..0132264969db 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -4521,8 +4521,28 @@ js::EqualStrings(JSLinearString *str1, JSLinearString *str2) return EqualChars(str1, str2); } -static bool -CompareStringsImpl(JSContext *cx, JSString *str1, JSString *str2, int32_t *result) +static int32_t +CompareStringsImpl(JSLinearString *str1, JSLinearString *str2) +{ + size_t len1 = str1->length(); + size_t len2 = str2->length(); + + AutoCheckCannotGC nogc; + if (str1->hasLatin1Chars()) { + const Latin1Char *chars1 = str1->latin1Chars(nogc); + return str2->hasLatin1Chars() + ? CompareChars(chars1, len1, str2->latin1Chars(nogc), len2) + : CompareChars(chars1, len1, str2->twoByteChars(nogc), len2); + } + + const jschar *chars1 = str1->twoByteChars(nogc); + return str2->hasLatin1Chars() + ? CompareChars(chars1, len1, str2->latin1Chars(nogc), len2) + : CompareChars(chars1, len1, str2->twoByteChars(nogc), len2); +} + +bool +js::CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result) { JS_ASSERT(str1); JS_ASSERT(str2); @@ -4532,28 +4552,22 @@ CompareStringsImpl(JSContext *cx, JSString *str1, JSString *str2, int32_t *resul return true; } - const jschar *s1 = str1->getChars(cx); - if (!s1) + JSLinearString *linear1 = str1->ensureLinear(cx); + if (!linear1) return false; - const jschar *s2 = str2->getChars(cx); - if (!s2) + JSLinearString *linear2 = str2->ensureLinear(cx); + if (!linear2) return false; - *result = CompareChars(s1, str1->length(), s2, str2->length()); + *result = CompareStringsImpl(linear1, linear2); return true; } -bool -js::CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result) -{ - return CompareStringsImpl(cx, str1, str2, result); -} - int32_t js::CompareAtoms(JSAtom *atom1, JSAtom *atom2) { - return CompareChars(atom1->chars(), atom1->length(), atom2->chars(), atom2->length()); + return CompareStringsImpl(atom1, atom2); } bool diff --git a/js/src/jsstr.h b/js/src/jsstr.h index b021daf20a9b..49e3d4d4f1e8 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -48,16 +48,17 @@ SkipSpace(const CharT *s, const CharT *end) // Return less than, equal to, or greater than zero depending on whether // s1 is less than, equal to, or greater than s2. +template inline int32_t -CompareChars(const jschar *s1, size_t l1, const jschar *s2, size_t l2) +CompareChars(const Char1 *s1, size_t len1, const Char2 *s2, size_t len2) { - size_t n = Min(l1, l2); + size_t n = Min(len1, len2); for (size_t i = 0; i < n; i++) { if (int32_t cmp = s1[i] - s2[i]) return cmp; } - return (int32_t)(l1 - l2); + return int32_t(len1 - len2); } } /* namespace js */ From 197045f650495977d1b9950a6c0810264a0e6025 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Tue, 17 Jun 2014 10:37:45 +0100 Subject: [PATCH 07/43] Bug 1025497 - Stop using gfxImageSurface in Cocoa widget code. r=mstange --- gfx/gl/GLTextureImage.cpp | 1 + gfx/layers/Layers.cpp | 1 + widget/android/AndroidBridge.cpp | 1 - widget/android/nsWindow.cpp | 1 - widget/cocoa/nsCocoaUtils.mm | 1 - widget/cocoa/nsDragService.mm | 28 ++++++++++++++++++---------- 6 files changed, 20 insertions(+), 13 deletions(-) diff --git a/gfx/gl/GLTextureImage.cpp b/gfx/gl/GLTextureImage.cpp index 368969b758b2..45b6fc9f8c5f 100644 --- a/gfx/gl/GLTextureImage.cpp +++ b/gfx/gl/GLTextureImage.cpp @@ -6,6 +6,7 @@ #include "GLTextureImage.h" #include "GLContext.h" #include "gfxContext.h" +#include "gfxImageSurface.h" #include "gfxPlatform.h" #include "gfxUtils.h" #include "gfx2DGlue.h" diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index 265212d6f6b1..8292117a9856 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -14,6 +14,7 @@ #include "LayerSorter.h" // for SortLayersBy3DZOrder #include "LayersLogging.h" // for AppendToString #include "ReadbackLayer.h" // for ReadbackLayer +#include "gfxImageSurface.h" #include "gfxPlatform.h" // for gfxPlatform #include "gfxUtils.h" // for gfxUtils, etc #include "gfx2DGlue.h" diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index 1469b3d4e35b..fe4b25349801 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -24,7 +24,6 @@ #include "nsThreadUtils.h" #include "nsIThreadManager.h" #include "mozilla/dom/mobilemessage/PSms.h" -#include "gfxImageSurface.h" #include "gfxPlatform.h" #include "gfxContext.h" #include "mozilla/gfx/2D.h" diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 9957945fd898..d072eb5c0af0 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -38,7 +38,6 @@ using mozilla::unused; #include "nsWidgetsCID.h" #include "nsGfxCIID.h" -#include "gfxImageSurface.h" #include "gfxContext.h" #include "Layers.h" diff --git a/widget/cocoa/nsCocoaUtils.mm b/widget/cocoa/nsCocoaUtils.mm index 4f66b36758e3..798aeea02458 100644 --- a/widget/cocoa/nsCocoaUtils.mm +++ b/widget/cocoa/nsCocoaUtils.mm @@ -3,7 +3,6 @@ * 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 "gfxImageSurface.h" #include "gfxPlatform.h" #include "gfxUtils.h" #include "nsCocoaUtils.h" diff --git a/widget/cocoa/nsDragService.mm b/widget/cocoa/nsDragService.mm index fcb93112a25f..dffeb4e2f08f 100644 --- a/widget/cocoa/nsDragService.mm +++ b/widget/cocoa/nsDragService.mm @@ -166,24 +166,31 @@ nsDragService::ConstructDragImage(nsIDOMNode* aDOMNode, uint32_t width = aDragRect->width; uint32_t height = aDragRect->height; - nsRefPtr imgSurface = new gfxImageSurface( - gfxIntSize(width, height), gfxImageFormat::ARGB32); - if (!imgSurface) + + + RefPtr dataSurface = + Factory::CreateDataSourceSurface(IntSize(width, height), + SurfaceFormat::B8G8R8A8); + DataSourceSurface::MappedSurface map; + if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) { return nil; + } RefPtr dt = - gfxPlatform::GetPlatform()-> - CreateDrawTargetForSurface(imgSurface, IntSize(width, height)); - if (!dt) + Factory::CreateDrawTargetForData(BackendType::CAIRO, + map.mData, + dataSurface->GetSize(), + map.mStride, + dataSurface->GetFormat()); + if (!dt) { + dataSurface->Unmap(); return nil; + } dt->FillRect(gfx::Rect(0, 0, width, height), SurfacePattern(surface, ExtendMode::CLAMP), DrawOptions(1.0f, CompositionOp::OP_SOURCE)); - uint32_t* imageData = (uint32_t*)imgSurface->Data(); - int32_t stride = imgSurface->Stride(); - NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:width @@ -198,7 +205,7 @@ nsDragService::ConstructDragImage(nsIDOMNode* aDOMNode, uint8_t* dest = [imageRep bitmapData]; for (uint32_t i = 0; i < height; ++i) { - uint8_t* src = (uint8_t *)imageData + i * stride; + uint8_t* src = map.mData + i * map.mStride; for (uint32_t j = 0; j < width; ++j) { // Reduce transparency overall by multipying by a factor. Remember, Alpha // is premultipled here. Also, Quartz likes RGBA, so do that translation as well. @@ -217,6 +224,7 @@ nsDragService::ConstructDragImage(nsIDOMNode* aDOMNode, dest += 4; } } + dataSurface->Unmap(); NSImage* image = [[NSImage alloc] initWithSize:NSMakeSize(width / scaleFactor, From c98228197edb5246ebb8fb88e8d987e0172fd24d Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Tue, 17 Jun 2014 10:37:46 +0100 Subject: [PATCH 08/43] Bug 1025858 - Remove gfxPlatform's SourceSnapshotDetached. r=gal --- gfx/thebes/gfxPlatform.cpp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 593cff50533c..cfafb699b794 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -630,22 +630,6 @@ void SourceSurfaceDestroyed(void *aData) delete static_cast(aData); } -#if MOZ_TREE_CAIRO -void SourceSnapshotDetached(cairo_surface_t *nullSurf) -{ - gfxImageSurface* origSurf = - static_cast(cairo_surface_get_user_data(nullSurf, &kSourceSurface)); - - origSurf->SetData(&kSourceSurface, nullptr, nullptr); -} -#else -void SourceSnapshotDetached(void *nullSurf) -{ - gfxImageSurface* origSurf = static_cast(nullSurf); - origSurf->SetData(&kSourceSurface, nullptr, nullptr); -} -#endif - void gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface) { From 684a6bdf1db73348452e4e3c016dbc8410c630a5 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Tue, 17 Jun 2014 10:37:46 +0100 Subject: [PATCH 09/43] Bug 1025802 - Get rid of the Thebes backed gfxContext in the GTK widget code (Moz2D conversion). r=mattwoodrow --- widget/gtk/nsWindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 04dd30bf713d..98f400f07612 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -2148,8 +2148,8 @@ nsWindow::OnExposeEvent(cairo_t *cr) gfxPlatform::GetPlatform()->CreateDrawTargetForData( imgSurf->Data(), intSize, imgSurf->Stride(), format); ctx = new gfxContext(dt); - } else { - ctx = new gfxContext(surf); + } else { + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected content type"); } #ifdef MOZ_X11 From a9360e4878a7c6eeadb41d7fff7a8a2bec616368 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Tue, 17 Jun 2014 10:37:46 +0100 Subject: [PATCH 10/43] Bug 1022821, part 3 - In content code, stop returning RefPtr and, where not an out-param, stop using RefPtr arguments. r=gw280 --- content/canvas/src/CanvasRenderingContext2D.cpp | 12 ++++++------ content/canvas/src/CanvasRenderingContext2D.h | 9 ++++++--- content/svg/content/src/SVGContentUtils.cpp | 2 +- content/svg/content/src/SVGContentUtils.h | 2 +- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/content/canvas/src/CanvasRenderingContext2D.cpp b/content/canvas/src/CanvasRenderingContext2D.cpp index b0aa16fdbe1b..33a306367e50 100644 --- a/content/canvas/src/CanvasRenderingContext2D.cpp +++ b/content/canvas/src/CanvasRenderingContext2D.cpp @@ -4358,7 +4358,7 @@ CanvasPath::CanvasPath(nsISupports* aParent) mPathBuilder = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget()->CreatePathBuilder(); } -CanvasPath::CanvasPath(nsISupports* aParent, RefPtr aPathBuilder) +CanvasPath::CanvasPath(nsISupports* aParent, TemporaryRef aPathBuilder) : mParent(aParent), mPathBuilder(aPathBuilder) { SetIsDOMBinding(); @@ -4555,8 +4555,8 @@ CanvasPath::BezierTo(const gfx::Point& aCP1, mPathBuilder->BezierTo(aCP1, aCP2, aCP3); } -RefPtr -CanvasPath::GetPath(const CanvasWindingRule& winding, const mozilla::RefPtr& mTarget) const +TemporaryRef +CanvasPath::GetPath(const CanvasWindingRule& winding, const DrawTarget* aTarget) const { FillRule fillRule = FillRule::FILL_WINDING; if (winding == CanvasWindingRule::Evenodd) { @@ -4564,7 +4564,7 @@ CanvasPath::GetPath(const CanvasWindingRule& winding, const mozilla::RefPtrGetBackendType() == mTarget->GetType()) && + (mPath->GetBackendType() == aTarget->GetType()) && (mPath->GetFillRule() == fillRule)) { return mPath; } @@ -4580,8 +4580,8 @@ CanvasPath::GetPath(const CanvasWindingRule& winding, const mozilla::RefPtrGetBackendType() != mTarget->GetType()) { - RefPtr tmpPathBuilder = mTarget->CreatePathBuilder(fillRule); + if (mPath->GetBackendType() != aTarget->GetType()) { + RefPtr tmpPathBuilder = aTarget->CreatePathBuilder(fillRule); mPath->StreamToSink(tmpPathBuilder); mPath = tmpPathBuilder->Finish(); } else if (mPath->GetFillRule() != fillRule) { diff --git a/content/canvas/src/CanvasRenderingContext2D.h b/content/canvas/src/CanvasRenderingContext2D.h index b13f6a2de3c2..5141bfc5c894 100644 --- a/content/canvas/src/CanvasRenderingContext2D.h +++ b/content/canvas/src/CanvasRenderingContext2D.h @@ -85,11 +85,14 @@ public: const gfx::Point& aCP2, const gfx::Point& aCP3); - mozilla::RefPtr GetPath(const CanvasWindingRule& winding, - const mozilla::RefPtr& mTarget) const; + TemporaryRef GetPath(const CanvasWindingRule& aWinding, + const gfx::DrawTarget* aTarget) const; explicit CanvasPath(nsISupports* aParent); - CanvasPath(nsISupports* aParent, RefPtr mPathBuilder); + // TemporaryRef arg because the return value from Path::CopyToBuilder() is + // passed directly and we can't drop the only ref to have a raw pointer. + CanvasPath(nsISupports* aParent, + TemporaryRef aPathBuilder); virtual ~CanvasPath() {} private: diff --git a/content/svg/content/src/SVGContentUtils.cpp b/content/svg/content/src/SVGContentUtils.cpp index fac4872f4920..27aa863afa6b 100644 --- a/content/svg/content/src/SVGContentUtils.cpp +++ b/content/svg/content/src/SVGContentUtils.cpp @@ -588,7 +588,7 @@ SVGContentUtils::CoordToFloat(nsPresContext *aPresContext, } } -RefPtr +TemporaryRef SVGContentUtils::GetPath(const nsAString& aPathString) { SVGPathData pathData; diff --git a/content/svg/content/src/SVGContentUtils.h b/content/svg/content/src/SVGContentUtils.h index aa3208b6a5e8..55dc6f21c4a1 100644 --- a/content/svg/content/src/SVGContentUtils.h +++ b/content/svg/content/src/SVGContentUtils.h @@ -249,7 +249,7 @@ public: * Returns a path * string formatted as an SVG path */ - static mozilla::RefPtr + static mozilla::TemporaryRef GetPath(const nsAString& aPathString); }; From c0c094e7c724daba275b0ac46fb7794a814472b5 Mon Sep 17 00:00:00 2001 From: Mark Banner Date: Tue, 17 Jun 2014 11:23:40 +0100 Subject: [PATCH 11/43] Bug 1011392 - Make Social API's panel handling generic so that Loop can use it as well, enabling Loop to function properly in the Application menu. r=mhammond --- browser/base/content/browser-loop.js | 49 ++-- browser/base/content/browser-social.js | 159 +------------ browser/base/content/browser.xul | 10 + .../customizableui/content/panelUI.inc.xul | 4 + browser/modules/PanelFrame.jsm | 209 ++++++++++++++++++ browser/modules/moz.build | 1 + 6 files changed, 245 insertions(+), 187 deletions(-) create mode 100644 browser/modules/PanelFrame.jsm diff --git a/browser/base/content/browser-loop.js b/browser/base/content/browser-loop.js index 271547865bfc..fdcc3d4ed529 100644 --- a/browser/base/content/browser-loop.js +++ b/browser/base/content/browser-loop.js @@ -7,6 +7,7 @@ let LoopUI; XPCOMUtils.defineLazyModuleGetter(this, "injectLoopAPI", "resource:///modules/loop/MozLoopAPI.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "MozLoopService", "resource:///modules/loop/MozLoopService.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PanelFrame", "resource:///modules/PanelFrame.jsm"); (function() { @@ -19,41 +20,24 @@ XPCOMUtils.defineLazyModuleGetter(this, "MozLoopService", "resource:///modules/l * the panel to the button which triggers it. */ openCallPanel: function(event) { - let panel = document.getElementById("loop-panel"); - let anchor = event.target; - let iframe = document.getElementById("loop-panel-frame"); + let callback = iframe => { + iframe.addEventListener("DOMContentLoaded", function documentDOMLoaded() { + iframe.removeEventListener("DOMContentLoaded", documentDOMLoaded, true); + injectLoopAPI(iframe.contentWindow); - if (!iframe) { - // XXX This should be using SharedFrame (bug 1011392 may do this). - iframe = document.createElement("iframe"); - iframe.setAttribute("id", "loop-panel-frame"); - iframe.setAttribute("type", "content"); - iframe.setAttribute("class", "loop-frame social-panel-frame"); - iframe.setAttribute("flex", "1"); - panel.appendChild(iframe); - } + // We use loopPanelInitialized so that we know we've finished localising before + // sizing the panel. + iframe.contentWindow.addEventListener("loopPanelInitialized", + function documentLoaded() { + iframe.contentWindow.removeEventListener("loopPanelInitialized", + documentLoaded, true); + }, true); - // We inject in DOMContentLoaded as that is before any scripts have tun. - iframe.addEventListener("DOMContentLoaded", function documentDOMLoaded() { - iframe.removeEventListener("DOMContentLoaded", documentDOMLoaded, true); - injectLoopAPI(iframe.contentWindow); + }, true); + }; - // We use loopPanelInitialized so that we know we've finished localising before - // sizing the panel. - iframe.contentWindow.addEventListener("loopPanelInitialized", - function documentLoaded() { - iframe.contentWindow.removeEventListener("loopPanelInitialized", - documentLoaded, true); - // XXX We end up with the wrong size here, so this - // needs further investigation (bug 1011394). - sizeSocialPanelToContent(panel, iframe); - }, true); - - }, true); - - iframe.setAttribute("src", "about:looppanel"); - panel.hidden = false; - panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false); + PanelFrame.showPopup(window, PanelUI, event.target, "loop", null, + "about:looppanel", null, callback); }, /** @@ -63,6 +47,5 @@ XPCOMUtils.defineLazyModuleGetter(this, "MozLoopService", "resource:///modules/l initialize: function() { MozLoopService.initialize(); }, - }; })(); diff --git a/browser/base/content/browser-social.js b/browser/base/content/browser-social.js index e3ec47491e5d..78e3688e3710 100644 --- a/browser/base/content/browser-social.js +++ b/browser/base/content/browser-social.js @@ -12,13 +12,12 @@ let SocialUI, (function() { -// The minimum sizes for the auto-resize panel code. -const PANEL_MIN_HEIGHT = 100; -const PANEL_MIN_WIDTH = 330; - XPCOMUtils.defineLazyModuleGetter(this, "SharedFrame", "resource:///modules/SharedFrame.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PanelFrame", + "resource:///modules/PanelFrame.jsm"); + XPCOMUtils.defineLazyGetter(this, "OpenGraphBuilder", function() { let tmp = {}; Cu.import("resource:///modules/Social.jsm", tmp); @@ -1145,66 +1144,6 @@ SocialStatus = { return this._toolbarHelper; }, - get _dynamicResizer() { - delete this._dynamicResizer; - this._dynamicResizer = new DynamicResizeWatcher(); - return this._dynamicResizer; - }, - - // status panels are one-per button per-process, we swap the docshells between - // windows when necessary - _attachNotificatonPanel: function(aParent, aButton, provider) { - aParent.hidden = !SocialUI.enabled; - let notificationFrameId = "social-status-" + provider.origin; - let frame = document.getElementById(notificationFrameId); - - // If the button was customized to a new location, we we'll destroy the - // iframe and start fresh. - if (frame && frame.parentNode != aParent) { - SharedFrame.forgetGroup(frame.id); - frame.parentNode.removeChild(frame); - frame = null; - } - - if (!frame) { - let size = provider.getPageSize("status"); - let {width, height} = size ? size : {width: PANEL_MIN_WIDTH, height: PANEL_MIN_HEIGHT}; - - frame = SharedFrame.createFrame( - notificationFrameId, /* frame name */ - aParent, /* parent */ - { - "type": "content", - "mozbrowser": "true", - "class": "social-panel-frame", - "id": notificationFrameId, - "tooltip": "aHTMLTooltip", - "context": "contentAreaContextMenu", - "flex": "1", - - // work around bug 793057 - by making the panel roughly the final size - // we are more likely to have the anchor in the correct position. - "style": "width: " + width + "px; height: " + height + "px;", - "dynamicresizer": !size, - - "origin": provider.origin, - "src": provider.statusURL - } - ); - - if (frame.socialErrorListener) - frame.socialErrorListener.remove(); - if (frame.docShell) { - frame.docShell.isActive = false; - Social.setErrorListener(frame, this.setPanelErrorMessage.bind(this)); - } - } else { - frame.setAttribute("origin", provider.origin); - SharedFrame.updateURL(notificationFrameId, provider.statusURL); - } - aButton.setAttribute("notificationFrameId", notificationFrameId); - }, - updateButton: function(origin) { let id = this._toolbarHelper.idFromOrigin(origin); let widget = CustomizableUI.getWidget(id); @@ -1249,96 +1188,8 @@ SocialStatus = { let origin = aToolbarButton.getAttribute("origin"); let provider = Social._getProviderFromOrigin(origin); - // if we're a slice in the hamburger, use that panel instead - let widgetGroup = CustomizableUI.getWidget(aToolbarButton.getAttribute("id")); - let widget = widgetGroup.forWindow(window); - let panel, showingEvent, hidingEvent; - let inMenuPanel = widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL; - if (inMenuPanel) { - panel = document.getElementById("PanelUI-socialapi"); - this._attachNotificatonPanel(panel, aToolbarButton, provider); - widget.node.setAttribute("closemenu", "none"); - showingEvent = "ViewShowing"; - hidingEvent = "ViewHiding"; - } else { - panel = document.getElementById("social-notification-panel"); - this._attachNotificatonPanel(panel, aToolbarButton, provider); - showingEvent = "popupshown"; - hidingEvent = "popuphidden"; - } - let notificationFrameId = aToolbarButton.getAttribute("notificationFrameId"); - let notificationFrame = document.getElementById(notificationFrameId); - - let wasAlive = SharedFrame.isGroupAlive(notificationFrameId); - SharedFrame.setOwner(notificationFrameId, notificationFrame); - - // Clear dimensions on all browsers so the panel size will - // only use the selected browser. - let frameIter = panel.firstElementChild; - while (frameIter) { - frameIter.collapsed = (frameIter != notificationFrame); - frameIter = frameIter.nextElementSibling; - } - - function dispatchPanelEvent(name) { - let evt = notificationFrame.contentDocument.createEvent("CustomEvent"); - evt.initCustomEvent(name, true, true, {}); - notificationFrame.contentDocument.documentElement.dispatchEvent(evt); - } - - // we only use a dynamic resizer when we're located the toolbar. - let dynamicResizer; - if (!inMenuPanel && notificationFrame.getAttribute("dynamicresizer") == "true") { - dynamicResizer = this._dynamicResizer; - } - panel.addEventListener(hidingEvent, function onpopuphiding() { - panel.removeEventListener(hidingEvent, onpopuphiding); - aToolbarButton.removeAttribute("open"); - if (dynamicResizer) - dynamicResizer.stop(); - notificationFrame.docShell.isActive = false; - dispatchPanelEvent("socialFrameHide"); - }); - - panel.addEventListener(showingEvent, function onpopupshown() { - panel.removeEventListener(showingEvent, onpopupshown); - // This attribute is needed on both the button and the - // containing toolbaritem since the buttons on OS X have - // moz-appearance:none, while their container gets - // moz-appearance:toolbarbutton due to the way that toolbar buttons - // get combined on OS X. - let initFrameShow = () => { - notificationFrame.docShell.isActive = true; - notificationFrame.docShell.isAppTab = true; - if (dynamicResizer) - dynamicResizer.start(panel, notificationFrame); - dispatchPanelEvent("socialFrameShow"); - }; - if (!inMenuPanel) - aToolbarButton.setAttribute("open", "true"); - if (notificationFrame.contentDocument && - notificationFrame.contentDocument.readyState == "complete" && wasAlive) { - initFrameShow(); - } else { - // first time load, wait for load and dispatch after load - notificationFrame.addEventListener("load", function panelBrowserOnload(e) { - notificationFrame.removeEventListener("load", panelBrowserOnload, true); - initFrameShow(); - }, true); - } - }); - - if (inMenuPanel) { - PanelUI.showSubView("PanelUI-socialapi", widget.node, - CustomizableUI.AREA_PANEL); - } else { - let anchor = document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-badge-container"); - // Bug 849216 - open the popup in a setTimeout so we avoid the auto-rollup - // handling from preventing it being opened in some cases. - setTimeout(function() { - panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false); - }, 0); - } + PanelFrame.showPopup(window, PanelUI, aToolbarButton, "social", origin, + provider.statusURL, provider.getPageSize("status")); }, setPanelErrorMessage: function(aNotificationFrame) { diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index 50c334a9819e..7f2c11ccb16a 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -268,6 +268,12 @@ position="topcenter topright"/> #ifdef MOZ_LOOP +