From 97c5578cb5f142c5ee2f90ddcdc15e660382fd57 Mon Sep 17 00:00:00 2001 From: John Daggett Date: Fri, 5 Feb 2016 16:46:05 +0900 Subject: [PATCH 01/72] Bug 1244017 - remove system font cascade for OSX. r=m_kato --- gfx/thebes/gfxFontEntry.h | 7 +- gfx/thebes/gfxMacPlatformFontList.h | 22 ----- gfx/thebes/gfxMacPlatformFontList.mm | 133 --------------------------- gfx/thebes/gfxPlatformFontList.h | 4 - gfx/thebes/gfxTextRun.cpp | 6 -- 5 files changed, 1 insertion(+), 171 deletions(-) diff --git a/gfx/thebes/gfxFontEntry.h b/gfx/thebes/gfxFontEntry.h index 1b03a9b251e..f177c4fdaf1 100644 --- a/gfx/thebes/gfxFontEntry.h +++ b/gfx/thebes/gfxFontEntry.h @@ -667,8 +667,7 @@ public: mIsBadUnderlineFamily(false), mFamilyCharacterMapInitialized(false), mSkipDefaultFeatureSpaceCheck(false), - mCheckForFallbackFaces(false), - mLinkedSystemFamily(false) + mCheckForFallbackFaces(false) { } const nsString& Name() { return mName; } @@ -797,9 +796,6 @@ public: mSkipDefaultFeatureSpaceCheck = aSkipCheck; } - bool LinkedSystemFamily() const { return mLinkedSystemFamily; } - void SetLinkedSystemFamily() { mLinkedSystemFamily = true; } - protected: // Protected destructor, to discourage deletion outside of Release(): virtual ~gfxFontFamily() @@ -832,7 +828,6 @@ protected: bool mFamilyCharacterMapInitialized : 1; bool mSkipDefaultFeatureSpaceCheck : 1; bool mCheckForFallbackFaces : 1; // check other faces for character - bool mLinkedSystemFamily : 1; // system fonts linked to other families enum { // for "simple" families, the faces are stored in mAvailableFonts diff --git a/gfx/thebes/gfxMacPlatformFontList.h b/gfx/thebes/gfxMacPlatformFontList.h index 3f066bb2398..766a4c08e43 100644 --- a/gfx/thebes/gfxMacPlatformFontList.h +++ b/gfx/thebes/gfxMacPlatformFontList.h @@ -106,10 +106,6 @@ public: gfxFontStyle &aFontStyle, float aDevPixPerCSSPixel); - virtual void - AppendLinkedSystemFamilies(nsIAtom* aLanguage, - nsTArray& aFamilyList) override; - private: friend class gfxPlatformMac; @@ -125,10 +121,6 @@ private: // initialize system fonts void InitSystemFonts(); - // helper function for looking up font cascades - void LookupFontCascadeForLang(const nsACString& aLang, - nsTArray& aCascadeList); - // helper function to lookup in both hidden system fonts and normal fonts gfxFontFamily* FindSystemFontFamily(const nsAString& aFamily); @@ -178,20 +170,6 @@ private: bool mUseSizeSensitiveSystemFont; RefPtr mSystemTextFontFamily; RefPtr mSystemDisplayFontFamily; // only used on OSX 10.11 - - // system font cascade - under OSX, the system font is effectively - // not a single family but a fontlist with the Latin font at the end - // of the list (e.g. Lucida Grande, Helevetica Neue, San Francisco) - - // most languages use a common default set of choices matching lang=en - PrefFontList mDefaultCascadeFamilies; - - // for languages where the fontlist doesn't match the default list - // (e.g. zh-TW will prioritize the traditional Chinese font over the - // Japanese font) - nsBaseHashtable, - PrefFontList*> mNonDefaultCascadeFamilies; }; #endif /* gfxMacPlatformFontList_H_ */ diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index 9d2a85a9965..f79c5669d95 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -623,10 +623,6 @@ gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformF mOtherFamilyNamesInitialized = true; } -typedef CFArrayRef (CTFontCopyDefaultCascadeListForLanguagesFunc)(CTFontRef font, CFArrayRef languagePrefList); -static CTFontCopyDefaultCascadeListForLanguagesFunc* - CTFontCopyDefaultCascadeListForLanguagesPtr = nullptr; - /* gfxMacPlatformFontList */ #pragma mark- @@ -649,11 +645,6 @@ gfxMacPlatformFontList::gfxMacPlatformFontList() : // cache this in a static variable so that MacOSFontFamily objects // don't have to repeatedly look it up sFontManager = [NSFontManager sharedFontManager]; - - // available in 10.8 and above - CTFontCopyDefaultCascadeListForLanguagesPtr = - (CTFontCopyDefaultCascadeListForLanguagesFunc*) - dlsym(RTLD_DEFAULT, "CTFontCopyDefaultCascadeListForLanguages"); } gfxMacPlatformFontList::~gfxMacPlatformFontList() @@ -791,63 +782,6 @@ static NSString* GetRealFamilyName(NSFont* aFont) const CGFloat kTextDisplayCrossover = 20.0; // use text family below this size -void -gfxMacPlatformFontList::LookupFontCascadeForLang(const nsACString& aLang, - nsTArray& aCascadeList) -{ - // if cascade not available just return empty list - if (!CTFontCopyDefaultCascadeListForLanguagesPtr) { - return; - } - - // get the system font (note: the lang parameter doesn't affect the result) - CTFontRef systemFont = - CTFontCreateUIFontForLanguage(kCTFontSystemFontType, 12.0, - CFSTR("en-US")); - - // fetch cascade list - CFStringRef langStr = - CFStringCreateWithCString(kCFAllocatorDefault, - PromiseFlatCString(aLang).get(), - kCFStringEncodingUTF8); - CFStringRef languages[1] = { langStr }; - CFArrayRef langList = CFArrayCreate(kCFAllocatorDefault, - (const void **) languages, 1, - &kCFTypeArrayCallBacks); - CFRelease(langStr); - CFArrayRef cascade = - CTFontCopyDefaultCascadeListForLanguagesPtr(systemFont, langList); - CFRelease(systemFont); - CFRelease(langList); - - // iterate over font descriptors in cascade array - for (NSFontDescriptor* fontDesc in (NSArray*) cascade) { - // First, determine the font family name. Since font cascades - // sometimes include weird "meta" names, need to determine the - // family name using the CGFont object - CTFontDescriptorRef fd = (CTFontDescriptorRef) fontDesc; - CTFontRef fontRef = CTFontCreateWithFontDescriptor(fd, 0.0, 0); - CFRelease(fd); - CGFontRef cgFontRef = CTFontCopyGraphicsFont(fontRef, NULL); - CFRelease(fontRef); - CFStringRef psname = CGFontCopyPostScriptName(cgFontRef); - CFRelease(cgFontRef); - fontRef = CTFontCreateWithName(psname, 0.0, NULL); - CFRelease(psname); - CFStringRef name = CTFontCopyFamilyName(fontRef); - CFRelease(fontRef); - - // lookup the family and append it to the list - nsAutoString familyStr; - GetStringForNSString((NSString*) name, familyStr); - CFRelease(name); - gfxFontFamily* family = FindFamily(familyStr); - if (family) { - aCascadeList.AppendElement(family); - } - } -} - void gfxMacPlatformFontList::InitSystemFonts() { @@ -863,7 +797,6 @@ gfxMacPlatformFontList::InitSystemFonts() nsCocoaUtils::GetStringForNSString(textFamilyName, familyName); mSystemTextFontFamily = FindSystemFontFamily(familyName); NS_ASSERTION(mSystemTextFontFamily, "null system display font family"); - mSystemTextFontFamily->SetLinkedSystemFamily(); // display font family, if on OSX 10.11 if (mUseSizeSensitiveSystemFont) { @@ -872,7 +805,6 @@ gfxMacPlatformFontList::InitSystemFonts() nsCocoaUtils::GetStringForNSString(displayFamilyName, familyName); mSystemDisplayFontFamily = FindSystemFontFamily(familyName); NS_ASSERTION(mSystemDisplayFontFamily, "null system display font family"); - mSystemDisplayFontFamily->SetLinkedSystemFamily(); #if DEBUG // confirm that the optical size switch is at 20.0 @@ -900,11 +832,6 @@ gfxMacPlatformFontList::InitSystemFonts() " -- please log a bug!!"); } #endif - - nsAutoCString en("en"); - AutoTArray list; - LookupFontCascadeForLang(en, list); - mDefaultCascadeFamilies.AppendElements(list); } gfxFontFamily* @@ -1252,66 +1179,6 @@ gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID, aFontStyle.systemFont = true; } -void -gfxMacPlatformFontList::AppendLinkedSystemFamilies(nsIAtom* aLanguage, - nsTArray& aFamilyList) -{ - // map lang atom to lang string - nsAutoCString lang; - GetSampleLangForGroup(aLanguage, lang, false); - ToLowerCase(lang); - - // quick exit for older versions of OSX - if (mDefaultCascadeFamilies.IsEmpty()) { - return; - } - - // assume default cascade except for CJK locales - bool defaultCascade = true; - if (lang.Length() >= 2) { - const nsACString& langTag = Substring(lang, 0, 2); - if (langTag.EqualsLiteral("zh")) { - defaultCascade = false; - // the font cascade code is fussy about the hyphen/underbar before - // the region code, so zh_TW is recognized, zh-TW is ignored - if (lang.EqualsLiteral("zh-tw")) { - lang.AssignLiteral("zh_tw"); - } else if (lang.EqualsLiteral("zh-cn")) { - lang.AssignLiteral("zh_cn"); - } else if (lang.EqualsLiteral("zh-hk")) { - lang.AssignLiteral("zh_hk"); - } - } else if (langTag.EqualsLiteral("ja") || - langTag.EqualsLiteral("ko")) { - defaultCascade = false; - } - } - - if (defaultCascade) { - aFamilyList.AppendElements(mDefaultCascadeFamilies); - return; - } - - // check to see if cached already - PrefFontList* fontsForLang = mNonDefaultCascadeFamilies.Get(lang); - if (fontsForLang) { - aFamilyList.AppendElements(*fontsForLang); - return; - } - - // lookup the cascade fonts - AutoTArray list; - LookupFontCascadeForLang(lang, list); - - // add cascade to cascade cache - fontsForLang = new PrefFontList; - fontsForLang->AppendElements(list); - mNonDefaultCascadeFamilies.Put(lang, fontsForLang); - - // use the new list - aFamilyList.AppendElements(list); -} - // used to load system-wide font info on off-main thread class MacFontInfo : public FontInfoData { public: diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h index 8addc5424b5..d76ac9e90fa 100644 --- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -200,10 +200,6 @@ public: aLoaderState = (uint32_t) mState; } - // for platforms that use linked system fontlists, append these - virtual void - AppendLinkedSystemFamilies(nsIAtom* aLanguage, - nsTArray& aFamilyList) {} virtual void AddGenericFonts(mozilla::FontFamilyType aGenericType, nsIAtom* aLanguage, diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index aa7207f176e..220384dbe87 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -1669,12 +1669,6 @@ gfxFontGroup::AddPlatformFont(const nsAString& aName, if (family) { aFamilyList.AppendElement(family); - // In some cases, system generic fonts are linked to a set of - // families, so include these if that's the case - if (family->LinkedSystemFamily()) { - fontList->AppendLinkedSystemFamilies(mStyle.language, - aFamilyList); - } } } From 544130b6505eacdee00da24613a9d074963914f7 Mon Sep 17 00:00:00 2001 From: John Daggett Date: Fri, 5 Feb 2016 16:46:27 +0900 Subject: [PATCH 02/72] Bug 1188802 - only rebuild local webfont rules when needed. r=heycam --- gfx/thebes/gfxUserFontSet.cpp | 2 ++ gfx/thebes/gfxUserFontSet.h | 3 +++ layout/style/FontFaceSet.cpp | 10 +++++++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp index a1acf253188..97f940817b2 100644 --- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -784,6 +784,7 @@ gfxUserFontEntry::GetUserFontSets(nsTArray& aResult) gfxUserFontSet::gfxUserFontSet() : mFontFamilies(4), mLocalRulesUsed(false), + mRebuildLocalRules(false), mDownloadCount(0), mDownloadSize(0) { @@ -958,6 +959,7 @@ void gfxUserFontSet::RebuildLocalRules() { if (mLocalRulesUsed) { + mRebuildLocalRules = true; DoRebuildUserFontSet(); } } diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index eb4720a5f36..88caa6ff442 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -526,6 +526,9 @@ protected: // true when local names have been looked up, false otherwise bool mLocalRulesUsed; + // true when rules using local names need to be redone + bool mRebuildLocalRules; + // performance stats uint32_t mDownloadCount; uint64_t mDownloadSize; diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp index 6a18c330dd6..9d07a8ce277 100644 --- a/layout/style/FontFaceSet.cpp +++ b/layout/style/FontFaceSet.cpp @@ -789,8 +789,11 @@ FontFaceSet::UpdateRules(const nsTArray& aRules) CheckLoadingFinished(); } - // local rules have been rebuilt, so clear the flag - mUserFontSet->mLocalRulesUsed = false; + // if local rules needed to be rebuilt, they have been rebuilt at this point + if (mUserFontSet->mRebuildLocalRules) { + mUserFontSet->mLocalRulesUsed = false; + mUserFontSet->mRebuildLocalRules = false; + } if (LOG_ENABLED() && !mRuleFaces.IsEmpty()) { LOG(("userfonts (%p) userfont rules update (%s) rule count: %d", @@ -875,7 +878,8 @@ FontFaceSet::InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType, // if local rules were used, don't use the old font entry // for rules containing src local usage - if (mUserFontSet->mLocalRulesUsed) { + if (mUserFontSet->mLocalRulesUsed && + mUserFontSet->mRebuildLocalRules) { nsCSSValue val; aFontFace->GetDesc(eCSSFontDesc_Src, val); nsCSSUnit unit = val.GetUnit(); From 27d102f477e472f6a686208ff09d17fdc816fff6 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 4 Feb 2016 16:17:42 +0900 Subject: [PATCH 03/72] Bug 1245764 - Move Windows RTL flags (-MD/-MT) flags out of config.mk. r=gps --- config/config.mk | 30 ------------------- python/mozbuild/mozbuild/frontend/emitter.py | 16 +++++++++- .../backend/data/variable_passthru/moz.build | 2 -- .../test/backend/test_recursivemake.py | 3 -- .../frontend/data/variable-passthru/moz.build | 2 -- .../mozbuild/test/frontend/test_emitter.py | 1 - 6 files changed, 15 insertions(+), 39 deletions(-) diff --git a/config/config.mk b/config/config.mk index b5cd9c6f6e2..3e39b2d835d 100644 --- a/config/config.mk +++ b/config/config.mk @@ -357,36 +357,6 @@ CXXFLAGS += $(WARNINGS_AS_ERRORS) CFLAGS += $(WARNINGS_AS_ERRORS) endif # ALLOW_COMPILER_WARNINGS -ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_) -#// Currently, unless USE_STATIC_LIBS is defined, the multithreaded -#// DLL version of the RTL is used... -#// -#//------------------------------------------------------------------------ -ifdef MOZ_ASAN -# ASAN-instrumented code tries to link against the dynamic CRT, which can't be -# used in the same link as the static CRT. -USE_STATIC_LIBS= -endif # MOZ_ASAN - -ifdef USE_STATIC_LIBS -RTL_FLAGS=-MT # Statically linked multithreaded RTL -ifdef MOZ_DEBUG -ifndef MOZ_NO_DEBUG_RTL -RTL_FLAGS=-MTd # Statically linked multithreaded MSVC4.0 debug RTL -endif -endif # MOZ_DEBUG - -else # !USE_STATIC_LIBS - -RTL_FLAGS=-MD # Dynamically linked, multithreaded RTL -ifdef MOZ_DEBUG -ifndef MOZ_NO_DEBUG_RTL -RTL_FLAGS=-MDd # Dynamically linked, multithreaded MSVC4.0 debug RTL -endif -endif # MOZ_DEBUG -endif # USE_STATIC_LIBS -endif # WINNT && !GNU_CC - COMPILE_CFLAGS = $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(OS_INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CFLAGS) $(_DEPEND_CFLAGS) $(CFLAGS) $(MOZBUILD_CFLAGS) COMPILE_CXXFLAGS = $(if $(DISABLE_STL_WRAPPING),,$(STL_FLAGS)) $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(OS_INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CXXFLAGS) $(_DEPEND_CFLAGS) $(CXXFLAGS) $(MOZBUILD_CXXFLAGS) COMPILE_CMFLAGS = $(OS_COMPILE_CMFLAGS) $(MOZBUILD_CMFLAGS) diff --git a/python/mozbuild/mozbuild/frontend/emitter.py b/python/mozbuild/mozbuild/frontend/emitter.py index bf71417d5ba..39dfa2f7a53 100644 --- a/python/mozbuild/mozbuild/frontend/emitter.py +++ b/python/mozbuild/mozbuild/frontend/emitter.py @@ -729,7 +729,6 @@ class TreeMetadataEmitter(LoggingMixin): 'ANDROID_GENERATED_RESFILES', 'DISABLE_STL_WRAPPING', 'EXTRA_DSO_LDOPTS', - 'USE_STATIC_LIBS', 'PYTHON_UNIT_TESTS', 'RCFILE', 'RESFILE', @@ -769,6 +768,21 @@ class TreeMetadataEmitter(LoggingMixin): elif dist_install is False: passthru.variables['NO_DIST_INSTALL'] = True + # Ideally, this should be done in templates, but this is difficult at + # the moment because USE_STATIC_LIBS can be set after a template + # returns. Eventually, with context-based templates, it will be + # possible. + if (context.config.substs.get('OS_ARCH') == 'WINNT' and + not context.config.substs.get('GNU_CC')): + use_static_lib = (context.get('USE_STATIC_LIBS') and + not context.config.substs.get('MOZ_ASAN')) + rtl_flag = '-MT' if use_static_lib else '-MD' + if (context.config.substs.get('MOZ_DEBUG') and + not context.config.substs.get('MOZ_NO_DEBUG_RTL')): + rtl_flag += 'd' + # Use a list, like MOZBUILD_*FLAGS variables + passthru.variables['RTL_FLAGS'] = [rtl_flag] + generated_files = set() for obj in self._process_generated_files(context): generated_files.add(obj.output) diff --git a/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build b/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build index 34f8deb5799..c6aa7dfa5c3 100644 --- a/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build +++ b/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build @@ -11,8 +11,6 @@ RESFILE = 'bar.res' RCINCLUDE = 'bar.rc' DEFFILE = 'baz.def' -USE_STATIC_LIBS = True - CFLAGS += ['-fno-exceptions', '-w'] CXXFLAGS += ['-fcxx-exceptions', '-option with spaces'] LDFLAGS += ['-ld flag with spaces', '-x'] diff --git a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py index 8aed2cfe530..615b4fc819a 100644 --- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py +++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py @@ -292,9 +292,6 @@ class TestRecursiveMakeBackend(BackendTester): 'DEFFILE': [ 'DEFFILE := baz.def', ], - 'USE_STATIC_LIBS': [ - 'USE_STATIC_LIBS := 1', - ], 'MOZBUILD_CFLAGS': [ 'MOZBUILD_CFLAGS += -fno-exceptions', 'MOZBUILD_CFLAGS += -w', diff --git a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build index 7385e8cc710..28716ff98d0 100644 --- a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build +++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build @@ -13,8 +13,6 @@ RESFILE = 'bar.res' RCINCLUDE = 'bar.rc' DEFFILE = 'baz.def' -USE_STATIC_LIBS = True - CFLAGS += ['-fno-exceptions', '-w'] CXXFLAGS += ['-fcxx-exceptions', '-include foo.h'] LDFLAGS += ['-framework Foo', '-x'] diff --git a/python/mozbuild/mozbuild/test/frontend/test_emitter.py b/python/mozbuild/mozbuild/test/frontend/test_emitter.py index 3bebd7f84b4..473ae177ec6 100644 --- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py +++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py @@ -178,7 +178,6 @@ class TestEmitterBasic(unittest.TestCase): 'RESFILE': 'bar.res', 'RCINCLUDE': 'bar.rc', 'DEFFILE': 'baz.def', - 'USE_STATIC_LIBS': True, 'MOZBUILD_CFLAGS': ['-fno-exceptions', '-w'], 'MOZBUILD_CXXFLAGS': ['-fcxx-exceptions', '-include foo.h'], 'MOZBUILD_LDFLAGS': ['-framework Foo', '-x', '-DELAYLOAD:foo.dll', From 14af904d4502cea8249a3a4a909a18bf16df329d Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Fri, 5 Feb 2016 11:19:11 +0100 Subject: [PATCH 04/72] Backed out changeset 2257088c6b04 (bug 1188802) --- gfx/thebes/gfxUserFontSet.cpp | 2 -- gfx/thebes/gfxUserFontSet.h | 3 --- layout/style/FontFaceSet.cpp | 10 +++------- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp index 97f940817b2..a1acf253188 100644 --- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -784,7 +784,6 @@ gfxUserFontEntry::GetUserFontSets(nsTArray& aResult) gfxUserFontSet::gfxUserFontSet() : mFontFamilies(4), mLocalRulesUsed(false), - mRebuildLocalRules(false), mDownloadCount(0), mDownloadSize(0) { @@ -959,7 +958,6 @@ void gfxUserFontSet::RebuildLocalRules() { if (mLocalRulesUsed) { - mRebuildLocalRules = true; DoRebuildUserFontSet(); } } diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index 88caa6ff442..eb4720a5f36 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -526,9 +526,6 @@ protected: // true when local names have been looked up, false otherwise bool mLocalRulesUsed; - // true when rules using local names need to be redone - bool mRebuildLocalRules; - // performance stats uint32_t mDownloadCount; uint64_t mDownloadSize; diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp index 9d07a8ce277..6a18c330dd6 100644 --- a/layout/style/FontFaceSet.cpp +++ b/layout/style/FontFaceSet.cpp @@ -789,11 +789,8 @@ FontFaceSet::UpdateRules(const nsTArray& aRules) CheckLoadingFinished(); } - // if local rules needed to be rebuilt, they have been rebuilt at this point - if (mUserFontSet->mRebuildLocalRules) { - mUserFontSet->mLocalRulesUsed = false; - mUserFontSet->mRebuildLocalRules = false; - } + // local rules have been rebuilt, so clear the flag + mUserFontSet->mLocalRulesUsed = false; if (LOG_ENABLED() && !mRuleFaces.IsEmpty()) { LOG(("userfonts (%p) userfont rules update (%s) rule count: %d", @@ -878,8 +875,7 @@ FontFaceSet::InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType, // if local rules were used, don't use the old font entry // for rules containing src local usage - if (mUserFontSet->mLocalRulesUsed && - mUserFontSet->mRebuildLocalRules) { + if (mUserFontSet->mLocalRulesUsed) { nsCSSValue val; aFontFace->GetDesc(eCSSFontDesc_Src, val); nsCSSUnit unit = val.GetUnit(); From 7d86d076e84ad35c0ce3fb71eee566ec64baf8a0 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Fri, 5 Feb 2016 11:19:25 +0100 Subject: [PATCH 05/72] Backed out changeset 0e3ca319b742 (bug 1244017) for reftest failures --- gfx/thebes/gfxFontEntry.h | 7 +- gfx/thebes/gfxMacPlatformFontList.h | 22 +++++ gfx/thebes/gfxMacPlatformFontList.mm | 133 +++++++++++++++++++++++++++ gfx/thebes/gfxPlatformFontList.h | 4 + gfx/thebes/gfxTextRun.cpp | 6 ++ 5 files changed, 171 insertions(+), 1 deletion(-) diff --git a/gfx/thebes/gfxFontEntry.h b/gfx/thebes/gfxFontEntry.h index f177c4fdaf1..1b03a9b251e 100644 --- a/gfx/thebes/gfxFontEntry.h +++ b/gfx/thebes/gfxFontEntry.h @@ -667,7 +667,8 @@ public: mIsBadUnderlineFamily(false), mFamilyCharacterMapInitialized(false), mSkipDefaultFeatureSpaceCheck(false), - mCheckForFallbackFaces(false) + mCheckForFallbackFaces(false), + mLinkedSystemFamily(false) { } const nsString& Name() { return mName; } @@ -796,6 +797,9 @@ public: mSkipDefaultFeatureSpaceCheck = aSkipCheck; } + bool LinkedSystemFamily() const { return mLinkedSystemFamily; } + void SetLinkedSystemFamily() { mLinkedSystemFamily = true; } + protected: // Protected destructor, to discourage deletion outside of Release(): virtual ~gfxFontFamily() @@ -828,6 +832,7 @@ protected: bool mFamilyCharacterMapInitialized : 1; bool mSkipDefaultFeatureSpaceCheck : 1; bool mCheckForFallbackFaces : 1; // check other faces for character + bool mLinkedSystemFamily : 1; // system fonts linked to other families enum { // for "simple" families, the faces are stored in mAvailableFonts diff --git a/gfx/thebes/gfxMacPlatformFontList.h b/gfx/thebes/gfxMacPlatformFontList.h index 766a4c08e43..3f066bb2398 100644 --- a/gfx/thebes/gfxMacPlatformFontList.h +++ b/gfx/thebes/gfxMacPlatformFontList.h @@ -106,6 +106,10 @@ public: gfxFontStyle &aFontStyle, float aDevPixPerCSSPixel); + virtual void + AppendLinkedSystemFamilies(nsIAtom* aLanguage, + nsTArray& aFamilyList) override; + private: friend class gfxPlatformMac; @@ -121,6 +125,10 @@ private: // initialize system fonts void InitSystemFonts(); + // helper function for looking up font cascades + void LookupFontCascadeForLang(const nsACString& aLang, + nsTArray& aCascadeList); + // helper function to lookup in both hidden system fonts and normal fonts gfxFontFamily* FindSystemFontFamily(const nsAString& aFamily); @@ -170,6 +178,20 @@ private: bool mUseSizeSensitiveSystemFont; RefPtr mSystemTextFontFamily; RefPtr mSystemDisplayFontFamily; // only used on OSX 10.11 + + // system font cascade - under OSX, the system font is effectively + // not a single family but a fontlist with the Latin font at the end + // of the list (e.g. Lucida Grande, Helevetica Neue, San Francisco) + + // most languages use a common default set of choices matching lang=en + PrefFontList mDefaultCascadeFamilies; + + // for languages where the fontlist doesn't match the default list + // (e.g. zh-TW will prioritize the traditional Chinese font over the + // Japanese font) + nsBaseHashtable, + PrefFontList*> mNonDefaultCascadeFamilies; }; #endif /* gfxMacPlatformFontList_H_ */ diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index f79c5669d95..9d2a85a9965 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -623,6 +623,10 @@ gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformF mOtherFamilyNamesInitialized = true; } +typedef CFArrayRef (CTFontCopyDefaultCascadeListForLanguagesFunc)(CTFontRef font, CFArrayRef languagePrefList); +static CTFontCopyDefaultCascadeListForLanguagesFunc* + CTFontCopyDefaultCascadeListForLanguagesPtr = nullptr; + /* gfxMacPlatformFontList */ #pragma mark- @@ -645,6 +649,11 @@ gfxMacPlatformFontList::gfxMacPlatformFontList() : // cache this in a static variable so that MacOSFontFamily objects // don't have to repeatedly look it up sFontManager = [NSFontManager sharedFontManager]; + + // available in 10.8 and above + CTFontCopyDefaultCascadeListForLanguagesPtr = + (CTFontCopyDefaultCascadeListForLanguagesFunc*) + dlsym(RTLD_DEFAULT, "CTFontCopyDefaultCascadeListForLanguages"); } gfxMacPlatformFontList::~gfxMacPlatformFontList() @@ -782,6 +791,63 @@ static NSString* GetRealFamilyName(NSFont* aFont) const CGFloat kTextDisplayCrossover = 20.0; // use text family below this size +void +gfxMacPlatformFontList::LookupFontCascadeForLang(const nsACString& aLang, + nsTArray& aCascadeList) +{ + // if cascade not available just return empty list + if (!CTFontCopyDefaultCascadeListForLanguagesPtr) { + return; + } + + // get the system font (note: the lang parameter doesn't affect the result) + CTFontRef systemFont = + CTFontCreateUIFontForLanguage(kCTFontSystemFontType, 12.0, + CFSTR("en-US")); + + // fetch cascade list + CFStringRef langStr = + CFStringCreateWithCString(kCFAllocatorDefault, + PromiseFlatCString(aLang).get(), + kCFStringEncodingUTF8); + CFStringRef languages[1] = { langStr }; + CFArrayRef langList = CFArrayCreate(kCFAllocatorDefault, + (const void **) languages, 1, + &kCFTypeArrayCallBacks); + CFRelease(langStr); + CFArrayRef cascade = + CTFontCopyDefaultCascadeListForLanguagesPtr(systemFont, langList); + CFRelease(systemFont); + CFRelease(langList); + + // iterate over font descriptors in cascade array + for (NSFontDescriptor* fontDesc in (NSArray*) cascade) { + // First, determine the font family name. Since font cascades + // sometimes include weird "meta" names, need to determine the + // family name using the CGFont object + CTFontDescriptorRef fd = (CTFontDescriptorRef) fontDesc; + CTFontRef fontRef = CTFontCreateWithFontDescriptor(fd, 0.0, 0); + CFRelease(fd); + CGFontRef cgFontRef = CTFontCopyGraphicsFont(fontRef, NULL); + CFRelease(fontRef); + CFStringRef psname = CGFontCopyPostScriptName(cgFontRef); + CFRelease(cgFontRef); + fontRef = CTFontCreateWithName(psname, 0.0, NULL); + CFRelease(psname); + CFStringRef name = CTFontCopyFamilyName(fontRef); + CFRelease(fontRef); + + // lookup the family and append it to the list + nsAutoString familyStr; + GetStringForNSString((NSString*) name, familyStr); + CFRelease(name); + gfxFontFamily* family = FindFamily(familyStr); + if (family) { + aCascadeList.AppendElement(family); + } + } +} + void gfxMacPlatformFontList::InitSystemFonts() { @@ -797,6 +863,7 @@ gfxMacPlatformFontList::InitSystemFonts() nsCocoaUtils::GetStringForNSString(textFamilyName, familyName); mSystemTextFontFamily = FindSystemFontFamily(familyName); NS_ASSERTION(mSystemTextFontFamily, "null system display font family"); + mSystemTextFontFamily->SetLinkedSystemFamily(); // display font family, if on OSX 10.11 if (mUseSizeSensitiveSystemFont) { @@ -805,6 +872,7 @@ gfxMacPlatformFontList::InitSystemFonts() nsCocoaUtils::GetStringForNSString(displayFamilyName, familyName); mSystemDisplayFontFamily = FindSystemFontFamily(familyName); NS_ASSERTION(mSystemDisplayFontFamily, "null system display font family"); + mSystemDisplayFontFamily->SetLinkedSystemFamily(); #if DEBUG // confirm that the optical size switch is at 20.0 @@ -832,6 +900,11 @@ gfxMacPlatformFontList::InitSystemFonts() " -- please log a bug!!"); } #endif + + nsAutoCString en("en"); + AutoTArray list; + LookupFontCascadeForLang(en, list); + mDefaultCascadeFamilies.AppendElements(list); } gfxFontFamily* @@ -1179,6 +1252,66 @@ gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID, aFontStyle.systemFont = true; } +void +gfxMacPlatformFontList::AppendLinkedSystemFamilies(nsIAtom* aLanguage, + nsTArray& aFamilyList) +{ + // map lang atom to lang string + nsAutoCString lang; + GetSampleLangForGroup(aLanguage, lang, false); + ToLowerCase(lang); + + // quick exit for older versions of OSX + if (mDefaultCascadeFamilies.IsEmpty()) { + return; + } + + // assume default cascade except for CJK locales + bool defaultCascade = true; + if (lang.Length() >= 2) { + const nsACString& langTag = Substring(lang, 0, 2); + if (langTag.EqualsLiteral("zh")) { + defaultCascade = false; + // the font cascade code is fussy about the hyphen/underbar before + // the region code, so zh_TW is recognized, zh-TW is ignored + if (lang.EqualsLiteral("zh-tw")) { + lang.AssignLiteral("zh_tw"); + } else if (lang.EqualsLiteral("zh-cn")) { + lang.AssignLiteral("zh_cn"); + } else if (lang.EqualsLiteral("zh-hk")) { + lang.AssignLiteral("zh_hk"); + } + } else if (langTag.EqualsLiteral("ja") || + langTag.EqualsLiteral("ko")) { + defaultCascade = false; + } + } + + if (defaultCascade) { + aFamilyList.AppendElements(mDefaultCascadeFamilies); + return; + } + + // check to see if cached already + PrefFontList* fontsForLang = mNonDefaultCascadeFamilies.Get(lang); + if (fontsForLang) { + aFamilyList.AppendElements(*fontsForLang); + return; + } + + // lookup the cascade fonts + AutoTArray list; + LookupFontCascadeForLang(lang, list); + + // add cascade to cascade cache + fontsForLang = new PrefFontList; + fontsForLang->AppendElements(list); + mNonDefaultCascadeFamilies.Put(lang, fontsForLang); + + // use the new list + aFamilyList.AppendElements(list); +} + // used to load system-wide font info on off-main thread class MacFontInfo : public FontInfoData { public: diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h index d76ac9e90fa..8addc5424b5 100644 --- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -200,6 +200,10 @@ public: aLoaderState = (uint32_t) mState; } + // for platforms that use linked system fontlists, append these + virtual void + AppendLinkedSystemFamilies(nsIAtom* aLanguage, + nsTArray& aFamilyList) {} virtual void AddGenericFonts(mozilla::FontFamilyType aGenericType, nsIAtom* aLanguage, diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 220384dbe87..aa7207f176e 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -1669,6 +1669,12 @@ gfxFontGroup::AddPlatformFont(const nsAString& aName, if (family) { aFamilyList.AppendElement(family); + // In some cases, system generic fonts are linked to a set of + // families, so include these if that's the case + if (family->LinkedSystemFamily()) { + fontList->AppendLinkedSystemFamilies(mStyle.language, + aFamilyList); + } } } From 790d83ccdd5daa5108bd87357c080b6dc35a1423 Mon Sep 17 00:00:00 2001 From: Maksim Lebedev Date: Tue, 31 Mar 2015 07:02:00 +0200 Subject: [PATCH 06/72] Bug 1000870 - Add original official tests from W3C at 2015.03.01. r=smaug --- ...erevent_button_attribute_mouse-manual.html | 57 ++++++ .../pointerevent_capture_mouse-manual.html | 132 +++++++++++++ ...vent_capture_suppressing_mouse-manual.html | 175 ++++++++++++++++++ ...uch-action-onpointerdown_touch-manual.html | 135 ++++++++++++++ .../pointerevent_constructor.html | 104 +++++++++++ ...ture_before_first_pointerevent-manual.html | 97 ++++++++++ ...rcapture_for_disconnected_node-manual.html | 78 ++++++++ ...nt_lostpointercapture_is_first-manual.html | 111 +++++++++++ ...interevent_pointercancel_touch-manual.html | 77 ++++++++ .../pointerevent_pointerdown-manual.html | 59 ++++++ .../pointerevent_pointerenter-manual.html | 52 ++++++ ...t_pointerenter_does_not_bubble-manual.html | 88 +++++++++ ...nterevent_pointerenter_nohover-manual.html | 74 ++++++++ ...eave_after_pointercancel_touch-manual.html | 66 +++++++ ...rleave_after_pointerup_nohover-manual.html | 67 +++++++ ...t_pointerleave_descendant_over-manual.html | 61 ++++++ ...event_pointerleave_descendants-manual.html | 52 ++++++ ...t_pointerleave_does_not_bubble-manual.html | 77 ++++++++ ...ointerevent_pointerleave_mouse-manual.html | 53 ++++++ .../pointerevent_pointerleave_pen-manual.html | 58 ++++++ ...ointerevent_pointerleave_touch-manual.html | 53 ++++++ .../pointerevent_pointermove-manual.html | 44 +++++ ..._isprimary_same_as_pointerdown-manual.html | 70 +++++++ ...revent_pointermove_pointertype-manual.html | 64 +++++++ .../pointerevent_pointerout-manual.html | 46 +++++ ...rout_after_pointercancel_touch-manual.html | 67 +++++++ ...terout_after_pointerup_nohover-manual.html | 67 +++++++ .../pointerevent_pointerout_pen-manual.html | 57 ++++++ ...event_pointerout_received_once-manual.html | 58 ++++++ .../pointerevent_pointerover-manual.html | 52 ++++++ ...pointerevent_pointertype_mouse-manual.html | 63 +++++++ .../pointerevent_pointertype_pen-manual.html | 61 ++++++ ...pointerevent_pointertype_touch-manual.html | 62 +++++++ .../pointerevent_pointerup-manual.html | 44 +++++ ..._isprimary_same_as_pointerdown-manual.html | 63 +++++++ ...terevent_pointerup_pointertype-manual.html | 64 +++++++ ...ture_events_to_original_target-manual.html | 116 ++++++++++++ ...intercapture_invalid_pointerid-manual.html | 76 ++++++++ ...rcapture_onpointercancel_touch-manual.html | 71 +++++++ ...intercapture_onpointerup_mouse-manual.html | 79 ++++++++ ...setpointercapture_disconnected-manual.html | 55 ++++++ ...rcapture_inactive_button_mouse-manual.html | 58 ++++++ ...intercapture_invalid_pointerid-manual.html | 65 +++++++ ...etpointercapture_relatedtarget-manual.html | 101 ++++++++++ .../pointerevents/pointerevent_styles.css | 61 ++++++ .../pointerevents/pointerevent_support.js | 170 +++++++++++++++++ ...nt_touch-action-auto-css_touch-manual.html | 129 +++++++++++++ ...touch-action-button-test_touch-manual.html | 109 +++++++++++ .../pointerevent_touch-action-illegal.html | 67 +++++++ ...it_child-auto-child-none_touch-manual.html | 117 ++++++++++++ ...ction-inherit_child-none_touch-manual.html | 112 +++++++++++ ..._child-pan-x-child-pan-x_touch-manual.html | 112 +++++++++++ ..._child-pan-x-child-pan-y_touch-manual.html | 117 ++++++++++++ ...erit_highest-parent-none_touch-manual.html | 133 +++++++++++++ ...tion-inherit_parent-none_touch-manual.html | 112 +++++++++++ ...terevent_touch-action-keyboard-manual.html | 124 +++++++++++++ ...ointerevent_touch-action-mouse-manual.html | 130 +++++++++++++ ...nt_touch-action-none-css_touch-manual.html | 111 +++++++++++ ...t_touch-action-pan-x-css_touch-manual.html | 106 +++++++++++ ...action-pan-x-pan-y-pan-y_touch-manual.html | 111 +++++++++++ ...touch-action-pan-x-pan-y_touch-manual.html | 126 +++++++++++++ ...t_touch-action-pan-y-css_touch-manual.html | 106 +++++++++++ ...t_touch-action-span-test_touch-manual.html | 113 +++++++++++ ...nt_touch-action-svg-test_touch-manual.html | 122 ++++++++++++ ..._touch-action-table-test_touch-manual.html | 141 ++++++++++++++ ...ointerevent_touch-action-verification.html | 101 ++++++++++ dom/events/test/pointerevents/readme.md | 5 + 67 files changed, 5764 insertions(+) create mode 100644 dom/events/test/pointerevents/pointerevent_button_attribute_mouse-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_capture_mouse-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_capture_suppressing_mouse-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_change-touch-action-onpointerdown_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_constructor.html create mode 100644 dom/events/test/pointerevents/pointerevent_gotpointercapture_before_first_pointerevent-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_lostpointercapture_is_first-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerdown-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerenter-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerenter_does_not_bubble-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerenter_nohover-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerleave_after_pointerup_nohover-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerleave_descendant_over-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerleave_descendants-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerleave_does_not_bubble-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerleave_mouse-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerleave_pen-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerleave_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointermove-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointermove_isprimary_same_as_pointerdown-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointermove_pointertype-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerout-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerout_after_pointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerout_after_pointerup_nohover-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerout_pen-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerout_received_once-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerover-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointertype_mouse-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointertype_pen-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointertype_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerup-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_pointerup_pointertype-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_releasepointercapture_invalid_pointerid-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_releasepointercapture_onpointerup_mouse-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_setpointercapture_disconnected-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_setpointercapture_inactive_button_mouse-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_setpointercapture_invalid_pointerid-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_setpointercapture_relatedtarget-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_styles.css create mode 100644 dom/events/test/pointerevents/pointerevent_support.js create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-auto-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-button-test_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-illegal.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-keyboard-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-mouse-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-none-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-span-test_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-table-test_touch-manual.html create mode 100644 dom/events/test/pointerevents/pointerevent_touch-action-verification.html create mode 100644 dom/events/test/pointerevents/readme.md diff --git a/dom/events/test/pointerevents/pointerevent_button_attribute_mouse-manual.html b/dom/events/test/pointerevents/pointerevent_button_attribute_mouse-manual.html new file mode 100644 index 00000000000..a31e53d3285 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_button_attribute_mouse-manual.html @@ -0,0 +1,57 @@ + + + + Button and buttons attribute test for mouse + + + + + + + +

Button attribute test for mouse

+

This test is for mouse only

+

+ Test Description: This test checks if button attribute for mouse handled properly. +

Put your mouse over the black rectangle

+

+

+

+ +

Pointer Events button attribute test for mouse test

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_capture_mouse-manual.html b/dom/events/test/pointerevents/pointerevent_capture_mouse-manual.html new file mode 100644 index 00000000000..c4c7bc8c7c4 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_capture_mouse-manual.html @@ -0,0 +1,132 @@ + + + + Set/Release capture + + + + + + + + +

Pointer Events capture test

+

+ Test Description: This test checks if setCapture/releaseCapture functions works properly. Complete the following actions: +
    +
  1. Move your mouse over the black rectangle. pointermove event should be logged in the black rectangle
  2. +
  3. Move your mouse over the purple rectangle. pointerover event should be logged in the purple rectangle
  4. +
  5. Press and hold left mouse button over "Set Capture" button. "gotpointercapture" should be logged in the black rectangle
  6. +
  7. Move your mouse anywhere. pointermove should be logged in the black rectangle
  8. +
  9. Move your mouse over the purple rectangle. Nothig should happen
  10. +
  11. Move your mouse over the black rectangle. pointermove should be logged in the black rectangle
  12. +
  13. Release left mouse button. "lostpointercapture" should be logged in the black rectangle
  14. +
+

+ Test passes if the proper behaviour of the events is observed. +
+
+
+
+ + +

Pointer Events Capture Test

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_capture_suppressing_mouse-manual.html b/dom/events/test/pointerevents/pointerevent_capture_suppressing_mouse-manual.html new file mode 100644 index 00000000000..60e22d4b7d5 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_capture_suppressing_mouse-manual.html @@ -0,0 +1,175 @@ + + + + Set/Release capture + + + + + + + + +

Pointer Events capture test

+

+ Test Description: This test checks if setCapture/releaseCapture functions works properly. Complete the following actions: +
    +
  1. Put your mouse over the black rectangle. pointerover and pointerenter should be logged inside of it.
  2. +
  3. Move your mouse out of the black rectangle. pointerout and pointerleave should be logged inside of it
  4. +
  5. Put your mouse over the purple rectangle. pointerover and pointerenter should be logged inside of it.
  6. +
  7. Move your mouse out of the purple rectangle. pointerout and pointerleave should be logged inside of it
  8. +
  9. Press and hold left mouse button over "Set Capture" button. "gotpointercapture" should be logged in the black rectangle
  10. +
  11. Put your mouse over the purple rectangle and then move it out. Nothing should happen
  12. +
  13. Put your mouse over the black rectangle. pointerover and pointerenter should be logged inside of it.
  14. +
  15. Move your mouse out of the black rectangle. pointerout and pointerleave should be logged inside of it
  16. +
  17. Release left mouse button. "lostpointercapture" should be logged in the black rectangle
  18. +
+

+ Test passes if the proper behaviour of the events is observed. +
+
+
+
+ + +

Pointer Events Capture Test

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_change-touch-action-onpointerdown_touch-manual.html b/dom/events/test/pointerevents/pointerevent_change-touch-action-onpointerdown_touch-manual.html new file mode 100644 index 00000000000..04d56cb7a51 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_change-touch-action-onpointerdown_touch-manual.html @@ -0,0 +1,135 @@ + + + + Change touch-action on pointerdown + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Press and hold your touch. Try to scroll text in any direction. + Then release your touch and try to scroll again. Expected: no panning. +

+

Note: this test is for touch-devices only

+
+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+ +

touch-action: auto to none

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_constructor.html b/dom/events/test/pointerevents/pointerevent_constructor.html new file mode 100644 index 00000000000..36e0394c358 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_constructor.html @@ -0,0 +1,104 @@ + + + + PointerEvent: Constructor test + + + + + + + + +

PointerEvent: Dispatch custom event

+

Test Description: This test checks if PointerEvent constructor works properly using synthetic pointerover and pointerout events. For valid results, this test must be run without generating real (trusted) pointerover or pointerout events on the black rectangle below.

+
+ +
+

The following pointer types were detected: .

+
+
+ + diff --git a/dom/events/test/pointerevents/pointerevent_gotpointercapture_before_first_pointerevent-manual.html b/dom/events/test/pointerevents/pointerevent_gotpointercapture_before_first_pointerevent-manual.html new file mode 100644 index 00000000000..754a58facfd --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_gotpointercapture_before_first_pointerevent-manual.html @@ -0,0 +1,97 @@ + + + + Pointer Event: gotpiontercapture is fired first and asynchronously. + + + + + + + + + + + + +

Pointer Event: Dispatch gotpointercapture event

+

Test Description: + After pointer capture is set for a pointer, and prior to dispatching the first event for the pointer, the gotpointercapture + event must be dispatched to the element that is receiving the pointer capture. The gotpointercapture event must be dispatched asynchronously. +

+
+
+ Use the mouse, touch or pen to tap/click this box. +
+
Do not hover over or touch this element.
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html b/dom/events/test/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html new file mode 100644 index 00000000000..4d152b73a6a --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html @@ -0,0 +1,78 @@ + + + + Lostpointercapture fires on document when target is removed + + + + + + + +

Pointer Events - lostpointercapture when capturing element is removed

+

+ Test Description: + This test checks if lostpointercapture is fired at the document when the capturing node is removed from the document. + Complete the following actions: +
    +
  1. Press and hold left mouse button over "Set Capture" button. "gotpointercapture" should be logged inside of the black rectangle. +
  2. "lostpointercapture" should be logged inside of the black rectangle after a short delay. +
+

+
+
+
+ + +

Pointer Events Capture Test

+
+

The following pointer types were detected: .

+
+
+ + diff --git a/dom/events/test/pointerevents/pointerevent_lostpointercapture_is_first-manual.html b/dom/events/test/pointerevents/pointerevent_lostpointercapture_is_first-manual.html new file mode 100644 index 00000000000..566676d2aef --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_lostpointercapture_is_first-manual.html @@ -0,0 +1,111 @@ + + + + Lostpointercapture triggers first and asynchronously + + + + + + + + +

Pointer Events capture test - lostpointercapture order

+

+ Test Description: + This test checks if lostpointercapture is handled asynchronously and prior to all subsequent events. + Complete the following actions: +
    +
  1. Press and hold left mouse button over "Set Capture" button. "gotpointercapture" should be logged inside of the black rectangle +
  2. "lostpointercapture" should be logged inside of the black rectangle after a short delay +
+

+ Test passes if lostpointercapture is dispatched after releasing the mouse button and before any additional pointer events. +
+
+ + +

Pointer Events Capture Test

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointercancel_touch-manual.html b/dom/events/test/pointerevents/pointerevent_pointercancel_touch-manual.html new file mode 100644 index 00000000000..70a65eeb5ca --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointercancel_touch-manual.html @@ -0,0 +1,77 @@ + + + + PointerCancel - touch + + + + + + + + +

pointercancel test

+

Warning: this test works properly only for devices that have touchscreen

+

+ Test Description: This test checks if pointercancel event triggers. +

Start touch over the black rectangle and then move your finger to scroll the page.

+

+

+

+ +

Pointer Events pointercancel Tests

+
+

The following pointer types were detected: .

+
+
+ + diff --git a/dom/events/test/pointerevents/pointerevent_pointerdown-manual.html b/dom/events/test/pointerevents/pointerevent_pointerdown-manual.html new file mode 100644 index 00000000000..0167e08ba5a --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerdown-manual.html @@ -0,0 +1,59 @@ + + + + + Pointer Events pointerdown tests + + + + + + + + + +

Pointer Events pointerdown tests

+
+ Start with your pointing device outside of this box, then click here. +
+
+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerenter-manual.html b/dom/events/test/pointerevents/pointerevent_pointerenter-manual.html new file mode 100644 index 00000000000..613eb8e4064 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerenter-manual.html @@ -0,0 +1,52 @@ + + + + Pointer Event: Dispatch pointerenter. + + + + + + + + + + + + +

Pointer Event: Dispatch pointerenter

+

+ Test Description: + When a pointing device is moved into the hit test boundaries of an element or one of its descendants, the pointerenter event must be dispatched. +

+
+ Use the mouse or pen to move over this box. +
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerenter_does_not_bubble-manual.html b/dom/events/test/pointerevents/pointerevent_pointerenter_does_not_bubble-manual.html new file mode 100644 index 00000000000..3f0583364a2 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerenter_does_not_bubble-manual.html @@ -0,0 +1,88 @@ + + + + Pointer Event: The pointerenter event does not bubble + + + + + + + + + + + + + +

Pointer Event: pointerenter does not bubble

+

+ Test Description: + The pointerenter event must not bubble up to parent elements. +

+
+ Use the mouse or pen to hover over then out of the purple box nested in the black box. Or with touch, tap on the purple box. +
+
+
+
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerenter_nohover-manual.html b/dom/events/test/pointerevents/pointerevent_pointerenter_nohover-manual.html new file mode 100644 index 00000000000..32675bbb441 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerenter_nohover-manual.html @@ -0,0 +1,74 @@ + + + + Pointer Event: Dispatch pointerenter. (nohover) + + + + + + + + + + + + +

Pointer Event: Dispatch pointerenter (nohover)

+

+ Test Description: + When a pointing device that does not support hover is moved into the hit test boundaries of an element or one of its + descendants as a result of a pointerdown event, the pointerenter event must be dispatched. +

+
+
+ Tap here. +
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+
+
+ + diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual.html new file mode 100644 index 00000000000..56be26549f8 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual.html @@ -0,0 +1,66 @@ + + + + pointerleave after pointercancel + + + + + + + + +

pointerleave after pointercancel

+

Test Description: This test checks if pointerleave event triggers after pointercancel. Start touch on the black rectangle and move your touch to scroll in any direction.

+

Note: this test is for touch devices only

+
+ +

Pointer Events pointerleave tests

+
+

The following pointer types were detected: .

+
+
+ + diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_after_pointerup_nohover-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_after_pointerup_nohover-manual.html new file mode 100644 index 00000000000..30412378428 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerleave_after_pointerup_nohover-manual.html @@ -0,0 +1,67 @@ + + + + pointerleave after pointerup + + + + + + + + +

pointerleave after pointerup

+

Test Description: This test checks if pointerleave event triggers for devices that don't support hover. Tap the black rectangle.

+

Note: this test is only for devices that do not support hover.

+
+ +

Pointer Events pointerleave tests

+
+

The following pointer types were detected: .

+
+
+ + diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_descendant_over-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_descendant_over-manual.html new file mode 100644 index 00000000000..8f4f4bfc7a1 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerleave_descendant_over-manual.html @@ -0,0 +1,61 @@ + + + + pointerleave + descendant + + + + + + + +

pointerleave

+

+ Test Description: This test checks if pointerleave event works properly. +
    +
  1. Put your mouse over the black rectangle +
  2. Then move it into the purple rectangle +
  3. Click on the purple rectangle to complete the test +
+ Note: when you entered the black rectangle once don't leave it before the end of the test to get proper results. +

+

+

+
+
+ +

Pointer Events pointerleave tests

+
+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_descendants-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_descendants-manual.html new file mode 100644 index 00000000000..ac9edcff38a --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerleave_descendants-manual.html @@ -0,0 +1,52 @@ + + + + Pointerleave + descendant + + + + + + + +

pointerleave

+

+ Test Description: This test checks if pointerleave event works properly. +

Put your mouse over the black rectangle and then move it out through purple rectangle boundaries.

+

+

+

+
+
+ +

Pointer Events pointerleave tests

+
+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_does_not_bubble-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_does_not_bubble-manual.html new file mode 100644 index 00000000000..c0e551cd658 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerleave_does_not_bubble-manual.html @@ -0,0 +1,77 @@ + + + + Pointer Event: The pointerleave event does not bubble + + + + + + + + + + + + + +

Pointer Event: pointerleave does not bubble

+

+ Test Description: + The pointerleave event must not bubble up to parent elements. +

+
+ Use the mouse or pen to hover over then out of the purple box nested in the black box. Or with touch, tap on the purple box. +
+
+
+
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_mouse-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_mouse-manual.html new file mode 100644 index 00000000000..708aed91af4 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerleave_mouse-manual.html @@ -0,0 +1,53 @@ + + + + Pointer Event: Dispatch pointerleave (mouse). + + + + + + + + + + + + +

Pointer Event: Dispatch pointerleave (mouse)

+

+ Test Description: + When a pointing device that has continuous position (such as a mouse) leaves the hit test boundaries of an element, the pointerleave event must be dispatched. +

+
+
+ Use a mouse to move over then out of this element +
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_pen-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_pen-manual.html new file mode 100644 index 00000000000..38a2f697920 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerleave_pen-manual.html @@ -0,0 +1,58 @@ + + + + Pointer Event: Dispatch pointerleave (pen). + + + + + + + + + + + + +

Pointer Event: Dispatch pointerleave (pen)

+

+ Test Description: + When a pointing device that supports hover (pen stylus) leaves the range of the digitizer while over an element, the pointerleave event must be dispatched. +

+
+
+ Use a pen to hover over then lift up away from this element. +
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_touch-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_touch-manual.html new file mode 100644 index 00000000000..3044327a5ff --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerleave_touch-manual.html @@ -0,0 +1,53 @@ + + + + Pointer Event: Dispatch pointerleave (touch). + + + + + + + + + + + + +

Pointer Event: Dispatch pointerleave (touch)

+

+ Test Description: + When a pointing device that does not support hover (such as a finger) leaves the hit test boundaries as a result of a pointerup event, the pointerleave event must be dispatched. +

+
+
+ Use touch to tap on this box. +
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointermove-manual.html b/dom/events/test/pointerevents/pointerevent_pointermove-manual.html new file mode 100644 index 00000000000..cf1a1ee4ee8 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointermove-manual.html @@ -0,0 +1,44 @@ + + + + Pointermove + + + + + + + + + +

PointerMove

+

Test Description: This test checks if pointermove event triggers. Move your mouse over the black rectangle or slide it if you are using touchscreen.

+
+ +

Pointer Events pointermove Tests

+
+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointermove_isprimary_same_as_pointerdown-manual.html b/dom/events/test/pointerevents/pointerevent_pointermove_isprimary_same_as_pointerdown-manual.html new file mode 100644 index 00000000000..b43d59f4f6e --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointermove_isprimary_same_as_pointerdown-manual.html @@ -0,0 +1,70 @@ + + + + Pointer Event: pointermove has same isPrimary as last pointerdown with the same pointerId + + + + + + + + + + + + +

Pointer Event: pointermove has the same isPrimary as last pointerdown with the same pointerId

+

Test Description: + The isPrimary attribute of a pointermove event must have the same value as the isPrimary attribute of the last pointerdown event with the same pointerId attribute. +

+
+ Press and hold a mouse button, touch contact or pen contact on this element. Move around inside the element while maintaining contact/button down. Only use one device per test run. +

Lift off of the element to complete the test.

+
+
+
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointermove_pointertype-manual.html b/dom/events/test/pointerevents/pointerevent_pointermove_pointertype-manual.html new file mode 100644 index 00000000000..4c410159c13 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointermove_pointertype-manual.html @@ -0,0 +1,64 @@ + + + + pointerType conservation + + + + + + + +

pointerType conservation

+

Test Description: This test checks if pointerType attribute defined properly.

+
+ Press and move a mouse button, touch contact or pen contact on the black rectangle. Only use one device per test run. +
+

Note: This test may be run with different pointer devices, however only one device should be used per test run. +

+

+ +

Pointer Events pointerType conservation tests

+
+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerout-manual.html b/dom/events/test/pointerevents/pointerevent_pointerout-manual.html new file mode 100644 index 00000000000..473fa14ebbc --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerout-manual.html @@ -0,0 +1,46 @@ + + + + pointerout + + + + + + + + +

pointerout

+

Test Description: This test checks if pointerout event triggers. Put your mouse over the black rectangle and then move it out of the rectangle boundaries. If you are using touchscreen tap the black rectangle.

+
+ +

Pointer Events pointerout tests

+
+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerout_after_pointercancel_touch-manual.html b/dom/events/test/pointerevents/pointerevent_pointerout_after_pointercancel_touch-manual.html new file mode 100644 index 00000000000..1888591a7c2 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerout_after_pointercancel_touch-manual.html @@ -0,0 +1,67 @@ + + + + pointerout + + + + + + + + +

pointerout

+

Test Description: This test checks if pointerout event triggers after pointercancel. Start touch on the black rectangle and move your touch to scroll in any direction.

+

Note: this test is for touch devices only

+
+ +

Pointer Events pointerout tests

+
+

The following pointer types were detected: .

+
+
+ + diff --git a/dom/events/test/pointerevents/pointerevent_pointerout_after_pointerup_nohover-manual.html b/dom/events/test/pointerevents/pointerevent_pointerout_after_pointerup_nohover-manual.html new file mode 100644 index 00000000000..44813033a72 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerout_after_pointerup_nohover-manual.html @@ -0,0 +1,67 @@ + + + + pointerout + + + + + + + + +

pointerout

+

Test Description: This test checks if pointerout event triggers for devices that don't support hover. Tap the black rectangle.

+

Note: this test is only for devices that do not support hover.

+
+ +

Pointer Events pointerout tests

+
+

The following pointer types were detected: .

+
+
+ + diff --git a/dom/events/test/pointerevents/pointerevent_pointerout_pen-manual.html b/dom/events/test/pointerevents/pointerevent_pointerout_pen-manual.html new file mode 100644 index 00000000000..3973948c164 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerout_pen-manual.html @@ -0,0 +1,57 @@ + + + + pointerout + + + + + + + + +

pointerout

+

Test Description: This test checks if pointerout event triggers for pen. Place your pen over the black rectangle and then pull the pen out of the digitizer's detectable range.

+

Note: this test is for devices that support hover - for pen only

+
+ +

Pointer Events pointerout tests

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerout_received_once-manual.html b/dom/events/test/pointerevents/pointerevent_pointerout_received_once-manual.html new file mode 100644 index 00000000000..4827ae91de1 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerout_received_once-manual.html @@ -0,0 +1,58 @@ + + + + pointerout received just once + + + + + + + +

pointerout received just once

+

+ Test Description: This test checks if pointerout event dispatched properly. +
    +
  1. Put your mouse over the black rectangle. +
  2. Move your mouse out of the black rectangle +
+

+

+

+ +

Pointer Events pointerout received once test

+
+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerover-manual.html b/dom/events/test/pointerevents/pointerevent_pointerover-manual.html new file mode 100644 index 00000000000..4601c08aaaf --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerover-manual.html @@ -0,0 +1,52 @@ + + + + Pointer Event: Dispatch pointerover. + + + + + + + + + + + + +

Pointer Event: Dispatch pointerover.

+

Test Description: + When a pointing device is moved into the hit test boundaries of an element, the pointerover event must be dispatched. +

+
+
+ Use mouse, touch or pen to hover or contact this element.. +
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointertype_mouse-manual.html b/dom/events/test/pointerevents/pointerevent_pointertype_mouse-manual.html new file mode 100644 index 00000000000..b1e7d7046ea --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointertype_mouse-manual.html @@ -0,0 +1,63 @@ + + + + Pointer Event: If a pointer event is initiated by a mouse device, then the pointerType must be "mouse" + + + + + + + + + + + + +

Pointer Event: Dispatch pointer events with pointerType equal to "mouse"

+

Test Description: + If a pointer event is initiated by a mouse device, then the pointerType must be 'mouse'. +

+
+
+ Using the mouse, click this element. +
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointertype_pen-manual.html b/dom/events/test/pointerevents/pointerevent_pointertype_pen-manual.html new file mode 100644 index 00000000000..0aabfce4fc9 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointertype_pen-manual.html @@ -0,0 +1,61 @@ + + + + Pointer Event: If a pointer event is initiated by a pen device, then the pointerType must be "pen" + + + + + + + + + + + + +

Pointer Event: Dispatch pointer events with pointerType equal to "pen"

+

Test Description: + If a pointer event is initiated by a pen device, then the pointerType must be 'pen'. +

+
+
+ Using pen, tap here. +
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointertype_touch-manual.html b/dom/events/test/pointerevents/pointerevent_pointertype_touch-manual.html new file mode 100644 index 00000000000..c06fbe48c6d --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointertype_touch-manual.html @@ -0,0 +1,62 @@ + + + + Pointer Event: If a pointer event is initiated by a touch device, then the pointerType must be "touch" + + + + + + + + + + + + +

Pointer Event: Dispatch pointer events with pointerType equal to "touch"

+

Test Description: + If a pointer event is initiated by a touch device, then the pointerType must be 'touch'. +

+
+
+ Using touch, tap here. +
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerup-manual.html b/dom/events/test/pointerevents/pointerevent_pointerup-manual.html new file mode 100644 index 00000000000..30a03f23dcf --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerup-manual.html @@ -0,0 +1,44 @@ + + + + pointerup + + + + + + + + +

pointerup

+

Test Description: This test checks if pointerup event triggers. Press mouse left button and release it over the black rectangle or tap it if you are using a touchscreen.

+
+ +

Pointer Events pointerup tests

+
+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html b/dom/events/test/pointerevents/pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html new file mode 100644 index 00000000000..994061b8bf0 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html @@ -0,0 +1,63 @@ + + + + Pointer Event: pointerup has same isPrimary as last pointerdown with the same pointerId + + + + + + + + + + + + +

Pointer Event: pointerup has the same isPrimary as last pointerdown with the same pointerId

+

Test Description: + The isPrimary attribute of a pointerup event must have the same value as the isPrimary attribute of the last pointerdown event with the same pointerId attribute. +

+
+ Press and release a mouse button, touch contact or pen contact on this element. Only use one device per test run. +
+
+
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerup_pointertype-manual.html b/dom/events/test/pointerevents/pointerevent_pointerup_pointertype-manual.html new file mode 100644 index 00000000000..b356484bacc --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_pointerup_pointertype-manual.html @@ -0,0 +1,64 @@ + + + + pointerType conservation + + + + + + + +

pointerType conservation

+

Test Description: This test checks if pointerType attribute defined properly.

+
+ Press and release a mouse button, touch contact or pen contact on the black rectangle. Only use one device per test run. +
+

Note: This test may be run with different pointer devices, however only one device should be used per test run. +

+

+ +

Pointer Events pointerType conservation tests

+
+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html b/dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html new file mode 100644 index 00000000000..f3991d98d74 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html @@ -0,0 +1,116 @@ + + + + Pointer Event: releasePointerCapture() - subsequent events follow normal hitting testing mechanisms + + + + + + + + + + + +
+

Pointer Event: releasePointerCapture() - subsequent events follow normal hitting testing mechanisms

+

+ Test Description: + After invoking the releasePointerCapture method on an element, subsequent events for the specified + pointer must follow normal hit testing mechanisms for determining the event target +

+
+
+ Use mouse, touch or pen to contact here and move around. +
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_releasepointercapture_invalid_pointerid-manual.html b/dom/events/test/pointerevents/pointerevent_releasepointercapture_invalid_pointerid-manual.html new file mode 100644 index 00000000000..fe2ab006181 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_releasepointercapture_invalid_pointerid-manual.html @@ -0,0 +1,76 @@ + + + + Pointer Event: releasePointerCapture DOMException - InvalidPointerId + + + + + + + + + + + + + + +
+

Pointer Event: releasePointerCapture() DOMException - InvalidPointerId

+

+ Test Description: + Upon invocation of the releasePointerCapture method, if the provided pointerId value does not match any of the + active pointers, a DOMException with the name InvalidPointerId must be thrown. +

+
+
+ Use the mouse, touch or pen to move over or contact this box. +
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch-manual.html b/dom/events/test/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch-manual.html new file mode 100644 index 00000000000..105e3b5a974 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch-manual.html @@ -0,0 +1,71 @@ + + + + Release capture on pointercancel + + + + + + + +

Pointer Events Capture Test - release capture on pointercancel

+

+ Test Description: This test checks if setCapture/releaseCapture functions works properly. Complete the following actions: +
    +
  1. Touch black rectangle and do not release your touch +
  2. Move your touch to scroll the page. "lostpointercapture" should be logged inside of the black rectangle immediately after "pointercancel" +
+

+ Test passes if the proper behavior of the events is observed. +
+ + +

Pointer Events Capture Test

+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+
+
+ + diff --git a/dom/events/test/pointerevents/pointerevent_releasepointercapture_onpointerup_mouse-manual.html b/dom/events/test/pointerevents/pointerevent_releasepointercapture_onpointerup_mouse-manual.html new file mode 100644 index 00000000000..df515436c05 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_releasepointercapture_onpointerup_mouse-manual.html @@ -0,0 +1,79 @@ + + + + Release capture on pointerup + + + + + + + +

Pointer Events Capture Test - release capture on pointerup

+

+ Test Description: This test checks if setCapture/releaseCapture functions works properly. Complete the following actions: +
    +
  1. Press and hold left mouse button over "Set Capture" button +
  2. Release left mouse button anywhere over the document. "lostpointercapture" should be logged inside of the black rectangle immediately after "pointerup" +
+

+ Test passes if the proper behavior of the events is observed. +
+
+ + +

Pointer Events Capture Test

+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_setpointercapture_disconnected-manual.html b/dom/events/test/pointerevents/pointerevent_setpointercapture_disconnected-manual.html new file mode 100644 index 00000000000..9e9646525fa --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_setpointercapture_disconnected-manual.html @@ -0,0 +1,55 @@ + + + + setPointerCapture() throws on disconnected node + + + + + + + + +

Pointer Event: DOMException InvalidStateError

+

Test Description: + When the setPointerCapture method is invoked, if the target node does not participate in its ownerDocument's tree, a DOMException with the name InvalidStateError must be thrown. +

+
+
+ Use the mouse, touch or pen to contact this box. +
+
+
+

The following pointer types were detected: .

+
+
+ + diff --git a/dom/events/test/pointerevents/pointerevent_setpointercapture_inactive_button_mouse-manual.html b/dom/events/test/pointerevents/pointerevent_setpointercapture_inactive_button_mouse-manual.html new file mode 100644 index 00000000000..b3e8debb716 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_setpointercapture_inactive_button_mouse-manual.html @@ -0,0 +1,58 @@ + + + + setPointerCapture + inactive button state + + + + + + + +

setPointerCapture

+

+ Test Description: This test checks if setPointerCapture works properly. +
    +
  1. Put your mouse over the black rectangle +
  2. Move you mouse out to complete the test +
+

+

+

+ +

Pointer Events setPointerCapture Tests

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_setpointercapture_invalid_pointerid-manual.html b/dom/events/test/pointerevents/pointerevent_setpointercapture_invalid_pointerid-manual.html new file mode 100644 index 00000000000..4dbe858db16 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_setpointercapture_invalid_pointerid-manual.html @@ -0,0 +1,65 @@ + + + + Pointer Event: gotPiontercapture is fired first. + + + + + + + + + + + + + +

Pointer Event: DOMException InvalidPointerId

+

Test Description: + When the setPointerCapture method is invoked, if the provided pointerId value does not match any of the active pointers, a DOMException with the name InvalidPointerId must be thrown. +

+
+
+ Use the mouse, touch or pen to contact this box. +
+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_setpointercapture_relatedtarget-manual.html b/dom/events/test/pointerevents/pointerevent_setpointercapture_relatedtarget-manual.html new file mode 100644 index 00000000000..45b67414b26 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_setpointercapture_relatedtarget-manual.html @@ -0,0 +1,101 @@ + + + + Set/Release capture + relatedTarget + + + + + + + +

Pointer Events Capture Test - capture and relatedTarget

+

+ Test Description: This test checks if setCapture/releaseCapture functions works properly. Complete the following actions: +
    +
  1. Put your mouse over the lower rectangle. pointerover should be received for the purple rectangle +
  2. Press and hold left mouse button over "Set Capture" button +
  3. Put your mouse over the upper rectangle. pointerover should be received for the black rectangle +
  4. Release left mouse button to complete the test. +
+

+ Test passes if the proper behavior of the events is observed. + +
+
+
+
+ + +

Pointer Events Capture Test

+
+

Test complete: Scroll to Summary to view Pass/Fail Results.

+

The following pointer types were detected: .

+

Refresh the page to run the tests again with a different pointer type.

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_styles.css b/dom/events/test/pointerevents/pointerevent_styles.css new file mode 100644 index 00000000000..55265af4141 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_styles.css @@ -0,0 +1,61 @@ +#target0 { +background: black; +color: white; +white-space: nowrap; +overflow-y: auto; +overflow-x: auto; +} + +#target1 { +background: purple; +color: white; +white-space: nowrap; +overflow-y: auto; +overflow-x: auto; +} + +.scroller { +width: 700px; +height: 430px; +margin: 20px; +overflow: auto; +background: black; +} + +.scroller > div { +height: 1000px; +width: 1000px; +color: white; +} + +.scroller > div div { +height: 100%; +width: 100%; +color: white; +} + +div { +margin: 0em; +padding: 2em; +} + +#complete-notice { +background: #afa; +border: 1px solid #0a0; +display: none; +} + +#pointertype-log { +font-weight: bold; +} + +#listener { +background: orange; +border: 1px solid orange; +position: absolute; +top: -100px; +} + +body.scrollable { +min-height: 5000px; +} diff --git a/dom/events/test/pointerevents/pointerevent_support.js b/dom/events/test/pointerevents/pointerevent_support.js new file mode 100644 index 00000000000..b3fb661f8b7 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_support.js @@ -0,0 +1,170 @@ +var All_Pointer_Events = [ + "pointerdown", + "pointerup", + "pointercancel", + "pointermove", + "pointerover", + "pointerout", + "pointerenter", + "pointerleave", + "gotpointercapture", + "lostpointercapture"]; + +// Check for conformance to PointerEvent interface +// TA: 1.1, 1.2, 1.6, 1.7, 1.8, 1.9, 1.10, 1.11, 1.12, 1.13 +function check_PointerEvent(event) { + test(function () { + assert_true(event instanceof PointerEvent, "event is a PointerEvent event"); + }, event.type + " event is a PointerEvent event"); + + + // Check attributes for conformance to WebIDL: + // * attribute exists + // * has proper type + // * if the attribute is "readonly", it cannot be changed + // TA: 1.1, 1.2 + var idl_type_check = { + "long": function (v) { return typeof v === "number" && Math.round(v) === v; }, + "float": function (v) { return typeof v === "number"; }, + "string": function (v) { return typeof v === "string"; }, + "boolean": function (v) { return typeof v === "boolean" } + }; + [ + ["readonly", "long", "pointerId"], + ["readonly", "float", "width"], + ["readonly", "float", "height"], + ["readonly", "float", "pressure"], + ["readonly", "long", "tiltX"], + ["readonly", "long", "tiltY"], + ["readonly", "string", "pointerType"], + ["readonly", "boolean", "isPrimary"] + ].forEach(function (attr) { + var readonly = attr[0]; + var type = attr[1]; + var name = attr[2]; + + + // existence check + test(function () { + assert_true(name in event, name + " attribute in " + event.type + " event"); + }, event.type + "." + name + " attribute exists"); + + + // readonly check + if (readonly === "readonly") { + test(function () { + assert_readonly(event.type, name, event.type + "." + name + " cannot be changed"); + }, event.type + "." + name + " is readonly"); + } + + + // type check + test(function () { + assert_true(idl_type_check[type](event[name]), name + " attribute of type " + type); + }, event.type + "." + name + " IDL type " + type + " (JS type was " + typeof event[name] + ")"); + }); + + + // Check the pressure value + // TA: 1.6, 1.7, 1.8 + test(function () { + // TA: 1.6 + assert_greater_than_equal(event.pressure, 0, "pressure is greater than or equal to 0"); + assert_less_than_equal(event.pressure, 1, "pressure is less than or equal to 1"); + + + // TA: 1.7, 1.8 + if (event.pointerType === "mouse") { + if (event.buttons === 0) { + assert_equals(event.pressure, 0, "pressure is 0 for mouse with no buttons pressed"); + } else { + assert_equals(event.pressure, 0.5, "pressure is 0.5 for mouse with a button pressed"); + } + } + }, event.type + ".pressure value is valid"); + + + // Check mouse-specific properties + if (event.pointerType === "mouse") { + // TA: 1.9, 1.10, 1.13 + test(function () { + assert_equals(event.tiltX, 0, event.type + ".tiltX is 0 for mouse"); + assert_equals(event.tiltY, 0, event.type + ".tiltY is 0 for mouse"); + assert_true(event.isPrimary, event.type + ".isPrimary is true for mouse"); + }, event.type + " properties for pointerType = mouse"); + // Check properties for pointers other than mouse + } +} + +function showPointerTypes() { + var complete_notice = document.getElementById("complete-notice"); + var pointertype_log = document.getElementById("pointertype-log"); + var pointertypes = Object.keys(detected_pointertypes); + pointertype_log.innerHTML = pointertypes.length ? + pointertypes.join(",") : "(none)"; + complete_notice.style.display = "block"; +} + +function log(msg, el) { + if (++count > 10){ + count = 0; + el.innerHTML = ' '; + } + el.innerHTML = msg + '; ' + el.innerHTML; +} + + function failOnScroll() { + assert_true(false, + "scroll received while shouldn't"); +} + +function updateDescriptionNextStep() { + document.getElementById('desc').innerHTML = "Test Description: Try to scroll text RIGHT."; +} + +function updateDescriptionComplete() { + document.getElementById('desc').innerHTML = "Test Description: Test complete"; +} + +function updateDescriptionSecondStepTouchActionElement(target, scrollReturnInterval) { + window.setTimeout(function() { + objectScroller(target, 'up', 0);} + , scrollReturnInterval); + document.getElementById('desc').innerHTML = "Test Description: Try to scroll element RIGHT moving your outside of the red border"; +} + +function updateDescriptionThirdStepTouchActionElement(target, scrollReturnInterval) { + window.setTimeout(function() { + objectScroller(target, 'left', 0);} + , scrollReturnInterval); + document.getElementById('desc').innerHTML = "Test Description: Try to scroll element DOWN then RIGHT starting your touch inside of the element. Then tap complete button"; +} + +function updateDescriptionFourthStepTouchActionElement(target, scrollReturnInterval) { + document.getElementById('desc').innerHTML = "Test Description: Try to scroll element RIGHT starting your touch inside of the element"; +} + +function objectScroller(target, direction, value) { + if (direction == 'up') { + target.scrollTop = 0; + } else if (direction == 'left') { + target.scrollLeft = 0; + } +} + +function sPointerCapture(e) { + try { + target0.setPointerCapture(e.pointerId); + } + catch(e) { + } +} + +function rPointerCapture(e) { + try { + captureButton.value = 'Set Capture'; + target0.releasePointerCapture(e.pointerId); + } + catch(e) { + } +} \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-auto-css_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-auto-css_touch-manual.html new file mode 100644 index 00000000000..f5e9d12c353 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-auto-css_touch-manual.html @@ -0,0 +1,129 @@ + + + + touch-action: auto + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll text DOWN. Wait for description update. Expected: pan enabled

+

Note: this test is for touch-devices only

+
+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+ +

touch-action: auto

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-button-test_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-button-test_touch-manual.html new file mode 100644 index 00000000000..01a1c88c181 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-button-test_touch-manual.html @@ -0,0 +1,109 @@ + + + + Button touch-action test + + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll black element DOWN moving your touch outside of the red border. Wait for description update.

+

Note: this test is for touch only

+
+ +
+
+ + + +

touch-action: none

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-illegal.html b/dom/events/test/pointerevents/pointerevent_touch-action-illegal.html new file mode 100644 index 00000000000..5fe6179840e --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-illegal.html @@ -0,0 +1,67 @@ + + + + touch-action: illegal + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Test will automatically check behaviour of following combinations: 'pan-x none', 'pan-y none', 'auto none'

+
+
+
+ +

touch-action: none

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html new file mode 100644 index 00000000000..364c9c11f6a --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html @@ -0,0 +1,117 @@ + + + + touch-action: parent > child: auto > child: none + + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: no panning.

+

Note: this test is for touch-devices only

+
+
+
+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+
+
+ + +

behaviour: none

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html new file mode 100644 index 00000000000..786819b8588 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html @@ -0,0 +1,112 @@ + + + + touch-action: child: none + + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: no panning

+

Note: this test is for touch-devices only

+
+
+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+
+ + +

behaviour: none

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html new file mode 100644 index 00000000000..09a97e3cbe2 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html @@ -0,0 +1,112 @@ + + + + touch-action: parent > child: pan-x > child: pan-x + + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: only pans in x direction.

+

Note: this test is for touch-devices only

+
+
+
+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+
+
+ + +

behaviour: pan-x

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html new file mode 100644 index 00000000000..527e5537400 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html @@ -0,0 +1,117 @@ + + + + touch-action: parent > child: pan-x > child: pan-y + + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: no panning/zooming/etc.

+

Note: this test is for touch-devices only

+
+
+
+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+
+
+ + +

behaviour: none

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html new file mode 100644 index 00000000000..b13013c4376 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html @@ -0,0 +1,133 @@ + + + + touch-action: parent: none + two embedded children + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll text DOWN. Wait for description update. Expected: pan enabled

+

Note: this test is for touch-devices only

+
+
+
+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+
+
+ +

behaviour: auto

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html new file mode 100644 index 00000000000..163ef9b8ef4 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html @@ -0,0 +1,112 @@ + + + + touch-action: inherit from parent: none + + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: no panning

+

Note: this test is for touch-devices only

+
+
+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+
+ + +

behaviour: none

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-keyboard-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-keyboard-manual.html new file mode 100644 index 00000000000..3fef3f646f7 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-keyboard-manual.html @@ -0,0 +1,124 @@ + + + + touch-action: keyboard + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Press DOWN ARROW key. Wait for description update. Expected: pan enabled

+

Note: this test is for keyboard only

+
+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+ +

touch-action: none

+
+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-mouse-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-mouse-manual.html new file mode 100644 index 00000000000..fcc8584515c --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-mouse-manual.html @@ -0,0 +1,130 @@ + + + + touch-action: mouse + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll text down using mouse (use mouse wheel or click on the scrollbar). Wait for description update.

+

Note: this test is for mouse only

+
+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+ +

touch-action: none

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-none-css_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-none-css_touch-manual.html new file mode 100644 index 00000000000..dec694f3eca --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-none-css_touch-manual.html @@ -0,0 +1,111 @@ + + + + touch-action: none + + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: no panning/zooming/etc.

+

Note: this test is for touch-devices only

+
+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+ + +

touch-action: none

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual.html new file mode 100644 index 00000000000..e757baec6be --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual.html @@ -0,0 +1,106 @@ + + + + touch-action: pan-x + + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: only pans in x direction.

+

Note: this test is for touch-devices only

+
+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+ + +

touch-action: pan-x

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html new file mode 100644 index 00000000000..e89b8b742e9 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html @@ -0,0 +1,111 @@ + + + + touch-action: parent > child: pan-x pan-y > child: pan-y + + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: only pans in y direction.

+

Note: this test is for touch-devices only

+
+
+
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+
+
+ + +

behaviour: pan-y

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch-manual.html new file mode 100644 index 00000000000..0c900ff7407 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch-manual.html @@ -0,0 +1,126 @@ + + + + touch-action: pan-x pan-y + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll text DOWN. Wait for description update. Expected: pan enabled

+

Note: this test is for touch-devices only

+
+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+ +

touch-action: pan-x pan-y

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual.html new file mode 100644 index 00000000000..4ad39ecc838 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual.html @@ -0,0 +1,106 @@ + + + + touch-action: pan-y + + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: only pans in y direction.

+

Note: this test is for touch-devices only

+
+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem + nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. + Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit + lobortis nisl ut aliquip ex ea commodo consequat. +

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+

Lorem ipsum dolor sit amet...

+
+ + +

touch-action: pan-y

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-span-test_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-span-test_touch-manual.html new file mode 100644 index 00000000000..41635e0bf94 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-span-test_touch-manual.html @@ -0,0 +1,113 @@ + + + + Span touch-action test + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll black element DOWN moving your touch outside of the red border. Wait for description update.

+

Note: this test is for touch only

+
+ + Test span + +
+ + + +

touch-action: none

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html new file mode 100644 index 00000000000..6c9c0b3f68c --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html @@ -0,0 +1,122 @@ + + + + SVG test + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll black element DOWN moving your touch outside of the red border. Wait for description update.

+

Note: this test is for touch only

+
+ + + Sorry, your browser does not support inline SVG. + +
+
+ + +

touch-action: none

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-table-test_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-table-test_touch-manual.html new file mode 100644 index 00000000000..fcc3a3e7cad --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-table-test_touch-manual.html @@ -0,0 +1,141 @@ + + + + Table touch-action test + + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Try to scroll element DOWN starting your touch over the 1st Row. Wait for description update.

+

Note: this test is for touch only

+
+ + + + + +
The caption, first row element, and cell 3 have touch-action: none.
Header 1 Cell 1 Cell 2
Header 2 Cell 3 Cell 4
Header 3 Cell 5 Cell 6
+
+
+ + + +

touch-action: none

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-verification.html b/dom/events/test/pointerevents/pointerevent_touch-action-verification.html new file mode 100644 index 00000000000..2e694229a21 --- /dev/null +++ b/dom/events/test/pointerevents/pointerevent_touch-action-verification.html @@ -0,0 +1,101 @@ + + + + touch-action: basic verification + + + + + + + + + +

Pointer Events touch-action attribute support

+

Test Description: Test will automatically check behaviour of following values: 'auto', 'pan-x', 'pan-y', ' none', 'manipulation'

+
+
+
+
+
+ +

touch-action: basic verification

+
+

The following pointer types were detected: .

+
+
+ + \ No newline at end of file diff --git a/dom/events/test/pointerevents/readme.md b/dom/events/test/pointerevents/readme.md new file mode 100644 index 00000000000..f0d4fc73e6f --- /dev/null +++ b/dom/events/test/pointerevents/readme.md @@ -0,0 +1,5 @@ +Directory for Pointer Events Tests + +All tests were got from official repository: + +https://github.com/w3c/web-platform-tests/tree/master/pointerevents From 72e63b81595e51109b26953b49b8663e1e10f887 Mon Sep 17 00:00:00 2001 From: Maksim Lebedev Date: Tue, 19 May 2015 07:03:00 +0200 Subject: [PATCH 07/72] Bug 1000870 - Add some features in testing system. r=smaug --- dom/base/nsContentUtils.cpp | 2 ++ widget/MouseEvents.h | 1 + 2 files changed, 3 insertions(+) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 86e80fc08a9..793bceb868c 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -7669,6 +7669,8 @@ int16_t nsContentUtils::GetButtonsFlagForButton(int32_t aButton) { switch (aButton) { + case -1: + return WidgetMouseEvent::eNoButtonFlag; case WidgetMouseEvent::eLeftButton: return WidgetMouseEvent::eLeftButtonFlag; case WidgetMouseEvent::eMiddleButton: diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h index d6b36238694..130b8faaa8c 100644 --- a/widget/MouseEvents.h +++ b/widget/MouseEvents.h @@ -115,6 +115,7 @@ public: int16_t button; enum buttonsFlag { + eNoButtonFlag = 0x00, eLeftButtonFlag = 0x01, eRightButtonFlag = 0x02, eMiddleButtonFlag = 0x04, From b5c92fbf2939f21ea0e7611ea91166ddf1ce3971 Mon Sep 17 00:00:00 2001 From: Lebedev Maksim Date: Wed, 3 Feb 2016 05:06:00 +0100 Subject: [PATCH 08/72] Bug 1000870 - Change official tests for pointer events to auto mochitest system. r=smaug --- dom/events/moz.build | 6 +- dom/events/test/pointerevents/mochitest.ini | 165 ++++++++++++++++++ .../mochitest_support_external.js | 93 ++++++++++ .../mochitest_support_internal.js | 40 +++++ ...erevent_button_attribute_mouse-manual.html | 6 +- .../pointerevent_capture_mouse-manual.html | 5 +- ...vent_capture_suppressing_mouse-manual.html | 5 +- ...uch-action-onpointerdown_touch-manual.html | 5 +- .../pointerevent_constructor.html | 3 +- ...ture_before_first_pointerevent-manual.html | 5 +- ...rcapture_for_disconnected_node-manual.html | 5 +- ...nt_lostpointercapture_is_first-manual.html | 5 +- ...interevent_pointercancel_touch-manual.html | 5 +- .../pointerevent_pointerdown-manual.html | 3 +- .../pointerevent_pointerenter-manual.html | 3 +- ...t_pointerenter_does_not_bubble-manual.html | 5 +- ...nterevent_pointerenter_nohover-manual.html | 5 +- ...eave_after_pointercancel_touch-manual.html | 3 +- ...rleave_after_pointerup_nohover-manual.html | 3 +- ...t_pointerleave_descendant_over-manual.html | 5 +- ...event_pointerleave_descendants-manual.html | 5 +- ...t_pointerleave_does_not_bubble-manual.html | 5 +- ...ointerevent_pointerleave_mouse-manual.html | 5 +- .../pointerevent_pointerleave_pen-manual.html | 3 +- ...ointerevent_pointerleave_touch-manual.html | 3 +- .../pointerevent_pointermove-manual.html | 3 +- ..._isprimary_same_as_pointerdown-manual.html | 5 +- ...revent_pointermove_pointertype-manual.html | 5 +- .../pointerevent_pointerout-manual.html | 3 +- ...rout_after_pointercancel_touch-manual.html | 3 +- ...terout_after_pointerup_nohover-manual.html | 3 +- .../pointerevent_pointerout_pen-manual.html | 3 +- ...event_pointerout_received_once-manual.html | 3 +- .../pointerevent_pointerover-manual.html | 3 +- ...pointerevent_pointertype_mouse-manual.html | 5 +- .../pointerevent_pointertype_pen-manual.html | 7 +- ...pointerevent_pointertype_touch-manual.html | 7 +- .../pointerevent_pointerup-manual.html | 3 +- ..._isprimary_same_as_pointerdown-manual.html | 5 +- ...terevent_pointerup_pointertype-manual.html | 5 +- ...ture_events_to_original_target-manual.html | 5 +- ...intercapture_invalid_pointerid-manual.html | 5 +- ...rcapture_onpointercancel_touch-manual.html | 5 +- ...intercapture_onpointerup_mouse-manual.html | 5 +- ...setpointercapture_disconnected-manual.html | 5 +- ...rcapture_inactive_button_mouse-manual.html | 6 +- ...intercapture_invalid_pointerid-manual.html | 5 +- ...etpointercapture_relatedtarget-manual.html | 6 +- .../pointerevents/pointerevent_support.js | 24 ++- ...nt_touch-action-auto-css_touch-manual.html | 3 +- ...touch-action-button-test_touch-manual.html | 5 +- .../pointerevent_touch-action-illegal.html | 3 +- ...it_child-auto-child-none_touch-manual.html | 3 +- ...ction-inherit_child-none_touch-manual.html | 3 +- ..._child-pan-x-child-pan-x_touch-manual.html | 3 +- ..._child-pan-x-child-pan-y_touch-manual.html | 3 +- ...erit_highest-parent-none_touch-manual.html | 3 +- ...tion-inherit_parent-none_touch-manual.html | 3 +- ...terevent_touch-action-keyboard-manual.html | 3 +- ...ointerevent_touch-action-mouse-manual.html | 3 +- ...nt_touch-action-none-css_touch-manual.html | 3 +- ...t_touch-action-pan-x-css_touch-manual.html | 3 +- ...action-pan-x-pan-y-pan-y_touch-manual.html | 3 +- ...touch-action-pan-x-pan-y_touch-manual.html | 3 +- ...t_touch-action-pan-y-css_touch-manual.html | 3 +- ...t_touch-action-span-test_touch-manual.html | 3 +- ...nt_touch-action-svg-test_touch-manual.html | 3 +- ..._touch-action-table-test_touch-manual.html | 3 +- ...ointerevent_touch-action-verification.html | 3 +- .../test/pointerevents/test_empty_file.html | 7 + ...erevent_button_attribute_mouse-manual.html | 29 +++ ...est_pointerevent_capture_mouse-manual.html | 34 ++++ ...vent_capture_suppressing_mouse-manual.html | 35 ++++ ...uch-action-onpointerdown_touch-manual.html | 39 +++++ .../test_pointerevent_constructor.html | 28 +++ ...ture_before_first_pointerevent-manual.html | 32 ++++ ...rcapture_for_disconnected_node-manual.html | 33 ++++ ...nt_lostpointercapture_is_first-manual.html | 30 ++++ ...interevent_pointercancel_touch-manual.html | 29 +++ .../test_pointerevent_pointerdown-manual.html | 30 ++++ ...test_pointerevent_pointerenter-manual.html | 28 +++ ...t_pointerenter_does_not_bubble-manual.html | 29 +++ ...nterevent_pointerenter_nohover-manual.html | 30 ++++ ...eave_after_pointercancel_touch-manual.html | 29 +++ ...rleave_after_pointerup_nohover-manual.html | 29 +++ ...t_pointerleave_descendant_over-manual.html | 30 ++++ ...event_pointerleave_descendants-manual.html | 29 +++ ...t_pointerleave_does_not_bubble-manual.html | 29 +++ ...ointerevent_pointerleave_mouse-manual.html | 29 +++ ..._pointerevent_pointerleave_pen-manual.html | 30 ++++ ...ointerevent_pointerleave_touch-manual.html | 29 +++ .../test_pointerevent_pointermove-manual.html | 28 +++ ..._isprimary_same_as_pointerdown-manual.html | 30 ++++ ...revent_pointermove_pointertype-manual.html | 29 +++ .../test_pointerevent_pointerout-manual.html | 29 +++ ...rout_after_pointercancel_touch-manual.html | 29 +++ ...terout_after_pointerup_nohover-manual.html | 29 +++ ...st_pointerevent_pointerout_pen-manual.html | 30 ++++ ...event_pointerout_received_once-manual.html | 29 +++ .../test_pointerevent_pointerover-manual.html | 28 +++ ...pointerevent_pointertype_mouse-manual.html | 29 +++ ...t_pointerevent_pointertype_pen-manual.html | 29 +++ ...pointerevent_pointertype_touch-manual.html | 29 +++ .../test_pointerevent_pointerup-manual.html | 29 +++ ..._isprimary_same_as_pointerdown-manual.html | 29 +++ ...terevent_pointerup_pointertype-manual.html | 29 +++ ...ture_events_to_original_target-manual.html | 30 ++++ ...intercapture_invalid_pointerid-manual.html | 29 +++ ...rcapture_onpointercancel_touch-manual.html | 29 +++ ...intercapture_onpointerup_mouse-manual.html | 29 +++ ...setpointercapture_disconnected-manual.html | 28 +++ ...rcapture_inactive_button_mouse-manual.html | 30 ++++ ...intercapture_invalid_pointerid-manual.html | 28 +++ ...etpointercapture_relatedtarget-manual.html | 31 ++++ ...nt_touch-action-auto-css_touch-manual.html | 28 +++ ...touch-action-button-test_touch-manual.html | 28 +++ ...est_pointerevent_touch-action-illegal.html | 28 +++ ...it_child-auto-child-none_touch-manual.html | 28 +++ ...ction-inherit_child-none_touch-manual.html | 28 +++ ..._child-pan-x-child-pan-x_touch-manual.html | 28 +++ ..._child-pan-x-child-pan-y_touch-manual.html | 28 +++ ...erit_highest-parent-none_touch-manual.html | 28 +++ ...tion-inherit_parent-none_touch-manual.html | 28 +++ ...terevent_touch-action-keyboard-manual.html | 28 +++ ...ointerevent_touch-action-mouse-manual.html | 31 ++++ ...nt_touch-action-none-css_touch-manual.html | 28 +++ ...t_touch-action-pan-x-css_touch-manual.html | 28 +++ ...action-pan-x-pan-y-pan-y_touch-manual.html | 28 +++ ...touch-action-pan-x-pan-y_touch-manual.html | 28 +++ ...t_touch-action-pan-y-css_touch-manual.html | 28 +++ ...t_touch-action-span-test_touch-manual.html | 28 +++ ...nt_touch-action-svg-test_touch-manual.html | 28 +++ ..._touch-action-table-test_touch-manual.html | 28 +++ ...ointerevent_touch-action-verification.html | 28 +++ 134 files changed, 2397 insertions(+), 69 deletions(-) create mode 100644 dom/events/test/pointerevents/mochitest.ini create mode 100644 dom/events/test/pointerevents/mochitest_support_external.js create mode 100644 dom/events/test/pointerevents/mochitest_support_internal.js create mode 100644 dom/events/test/pointerevents/test_empty_file.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_button_attribute_mouse-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_capture_mouse-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_change-touch-action-onpointerdown_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_constructor.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_gotpointercapture_before_first_pointerevent-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_lostpointercapture_for_disconnected_node-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_lostpointercapture_is_first-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerdown-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerenter-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerenter_does_not_bubble-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerenter_nohover-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerleave_after_pointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerleave_after_pointerup_nohover-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerleave_descendant_over-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerleave_descendants-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerleave_does_not_bubble-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerleave_mouse-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerleave_pen-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerleave_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointermove-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointermove_isprimary_same_as_pointerdown-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointermove_pointertype-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerout-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerout_after_pointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerout_after_pointerup_nohover-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerout_pen-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerout_received_once-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerover-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointertype_mouse-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointertype_pen-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointertype_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerup-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_pointerup_pointertype-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_releasepointercapture_events_to_original_target-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_releasepointercapture_invalid_pointerid-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_releasepointercapture_onpointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_releasepointercapture_onpointerup_mouse-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_setpointercapture_disconnected-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_setpointercapture_inactive_button_mouse-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_setpointercapture_invalid_pointerid-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_setpointercapture_relatedtarget-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-auto-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-button-test_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-illegal.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-inherit_child-none_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-inherit_parent-none_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-keyboard-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-mouse-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-none-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-pan-x-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-pan-x-pan-y_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-pan-y-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-span-test_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-svg-test_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-table-test_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_pointerevent_touch-action-verification.html diff --git a/dom/events/moz.build b/dom/events/moz.build index d7d5decdf7d..566584a9ad7 100644 --- a/dom/events/moz.build +++ b/dom/events/moz.build @@ -4,7 +4,11 @@ # 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/. -MOCHITEST_MANIFESTS += ['test/mochitest.ini'] +MOCHITEST_MANIFESTS += [ + 'test/mochitest.ini', + 'test/pointerevents/mochitest.ini', +] + MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini'] XPIDL_SOURCES += [ diff --git a/dom/events/test/pointerevents/mochitest.ini b/dom/events/test/pointerevents/mochitest.ini new file mode 100644 index 00000000000..91ff591a2a5 --- /dev/null +++ b/dom/events/test/pointerevents/mochitest.ini @@ -0,0 +1,165 @@ +[DEFAULT] +skip-if = (toolkit == 'gonk') || (os == 'android') # Bug 1178701 - Issue on 'B2G ICS Emulator' and 'Android' +support-files = + mochitest_support_external.js + mochitest_support_internal.js + pointerevent_styles.css + pointerevent_support.js + +[test_pointerevent_button_attribute_mouse-manual.html] + support-files = pointerevent_button_attribute_mouse-manual.html +[test_pointerevent_capture_mouse-manual.html] + support-files = pointerevent_capture_mouse-manual.html +[test_pointerevent_capture_suppressing_mouse-manual.html] + support-files = pointerevent_capture_suppressing_mouse-manual.html +[test_pointerevent_change-touch-action-onpointerdown_touch-manual.html] + support-files = pointerevent_change-touch-action-onpointerdown_touch-manual.html + disabled = disabled +[test_pointerevent_constructor.html] + support-files = pointerevent_constructor.html +[test_pointerevent_gotpointercapture_before_first_pointerevent-manual.html] + support-files = pointerevent_gotpointercapture_before_first_pointerevent-manual.html + disabled = should be investigated +[test_pointerevent_lostpointercapture_for_disconnected_node-manual.html] + support-files = pointerevent_lostpointercapture_for_disconnected_node-manual.html +[test_pointerevent_lostpointercapture_is_first-manual.html] + support-files = pointerevent_lostpointercapture_is_first-manual.html +[test_pointerevent_pointercancel_touch-manual.html] + support-files = pointerevent_pointercancel_touch-manual.html +[test_pointerevent_pointerdown-manual.html] + support-files = pointerevent_pointerdown-manual.html + disabled = should be investigated +[test_pointerevent_pointerenter_does_not_bubble-manual.html] + support-files = pointerevent_pointerenter_does_not_bubble-manual.html +[test_pointerevent_pointerenter_nohover-manual.html] + support-files = pointerevent_pointerenter_nohover-manual.html +[test_pointerevent_pointerenter-manual.html] + support-files = pointerevent_pointerenter-manual.html +[test_pointerevent_pointerleave_after_pointercancel_touch-manual.html] + support-files = pointerevent_pointerleave_after_pointercancel_touch-manual.html +[test_pointerevent_pointerleave_after_pointerup_nohover-manual.html] + support-files = pointerevent_pointerleave_after_pointerup_nohover-manual.html +[test_pointerevent_pointerleave_descendant_over-manual.html] + support-files = pointerevent_pointerleave_descendant_over-manual.html + skip-if = (os == 'linux') # Bug 1180188 - Issue on Linux +[test_pointerevent_pointerleave_descendants-manual.html] + support-files = pointerevent_pointerleave_descendants-manual.html +[test_pointerevent_pointerleave_does_not_bubble-manual.html] + support-files = pointerevent_pointerleave_does_not_bubble-manual.html +[test_pointerevent_pointerleave_mouse-manual.html] + support-files = pointerevent_pointerleave_mouse-manual.html +[test_pointerevent_pointerleave_pen-manual.html] + support-files = pointerevent_pointerleave_pen-manual.html + disabled = should be investigated +[test_pointerevent_pointerleave_touch-manual.html] + support-files = pointerevent_pointerleave_touch-manual.html + skip-if = (os == 'linux') # Bug 1180188 - Issue on Linux +[test_pointerevent_pointermove-manual.html] + support-files = pointerevent_pointermove-manual.html +[test_pointerevent_pointermove_isprimary_same_as_pointerdown-manual.html] + support-files = pointerevent_pointermove_isprimary_same_as_pointerdown-manual.html +[test_pointerevent_pointermove_pointertype-manual.html] + support-files = pointerevent_pointermove_pointertype-manual.html +[test_pointerevent_pointerout-manual.html] + support-files = pointerevent_pointerout-manual.html +[test_pointerevent_pointerout_after_pointercancel_touch-manual.html] + support-files = pointerevent_pointerout_after_pointercancel_touch-manual.html +[test_pointerevent_pointerout_after_pointerup_nohover-manual.html] + support-files = pointerevent_pointerout_after_pointerup_nohover-manual.html +[test_pointerevent_pointerout_pen-manual.html] + support-files = pointerevent_pointerout_pen-manual.html + disabled = should be investigated +[test_pointerevent_pointerout_received_once-manual.html] + support-files = pointerevent_pointerout_received_once-manual.html +[test_pointerevent_pointerover-manual.html] + support-files = pointerevent_pointerover-manual.html +[test_pointerevent_pointertype_mouse-manual.html] + support-files = pointerevent_pointertype_mouse-manual.html +[test_pointerevent_pointertype_pen-manual.html] + support-files = pointerevent_pointertype_pen-manual.html +[test_pointerevent_pointertype_touch-manual.html] + support-files = pointerevent_pointertype_touch-manual.html +[test_pointerevent_pointerup-manual.html] + support-files = pointerevent_pointerup-manual.html +[test_pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html] + support-files = pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html +[test_pointerevent_pointerup_pointertype-manual.html] + support-files = pointerevent_pointerup_pointertype-manual.html +[test_pointerevent_releasepointercapture_events_to_original_target-manual.html] + support-files = pointerevent_releasepointercapture_events_to_original_target-manual.html +[test_pointerevent_releasepointercapture_invalid_pointerid-manual.html] + support-files = pointerevent_releasepointercapture_invalid_pointerid-manual.html +[test_pointerevent_releasepointercapture_onpointercancel_touch-manual.html] + support-files = pointerevent_releasepointercapture_onpointercancel_touch-manual.html +[test_pointerevent_releasepointercapture_onpointerup_mouse-manual.html] + support-files = pointerevent_releasepointercapture_onpointerup_mouse-manual.html +[test_pointerevent_setpointercapture_disconnected-manual.html] + support-files = pointerevent_setpointercapture_disconnected-manual.html +[test_pointerevent_setpointercapture_inactive_button_mouse-manual.html] + support-files = pointerevent_setpointercapture_inactive_button_mouse-manual.html + skip-if = debug && (os == 'linux') && e10s # Bug 1180188 - Issue on Linux +[test_pointerevent_setpointercapture_invalid_pointerid-manual.html] + support-files = pointerevent_setpointercapture_invalid_pointerid-manual.html +[test_pointerevent_setpointercapture_relatedtarget-manual.html] + support-files = pointerevent_setpointercapture_relatedtarget-manual.html +[test_pointerevent_touch-action-auto-css_touch-manual.html] + support-files = pointerevent_touch-action-auto-css_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-button-test_touch-manual.html] + support-files = pointerevent_touch-action-button-test_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-illegal.html] + support-files = pointerevent_touch-action-illegal.html + disabled = disabled +[test_pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html] + support-files = pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-inherit_child-none_touch-manual.html] + support-files = pointerevent_touch-action-inherit_child-none_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html] + support-files = pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html] + support-files = pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html] + support-files = pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-inherit_parent-none_touch-manual.html] + support-files = pointerevent_touch-action-inherit_parent-none_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-keyboard-manual.html] + support-files = pointerevent_touch-action-keyboard-manual.html + disabled = disabled +[test_pointerevent_touch-action-mouse-manual.html] + support-files = pointerevent_touch-action-mouse-manual.html + disabled = disabled +[test_pointerevent_touch-action-none-css_touch-manual.html] + support-files = pointerevent_touch-action-none-css_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-pan-x-css_touch-manual.html] + support-files = pointerevent_touch-action-pan-x-css_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html] + support-files = pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-pan-x-pan-y_touch-manual.html] + support-files = pointerevent_touch-action-pan-x-pan-y_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-pan-y-css_touch-manual.html] + support-files = pointerevent_touch-action-pan-y-css_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-span-test_touch-manual.html] + support-files = pointerevent_touch-action-span-test_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-svg-test_touch-manual.html] + support-files = pointerevent_touch-action-svg-test_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-table-test_touch-manual.html] + support-files = pointerevent_touch-action-table-test_touch-manual.html + disabled = disabled +[test_pointerevent_touch-action-verification.html] + support-files = pointerevent_touch-action-verification.html +[test_empty_file.html] + disabled = disabled # Bug 1150091 - Issue with support-files diff --git a/dom/events/test/pointerevents/mochitest_support_external.js b/dom/events/test/pointerevents/mochitest_support_external.js new file mode 100644 index 00000000000..eb77af3e9c1 --- /dev/null +++ b/dom/events/test/pointerevents/mochitest_support_external.js @@ -0,0 +1,93 @@ +// This file supports translating W3C tests +// to tests on auto MochiTest system with minimum changes. +// Author: Maksim Lebedev + +// Function allows to prepare our tests after load document +addEventListener("load", function(event) { + console.log("OnLoad external document"); + prepareTest(); +}, false); + +// Function allows to initialize prerequisites before testing +function prepareTest() { + SimpleTest.waitForExplicitFinish(); + SimpleTest.requestCompleteLog(); + turnOnPointerEvents(startTest); +} + +function turnOnPointerEvents(callback) { + console.log("SET dom.w3c_pointer_events.enabled as TRUE"); + console.log("SET layout.css.touch_action.enabled as TRUE"); + SpecialPowers.pushPrefEnv({ + "set": [ + ["dom.w3c_pointer_events.enabled", true], + ["layout.css.touch_action.enabled", true] + ] + }, callback); +} + +// Function checks that test should have status PASS +function result_function(testObj) { +if(testObj["status"] != testObj["PASS"]) + console.log(testObj["status"] + " = " + testObj["PASS"] + ". " + testObj["name"]); + is(testObj["status"], testObj["PASS"], testObj["name"]); +} + +// Function allows to correct finish test in mochitest system +function completion_function() { + console.log("w3c tests have been finished"); + if(!SimpleTest._stopOnLoad) { + console.log("Finishing Mochitest system"); + SimpleTest.finish(); + } +} + +// Helper function to send PointerEvent with different parameters +function sendPointerEvent(int_win, elemId, pointerEventType, inputSource, params) { + var elem = int_win.document.getElementById(elemId); + if(!!elem) { + var rect = elem.getBoundingClientRect(); + var eventObj = {type: pointerEventType, inputSource: inputSource}; + if(params && "button" in params) + eventObj.button = params.button; + if(params && "isPrimary" in params) + eventObj.isPrimary = params.isPrimary; + else if(MouseEvent.MOZ_SOURCE_MOUSE == inputSource) + eventObj.isPrimary = true; + console.log(elemId, eventObj); + var salt = ("pointermove" == pointerEventType) ? 1 : 2; + synthesizePointer(elem, rect.width*salt/5, rect.height/2, eventObj, int_win); + } else { + is(!!elem, true, "Document should have element with id: " + elemId); + } +} + +// Helper function to send MouseEvent with different parameters +function sendMouseEvent(int_win, elemId, mouseEventType, params) { + var elem = int_win.document.getElementById(elemId); + if(!!elem) { + var rect = elem.getBoundingClientRect(); + var eventObj = {type: mouseEventType}; + if(params && "button" in params) + eventObj.button = params.button; + if(params && "inputSource" in params) + eventObj.inputSource = params.inputSource; + console.log(elemId, eventObj); + synthesizeMouse(elem, rect.width/4, rect.height/2, eventObj, int_win); + } else { + is(!!elem, true, "Document should have element with id: " + elemId); + } +} + +// Helper function to send TouchEvent with different parameters +function sendTouchEvent(int_win, elemId, touchEventType, params) { + var elem = int_win.document.getElementById(elemId); + if(!!elem) { + var rect = elem.getBoundingClientRect(); + var eventObj = {type: touchEventType}; + console.log(elemId, eventObj); + synthesizeTouch(elem, rect.width/4, rect.height/2, eventObj, int_win); + } else { + is(!!elem, true, "Document should have element with id: " + elemId); + } +} diff --git a/dom/events/test/pointerevents/mochitest_support_internal.js b/dom/events/test/pointerevents/mochitest_support_internal.js new file mode 100644 index 00000000000..7a20045846e --- /dev/null +++ b/dom/events/test/pointerevents/mochitest_support_internal.js @@ -0,0 +1,40 @@ +// This file supports translating W3C tests +// to tests on auto MochiTest system with minimum changes. +// Author: Maksim Lebedev + +// Function allows to prepare our tests after load document +addEventListener("load", function(event) { + console.log("OnLoad internal document"); + addListeners(document.getElementById("target0")); + addListeners(document.getElementById("target1")); + preExecute(); +}, false); + +// Function allows to initialize prerequisites before testing +// and adds some callbacks to support mochitest system. +function preExecute() { + add_result_callback(parent.result_function); + add_completion_callback(parent.completion_function); + parent.turnOnPointerEvents(window.callExecute); +} + +// The main function allows to execute tests in auto mode +function callExecute() { + console.log("Run 'executeTest' function"); + if(!!parent.executeTest) + parent.executeTest(window); + else + parent.is(!!parent.executeTest, true, "parent-document should have function 'executeTest'"); +} + +function addListeners(elem) { + if(!elem) + return; + var All_Events = ["pointerdown","pointerup","pointercancel","pointermove","pointerover","pointerout", + "pointerenter","pointerleave","gotpointercapture","lostpointercapture"]; + All_Events.forEach(function(name) { + elem.addEventListener(name, function(event) { + console.log('('+event.type+')-('+event.pointerType+')'); + }, false); + }); +} diff --git a/dom/events/test/pointerevents/pointerevent_button_attribute_mouse-manual.html b/dom/events/test/pointerevents/pointerevent_button_attribute_mouse-manual.html index a31e53d3285..f8ada9703bf 100644 --- a/dom/events/test/pointerevents/pointerevent_button_attribute_mouse-manual.html +++ b/dom/events/test/pointerevents/pointerevent_button_attribute_mouse-manual.html @@ -5,18 +5,22 @@ - + +

Button attribute test for mouse

+
+
- + + +

diff --git a/dom/events/test/pointerevents/pointerevent_capture_suppressing_mouse-manual.html b/dom/events/test/pointerevents/pointerevent_capture_suppressing_mouse-manual.html index 60e22d4b7d5..95d07795b90 100644 --- a/dom/events/test/pointerevents/pointerevent_capture_suppressing_mouse-manual.html +++ b/dom/events/test/pointerevents/pointerevent_capture_suppressing_mouse-manual.html @@ -5,11 +5,13 @@ - + + +

diff --git a/dom/events/test/pointerevents/pointerevent_change-touch-action-onpointerdown_touch-manual.html b/dom/events/test/pointerevents/pointerevent_change-touch-action-onpointerdown_touch-manual.html index 04d56cb7a51..b5f522f8bb1 100644 --- a/dom/events/test/pointerevents/pointerevent_change-touch-action-onpointerdown_touch-manual.html +++ b/dom/events/test/pointerevents/pointerevent_change-touch-action-onpointerdown_touch-manual.html @@ -5,8 +5,9 @@ - + + +
diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-illegal.html b/dom/events/test/pointerevents/pointerevent_touch-action-illegal.html index 5fe6179840e..dd94c1d1f37 100644 --- a/dom/events/test/pointerevents/pointerevent_touch-action-illegal.html +++ b/dom/events/test/pointerevents/pointerevent_touch-action-illegal.html @@ -5,8 +5,9 @@ - + + -
diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-illegal.html b/dom/events/test/pointerevents/pointerevent_touch-action-illegal.html index dd94c1d1f37..5fe6179840e 100644 --- a/dom/events/test/pointerevents/pointerevent_touch-action-illegal.html +++ b/dom/events/test/pointerevents/pointerevent_touch-action-illegal.html @@ -5,9 +5,8 @@ - + - - - -

Pointer Events touch-action attribute support

-

Test Description: Press and hold your touch. Try to scroll text in any direction. - Then release your touch and try to scroll again. Expected: no panning. -

-

Note: this test is for touch-devices only

-
-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
- -

touch-action: auto to none

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_constructor.html b/dom/events/test/pointerevents/pointerevent_constructor.html deleted file mode 100644 index 36e0394c358..00000000000 --- a/dom/events/test/pointerevents/pointerevent_constructor.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - PointerEvent: Constructor test - - - - - - - - -

PointerEvent: Dispatch custom event

-

Test Description: This test checks if PointerEvent constructor works properly using synthetic pointerover and pointerout events. For valid results, this test must be run without generating real (trusted) pointerover or pointerout events on the black rectangle below.

-
- -
-

The following pointer types were detected: .

-
-
- - diff --git a/dom/events/test/pointerevents/pointerevent_gotpointercapture_before_first_pointerevent-manual.html b/dom/events/test/pointerevents/pointerevent_gotpointercapture_before_first_pointerevent-manual.html deleted file mode 100644 index 754a58facfd..00000000000 --- a/dom/events/test/pointerevents/pointerevent_gotpointercapture_before_first_pointerevent-manual.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - Pointer Event: gotpiontercapture is fired first and asynchronously. - - - - - - - - - - - - -

Pointer Event: Dispatch gotpointercapture event

-

Test Description: - After pointer capture is set for a pointer, and prior to dispatching the first event for the pointer, the gotpointercapture - event must be dispatched to the element that is receiving the pointer capture. The gotpointercapture event must be dispatched asynchronously. -

-
-
- Use the mouse, touch or pen to tap/click this box. -
-
Do not hover over or touch this element.
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html b/dom/events/test/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html deleted file mode 100644 index 4d152b73a6a..00000000000 --- a/dom/events/test/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - Lostpointercapture fires on document when target is removed - - - - - - - -

Pointer Events - lostpointercapture when capturing element is removed

-

- Test Description: - This test checks if lostpointercapture is fired at the document when the capturing node is removed from the document. - Complete the following actions: -
    -
  1. Press and hold left mouse button over "Set Capture" button. "gotpointercapture" should be logged inside of the black rectangle. -
  2. "lostpointercapture" should be logged inside of the black rectangle after a short delay. -
-

-
-
-
- - -

Pointer Events Capture Test

-
-

The following pointer types were detected: .

-
-
- - diff --git a/dom/events/test/pointerevents/pointerevent_lostpointercapture_is_first-manual.html b/dom/events/test/pointerevents/pointerevent_lostpointercapture_is_first-manual.html deleted file mode 100644 index 566676d2aef..00000000000 --- a/dom/events/test/pointerevents/pointerevent_lostpointercapture_is_first-manual.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - Lostpointercapture triggers first and asynchronously - - - - - - - - -

Pointer Events capture test - lostpointercapture order

-

- Test Description: - This test checks if lostpointercapture is handled asynchronously and prior to all subsequent events. - Complete the following actions: -
    -
  1. Press and hold left mouse button over "Set Capture" button. "gotpointercapture" should be logged inside of the black rectangle -
  2. "lostpointercapture" should be logged inside of the black rectangle after a short delay -
-

- Test passes if lostpointercapture is dispatched after releasing the mouse button and before any additional pointer events. -
-
- - -

Pointer Events Capture Test

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointercancel_touch-manual.html b/dom/events/test/pointerevents/pointerevent_pointercancel_touch-manual.html deleted file mode 100644 index 70a65eeb5ca..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointercancel_touch-manual.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - PointerCancel - touch - - - - - - - - -

pointercancel test

-

Warning: this test works properly only for devices that have touchscreen

-

- Test Description: This test checks if pointercancel event triggers. -

Start touch over the black rectangle and then move your finger to scroll the page.

-

-

-

- -

Pointer Events pointercancel Tests

-
-

The following pointer types were detected: .

-
-
- - diff --git a/dom/events/test/pointerevents/pointerevent_pointerdown-manual.html b/dom/events/test/pointerevents/pointerevent_pointerdown-manual.html deleted file mode 100644 index 0167e08ba5a..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerdown-manual.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - Pointer Events pointerdown tests - - - - - - - - - -

Pointer Events pointerdown tests

-
- Start with your pointing device outside of this box, then click here. -
-
-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerenter-manual.html b/dom/events/test/pointerevents/pointerevent_pointerenter-manual.html deleted file mode 100644 index 613eb8e4064..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerenter-manual.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - Pointer Event: Dispatch pointerenter. - - - - - - - - - - - - -

Pointer Event: Dispatch pointerenter

-

- Test Description: - When a pointing device is moved into the hit test boundaries of an element or one of its descendants, the pointerenter event must be dispatched. -

-
- Use the mouse or pen to move over this box. -
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerenter_does_not_bubble-manual.html b/dom/events/test/pointerevents/pointerevent_pointerenter_does_not_bubble-manual.html deleted file mode 100644 index 3f0583364a2..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerenter_does_not_bubble-manual.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - Pointer Event: The pointerenter event does not bubble - - - - - - - - - - - - - -

Pointer Event: pointerenter does not bubble

-

- Test Description: - The pointerenter event must not bubble up to parent elements. -

-
- Use the mouse or pen to hover over then out of the purple box nested in the black box. Or with touch, tap on the purple box. -
-
-
-
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerenter_nohover-manual.html b/dom/events/test/pointerevents/pointerevent_pointerenter_nohover-manual.html deleted file mode 100644 index 32675bbb441..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerenter_nohover-manual.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - Pointer Event: Dispatch pointerenter. (nohover) - - - - - - - - - - - - -

Pointer Event: Dispatch pointerenter (nohover)

-

- Test Description: - When a pointing device that does not support hover is moved into the hit test boundaries of an element or one of its - descendants as a result of a pointerdown event, the pointerenter event must be dispatched. -

-
-
- Tap here. -
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-
-
- - diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual.html deleted file mode 100644 index 56be26549f8..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - pointerleave after pointercancel - - - - - - - - -

pointerleave after pointercancel

-

Test Description: This test checks if pointerleave event triggers after pointercancel. Start touch on the black rectangle and move your touch to scroll in any direction.

-

Note: this test is for touch devices only

-
- -

Pointer Events pointerleave tests

-
-

The following pointer types were detected: .

-
-
- - diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_after_pointerup_nohover-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_after_pointerup_nohover-manual.html deleted file mode 100644 index 30412378428..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerleave_after_pointerup_nohover-manual.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - pointerleave after pointerup - - - - - - - - -

pointerleave after pointerup

-

Test Description: This test checks if pointerleave event triggers for devices that don't support hover. Tap the black rectangle.

-

Note: this test is only for devices that do not support hover.

-
- -

Pointer Events pointerleave tests

-
-

The following pointer types were detected: .

-
-
- - diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_descendant_over-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_descendant_over-manual.html deleted file mode 100644 index 8f4f4bfc7a1..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerleave_descendant_over-manual.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - pointerleave + descendant - - - - - - - -

pointerleave

-

- Test Description: This test checks if pointerleave event works properly. -
    -
  1. Put your mouse over the black rectangle -
  2. Then move it into the purple rectangle -
  3. Click on the purple rectangle to complete the test -
- Note: when you entered the black rectangle once don't leave it before the end of the test to get proper results. -

-

-

-
-
- -

Pointer Events pointerleave tests

-
-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_descendants-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_descendants-manual.html deleted file mode 100644 index ac9edcff38a..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerleave_descendants-manual.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - Pointerleave + descendant - - - - - - - -

pointerleave

-

- Test Description: This test checks if pointerleave event works properly. -

Put your mouse over the black rectangle and then move it out through purple rectangle boundaries.

-

-

-

-
-
- -

Pointer Events pointerleave tests

-
-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_does_not_bubble-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_does_not_bubble-manual.html deleted file mode 100644 index c0e551cd658..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerleave_does_not_bubble-manual.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - Pointer Event: The pointerleave event does not bubble - - - - - - - - - - - - - -

Pointer Event: pointerleave does not bubble

-

- Test Description: - The pointerleave event must not bubble up to parent elements. -

-
- Use the mouse or pen to hover over then out of the purple box nested in the black box. Or with touch, tap on the purple box. -
-
-
-
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_mouse-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_mouse-manual.html deleted file mode 100644 index 708aed91af4..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerleave_mouse-manual.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - Pointer Event: Dispatch pointerleave (mouse). - - - - - - - - - - - - -

Pointer Event: Dispatch pointerleave (mouse)

-

- Test Description: - When a pointing device that has continuous position (such as a mouse) leaves the hit test boundaries of an element, the pointerleave event must be dispatched. -

-
-
- Use a mouse to move over then out of this element -
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_pen-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_pen-manual.html deleted file mode 100644 index 38a2f697920..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerleave_pen-manual.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - Pointer Event: Dispatch pointerleave (pen). - - - - - - - - - - - - -

Pointer Event: Dispatch pointerleave (pen)

-

- Test Description: - When a pointing device that supports hover (pen stylus) leaves the range of the digitizer while over an element, the pointerleave event must be dispatched. -

-
-
- Use a pen to hover over then lift up away from this element. -
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerleave_touch-manual.html b/dom/events/test/pointerevents/pointerevent_pointerleave_touch-manual.html deleted file mode 100644 index 3044327a5ff..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerleave_touch-manual.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - Pointer Event: Dispatch pointerleave (touch). - - - - - - - - - - - - -

Pointer Event: Dispatch pointerleave (touch)

-

- Test Description: - When a pointing device that does not support hover (such as a finger) leaves the hit test boundaries as a result of a pointerup event, the pointerleave event must be dispatched. -

-
-
- Use touch to tap on this box. -
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointermove-manual.html b/dom/events/test/pointerevents/pointerevent_pointermove-manual.html deleted file mode 100644 index cf1a1ee4ee8..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointermove-manual.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - Pointermove - - - - - - - - - -

PointerMove

-

Test Description: This test checks if pointermove event triggers. Move your mouse over the black rectangle or slide it if you are using touchscreen.

-
- -

Pointer Events pointermove Tests

-
-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointermove_isprimary_same_as_pointerdown-manual.html b/dom/events/test/pointerevents/pointerevent_pointermove_isprimary_same_as_pointerdown-manual.html deleted file mode 100644 index b43d59f4f6e..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointermove_isprimary_same_as_pointerdown-manual.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - Pointer Event: pointermove has same isPrimary as last pointerdown with the same pointerId - - - - - - - - - - - - -

Pointer Event: pointermove has the same isPrimary as last pointerdown with the same pointerId

-

Test Description: - The isPrimary attribute of a pointermove event must have the same value as the isPrimary attribute of the last pointerdown event with the same pointerId attribute. -

-
- Press and hold a mouse button, touch contact or pen contact on this element. Move around inside the element while maintaining contact/button down. Only use one device per test run. -

Lift off of the element to complete the test.

-
-
-
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointermove_pointertype-manual.html b/dom/events/test/pointerevents/pointerevent_pointermove_pointertype-manual.html deleted file mode 100644 index 4c410159c13..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointermove_pointertype-manual.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - pointerType conservation - - - - - - - -

pointerType conservation

-

Test Description: This test checks if pointerType attribute defined properly.

-
- Press and move a mouse button, touch contact or pen contact on the black rectangle. Only use one device per test run. -
-

Note: This test may be run with different pointer devices, however only one device should be used per test run. -

-

- -

Pointer Events pointerType conservation tests

-
-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerout-manual.html b/dom/events/test/pointerevents/pointerevent_pointerout-manual.html deleted file mode 100644 index 473fa14ebbc..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerout-manual.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - pointerout - - - - - - - - -

pointerout

-

Test Description: This test checks if pointerout event triggers. Put your mouse over the black rectangle and then move it out of the rectangle boundaries. If you are using touchscreen tap the black rectangle.

-
- -

Pointer Events pointerout tests

-
-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerout_after_pointercancel_touch-manual.html b/dom/events/test/pointerevents/pointerevent_pointerout_after_pointercancel_touch-manual.html deleted file mode 100644 index 1888591a7c2..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerout_after_pointercancel_touch-manual.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - pointerout - - - - - - - - -

pointerout

-

Test Description: This test checks if pointerout event triggers after pointercancel. Start touch on the black rectangle and move your touch to scroll in any direction.

-

Note: this test is for touch devices only

-
- -

Pointer Events pointerout tests

-
-

The following pointer types were detected: .

-
-
- - diff --git a/dom/events/test/pointerevents/pointerevent_pointerout_after_pointerup_nohover-manual.html b/dom/events/test/pointerevents/pointerevent_pointerout_after_pointerup_nohover-manual.html deleted file mode 100644 index 44813033a72..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerout_after_pointerup_nohover-manual.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - pointerout - - - - - - - - -

pointerout

-

Test Description: This test checks if pointerout event triggers for devices that don't support hover. Tap the black rectangle.

-

Note: this test is only for devices that do not support hover.

-
- -

Pointer Events pointerout tests

-
-

The following pointer types were detected: .

-
-
- - diff --git a/dom/events/test/pointerevents/pointerevent_pointerout_pen-manual.html b/dom/events/test/pointerevents/pointerevent_pointerout_pen-manual.html deleted file mode 100644 index 3973948c164..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerout_pen-manual.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - pointerout - - - - - - - - -

pointerout

-

Test Description: This test checks if pointerout event triggers for pen. Place your pen over the black rectangle and then pull the pen out of the digitizer's detectable range.

-

Note: this test is for devices that support hover - for pen only

-
- -

Pointer Events pointerout tests

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerout_received_once-manual.html b/dom/events/test/pointerevents/pointerevent_pointerout_received_once-manual.html deleted file mode 100644 index 4827ae91de1..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerout_received_once-manual.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - pointerout received just once - - - - - - - -

pointerout received just once

-

- Test Description: This test checks if pointerout event dispatched properly. -
    -
  1. Put your mouse over the black rectangle. -
  2. Move your mouse out of the black rectangle -
-

-

-

- -

Pointer Events pointerout received once test

-
-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerover-manual.html b/dom/events/test/pointerevents/pointerevent_pointerover-manual.html deleted file mode 100644 index 4601c08aaaf..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerover-manual.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - Pointer Event: Dispatch pointerover. - - - - - - - - - - - - -

Pointer Event: Dispatch pointerover.

-

Test Description: - When a pointing device is moved into the hit test boundaries of an element, the pointerover event must be dispatched. -

-
-
- Use mouse, touch or pen to hover or contact this element.. -
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointertype_mouse-manual.html b/dom/events/test/pointerevents/pointerevent_pointertype_mouse-manual.html deleted file mode 100644 index b1e7d7046ea..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointertype_mouse-manual.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - Pointer Event: If a pointer event is initiated by a mouse device, then the pointerType must be "mouse" - - - - - - - - - - - - -

Pointer Event: Dispatch pointer events with pointerType equal to "mouse"

-

Test Description: - If a pointer event is initiated by a mouse device, then the pointerType must be 'mouse'. -

-
-
- Using the mouse, click this element. -
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointertype_pen-manual.html b/dom/events/test/pointerevents/pointerevent_pointertype_pen-manual.html deleted file mode 100644 index 0aabfce4fc9..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointertype_pen-manual.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - Pointer Event: If a pointer event is initiated by a pen device, then the pointerType must be "pen" - - - - - - - - - - - - -

Pointer Event: Dispatch pointer events with pointerType equal to "pen"

-

Test Description: - If a pointer event is initiated by a pen device, then the pointerType must be 'pen'. -

-
-
- Using pen, tap here. -
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointertype_touch-manual.html b/dom/events/test/pointerevents/pointerevent_pointertype_touch-manual.html deleted file mode 100644 index c06fbe48c6d..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointertype_touch-manual.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - Pointer Event: If a pointer event is initiated by a touch device, then the pointerType must be "touch" - - - - - - - - - - - - -

Pointer Event: Dispatch pointer events with pointerType equal to "touch"

-

Test Description: - If a pointer event is initiated by a touch device, then the pointerType must be 'touch'. -

-
-
- Using touch, tap here. -
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerup-manual.html b/dom/events/test/pointerevents/pointerevent_pointerup-manual.html deleted file mode 100644 index 30a03f23dcf..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerup-manual.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - pointerup - - - - - - - - -

pointerup

-

Test Description: This test checks if pointerup event triggers. Press mouse left button and release it over the black rectangle or tap it if you are using a touchscreen.

-
- -

Pointer Events pointerup tests

-
-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html b/dom/events/test/pointerevents/pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html deleted file mode 100644 index 994061b8bf0..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - Pointer Event: pointerup has same isPrimary as last pointerdown with the same pointerId - - - - - - - - - - - - -

Pointer Event: pointerup has the same isPrimary as last pointerdown with the same pointerId

-

Test Description: - The isPrimary attribute of a pointerup event must have the same value as the isPrimary attribute of the last pointerdown event with the same pointerId attribute. -

-
- Press and release a mouse button, touch contact or pen contact on this element. Only use one device per test run. -
-
-
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_pointerup_pointertype-manual.html b/dom/events/test/pointerevents/pointerevent_pointerup_pointertype-manual.html deleted file mode 100644 index b356484bacc..00000000000 --- a/dom/events/test/pointerevents/pointerevent_pointerup_pointertype-manual.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - pointerType conservation - - - - - - - -

pointerType conservation

-

Test Description: This test checks if pointerType attribute defined properly.

-
- Press and release a mouse button, touch contact or pen contact on the black rectangle. Only use one device per test run. -
-

Note: This test may be run with different pointer devices, however only one device should be used per test run. -

-

- -

Pointer Events pointerType conservation tests

-
-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html b/dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html deleted file mode 100644 index f3991d98d74..00000000000 --- a/dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - Pointer Event: releasePointerCapture() - subsequent events follow normal hitting testing mechanisms - - - - - - - - - - - -
-

Pointer Event: releasePointerCapture() - subsequent events follow normal hitting testing mechanisms

-

- Test Description: - After invoking the releasePointerCapture method on an element, subsequent events for the specified - pointer must follow normal hit testing mechanisms for determining the event target -

-
-
- Use mouse, touch or pen to contact here and move around. -
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_releasepointercapture_invalid_pointerid-manual.html b/dom/events/test/pointerevents/pointerevent_releasepointercapture_invalid_pointerid-manual.html deleted file mode 100644 index fe2ab006181..00000000000 --- a/dom/events/test/pointerevents/pointerevent_releasepointercapture_invalid_pointerid-manual.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - Pointer Event: releasePointerCapture DOMException - InvalidPointerId - - - - - - - - - - - - - - -
-

Pointer Event: releasePointerCapture() DOMException - InvalidPointerId

-

- Test Description: - Upon invocation of the releasePointerCapture method, if the provided pointerId value does not match any of the - active pointers, a DOMException with the name InvalidPointerId must be thrown. -

-
-
- Use the mouse, touch or pen to move over or contact this box. -
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch-manual.html b/dom/events/test/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch-manual.html deleted file mode 100644 index 105e3b5a974..00000000000 --- a/dom/events/test/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch-manual.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - Release capture on pointercancel - - - - - - - -

Pointer Events Capture Test - release capture on pointercancel

-

- Test Description: This test checks if setCapture/releaseCapture functions works properly. Complete the following actions: -
    -
  1. Touch black rectangle and do not release your touch -
  2. Move your touch to scroll the page. "lostpointercapture" should be logged inside of the black rectangle immediately after "pointercancel" -
-

- Test passes if the proper behavior of the events is observed. -
- - -

Pointer Events Capture Test

-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-
-
- - diff --git a/dom/events/test/pointerevents/pointerevent_releasepointercapture_onpointerup_mouse-manual.html b/dom/events/test/pointerevents/pointerevent_releasepointercapture_onpointerup_mouse-manual.html deleted file mode 100644 index df515436c05..00000000000 --- a/dom/events/test/pointerevents/pointerevent_releasepointercapture_onpointerup_mouse-manual.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - Release capture on pointerup - - - - - - - -

Pointer Events Capture Test - release capture on pointerup

-

- Test Description: This test checks if setCapture/releaseCapture functions works properly. Complete the following actions: -
    -
  1. Press and hold left mouse button over "Set Capture" button -
  2. Release left mouse button anywhere over the document. "lostpointercapture" should be logged inside of the black rectangle immediately after "pointerup" -
-

- Test passes if the proper behavior of the events is observed. -
-
- - -

Pointer Events Capture Test

-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_setpointercapture_disconnected-manual.html b/dom/events/test/pointerevents/pointerevent_setpointercapture_disconnected-manual.html deleted file mode 100644 index 9e9646525fa..00000000000 --- a/dom/events/test/pointerevents/pointerevent_setpointercapture_disconnected-manual.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - setPointerCapture() throws on disconnected node - - - - - - - - -

Pointer Event: DOMException InvalidStateError

-

Test Description: - When the setPointerCapture method is invoked, if the target node does not participate in its ownerDocument's tree, a DOMException with the name InvalidStateError must be thrown. -

-
-
- Use the mouse, touch or pen to contact this box. -
-
-
-

The following pointer types were detected: .

-
-
- - diff --git a/dom/events/test/pointerevents/pointerevent_setpointercapture_inactive_button_mouse-manual.html b/dom/events/test/pointerevents/pointerevent_setpointercapture_inactive_button_mouse-manual.html deleted file mode 100644 index b3e8debb716..00000000000 --- a/dom/events/test/pointerevents/pointerevent_setpointercapture_inactive_button_mouse-manual.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - setPointerCapture + inactive button state - - - - - - - -

setPointerCapture

-

- Test Description: This test checks if setPointerCapture works properly. -
    -
  1. Put your mouse over the black rectangle -
  2. Move you mouse out to complete the test -
-

-

-

- -

Pointer Events setPointerCapture Tests

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_setpointercapture_invalid_pointerid-manual.html b/dom/events/test/pointerevents/pointerevent_setpointercapture_invalid_pointerid-manual.html deleted file mode 100644 index 4dbe858db16..00000000000 --- a/dom/events/test/pointerevents/pointerevent_setpointercapture_invalid_pointerid-manual.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - Pointer Event: gotPiontercapture is fired first. - - - - - - - - - - - - - -

Pointer Event: DOMException InvalidPointerId

-

Test Description: - When the setPointerCapture method is invoked, if the provided pointerId value does not match any of the active pointers, a DOMException with the name InvalidPointerId must be thrown. -

-
-
- Use the mouse, touch or pen to contact this box. -
-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_setpointercapture_relatedtarget-manual.html b/dom/events/test/pointerevents/pointerevent_setpointercapture_relatedtarget-manual.html deleted file mode 100644 index 45b67414b26..00000000000 --- a/dom/events/test/pointerevents/pointerevent_setpointercapture_relatedtarget-manual.html +++ /dev/null @@ -1,101 +0,0 @@ - - - - Set/Release capture + relatedTarget - - - - - - - -

Pointer Events Capture Test - capture and relatedTarget

-

- Test Description: This test checks if setCapture/releaseCapture functions works properly. Complete the following actions: -
    -
  1. Put your mouse over the lower rectangle. pointerover should be received for the purple rectangle -
  2. Press and hold left mouse button over "Set Capture" button -
  3. Put your mouse over the upper rectangle. pointerover should be received for the black rectangle -
  4. Release left mouse button to complete the test. -
-

- Test passes if the proper behavior of the events is observed. - -
-
-
-
- - -

Pointer Events Capture Test

-
-

Test complete: Scroll to Summary to view Pass/Fail Results.

-

The following pointer types were detected: .

-

Refresh the page to run the tests again with a different pointer type.

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_styles.css b/dom/events/test/pointerevents/pointerevent_styles.css deleted file mode 100644 index 55265af4141..00000000000 --- a/dom/events/test/pointerevents/pointerevent_styles.css +++ /dev/null @@ -1,61 +0,0 @@ -#target0 { -background: black; -color: white; -white-space: nowrap; -overflow-y: auto; -overflow-x: auto; -} - -#target1 { -background: purple; -color: white; -white-space: nowrap; -overflow-y: auto; -overflow-x: auto; -} - -.scroller { -width: 700px; -height: 430px; -margin: 20px; -overflow: auto; -background: black; -} - -.scroller > div { -height: 1000px; -width: 1000px; -color: white; -} - -.scroller > div div { -height: 100%; -width: 100%; -color: white; -} - -div { -margin: 0em; -padding: 2em; -} - -#complete-notice { -background: #afa; -border: 1px solid #0a0; -display: none; -} - -#pointertype-log { -font-weight: bold; -} - -#listener { -background: orange; -border: 1px solid orange; -position: absolute; -top: -100px; -} - -body.scrollable { -min-height: 5000px; -} diff --git a/dom/events/test/pointerevents/pointerevent_support.js b/dom/events/test/pointerevents/pointerevent_support.js deleted file mode 100644 index b3fb661f8b7..00000000000 --- a/dom/events/test/pointerevents/pointerevent_support.js +++ /dev/null @@ -1,170 +0,0 @@ -var All_Pointer_Events = [ - "pointerdown", - "pointerup", - "pointercancel", - "pointermove", - "pointerover", - "pointerout", - "pointerenter", - "pointerleave", - "gotpointercapture", - "lostpointercapture"]; - -// Check for conformance to PointerEvent interface -// TA: 1.1, 1.2, 1.6, 1.7, 1.8, 1.9, 1.10, 1.11, 1.12, 1.13 -function check_PointerEvent(event) { - test(function () { - assert_true(event instanceof PointerEvent, "event is a PointerEvent event"); - }, event.type + " event is a PointerEvent event"); - - - // Check attributes for conformance to WebIDL: - // * attribute exists - // * has proper type - // * if the attribute is "readonly", it cannot be changed - // TA: 1.1, 1.2 - var idl_type_check = { - "long": function (v) { return typeof v === "number" && Math.round(v) === v; }, - "float": function (v) { return typeof v === "number"; }, - "string": function (v) { return typeof v === "string"; }, - "boolean": function (v) { return typeof v === "boolean" } - }; - [ - ["readonly", "long", "pointerId"], - ["readonly", "float", "width"], - ["readonly", "float", "height"], - ["readonly", "float", "pressure"], - ["readonly", "long", "tiltX"], - ["readonly", "long", "tiltY"], - ["readonly", "string", "pointerType"], - ["readonly", "boolean", "isPrimary"] - ].forEach(function (attr) { - var readonly = attr[0]; - var type = attr[1]; - var name = attr[2]; - - - // existence check - test(function () { - assert_true(name in event, name + " attribute in " + event.type + " event"); - }, event.type + "." + name + " attribute exists"); - - - // readonly check - if (readonly === "readonly") { - test(function () { - assert_readonly(event.type, name, event.type + "." + name + " cannot be changed"); - }, event.type + "." + name + " is readonly"); - } - - - // type check - test(function () { - assert_true(idl_type_check[type](event[name]), name + " attribute of type " + type); - }, event.type + "." + name + " IDL type " + type + " (JS type was " + typeof event[name] + ")"); - }); - - - // Check the pressure value - // TA: 1.6, 1.7, 1.8 - test(function () { - // TA: 1.6 - assert_greater_than_equal(event.pressure, 0, "pressure is greater than or equal to 0"); - assert_less_than_equal(event.pressure, 1, "pressure is less than or equal to 1"); - - - // TA: 1.7, 1.8 - if (event.pointerType === "mouse") { - if (event.buttons === 0) { - assert_equals(event.pressure, 0, "pressure is 0 for mouse with no buttons pressed"); - } else { - assert_equals(event.pressure, 0.5, "pressure is 0.5 for mouse with a button pressed"); - } - } - }, event.type + ".pressure value is valid"); - - - // Check mouse-specific properties - if (event.pointerType === "mouse") { - // TA: 1.9, 1.10, 1.13 - test(function () { - assert_equals(event.tiltX, 0, event.type + ".tiltX is 0 for mouse"); - assert_equals(event.tiltY, 0, event.type + ".tiltY is 0 for mouse"); - assert_true(event.isPrimary, event.type + ".isPrimary is true for mouse"); - }, event.type + " properties for pointerType = mouse"); - // Check properties for pointers other than mouse - } -} - -function showPointerTypes() { - var complete_notice = document.getElementById("complete-notice"); - var pointertype_log = document.getElementById("pointertype-log"); - var pointertypes = Object.keys(detected_pointertypes); - pointertype_log.innerHTML = pointertypes.length ? - pointertypes.join(",") : "(none)"; - complete_notice.style.display = "block"; -} - -function log(msg, el) { - if (++count > 10){ - count = 0; - el.innerHTML = ' '; - } - el.innerHTML = msg + '; ' + el.innerHTML; -} - - function failOnScroll() { - assert_true(false, - "scroll received while shouldn't"); -} - -function updateDescriptionNextStep() { - document.getElementById('desc').innerHTML = "Test Description: Try to scroll text RIGHT."; -} - -function updateDescriptionComplete() { - document.getElementById('desc').innerHTML = "Test Description: Test complete"; -} - -function updateDescriptionSecondStepTouchActionElement(target, scrollReturnInterval) { - window.setTimeout(function() { - objectScroller(target, 'up', 0);} - , scrollReturnInterval); - document.getElementById('desc').innerHTML = "Test Description: Try to scroll element RIGHT moving your outside of the red border"; -} - -function updateDescriptionThirdStepTouchActionElement(target, scrollReturnInterval) { - window.setTimeout(function() { - objectScroller(target, 'left', 0);} - , scrollReturnInterval); - document.getElementById('desc').innerHTML = "Test Description: Try to scroll element DOWN then RIGHT starting your touch inside of the element. Then tap complete button"; -} - -function updateDescriptionFourthStepTouchActionElement(target, scrollReturnInterval) { - document.getElementById('desc').innerHTML = "Test Description: Try to scroll element RIGHT starting your touch inside of the element"; -} - -function objectScroller(target, direction, value) { - if (direction == 'up') { - target.scrollTop = 0; - } else if (direction == 'left') { - target.scrollLeft = 0; - } -} - -function sPointerCapture(e) { - try { - target0.setPointerCapture(e.pointerId); - } - catch(e) { - } -} - -function rPointerCapture(e) { - try { - captureButton.value = 'Set Capture'; - target0.releasePointerCapture(e.pointerId); - } - catch(e) { - } -} \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-auto-css_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-auto-css_touch-manual.html deleted file mode 100644 index f5e9d12c353..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-auto-css_touch-manual.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - touch-action: auto - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll text DOWN. Wait for description update. Expected: pan enabled

-

Note: this test is for touch-devices only

-
-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
- -

touch-action: auto

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-button-test_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-button-test_touch-manual.html deleted file mode 100644 index 01a1c88c181..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-button-test_touch-manual.html +++ /dev/null @@ -1,109 +0,0 @@ - - - - Button touch-action test - - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll black element DOWN moving your touch outside of the red border. Wait for description update.

-

Note: this test is for touch only

-
- -
-
- - - -

touch-action: none

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-illegal.html b/dom/events/test/pointerevents/pointerevent_touch-action-illegal.html deleted file mode 100644 index 5fe6179840e..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-illegal.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - touch-action: illegal - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Test will automatically check behaviour of following combinations: 'pan-x none', 'pan-y none', 'auto none'

-
-
-
- -

touch-action: none

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html deleted file mode 100644 index 364c9c11f6a..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html +++ /dev/null @@ -1,117 +0,0 @@ - - - - touch-action: parent > child: auto > child: none - - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: no panning.

-

Note: this test is for touch-devices only

-
-
-
-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
-
-
- - -

behaviour: none

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html deleted file mode 100644 index 786819b8588..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - touch-action: child: none - - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: no panning

-

Note: this test is for touch-devices only

-
-
-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
-
- - -

behaviour: none

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html deleted file mode 100644 index 09a97e3cbe2..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - touch-action: parent > child: pan-x > child: pan-x - - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: only pans in x direction.

-

Note: this test is for touch-devices only

-
-
-
-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
-
-
- - -

behaviour: pan-x

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html deleted file mode 100644 index 527e5537400..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html +++ /dev/null @@ -1,117 +0,0 @@ - - - - touch-action: parent > child: pan-x > child: pan-y - - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: no panning/zooming/etc.

-

Note: this test is for touch-devices only

-
-
-
-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
-
-
- - -

behaviour: none

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html deleted file mode 100644 index b13013c4376..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - touch-action: parent: none + two embedded children - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll text DOWN. Wait for description update. Expected: pan enabled

-

Note: this test is for touch-devices only

-
-
-
-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
-
-
- -

behaviour: auto

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html deleted file mode 100644 index 163ef9b8ef4..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - touch-action: inherit from parent: none - - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: no panning

-

Note: this test is for touch-devices only

-
-
-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
-
- - -

behaviour: none

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-keyboard-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-keyboard-manual.html deleted file mode 100644 index 3fef3f646f7..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-keyboard-manual.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - touch-action: keyboard - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Press DOWN ARROW key. Wait for description update. Expected: pan enabled

-

Note: this test is for keyboard only

-
-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
- -

touch-action: none

-
-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-mouse-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-mouse-manual.html deleted file mode 100644 index fcc8584515c..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-mouse-manual.html +++ /dev/null @@ -1,130 +0,0 @@ - - - - touch-action: mouse - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll text down using mouse (use mouse wheel or click on the scrollbar). Wait for description update.

-

Note: this test is for mouse only

-
-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
- -

touch-action: none

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-none-css_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-none-css_touch-manual.html deleted file mode 100644 index dec694f3eca..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-none-css_touch-manual.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - touch-action: none - - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: no panning/zooming/etc.

-

Note: this test is for touch-devices only

-
-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
- - -

touch-action: none

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual.html deleted file mode 100644 index e757baec6be..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual.html +++ /dev/null @@ -1,106 +0,0 @@ - - - - touch-action: pan-x - - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: only pans in x direction.

-

Note: this test is for touch-devices only

-
-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
- - -

touch-action: pan-x

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html deleted file mode 100644 index e89b8b742e9..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - touch-action: parent > child: pan-x pan-y > child: pan-y - - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: only pans in y direction.

-

Note: this test is for touch-devices only

-
-
-
- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
-
-
- - -

behaviour: pan-y

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch-manual.html deleted file mode 100644 index 0c900ff7407..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch-manual.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - touch-action: pan-x pan-y - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll text DOWN. Wait for description update. Expected: pan enabled

-

Note: this test is for touch-devices only

-
-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
- -

touch-action: pan-x pan-y

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual.html deleted file mode 100644 index 4ad39ecc838..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual.html +++ /dev/null @@ -1,106 +0,0 @@ - - - - touch-action: pan-y - - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: only pans in y direction.

-

Note: this test is for touch-devices only

-
-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem - nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. - Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit - lobortis nisl ut aliquip ex ea commodo consequat. -

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-

Lorem ipsum dolor sit amet...

-
- - -

touch-action: pan-y

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-span-test_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-span-test_touch-manual.html deleted file mode 100644 index 41635e0bf94..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-span-test_touch-manual.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - Span touch-action test - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll black element DOWN moving your touch outside of the red border. Wait for description update.

-

Note: this test is for touch only

-
- - Test span - -
- - - -

touch-action: none

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html deleted file mode 100644 index 6c9c0b3f68c..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - SVG test - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll black element DOWN moving your touch outside of the red border. Wait for description update.

-

Note: this test is for touch only

-
- - - Sorry, your browser does not support inline SVG. - -
-
- - -

touch-action: none

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-table-test_touch-manual.html b/dom/events/test/pointerevents/pointerevent_touch-action-table-test_touch-manual.html deleted file mode 100644 index fcc3a3e7cad..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-table-test_touch-manual.html +++ /dev/null @@ -1,141 +0,0 @@ - - - - Table touch-action test - - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Try to scroll element DOWN starting your touch over the 1st Row. Wait for description update.

-

Note: this test is for touch only

-
- - - - - -
The caption, first row element, and cell 3 have touch-action: none.
Header 1 Cell 1 Cell 2
Header 2 Cell 3 Cell 4
Header 3 Cell 5 Cell 6
-
-
- - - -

touch-action: none

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/pointerevent_touch-action-verification.html b/dom/events/test/pointerevents/pointerevent_touch-action-verification.html deleted file mode 100644 index 2e694229a21..00000000000 --- a/dom/events/test/pointerevents/pointerevent_touch-action-verification.html +++ /dev/null @@ -1,101 +0,0 @@ - - - - touch-action: basic verification - - - - - - - - - -

Pointer Events touch-action attribute support

-

Test Description: Test will automatically check behaviour of following values: 'auto', 'pan-x', 'pan-y', ' none', 'manipulation'

-
-
-
-
-
- -

touch-action: basic verification

-
-

The following pointer types were detected: .

-
-
- - \ No newline at end of file diff --git a/dom/events/test/pointerevents/readme.md b/dom/events/test/pointerevents/readme.md deleted file mode 100644 index f0d4fc73e6f..00000000000 --- a/dom/events/test/pointerevents/readme.md +++ /dev/null @@ -1,5 +0,0 @@ -Directory for Pointer Events Tests - -All tests were got from official repository: - -https://github.com/w3c/web-platform-tests/tree/master/pointerevents From 04b60c23fdd5d7bf7dc7eece28de7d64562da04f Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Fri, 5 Feb 2016 14:06:48 +0100 Subject: [PATCH 41/72] Bug 1245767 followup - Make the test work in opt shell builds too. r=me --- js/src/jit-test/tests/gc/gczeal-range.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/js/src/jit-test/tests/gc/gczeal-range.js b/js/src/jit-test/tests/gc/gczeal-range.js index ea26f45f1bb..1589a54af5a 100644 --- a/js/src/jit-test/tests/gc/gczeal-range.js +++ b/js/src/jit-test/tests/gc/gczeal-range.js @@ -1,2 +1,5 @@ -// |jit-test| error:out of range -gczeal(123); +try { + gczeal(123); +} catch(e) { + assertEq(e.toString().includes("out of range"), true); +} From bbac15a2b0c3aebbc8da10b985b2e4a1c4cd0ba3 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Fri, 5 Feb 2016 14:18:19 +0100 Subject: [PATCH 42/72] Backed out 16 changesets (bug 1245153) for mochitest test-bustage on a CLOSED TREE Backed out changeset 30c8ec933737 (bug 1245153) Backed out changeset 4c2b1902d7cd (bug 1245153) Backed out changeset 1be5f60393a0 (bug 1245153) Backed out changeset 22321e6b65e9 (bug 1245153) Backed out changeset c1e0abbfa66e (bug 1245153) Backed out changeset 80ae953819c8 (bug 1245153) Backed out changeset 3edb67388ad6 (bug 1245153) Backed out changeset 55f64197f6b5 (bug 1245153) Backed out changeset 6bb93562a576 (bug 1245153) Backed out changeset 5da7628c3767 (bug 1245153) Backed out changeset bd41e4ab829d (bug 1245153) Backed out changeset ee7ee24cc65e (bug 1245153) Backed out changeset 4b2a5ee7199e (bug 1245153) Backed out changeset d75ad1397656 (bug 1245153) Backed out changeset 1f5e37f8e446 (bug 1245153) Backed out changeset aec0a0166685 (bug 1245153) --- testing/marionette/ChromeUtils.js | 291 ++++++ testing/marionette/EventUtils.js | 673 ++++++++++++ testing/marionette/{action.js => actions.js} | 33 +- testing/marionette/atoms/HOWTO | 29 + .../marionette/{atom.js => atoms/atoms.js} | 26 +- testing/marionette/atoms/jar.mn | 7 + testing/marionette/atoms/moz.build | 7 + testing/marionette/driver.js | 39 +- .../marionette/{element.js => elements.js} | 112 +- testing/marionette/error.js | 35 +- testing/marionette/event.js | 954 ------------------ testing/marionette/frame-manager.js | 230 +++++ testing/marionette/frame.js | 264 ----- .../{interaction.js => interactions.js} | 128 ++- testing/marionette/jar.mn | 13 +- testing/marionette/listener.js | 92 +- testing/marionette/moz.build | 2 +- testing/marionette/proxy.js | 3 +- testing/marionette/sendkeys.js | 165 +++ testing/marionette/server.js | 8 +- testing/marionette/test_error.js | 42 - 21 files changed, 1658 insertions(+), 1495 deletions(-) create mode 100644 testing/marionette/ChromeUtils.js create mode 100644 testing/marionette/EventUtils.js rename testing/marionette/{action.js => actions.js} (93%) create mode 100644 testing/marionette/atoms/HOWTO rename testing/marionette/{atom.js => atoms/atoms.js} (98%) create mode 100644 testing/marionette/atoms/jar.mn create mode 100644 testing/marionette/atoms/moz.build rename testing/marionette/{element.js => elements.js} (86%) delete mode 100644 testing/marionette/event.js create mode 100644 testing/marionette/frame-manager.js delete mode 100644 testing/marionette/frame.js rename testing/marionette/{interaction.js => interactions.js} (60%) create mode 100644 testing/marionette/sendkeys.js diff --git a/testing/marionette/ChromeUtils.js b/testing/marionette/ChromeUtils.js new file mode 100644 index 00000000000..d51f96bc39b --- /dev/null +++ b/testing/marionette/ChromeUtils.js @@ -0,0 +1,291 @@ +/* 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/. */ + +/** + * ChromeUtils.js is a set of mochitest utilities that are used to + * synthesize events in the browser. These are only used by + * mochitest-chrome and browser-chrome tests. Originally these functions were in + * EventUtils.js, but when porting to specialPowers, we didn't want + * to move unnecessary functions. + * + * ChromeUtils.js depends on EventUtils.js being loaded. + * + */ + +/** + * Synthesize a query text content event. + * + * @param aOffset The character offset. 0 means the first character in the + * selection root. + * @param aLength The length of getting text. If the length is too long, + * the extra length is ignored. + * @param aWindow Optional (If null, current |window| will be used) + * @return An nsIQueryContentEventResult object. If this failed, + * the result might be null. + */ +function synthesizeQueryTextContent(aOffset, aLength, aWindow) +{ + var utils = _getDOMWindowUtils(aWindow); + if (!utils) { + return nullptr; + } + return utils.sendQueryContentEvent(utils.QUERY_TEXT_CONTENT, + aOffset, aLength, 0, 0); +} + +/** + * Synthesize a query caret rect event. + * + * @param aOffset The caret offset. 0 means left side of the first character + * in the selection root. + * @param aWindow Optional (If null, current |window| will be used) + * @return An nsIQueryContentEventResult object. If this failed, + * the result might be null. + */ +function synthesizeQueryCaretRect(aOffset, aWindow) +{ + var utils = _getDOMWindowUtils(aWindow); + if (!utils) { + return nullptr; + } + return utils.sendQueryContentEvent(utils.QUERY_CARET_RECT, + aOffset, 0, 0, 0); +} + +/** + * Synthesize a query text rect event. + * + * @param aOffset The character offset. 0 means the first character in the + * selection root. + * @param aLength The length of the text. If the length is too long, + * the extra length is ignored. + * @param aWindow Optional (If null, current |window| will be used) + * @return An nsIQueryContentEventResult object. If this failed, + * the result might be null. + */ +function synthesizeQueryTextRect(aOffset, aLength, aWindow) +{ + var utils = _getDOMWindowUtils(aWindow); + if (!utils) { + return nullptr; + } + return utils.sendQueryContentEvent(utils.QUERY_TEXT_RECT, + aOffset, aLength, 0, 0); +} + +/** + * Synthesize a query editor rect event. + * + * @param aWindow Optional (If null, current |window| will be used) + * @return An nsIQueryContentEventResult object. If this failed, + * the result might be null. + */ +function synthesizeQueryEditorRect(aWindow) +{ + var utils = _getDOMWindowUtils(aWindow); + if (!utils) { + return nullptr; + } + return utils.sendQueryContentEvent(utils.QUERY_EDITOR_RECT, 0, 0, 0, 0); +} + +/** + * Synthesize a character at point event. + * + * @param aX, aY The offset in the client area of the DOM window. + * @param aWindow Optional (If null, current |window| will be used) + * @return An nsIQueryContentEventResult object. If this failed, + * the result might be null. + */ +function synthesizeCharAtPoint(aX, aY, aWindow) +{ + var utils = _getDOMWindowUtils(aWindow); + if (!utils) { + return nullptr; + } + return utils.sendQueryContentEvent(utils.QUERY_CHARACTER_AT_POINT, + 0, 0, aX, aY); +} + +/** + * Emulate a dragstart event. + * element - element to fire the dragstart event on + * expectedDragData - the data you expect the data transfer to contain afterwards + * This data is in the format: + * [ [ {type: value, data: value, test: function}, ... ], ... ] + * can be null + * aWindow - optional; defaults to the current window object. + * x - optional; initial x coordinate + * y - optional; initial y coordinate + * Returns null if data matches. + * Returns the event.dataTransfer if data does not match + * + * eqTest is an optional function if comparison can't be done with x == y; + * function (actualData, expectedData) {return boolean} + * @param actualData from dataTransfer + * @param expectedData from expectedDragData + * see bug 462172 for example of use + * + */ +function synthesizeDragStart(element, expectedDragData, aWindow, x, y) +{ + if (!aWindow) + aWindow = window; + x = x || 2; + y = y || 2; + const step = 9; + + var result = "trapDrag was not called"; + var trapDrag = function(event) { + try { + var dataTransfer = event.dataTransfer; + result = null; + if (!dataTransfer) + throw "no dataTransfer"; + if (expectedDragData == null || + dataTransfer.mozItemCount != expectedDragData.length) + throw dataTransfer; + for (var i = 0; i < dataTransfer.mozItemCount; i++) { + var dtTypes = dataTransfer.mozTypesAt(i); + if (dtTypes.length != expectedDragData[i].length) + throw dataTransfer; + for (var j = 0; j < dtTypes.length; j++) { + if (dtTypes[j] != expectedDragData[i][j].type) + throw dataTransfer; + var dtData = dataTransfer.mozGetDataAt(dtTypes[j],i); + if (expectedDragData[i][j].eqTest) { + if (!expectedDragData[i][j].eqTest(dtData, expectedDragData[i][j].data)) + throw dataTransfer; + } + else if (expectedDragData[i][j].data != dtData) + throw dataTransfer; + } + } + } catch(ex) { + result = ex; + } + event.preventDefault(); + event.stopPropagation(); + } + aWindow.addEventListener("dragstart", trapDrag, false); + synthesizeMouse(element, x, y, { type: "mousedown" }, aWindow); + x += step; y += step; + synthesizeMouse(element, x, y, { type: "mousemove" }, aWindow); + x += step; y += step; + synthesizeMouse(element, x, y, { type: "mousemove" }, aWindow); + aWindow.removeEventListener("dragstart", trapDrag, false); + synthesizeMouse(element, x, y, { type: "mouseup" }, aWindow); + return result; +} + +/** + * Emulate a drop by emulating a dragstart and firing events dragenter, dragover, and drop. + * srcElement - the element to use to start the drag, usually the same as destElement + * but if destElement isn't suitable to start a drag on pass a suitable + * element for srcElement + * destElement - the element to fire the dragover, dragleave and drop events + * dragData - the data to supply for the data transfer + * This data is in the format: + * [ [ {type: value, data: value}, ...], ... ] + * dropEffect - the drop effect to set during the dragstart event, or 'move' if null + * aWindow - optional; defaults to the current window object. + * eventUtils - optional; allows you to pass in a reference to EventUtils.js. + * If the eventUtils parameter is not passed in, we assume EventUtils.js is + * in the scope. Used by browser-chrome tests. + * + * Returns the drop effect that was desired. + */ +function synthesizeDrop(srcElement, destElement, dragData, dropEffect, aWindow, eventUtils) +{ + if (!aWindow) + aWindow = window; + + var synthesizeMouseAtCenter = (eventUtils || window).synthesizeMouseAtCenter; + var synthesizeMouse = (eventUtils || window).synthesizeMouse; + + var gWindowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor). + getInterface(Components.interfaces.nsIDOMWindowUtils); + var ds = Components.classes["@mozilla.org/widget/dragservice;1"]. + getService(Components.interfaces.nsIDragService); + + var dataTransfer; + var trapDrag = function(event) { + dataTransfer = event.dataTransfer; + for (var i = 0; i < dragData.length; i++) { + var item = dragData[i]; + for (var j = 0; j < item.length; j++) { + dataTransfer.mozSetDataAt(item[j].type, item[j].data, i); + } + } + dataTransfer.dropEffect = dropEffect || "move"; + event.preventDefault(); + event.stopPropagation(); + } + + ds.startDragSession(); + + try { + // need to use real mouse action + aWindow.addEventListener("dragstart", trapDrag, true); + synthesizeMouseAtCenter(srcElement, { type: "mousedown" }, aWindow); + + var rect = srcElement.getBoundingClientRect(); + var x = rect.width / 2; + var y = rect.height / 2; + synthesizeMouse(srcElement, x, y, { type: "mousemove" }, aWindow); + synthesizeMouse(srcElement, x+10, y+10, { type: "mousemove" }, aWindow); + aWindow.removeEventListener("dragstart", trapDrag, true); + + event = aWindow.document.createEvent("DragEvents"); + event.initDragEvent("dragenter", true, true, aWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); + gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true); + + var event = aWindow.document.createEvent("DragEvents"); + event.initDragEvent("dragover", true, true, aWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); + if (gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true)) { + synthesizeMouseAtCenter(destElement, { type: "mouseup" }, aWindow); + return "none"; + } + + if (dataTransfer.dropEffect != "none") { + event = aWindow.document.createEvent("DragEvents"); + event.initDragEvent("drop", true, true, aWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); + gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true); + } + + synthesizeMouseAtCenter(destElement, { type: "mouseup" }, aWindow); + + return dataTransfer.dropEffect; + } finally { + ds.endDragSession(true); + } +}; + +var PluginUtils = +{ + withTestPlugin : function(callback) + { + if (typeof Components == "undefined") + { + todo(false, "Not a Mozilla-based browser"); + return false; + } + + var ph = Components.classes["@mozilla.org/plugin/host;1"] + .getService(Components.interfaces.nsIPluginHost); + var tags = ph.getPluginTags(); + + // Find the test plugin + for (var i = 0; i < tags.length; i++) + { + if (tags[i].name == "Test Plug-in") + { + callback(tags[i]); + return true; + } + } + todo(false, "Need a test plugin on this platform"); + return false; + } +}; diff --git a/testing/marionette/EventUtils.js b/testing/marionette/EventUtils.js new file mode 100644 index 00000000000..0a0e5f052cb --- /dev/null +++ b/testing/marionette/EventUtils.js @@ -0,0 +1,673 @@ +/* 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/. */ + +/** + * EventUtils provides some utility methods for creating and sending DOM events. + * Current methods: + * sendMouseEvent + * sendChar + * sendString + * sendKey + * synthesizeMouse + * synthesizeMouseAtCenter + * synthesizeMouseScroll + * synthesizeKey + * synthesizeMouseExpectEvent + * synthesizeKeyExpectEvent + * + * When adding methods to this file, please add a performance test for it. + */ + +/** + * Send a mouse event to the node aTarget (aTarget can be an id, or an + * actual node) . The "event" passed in to aEvent is just a JavaScript + * object with the properties set that the real mouse event object should + * have. This includes the type of the mouse event. + * E.g. to send an click event to the node with id 'node' you might do this: + * + * sendMouseEvent({type:'click'}, 'node'); + */ +function getElement(id) { + return ((typeof(id) == "string") ? + document.getElementById(id) : id); +}; + +this.$ = this.getElement; +const KeyEvent = Components.interfaces.nsIDOMKeyEvent; + +function sendMouseEvent(aEvent, aTarget, aWindow) { + if (['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout'].indexOf(aEvent.type) == -1) { + throw new Error("sendMouseEvent doesn't know about event type '" + aEvent.type + "'"); + } + + if (!aWindow) { + aWindow = window; + } + + if (!(aTarget instanceof Element)) { + aTarget = aWindow.document.getElementById(aTarget); + } + + var event = aWindow.document.createEvent('MouseEvent'); + + var typeArg = aEvent.type; + var canBubbleArg = true; + var cancelableArg = true; + var viewArg = aWindow; + var detailArg = aEvent.detail || (aEvent.type == 'click' || + aEvent.type == 'mousedown' || + aEvent.type == 'mouseup' ? 1 : + aEvent.type == 'dblclick'? 2 : 0); + var screenXArg = aEvent.screenX || 0; + var screenYArg = aEvent.screenY || 0; + var clientXArg = aEvent.clientX || 0; + var clientYArg = aEvent.clientY || 0; + var ctrlKeyArg = aEvent.ctrlKey || false; + var altKeyArg = aEvent.altKey || false; + var shiftKeyArg = aEvent.shiftKey || false; + var metaKeyArg = aEvent.metaKey || false; + var buttonArg = aEvent.button || 0; + var relatedTargetArg = aEvent.relatedTarget || null; + + event.initMouseEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg, + screenXArg, screenYArg, clientXArg, clientYArg, + ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg, + buttonArg, relatedTargetArg); + + //removed: SpecialPowers.dispatchEvent(aWindow, aTarget, event); +} + +/** + * Send the char aChar to the focused element. This method handles casing of + * chars (sends the right charcode, and sends a shift key for uppercase chars). + * No other modifiers are handled at this point. + * + * For now this method only works for English letters (lower and upper case) + * and the digits 0-9. + */ +function sendChar(aChar, aWindow) { + // DOM event charcodes match ASCII (JS charcodes) for a-zA-Z0-9. + var hasShift = (aChar == aChar.toUpperCase()); + synthesizeKey(aChar, { shiftKey: hasShift }, aWindow); +} + +/** + * Send the string aStr to the focused element. + * + * For now this method only works for English letters (lower and upper case) + * and the digits 0-9. + */ +function sendString(aStr, aWindow) { + for (var i = 0; i < aStr.length; ++i) { + sendChar(aStr.charAt(i), aWindow); + } +} + +/** + * Send the non-character key aKey to the focused node. + * The name of the key should be the part that comes after "DOM_VK_" in the + * KeyEvent constant name for this key. + * No modifiers are handled at this point. + */ +function sendKey(aKey, aWindow) { + var keyName = "VK_" + aKey.toUpperCase(); + synthesizeKey(keyName, { shiftKey: false }, aWindow); +} + +/** + * Parse the key modifier flags from aEvent. Used to share code between + * synthesizeMouse and synthesizeKey. + */ +function _parseModifiers(aEvent) +{ + const masks = Components.interfaces.nsIDOMNSEvent; + var mval = 0; + if (aEvent.shiftKey) + mval |= masks.SHIFT_MASK; + if (aEvent.ctrlKey) + mval |= masks.CONTROL_MASK; + if (aEvent.altKey) + mval |= masks.ALT_MASK; + if (aEvent.metaKey) + mval |= masks.META_MASK; + if (aEvent.accelKey) + mval |= (navigator.platform.indexOf("Mac") >= 0) ? masks.META_MASK : + masks.CONTROL_MASK; + + return mval; +} + +/** + * Synthesize a mouse event on a target. The actual client point is determined + * by taking the aTarget's client box and offseting it by aOffsetX and + * aOffsetY. This allows mouse clicks to be simulated by calling this method. + * + * aEvent is an object which may contain the properties: + * shiftKey, ctrlKey, altKey, metaKey, accessKey, clickCount, button, type + * + * If the type is specified, an mouse event of that type is fired. Otherwise, + * a mousedown followed by a mouse up is performed. + * + * aWindow is optional, and defaults to the current window object. + */ +function synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow) +{ + var rect = aTarget.getBoundingClientRect(); + synthesizeMouseAtPoint(rect.left + aOffsetX, rect.top + aOffsetY, + aEvent, aWindow); +} + +/* + * Synthesize a mouse event at a particular point in aWindow. + * + * aEvent is an object which may contain the properties: + * shiftKey, ctrlKey, altKey, metaKey, accessKey, clickCount, button, type + * + * If the type is specified, an mouse event of that type is fired. Otherwise, + * a mousedown followed by a mouse up is performed. + * + * aWindow is optional, and defaults to the current window object. + */ +function synthesizeMouseAtPoint(left, top, aEvent, aWindow) +{ + var utils = _getDOMWindowUtils(aWindow); + + if (utils) { + var button = aEvent.button || 0; + var clickCount = aEvent.clickCount || 1; + var modifiers = _parseModifiers(aEvent); + + if (("type" in aEvent) && aEvent.type) { + utils.sendMouseEvent(aEvent.type, left, top, button, clickCount, modifiers); + } + else { + utils.sendMouseEvent("mousedown", left, top, button, clickCount, modifiers); + utils.sendMouseEvent("mouseup", left, top, button, clickCount, modifiers); + } + } +} + +// Call synthesizeMouse with coordinates at the center of aTarget. +function synthesizeMouseAtCenter(aTarget, aEvent, aWindow) +{ + var rect = aTarget.getBoundingClientRect(); + synthesizeMouse(aTarget, rect.width / 2, rect.height / 2, aEvent, + aWindow); +} + +/** + * Synthesize a mouse scroll event on a target. The actual client point is determined + * by taking the aTarget's client box and offseting it by aOffsetX and + * aOffsetY. + * + * aEvent is an object which may contain the properties: + * shiftKey, ctrlKey, altKey, metaKey, accessKey, button, type, axis, delta, hasPixels + * + * If the type is specified, a mouse scroll event of that type is fired. Otherwise, + * "DOMMouseScroll" is used. + * + * If the axis is specified, it must be one of "horizontal" or "vertical". If not specified, + * "vertical" is used. + * + * 'delta' is the amount to scroll by (can be positive or negative). It must + * be specified. + * + * 'hasPixels' specifies whether kHasPixels should be set in the scrollFlags. + * + * 'isMomentum' specifies whether kIsMomentum should be set in the scrollFlags. + * + * aWindow is optional, and defaults to the current window object. + */ +function synthesizeMouseScroll(aTarget, aOffsetX, aOffsetY, aEvent, aWindow) +{ + var utils = _getDOMWindowUtils(aWindow); + + if (utils) { + // See nsMouseScrollFlags in nsGUIEvent.h + const kIsVertical = 0x02; + const kIsHorizontal = 0x04; + const kHasPixels = 0x08; + const kIsMomentum = 0x40; + + var button = aEvent.button || 0; + var modifiers = _parseModifiers(aEvent); + + var rect = aTarget.getBoundingClientRect(); + + var left = rect.left; + var top = rect.top; + + var type = (("type" in aEvent) && aEvent.type) || "DOMMouseScroll"; + var axis = aEvent.axis || "vertical"; + var scrollFlags = (axis == "horizontal") ? kIsHorizontal : kIsVertical; + if (aEvent.hasPixels) { + scrollFlags |= kHasPixels; + } + if (aEvent.isMomentum) { + scrollFlags |= kIsMomentum; + } + utils.sendMouseScrollEvent(type, left + aOffsetX, top + aOffsetY, button, + scrollFlags, aEvent.delta, modifiers); + } +} + +function _computeKeyCodeFromChar(aChar) +{ + if (aChar.length != 1) { + return 0; + } + const nsIDOMKeyEvent = Components.interfaces.nsIDOMKeyEvent; + if (aChar >= 'a' && aChar <= 'z') { + return nsIDOMKeyEvent.DOM_VK_A + aChar.charCodeAt(0) - 'a'.charCodeAt(0); + } + if (aChar >= 'A' && aChar <= 'Z') { + return nsIDOMKeyEvent.DOM_VK_A + aChar.charCodeAt(0) - 'A'.charCodeAt(0); + } + if (aChar >= '0' && aChar <= '9') { + return nsIDOMKeyEvent.DOM_VK_0 + aChar.charCodeAt(0) - '0'.charCodeAt(0); + } + // returns US keyboard layout's keycode + switch (aChar) { + case '~': + case '`': + return nsIDOMKeyEvent.DOM_VK_BACK_QUOTE; + case '!': + return nsIDOMKeyEvent.DOM_VK_1; + case '@': + return nsIDOMKeyEvent.DOM_VK_2; + case '#': + return nsIDOMKeyEvent.DOM_VK_3; + case '$': + return nsIDOMKeyEvent.DOM_VK_4; + case '%': + return nsIDOMKeyEvent.DOM_VK_5; + case '^': + return nsIDOMKeyEvent.DOM_VK_6; + case '&': + return nsIDOMKeyEvent.DOM_VK_7; + case '*': + return nsIDOMKeyEvent.DOM_VK_8; + case '(': + return nsIDOMKeyEvent.DOM_VK_9; + case ')': + return nsIDOMKeyEvent.DOM_VK_0; + case '-': + case '_': + return nsIDOMKeyEvent.DOM_VK_SUBTRACT; + case '+': + case '=': + return nsIDOMKeyEvent.DOM_VK_EQUALS; + case '{': + case '[': + return nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET; + case '}': + case ']': + return nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET; + case '|': + case '\\': + return nsIDOMKeyEvent.DOM_VK_BACK_SLASH; + case ':': + case ';': + return nsIDOMKeyEvent.DOM_VK_SEMICOLON; + case '\'': + case '"': + return nsIDOMKeyEvent.DOM_VK_QUOTE; + case '<': + case ',': + return nsIDOMKeyEvent.DOM_VK_COMMA; + case '>': + case '.': + return nsIDOMKeyEvent.DOM_VK_PERIOD; + case '?': + case '/': + return nsIDOMKeyEvent.DOM_VK_SLASH; + case '\n': + return nsIDOMKeyEvent.DOM_VK_RETURN; + default: + return 0; + } +} + +/** + * isKeypressFiredKey() returns TRUE if the given key should cause keypress + * event when widget handles the native key event. Otherwise, FALSE. + * + * aDOMKeyCode should be one of consts of nsIDOMKeyEvent::DOM_VK_*, or a key + * name begins with "VK_", or a character. + */ +function isKeypressFiredKey(aDOMKeyCode) +{ + const KeyEvent = Components.interfaces.nsIDOMKeyEvent; + if (typeof(aDOMKeyCode) == "string") { + if (aDOMKeyCode.indexOf("VK_") == 0) { + aDOMKeyCode = KeyEvent["DOM_" + aDOMKeyCode]; + if (!aDOMKeyCode) { + throw "Unknown key: " + aDOMKeyCode; + } + } else { + // If the key generates a character, it must cause a keypress event. + return true; + } + } + switch (aDOMKeyCode) { + case KeyEvent.DOM_VK_SHIFT: + case KeyEvent.DOM_VK_CONTROL: + case KeyEvent.DOM_VK_ALT: + case KeyEvent.DOM_VK_CAPS_LOCK: + case KeyEvent.DOM_VK_NUM_LOCK: + case KeyEvent.DOM_VK_SCROLL_LOCK: + case KeyEvent.DOM_VK_META: + return false; + default: + return true; + } +} + +/** + * Synthesize a key event. It is targeted at whatever would be targeted by an + * actual keypress by the user, typically the focused element. + * + * aKey should be either a character or a keycode starting with VK_ such as + * VK_RETURN. + * + * aEvent is an object which may contain the properties: + * shiftKey, ctrlKey, altKey, metaKey, accessKey, type + * + * If the type is specified, a key event of that type is fired. Otherwise, + * a keydown, a keypress and then a keyup event are fired in sequence. + * + * aWindow is optional, and defaults to the current window object. + */ +function synthesizeKey(aKey, aEvent, aWindow) +{ + var utils = _getDOMWindowUtils(aWindow); + if (utils) { + var keyCode = 0, charCode = 0; + if (aKey.indexOf("VK_") == 0) { + keyCode = KeyEvent["DOM_" + aKey]; + if (!keyCode) { + throw "Unknown key: " + aKey; + } + } else { + charCode = aKey.charCodeAt(0); + keyCode = _computeKeyCodeFromChar(aKey.charAt(0)); + } + + var modifiers = _parseModifiers(aEvent); + + if (!("type" in aEvent) || !aEvent.type) { + // Send keydown + (optional) keypress + keyup events. + var keyDownDefaultHappened = + utils.sendKeyEvent("keydown", keyCode, 0, modifiers); + if (isKeypressFiredKey(keyCode)) { + utils.sendKeyEvent("keypress", charCode ? 0 : keyCode, charCode, + modifiers, !keyDownDefaultHappened); + } + utils.sendKeyEvent("keyup", keyCode, 0, modifiers); + } else if (aEvent.type == "keypress") { + // Send standalone keypress event. + utils.sendKeyEvent(aEvent.type, charCode ? 0 : keyCode, + charCode, modifiers); + } else { + // Send other standalone event than keypress. + utils.sendKeyEvent(aEvent.type, keyCode, 0, modifiers); + } + } +} + +var _gSeenEvent = false; + +/** + * Indicate that an event with an original target of aExpectedTarget and + * a type of aExpectedEvent is expected to be fired, or not expected to + * be fired. + */ +function _expectEvent(aExpectedTarget, aExpectedEvent, aTestName) +{ + if (!aExpectedTarget || !aExpectedEvent) + return null; + + _gSeenEvent = false; + + var type = (aExpectedEvent.charAt(0) == "!") ? + aExpectedEvent.substring(1) : aExpectedEvent; + var eventHandler = function(event) { + var epassed = (!_gSeenEvent && event.originalTarget == aExpectedTarget && + event.type == type); + is(epassed, true, aTestName + " " + type + " event target " + (_gSeenEvent ? "twice" : "")); + _gSeenEvent = true; + }; + + aExpectedTarget.addEventListener(type, eventHandler, false); + return eventHandler; +} + +/** + * Check if the event was fired or not. The event handler aEventHandler + * will be removed. + */ +function _checkExpectedEvent(aExpectedTarget, aExpectedEvent, aEventHandler, aTestName) +{ + if (aEventHandler) { + var expectEvent = (aExpectedEvent.charAt(0) != "!"); + var type = expectEvent ? aExpectedEvent : aExpectedEvent.substring(1); + aExpectedTarget.removeEventListener(type, aEventHandler, false); + var desc = type + " event"; + if (!expectEvent) + desc += " not"; + is(_gSeenEvent, expectEvent, aTestName + " " + desc + " fired"); + } + + _gSeenEvent = false; +} + +/** + * Similar to synthesizeMouse except that a test is performed to see if an + * event is fired at the right target as a result. + * + * aExpectedTarget - the expected originalTarget of the event. + * aExpectedEvent - the expected type of the event, such as 'select'. + * aTestName - the test name when outputing results + * + * To test that an event is not fired, use an expected type preceded by an + * exclamation mark, such as '!select'. This might be used to test that a + * click on a disabled element doesn't fire certain events for instance. + * + * aWindow is optional, and defaults to the current window object. + */ +function synthesizeMouseExpectEvent(aTarget, aOffsetX, aOffsetY, aEvent, + aExpectedTarget, aExpectedEvent, aTestName, + aWindow) +{ + var eventHandler = _expectEvent(aExpectedTarget, aExpectedEvent, aTestName); + synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow); + _checkExpectedEvent(aExpectedTarget, aExpectedEvent, eventHandler, aTestName); +} + +/** + * Similar to synthesizeKey except that a test is performed to see if an + * event is fired at the right target as a result. + * + * aExpectedTarget - the expected originalTarget of the event. + * aExpectedEvent - the expected type of the event, such as 'select'. + * aTestName - the test name when outputing results + * + * To test that an event is not fired, use an expected type preceded by an + * exclamation mark, such as '!select'. + * + * aWindow is optional, and defaults to the current window object. + */ +function synthesizeKeyExpectEvent(key, aEvent, aExpectedTarget, aExpectedEvent, + aTestName, aWindow) +{ + var eventHandler = _expectEvent(aExpectedTarget, aExpectedEvent, aTestName); + synthesizeKey(key, aEvent, aWindow); + _checkExpectedEvent(aExpectedTarget, aExpectedEvent, eventHandler, aTestName); +} + +function disableNonTestMouseEvents(aDisable) +{ + var domutils = _getDOMWindowUtils(); + domutils.disableNonTestMouseEvents(aDisable); +} + +function _getDOMWindowUtils(aWindow) +{ + if (!aWindow) { + aWindow = window; + } + + //TODO: this is assuming we are in chrome space + return aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor). + getInterface(Components.interfaces.nsIDOMWindowUtils); +} + +// Must be synchronized with nsIDOMWindowUtils. +const COMPOSITION_ATTR_RAWINPUT = 0x02; +const COMPOSITION_ATTR_SELECTEDRAWTEXT = 0x03; +const COMPOSITION_ATTR_CONVERTEDTEXT = 0x04; +const COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT = 0x05; + +/** + * Synthesize a composition event. + * + * @param aEvent The composition event information. This must + * have |type| member. The value must be + * "compositionstart", "compositionend" or + * "compositionupdate". + * And also this may have |data| and |locale| which + * would be used for the value of each property of + * the composition event. Note that the data would + * be ignored if the event type were + * "compositionstart". + * @param aWindow Optional (If null, current |window| will be used) + */ +function synthesizeComposition(aEvent, aWindow) +{ + var utils = _getDOMWindowUtils(aWindow); + if (!utils) { + return; + } + + utils.sendCompositionEvent(aEvent.type, aEvent.data ? aEvent.data : "", + aEvent.locale ? aEvent.locale : ""); +} +/** + * Synthesize a text event. + * + * @param aEvent The text event's information, this has |composition| + * and |caret| members. |composition| has |string| and + * |clauses| members. |clauses| must be array object. Each + * object has |length| and |attr|. And |caret| has |start| and + * |length|. See the following tree image. + * + * aEvent + * +-- composition + * | +-- string + * | +-- clauses[] + * | +-- length + * | +-- attr + * +-- caret + * +-- start + * +-- length + * + * Set the composition string to |composition.string|. Set its + * clauses information to the |clauses| array. + * + * When it's composing, set the each clauses' length to the + * |composition.clauses[n].length|. The sum of the all length + * values must be same as the length of |composition.string|. + * Set nsIDOMWindowUtils.COMPOSITION_ATTR_* to the + * |composition.clauses[n].attr|. + * + * When it's not composing, set 0 to the + * |composition.clauses[0].length| and + * |composition.clauses[0].attr|. + * + * Set caret position to the |caret.start|. It's offset from + * the start of the composition string. Set caret length to + * |caret.length|. If it's larger than 0, it should be wide + * caret. However, current nsEditor doesn't support wide + * caret, therefore, you should always set 0 now. + * + * @param aWindow Optional (If null, current |window| will be used) + */ +function synthesizeText(aEvent, aWindow) +{ + var utils = _getDOMWindowUtils(aWindow); + if (!utils) { + return; + } + + if (!aEvent.composition || !aEvent.composition.clauses || + !aEvent.composition.clauses[0]) { + return; + } + + var firstClauseLength = aEvent.composition.clauses[0].length; + var firstClauseAttr = aEvent.composition.clauses[0].attr; + var secondClauseLength = 0; + var secondClauseAttr = 0; + var thirdClauseLength = 0; + var thirdClauseAttr = 0; + if (aEvent.composition.clauses[1]) { + secondClauseLength = aEvent.composition.clauses[1].length; + secondClauseAttr = aEvent.composition.clauses[1].attr; + if (aEvent.composition.clauses[2]) { + thirdClauseLength = aEvent.composition.clauses[2].length; + thirdClauseAttr = aEvent.composition.clauses[2].attr; + } + } + + var caretStart = -1; + var caretLength = 0; + if (aEvent.caret) { + caretStart = aEvent.caret.start; + caretLength = aEvent.caret.length; + } + + utils.sendTextEvent(aEvent.composition.string, + firstClauseLength, firstClauseAttr, + secondClauseLength, secondClauseAttr, + thirdClauseLength, thirdClauseAttr, + caretStart, caretLength); +} + +/** + * Synthesize a query selected text event. + * + * @param aWindow Optional (If null, current |window| will be used) + * @return An nsIQueryContentEventResult object. If this failed, + * the result might be null. + */ +function synthesizeQuerySelectedText(aWindow) +{ + var utils = _getDOMWindowUtils(aWindow); + if (!utils) { + return null; + } + + return utils.sendQueryContentEvent(utils.QUERY_SELECTED_TEXT, 0, 0, 0, 0); +} + +/** + * Synthesize a selection set event. + * + * @param aOffset The character offset. 0 means the first character in the + * selection root. + * @param aLength The length of the text. If the length is too long, + * the extra length is ignored. + * @param aReverse If true, the selection is from |aOffset + aLength| to + * |aOffset|. Otherwise, from |aOffset| to |aOffset + aLength|. + * @param aWindow Optional (If null, current |window| will be used) + * @return True, if succeeded. Otherwise false. + */ +function synthesizeSelectionSet(aOffset, aLength, aReverse, aWindow) +{ + var utils = _getDOMWindowUtils(aWindow); + if (!utils) { + return false; + } + return utils.sendSelectionSetEvent(aOffset, aLength, aReverse); +} diff --git a/testing/marionette/action.js b/testing/marionette/actions.js similarity index 93% rename from testing/marionette/action.js rename to testing/marionette/actions.js index c74d667bde1..0c2dd76bf74 100644 --- a/testing/marionette/action.js +++ b/testing/marionette/actions.js @@ -7,21 +7,19 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://gre/modules/Log.jsm"); Cu.import("resource://gre/modules/Preferences.jsm"); -Cu.import("chrome://marionette/content/event.js"); - const CONTEXT_MENU_DELAY_PREF = "ui.click_hold_context_menus.delay"; const DEFAULT_CONTEXT_MENU_DELAY = 750; // ms -this.EXPORTED_SYMBOLS = ["action"]; +this.EXPORTED_SYMBOLS = ["actions"]; const logger = Log.repository.getLogger("Marionette"); -this.action = {}; +this.actions = {}; /** * Functionality for (single finger) action chains. */ -action.Chain = function(checkForInterrupted) { +actions.Chain = function(utils, checkForInterrupted) { // for assigning unique ids to all touches this.nextTouchId = 1000; // keep track of active Touches @@ -45,9 +43,12 @@ action.Chain = function(checkForInterrupted) { // determines if we create touch events this.inputSource = null; + + // test utilities providing some event synthesis code + this.utils = utils; }; -action.Chain.prototype.dispatchActions = function( +actions.Chain.prototype.dispatchActions = function( args, touchId, container, @@ -105,7 +106,7 @@ action.Chain.prototype.dispatchActions = function( * @param {Object} modifiers * An object of modifier keys present. */ -action.Chain.prototype.emitMouseEvent = function( +actions.Chain.prototype.emitMouseEvent = function( doc, type, elClientX, @@ -126,7 +127,7 @@ action.Chain.prototype.emitMouseEvent = function( let mods; if (typeof modifiers != "undefined") { - mods = event.parseModifiers_(modifiers); + mods = this.utils._parseModifiers(modifiers); } else { mods = 0; } @@ -147,7 +148,7 @@ action.Chain.prototype.emitMouseEvent = function( /** * Reset any persisted values after a command completes. */ -action.Chain.prototype.resetValues = function() { +actions.Chain.prototype.resetValues = function() { this.onSuccess = null; this.onError = null; this.container = null; @@ -163,7 +164,7 @@ action.Chain.prototype.resetValues = function() { * keyModifiers is an object keeping track keyDown/keyUp pairs through * an action chain. */ -action.Chain.prototype.actions = function(chain, touchId, i, keyModifiers) { +actions.Chain.prototype.actions = function(chain, touchId, i, keyModifiers) { if (i == chain.length) { this.onSuccess(touchId || null); this.resetValues(); @@ -186,12 +187,12 @@ action.Chain.prototype.actions = function(chain, touchId, i, keyModifiers) { switch(command) { case "keyDown": - event.sendKeyDown(pack[1], keyModifiers, this.container.frame); + this.utils.sendKeyDown(pack[1], keyModifiers, this.container.frame); this.actions(chain, touchId, i, keyModifiers); break; case "keyUp": - event.sendKeyUp(pack[1], keyModifiers, this.container.frame); + this.utils.sendKeyUp(pack[1], keyModifiers, this.container.frame); this.actions(chain, touchId, i, keyModifiers); break; @@ -323,7 +324,7 @@ action.Chain.prototype.actions = function(chain, touchId, i, keyModifiers) { * Y coordinate relative to target. If unspecified, the centre of * the target is used. */ -action.Chain.prototype.coordinates = function(target, x, y) { +actions.Chain.prototype.coordinates = function(target, x, y) { let box = target.getBoundingClientRect(); if (x == null) { x = box.width / 2; @@ -341,7 +342,7 @@ action.Chain.prototype.coordinates = function(target, x, y) { * Given an element and a pair of coordinates, returns an array of the * form [clientX, clientY, pageX, pageY, screenX, screenY]. */ -action.Chain.prototype.getCoordinateInfo = function(el, corx, cory) { +actions.Chain.prototype.getCoordinateInfo = function(el, corx, cory) { let win = el.ownerDocument.defaultView; return [ corx, // clientX @@ -361,7 +362,7 @@ action.Chain.prototype.getCoordinateInfo = function(el, corx, cory) { * Y coordinate of the location to generate the event that is relative * to the viewport. */ -action.Chain.prototype.generateEvents = function( +actions.Chain.prototype.generateEvents = function( type, x, y, touchId, target, keyModifiers) { this.lastCoordinates = [x, y]; let doc = this.container.frame.document; @@ -494,7 +495,7 @@ action.Chain.prototype.generateEvents = function( this.checkForInterrupted(); }; -action.Chain.prototype.mouseTap = function(doc, x, y, button, count, mod) { +actions.Chain.prototype.mouseTap = function(doc, x, y, button, count, mod) { this.emitMouseEvent(doc, "mousemove", x, y, button, count, mod); this.emitMouseEvent(doc, "mousedown", x, y, button, count, mod); this.emitMouseEvent(doc, "mouseup", x, y, button, count, mod); diff --git a/testing/marionette/atoms/HOWTO b/testing/marionette/atoms/HOWTO new file mode 100644 index 00000000000..72829e665e3 --- /dev/null +++ b/testing/marionette/atoms/HOWTO @@ -0,0 +1,29 @@ +These atoms are generated from the selenium trunk. They are minified versions of what's in the trunk, +optimized to run on Firefox. To generate them, clone the repo: + + svn checkout http://selenium.googlecode.com/svn/trunk/ selenium-read-only + +then run the Google closure compiler and specify which atom you'd like to get. +For example, this will generate the "get_text" atom: + + cd selenium-read-only + ./go //javascript/webdriver/atoms:get_text:firefox + +This generates the atom, which is a function. You'll need to assign that function to a variable of your choice +which you can then import, i.e.: you'll need to modify the atom with a variable assignment: + + var myVar = + +You can now import this atom and call it with myVar(). Please note the name of the function as a comment above this line to help readability in the atoms file. + +For more information on atoms, refer to http://code.google.com/p/selenium/wiki/AutomationAtoms#Atoms_Summary + +Currently bundled atoms (please update as you add more): +- clearElement +- click +- getAttributeValue +- getElementText +- isElementDisplayed +- isElementEnabled +- isElementSelected +- sendKeysToElement/type diff --git a/testing/marionette/atom.js b/testing/marionette/atoms/atoms.js similarity index 98% rename from testing/marionette/atom.js rename to testing/marionette/atoms/atoms.js index 570bb5a0c11..35ad299a62e 100644 --- a/testing/marionette/atom.js +++ b/testing/marionette/atoms/atoms.js @@ -12,11 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -this.EXPORTED_SYMBOLS = ["atom"]; - -this.atom = {}; - -atom.clearElement = function(element, window){return function(){function g(a){throw a;}var h=void 0,i=!0,k=null,l=!1;function n(a){return function(){return this[a]}}function o(a){return function(){return a}}var p,q=this; +//clearElement +var clearElement = function(){return function(){function g(a){throw a;}var h=void 0,i=!0,k=null,l=!1;function n(a){return function(){return this[a]}}function o(a){return function(){return a}}var p,q=this; function aa(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null"; else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function r(a){return a!==h}function ba(a){var b=aa(a);return"array"==b||"object"==b&&"number"==typeof a.length}function t(a){return"string"==typeof a}function w(a){return"function"==aa(a)}function ca(a){a=aa(a);return"object"==a||"array"==a||"function"==a}var da="closure_uid_"+Math.floor(2147483648*Math.random()).toString(36),ea=0,fa=Date.now||function(){return+new Date}; function x(a,b){function c(){}c.prototype=b.prototype;a.$=b.prototype;a.prototype=new c};function ga(a,b){for(var c=1;c")&&(a=a.replace(ma,">"));-1!=a.indexOf('"')&&(a=a.replace(na,"""));return a}var ka=/&/g,la=//g,na=/\"/g,ja=/[&<>\"]/; @@ -89,8 +86,8 @@ p.H=k;p.V=0;p.b=function(){return this.H[0].b()};p.g=function(){return z(this.H) function Lc(a,b,c,d){if(a==c)return d(0==B[1].length? 0:parseInt(B[1],10))?1:0)||((0==A[2].length)<(0==B[2].length)?-1:(0==A[2].length)>(0==B[2].length)?1:0)||(A[2]B[2]?1:0)}while(0==q)}k["1.9.1"]=0<=q};(function(){var a=e.Components;if(!a)return!1;try{if(!a.classes)return!1}catch(c){return!1}var b=a.classes,a=a.interfaces;b["@mozilla.org/xpcom/version-comparator;1"].getService(a.nsIVersionComparator);b["@mozilla.org/xre/app-info;1"].getService(a.nsIXULAppInfo);return!0})();function C(a,c,b,d,y){this.b=!!c;if(a&&(this.a=a))this.c="number"==typeof d?d:1!=this.a.nodeType?0:this.b?-1:1;this.depth=void 0!=y?y:this.c||0;this.b&&(this.depth*=-1)}f(C,function(){});C.prototype.a=null;C.prototype.c=0;f(function(a,c,b,d){C.call(this,a,c,0,null,d)},C);var D={"class":"className",readonly:"readOnly"},E=["checked","disabled","draggable","hidden"],F="BUTTON,INPUT,OPTGROUP,OPTION,SELECT,TEXTAREA".split(",");function G(a){var c=a.tagName.toUpperCase();if(p(F,c)){var b;b=D.disabled||"disabled";var d=a[b];b=void 0===d&&p(E,b)?!1:d;a=b?!1:a.parentNode&&1==a.parentNode.nodeType&&"OPTGROUP"==c||"OPTION"==c?G(a.parentNode):!0}else a=!0;return a};var H=G,I=["_"],J=e;!(I[0]in J)&&J.execScript&&J.execScript("var "+I[0]);for(var K;I.length&&(K=I.shift());)!I.length&&void 0!==H?J[K]=H:J=J[K]?J[K]:J[K]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);} - -atom.isElementSelected = function(element, window){return function(){var f=!1,g=this;function h(a,b){function c(){}c.prototype=b.prototype;a.d=b.prototype;a.prototype=new c};function i(a,b){for(var c=1;c(0==C[1].length? 0:parseInt(C[1],10))?1:0)||((0==B[2].length)<(0==C[2].length)?-1:(0==B[2].length)>(0==C[2].length)?1:0)||(B[2]C[2]?1:0)}while(0==s)}n["1.9.1"]=0<=s};var D={SCRIPT:1,STYLE:1,HEAD:1,IFRAME:1,OBJECT:1},E={IMG:" ",BR:"\n"};function F(a,b,c){if(!(a.nodeName in D))if(3==a.nodeType)c?b.push((""+a.nodeValue).replace(/(\r\n|\r|\n)/g,"")):b.push(a.nodeValue);else if(a.nodeName in E)b.push(E[a.nodeName]);else for(a=a.firstChild;a;)F(a,b,c),a=a.nextSibling};(function(){var a=g.Components;if(!a)return f;try{if(!a.classes)return f}catch(b){return f}var c=a.classes,a=a.interfaces;c["@mozilla.org/xpcom/version-comparator;1"].getService(a.nsIVersionComparator);c["@mozilla.org/xre/app-info;1"].getService(a.nsIXULAppInfo);return!0})();function G(a,b,c,d,e){this.b=!!b;if(a&&(this.a=a))this.c="number"==typeof d?d:1!=this.a.nodeType?0:this.b?-1:1;this.depth=void 0!=e?e:this.c||0;this.b&&(this.depth*=-1)}h(G,function(){});G.prototype.a=null;G.prototype.c=0;h(function(a,b,c,d){G.call(this,a,b,0,null,d)},G);function H(a,b){return!!a&&1==a.nodeType&&(!b||a.tagName.toUpperCase()==b)}function I(a){return H(a,"OPTION")?!0:H(a,"INPUT")?(a=a.type.toLowerCase(),"checkbox"==a||"radio"==a):f}var J={"class":"className",readonly:"readOnly"},K=["checked","disabled","draggable","hidden"];function L(a){if(I(a)){if(!I(a))throw new o(15,"Element is not selectable");var b="selected",c=a.type&&a.type.toLowerCase();if("checkbox"==c||"radio"==c)b="checked";var c=b,d=J[c]||c,b=a[d],e;if(e=void 0===b){b:if("string"==typeof K)d="string"!=typeof d||1!=d.length?-1:K.indexOf(d,0);else{for(e=0;e(0==v[1].length? 0:parseInt(v[1],10))?1:0)||((0==l[2].length)<(0==v[2].length)?-1:(0==l[2].length)>(0==v[2].length)?1:0)||(l[2]v[2]?1:0)}while(0==b)}return b}function aa(a){return String(a).replace(/\-([a-z])/g,function(a,c){return c.toUpperCase()})};var s=Array.prototype;function t(a,b){for(var c=a.length,d=n(a)?a.split(""):a,e=0;e this.sessionCapabilities); + this.interactions = new Interactions(utils, () => this.sessionCapabilities); this.mm = globalMessageManager; this.listener = proxy.toListener(() => this.mm, this.sendAsync.bind(this)); @@ -349,6 +354,8 @@ GeckoDriver.prototype.startBrowser = function(win, isNewSession=false) { * True if this is the first time we're talking to this browser. */ GeckoDriver.prototype.whenBrowserStarted = function(win, isNewSession) { + utils.window = win; + try { let mm = win.window.messageManager; if (!isNewSession) { @@ -383,7 +390,7 @@ GeckoDriver.prototype.whenBrowserStarted = function(win, isNewSession) { */ GeckoDriver.prototype.getVisibleText = function(el, lines) { try { - if (atom.isElementDisplayed(el, this.getCurrentWindow())) { + if (utils.isElementDisplayed(el)) { if (el.value) { lines.push(el.value); } @@ -778,6 +785,7 @@ GeckoDriver.prototype.createExecuteSandbox = function(win, mn, sandboxName) { let sb = new Cu.Sandbox(principal, {sandboxPrototype: win, wantXrays: false, sandboxName: ""}); sb.global = sb; + sb.testUtils = utils; sb.proto = win; mn.exports.forEach(function(fn) { @@ -1583,6 +1591,7 @@ GeckoDriver.prototype.switchToWindow = function(cmd, resp) { yield browserListening; } } else { + utils.window = found.win; this.curBrowser = this.browsers[found.outerId]; if ("tabIndex" in found) { @@ -2012,7 +2021,7 @@ GeckoDriver.prototype.getElementAttribute = function(cmd, resp) { case Context.CHROME: let win = this.getCurrentWindow(); let el = this.curBrowser.elementManager.getKnownElement(id, {frame: win}); - resp.body.value = atom.getElementAttribute(el, name, this.getCurrentWindow()); + resp.body.value = utils.getElementAttribute(el, name); break; case Context.CONTENT: @@ -2788,11 +2797,11 @@ GeckoDriver.prototype.sendKeysToDialog = function(cmd, resp) { } let win = this.dialog.window ? this.dialog.window : this.getCurrentWindow(); - event.sendKeysToElement( - cmd.parameters.value, + utils.sendKeysToElement( + win, loginTextbox, - {ignoreVisibility: true}, - win); + cmd.parameters.value, + true /* ignore visibility check */); }; /** @@ -3064,7 +3073,7 @@ var BrowserObj = function(win, driver) { this.pendingCommands = []; // we should have one FM per BO so that we can handle modals in each Browser - this.frameManager = new frame.Manager(driver); + this.frameManager = new FrameManager(driver); this.frameRegsPending = 0; // register all message listeners diff --git a/testing/marionette/element.js b/testing/marionette/elements.js similarity index 86% rename from testing/marionette/element.js rename to testing/marionette/elements.js index 21e55d70a97..3f9eaf91ed7 100644 --- a/testing/marionette/element.js +++ b/testing/marionette/elements.js @@ -2,11 +2,8 @@ * 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/. */ -"use strict"; +let {classes: Cc, interfaces: Ci, utils: Cu} = Components; -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("chrome://marionette/content/atom.js"); Cu.import("chrome://marionette/content/error.js"); /** @@ -302,7 +299,7 @@ ElementManager.prototype = { * as its members. */ applyNamedArgs: function EM_applyNamedArgs(args) { - let namedArgs = {}; + namedArgs = {}; args.forEach(function(arg) { if (arg && typeof(arg['__marionetteArgs']) === 'object') { for (let prop in arg['__marionetteArgs']) { @@ -595,113 +592,10 @@ ElementManager.prototype = { } return elements; }, -}; +} this.elements = {}; - elements.generateUUID = function() { let uuid = uuidGen.generateUUID().toString(); return uuid.substring(1, uuid.length - 1); }; - -/** - * This function generates a pair of coordinates relative to the viewport - * given a target element and coordinates relative to that element's - * top-left corner. - * - * @param {Node} node - * Target node. - * @param {number=} x - * Horizontal offset relative to target. Defaults to the centre of - * the target's bounding box. - * @param {number=} y - * Vertical offset relative to target. Defaults to the centre of - * the target's bounding box. - */ -// TODO(ato): Replicated from listener.js for the time being -elements.coordinates = function(node, x = undefined, y = undefined) { - let box = node.getBoundingClientRect(); - if (!x) { - x = box.width / 2.0; - } - if (!y) { - y = box.height / 2.0; - } - return { - x: box.left + x, - y: box.top + y, - }; -} - -/** - * This function returns true if the node is in the viewport. - * - * @param {Element} element - * Target element. - * @param {number=} x - * Horizontal offset relative to target. Defaults to the centre of - * the target's bounding box. - * @param {number=} y - * Vertical offset relative to target. Defaults to the centre of - * the target's bounding box. - */ -elements.inViewport = function(el, x = undefined, y = undefined) { - let win = el.ownerDocument.defaultView; - let c = elements.coordinates(el, x, y); - let vp = { - top: win.pageYOffset, - left: win.pageXOffset, - bottom: (win.pageYOffset + win.innerHeight), - right: (win.pageXOffset + win.innerWidth) - }; - - return (vp.left <= c.x + win.pageXOffset && - c.x + win.pageXOffset <= vp.right && - vp.top <= c.y + win.pageYOffset && - c.y + win.pageYOffset <= vp.bottom); -}; - -/** - * This function throws the visibility of the element error if the element is - * not displayed or the given coordinates are not within the viewport. - * - * @param {Element} element - * Element to check if visible. - * @param {Window} window - * Window object. - * @param {number=} x - * Horizontal offset relative to target. Defaults to the centre of - * the target's bounding box. - * @param {number=} y - * Vertical offset relative to target. Defaults to the centre of - * the target's bounding box. - */ -elements.checkVisible = function(el, win, x = undefined, y = undefined) { - // Bug 1094246: Webdriver's isShown doesn't work with content xul - let ns = atom.getElementAttribute(el, "namespaceURI", win); - if (ns.indexOf("there.is.only.xul") < 0 && - !atom.isElementDisplayed(el, win)) { - return false; - } - - if (el.tagName.toLowerCase() == "body") { - return true; - } - - if (!elements.inViewport(el, x, y)) { - if (el.scrollIntoView) { - el.scrollIntoView(false); - if (!elements.inViewport(el)) { - return false; - } - } else { - return false; - } - } - return true; -}; - -elements.isXULElement = function(el) { - let ns = atom.getElementAttribute(el, "namespaceURI"); - return ns.indexOf("there.is.only.xul") >= 0; -}; diff --git a/testing/marionette/error.js b/testing/marionette/error.js index 01a31d49813..fb00c40b2b1 100644 --- a/testing/marionette/error.js +++ b/testing/marionette/error.js @@ -6,7 +6,7 @@ const {interfaces: Ci, utils: Cu} = Components; -const ERRORS = [ +const errors = [ "ElementNotAccessibleError", "ElementNotVisibleError", "InvalidArgumentError", @@ -29,21 +29,10 @@ const ERRORS = [ "WebDriverError", ]; -this.EXPORTED_SYMBOLS = ["error"].concat(ERRORS); +this.EXPORTED_SYMBOLS = ["error"].concat(errors); this.error = {}; -error.BuiltinErrors = { - Error: 0, - EvalError: 1, - InternalError: 2, - RangeError: 3, - ReferenceError: 4, - SyntaxError: 5, - TypeError: 6, - URIError: 7, -}; - /** * Checks if obj is an instance of the Error prototype in a safe manner. * Prefer using this over using instanceof since the Error prototype @@ -61,7 +50,7 @@ error.isError = function(val) { } else if (val instanceof Ci.nsIException) { return true; } else { - return Object.getPrototypeOf(val) in error.BuiltinErrors; + return Object.getPrototypeOf(val) == "Error"; } }; @@ -70,18 +59,7 @@ error.isError = function(val) { */ error.isWebDriverError = function(obj) { return error.isError(obj) && - ("name" in obj && ERRORS.indexOf(obj.name) >= 0); -}; - -/** - * Wraps an Error prototype in a WebDriverError. If the given error is - * already a WebDriverError, this is effectively a no-op. - */ -error.wrap = function(err) { - if (error.isWebDriverError(err)) { - return err; - } - return new WebDriverError(`${err.name}: ${err.message}`, err.stack); + ("name" in obj && errors.indexOf(obj.name) >= 0); }; /** @@ -162,12 +140,11 @@ error.fromJson = function(json) { * It should not be used directly, as it does not correspond to a real * error in the specification. */ -this.WebDriverError = function(msg, stack = undefined) { +this.WebDriverError = function(msg) { Error.call(this, msg); this.name = "WebDriverError"; this.message = msg; this.status = "webdriver error"; - this.stack = stack; }; WebDriverError.prototype = Object.create(Error.prototype); @@ -351,7 +328,7 @@ UnsupportedOperationError.prototype = Object.create(WebDriverError.prototype); const nameLookup = new Map(); const statusLookup = new Map(); -for (let s of ERRORS) { +for (let s of errors) { let cls = this[s]; let inst = new cls(); nameLookup.set(inst.name, cls); diff --git a/testing/marionette/event.js b/testing/marionette/event.js deleted file mode 100644 index 4abbeb32ff7..00000000000 --- a/testing/marionette/event.js +++ /dev/null @@ -1,954 +0,0 @@ -/* 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/. */ - -// Provides functionality for creating and sending DOM events. - -"use strict"; - -const {interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/Log.jsm"); -const logger = Log.repository.getLogger("Marionette"); - -Cu.import("chrome://marionette/content/element.js"); -Cu.import("chrome://marionette/content/error.js"); - -this.EXPORTED_SYMBOLS = ["event"]; - -// must be synchronised with nsIDOMWindowUtils -const COMPOSITION_ATTR_RAWINPUT = 0x02; -const COMPOSITION_ATTR_SELECTEDRAWTEXT = 0x03; -const COMPOSITION_ATTR_CONVERTEDTEXT = 0x04; -const COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT = 0x05; - -// TODO(ato): Document! -let seenEvent = false; - -function getDOMWindowUtils(win) { - if (!win) { - win = window; - } - - // this assumes we are operating in chrome space - return win.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); -} - -this.event = {}; - -event.MouseEvents = { - click: 0, - dblclick: 1, - mousedown: 2, - mouseup: 3, - mouseover: 4, - mouseout: 5, -}; - -event.Modifiers = { - shiftKey: 0, - ctrlKey: 1, - altKey: 2, - metaKey: 3, -}; - -/** - * Sends a mouse event to given target. - * - * @param {nsIDOMMouseEvent} mouseEvent - * Event to send. - * @param {(Element|string)} target - * Target of event. Can either be an Element or the ID of an element. - * @param {Window=} window - * Window object. Defaults to the current window. - * - * @throws {TypeError} - * If the event is unsupported. - */ -event.sendMouseEvent = function(mouseEvent, target, window = undefined) { - if (event.MouseEvents.hasOwnProperty(mouseEvent.type)) { - throw new TypeError("Unsupported event type: " + mouseEvent.type); - } - - if (!(target instanceof Element)) { - target = window.document.getElementById(target); - } - - let ev = window.document.createEvent("MouseEvent"); - - let type = mouseEvent.type; - let view = window; - - let detail = mouseEvent.detail; - if (!detail) { - if (mouseEvent.type in ["click", "mousedown", "mouseup"]) { - detail = 1; - } else if (mouseEvent.type == "dblclick") { - detail = 2; - } else { - detail = 0; - } - } - - let screenX = mouseEvent.screenX || 0; - let screenY = mouseEvent.screenY || 0; - let clientX = mouseEvent.clientX || 0; - let clientY = mouseEvent.clientY || 0; - let ctrlKey = mouseEvent.ctrlKey || false; - let altKey = mouseEvent.altKey || false; - let shiftKey = mouseEvent.shiftKey || false; - let metaKey = mouseEvent.metaKey || false; - let button = mouseEvent.button || 0; - let relatedTarget = mouseEvent.relatedTarget || null; - - ev.initMouseEvent( - mouseEvent.type, - /* canBubble */ true, - /* cancelable */ true, - view, - detail, - screenX, - screenY, - clientX, - clientY, - ctrlKey, - altKey, - shiftKey, - metaKey, - button, - relatedTarget); -}; - -/** - * Send character to the currently focused element. - * - * This function handles casing of characters (sends the right charcode, - * and sends a shift key for uppercase chars). No other modifiers are - * handled at this point. - * - * For now this method only works for English letters (lower and upper - * case) and the digits 0-9. - */ -event.sendChar = function(char, window = undefined) { - // DOM event charcodes match ASCII (JS charcodes) for a-zA-Z0-9 - let hasShift = (char == char.toUpperCase()); - event.synthesizeKey(char, {shiftKey: hasShift}, window); -}; - -/** - * Send string to the focused element. - * - * For now this method only works for English letters (lower and upper - * case) and the digits 0-9. - */ -event.sendString = function(string, window = undefined) { - for (let i = 0; i < string.length; ++i) { - event.sendChar(string.charAt(i), window); - } -}; - -/** - * Send the non-character key to the focused element. - * - * The name of the key should be the part that comes after "DOM_VK_" - * in the nsIDOMKeyEvent constant name for this key. No modifiers are - * handled at this point. - */ -event.sendKey = function(key, window = undefined) { - let keyName = "VK_" + key.toUpperCase(); - event.synthesizeKey(keyName, {shiftKey: false}, window); -}; - -// TODO(ato): Unexpose this when action.Chain#emitMouseEvent -// no longer emits its own events -event.parseModifiers_ = function(event) { - let mval = 0; - if (event.shiftKey) { - mval |= Ci.nsIDOMNSEvent.SHIFT_MASK; - } - if (event.ctrlKey) { - mval |= Ci.nsIDOMNSEvent.CONTROL_MASK; - } - if (event.altKey) { - mval |= Ci.nsIDOMNSEvent.ALT_MASK; - } - if (event.metaKey) { - mval |= Ci.nsIDOMNSEvent.META_MASK; - } - if (event.accelKey) { - if (navigator.platform.indexOf("Mac") >= 0) { - mval |= Ci.nsIDOMNSEvent.META_MASK; - } else { - mval |= Ci.nsIDOMNSEvent.CONTROL_MASK; - } - } - return mval; -}; - -/** - * Synthesise a mouse event on a target. - * - * The actual client point is determined by taking the aTarget's client - * box and offseting it by offsetX and offsetY. This allows mouse clicks - * to be simulated by calling this method. - * - * If the type is specified, an mouse event of that type is - * fired. Otherwise, a mousedown followed by a mouse up is performed. - * - * @param {Element} element - * Element to click. - * @param {number} offsetX - * Horizontal offset to click from the target's bounding box. - * @param {number} offsetY - * Vertical offset to click from the target's bounding box. - * @param {Object.} opts - * Object which may contain the properties "shiftKey", "ctrlKey", - * "altKey", "metaKey", "accessKey", "clickCount", "button", and - * "type". - * @param {Window=} window - * Window object. Defaults to the current window. - */ -event.synthesizeMouse = function( - element, offsetX, offsetY, opts, window = undefined) { - let rect = element.getBoundingClientRect(); - event.synthesizeMouseAtPoint( - rect.left + offsetX, rect.top + offsetY, opts, window); -}; - -/* - * Synthesize a mouse event at a particular point in a window. - * - * If the type of the event is specified, a mouse event of that type is - * fired. Otherwise, a mousedown followed by a mouse up is performed. - * - * @param {number} left - * CSS pixels from the left document margin. - * @param {number} top - * CSS pixels from the top document margin. - * @param {Object.} event - * Object which may contain the properties "shiftKey", "ctrlKey", - * "altKey", "metaKey", "accessKey", "clickCount", "button", and - * "type". - * @param {Window=} window - * Window object. Defaults to the current window. - */ -event.synthesizeMouseAtPoint = function( - left, top, opts, window = undefined) { - - let domutils = getDOMWindowUtils(window); - - let button = event.button || 0; - let clickCount = event.clickCount || 1; - let modifiers = event.parseModifiers_(event); - - if (("type" in event) && event.type) { - domutils.sendMouseEvent( - event.type, left, top, button, clickCount, modifiers); - } else { - domutils.sendMouseEvent( - "mousedown", left, top, button, clickCount, modifiers); - domutils.sendMouseEvent( - "mouseup", left, top, button, clickCount, modifiers); - } -}; - -/** - * Call event.synthesizeMouse with coordinates at the centre of the - * target. - */ -event.synthesizeMouseAtCenter = function(element, event, window) { - let rect = element.getBoundingClientRect(); - event.synthesizeMouse( - element, - rect.width / 2, - rect.height / 2, - event, - window); -}; - -/** - * Synthesise a mouse scroll event on a target. - * - * The actual client point is determined by taking the target's client - * box and offseting it by |offsetX| and |offsetY|. - * - * If the |type| property is specified for the |event| argument, a mouse - * scroll event of that type is fired. Otherwise, DOMMouseScroll is used. - * - * If the |axis| is specified, it must be one of "horizontal" or - * "vertical". If not specified, "vertical" is used. - * - * |delta| is the amount to scroll by (can be positive or negative). - * It must be specified. - * - * |hasPixels| specifies whether kHasPixels should be set in the - * |scrollFlags|. - * - * |isMomentum| specifies whether kIsMomentum should be set in the - * |scrollFlags|. - * - * @param {Element} target - * @param {number} offsetY - * @param {number} offsetY - * @param {Object.} event - * Object which may contain the properties shiftKey, ctrlKey, altKey, - * metaKey, accessKey, button, type, axis, delta, and hasPixels. - * @param {Window=} window - * Window object. Defaults to the current window. - */ -event.synthesizeMouseScroll = function( - target, offsetX, offsetY, ev, window = undefined) { - - let domutils = getDOMWindowUtils(window); - - // see nsMouseScrollFlags in nsGUIEvent.h - const kIsVertical = 0x02; - const kIsHorizontal = 0x04; - const kHasPixels = 0x08; - const kIsMomentum = 0x40; - - let button = ev.button || 0; - let modifiers = event.parseModifiers_(ev); - - let rect = target.getBoundingClientRect(); - let left = rect.left; - let top = rect.top; - - let type = (("type" in ev) && ev.type) || "DOMMouseScroll"; - let axis = ev.axis || "vertical"; - let scrollFlags = (axis == "horizontal") ? kIsHorizontal : kIsVertical; - if (ev.hasPixels) { - scrollFlags |= kHasPixels; - } - if (ev.isMomentum) { - scrollFlags |= kIsMomentum; - } - - domutils.sendMouseScrollEvent( - type, - left + offsetX, - top + offsetY, - button, - scrollFlags, - ev.delta, - modifiers); -}; - -function computeKeyCodeFromChar_(char) { - if (char.length != 1) { - return 0; - } - - if (char >= "a" && char <= "z") { - return Ci.nsIDOMKeyEvent.DOM_VK_A + char.charCodeAt(0) - "a".charCodeAt(0); - } - if (char >= "A" && char <= "Z") { - return Ci.nsIDOMKeyEvent.DOM_VK_A + char.charCodeAt(0) - "A".charCodeAt(0); - } - if (char >= "0" && char <= "9") { - return Ci.nsIDOMKeyEvent.DOM_VK_0 + char.charCodeAt(0) - "0".charCodeAt(0); - } - - // returns US keyboard layout's keycode - switch (char) { - case "~": - case "`": - return Ci.nsIDOMKeyEvent.DOM_VK_BACK_QUOTE; - - case "!": - return Ci.nsIDOMKeyEvent.DOM_VK_1; - - case "@": - return Ci.nsIDOMKeyEvent.DOM_VK_2; - - case "#": - return Ci.nsIDOMKeyEvent.DOM_VK_3; - - case "$": - return Ci.nsIDOMKeyEvent.DOM_VK_4; - - case "%": - return Ci.nsIDOMKeyEvent.DOM_VK_5; - - case "^": - return Ci.nsIDOMKeyEvent.DOM_VK_6; - - case "&": - return Ci.nsIDOMKeyEvent.DOM_VK_7; - - case "*": - return Ci.nsIDOMKeyEvent.DOM_VK_8; - - case "(": - return Ci.nsIDOMKeyEvent.DOM_VK_9; - - case ")": - return Ci.nsIDOMKeyEvent.DOM_VK_0; - - case "-": - case "_": - return Ci.nsIDOMKeyEvent.DOM_VK_SUBTRACT; - - case "+": - case "=": - return Ci.nsIDOMKeyEvent.DOM_VK_EQUALS; - - case "{": - case "[": - return Ci.nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET; - - case "}": - case "]": - return Ci.nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET; - - case "|": - case "\\": - return Ci.nsIDOMKeyEvent.DOM_VK_BACK_SLASH; - - case ":": - case ";": - return Ci.nsIDOMKeyEvent.DOM_VK_SEMICOLON; - - case "'": - case "\"": - return Ci.nsIDOMKeyEvent.DOM_VK_QUOTE; - - case "<": - case ",": - return Ci.nsIDOMKeyEvent.DOM_VK_COMMA; - - case ">": - case ".": - return Ci.nsIDOMKeyEvent.DOM_VK_PERIOD; - - case "?": - case "/": - return Ci.nsIDOMKeyEvent.DOM_VK_SLASH; - - case "\n": - return Ci.nsIDOMKeyEvent.DOM_VK_RETURN; - - default: - return 0; - } -} - -/** - * Returns true if the given key should cause keypress event when widget - * handles the native key event. Otherwise, false. - * - * The key code should be one of consts of nsIDOMKeyEvent.DOM_VK_*, - * or a key name begins with "VK_", or a character. - */ -event.isKeypressFiredKey = function(key) { - if (typeof key == "string") { - if (key.indexOf("VK_") === 0) { - key = Ci.nsIDOMKeyEvent["DOM_" + key]; - if (!key) { - throw new TypeError("Unknown key: " + key); - } - - // if key generates a character, it must cause a keypress event - } else { - return true; - } - } - - switch (key) { - case Ci.nsIDOMKeyEvent.DOM_VK_SHIFT: - case Ci.nsIDOMKeyEvent.DOM_VK_CONTROL: - case Ci.nsIDOMKeyEvent.DOM_VK_ALT: - case Ci.nsIDOMKeyEvent.DOM_VK_CAPS_LOCK: - case Ci.nsIDOMKeyEvent.DOM_VK_NUM_LOCK: - case Ci.nsIDOMKeyEvent.DOM_VK_SCROLL_LOCK: - case Ci.nsIDOMKeyEvent.DOM_VK_META: - return false; - - default: - return true; - } -}; - -/** - * Synthesise a key event. - * - * It is targeted at whatever would be targeted by an actual keypress - * by the user, typically the focused element. - * - * @param {string} key - * Key to synthesise. Should either be a character or a key code - * starting with "VK_" such as VK_RETURN. - * @param {Object.} event - * Object which may contain the properties shiftKey, ctrlKey, altKey, - * metaKey, accessKey, type. If the type is specified, a key event - * of that type is fired. Otherwise, a keydown, a keypress, and then a - * keyup event are fired in sequence. - * @param {Window=} window - * Window object. Defaults to the current window. - * - * @throws {TypeError} - * If unknown key. - */ -event.synthesizeKey = function(key, ev, window = undefined) { - let domutils = getDOMWindowUtils(window); - - let keyCode = 0; - let charCode = 0; - if (key.indexOf("VK_") === 0) { - keyCode = Ci.nsIDOMKeyEvent["DOM_" + key]; - if (!keyCode) { - throw new TypeError("Unknown key: " + key); - } - } else { - charCode = key.charCodeAt(0); - keyCode = computeKeyCodeFromChar_(key.charAt(0)); - } - - let modifiers = event.parseModifiers_(ev); - - // send keydown + (optional) keypress + keyup events - if (!("type" in ev) || !ev.type) { - let keyDownDefaultHappened = domutils.sendKeyEvent( - "keydown", keyCode, 0, modifiers); - if (event.isKeypressFiredKey(keyCode)) { - domutils.sendKeyEvent( - "keypress", - charCode ? 0 : keyCode, - charCode, - modifiers, - !keyDownDefaultHappened); - } - domutils.sendKeyEvent("keyup", keyCode, 0, modifiers); - - // send standalone keypress event - } else if (ev.type == "keypress") { - domutils.sendKeyEvent( - ev.type, - charCode ? 0 : keyCode, - charCode, - modifiers); - - // send other standalone event than keypress - } else { - domutils.sendKeyEvent(ev.type, keyCode, 0, modifiers); - } -}; - -/** - * Indicate that an event with an original target and type is expected - * to be fired, or not expected to be fired. - */ -function expectEvent_(expectedTarget, expectedEvent, testName) { - if (!expectedTarget || !expectedEvent) { - return null; - } - - seenEvent = false; - - let type; - if (expectedEvent.charAt(0) == "!") { - type = expectedEvent.substring(1); - } else { - type = expectedEvent; - } - - let handler = ev => { - let pass = (!seenEvent && ev.originalTarget == expectedTarget && ev.type == type); - is(pass, true, `${testName} ${type} event target ${seenEvent ? "twice" : ""}`); - seenEvent = true; - }; - - expectedTarget.addEventListener(type, handler, false); - return handler; -} - -/** - * Check if the event was fired or not. The provided event handler will - * be removed. - */ -function checkExpectedEvent_( - expectedTarget, expectedEvent, eventHandler, testName) { - - if (eventHandler) { - let expectEvent = (expectedEvent.charAt(0) != "!"); - let type = expectEvent; - if (!type) { - type = expectedEvent.substring(1); - } - expectedTarget.removeEventListener(type, eventHandler, false); - - let desc = `${type} event`; - if (!expectEvent) { - desc += " not"; - } - is(seenEvent, expectEvent, `${testName} ${desc} fired`); - } - - seenEvent = false; -} - -/** - * Similar to event.synthesizeMouse except that a test is performed to - * see if an event is fired at the right target as a result. - * - * To test that an event is not fired, use an expected type preceded by - * an exclamation mark, such as "!select". This might be used to test that - * a click on a disabled element doesn't fire certain events for instance. - * - * @param {Element} target - * Synthesise the mouse event on this target. - * @param {number} offsetX - * Horizontal offset from the target's bounding box. - * @param {number} offsetY - * Vertical offset from the target's bounding box. - * @param {Object.} ev - * Object which may contain the properties shiftKey, ctrlKey, altKey, - * metaKey, accessKey, type. - * @param {Element} expectedTarget - * Expected originalTarget of the event. - * @param {DOMEvent} expectedEvent - * Expected type of the event, such as "select". - * @param {string} testName - * Test name when outputing results. - * @param {Window=} window - * Window object. Defaults to the current window. - */ -event.synthesizeMouseExpectEvent = function( - target, offsetX, offsetY, ev, expectedTarget, expectedEvent, - testName, window = undefined) { - - let eventHandler = expectEvent_( - expectedTarget, - expectedEvent, - testName); - event.synthesizeMouse(target, offsetX, offsetY, ev, window); - checkExpectedEvent_( - expectedTarget, - expectedEvent, - eventHandler, - testName); -}; - -/** - * Similar to synthesizeKey except that a test is performed to see if - * an event is fired at the right target as a result. - * - * @param {string} key - * Key to synthesise. - * @param {Object.} ev - * Object which may contain the properties shiftKey, ctrlKey, altKey, - * metaKey, accessKey, type. - * @param {Element} expectedTarget - * Expected originalTarget of the event. - * @param {DOMEvent} expectedEvent - * Expected type of the event, such as "select". - * @param {string} testName - * Test name when outputing results - * @param {Window=} window - * Window object. Defaults to the current window. - * - * To test that an event is not fired, use an expected type preceded by an - * exclamation mark, such as "!select". - * - * aWindow is optional, and defaults to the current window object. - */ -event.synthesizeKeyExpectEvent = function( - key, ev, expectedTarget, expectedEvent, testName, - window = undefined) { - - let eventHandler = expectEvent_( - expectedTarget, - expectedEvent, - testName); - event.synthesizeKey(key, ev, window); - checkExpectedEvent_( - expectedTarget, - expectedEvent, - eventHandler, - testName); -}; - -/** - * Synthesize a composition event. - * - * @param {DOMEvent} ev - * The composition event information. This must have |type| - * member. The value must be "compositionstart", "compositionend" or - * "compositionupdate". And also this may have |data| and |locale| - * which would be used for the value of each property of the - * composition event. Note that the data would be ignored if the - * event type were "compositionstart". - * @param {Window=} window - * Window object. Defaults to the current window. - */ -event.synthesizeComposition = function(ev, window = undefined) { - let domutils = getDOMWindowUtils(window); - domutils.sendCompositionEvent(ev.type, ev.data || "", ev.locale || ""); -}; - -/** - * Synthesize a text event. - * - * The text event's information, this has |composition| and |caret| - * members. |composition| has |string| and |clauses| members. |clauses| - * must be array object. Each object has |length| and |attr|. - * And |caret| has |start| and |length|. See the following tree image. - * - * ev - * +-- composition - * | +-- string - * | +-- clauses[] - * | +-- length - * | +-- attr - * +-- caret - * +-- start - * +-- length - * - * Set the composition string to |composition.string|. Set its clauses - * information to the |clauses| array. - * - * When it's composing, set the each clauses' length - * to the |composition.clauses[n].length|. The sum - * of the all length values must be same as the length of - * |composition.string|. Set nsIDOMWindowUtils.COMPOSITION_ATTR_* to the - * |composition.clauses[n].attr|. - * - * When it's not composing, set 0 to the |composition.clauses[0].length| - * and |composition.clauses[0].attr|. - * - * Set caret position to the |caret.start|. Its offset from the start of - * the composition string. Set caret length to |caret.length|. If it's - * larger than 0, it should be wide caret. However, current nsEditor - * doesn't support wide caret, therefore, you should always set 0 now. - * - * @param {Object.} ev - * The text event's information, - * @param {Window=} window - * Window object. Defaults to the current window. - */ -event.synthesizeText = function(ev, window = undefined) { - let domutils = getDOMWindowUtils(window); - - if (!ev.composition || - !ev.composition.clauses || - !ev.composition.clauses[0]) { - return; - } - - let firstClauseLength = ev.composition.clauses[0].length; - let firstClauseAttr = ev.composition.clauses[0].attr; - let secondClauseLength = 0; - let secondClauseAttr = 0; - let thirdClauseLength = 0; - let thirdClauseAttr = 0; - if (ev.composition.clauses[1]) { - secondClauseLength = ev.composition.clauses[1].length; - secondClauseAttr = ev.composition.clauses[1].attr; - if (event.composition.clauses[2]) { - thirdClauseLength = ev.composition.clauses[2].length; - thirdClauseAttr = ev.composition.clauses[2].attr; - } - } - - let caretStart = -1; - let caretLength = 0; - if (event.caret) { - caretStart = ev.caret.start; - caretLength = ev.caret.length; - } - - domutils.sendTextEvent( - ev.composition.string, - firstClauseLength, - firstClauseAttr, - secondClauseLength, - secondClauseAttr, - thirdClauseLength, - thirdClauseAttr, - caretStart, - caretLength); -}; - -/** - * Synthesize a query selected text event. - * - * @param {Window=} - * Window object. Defaults to the current window. - * - * @return {(nsIQueryContentEventResult|null)} - * Event's result, or null if it failed. - */ -event.synthesizeQuerySelectedText = function(window = undefined) { - let domutils = getDOMWindowUtils(window); - return domutils.sendQueryContentEvent( - domutils.QUERY_SELECTED_TEXT, 0, 0, 0, 0); -}; - -/** - * Synthesize a selection set event. - * - * @param {number} offset - * Character offset. 0 means the first character in the selection - * root. - * @param {number} length - * Length of the text. If the length is too long, the extra length - * is ignored. - * @param {boolean} reverse - * If true, the selection is from |aOffset + aLength| to |aOffset|. - * Otherwise, from |aOffset| to |aOffset + aLength|. - * @param {Window=} window - * Window object. Defaults to the current window. - * - * @return True, if succeeded. Otherwise false. - */ -event.synthesizeSelectionSet = function( - offset, length, reverse, window = undefined) { - let domutils = getDOMWindowUtils(window); - return domutils.sendSelectionSetEvent(offset, length, reverse); -}; - -const KEYCODES_LOOKUP = { - "VK_SHIFT": "shiftKey", - "VK_CONTROL": "ctrlKey", - "VK_ALT": "altKey", - "VK_META": "metaKey", -}; - -const VIRTUAL_KEYCODE_LOOKUP = { - "\uE001": "VK_CANCEL", - "\uE002": "VK_HELP", - "\uE003": "VK_BACK_SPACE", - "\uE004": "VK_TAB", - "\uE005": "VK_CLEAR", - "\uE006": "VK_RETURN", - "\uE007": "VK_RETURN", - "\uE008": "VK_SHIFT", - "\uE009": "VK_CONTROL", - "\uE00A": "VK_ALT", - "\uE03D": "VK_META", - "\uE00B": "VK_PAUSE", - "\uE00C": "VK_ESCAPE", - "\uE00D": "VK_SPACE", // printable - "\uE00E": "VK_PAGE_UP", - "\uE00F": "VK_PAGE_DOWN", - "\uE010": "VK_END", - "\uE011": "VK_HOME", - "\uE012": "VK_LEFT", - "\uE013": "VK_UP", - "\uE014": "VK_RIGHT", - "\uE015": "VK_DOWN", - "\uE016": "VK_INSERT", - "\uE017": "VK_DELETE", - "\uE018": "VK_SEMICOLON", - "\uE019": "VK_EQUALS", - "\uE01A": "VK_NUMPAD0", - "\uE01B": "VK_NUMPAD1", - "\uE01C": "VK_NUMPAD2", - "\uE01D": "VK_NUMPAD3", - "\uE01E": "VK_NUMPAD4", - "\uE01F": "VK_NUMPAD5", - "\uE020": "VK_NUMPAD6", - "\uE021": "VK_NUMPAD7", - "\uE022": "VK_NUMPAD8", - "\uE023": "VK_NUMPAD9", - "\uE024": "VK_MULTIPLY", - "\uE025": "VK_ADD", - "\uE026": "VK_SEPARATOR", - "\uE027": "VK_SUBTRACT", - "\uE028": "VK_DECIMAL", - "\uE029": "VK_DIVIDE", - "\uE031": "VK_F1", - "\uE032": "VK_F2", - "\uE033": "VK_F3", - "\uE034": "VK_F4", - "\uE035": "VK_F5", - "\uE036": "VK_F6", - "\uE037": "VK_F7", - "\uE038": "VK_F8", - "\uE039": "VK_F9", - "\uE03A": "VK_F10", - "\uE03B": "VK_F11", - "\uE03C": "VK_F12", -}; - -function getKeyCode(c) { - if (c in VIRTUAL_KEYCODE_LOOKUP) { - return VIRTUAL_KEYCODE_LOOKUP[c]; - } - return c; -} - -event.sendKeyDown = function(keyToSend, modifiers, document) { - modifiers.type = "keydown"; - event.sendSingleKey(keyToSend, modifiers, document); - if (["VK_SHIFT", "VK_CONTROL", "VK_ALT", "VK_META"].indexOf(getKeyCode(keyToSend)) < 0) { - modifiers.type = "keypress"; - event.sendSingleKey(keyToSend, modifiers, document); - } - delete modifiers.type; -}; - -event.sendKeyUp = function(keyToSend, modifiers, window = undefined) { - modifiers.type = "keyup"; - event.sendSingleKey(keyToSend, modifiers, window); - delete modifiers.type; -}; - -event.sendSingleKey = function(keyToSend, modifiers, window = undefined) { - let keyCode = getKeyCode(keyToSend); - if (keyCode in KEYCODES_LOOKUP) { - let modName = KEYCODES_LOOKUP[keyCode]; - modifiers[modName] = !modifiers[modName]; - } else if (modifiers.shiftKey) { - keyCode = keyCode.toUpperCase(); - } - event.synthesizeKey(keyCode, modifiers, window); -}; - -/** - * Focus element and, if a textual input field and no previous selection - * state exists, move the caret to the end of the input field. - * - * @param {Element} element - * Element to focus. - */ -function focusElement(element) { - let t = element.type; - if (t && (t == "text" || t == "textarea")) { - if (element.selectionEnd == 0) { - let len = element.value.length; - element.setSelectionRange(len, len); - } - } - element.focus(); -} - -/** - * @param {Array.} keySequence - * @param {Element} element - * @param {Object.=} opts - * @param {Window=} window - */ -event.sendKeysToElement = function( - keySequence, element, opts = {}, window = undefined) { - - if (opts.ignoreVisibility || elements.checkVisible(element, window)) { - focusElement(element); - - // make Object. map - let modifiers = Object.create(event.Modifiers); - for (let modifier in event.Modifiers) { - modifiers[modifier] = false; - } - - let value = keySequence.join(""); - for (let i = 0; i < value.length; i++) { - let c = value.charAt(i); - event.sendSingleKey(c, modifiers, window); - } - - } else { - throw new ElementNotVisibleError("Element is not visible"); - } -}; diff --git a/testing/marionette/frame-manager.js b/testing/marionette/frame-manager.js new file mode 100644 index 00000000000..ae71f8ea835 --- /dev/null +++ b/testing/marionette/frame-manager.js @@ -0,0 +1,230 @@ +/* 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/. */ + +var {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +this.EXPORTED_SYMBOLS = ["FrameManager"]; + +var FRAME_SCRIPT = "chrome://marionette/content/listener.js"; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"] + .getService(Ci.mozIJSSubScriptLoader); + +//list of OOP frames that has the frame script loaded +var remoteFrames = []; + +/** + * An object representing a frame that Marionette has loaded a + * frame script in. + */ +function MarionetteRemoteFrame(windowId, frameId) { + this.windowId = windowId; //outerWindowId relative to main process + this.frameId = frameId; //actual frame relative to windowId's frames list + this.targetFrameId = this.frameId; //assigned FrameId, used for messaging +}; + +/** + * The FrameManager will maintain the list of Out Of Process (OOP) frames and will handle + * frame switching between them. + * It handles explicit frame switching (switchToFrame), and implicit frame switching, which + * occurs when a modal dialog is triggered in B2G. + * + */ +this.FrameManager = function FrameManager(server) { + //messageManager maintains the messageManager for the current process' chrome frame or the global message manager + this.currentRemoteFrame = null; //holds a member of remoteFrames (for an OOP frame) or null (for the main process) + this.previousRemoteFrame = null; //frame we'll need to restore once interrupt is gone + this.handledModal = false; //set to true when we have been interrupted by a modal + this.server = server; // a reference to the marionette server +}; + +FrameManager.prototype = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener, + Ci.nsISupportsWeakReference]), + + /** + * Receives all messages from content messageManager + */ + receiveMessage: function FM_receiveMessage(message) { + switch (message.name) { + case "MarionetteFrame:getInterruptedState": + // This will return true if the calling frame was interrupted by a modal dialog + if (this.previousRemoteFrame) { + let interruptedFrame = Services.wm.getOuterWindowWithId(this.previousRemoteFrame.windowId);//get the frame window of the interrupted frame + if (this.previousRemoteFrame.frameId != null) { + interruptedFrame = interruptedFrame.document.getElementsByTagName("iframe")[this.previousRemoteFrame.frameId]; //find the OOP frame + } + //check if the interrupted frame is the same as the calling frame + if (interruptedFrame.src == message.target.src) { + return {value: this.handledModal}; + } + } + else if (this.currentRemoteFrame == null) { + // we get here if previousRemoteFrame and currentRemoteFrame are null, ie: if we're in a non-OOP process, or we haven't switched into an OOP frame, in which case, handledModal can't be set to true. + return {value: this.handledModal}; + } + return {value: false}; + case "MarionetteFrame:handleModal": + /* + * handleModal is called when we need to switch frames to the main process due to a modal dialog interrupt. + */ + // If previousRemoteFrame was set, that means we switched into a remote frame. + // If this is the case, then we want to switch back into the system frame. + // If it isn't the case, then we're in a non-OOP environment, so we don't need to handle remote frames + let isLocal = true; + if (this.currentRemoteFrame != null) { + isLocal = false; + this.removeMessageManagerListeners(this.currentRemoteFrame.messageManager.get()); + //store the previous frame so we can switch back to it when the modal is dismissed + this.previousRemoteFrame = this.currentRemoteFrame; + //by setting currentRemoteFrame to null, it signifies we're in the main process + this.currentRemoteFrame = null; + this.server.messageManager = Cc["@mozilla.org/globalmessagemanager;1"] + .getService(Ci.nsIMessageBroadcaster); + } + this.handledModal = true; + this.server.sendOk(this.server.command_id); + return {value: isLocal}; + case "MarionetteFrame:getCurrentFrameId": + if (this.currentRemoteFrame != null) { + return this.currentRemoteFrame.frameId; + } + } + }, + + getOopFrame: function FM_getOopFrame(winId, frameId) { + // get original frame window + let outerWin = Services.wm.getOuterWindowWithId(winId); + // find the OOP frame + let f = outerWin.document.getElementsByTagName("iframe")[frameId]; + return f; + }, + + getFrameMM: function FM_getFrameMM(winId, frameId) { + let oopFrame = this.getOopFrame(winId, frameId); + let mm = oopFrame.QueryInterface(Ci.nsIFrameLoaderOwner) + .frameLoader.messageManager; + return mm; + }, + + /** + * Switch to OOP frame. We're handling this here + * so we can maintain a list of remote frames. + */ + switchToFrame: function FM_switchToFrame(winId, frameId) { + let oopFrame = this.getOopFrame(winId, frameId); + let mm = this.getFrameMM(winId, frameId); + + // See if this frame already has our frame script loaded in it; + // if so, just wake it up. + for (let i = 0; i < remoteFrames.length; i++) { + let frame = remoteFrames[i]; + let frameMessageManager = frame.messageManager.get(); + try { + frameMessageManager.sendAsyncMessage("aliveCheck", {}); + } catch (e) { + if (e.result == Components.results.NS_ERROR_NOT_INITIALIZED) { + remoteFrames.splice(i--, 1); + continue; + } + } + if (frameMessageManager == mm) { + this.currentRemoteFrame = frame; + this.addMessageManagerListeners(mm); + + mm.sendAsyncMessage("Marionette:restart"); + return oopFrame.id; + } + } + + // If we get here, then we need to load the frame script in this frame, + // and set the frame's ChromeMessageSender as the active message manager + // the server will listen to. + this.addMessageManagerListeners(mm); + let aFrame = new MarionetteRemoteFrame(winId, frameId); + aFrame.messageManager = Cu.getWeakReference(mm); + remoteFrames.push(aFrame); + this.currentRemoteFrame = aFrame; + + mm.loadFrameScript(FRAME_SCRIPT, true, true); + + return oopFrame.id; + }, + + /* + * This function handles switching back to the frame that was interrupted by the modal dialog. + * This function gets called by the interrupted frame once the dialog is dismissed and the frame resumes its process + */ + switchToModalOrigin: function FM_switchToModalOrigin() { + //only handle this if we indeed switched out of the modal's originating frame + if (this.previousRemoteFrame != null) { + this.currentRemoteFrame = this.previousRemoteFrame; + this.addMessageManagerListeners(this.currentRemoteFrame.messageManager.get()); + } + this.handledModal = false; + }, + + /** + * Adds message listeners to the server, + * listening for messages from content frame scripts. + * It also adds a MarionetteFrame:getInterruptedState + * message listener to the FrameManager, + * so the frame manager's state can be checked by the frame. + * + * @param {nsIMessageListenerManager} mm + * The message manager object, typically + * ChromeMessageBroadcaster or ChromeMessageSender. + */ + addMessageManagerListeners: function FM_addMessageManagerListeners(mm) { + mm.addWeakMessageListener("Marionette:ok", this.server); + mm.addWeakMessageListener("Marionette:done", this.server); + mm.addWeakMessageListener("Marionette:error", this.server); + mm.addWeakMessageListener("Marionette:emitTouchEvent", this.server); + mm.addWeakMessageListener("Marionette:log", this.server); + mm.addWeakMessageListener("Marionette:runEmulatorCmd", this.server.emulator); + mm.addWeakMessageListener("Marionette:runEmulatorShell", this.server.emulator); + mm.addWeakMessageListener("Marionette:shareData", this.server); + mm.addWeakMessageListener("Marionette:switchToModalOrigin", this.server); + mm.addWeakMessageListener("Marionette:switchedToFrame", this.server); + mm.addWeakMessageListener("Marionette:getVisibleCookies", this.server); + mm.addWeakMessageListener("Marionette:register", this.server); + mm.addWeakMessageListener("Marionette:listenersAttached", this.server); + mm.addWeakMessageListener("Marionette:getFiles", this.server); + mm.addWeakMessageListener("MarionetteFrame:handleModal", this); + mm.addWeakMessageListener("MarionetteFrame:getCurrentFrameId", this); + mm.addWeakMessageListener("MarionetteFrame:getInterruptedState", this); + }, + + /** + * Removes listeners for messages from content frame scripts. + * We do not remove the MarionetteFrame:getInterruptedState + * or the Marionette:switchToModalOrigin message listener, + * because we want to allow all known frames to contact the frame manager + * so that it can check if it was interrupted, and if so, + * it will call switchToModalOrigin when its process gets resumed. + * + * @param {nsIMessageListenerManager} mm + * The message manager object, typically + * ChromeMessageBroadcaster or ChromeMessageSender. + */ + removeMessageManagerListeners: function FM_removeMessageManagerListeners(mm) { + mm.removeWeakMessageListener("Marionette:ok", this.server); + mm.removeWeakMessageListener("Marionette:done", this.server); + mm.removeWeakMessageListener("Marionette:error", this.server); + mm.removeWeakMessageListener("Marionette:log", this.server); + mm.removeWeakMessageListener("Marionette:shareData", this.server); + mm.removeWeakMessageListener("Marionette:runEmulatorCmd", this.server.emulator); + mm.removeWeakMessageListener("Marionette:runEmulatorShell", this.server.emulator); + mm.removeWeakMessageListener("Marionette:switchedToFrame", this.server); + mm.removeWeakMessageListener("Marionette:getVisibleCookies", this.server); + mm.removeWeakMessageListener("Marionette:listenersAttached", this.server); + mm.removeWeakMessageListener("Marionette:register", this.server); + mm.removeWeakMessageListener("Marionette:getFiles", this.server); + mm.removeWeakMessageListener("MarionetteFrame:handleModal", this); + mm.removeWeakMessageListener("MarionetteFrame:getCurrentFrameId", this); + } +}; diff --git a/testing/marionette/frame.js b/testing/marionette/frame.js deleted file mode 100644 index de1614934df..00000000000 --- a/testing/marionette/frame.js +++ /dev/null @@ -1,264 +0,0 @@ -/* 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/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -this.EXPORTED_SYMBOLS = ["frame"]; - -this.frame = {}; - -const FRAME_SCRIPT = "chrome://marionette/content/listener.js"; - -// list of OOP frames that has the frame script loaded -var remoteFrames = []; - -/** - * An object representing a frame that Marionette has loaded a - * frame script in. - */ -frame.RemoteFrame = function(windowId, frameId) { - // outerWindowId relative to main process - this.windowId = windowId; - // actual frame relative to the windowId's frames list - this.frameId = frameId; - // assigned frame ID, used for messaging - this.targetFrameId = this.frameId; - // list of OOP frames that has the frame script loaded - this.remoteFrames = []; -}; - -/** - * The FrameManager will maintain the list of Out Of Process (OOP) - * frames and will handle frame switching between them. - * - * It handles explicit frame switching (switchToFrame), and implicit - * frame switching, which occurs when a modal dialog is triggered in B2G. - * - * @param {GeckoDriver} driver - * Reference to the driver instance. - */ -frame.Manager = class { - constructor(driver) { - // messageManager maintains the messageManager - // for the current process' chrome frame or the global message manager - - // holds a member of the remoteFrames (for an OOP frame) - // or null (for the main process) - this.currentRemoteFrame = null; - // frame we'll need to restore once interrupt is gone - this.previousRemoteFrame = null; - // set to true when we have been interrupted by a modal - this.handledModal = false; - this.driver = driver; - } - - /** - * Receives all messages from content messageManager. - */ - receiveMessage(message) { - switch (message.name) { - case "MarionetteFrame:getInterruptedState": - // this will return true if the calling frame was interrupted by a modal dialog - if (this.previousRemoteFrame) { - // get the frame window of the interrupted frame - let interruptedFrame = Services.wm.getOuterWindowWithId( - this.previousRemoteFrame.windowId); - - if (this.previousRemoteFrame.frameId !== null) { - // find OOP frame - let iframes = interruptedFrame.document.getElementsByTagName("iframe"); - interruptedFrame = iframes[this.previousRemoteFrame.frameId]; - } - - // check if the interrupted frame is the same as the calling frame - if (interruptedFrame.src == message.target.src) { - return {value: this.handledModal}; - } - - // we get here if previousRemoteFrame and currentRemoteFrame are null, - // i.e. if we're in a non-OOP process, or we haven't switched into an OOP frame, - // in which case, handledModal can't be set to true - } else if (this.currentRemoteFrame === null) { - return {value: this.handledModal}; - } - return {value: false}; - - // handleModal is called when we need to switch frames to the main - // process due to a modal dialog interrupt - case "MarionetteFrame:handleModal": - // If previousRemoteFrame was set, that means we switched into a - // remote frame. If this is the case, then we want to switch back - // into the system frame. If it isn't the case, then we're in a - // non-OOP environment, so we don't need to handle remote frames. - let isLocal = true; - if (this.currentRemoteFrame !== null) { - isLocal = false; - this.removeMessageManagerListeners( - this.currentRemoteFrame.messageManager.get()); - - // store the previous frame so we can switch back to it when - // the modal is dismissed - this.previousRemoteFrame = this.currentRemoteFrame; - - // by setting currentRemoteFrame to null, - // it signifies we're in the main process - this.currentRemoteFrame = null; - this.driver.messageManager = Cc["@mozilla.org/globalmessagemanager;1"] - .getService(Ci.nsIMessageBroadcaster); - } - - this.handledModal = true; - this.driver.sendOk(this.driver.command_id); - return {value: isLocal}; - - case "MarionetteFrame:getCurrentFrameId": - if (this.currentRemoteFrame !== null) { - return this.currentRemoteFrame.frameId; - } - } - } - - getOopFrame(winId, frameId) { - // get original frame window - let outerWin = Services.wm.getOuterWindowWithId(winId); - // find the OOP frame - let f = outerWin.document.getElementsByTagName("iframe")[frameId]; - return f; - } - - getFrameMM(winId, frameId) { - let oopFrame = this.getOopFrame(winId, frameId); - let mm = oopFrame.QueryInterface(Ci.nsIFrameLoaderOwner) - .frameLoader.messageManager; - return mm; - } - - /** - * Switch to OOP frame. We're handling this here so we can maintain - * a list of remote frames. - */ - switchToFrame(winId, frameId) { - let oopFrame = this.getOopFrame(winId, frameId); - let mm = this.getFrameMM(winId, frameId); - - // see if this frame already has our frame script loaded in it; - // if so, just wake it up - for (let i = 0; i < remoteFrames.length; i++) { - let f = remoteFrames[i]; - let fmm = f.messageManager.get(); - try { - fmm.sendAsyncMessage("aliveCheck", {}); - } catch (e) { - if (e.result == Cr.NS_ERROR_NOT_INITIALIZED) { - remoteFrames.splice(i--, 1); - continue; - } - } - - if (fmm == mm) { - this.currentRemoteFrame = f; - this.addMessageManagerListeners(mm); - - mm.sendAsyncMessage("Marionette:restart"); - return oopFrame.id; - } - } - - // if we get here, then we need to load the frame script in this frame, - // and set the frame's ChromeMessageSender as the active message manager - // the driver will listen to. - this.addMessageManagerListeners(mm); - let f = new frame.RemoteFrame(winId, frameId); - f.messageManager = Cu.getWeakReference(mm); - remoteFrames.push(f); - this.currentRemoteFrame = f; - - mm.loadFrameScript(FRAME_SCRIPT, true, true); - - return oopFrame.id; - } - - /* - * This function handles switching back to the frame that was - * interrupted by the modal dialog. It gets called by the interrupted - * frame once the dialog is dismissed and the frame resumes its process. - */ - switchToModalOrigin() { - // only handle this if we indeed switched out of the modal's - // originating frame - if (this.previousRemoteFrame !== null) { - this.currentRemoteFrame = this.previousRemoteFrame; - let mm = this.currentRemoteFrame.messageManager.get(); - this.addMessageManagerListeners(mm); - } - this.handledModal = false; - } - - /** - * Adds message listeners to the driver, listening for - * messages from content frame scripts. It also adds a - * MarionetteFrame:getInterruptedState message listener to the - * FrameManager, so the frame manager's state can be checked by the frame. - * - * @param {nsIMessageListenerManager} mm - * The message manager object, typically - * ChromeMessageBroadcaster or ChromeMessageSender. - */ - addMessageManagerListeners(mm) { - mm.addWeakMessageListener("Marionette:ok", this.driver); - mm.addWeakMessageListener("Marionette:done", this.driver); - mm.addWeakMessageListener("Marionette:error", this.driver); - mm.addWeakMessageListener("Marionette:emitTouchEvent", this.driver); - mm.addWeakMessageListener("Marionette:log", this.driver); - mm.addWeakMessageListener("Marionette:runEmulatorCmd", this.driver.emulator); - mm.addWeakMessageListener("Marionette:runEmulatorShell", this.driver.emulator); - mm.addWeakMessageListener("Marionette:shareData", this.driver); - mm.addWeakMessageListener("Marionette:switchToModalOrigin", this.driver); - mm.addWeakMessageListener("Marionette:switchedToFrame", this.driver); - mm.addWeakMessageListener("Marionette:getVisibleCookies", this.driver); - mm.addWeakMessageListener("Marionette:register", this.driver); - mm.addWeakMessageListener("Marionette:listenersAttached", this.driver); - mm.addWeakMessageListener("Marionette:getFiles", this.driver); - mm.addWeakMessageListener("MarionetteFrame:handleModal", this); - mm.addWeakMessageListener("MarionetteFrame:getCurrentFrameId", this); - mm.addWeakMessageListener("MarionetteFrame:getInterruptedState", this); - } - - /** - * Removes listeners for messages from content frame scripts. - * We do not remove the MarionetteFrame:getInterruptedState or - * the Marionette:switchToModalOrigin message listener, because we - * want to allow all known frames to contact the frame manager so - * that it can check if it was interrupted, and if so, it will call - * switchToModalOrigin when its process gets resumed. - * - * @param {nsIMessageListenerManager} mm - * The message manager object, typically - * ChromeMessageBroadcaster or ChromeMessageSender. - */ - removeMessageManagerListeners(mm) { - mm.removeWeakMessageListener("Marionette:ok", this.driver); - mm.removeWeakMessageListener("Marionette:done", this.driver); - mm.removeWeakMessageListener("Marionette:error", this.driver); - mm.removeWeakMessageListener("Marionette:log", this.driver); - mm.removeWeakMessageListener("Marionette:shareData", this.driver); - mm.removeWeakMessageListener("Marionette:runEmulatorCmd", this.driver.emulator); - mm.removeWeakMessageListener("Marionette:runEmulatorShell", this.driver.emulator); - mm.removeWeakMessageListener("Marionette:switchedToFrame", this.driver); - mm.removeWeakMessageListener("Marionette:getVisibleCookies", this.driver); - mm.removeWeakMessageListener("Marionette:listenersAttached", this.driver); - mm.removeWeakMessageListener("Marionette:register", this.driver); - mm.removeWeakMessageListener("Marionette:getFiles", this.driver); - mm.removeWeakMessageListener("MarionetteFrame:handleModal", this); - mm.removeWeakMessageListener("MarionetteFrame:getCurrentFrameId", this); - } -}; - -frame.Manager.prototype.QueryInterface = XPCOMUtils.generateQI( - [Ci.nsIMessageListener, Ci.nsISupportsWeakReference]); diff --git a/testing/marionette/interaction.js b/testing/marionette/interactions.js similarity index 60% rename from testing/marionette/interaction.js rename to testing/marionette/interactions.js index d2921f0840f..1679fb9e2f2 100644 --- a/testing/marionette/interaction.js +++ b/testing/marionette/interactions.js @@ -2,17 +2,15 @@ * 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/. */ -"use strict"; +/* global Components, Accessibility, ElementNotVisibleError, + InvalidElementStateError, Interactions */ -const {utils: Cu} = Components; +var {utils: Cu} = Components; -Cu.import("chrome://marionette/content/accessibility.js"); -Cu.import("chrome://marionette/content/atom.js"); -Cu.import("chrome://marionette/content/error.js"); -Cu.import("chrome://marionette/content/element.js"); -Cu.import("chrome://marionette/content/event.js"); +this.EXPORTED_SYMBOLS = ['Interactions']; -this.EXPORTED_SYMBOLS = ["Interactions"]; +Cu.import('chrome://marionette/content/accessibility.js'); +Cu.import('chrome://marionette/content/error.js'); /** * XUL elements that support disabled attribtue. @@ -74,11 +72,32 @@ const SELECTED_PROPERTY_SUPPORTED_XUL = new Set([ 'TAB' ]); +/** + * This function generates a pair of coordinates relative to the viewport given + * a target element and coordinates relative to that element's top-left corner. + * @param 'x', and 'y' are the relative to the target. + * If they are not specified, then the center of the target is used. + */ +function coordinates(target, x, y) { + let box = target.getBoundingClientRect(); + if (typeof x === 'undefined') { + x = box.width / 2; + } + if (typeof y === 'undefined') { + y = box.height / 2; + } + return { + x: box.left + x, + y: box.top + y + }; +} + /** * A collection of interactions available in marionette. * @type {Object} */ -this.Interactions = function(getCapabilies) { +this.Interactions = function(utils, getCapabilies) { + this.utils = utils; this.accessibility = new Accessibility(getCapabilies); }; @@ -96,25 +115,22 @@ Interactions.prototype = { */ clickElement(container, elementManager, id) { let el = elementManager.getKnownElement(id, container); - let visible = elements.checkVisible(el, container.frame); + let visible = this.checkVisible(container, el); if (!visible) { throw new ElementNotVisibleError('Element is not visible'); } return this.accessibility.getAccessibleObject(el, true).then(acc => { this.accessibility.checkVisible(acc, el, visible); - if (atom.isElementEnabled(el)) { + if (this.utils.isElementEnabled(el)) { this.accessibility.checkEnabled(acc, el, true, container); this.accessibility.checkActionable(acc, el); - if (elements.isXULElement(el)) { + if (this.isXULElement(el)) { el.click(); } else { let rects = el.getClientRects(); - let win = el.ownerDocument.defaultView; - event.synthesizeMouseAtPoint( - rects[0].left + rects[0].width / 2, - rects[0].top + rects[0].height / 2, - {} /* opts */, - win); + this.utils.synthesizeMouseAtPoint(rects[0].left + rects[0].width/2, + rects[0].top + rects[0].height/2, + {}, el.ownerDocument.defaultView); } } else { throw new InvalidElementStateError('Element is not enabled'); @@ -143,8 +159,8 @@ Interactions.prototype = { let el = elementManager.getKnownElement(id, container); return this.accessibility.getAccessibleObject(el, true).then(acc => { this.accessibility.checkActionable(acc, el); - event.sendKeysToElement( - value, el, {ignoreVisibility: false}, container.frame); + this.utils.sendKeysToElement( + container.frame, el, value, ignoreVisibility); }); }, @@ -164,7 +180,7 @@ Interactions.prototype = { */ isElementDisplayed(container, elementManager, id) { let el = elementManager.getKnownElement(id, container); - let displayed = atom.isElementDisplayed(el, container.frame); + let displayed = this.utils.isElementDisplayed(el); return this.accessibility.getAccessibleObject(el).then(acc => { this.accessibility.checkVisible(acc, el, displayed); return displayed; @@ -188,16 +204,16 @@ Interactions.prototype = { isElementEnabled(container, elementManager, id) { let el = elementManager.getKnownElement(id, container); let enabled = true; - if (elements.isXULElement(el)) { + if (this.isXULElement(el)) { // Check if XUL element supports disabled attribute if (DISABLED_ATTRIBUTE_SUPPORTED_XUL.has(el.tagName.toUpperCase())) { - let disabled = atom.getElementAttribute(el, 'disabled', container.frame); + let disabled = this.utils.getElementAttribute(el, 'disabled'); if (disabled && disabled === 'true') { enabled = false; } } } else { - enabled = atom.isElementEnabled(el, container.frame); + enabled = this.utils.isElementEnabled(el); } return this.accessibility.getAccessibleObject(el).then(acc => { this.accessibility.checkEnabled(acc, el, enabled, container); @@ -222,7 +238,7 @@ Interactions.prototype = { isElementSelected(container, elementManager, id) { let el = elementManager.getKnownElement(id, container); let selected = true; - if (elements.isXULElement(el)) { + if (this.isXULElement(el)) { let tagName = el.tagName.toUpperCase(); if (CHECKED_PROPERTY_SUPPORTED_XUL.has(tagName)) { selected = el.checked; @@ -231,11 +247,71 @@ Interactions.prototype = { selected = el.selected; } } else { - selected = atom.isElementSelected(el, container.frame); + selected = this.utils.isElementSelected(el); } return this.accessibility.getAccessibleObject(el).then(acc => { this.accessibility.checkSelected(acc, el, selected); return selected; }); }, + + /** + * This function throws the visibility of the element error if the element is + * not displayed or the given coordinates are not within the viewport. + * + * @param 'x', and 'y' are the coordinates relative to the target. + * If they are not specified, then the center of the target is used. + */ + checkVisible(container, el, x, y) { + // Bug 1094246 - Webdriver's isShown doesn't work with content xul + if (!this.isXULElement(el)) { + //check if the element is visible + let visible = this.utils.isElementDisplayed(el); + if (!visible) { + return false; + } + } + + if (el.tagName.toLowerCase() === 'body') { + return true; + } + if (!this.elementInViewport(container, el, x, y)) { + //check if scroll function exist. If so, call it. + if (el.scrollIntoView) { + el.scrollIntoView(false); + if (!this.elementInViewport(container, el)) { + return false; + } + } + else { + return false; + } + } + return true; + }, + + isXULElement(el) { + return this.utils.getElementAttribute(el, 'namespaceURI').indexOf( + 'there.is.only.xul') >= 0; + }, + + /** + * This function returns true if the given coordinates are in the viewport. + * @param 'x', and 'y' are the coordinates relative to the target. + * If they are not specified, then the center of the target is used. + */ + elementInViewport(container, el, x, y) { + let c = coordinates(el, x, y); + let win = container.frame; + let viewPort = { + top: win.pageYOffset, + left: win.pageXOffset, + bottom: win.pageYOffset + win.innerHeight, + right: win.pageXOffset + win.innerWidth + }; + return (viewPort.left <= c.x + win.pageXOffset && + c.x + win.pageXOffset <= viewPort.right && + viewPort.top <= c.y + win.pageYOffset && + c.y + win.pageYOffset <= viewPort.bottom); + } }; diff --git a/testing/marionette/jar.mn b/testing/marionette/jar.mn index 24d60837484..4cbb9585f14 100644 --- a/testing/marionette/jar.mn +++ b/testing/marionette/jar.mn @@ -6,15 +6,17 @@ marionette.jar: % content marionette %content/ content/server.js (server.js) content/driver.js (driver.js) - content/action.js (action.js) - content/interaction.js (interaction.js) + content/actions.js (actions.js) + content/interactions.js (interactions.js) content/accessibility.js (accessibility.js) content/listener.js (listener.js) - content/element.js (element.js) + content/elements.js (elements.js) + content/sendkeys.js (sendkeys.js) content/common.js (common.js) content/simpletest.js (simpletest.js) - content/frame.js (frame.js) - content/event.js (event.js) + content/frame-manager.js (frame-manager.js) + content/EventUtils.js (EventUtils.js) + content/ChromeUtils.js (ChromeUtils.js) content/error.js (error.js) content/message.js (message.js) content/dispatcher.js (dispatcher.js) @@ -23,7 +25,6 @@ marionette.jar: content/proxy.js (proxy.js) content/capture.js (capture.js) content/cookies.js (cookies.js) - content/atom.js (atom.js) #ifdef ENABLE_TESTS content/test.xul (client/marionette/chrome/test.xul) content/test2.xul (client/marionette/chrome/test2.xul) diff --git a/testing/marionette/listener.js b/testing/marionette/listener.js index cc11b3c8029..0cec32be334 100644 --- a/testing/marionette/listener.js +++ b/testing/marionette/listener.js @@ -5,28 +5,33 @@ var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; var uuidGen = Cc["@mozilla.org/uuid-generator;1"] - .getService(Ci.nsIUUIDGenerator); + .getService(Ci.nsIUUIDGenerator); var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"] - .getService(Ci.mozIJSSubScriptLoader); + .getService(Ci.mozIJSSubScriptLoader); loader.loadSubScript("chrome://marionette/content/simpletest.js"); loader.loadSubScript("chrome://marionette/content/common.js"); -Cu.import("chrome://marionette/content/action.js"); -Cu.import("chrome://marionette/content/atom.js"); +Cu.import("chrome://marionette/content/actions.js"); Cu.import("chrome://marionette/content/capture.js"); Cu.import("chrome://marionette/content/cookies.js"); -Cu.import("chrome://marionette/content/element.js"); +Cu.import("chrome://marionette/content/elements.js"); Cu.import("chrome://marionette/content/error.js"); -Cu.import("chrome://marionette/content/event.js"); Cu.import("chrome://marionette/content/proxy.js"); -Cu.import("chrome://marionette/content/interaction.js"); +Cu.import("chrome://marionette/content/interactions.js"); Cu.import("resource://gre/modules/FileUtils.jsm"); Cu.import("resource://gre/modules/NetUtil.jsm"); Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +var utils = {}; +utils.window = content; +// Load Event/ChromeUtils for use with JS scripts: +loader.loadSubScript("chrome://marionette/content/EventUtils.js", utils); +loader.loadSubScript("chrome://marionette/content/ChromeUtils.js", utils); +loader.loadSubScript("chrome://marionette/content/atoms.js", utils); +loader.loadSubScript("chrome://marionette/content/sendkeys.js", utils); var marionetteLogObj = new MarionetteLogObj(); @@ -43,9 +48,9 @@ var elementManager = new ElementManager([]); // Holds session capabilities. var capabilities = {}; -var interactions = new Interactions(() => capabilities); +var interactions = new Interactions(utils, () => capabilities); -var actions = new action.Chain(checkForInterrupted); +var actions = new actions.Chain(utils, checkForInterrupted); var importedScripts = null; // Contains the last file input element that was the target of @@ -524,6 +529,7 @@ function createExecuteContentSandbox(win, timeout) { sandbox.window = win; sandbox.document = sandbox.window.document; sandbox.navigator = sandbox.window.navigator; + sandbox.testUtils = utils; sandbox.asyncTestCommandId = asyncTestCommandId; sandbox.marionette = mn; @@ -887,13 +893,67 @@ function coordinates(target, x, y) { return coords; } + +/** + * This function returns true if the given coordinates are in the viewport. + * @param 'x', and 'y' are the coordinates relative to the target. + * If they are not specified, then the center of the target is used. + */ +function elementInViewport(el, x, y) { + let c = coordinates(el, x, y); + let curFrame = curContainer.frame; + let viewPort = {top: curFrame.pageYOffset, + left: curFrame.pageXOffset, + bottom: (curFrame.pageYOffset + curFrame.innerHeight), + right:(curFrame.pageXOffset + curFrame.innerWidth)}; + return (viewPort.left <= c.x + curFrame.pageXOffset && + c.x + curFrame.pageXOffset <= viewPort.right && + viewPort.top <= c.y + curFrame.pageYOffset && + c.y + curFrame.pageYOffset <= viewPort.bottom); +} + +/** + * This function throws the visibility of the element error if the element is + * not displayed or the given coordinates are not within the viewport. + * @param 'x', and 'y' are the coordinates relative to the target. + * If they are not specified, then the center of the target is used. + */ +function checkVisible(el, x, y) { + // Bug 1094246 - Webdriver's isShown doesn't work with content xul + if (utils.getElementAttribute(el, "namespaceURI").indexOf("there.is.only.xul") == -1) { + //check if the element is visible + let visible = utils.isElementDisplayed(el); + if (!visible) { + return false; + } + } + + if (el.tagName.toLowerCase() === 'body') { + return true; + } + if (!elementInViewport(el, x, y)) { + //check if scroll function exist. If so, call it. + if (el.scrollIntoView) { + el.scrollIntoView(false); + if (!elementInViewport(el)) { + return false; + } + } + else { + return false; + } + } + return true; +} + + /** * Function that perform a single tap */ function singleTap(id, corx, cory) { let el = elementManager.getKnownElement(id, curContainer); // after this block, the element will be scrolled into view - let visible = elements.checkVisible(el, curContainer.frame, corx, cory); + let visible = checkVisible(el, corx, cory); if (!visible) { throw new ElementNotVisibleError("Element is not currently visible and may not be manipulated"); } @@ -1333,7 +1393,7 @@ function clickElement(id) { */ function getElementAttribute(id, name) { let el = elementManager.getKnownElement(id, curContainer); - return atom.getElementAttribute(el, name, curContainer.frame); + return utils.getElementAttribute(el, name); } /** @@ -1347,7 +1407,7 @@ function getElementAttribute(id, name) { */ function getElementText(id) { let el = elementManager.getKnownElement(id, curContainer); - return atom.getElementText(el, curContainer.frame); + return utils.getElementText(el); } /** @@ -1451,11 +1511,11 @@ function sendKeysToElement(msg) { // so pass the filename to driver.js, which in turn passes them back // to this frame script in receiveFiles. sendSyncMessage("Marionette:getFiles", - {value: p, command_id: command_id}); + {value: p, command_id: command_id}); } else { interactions.sendKeysToElement(curContainer, elementManager, id, val) - .then(() => sendOk(command_id)) - .catch(e => sendError(e, command_id)); + .then(() => sendOk(command_id)) + .catch(e => sendError(e, command_id)); } } @@ -1468,7 +1528,7 @@ function clearElement(id) { if (el.type == "file") { el.value = null; } else { - atom.clearElement(el, curContainer.frame); + utils.clearElement(el); } } catch (e) { // Bug 964738: Newer atoms contain status codes which makes wrapping diff --git a/testing/marionette/moz.build b/testing/marionette/moz.build index 2df34a120fa..9c0b3a39f60 100644 --- a/testing/marionette/moz.build +++ b/testing/marionette/moz.build @@ -2,7 +2,7 @@ # 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/. -DIRS += ["components"] +DIRS += ["components", "atoms"] JAR_MANIFESTS += ["jar.mn"] MARIONETTE_UNIT_MANIFESTS += ['client/marionette/tests/unit/unit-tests.ini'] diff --git a/testing/marionette/proxy.js b/testing/marionette/proxy.js index 0be8b35e9d7..1a294394f1f 100644 --- a/testing/marionette/proxy.js +++ b/testing/marionette/proxy.js @@ -171,8 +171,7 @@ proxy.AsyncMessageChannel = class { if (typeof obj == "undefined") { this.sendReply_(uuid, proxy.AsyncMessageChannel.ReplyType.Ok); } else if (error.isError(obj)) { - let err = error.wrap(obj); - let serr = error.toJson(err); + let serr = error.toJson(obj); this.sendReply_(uuid, proxy.AsyncMessageChannel.ReplyType.Error, serr); } else { this.sendReply_(uuid, proxy.AsyncMessageChannel.ReplyType.Value, obj); diff --git a/testing/marionette/sendkeys.js b/testing/marionette/sendkeys.js new file mode 100644 index 00000000000..2475fd7839a --- /dev/null +++ b/testing/marionette/sendkeys.js @@ -0,0 +1,165 @@ +/* + * Copyright 2007-2009 WebDriver committers + * Copyright 2007-2009 Google Inc. + * Portions copyright 2012 Software Freedom Conservancy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +Cu.import("chrome://marionette/content/error.js"); + +var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"] + .getService(Ci.mozIJSSubScriptLoader); + +var utils = {}; +loader.loadSubScript("chrome://marionette/content/EventUtils.js", utils); +loader.loadSubScript("chrome://marionette/content/ChromeUtils.js", utils); + +var keyModifierNames = { + "VK_SHIFT": 'shiftKey', + "VK_CONTROL": 'ctrlKey', + "VK_ALT": 'altKey', + "VK_META": 'metaKey' +}; + +var keyCodes = { + '\uE001': "VK_CANCEL", + '\uE002': "VK_HELP", + '\uE003': "VK_BACK_SPACE", + '\uE004': "VK_TAB", + '\uE005': "VK_CLEAR", + '\uE006': "VK_RETURN", + '\uE007': "VK_RETURN", + '\uE008': "VK_SHIFT", + '\uE009': "VK_CONTROL", + '\uE00A': "VK_ALT", + '\uE03D': "VK_META", + '\uE00B': "VK_PAUSE", + '\uE00C': "VK_ESCAPE", + '\uE00D': "VK_SPACE", // printable + '\uE00E': "VK_PAGE_UP", + '\uE00F': "VK_PAGE_DOWN", + '\uE010': "VK_END", + '\uE011': "VK_HOME", + '\uE012': "VK_LEFT", + '\uE013': "VK_UP", + '\uE014': "VK_RIGHT", + '\uE015': "VK_DOWN", + '\uE016': "VK_INSERT", + '\uE017': "VK_DELETE", + '\uE018': "VK_SEMICOLON", + '\uE019': "VK_EQUALS", + '\uE01A': "VK_NUMPAD0", + '\uE01B': "VK_NUMPAD1", + '\uE01C': "VK_NUMPAD2", + '\uE01D': "VK_NUMPAD3", + '\uE01E': "VK_NUMPAD4", + '\uE01F': "VK_NUMPAD5", + '\uE020': "VK_NUMPAD6", + '\uE021': "VK_NUMPAD7", + '\uE022': "VK_NUMPAD8", + '\uE023': "VK_NUMPAD9", + '\uE024': "VK_MULTIPLY", + '\uE025': "VK_ADD", + '\uE026': "VK_SEPARATOR", + '\uE027': "VK_SUBTRACT", + '\uE028': "VK_DECIMAL", + '\uE029': "VK_DIVIDE", + '\uE031': "VK_F1", + '\uE032': "VK_F2", + '\uE033': "VK_F3", + '\uE034': "VK_F4", + '\uE035': "VK_F5", + '\uE036': "VK_F6", + '\uE037': "VK_F7", + '\uE038': "VK_F8", + '\uE039': "VK_F9", + '\uE03A': "VK_F10", + '\uE03B': "VK_F11", + '\uE03C': "VK_F12" +}; + +function getKeyCode (c) { + if (c in keyCodes) { + return keyCodes[c]; + } + return c; +}; + +function sendKeyDown (keyToSend, modifiers, document) { + modifiers.type = "keydown"; + sendSingleKey(keyToSend, modifiers, document); + if (["VK_SHIFT", "VK_CONTROL", + "VK_ALT", "VK_META"].indexOf(getKeyCode(keyToSend)) == -1) { + modifiers.type = "keypress"; + sendSingleKey(keyToSend, modifiers, document); + } + delete modifiers.type; +} + +function sendKeyUp (keyToSend, modifiers, document) { + modifiers.type = "keyup"; + sendSingleKey(keyToSend, modifiers, document); + delete modifiers.type; +} + +function sendSingleKey (keyToSend, modifiers, document) { + let keyCode = getKeyCode(keyToSend); + if (keyCode in keyModifierNames) { + let modName = keyModifierNames[keyCode]; + modifiers[modName] = !modifiers[modName]; + } else if (modifiers.shiftKey) { + keyCode = keyCode.toUpperCase(); + } + utils.synthesizeKey(keyCode, modifiers, document); +} + +/** + * Focus element and, if a textual input field and no previous selection + * state exists, move the caret to the end of the input field. + * + * @param {Element} el + * Element to focus. + */ +function focusElement(el) { + let t = el.type; + if (t && (t == "text" || t == "textarea")) { + if (el.selectionEnd == 0) { + let len = el.value.length; + el.setSelectionRange(len, len); + } + } + el.focus(); +} + +function sendKeysToElement(document, element, keysToSend, ignoreVisibility) { + if (ignoreVisibility || checkVisible(element)) { + focusElement(element); + + let modifiers = { + shiftKey: false, + ctrlKey: false, + altKey: false, + metaKey: false + }; + let value = keysToSend.join(""); + for (var i = 0; i < value.length; i++) { + var c = value.charAt(i); + sendSingleKey(c, modifiers, document); + } + } else { + throw new ElementNotVisibleError("Element is not visible"); + } +}; diff --git a/testing/marionette/server.js b/testing/marionette/server.js index e4de2049862..492291d2bb3 100644 --- a/testing/marionette/server.js +++ b/testing/marionette/server.js @@ -15,12 +15,18 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("chrome://marionette/content/dispatcher.js"); Cu.import("chrome://marionette/content/driver.js"); -Cu.import("chrome://marionette/content/element.js"); +Cu.import("chrome://marionette/content/elements.js"); Cu.import("chrome://marionette/content/simpletest.js"); // Bug 1083711: Load transport.js as an SDK module instead of subscript loader.loadSubScript("resource://devtools/shared/transport/transport.js"); +// Preserve this import order: +var events = {}; +loader.loadSubScript("chrome://marionette/content/EventUtils.js", events); +loader.loadSubScript("chrome://marionette/content/ChromeUtils.js", events); +loader.loadSubScript("chrome://marionette/content/frame-manager.js"); + const logger = Log.repository.getLogger("Marionette"); this.EXPORTED_SYMBOLS = ["MarionetteServer"]; diff --git a/testing/marionette/test_error.js b/testing/marionette/test_error.js index c20b93aec51..2ee7c18996b 100644 --- a/testing/marionette/test_error.js +++ b/testing/marionette/test_error.js @@ -14,19 +14,6 @@ function notok(condition) { ok(!(condition)); } -add_test(function test_BuiltinErrors() { - ok("Error" in error.BuiltinErrors); - ok("EvalError" in error.BuiltinErrors); - ok("InternalError" in error.BuiltinErrors); - ok("RangeError" in error.BuiltinErrors); - ok("ReferenceError" in error.BuiltinErrors); - ok("SyntaxError" in error.BuiltinErrors); - ok("TypeError" in error.BuiltinErrors); - ok("URIError" in error.BuiltinErrors); - - run_next_test(); -}); - add_test(function test_isError() { notok(error.isError(null)); notok(error.isError([])); @@ -34,13 +21,6 @@ add_test(function test_isError() { ok(error.isError(new Components.Exception())); ok(error.isError(new Error())); - ok(error.isError(new EvalError())); - ok(error.isError(new InternalError())); - ok(error.isError(new RangeError())); - ok(error.isError(new ReferenceError())); - ok(error.isError(new SyntaxError())); - ok(error.isError(new TypeError())); - ok(error.isError(new URIError())); ok(error.isError(new WebDriverError())); ok(error.isError(new InvalidArgumentError())); @@ -50,13 +30,6 @@ add_test(function test_isError() { add_test(function test_isWebDriverError() { notok(error.isWebDriverError(new Components.Exception())); notok(error.isWebDriverError(new Error())); - notok(error.isWebDriverError(new EvalError())); - notok(error.isWebDriverError(new InternalError())); - notok(error.isWebDriverError(new RangeError())); - notok(error.isWebDriverError(new ReferenceError())); - notok(error.isWebDriverError(new SyntaxError())); - notok(error.isWebDriverError(new TypeError())); - notok(error.isWebDriverError(new URIError())); ok(error.isWebDriverError(new WebDriverError())); ok(error.isWebDriverError(new InvalidArgumentError())); @@ -64,21 +37,6 @@ add_test(function test_isWebDriverError() { run_next_test(); }); -add_test(function test_wrap() { - equal(error.wrap(new WebDriverError()).name, "WebDriverError"); - equal(error.wrap(new InvalidArgumentError()).name, "InvalidArgumentError"); - equal(error.wrap(new Error()).name, "WebDriverError"); - equal(error.wrap(new EvalError()).name, "WebDriverError"); - equal(error.wrap(new InternalError()).name, "WebDriverError"); - equal(error.wrap(new RangeError()).name, "WebDriverError"); - equal(error.wrap(new ReferenceError()).name, "WebDriverError"); - equal(error.wrap(new SyntaxError()).name, "WebDriverError"); - equal(error.wrap(new TypeError()).name, "WebDriverError"); - equal(error.wrap(new URIError()).name, "WebDriverError"); - - run_next_test(); -}); - add_test(function test_stringify() { equal("", error.stringify()); equal("", error.stringify("foo")); From c012d9ac306b495786793d0332eeb760843e34fd Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Mon, 1 Feb 2016 14:07:16 +0100 Subject: [PATCH 43/72] Bug 377052 - nsBaseURLParser::ParseURL doesn't handle spaces embedded in the scheme properly r=mcmanus --- netwerk/base/nsURLParsers.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/netwerk/base/nsURLParsers.cpp b/netwerk/base/nsURLParsers.cpp index a024174f04c..ac22ae7540d 100644 --- a/netwerk/base/nsURLParsers.cpp +++ b/netwerk/base/nsURLParsers.cpp @@ -62,17 +62,21 @@ nsBaseURLParser::ParseURL(const char *spec, int32_t specLen, const char *stop = nullptr; const char *colon = nullptr; const char *slash = nullptr; - const char *p; + const char *p = spec; uint32_t offset = 0; int32_t len = specLen; - for (p = spec; len && *p && !colon && !slash; ++p, --len) { - // skip leading whitespace - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') { - spec++; - specLen--; - offset++; - continue; - } + + // skip leading whitespace + while (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') { + spec++; + specLen--; + offset++; + + p++; + len--; + } + + for (; len && *p && !colon && !slash; ++p, --len) { switch (*p) { case ':': if (!colon) From 43aaf2a18d2759585cb632a409b539b4ed07d8fa Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Fri, 5 Feb 2016 14:43:45 +0100 Subject: [PATCH 44/72] Bug 241788 - mozilla::Tokenizer - token type for \n should whitespace if given in constructor r=honzab --- xpcom/ds/Tokenizer.cpp | 4 ++-- xpcom/tests/gtest/TestTokenizer.cpp | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/xpcom/ds/Tokenizer.cpp b/xpcom/ds/Tokenizer.cpp index 81d6490e3ba..6fa9ff56a59 100644 --- a/xpcom/ds/Tokenizer.cpp +++ b/xpcom/ds/Tokenizer.cpp @@ -260,12 +260,12 @@ Tokenizer::Parse(Token& aToken) const state = PARSE_WORD; } else if (IsNumber(*next)) { state = PARSE_INTEGER; + } else if (strchr(mWhitespaces, *next)) { // not UTF-8 friendly? + state = PARSE_WS; } else if (*next == '\r') { state = PARSE_CRLF; } else if (*next == '\n') { state = PARSE_LF; - } else if (strchr(mWhitespaces, *next)) { // not UTF-8 friendly? - state = PARSE_WS; } else { state = PARSE_CHAR; } diff --git a/xpcom/tests/gtest/TestTokenizer.cpp b/xpcom/tests/gtest/TestTokenizer.cpp index c98d8bcbf5e..019ffedf50e 100644 --- a/xpcom/tests/gtest/TestTokenizer.cpp +++ b/xpcom/tests/gtest/TestTokenizer.cpp @@ -526,6 +526,21 @@ TEST(Tokenizer, SkipWhites) EXPECT_TRUE(p.CheckEOF()); } +TEST(Tokenizer, SkipCustomWhites) +{ + Tokenizer p("Text1 \n\r\t.Text2 \n\r\t.", " \n\r\t."); + + EXPECT_TRUE(p.CheckWord("Text1")); + p.SkipWhites(); + EXPECT_TRUE(p.CheckWord("Text2")); + EXPECT_TRUE(p.CheckWhite()); + EXPECT_TRUE(p.CheckWhite()); + EXPECT_TRUE(p.CheckWhite()); + EXPECT_TRUE(p.CheckWhite()); + EXPECT_TRUE(p.CheckWhite()); + EXPECT_TRUE(p.CheckEOF()); +} + TEST(Tokenizer, IntegerReading) { #define INT_6_BITS 64U From 96799fea07e28b48a1db97bb2088ed00cd67f230 Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Fri, 5 Feb 2016 14:45:08 +0100 Subject: [PATCH 45/72] Bug 241788 - net_FilterURIString should filter \r\n\t from the entire URL r=honzab * net_ExtractURLScheme now uses mozilla::Tokenizer * net_FilterURIString also filters characters in the scheme now * removed startPos and endPos parameters for net_FilterURIString and introduced net_IsAbsoluteURL --- netwerk/base/nsIOService.cpp | 2 +- netwerk/base/nsStandardURL.cpp | 16 +- netwerk/base/nsURLHelper.cpp | 209 ++++++++---------- netwerk/base/nsURLHelper.h | 17 +- netwerk/protocol/http/Http2Stream.cpp | 2 +- .../res/SubstitutingProtocolHandler.cpp | 2 +- .../streamconv/converters/nsIndexedToHTML.cpp | 4 +- netwerk/test/unit/test_standardurl.js | 6 + 8 files changed, 121 insertions(+), 137 deletions(-) diff --git a/netwerk/base/nsIOService.cpp b/netwerk/base/nsIOService.cpp index a7860a4fdaf..349767ec060 100644 --- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -564,7 +564,7 @@ nsIOService::GetProtocolHandler(const char* scheme, nsIProtocolHandler* *result) NS_IMETHODIMP nsIOService::ExtractScheme(const nsACString &inURI, nsACString &scheme) { - return net_ExtractURLScheme(inURI, nullptr, nullptr, &scheme); + return net_ExtractURLScheme(inURI, scheme); } NS_IMETHODIMP diff --git a/netwerk/base/nsStandardURL.cpp b/netwerk/base/nsStandardURL.cpp index 9e9825f94d5..86ea6d62e4b 100644 --- a/netwerk/base/nsStandardURL.cpp +++ b/netwerk/base/nsStandardURL.cpp @@ -2867,20 +2867,8 @@ nsStandardURL::Init(uint32_t urlType, mOriginCharset = charset; } - if (baseURI) { - uint32_t start, end; - // pull out the scheme and where it ends - nsresult rv = net_ExtractURLScheme(spec, &start, &end, nullptr); - if (NS_SUCCEEDED(rv) && spec.Length() > end+2) { - nsACString::const_iterator slash; - spec.BeginReading(slash); - slash.advance(end+1); - // then check if // follows - // if it follows, aSpec is really absolute ... - // ignore aBaseURI in this case - if (*slash == '/' && *(++slash) == '/') - baseURI = nullptr; - } + if (baseURI && net_IsAbsoluteURL(spec)) { + baseURI = nullptr; } if (!baseURI) diff --git a/netwerk/base/nsURLHelper.cpp b/netwerk/base/nsURLHelper.cpp index 9871e05eca6..8a30c3719fb 100644 --- a/netwerk/base/nsURLHelper.cpp +++ b/netwerk/base/nsURLHelper.cpp @@ -14,6 +14,7 @@ #include "nsNetCID.h" #include "mozilla/Preferences.h" #include "prnetdb.h" +#include "mozilla/Tokenizer.h" using namespace mozilla; @@ -179,12 +180,12 @@ net_ParseFileURL(const nsACString &inURL, const nsPromiseFlatCString &flatURL = PromiseFlatCString(inURL); const char *url = flatURL.get(); - - uint32_t schemeBeg, schemeEnd; - rv = net_ExtractURLScheme(flatURL, &schemeBeg, &schemeEnd, nullptr); + + nsAutoCString scheme; + rv = net_ExtractURLScheme(flatURL, scheme); if (NS_FAILED(rv)) return rv; - if (strncmp(url + schemeBeg, "file", schemeEnd - schemeBeg) != 0) { + if (!scheme.EqualsLiteral("file")) { NS_ERROR("must be a file:// url"); return NS_ERROR_UNEXPECTED; } @@ -483,57 +484,55 @@ net_ResolveRelativePath(const nsACString &relativePath, // scheme fu //---------------------------------------------------------------------------- +#if !defined(MOZILLA_XPCOMRT_API) +static bool isAsciiAlpha(char c) { + return nsCRT::IsAsciiAlpha(c); +} + +static bool +net_IsValidSchemeChar(const char aChar) +{ + if (nsCRT::IsAsciiAlpha(aChar) || nsCRT::IsAsciiDigit(aChar) || + aChar == '+' || aChar == '.' || aChar == '-') { + return true; + } + return false; +} +#endif + /* Extract URI-Scheme if possible */ nsresult net_ExtractURLScheme(const nsACString &inURI, - uint32_t *startPos, - uint32_t *endPos, - nsACString *scheme) + nsACString& scheme) { - // search for something up to a colon, and call it the scheme - const nsPromiseFlatCString &flatURI = PromiseFlatCString(inURI); - const char* uri_start = flatURI.get(); - const char* uri = uri_start; +#if defined(MOZILLA_XPCOMRT_API) + NS_WARNING("net_ExtractURLScheme not implemented"); + return NS_ERROR_NOT_IMPLEMENTED; +#else + Tokenizer p(inURI, "\r\n\t"); - if (!uri) + while (p.CheckWhite() || p.CheckChar(' ')) { + // Skip leading whitespace + } + + p.Record(); + if (!p.CheckChar(isAsciiAlpha)) { + // First char must be alpha return NS_ERROR_MALFORMED_URI; - - // skip leading white space - while (nsCRT::IsAsciiSpace(*uri)) - uri++; - - uint32_t start = uri - uri_start; - if (startPos) { - *startPos = start; } - uint32_t length = 0; - char c; - while ((c = *uri++) != '\0') { - // First char must be Alpha - if (length == 0 && nsCRT::IsAsciiAlpha(c)) { - length++; - } - // Next chars can be alpha + digit + some special chars - else if (length > 0 && (nsCRT::IsAsciiAlpha(c) || - nsCRT::IsAsciiDigit(c) || c == '+' || - c == '.' || c == '-')) { - length++; - } - // stop if colon reached but not as first char - else if (c == ':' && length > 0) { - if (endPos) { - *endPos = start + length; - } - - if (scheme) - scheme->Assign(Substring(inURI, start, length)); - return NS_OK; - } - else - break; + while (p.CheckChar(net_IsValidSchemeChar) || p.CheckWhite()) { + // Skip valid scheme characters or \r\n\t } - return NS_ERROR_MALFORMED_URI; + + if (!p.CheckChar(':')) { + return NS_ERROR_MALFORMED_URI; + } + + p.Claim(scheme); + scheme.StripChars("\r\n\t"); + return NS_OK; +#endif } bool @@ -556,87 +555,73 @@ net_IsValidScheme(const char *scheme, uint32_t schemeLen) return true; } +bool +net_IsAbsoluteURL(const nsACString& uri) +{ +#if !defined(MOZILLA_XPCOMRT_API) + Tokenizer p(uri, "\r\n\t"); + + while (p.CheckWhite() || p.CheckChar(' ')) { + // Skip leading whitespace + } + + // First char must be alpha + if (!p.CheckChar(isAsciiAlpha)) { + return false; + } + + while (p.CheckChar(net_IsValidSchemeChar) || p.CheckWhite()) { + // Skip valid scheme characters or \r\n\t + } + if (!p.CheckChar(':')) { + return false; + } + p.SkipWhites(); + + if (!p.CheckChar('/')) { + return false; + } + p.SkipWhites(); + + if (p.CheckChar('/')) { + // aSpec is really absolute. Ignore aBaseURI in this case + return true; + } +#endif + return false; +} + bool net_FilterURIString(const char *str, nsACString& result) { NS_PRECONDITION(str, "Must have a non-null string!"); - bool writing = false; result.Truncate(); const char *p = str; - // Remove leading spaces, tabs, CR, LF if any. - while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') { - writing = true; - str = p + 1; - p++; - } - - // Don't strip from the scheme, because other code assumes everything - // up to the ':' is the scheme, and it's bad not to have it match. - // If there's no ':', strip. - bool found_colon = false; - const char *first = nullptr; + // Figure out if we need to filter anything. + bool writing = false; while (*p) { - switch (*p) { - case '\t': - case '\r': - case '\n': - if (found_colon) { - writing = true; - // append chars up to but not including *p - if (p > str) - result.Append(str, p - str); - str = p + 1; - } else { - // remember where the first \t\r\n was in case we find no scheme - if (!first) - first = p; - } - break; - - case ':': - found_colon = true; - break; - - case '/': - case '@': - if (!found_colon) { - // colon also has to precede / or @ to be a scheme - found_colon = true; // not really, but means ok to strip - if (first) { - // go back and replace - p = first; - continue; // process *p again - } - } - break; - - default: - break; + if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') { + writing = true; + break; } p++; - - // At end, if there was no scheme, and we hit a control char, fix - // it up now. - if (!*p && first != nullptr && !found_colon) { - // TRICKY - to avoid duplicating code, we reset the loop back - // to the point we found something to do - p = first; - // This also stops us from looping after we finish - found_colon = true; // so we'll replace \t\r\n - } } - // Remove trailing spaces if any - while (((p-1) >= str) && (*(p-1) == ' ')) { - writing = true; - p--; + if (!writing) { + // Nothing to strip or filter + return false; } - if (writing && p > str) - result.Append(str, p - str); + nsAutoCString temp; - return writing; + temp.Assign(str); + temp.Trim("\r\n\t "); + temp.StripChars("\r\n\t"); + + result.Assign(temp); + + return true; } #if defined(XP_WIN) diff --git a/netwerk/base/nsURLHelper.h b/netwerk/base/nsURLHelper.h index bc4dacf3652..8ec1406347a 100644 --- a/netwerk/base/nsURLHelper.h +++ b/netwerk/base/nsURLHelper.h @@ -79,18 +79,22 @@ nsresult net_ResolveRelativePath(const nsACString &relativePath, const nsACString &basePath, nsACString &result); +/** + * Check if a URL is absolute + * + * @param inURL URL spec + * @return true if the given spec represents an absolute URL + */ +bool net_IsAbsoluteURL(const nsACString& inURL); + /** * Extract URI-Scheme if possible * * @param inURI URI spec - * @param startPos start of scheme (may be null) - * @param endPos end of scheme; index of colon (may be null) * @param scheme scheme copied to this buffer on return (may be null) */ nsresult net_ExtractURLScheme(const nsACString &inURI, - uint32_t *startPos, - uint32_t *endPos, - nsACString *scheme = nullptr); + nsACString &scheme); /* check that the given scheme conforms to RFC 2396 */ bool net_IsValidScheme(const char *scheme, uint32_t schemeLen); @@ -109,8 +113,7 @@ inline bool net_IsValidScheme(const nsAFlatCString &scheme) * This function strips out all whitespace at the beginning and end of the URL * and strips out \r, \n, \t from the middle of the URL. This makes it safe to * call on things like javascript: urls or data: urls, where we may in fact run - * into whitespace that is not properly encoded. Note that stripping does not - * occur in the scheme portion itself. + * into whitespace that is not properly encoded. * * @param str the pointer to the string to filter. Must be non-null. * @param result the out param to write to if filtering happens diff --git a/netwerk/protocol/http/Http2Stream.cpp b/netwerk/protocol/http/Http2Stream.cpp index a366b251df3..40df0f262e4 100644 --- a/netwerk/protocol/http/Http2Stream.cpp +++ b/netwerk/protocol/http/Http2Stream.cpp @@ -344,7 +344,7 @@ nsresult Http2Stream::MakeOriginURL(const nsACString &origin, RefPtr &url) { nsAutoCString scheme; - nsresult rv = net_ExtractURLScheme(origin, nullptr, nullptr, &scheme); + nsresult rv = net_ExtractURLScheme(origin, scheme); NS_ENSURE_SUCCESS(rv, rv); return MakeOriginURL(scheme, origin, url); } diff --git a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp index 181aabd72a5..eb651058edf 100644 --- a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp +++ b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp @@ -54,7 +54,7 @@ SubstitutingURL::EnsureFile() return rv; nsAutoCString scheme; - rv = net_ExtractURLScheme(spec, nullptr, nullptr, &scheme); + rv = net_ExtractURLScheme(spec, scheme); if (NS_FAILED(rv)) return rv; diff --git a/netwerk/streamconv/converters/nsIndexedToHTML.cpp b/netwerk/streamconv/converters/nsIndexedToHTML.cpp index 20835551baf..b4c2ec9d106 100644 --- a/netwerk/streamconv/converters/nsIndexedToHTML.cpp +++ b/netwerk/streamconv/converters/nsIndexedToHTML.cpp @@ -760,8 +760,10 @@ nsIndexedToHTML::OnIndexAvailable(nsIRequest *aRequest, // for some protocols, we expect the location to be absolute. // if so, and if the location indeed appears to be a valid URI, then go // ahead and treat it like one. + + nsAutoCString scheme; if (mExpectAbsLoc && - NS_SUCCEEDED(net_ExtractURLScheme(loc, nullptr, nullptr, nullptr))) { + NS_SUCCEEDED(net_ExtractURLScheme(loc, scheme))) { // escape as absolute escFlags = esc_Forced | esc_AlwaysCopy | esc_Minimal; } diff --git a/netwerk/test/unit/test_standardurl.js b/netwerk/test/unit/test_standardurl.js index 0d914c7d57d..9d186efad5d 100644 --- a/netwerk/test/unit/test_standardurl.js +++ b/netwerk/test/unit/test_standardurl.js @@ -300,3 +300,9 @@ add_test(function test_hugeStringThrows() run_next_test(); }); + +add_test(function test_filterWhitespace() +{ + var url = stringToURL(" \r\n\th\nt\rt\tp://ex\r\n\tample.com/path\r\n\t/\r\n\tto the/fil\r\n\te.e\r\n\txt?que\r\n\try#ha\r\n\tsh \r\n\t "); + do_check_eq(url.spec, "http://example.com/path/to%20the/file.ext?query#hash"); +}); From 572168894f7ea53aabc1eff581e4af756635357d Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Fri, 5 Feb 2016 07:04:27 -0700 Subject: [PATCH 46/72] Bug 1245884 - Skip some layout/reftests/css-grid reftests on Android Debug only, for being too slow; r=me --- layout/reftests/css-grid/reftest.list | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/layout/reftests/css-grid/reftest.list b/layout/reftests/css-grid/reftest.list index 67e52d2a51e..0aeabc80514 100644 --- a/layout/reftests/css-grid/reftest.list +++ b/layout/reftests/css-grid/reftest.list @@ -77,15 +77,15 @@ fuzzy-if(winWidget,1,36) == grid-auto-min-sizing-definite-001.html grid-auto-min == grid-item-stretch-001.html grid-item-stretch-001-ref.html == grid-align-content-001.html grid-align-content-001-ref.html == grid-justify-content-001.html grid-justify-content-001-ref.html -== grid-justify-content-002.html grid-justify-content-002-ref.html -== grid-justify-content-003.html grid-justify-content-003-ref.html -== grid-column-gap-001.html grid-column-gap-001-ref.html +skip-if(Android&&isDebugBuild) == grid-justify-content-002.html grid-justify-content-002-ref.html # Bug 1245884 - slow +skip-if(Android&&isDebugBuild) == grid-justify-content-003.html grid-justify-content-003-ref.html # Bug 1245884 - slow +skip-if(Android&&isDebugBuild) == grid-column-gap-001.html grid-column-gap-001-ref.html # Bug 1245884 - slow == grid-column-gap-002.html grid-column-gap-002-ref.html == grid-column-gap-003.html grid-column-gap-003-ref.html == grid-row-gap-001.html grid-row-gap-001-ref.html -== grid-row-gap-002.html grid-row-gap-002-ref.html -== grid-row-gap-003.html grid-row-gap-003-ref.html -== grid-row-gap-004.html grid-row-gap-004-ref.html +skip-if(Android&&isDebugBuild) == grid-row-gap-002.html grid-row-gap-002-ref.html # Bug 1245884 - slow +skip-if(Android&&isDebugBuild) == grid-row-gap-003.html grid-row-gap-003-ref.html # Bug 1245884 - slow +skip-if(Android&&isDebugBuild) == grid-row-gap-004.html grid-row-gap-004-ref.html # Bug 1245884 - slow == grid-container-overflow-001.html grid-container-overflow-001-ref.html == grid-item-margin-left-auto-001.html grid-item-margin-left-auto-001-ref.html == grid-item-margin-left-auto-002.html grid-item-margin-left-auto-002-ref.html From d3d7b769664aabe66868b26013b7fec4e2d10d40 Mon Sep 17 00:00:00 2001 From: Andrew Halberstadt Date: Thu, 29 Oct 2015 15:01:44 -0400 Subject: [PATCH 47/72] Bug 1034290 - Use structured log output for test results in reftest, r=jmaher Structured logs bring many benefits. We can stop parsing the logs for magic strings, we can modify the format without breaking things, and we can stream results into systems like ActiveData. The structured logs originate primarily in reftest.js. StructuredLog.jsm is used to generate the JSON-based log stream. Finally OutputHandler in the python harness reads structured output from stdout, and formats it into human readable form. --- build/automation.py.in | 14 +- build/mobile/b2gautomation.py | 29 +- build/mobile/remoteautomation.py | 38 +-- layout/tools/reftest/Makefile.in | 1 + layout/tools/reftest/jar.mn | 1 + layout/tools/reftest/mach_commands.py | 2 - layout/tools/reftest/output.py | 144 +++++++++ layout/tools/reftest/reftest.js | 295 ++++++++---------- layout/tools/reftest/reftestcommandline.py | 7 +- layout/tools/reftest/remotereftest.py | 20 +- layout/tools/reftest/runreftest.py | 183 ++++------- layout/tools/reftest/runreftestb2g.py | 7 +- layout/tools/reftest/runreftestmulet.py | 39 +-- testing/modules/StructuredLog.jsm | 32 +- testing/mozbase/mozleak/mozleak/leaklog.py | 16 +- .../mozlog/mozlog/formatters/tbplformatter.py | 15 +- testing/mozbase/mozlog/mozlog/logtypes.py | 4 +- .../mozbase/mozlog/mozlog/structuredlog.py | 5 +- 18 files changed, 481 insertions(+), 371 deletions(-) create mode 100644 layout/tools/reftest/output.py diff --git a/build/automation.py.in b/build/automation.py.in index e92f1740ac1..c5f1ad9f417 100644 --- a/build/automation.py.in +++ b/build/automation.py.in @@ -396,7 +396,7 @@ class Automation(object): self.log.info("Can't trigger Breakpad, just killing process") self.killPid(processPID) - def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath): + def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath, outputHandler=None): """ Look for timeout or crashes and return the status after the process terminates """ stackFixerFunction = None didTimeout = False @@ -436,7 +436,12 @@ class Automation(object): while line != "" and not didTimeout: if stackFixerFunction: line = stackFixerFunction(line) - self.log.info(line.rstrip().decode("UTF-8", "ignore")) + + if outputHandler is None: + self.log.info(line.rstrip().decode("UTF-8", "ignore")) + else: + outputHandler(line) + if "TEST-START" in line and "|" in line: self.lastTestSeen = line.split("|")[1].strip() if not debuggerInfo and "TEST-UNEXPECTED-FAIL" in line and "Test timed out" in line: @@ -530,7 +535,7 @@ class Automation(object): debuggerInfo = None, symbolsPath = None, timeout = -1, maxTime = None, onLaunch = None, detectShutdownLeaks = False, screenshotOnFail=False, testPath=None, bisectChunk=None, - valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None): + valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None, outputHandler=None): """ Run the app, log the duration it took to execute, return the status code. Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds. @@ -579,7 +584,8 @@ class Automation(object): # app is launched. onLaunch() - status = self.waitForFinish(proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath) + status = self.waitForFinish(proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath, + outputHandler=outputHandler) self.log.info("INFO | automation.py | Application ran for: %s", str(datetime.now() - startTime)) # Do a final check for zombie child processes. diff --git a/build/mobile/b2gautomation.py b/build/mobile/b2gautomation.py index 75a93c6e08a..545e8bdd770 100644 --- a/build/mobile/b2gautomation.py +++ b/build/mobile/b2gautomation.py @@ -209,23 +209,31 @@ class B2GRemoteAutomation(Automation): return app, args def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, - debuggerInfo, symbolsPath): + debuggerInfo, symbolsPath, outputHandler=None): """ Wait for tests to finish (as evidenced by a signature string in logcat), or for a given amount of time to elapse with no output. """ timeout = timeout or 120 while True: - currentlog = proc.getStdoutLines(timeout) - if currentlog: - print currentlog + lines = proc.getStdoutLines(timeout) + if lines: + currentlog = '\n'.join(lines) + + if outputHandler: + for line in lines: + outputHandler(line) + else: + print(currentlog) + # Match the test filepath from the last TEST-START line found in the new # log content. These lines are in the form: # ... INFO TEST-START | /filepath/we/wish/to/capture.html\n testStartFilenames = re.findall(r"TEST-START \| ([^\s]*)", currentlog) if testStartFilenames: self.lastTestSeen = testStartFilenames[-1] - if hasattr(self, 'logFinish') and self.logFinish in currentlog: + if (outputHandler and outputHandler.suite_finished) or ( + hasattr(self, 'logFinish') and self.logFinish in currentlog): return 0 else: self.log.info("TEST-UNEXPECTED-FAIL | %s | application timed " @@ -434,11 +442,12 @@ class B2GRemoteAutomation(Automation): break # wait 'timeout' for any additional lines - try: - lines.append(self.queue.get(True, timeout)) - except Queue.Empty: - pass - return '\n'.join(lines) + if not lines: + try: + lines.append(self.queue.get(True, timeout)) + except Queue.Empty: + pass + return lines def wait(self, timeout=None): # this should never happen diff --git a/build/mobile/remoteautomation.py b/build/mobile/remoteautomation.py index c402031b3ae..bf9342c480a 100644 --- a/build/mobile/remoteautomation.py +++ b/build/mobile/remoteautomation.py @@ -95,7 +95,7 @@ class RemoteAutomation(Automation): return env - def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath): + def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath, outputHandler=None): """ Wait for tests to finish. If maxTime seconds elapse or no output is detected for timeout seconds, kill the process and fail the test. @@ -307,20 +307,21 @@ class RemoteAutomation(Automation): return pid def read_stdout(self): - """ Fetch the full remote log file using devicemanager and return just - the new log entries since the last call (as a list of messages or lines). + """ + Fetch the full remote log file using devicemanager, process them and + return whether there were any new log entries since the last call. """ if not self.dm.fileExists(self.proc): - return [] + return False try: newLogContent = self.dm.pullFile(self.proc, self.stdoutlen) except DMError: # we currently don't retry properly in the pullFile # function in dmSUT, so an error here is not necessarily # the end of the world - return [] + return False if not newLogContent: - return [] + return False self.stdoutlen += len(newLogContent) @@ -329,26 +330,27 @@ class RemoteAutomation(Automation): if testStartFilenames: self.lastTestSeen = testStartFilenames[-1] print newLogContent - return [newLogContent] + return True self.logBuffer += newLogContent lines = self.logBuffer.split('\n') - if not lines: - return - # We only keep the last (unfinished) line in the buffer - self.logBuffer = lines[-1] - del lines[-1] - messages = [] + if lines: + # We only keep the last (unfinished) line in the buffer + self.logBuffer = lines[-1] + del lines[-1] + + if not lines: + return False + for line in lines: # This passes the line to the logger (to be logged or buffered) # and returns a list of structured messages (dict) parsed_messages = self.messageLogger.write(line) for message in parsed_messages: - if message['action'] == 'test_start': + if isinstance(message, dict) and message.get('action') == 'test_start': self.lastTestSeen = message['test'] - messages += parsed_messages - return messages + return True @property def getLastTestSeen(self): @@ -374,10 +376,10 @@ class RemoteAutomation(Automation): # too long, only do it every 60 seconds if (not slowLog) or (timer % 60 == 0): startRead = datetime.datetime.now() - messages = self.read_stdout() + hasOutput = self.read_stdout() if (datetime.datetime.now() - startRead) > datetime.timedelta(seconds=5): slowLog = True - if messages: + if hasOutput: noOutputTimer = 0 time.sleep(interval) timer += interval diff --git a/layout/tools/reftest/Makefile.in b/layout/tools/reftest/Makefile.in index 07776f1e7ad..9b52b80e107 100644 --- a/layout/tools/reftest/Makefile.in +++ b/layout/tools/reftest/Makefile.in @@ -12,6 +12,7 @@ _HARNESS_FILES = \ $(srcdir)/runreftestb2g.py \ $(srcdir)/runreftestmulet.py \ $(srcdir)/gaia_lock_screen.js \ + $(srcdir)/output.py \ automation.py \ $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanager.py \ $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py \ diff --git a/layout/tools/reftest/jar.mn b/layout/tools/reftest/jar.mn index 8a38a910c5b..776e9f77c65 100644 --- a/layout/tools/reftest/jar.mn +++ b/layout/tools/reftest/jar.mn @@ -2,6 +2,7 @@ reftest.jar: % content reftest %content/ * content/reftest-content.js (reftest-content.js) content/httpd.jsm (../../../netwerk/test/httpserver/httpd.js) + content/StructuredLog.jsm (../../../testing/modules/StructuredLog.jsm) #ifdef BOOTSTRAP * content/reftest.jsm (reftest.js) #else diff --git a/layout/tools/reftest/mach_commands.py b/layout/tools/reftest/mach_commands.py index eecff54b396..b3b2bc5ebd4 100644 --- a/layout/tools/reftest/mach_commands.py +++ b/layout/tools/reftest/mach_commands.py @@ -203,8 +203,6 @@ class ReftestRunner(MozbuildObject): if not kwargs["runTestsInParallel"]: kwargs["logFile"] = "%s.log" % kwargs["suite"] - # Remove the stdout handler from the internal logger and let mach deal with it - runreftest.log.removeHandler(runreftest.log.handlers[0]) self.log_manager.enable_unstructured() try: rv = runreftest.run(**kwargs) diff --git a/layout/tools/reftest/output.py b/layout/tools/reftest/output.py new file mode 100644 index 00000000000..a356a50d850 --- /dev/null +++ b/layout/tools/reftest/output.py @@ -0,0 +1,144 @@ +# 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/. + +import json +import os +import threading + +from mozlog.formatters import TbplFormatter +from mozrunner.utils import get_stack_fixer_function + + +class ReftestFormatter(TbplFormatter): + """ + Formatter designed to preserve the legacy "tbpl" format in reftest. + + This is needed for both the reftest-analyzer and mozharness log parsing. + We can change this format when both reftest-analyzer and mozharness have + been changed to read structured logs. + """ + + def __call__(self, data): + if 'component' in data and data['component'] == 'mozleak': + # Output from mozleak requires that no prefix be added + # so that mozharness will pick up these failures. + return "%s\n" % data['message'] + + formatted = TbplFormatter.__call__(self, data) + if data['action'] == 'process_output': + return formatted + return 'REFTEST %s' % formatted + + def log(self, data): + prefix = "%s |" % data['level'].upper() + return "%s %s\n" % (prefix, data['message']) + + def test_end(self, data): + extra = data.get('extra', {}) + status = data['status'] + + status_msg = "TEST-" + if 'expected' in data: + status_msg += "UNEXPECTED-%s" % status + else: + if status != "PASS": + status_msg += "KNOWN-" + status_msg += status + if extra.get('status_msg') == 'Random': + status_msg += "(EXPECTED RANDOM)" + test = self.id_str(data['test']) + if 'message' in data: + status_details = data['message'] + elif isinstance(data['test'], tuple): + status_details = 'image comparison ({})'.format(data['test'][1]) + else: + status_details = '(LOAD ONLY)' + + output_text = "%s | %s | %s" % (status_msg, test, status_details) + if 'differences' in extra: + diff_msg = (", max difference: %(max_difference)s" + ", number of differing pixels: %(differences)s") % extra + diagnostic_data = ("REFTEST IMAGE 1 (TEST): %(image1)s\n" + "REFTEST IMAGE 2 (REFERENCE): %(image2)s") % extra + output_text += '%s\n%s' % (diff_msg, diagnostic_data) + elif "image1" in extra: + diagnostic_data = "REFTEST IMAGE: %(image1)s" % extra + output_text += '\n%s' % diagnostic_data + + output_text += "\nREFTEST TEST-END | %s" % test + return "%s\n" % output_text + + def process_output(self, data): + return "%s\n" % data["data"] + + def suite_end(self, data): + lines = [] + summary = data['extra']['results'] + summary['success'] = summary['Pass'] + summary['LoadOnly'] + lines.append("Successful: %(success)s (%(Pass)s pass, %(LoadOnly)s load only)" % + summary) + summary['unexpected'] = (summary['Exception'] + summary['FailedLoad'] + + summary['UnexpectedFail'] + summary['UnexpectedPass'] + + summary['AssertionUnexpected'] + + summary['AssertionUnexpectedFixed']) + lines.append(("Unexpected: %(unexpected)s (%(UnexpectedFail)s unexpected fail, " + "%(UnexpectedPass)s unexpected pass, " + "%(AssertionUnexpected)s unexpected asserts, " + "%(FailedLoad)s failed load, " + "%(Exception)s exception)") % summary) + summary['known'] = (summary['KnownFail'] + summary['AssertionKnown'] + + summary['Random'] + summary['Skip'] + summary['Slow']) + lines.append(("Known problems: %(known)s (" + + "%(KnownFail)s known fail, " + + "%(AssertionKnown)s known asserts, " + + "%(Random)s random, " + + "%(Skip)s skipped, " + + "%(Slow)s slow)") % summary) + lines = ["REFTEST INFO | %s" % s for s in lines] + lines.append("REFTEST SUITE-END | Shutdown") + return "INFO | Result summary:\n{}\n".format('\n'.join(lines)) + + def id_str(self, test_id): + if isinstance(test_id, basestring): + return test_id + return test_id[0] + + +class OutputHandler(object): + """Process the output of a process during a test run and translate + raw data logged from reftest.js to an appropriate structured log action, + where applicable. + """ + + def __init__(self, log, utilityPath, symbolsPath=None): + self.stack_fixer_function = get_stack_fixer_function(utilityPath, symbolsPath) + self.log = log + # needed for b2gautomation.py + self.suite_finished = False + + def __call__(self, line): + # need to return processed messages to appease remoteautomation.py + if not line.strip(): + return [] + + try: + data = json.loads(line) + except ValueError: + self.verbatim(line) + return [line] + + if isinstance(data, dict) and 'action' in data: + if data['action'] == 'suite_end': + self.suite_finished = True + + self.log.log_raw(data) + else: + self.verbatim(json.dumps(data)) + + return [data] + + def verbatim(self, line): + if self.stack_fixer_function: + line = self.stack_fixer_function(line.encode('utf-8', 'replace')) + self.log.process_output(threading.current_thread().name, line) diff --git a/layout/tools/reftest/reftest.js b/layout/tools/reftest/reftest.js index 728a1b74eb8..19bf9607066 100644 --- a/layout/tools/reftest/reftest.js +++ b/layout/tools/reftest/reftest.js @@ -38,6 +38,7 @@ const NS_OBSERVER_SERVICE_CONTRACTID = CU.import("resource://gre/modules/FileUtils.jsm"); CU.import("chrome://reftest/content/httpd.jsm", this); +CU.import("chrome://reftest/content/StructuredLog.jsm", this); CU.import("resource://gre/modules/Services.jsm"); CU.import("resource://gre/modules/NetUtil.jsm"); @@ -99,6 +100,7 @@ var gTotalTests = 0; var gState; var gCurrentURL; var gTestLog = []; +var gLogLevel; var gServer; var gCount = 0; var gAssertionCount = 0; @@ -163,10 +165,6 @@ var gNoCanvasCache = false; var gRecycledCanvases = new Array(); -// By default we just log to stdout -var gDumpLog = dump; -var gVerbose = false; - // Only dump the sandbox once, because it doesn't depend on the // manifest URL (yet!). var gDumpedConditionSandbox = false; @@ -181,25 +179,27 @@ function HasUnexpectedResult() gTestResults.AssertionUnexpectedFixed > 0; } -function LogWarning(str) +// By default we just log to stdout +var gDumpFn = dump; +var gDumpRawLog = function(record) { + // Dump JSON representation of data on a single line + var line = JSON.stringify(record); + gDumpFn("\n" + line + "\n"); +} +var logger = new StructuredLogger('reftest', gDumpRawLog); + +function TestBuffer(str) { - gDumpLog("REFTEST INFO | " + str + "\n"); + logger.debug(str); gTestLog.push(str); } -function LogInfo(str) +function FlushTestBuffer() { - if (gVerbose) - gDumpLog("REFTEST INFO | " + str + "\n"); - gTestLog.push(str); -} - -function FlushTestLog() -{ - if (!gVerbose) { - // In verbose mode, we've dumped all these messages already. + // In debug mode, we've dumped all these messages already. + if (gLogLevel !== 'debug') { for (var i = 0; i < gTestLog.length; ++i) { - gDumpLog("REFTEST INFO | Saved log: " + gTestLog[i] + "\n"); + logger.info("Saved log: " + gTestLog[i]); } } gTestLog = []; @@ -244,7 +244,7 @@ function getTestPlugin(aName) { return tags[i]; } - LogWarning("Failed to find the test-plugin."); + logger.warning("Failed to find the test-plugin."); return null; } @@ -257,7 +257,6 @@ this.OnRefTestLoad = function OnRefTestLoad(win) var env = CC["@mozilla.org/process/environment;1"]. getService(CI.nsIEnvironment); - gVerbose = !!env.get("MOZ_REFTEST_VERBOSE"); var prefs = Components.classes["@mozilla.org/preferences-service;1"]. getService(Components.interfaces.nsIPrefBranch); @@ -279,6 +278,12 @@ this.OnRefTestLoad = function OnRefTestLoad(win) gBrowserIsIframe = false; } + try { + gLogLevel = prefs.getCharPref("reftest.logLevel"); + } catch (e) { + gLogLevel ='info'; + } + if (win === undefined || win == null) { win = window; } @@ -322,7 +327,7 @@ this.OnRefTestLoad = function OnRefTestLoad(win) plugin1.enabledState = CI.nsIPluginTag.STATE_ENABLED; plugin2.enabledState = CI.nsIPluginTag.STATE_ENABLED; } else { - LogWarning("Could not get test plugin tags."); + logger.warning("Could not get test plugin tags."); } gBrowserMessageManager = gBrowser.QueryInterface(CI.nsIFrameLoaderOwner) @@ -339,7 +344,7 @@ function InitAndStartRefTests() var prefs = Components.classes["@mozilla.org/preferences-service;1"]. getService(Components.interfaces.nsIPrefBranch); } catch(e) { - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + e + "\n"); + logger.error("EXCEPTION: " + e); } try { @@ -361,7 +366,7 @@ function InitAndStartRefTests() var f = FileUtils.File(logFile); var mfl = FileUtils.openFileOutputStream(f, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE); // Set to mirror to stdout as well as the file - gDumpLog = function (msg) { + gDumpFn = function (msg) { #ifdef BOOTSTRAP #ifdef REFTEST_B2G dump(msg); @@ -376,7 +381,7 @@ function InitAndStartRefTests() } catch(e) { // If there is a problem, just use stdout - gDumpLog = dump; + gDumpFn = dump; } } } catch(e) {} @@ -427,7 +432,7 @@ function InitAndStartRefTests() } catch (ex) { //gBrowser.loadURI('data:text/plain,' + ex); ++gTestResults.Exception; - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n"); + logger.error("EXCEPTION: " + ex); DoneTests(); } @@ -465,7 +470,7 @@ function StartTests() var prefs = Components.classes["@mozilla.org/preferences-service;1"]. getService(Components.interfaces.nsIPrefBranch); } catch(e) { - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + e + "\n"); + logger.error("EXCEPTION: " + e); } try { @@ -513,7 +518,7 @@ function StartTests() var manifests = JSON.parse(prefs.getCharPref("reftest.manifests")); gURLFilterRegex = manifests[null]; } catch(e) { - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | Unable to find reftest.manifests pref. Please ensure your profile is setup properly\n"); + logger.error("Unable to find reftest.manifests pref. Please ensure your profile is setup properly"); DoneTests(); } @@ -525,7 +530,7 @@ function StartTests() // process includes before reading the included manifest again manifestURLs.sort(function(a,b) {return a.length - b.length}) manifestURLs.forEach(function(manifestURL) { - gDumpLog("Reading manifest " + manifestURL + "\n"); + logger.info("Reading manifest " + manifestURL); var filter = manifests[manifestURL] ? new RegExp(manifests[manifestURL]) : null; ReadTopManifest(manifestURL, [globalFilter, filter, false]); }); @@ -534,6 +539,7 @@ function StartTests() // Filter tests which will be skipped to get a more even distribution when chunking // tURLs is a temporary array containing all active tests var tURLs = new Array(); + var tIDs = new Array(); for (var i = 0; i < gURLs.length; ++i) { if (gURLs[i].expected == EXPECTED_DEATH) continue; @@ -545,9 +551,10 @@ function StartTests() continue; tURLs.push(gURLs[i]); + tIDs.push(gURLs[i].identifier); } - gDumpLog("REFTEST INFO | Discovered " + gURLs.length + " tests, after filtering SKIP tests, we have " + tURLs.length + "\n"); + logger.suiteStart(tIDs, {"skipped": gURLs.length - tURLs.length}); if (gTotalChunks > 0 && gThisChunk > 0) { // Calculate start and end indices of this chunk if tURLs array were @@ -562,8 +569,8 @@ function StartTests() end = gThisChunk == gTotalChunks ? gURLs.length : gURLs.indexOf(tURLs[end + 1]) - 1; gURLs = gURLs.slice(start, end); - gDumpLog("REFTEST INFO | Running chunk " + gThisChunk + " out of " + gTotalChunks + " chunks. "); - gDumpLog("tests " + (start+1) + "-" + end + "/" + gURLs.length + "\n"); + logger.info("Running chunk " + gThisChunk + " out of " + gTotalChunks + " chunks. " + + "tests " + (start+1) + "-" + end + "/" + gURLs.length); } if (gShuffle) { @@ -580,7 +587,7 @@ function StartTests() } catch (ex) { //gBrowser.loadURI('data:text/plain,' + ex); ++gTestResults.Exception; - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n"); + logger.error("EXCEPTION: " + ex); DoneTests(); } } @@ -593,7 +600,7 @@ function OnRefTestUnload() plugin1.enabledState = gTestPluginEnabledStates[0]; plugin2.enabledState = gTestPluginEnabledStates[1]; } else { - LogWarning("Failed to get test plugin tags."); + logger.warning("Failed to get test plugin tags."); } } @@ -749,8 +756,8 @@ function BuildConditionSandbox(aURL) { } if (!gDumpedConditionSandbox) { - dump("REFTEST INFO | Dumping JSON representation of sandbox \n"); - dump("REFTEST INFO | " + JSON.stringify(CU.waiveXrays(sandbox)) + " \n"); + logger.info("Dumping JSON representation of sandbox"); + logger.info(JSON.stringify(CU.waiveXrays(sandbox))); gDumpedConditionSandbox = true; } @@ -811,6 +818,12 @@ function AddTestItem(aTest, aFilter) if (gFocusFilterMode == FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS && aTest.needsFocus) return; + + if (aTest.url2 !== null) + aTest.identifier = [aTest.prettyPath, aTest.type, aTest.url2.spec]; + else + aTest.identifier = aTest.prettyPath; + gURLs.push(aTest); } @@ -837,8 +850,7 @@ function ReadManifest(aURL, inherited_status, aFilter) var inputStream = channel.open2(); if (channel instanceof Components.interfaces.nsIHttpChannel && channel.responseStatus != 200) { - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | HTTP ERROR : " + - channel.responseStatus + "\n"); + logger.error("HTTP ERROR : " + channel.responseStatus); } var streamBuf = getStreamContent(inputStream); inputStream.close(); @@ -1238,19 +1250,20 @@ function StartCurrentTest() // make sure we don't run tests that are expected to kill the browser while (gURLs.length > 0) { var test = gURLs[0]; + logger.testStart(test.identifier); if (test.expected == EXPECTED_DEATH) { ++gTestResults.Skip; - gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + " | (SKIP)\n"); + logger.testEnd(test.identifier, "SKIP"); gURLs.shift(); } else if (test.needsFocus && !Focus()) { // FIXME: Marking this as a known fail is dangerous! What // if it starts failing all the time? ++gTestResults.Skip; - gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + " | (SKIPPED; COULDN'T GET FOCUS)\n"); + logger.testEnd(test.identifier, "SKIP", null, "(COULDN'T GET FOCUS)"); gURLs.shift(); } else if (test.slow && !gRunSlowTests) { ++gTestResults.Slow; - gDumpLog("REFTEST TEST-KNOWN-SLOW | " + test.url1.spec + " | (SLOW)\n"); + logger.testEnd(test.identifier, "SKIP", null, "(SLOW)"); gURLs.shift(); } else { break; @@ -1266,7 +1279,6 @@ function StartCurrentTest() gRepeat--; StartTests(); } else { - gDumpLog("REFTEST TEST-START | " + gURLs[0].prettyPath + "\n"); if (gURLs[0].chaosMode) { gWindowUtils.enterChaosMode(); } @@ -1332,32 +1344,30 @@ function StartCurrentURI(aState) } else if (ps.type == PREF_INTEGER) { prefs.setIntPref(ps.name, value); } - gDumpLog("SET PREFERENCE pref(" + ps.name + "," + value + ")\n"); + logger.info("SET PREFERENCE pref(" + ps.name + "," + value + ")"); } }); } catch (e) { if (e == "bad pref") { var test = gURLs[0]; if (test.expected == EXPECTED_FAIL) { - gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + - " | (SKIPPED; " + badPref + " not known or wrong type)\n"); + logger.testEnd(test.identifier, "FAIL", "FAIL", + "(SKIPPED; " + badPref + " not known or wrong type)"); ++gTestResults.Skip; } else { - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + test.url1.spec + - " | " + badPref + " not known or wrong type\n"); + logger.testEnd(test.identifier, "FAIL", "PASS", + badPref + " not known or wrong type"); ++gTestResults.UnexpectedFail; } + + // skip the test that had a bad preference + gURLs.shift(); + StartCurrentTest(); + return; } else { throw e; } } - if (badPref != undefined) { - // skip the test that had a bad preference - gURLs.shift(); - - StartCurrentTest(); - return; - } } if (prefSettings.length == 0 && @@ -1370,9 +1380,11 @@ function StartCurrentURI(aState) gContainingWindow.setTimeout(RecordResult, 0); } else { var currentTest = gTotalTests - gURLs.length; - gDumpLog("REFTEST TEST-LOAD | " + gCurrentURL + " | " + currentTest + " / " + gTotalTests + - " (" + Math.floor(100 * (currentTest / gTotalTests)) + "%)\n"); - LogInfo("START " + gCurrentURL); + // Log this to preserve the same overall log format, + // should be removed if the format is updated + gDumpFn("REFTEST TEST-LOAD | " + gCurrentURL + " | " + currentTest + " / " + gTotalTests + + " (" + Math.floor(100 * (currentTest / gTotalTests)) + "%)\n"); + TestBuffer("START " + gCurrentURL); var type = gURLs[0].type if (TYPE_SCRIPT == type) { SendLoadScriptTest(gCurrentURL, gLoadTimeout); @@ -1384,37 +1396,10 @@ function StartCurrentURI(aState) function DoneTests() { - gDumpLog("REFTEST FINISHED: Slowest test took " + gSlowestTestTime + - "ms (" + gSlowestTestURL + ")\n"); + logger.suiteEnd(extra={'results': gTestResults}); + logger.info("Slowest test took " + gSlowestTestTime + "ms (" + gSlowestTestURL + ")"); + logger.info("Total canvas count = " + gRecycledCanvases.length); - gDumpLog("REFTEST INFO | Result summary:\n"); - var count = gTestResults.Pass + gTestResults.LoadOnly; - gDumpLog("REFTEST INFO | Successful: " + count + " (" + - gTestResults.Pass + " pass, " + - gTestResults.LoadOnly + " load only)\n"); - count = gTestResults.Exception + gTestResults.FailedLoad + - gTestResults.UnexpectedFail + gTestResults.UnexpectedPass + - gTestResults.AssertionUnexpected + - gTestResults.AssertionUnexpectedFixed; - gDumpLog("REFTEST INFO | Unexpected: " + count + " (" + - gTestResults.UnexpectedFail + " unexpected fail, " + - gTestResults.UnexpectedPass + " unexpected pass, " + - gTestResults.AssertionUnexpected + " unexpected asserts, " + - gTestResults.AssertionUnexpectedFixed + " unexpected fixed asserts, " + - gTestResults.FailedLoad + " failed load, " + - gTestResults.Exception + " exception)\n"); - count = gTestResults.KnownFail + gTestResults.AssertionKnown + - gTestResults.Random + gTestResults.Skip + gTestResults.Slow; - gDumpLog("REFTEST INFO | Known problems: " + count + " (" + - gTestResults.KnownFail + " known fail, " + - gTestResults.AssertionKnown + " known asserts, " + - gTestResults.Random + " random, " + - gTestResults.Skip + " skipped, " + - gTestResults.Slow + " slow)\n"); - - gDumpLog("REFTEST INFO | Total canvas count = " + gRecycledCanvases.length + "\n"); - - gDumpLog("REFTEST TEST-START | Shutdown\n"); function onStopped() { let appStartup = CC["@mozilla.org/toolkit/app-startup;1"].getService(CI.nsIAppStartup); appStartup.quit(CI.nsIAppStartup.eForceQuit); @@ -1462,7 +1447,7 @@ function DoDrawWindow(ctx, x, y, w, h) // browser element flags |= ctx.DRAWWINDOW_USE_WIDGET_LAYERS; } else if (gBrowserIsRemote) { - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | can't drawWindow remote content\n"); + logger.error(gCurrentURL + " | can't drawWindow remote content"); ++gTestResults.Exception; } @@ -1475,22 +1460,21 @@ function DoDrawWindow(ctx, x, y, w, h) } else { // Output a special warning because we need to be able to detect // this whenever it happens. - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | WARNING: USE_WIDGET_LAYERS disabled\n"); + logger.error("WARNING: USE_WIDGET_LAYERS disabled"); } - gDumpLog("REFTEST INFO | drawWindow flags = " + flagsStr + - "; window size = " + gContainingWindow.innerWidth + "," + gContainingWindow.innerHeight + - "; test browser size = " + testRect.width + "," + testRect.height + - "\n"); + logger.info("drawWindow flags = " + flagsStr + + "; window size = " + gContainingWindow.innerWidth + "," + gContainingWindow.innerHeight + + "; test browser size = " + testRect.width + "," + testRect.height); } - LogInfo("DoDrawWindow " + x + "," + y + "," + w + "," + h); + TestBuffer("DoDrawWindow " + x + "," + y + "," + w + "," + h); ctx.drawWindow(gContainingWindow, x, y, w, h, "rgb(255,255,255)", gDrawWindowFlags); } function InitCurrentCanvasWithSnapshot() { - LogInfo("Initializing canvas snapshot"); + TestBuffer("Initializing canvas snapshot"); if (gURLs[0].type == TYPE_LOAD || gURLs[0].type == TYPE_SCRIPT) { // We don't want to snapshot this kind of test @@ -1508,7 +1492,7 @@ function InitCurrentCanvasWithSnapshot() function UpdateCurrentCanvasForInvalidation(rects) { - LogInfo("Updating canvas for invalidation"); + TestBuffer("Updating canvas for invalidation"); if (!gCurrentCanvas) { return; @@ -1538,7 +1522,7 @@ function UpdateCurrentCanvasForInvalidation(rects) function UpdateWholeCurrentCanvasForInvalidation() { - LogInfo("Updating entire canvas for invalidation"); + TestBuffer("Updating entire canvas for invalidation"); if (!gCurrentCanvas) { return; @@ -1550,7 +1534,7 @@ function UpdateWholeCurrentCanvasForInvalidation() function RecordResult(testRunTime, errorMsg, scriptResults) { - LogInfo("RecordResult fired"); + TestBuffer("RecordResult fired"); // Keep track of which test was slowest, and how long it took. if (testRunTime > gSlowestTestTime) { @@ -1560,26 +1544,26 @@ function RecordResult(testRunTime, errorMsg, scriptResults) // Not 'const ...' because of 'EXPECTED_*' value dependency. var outputs = {}; - const randomMsg = "(EXPECTED RANDOM)"; outputs[EXPECTED_PASS] = { - true: {s: "TEST-PASS" , n: "Pass"}, - false: {s: "TEST-UNEXPECTED-FAIL" , n: "UnexpectedFail"} + true: {s: ["PASS", "PASS"], n: "Pass"}, + false: {s: ["FAIL", "PASS"], n: "UnexpectedFail"} }; outputs[EXPECTED_FAIL] = { - true: {s: "TEST-UNEXPECTED-PASS" , n: "UnexpectedPass"}, - false: {s: "TEST-KNOWN-FAIL" , n: "KnownFail"} + true: {s: ["PASS", "FAIL"], n: "UnexpectedPass"}, + false: {s: ["FAIL", "FAIL"], n: "KnownFail"} }; outputs[EXPECTED_RANDOM] = { - true: {s: "TEST-PASS" + randomMsg , n: "Random"}, - false: {s: "TEST-KNOWN-FAIL" + randomMsg, n: "Random"} + true: {s: ["PASS", "PASS"], n: "Random"}, + false: {s: ["FAIL", "FAIL"], n: "Random"} }; outputs[EXPECTED_FUZZY] = outputs[EXPECTED_PASS]; var output; + var extra; if (gURLs[0].type == TYPE_LOAD) { ++gTestResults.LoadOnly; - gDumpLog("REFTEST TEST-PASS | " + gURLs[0].prettyPath + " | (LOAD ONLY)\n"); + logger.testEnd(gURLs[0].identifier, "PASS", "PASS", "(LOAD ONLY)"); gCurrentCanvas = null; FinishTestItem(); return; @@ -1597,17 +1581,14 @@ function RecordResult(testRunTime, errorMsg, scriptResults) if (!gURLs[0].allowSilentFail) errorMsg = "No test results reported. (SCRIPT)\n"; else - gDumpLog("REFTEST INFO | An expected silent failure occurred \n"); + logger.info("An expected silent failure occurred"); } if (errorMsg) { output = outputs[expected][false]; + extra = { status_msg: output.n }; ++gTestResults[output.n]; - var result = "REFTEST " + output.s + " | " + - gURLs[0].prettyPath + " | " + // the URL being tested - errorMsg; - - gDumpLog(result); + logger.testEnd(gURLs[0].identifier, output.s[0], output.s[1], errorMsg, null, extra); FinishTestItem(); return; } @@ -1627,16 +1608,15 @@ function RecordResult(testRunTime, errorMsg, scriptResults) var index = 0; scriptResults.forEach(function(result) { var output = outputPair[result.passed]; + var extra = { status_msg: output.n }; ++gTestResults[output.n]; - result = "REFTEST " + output.s + " | " + - gURLs[0].prettyPath + " | " + // the URL being tested - result.description + " item " + (++index) + "\n"; - gDumpLog(result); + logger.testEnd(gURLs[0].identifier, output.s[0], output.s[1], + result.description + " item " + (++index), null, extra); }); if (anyFailed && expected == EXPECTED_PASS) { - FlushTestLog(); + FlushTestBuffer(); } FinishTestItem(); @@ -1648,7 +1628,7 @@ function RecordResult(testRunTime, errorMsg, scriptResults) gCurrentCanvas = gURICanvases[gCurrentURL]; } if (gCurrentCanvas == null) { - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | program error managing snapshots\n"); + logger.error(gCurrentURL, "program error managing snapshots"); ++gTestResults.Exception; } if (gState == 1) { @@ -1691,7 +1671,7 @@ function RecordResult(testRunTime, errorMsg, scriptResults) throw "Inconsistent result from compareCanvases."; } equal = expected == EXPECTED_FUZZY; - gDumpLog("REFTEST fuzzy match\n"); + logger.info("REFTEST fuzzy match"); } var failedExtraCheck = gFailedNoPaint || gFailedOpaqueLayer || gFailedAssignedLayer; @@ -1700,6 +1680,7 @@ function RecordResult(testRunTime, errorMsg, scriptResults) var test_passed = (equal == (gURLs[0].type == TYPE_REFTEST_EQUAL)) && !failedExtraCheck; output = outputs[expected][test_passed]; + extra = { status_msg: output.n }; ++gTestResults[output.n]; @@ -1718,39 +1699,21 @@ function RecordResult(testRunTime, errorMsg, scriptResults) failures.push("failed reftest-assigned-layer: " + gFailedAssignedLayerMessages.join(", ")); } var failureString = failures.join(", "); - if (expected == EXPECTED_FAIL) { - gDumpLog("REFTEST TEST-KNOWN-FAIL | " + gURLs[0].prettyPath + " | " + failureString + "\n"); - } else { - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gURLs[0].prettyPath + " | " + failureString + "\n"); - } + logger.testEnd(gURLs[0].identifier, output.s[0], output.s[1], failureString, null, extra); } else { - var result = "REFTEST " + output.s + " | " + - gURLs[0].prettyPath + " | "; // the URL being tested - switch (gURLs[0].type) { - case TYPE_REFTEST_NOTEQUAL: - result += "image comparison (!=)"; - break; - case TYPE_REFTEST_EQUAL: - result += "image comparison (==)"; - break; - } - if (!test_passed && expected == EXPECTED_PASS || !test_passed && expected == EXPECTED_FUZZY || test_passed && expected == EXPECTED_FAIL) { if (!equal) { - result += ", max difference: " + maxDifference.value + ", number of differing pixels: " + differences + "\n"; - result += "REFTEST IMAGE 1 (TEST): " + gCanvas1.toDataURL() + "\n"; - result += "REFTEST IMAGE 2 (REFERENCE): " + gCanvas2.toDataURL() + "\n"; + extra.max_difference = maxDifference.value; + extra.differences = differences; + extra.image1 = gCanvas1.toDataURL(); + extra.image2 = gCanvas2.toDataURL(); } else { - result += "\n"; - result += "REFTEST IMAGE: " + gCanvas1.toDataURL() + "\n"; + extra.image1 = gCanvas1.toDataURL(); } - } else { - result += "\n"; } - - gDumpLog(result); + logger.testEnd(gURLs[0].identifier, output.s[0], output.s[1], null, null, extra); if (gURLs[0].prefSettings1.length == 0) { UpdateCanvasCache(gURLs[0].url1, gCanvas1); @@ -1761,7 +1724,7 @@ function RecordResult(testRunTime, errorMsg, scriptResults) } if ((!test_passed && expected == EXPECTED_PASS) || (test_passed && expected == EXPECTED_FAIL)) { - FlushTestLog(); + FlushTestBuffer(); } CleanUpCrashDumpFiles(); @@ -1778,11 +1741,10 @@ function LoadFailed(why) // Once bug 896840 is fixed, this can go away, but for now it will give log // output that is TBPL starable for bug 789751 and bug 720452. if (!why) { - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | load failed with unknown reason\n"); + logger.error("load failed with unknown reason"); } - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + - gURLs[0]["url" + gState].spec + " | load failed: " + why + "\n"); - FlushTestLog(); + logger.testEnd(gURLs[0]["url" + gState].spec, "FAIL", "PASS", "load failed: " + why); + FlushTestBuffer(); FinishTestItem(); } @@ -1819,11 +1781,9 @@ function FindUnexpectedCrashDumpFiles() if (!foundCrashDumpFile) { ++gTestResults.UnexpectedFail; foundCrashDumpFile = true; - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + - " | This test left crash dumps behind, but we weren't expecting it to!\n"); + logger.testEnd(gCurrentURL, "FAIL", "PASS", "This test left crash dumps behind, but we weren't expecting it to!"); } - gDumpLog("REFTEST INFO | Found unexpected crash dump file " + path + - ".\n"); + logger.info("Found unexpected crash dump file " + path); gUnexpectedCrashDumpFiles[path] = true; } } @@ -1840,7 +1800,7 @@ function FinishTestItem() { // Replace document with BLANK_URL_FOR_CLEARING in case there are // assertions when unloading. - gDumpLog("REFTEST INFO | Loading a blank page\n"); + logger.debug("Loading a blank page"); // After clearing, content will notify us of the assertion count // and tests will continue. SendClear(); @@ -1875,26 +1835,25 @@ function DoAssertionCheck(numAsserts) if (numAsserts < minAsserts) { ++gTestResults.AssertionUnexpectedFixed; - gDumpLog("REFTEST TEST-UNEXPECTED-PASS | " + gURLs[0].prettyPath + - " | assertion count " + numAsserts + " is less than " + - expectedAssertions + "\n"); + gDumpFn("REFTEST TEST-UNEXPECTED-PASS | " + gURLs[0].prettyPath + + " | assertion count" + numAsserts + " is less than " + + expectedAssertions + "\n"); } else if (numAsserts > maxAsserts) { ++gTestResults.AssertionUnexpected; - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gURLs[0].prettyPath + - " | assertion count " + numAsserts + " is more than " + - expectedAssertions + "\n"); + gDumpFn("REFTEST TEST-UNEXPECTED-FAIL | " + gURLs[0].prettyPath + + " | assertion count " + numAsserts + " is more than " + + expectedAssertions + "\n"); } else if (numAsserts != 0) { ++gTestResults.AssertionKnown; - gDumpLog("REFTEST TEST-KNOWN-FAIL | " + gURLs[0].prettyPath + - " | assertion count " + numAsserts + " matches " + - expectedAssertions + "\n"); + gDumpFn("REFTEST TEST-KNOWN-FAIL | " + gURLs[0].prettyPath + + "assertion count " + numAsserts + " matches " + + expectedAssertions + "\n"); } } if (gURLs[0].chaosMode) { gWindowUtils.leaveChaosMode(); } - gDumpLog("REFTEST TEST-END | " + gURLs[0].prettyPath + "\n"); // And start the next test. gURLs.shift(); @@ -1923,7 +1882,7 @@ function RestoreChangedPreferences() } else if (ps.type == PREF_INTEGER) { prefs.setIntPref(ps.name, value); } - gDumpLog("RESTORE PREFERENCE pref(" + ps.name + "," + value + ")\n"); + logger.info("RESTORE PREFERENCE pref(" + ps.name + "," + value + ")"); }); gPrefsToRestore = []; } @@ -2004,7 +1963,7 @@ function RecvContentReady() function RecvException(what) { - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | " + what + "\n"); + logger.error(gCurrentURL + " | " + what); ++gTestResults.Exception; } @@ -2036,13 +1995,13 @@ function RecvInitCanvasWithSnapshot() function RecvLog(type, msg) { - msg = "[CONTENT] "+ msg; + msg = "[CONTENT] " + msg; if (type == "info") { - LogInfo(msg); + TestBuffer(msg); } else if (type == "warning") { - LogWarning(msg); + logger.warning(msg); } else { - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | unknown log type " + type + "\n"); + logger.error("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | unknown log type " + type + "\n"); ++gTestResults.Exception; } } diff --git a/layout/tools/reftest/reftestcommandline.py b/layout/tools/reftest/reftestcommandline.py index df7b63d3eca..28e8b4f5f41 100644 --- a/layout/tools/reftest/reftestcommandline.py +++ b/layout/tools/reftest/reftestcommandline.py @@ -1,8 +1,11 @@ import argparse import os +import sys from collections import OrderedDict from urlparse import urlparse +import mozlog + here = os.path.abspath(os.path.dirname(__file__)) @@ -207,6 +210,8 @@ class ReftestArgumentsParser(argparse.ArgumentParser): nargs="*", help="Path to test file, manifest file, or directory containing tests") + mozlog.commandline.add_logging_group(self) + def get_ip(self): import moznetwork if os.name != "nt": @@ -235,8 +240,6 @@ class ReftestArgumentsParser(argparse.ArgumentParser): self.error("Failed to determine test suite; supply --suite to set this explicitly") def validate(self, options, reftest): - import sys - if not options.tests: # Can't just set this in the argument parser because mach will set a default self.error("Must supply at least one path to a manifest file, test directory, or test file to run.") diff --git a/layout/tools/reftest/remotereftest.py b/layout/tools/reftest/remotereftest.py index 5ab8f0fd985..9f2feff87b1 100644 --- a/layout/tools/reftest/remotereftest.py +++ b/layout/tools/reftest/remotereftest.py @@ -8,19 +8,21 @@ import time import tempfile import traceback -# We need to know our current directory so that we can serve our test files from it. -SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(__file__))) - -from runreftest import RefTest, ReftestResolver -from automation import Automation import devicemanager import droid import mozinfo import moznetwork +from automation import Automation from remoteautomation import RemoteAutomation, fennecLogcatFilters +from output import OutputHandler +from runreftest import RefTest, ReftestResolver import reftestcommandline +# We need to know our current directory so that we can serve our test files from it. +SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(__file__))) + + class RemoteReftestResolver(ReftestResolver): def absManifestPath(self, path): script_abs_path = os.path.join(SCRIPT_DIRECTORY, path) @@ -146,6 +148,13 @@ class RemoteReftest(RefTest): self.automation.deleteANRs() self.automation.deleteTombstones() + self._populate_logger(options) + outputHandler = OutputHandler(self.log, options.utilityPath, options.symbolsPath) + # RemoteAutomation.py's 'messageLogger' is also used by mochitest. Mimic a mochitest + # MessageLogger object to re-use this code path. + outputHandler.write = outputHandler.__call__ + self.automation._processArgs['messageLogger'] = outputHandler + def findPath(self, paths, filename = None): for path in paths: p = path @@ -445,4 +454,3 @@ def main(): if __name__ == "__main__": sys.exit(main()) - diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py index 1cfadb8b446..457f4242014 100644 --- a/layout/tools/reftest/runreftest.py +++ b/layout/tools/reftest/runreftest.py @@ -26,26 +26,23 @@ import mozcrash import mozdebug import mozinfo import mozleak +import mozlog import mozprocess import mozprofile import mozrunner from mozrunner.utils import get_stack_fixer_function, test_environment from mozscreenshot import printstatus, dump_screen +from output import OutputHandler, ReftestFormatter import reftestcommandline -# set up logging handler a la automation.py.in for compatability -import logging -log = logging.getLogger() +here = os.path.abspath(os.path.dirname(__file__)) - -def resetGlobalLog(): - while log.handlers: - log.removeHandler(log.handlers[0]) - handler = logging.StreamHandler(sys.stdout) - log.setLevel(logging.INFO) - log.addHandler(handler) -resetGlobalLog() +try: + from mozbuild.base import MozbuildObject + build_obj = MozbuildObject.from_environment(cwd=here) +except ImportError: + build_obj = None def categoriesToRegex(categoryList): @@ -203,6 +200,21 @@ class RefTest(object): self.lastTestSeen = 'reftest' self.haveDumpedScreen = False self.resolver = self.resolver_cls() + self.log = None + + def _populate_logger(self, options): + if self.log: + return + + mozlog.commandline.log_formatters["tbpl"] = (ReftestFormatter, + "Reftest specific formatter for the" + "benefit of legacy log parsers and" + "tools such as the reftest analyzer") + fmt_options = {} + if not options.log_tbpl_level and os.environ.get('MOZ_REFTEST_VERBOSE'): + options.log_tbpl_level = fmt_options['level'] = 'debug' + self.log = mozlog.commandline.setup_logging( + "reftest harness", options, {"tbpl": sys.stdout}, fmt_options) def update_mozinfo(self): """walk up directories to find mozinfo.json update the info""" @@ -255,6 +267,7 @@ class RefTest(object): if options.runUntilFailure: prefs['reftest.runUntilFailure'] = True prefs['reftest.focusFilterMode'] = options.focusFilterMode + prefs['reftest.logLevel'] = options.log_tbpl_level or 'info' prefs['reftest.manifests'] = json.dumps(manifests) # Ensure that telemetry is disabled, so we don't connect to the telemetry @@ -331,7 +344,7 @@ class RefTest(object): return profile def environment(self, **kwargs): - kwargs['log'] = log + kwargs['log'] = self.log return test_environment(**kwargs) def buildBrowserEnv(self, options, profileDir): @@ -360,11 +373,11 @@ class RefTest(object): def killNamedOrphans(self, pname): """ Kill orphan processes matching the given command name """ - log.info("Checking for orphan %s processes..." % pname) + self.log.info("Checking for orphan %s processes..." % pname) def _psInfo(line): if pname in line: - log.info(line) + self.log.info(line) process = mozprocess.ProcessHandler(['ps', '-f'], processOutputLine=_psInfo) process.run() @@ -375,13 +388,13 @@ class RefTest(object): if len(parts) == 3 and parts[0].isdigit(): pid = int(parts[0]) if parts[2] == pname and parts[1] == '1': - log.info("killing %s orphan with pid %d" % (pname, pid)) + self.log.info("killing %s orphan with pid %d" % (pname, pid)) try: os.kill( pid, getattr(signal, "SIGKILL", signal.SIGTERM)) except Exception as e: - log.info("Failed to kill process %d: %s" % - (pid, str(e))) + self.log.info("Failed to kill process %d: %s" % + (pid, str(e))) process = mozprocess.ProcessHandler(['ps', '-o', 'pid,ppid,comm'], processOutputLine=_psKill) process.run() @@ -392,6 +405,8 @@ class RefTest(object): shutil.rmtree(profileDir, True) def runTests(self, tests, options, cmdlineArgs=None): + self._populate_logger(options) + # Despite our efforts to clean up servers started by this script, in practice # we still see infrequent cases where a process is orphaned and interferes # with future tests, typically because the old server is keeping the port in use. @@ -484,17 +499,16 @@ class RefTest(object): """handle process output timeout""" # TODO: bug 913975 : _processOutput should call self.processOutputLine # one more time one timeout (I think) - log.error("TEST-UNEXPECTED-FAIL | %s | application timed out after %d seconds with no output" % - (self.lastTestSeen, int(timeout))) + self.log.error("%s | application timed out after %d seconds with no output" % (self.lastTestSeen, int(timeout))) self.killAndGetStack( proc, utilityPath, debuggerInfo, dump_screen=not debuggerInfo) def dumpScreen(self, utilityPath): if self.haveDumpedScreen: - log.info("Not taking screenshot here: see the one that was previously logged") + self.log.info("Not taking screenshot here: see the one that was previously logged") return self.haveDumpedScreen = True - dump_screen(utilityPath, log) + dump_screen(utilityPath, self.log) def killAndGetStack(self, process, utilityPath, debuggerInfo, dump_screen=False): """ @@ -522,75 +536,11 @@ class RefTest(object): process.kill(sig=signal.SIGABRT) except OSError: # https://bugzilla.mozilla.org/show_bug.cgi?id=921509 - log.info("Can't trigger Breakpad, process no longer exists") + self.log.info("Can't trigger Breakpad, process no longer exists") return - log.info("Can't trigger Breakpad, just killing process") + self.log.info("Can't trigger Breakpad, just killing process") process.kill() - # output processing - - class OutputHandler(object): - - """line output handler for mozrunner""" - - def __init__(self, harness, utilityPath, symbolsPath=None, dump_screen_on_timeout=True): - """ - harness -- harness instance - dump_screen_on_timeout -- whether to dump the screen on timeout - """ - self.harness = harness - self.utilityPath = utilityPath - self.symbolsPath = symbolsPath - self.dump_screen_on_timeout = dump_screen_on_timeout - self.stack_fixer_function = self.stack_fixer() - - def processOutputLine(self, line): - """per line handler of output for mozprocess""" - for handler in self.output_handlers(): - line = handler(line) - __call__ = processOutputLine - - def output_handlers(self): - """returns ordered list of output handlers""" - return [self.fix_stack, - self.format, - self.record_last_test, - self.handle_timeout_and_dump_screen, - self.log, - ] - - def stack_fixer(self): - """ - return get_stack_fixer_function, if any, to use on the output lines - """ - return get_stack_fixer_function(self.utilityPath, self.symbolsPath) - - # output line handlers: - # these take a line and return a line - def fix_stack(self, line): - if self.stack_fixer_function: - return self.stack_fixer_function(line) - return line - - def format(self, line): - """format the line""" - return line.rstrip().decode("UTF-8", "ignore") - - def record_last_test(self, line): - """record last test on harness""" - if "TEST-START" in line and "|" in line: - self.harness.lastTestSeen = line.split("|")[1].strip() - return line - - def handle_timeout_and_dump_screen(self, line): - if self.dump_screen_on_timeout and "TEST-UNEXPECTED-FAIL" in line and "Test timed out" in line: - self.harness.dumpScreen(self.utilityPath) - return line - - def log(self, line): - log.info(line) - return line - def runApp(self, profile, binary, cmdargs, env, timeout=None, debuggerInfo=None, symbolsPath=None, options=None, @@ -606,10 +556,14 @@ class RefTest(object): interactive = debuggerInfo.interactive debug_args = [debuggerInfo.path] + debuggerInfo.args - outputHandler = self.OutputHandler(harness=self, - utilityPath=options.utilityPath, - symbolsPath=symbolsPath, - dump_screen_on_timeout=not debuggerInfo) + def record_last_test(message): + """Records the last test seen by this harness for the benefit of crash logging.""" + if message['action'] == 'test_start': + self.lastTestSeen = message['test'] + + self.log.add_handler(record_last_test) + + outputHandler = OutputHandler(self.log, options.utilityPath, symbolsPath=symbolsPath) kp_kwargs = { 'kill_on_timeout': False, @@ -639,21 +593,18 @@ class RefTest(object): interactive=interactive, outputTimeout=timeout) proc = runner.process_handler + status = runner.wait() runner.process_handler = None - if timeout is None: - didTimeout = False - else: - didTimeout = proc.didTimeout if status: - log.info("TEST-UNEXPECTED-FAIL | %s | application terminated with exit code %s", - self.lastTestSeen, status) + self.log.error("TEST-UNEXPECTED-FAIL | %s | application terminated with exit code %s" % (self.lastTestSeen, status)) else: self.lastTestSeen = 'Main app process exited normally' - crashed = mozcrash.check_for_crashes(os.path.join(profile.profile, "minidumps"), - symbolsPath, test_name=self.lastTestSeen) + crashed = mozcrash.log_crashes(self.log, os.path.join(profile.profile, 'minidumps'), + symbolsPath, test=self.lastTestSeen) + runner.cleanup() if not status and crashed: status = 1 @@ -667,7 +618,7 @@ class RefTest(object): profileDir = None try: - if cmdlineArgs == None: + if cmdlineArgs is None: cmdlineArgs = [] profile = self.createReftestProfile(options, manifests) profileDir = profile.profile # name makes more sense @@ -675,7 +626,6 @@ class RefTest(object): # browser environment browserEnv = self.buildBrowserEnv(options, profileDir) - log.info("REFTEST INFO | runreftest.py | Running tests: start.\n") status = self.runApp(profile, binary=options.app, cmdargs=cmdlineArgs, @@ -688,11 +638,9 @@ class RefTest(object): debuggerInfo=debuggerInfo) mozleak.process_leak_log(self.leakLogFile, leak_thresholds=options.leakThresholds, - log=log, stack_fixer=get_stack_fixer_function(options.utilityPath, options.symbolsPath), ) - log.info("\nREFTEST INFO | runreftest.py | Running tests: end.") finally: self.cleanup(profileDir) return status @@ -712,31 +660,28 @@ class RefTest(object): dest = os.path.join(profileDir, os.path.basename(abspath)) shutil.copytree(abspath, dest) else: - log.warning( - "WARNING | runreftest.py | Failed to copy %s to profile", abspath) + self.log.warning( + "runreftest.py | Failed to copy %s to profile" % abspath) continue def run(**kwargs): + parser = reftestcommandline.DesktopArgumentsParser() + # Mach gives us kwargs; this is a way to turn them back into an # options object - parser = reftestcommandline.DesktopArgumentsParser() - reftest = RefTest() parser.set_defaults(**kwargs) - options = parser.parse_args(kwargs["tests"]) + + if 'tests' in kwargs: + options = parser.parse_args(kwargs["tests"]) + else: + options = parser.parse_args() + + reftest = RefTest() parser.validate(options, reftest) + return reftest.runTests(options.tests, options) -def main(): - parser = reftestcommandline.DesktopArgumentsParser() - reftest = RefTest() - - options = parser.parse_args() - parser.validate(options, reftest) - - sys.exit(reftest.runTests(options.tests, options)) - - if __name__ == "__main__": - main() + sys.exit(run()) diff --git a/layout/tools/reftest/runreftestb2g.py b/layout/tools/reftest/runreftestb2g.py index b7aa9b3d25a..41f3d72874a 100644 --- a/layout/tools/reftest/runreftestb2g.py +++ b/layout/tools/reftest/runreftestb2g.py @@ -16,6 +16,7 @@ if here not in sys.path: from automation import Automation from b2gautomation import B2GRemoteAutomation from runreftestmulet import run_test_harness as run_mulet_reftests +from output import OutputHandler from remotereftest import RemoteReftestResolver, ReftestServer from runreftest import RefTest import reftestcommandline @@ -311,6 +312,8 @@ class B2GRemoteReftest(RefTest): timeout=None, debuggerInfo=None, symbolsPath=None, options=None, valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None): + + outputHandler = OutputHandler(self.log, options.utilityPath, options.symbolsPath) status = self.automation.runApp(None, env, binary, profile.profile, @@ -319,7 +322,8 @@ class B2GRemoteReftest(RefTest): xrePath=options.xrePath, debuggerInfo=debuggerInfo, symbolsPath=symbolsPath, - timeout=timeout) + timeout=timeout, + outputHandler=outputHandler) return status @@ -380,7 +384,6 @@ def run_remote_reftests(parser, options): auto.setProduct("b2g") auto.test_script = os.path.join(here, 'b2g_start_script.js') auto.test_script_args = [options.remoteWebServer, options.httpPort] - auto.logFinish = "REFTEST TEST-START | Shutdown" reftest = B2GRemoteReftest(auto, dm, options, here) parser.validate(options, reftest) diff --git a/layout/tools/reftest/runreftestmulet.py b/layout/tools/reftest/runreftestmulet.py index 1ffc9bee92d..d611b62902b 100644 --- a/layout/tools/reftest/runreftestmulet.py +++ b/layout/tools/reftest/runreftestmulet.py @@ -20,11 +20,10 @@ import mozinfo import mozlog from runreftest import RefTest +from output import OutputHandler import reftestcommandline -log = mozlog.unstructured.getLogger('REFTEST') - class MuletReftest(RefTest): build_type = "mulet" marionette = None @@ -59,7 +58,11 @@ class MuletReftest(RefTest): self.profile = self.create_profile(options, manifests, profile_to_clone=options.profile) env = self.buildBrowserEnv(options, self.profile.profile) - kp_kwargs = { 'processOutputLine': [self._on_output], + + self._populate_logger(options) + outputHandler = OutputHandler(self.log, options.utilityPath, symbolsPath=options.symbolsPath) + + kp_kwargs = { 'processOutputLine': [outputHandler], 'onTimeout': [self._on_timeout], 'kill_on_timeout': False } @@ -71,7 +74,7 @@ class MuletReftest(RefTest): options.timeout = 300 self.timeout = options.timeout + 30.0 - log.info("%s | Running tests: start.", os.path.basename(__file__)) + self.log.info("%s | Running tests: start." % os.path.basename(__file__)) cmd, args = self.build_command_line(options.app, ignore_window_size=options.ignoreWindowSize, browser_arg=options.browser_arg) @@ -86,9 +89,9 @@ class MuletReftest(RefTest): status = 0 try: self.runner.start(outputTimeout=self.timeout) - log.info("%s | Application pid: %d", + self.log.info("%s | Application pid: %d" % ( os.path.basename(__file__), - self.runner.process_handler.pid) + self.runner.process_handler.pid)) # kick starts the reftest harness self.run_marionette_script() @@ -98,13 +101,13 @@ class MuletReftest(RefTest): self.runner.cleanup() if status > 0: - log.testFail("%s | application terminated with exit code %s", - self.last_test, status) + self.log.testFail("%s | application terminated with exit code %s" % ( + self.last_test, status)) elif status < 0: - log.info("%s | application killed with signal %s", - self.last_test, -status) + self.log.info("%s | application killed with signal %s" % ( + self.last_test, -status)) - log.info("%s | Running tests: end.", os.path.basename(__file__)) + self.log.info("%s | Running tests: end." % os.path.basename(__file__)) return status def create_profile(self, options, manifests, profile_to_clone=None): @@ -159,22 +162,13 @@ class MuletReftest(RefTest): args += ['-chrome', 'chrome://b2g/content/shell.html'] return cmd, args - def _on_output(self, line): - sys.stdout.write("%s\n" % line) - sys.stdout.flush() - - # TODO use structured logging - if "TEST-START" in line and "|" in line: - self.last_test = line.split("|")[1].strip() - def _on_timeout(self): msg = "%s | application timed out after %s seconds with no output" - log.testFail(msg % (self.last_test, self.timeout)) + self.log.testFail(msg % (self.last_test, self.timeout)) # kill process to get a stack self.runner.stop(sig=signal.SIGABRT) - def _unlockScreen(self): self.marionette.set_context(self.marionette.CONTEXT_CONTENT) self.marionette.import_script(os.path.abspath( @@ -183,10 +177,11 @@ class MuletReftest(RefTest): self.marionette.execute_async_script('GaiaLockScreen.unlock()') def _wait_for_homescreen(self, timeout): - log.info("Waiting for home screen to load") + self.log.info("Waiting for home screen to load") Wait(self.marionette, timeout).until(expected.element_present( By.CSS_SELECTOR, '#homescreen[loading-state=false]')) + def run_test_harness(parser, options): marionette_args = {} if options.marionette: diff --git a/testing/modules/StructuredLog.jsm b/testing/modules/StructuredLog.jsm index 830f59f78a6..bfa51a2b570 100644 --- a/testing/modules/StructuredLog.jsm +++ b/testing/modules/StructuredLog.jsm @@ -87,17 +87,35 @@ StructuredLogger.prototype = { this._logData("test_end", data); }, - suiteStart: function (tests, runinfo=null) { + suiteStart: function (tests, runinfo=null, versioninfo=null, deviceinfo=null, extra=null) { var data = {tests: tests}; if (runinfo !== null) { data.runinfo = runinfo; } + if (versioninfo !== null) { + data.versioninfo = versioninfo; + } + + if (deviceinfo !== null) { + data.deviceinfo = deviceinfo; + } + + if (extra !== null) { + data.extra = extra; + } + this._logData("suite_start", data); }, - suiteEnd: function () { - this._logData("suite_end"); + suiteEnd: function (extra=null) { + var data = {}; + + if (extra !== null) { + data.extra = extra; + } + + this._logData("suite_end", data); }, @@ -142,6 +160,14 @@ StructuredLogger.prototype = { this.log("CRITICAL", message, extra); }, + processOutput: function(thread, message) { + this._logData('process_output', { + message: message, + thread: thread, + }); + }, + + _logData: function (action, data={}) { var allData = { action: action, diff --git a/testing/mozbase/mozleak/mozleak/leaklog.py b/testing/mozbase/mozleak/mozleak/leaklog.py index c72de250778..73a25d6476e 100644 --- a/testing/mozbase/mozleak/mozleak/leaklog.py +++ b/testing/mozbase/mozleak/mozleak/leaklog.py @@ -10,9 +10,15 @@ import sys import mozinfo import mozrunner.utils -def _raw_log(): - import logging - return logging.getLogger(__name__) + +def _get_default_logger(): + from mozlog import get_default_logger + log = get_default_logger(component='mozleak') + + if not log: + import logging + log = logging.getLogger(__name__) + return log # Do not add anything to this list, unless one of the existing leaks below @@ -130,7 +136,7 @@ def process_single_leak_file(leakLogFileName, processType, leakThreshold, r"\s*-?\d+\s+(?P-?\d+)") # The class name can contain spaces. We remove trailing whitespace later. - log = log or _raw_log() + log = log or _get_default_logger() processString = "%s process:" % processType expectedLeaks = expectedTabProcessLeakCounts() if processType == 'tab' else {} @@ -276,7 +282,7 @@ def process_leak_log(leak_log_file, leak_thresholds=None, in the list ignore_missing_leaks. """ - log = log or _raw_log() + log = log or _get_default_logger() leakLogFile = leak_log_file if not os.path.exists(leakLogFile): diff --git a/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py b/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py index ec5abc569c5..ca450adf4cd 100644 --- a/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py +++ b/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py @@ -5,6 +5,7 @@ from .base import BaseFormatter from .process import strstatus + class TbplFormatter(BaseFormatter): """Formatter that formats logs in the legacy formatting format used by TBPL This is intended to be used to preserve backward compatibility with existing tools @@ -102,12 +103,12 @@ class TbplFormatter(BaseFormatter): def test_end(self, data): test_id = self.test_id(data["test"]) - time_msg = "" + duration_msg = "" if test_id in self.test_start_times: start_time = self.test_start_times.pop(test_id) time = data["time"] - start_time - time_msg = "took %ims" % time + duration_msg = "took %ims" % time if "expected" in data: message = data.get("message", "") @@ -119,18 +120,20 @@ class TbplFormatter(BaseFormatter): message = message[:-1] failure_line = "TEST-UNEXPECTED-%s | %s | %s\n" % ( - data["status"], test_id, message) + data["status"], self.id_str(test_id), message) if data["expected"] not in ("PASS", "OK"): expected_msg = "expected %s | " % data["expected"] else: expected_msg = "" - info_line = "TEST-INFO %s%s\n" % (expected_msg, time_msg) + info_line = "TEST-INFO %s%s\n" % (expected_msg, duration_msg) return failure_line + info_line - return "TEST-%s | %s | %s\n" % ( - data["status"], test_id, time_msg) + sections = ["TEST-%s" % data['status'], self.id_str(test_id)] + if duration_msg: + sections.append(duration_msg) + return ' | '.join(sections) + '\n' def suite_end(self, data): start_time = self.suite_start_time diff --git a/testing/mozbase/mozlog/mozlog/logtypes.py b/testing/mozbase/mozlog/mozlog/logtypes.py index 4d458e2b30b..dc516c98864 100644 --- a/testing/mozbase/mozlog/mozlog/logtypes.py +++ b/testing/mozbase/mozlog/mozlog/logtypes.py @@ -132,9 +132,9 @@ class TestId(DataType): def convert(self, data): if isinstance(data, unicode): return data - elif isinstance(data, str): + elif isinstance(data, bytes): return data.decode("utf-8", "replace") - elif isinstance(data, tuple): + elif isinstance(data, (tuple, list)): # This is really a bit of a hack; should really split out convertors from the # fields they operate on func = Unicode(None).convert diff --git a/testing/mozbase/mozlog/mozlog/structuredlog.py b/testing/mozbase/mozlog/mozlog/structuredlog.py index adabdc31eac..fd5279b0823 100644 --- a/testing/mozbase/mozlog/mozlog/structuredlog.py +++ b/testing/mozbase/mozlog/mozlog/structuredlog.py @@ -238,7 +238,8 @@ class StructuredLogger(object): @log_action(List("tests", Unicode), Dict("run_info", default=None, optional=True), Dict("version_info", default=None, optional=True), - Dict("device_info", default=None, optional=True)) + Dict("device_info", default=None, optional=True), + Dict("extra", default=None, optional=True)) def suite_start(self, data): """Log a suite_start message @@ -252,7 +253,7 @@ class StructuredLogger(object): self._log_data("suite_start", data) - @log_action() + @log_action(Dict("extra", default=None, optional=True)) def suite_end(self, data): """Log a suite_end message""" if not self._ensure_suite_state('suite_end', data): From fc6cefa47ae352c736431045b1eaaeae8fd96240 Mon Sep 17 00:00:00 2001 From: Eddy Bruel Date: Thu, 4 Feb 2016 22:04:25 +0100 Subject: [PATCH 48/72] Bug 1212333 - WorkerDebuggerManager should live on the main thread;r=khuey --- dom/workers/RuntimeService.cpp | 6 -- dom/workers/WorkerDebuggerManager.cpp | 98 ++++++++++++++++++++++----- dom/workers/WorkerDebuggerManager.h | 83 +++++++++++++---------- layout/build/nsLayoutModule.cpp | 3 +- 4 files changed, 132 insertions(+), 58 deletions(-) diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 53319e82617..29a04e301f1 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -1974,12 +1974,6 @@ RuntimeService::Shutdown() // That's it, no more workers. mShuttingDown = true; - // Remove all listeners from the worker debugger manager to ensure that it - // gets properly destroyed. - if (NS_FAILED(ClearWorkerDebuggerManagerListeners())) { - NS_WARNING("Failed to clear worker debugger manager listeners!"); - } - nsCOMPtr obs = services::GetObserverService(); NS_WARN_IF_FALSE(obs, "Failed to get observer service?!"); diff --git a/dom/workers/WorkerDebuggerManager.cpp b/dom/workers/WorkerDebuggerManager.cpp index 28c0a878dfb..2d577c72341 100644 --- a/dom/workers/WorkerDebuggerManager.cpp +++ b/dom/workers/WorkerDebuggerManager.cpp @@ -8,22 +8,23 @@ #include "nsISimpleEnumerator.h" +#include "mozilla/ClearOnShutdown.h" + #include "WorkerPrivate.h" USING_WORKERS_NAMESPACE +namespace { + class RegisterDebuggerMainThreadRunnable final : public nsRunnable { - RefPtr mManager; WorkerPrivate* mWorkerPrivate; bool mNotifyListeners; public: - RegisterDebuggerMainThreadRunnable(WorkerDebuggerManager* aManager, - WorkerPrivate* aWorkerPrivate, + RegisterDebuggerMainThreadRunnable(WorkerPrivate* aWorkerPrivate, bool aNotifyListeners) - : mManager(aManager), - mWorkerPrivate(aWorkerPrivate), + : mWorkerPrivate(aWorkerPrivate), mNotifyListeners(aNotifyListeners) { } @@ -34,21 +35,21 @@ private: NS_IMETHOD Run() override { - mManager->RegisterDebuggerMainThread(mWorkerPrivate, mNotifyListeners); + WorkerDebuggerManager* manager = WorkerDebuggerManager::Get(); + MOZ_ASSERT(manager); + manager->RegisterDebuggerMainThread(mWorkerPrivate, mNotifyListeners); return NS_OK; } }; class UnregisterDebuggerMainThreadRunnable final : public nsRunnable { - RefPtr mManager; WorkerPrivate* mWorkerPrivate; public: - UnregisterDebuggerMainThreadRunnable(WorkerDebuggerManager* aManager, - WorkerPrivate* aWorkerPrivate) - : mManager(aManager), mWorkerPrivate(aWorkerPrivate) + UnregisterDebuggerMainThreadRunnable(WorkerPrivate* aWorkerPrivate) + : mWorkerPrivate(aWorkerPrivate) { } private: @@ -58,12 +59,19 @@ private: NS_IMETHOD Run() override { - mManager->UnregisterDebuggerMainThread(mWorkerPrivate); + WorkerDebuggerManager* manager = WorkerDebuggerManager::Get(); + MOZ_ASSERT(manager); + manager->UnregisterDebuggerMainThread(mWorkerPrivate); return NS_OK; } }; +// Does not hold an owning reference. +static WorkerDebuggerManager* gWorkerDebuggerManager; + +} /* anonymous namespace */ + BEGIN_WORKERS_NAMESPACE class WorkerDebuggerEnumerator final : public nsISimpleEnumerator @@ -116,7 +124,54 @@ WorkerDebuggerManager::~WorkerDebuggerManager() AssertIsOnMainThread(); } -NS_IMPL_ISUPPORTS(WorkerDebuggerManager, nsIWorkerDebuggerManager); +// static +already_AddRefed +WorkerDebuggerManager::GetInstance() +{ + RefPtr manager = WorkerDebuggerManager::GetOrCreate(); + return manager.forget(); +} + +// static +WorkerDebuggerManager* +WorkerDebuggerManager::GetOrCreate() +{ + AssertIsOnMainThread(); + + if (!gWorkerDebuggerManager) { + // The observer service now owns us until shutdown. + gWorkerDebuggerManager = new WorkerDebuggerManager(); + if (NS_FAILED(gWorkerDebuggerManager->Init())) { + NS_WARNING("Failed to initialize worker debugger manager!"); + gWorkerDebuggerManager = nullptr; + return nullptr; + } + } + + return gWorkerDebuggerManager; +} + +WorkerDebuggerManager* +WorkerDebuggerManager::Get() +{ + MOZ_ASSERT(gWorkerDebuggerManager); + return gWorkerDebuggerManager; +} + +NS_IMPL_ISUPPORTS(WorkerDebuggerManager, nsIObserver, nsIWorkerDebuggerManager); + +NS_IMETHODIMP +WorkerDebuggerManager::Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) +{ + if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { + Shutdown(); + return NS_OK; + } + + NS_NOTREACHED("Unknown observer topic!"); + return NS_OK; +} NS_IMETHODIMP WorkerDebuggerManager::GetWorkerDebuggerEnumerator( @@ -161,8 +216,20 @@ WorkerDebuggerManager::RemoveListener( return NS_OK; } +nsresult +WorkerDebuggerManager::Init() +{ + nsCOMPtr obs = services::GetObserverService(); + NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE); + + nsresult rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + void -WorkerDebuggerManager::ClearListeners() +WorkerDebuggerManager::Shutdown() { AssertIsOnMainThread(); @@ -205,8 +272,7 @@ WorkerDebuggerManager::RegisterDebugger(WorkerPrivate* aWorkerPrivate) } nsCOMPtr runnable = - new RegisterDebuggerMainThreadRunnable(this, aWorkerPrivate, - hasListeners); + new RegisterDebuggerMainThreadRunnable(aWorkerPrivate, hasListeners); MOZ_ALWAYS_TRUE(NS_SUCCEEDED( NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))); @@ -225,7 +291,7 @@ WorkerDebuggerManager::UnregisterDebugger(WorkerPrivate* aWorkerPrivate) UnregisterDebuggerMainThread(aWorkerPrivate); } else { nsCOMPtr runnable = - new UnregisterDebuggerMainThreadRunnable(this, aWorkerPrivate); + new UnregisterDebuggerMainThreadRunnable(aWorkerPrivate); MOZ_ALWAYS_TRUE(NS_SUCCEEDED( NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))); diff --git a/dom/workers/WorkerDebuggerManager.h b/dom/workers/WorkerDebuggerManager.h index 2b3d1b5646a..2ba6a75441c 100644 --- a/dom/workers/WorkerDebuggerManager.h +++ b/dom/workers/WorkerDebuggerManager.h @@ -9,6 +9,7 @@ #include "Workers.h" +#include "nsIObserver.h" #include "nsIWorkerDebuggerManager.h" #include "nsServiceManagerUtils.h" @@ -24,7 +25,8 @@ BEGIN_WORKERS_NAMESPACE class WorkerDebugger; -class WorkerDebuggerManager final : public nsIWorkerDebuggerManager +class WorkerDebuggerManager final : public nsIObserver, + public nsIWorkerDebuggerManager { Mutex mMutex; @@ -35,54 +37,58 @@ class WorkerDebuggerManager final : public nsIWorkerDebuggerManager nsTArray> mDebuggers; public: + static already_AddRefed + GetInstance(); + static WorkerDebuggerManager* - GetOrCreateService() - { - nsCOMPtr manager = - do_GetService(WORKERDEBUGGERMANAGER_CONTRACTID); - return static_cast(manager.get()); - } + GetOrCreate(); + + static WorkerDebuggerManager* + Get(); WorkerDebuggerManager(); - NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER NS_DECL_NSIWORKERDEBUGGERMANAGER - void ClearListeners(); + nsresult + Init(); - void RegisterDebugger(WorkerPrivate* aWorkerPrivate); + void + Shutdown(); - void UnregisterDebugger(WorkerPrivate* aWorkerPrivate); + void + RegisterDebugger(WorkerPrivate* aWorkerPrivate); - void RegisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate, - bool aNotifyListeners); + void + RegisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate, + bool aNotifyListeners); - void UnregisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate); + void + UnregisterDebugger(WorkerPrivate* aWorkerPrivate); + + void + UnregisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate); private: virtual ~WorkerDebuggerManager(); }; -inline nsresult -ClearWorkerDebuggerManagerListeners() -{ - RefPtr manager = - WorkerDebuggerManager::GetOrCreateService(); - if (!manager) { - return NS_ERROR_FAILURE; - } - - manager->ClearListeners(); - return NS_OK; -} - inline nsresult RegisterWorkerDebugger(WorkerPrivate* aWorkerPrivate) { - RefPtr manager = - WorkerDebuggerManager::GetOrCreateService(); - if (!manager) { - return NS_ERROR_FAILURE; + WorkerDebuggerManager* manager; + + if (NS_IsMainThread()) { + manager = WorkerDebuggerManager::GetOrCreate(); + if (!manager) { + NS_WARNING("Failed to create worker debugger manager!"); + return NS_ERROR_FAILURE; + } + } + else { + manager = WorkerDebuggerManager::Get(); } manager->RegisterDebugger(aWorkerPrivate); @@ -92,10 +98,17 @@ RegisterWorkerDebugger(WorkerPrivate* aWorkerPrivate) inline nsresult UnregisterWorkerDebugger(WorkerPrivate* aWorkerPrivate) { - RefPtr manager = - WorkerDebuggerManager::GetOrCreateService(); - if (!manager) { - return NS_ERROR_FAILURE; + WorkerDebuggerManager* manager; + + if (NS_IsMainThread()) { + manager = WorkerDebuggerManager::GetOrCreate(); + if (!manager) { + NS_WARNING("Failed to create worker debugger manager!"); + return NS_ERROR_FAILURE; + } + } + else { + manager = WorkerDebuggerManager::Get(); } manager->UnregisterDebugger(aWorkerPrivate); diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index 43c829c80e8..098c770e53c 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -322,7 +322,8 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(QuotaManagerService, QuotaManagerService::FactoryCreate) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(ServiceWorkerManager, ServiceWorkerManager::GetInstance) -NS_GENERIC_FACTORY_CONSTRUCTOR(WorkerDebuggerManager) +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WorkerDebuggerManager, + WorkerDebuggerManager::GetInstance) #ifdef MOZ_WIDGET_GONK NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(SystemWorkerManager, From be0e35fb437810417a5020caecd7c208ca6d156b Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Fri, 5 Feb 2016 16:09:28 +0100 Subject: [PATCH 49/72] Backed out changeset a6bc2efcdf26 (bug 1212333) for bustage --- dom/workers/RuntimeService.cpp | 6 ++ dom/workers/WorkerDebuggerManager.cpp | 98 +++++---------------------- dom/workers/WorkerDebuggerManager.h | 83 ++++++++++------------- layout/build/nsLayoutModule.cpp | 3 +- 4 files changed, 58 insertions(+), 132 deletions(-) diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 29a04e301f1..53319e82617 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -1974,6 +1974,12 @@ RuntimeService::Shutdown() // That's it, no more workers. mShuttingDown = true; + // Remove all listeners from the worker debugger manager to ensure that it + // gets properly destroyed. + if (NS_FAILED(ClearWorkerDebuggerManagerListeners())) { + NS_WARNING("Failed to clear worker debugger manager listeners!"); + } + nsCOMPtr obs = services::GetObserverService(); NS_WARN_IF_FALSE(obs, "Failed to get observer service?!"); diff --git a/dom/workers/WorkerDebuggerManager.cpp b/dom/workers/WorkerDebuggerManager.cpp index 2d577c72341..28c0a878dfb 100644 --- a/dom/workers/WorkerDebuggerManager.cpp +++ b/dom/workers/WorkerDebuggerManager.cpp @@ -8,23 +8,22 @@ #include "nsISimpleEnumerator.h" -#include "mozilla/ClearOnShutdown.h" - #include "WorkerPrivate.h" USING_WORKERS_NAMESPACE -namespace { - class RegisterDebuggerMainThreadRunnable final : public nsRunnable { + RefPtr mManager; WorkerPrivate* mWorkerPrivate; bool mNotifyListeners; public: - RegisterDebuggerMainThreadRunnable(WorkerPrivate* aWorkerPrivate, + RegisterDebuggerMainThreadRunnable(WorkerDebuggerManager* aManager, + WorkerPrivate* aWorkerPrivate, bool aNotifyListeners) - : mWorkerPrivate(aWorkerPrivate), + : mManager(aManager), + mWorkerPrivate(aWorkerPrivate), mNotifyListeners(aNotifyListeners) { } @@ -35,21 +34,21 @@ private: NS_IMETHOD Run() override { - WorkerDebuggerManager* manager = WorkerDebuggerManager::Get(); - MOZ_ASSERT(manager); + mManager->RegisterDebuggerMainThread(mWorkerPrivate, mNotifyListeners); - manager->RegisterDebuggerMainThread(mWorkerPrivate, mNotifyListeners); return NS_OK; } }; class UnregisterDebuggerMainThreadRunnable final : public nsRunnable { + RefPtr mManager; WorkerPrivate* mWorkerPrivate; public: - UnregisterDebuggerMainThreadRunnable(WorkerPrivate* aWorkerPrivate) - : mWorkerPrivate(aWorkerPrivate) + UnregisterDebuggerMainThreadRunnable(WorkerDebuggerManager* aManager, + WorkerPrivate* aWorkerPrivate) + : mManager(aManager), mWorkerPrivate(aWorkerPrivate) { } private: @@ -59,19 +58,12 @@ private: NS_IMETHOD Run() override { - WorkerDebuggerManager* manager = WorkerDebuggerManager::Get(); - MOZ_ASSERT(manager); + mManager->UnregisterDebuggerMainThread(mWorkerPrivate); - manager->UnregisterDebuggerMainThread(mWorkerPrivate); return NS_OK; } }; -// Does not hold an owning reference. -static WorkerDebuggerManager* gWorkerDebuggerManager; - -} /* anonymous namespace */ - BEGIN_WORKERS_NAMESPACE class WorkerDebuggerEnumerator final : public nsISimpleEnumerator @@ -124,54 +116,7 @@ WorkerDebuggerManager::~WorkerDebuggerManager() AssertIsOnMainThread(); } -// static -already_AddRefed -WorkerDebuggerManager::GetInstance() -{ - RefPtr manager = WorkerDebuggerManager::GetOrCreate(); - return manager.forget(); -} - -// static -WorkerDebuggerManager* -WorkerDebuggerManager::GetOrCreate() -{ - AssertIsOnMainThread(); - - if (!gWorkerDebuggerManager) { - // The observer service now owns us until shutdown. - gWorkerDebuggerManager = new WorkerDebuggerManager(); - if (NS_FAILED(gWorkerDebuggerManager->Init())) { - NS_WARNING("Failed to initialize worker debugger manager!"); - gWorkerDebuggerManager = nullptr; - return nullptr; - } - } - - return gWorkerDebuggerManager; -} - -WorkerDebuggerManager* -WorkerDebuggerManager::Get() -{ - MOZ_ASSERT(gWorkerDebuggerManager); - return gWorkerDebuggerManager; -} - -NS_IMPL_ISUPPORTS(WorkerDebuggerManager, nsIObserver, nsIWorkerDebuggerManager); - -NS_IMETHODIMP -WorkerDebuggerManager::Observe(nsISupports* aSubject, const char* aTopic, - const char16_t* aData) -{ - if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { - Shutdown(); - return NS_OK; - } - - NS_NOTREACHED("Unknown observer topic!"); - return NS_OK; -} +NS_IMPL_ISUPPORTS(WorkerDebuggerManager, nsIWorkerDebuggerManager); NS_IMETHODIMP WorkerDebuggerManager::GetWorkerDebuggerEnumerator( @@ -216,20 +161,8 @@ WorkerDebuggerManager::RemoveListener( return NS_OK; } -nsresult -WorkerDebuggerManager::Init() -{ - nsCOMPtr obs = services::GetObserverService(); - NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE); - - nsresult rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - void -WorkerDebuggerManager::Shutdown() +WorkerDebuggerManager::ClearListeners() { AssertIsOnMainThread(); @@ -272,7 +205,8 @@ WorkerDebuggerManager::RegisterDebugger(WorkerPrivate* aWorkerPrivate) } nsCOMPtr runnable = - new RegisterDebuggerMainThreadRunnable(aWorkerPrivate, hasListeners); + new RegisterDebuggerMainThreadRunnable(this, aWorkerPrivate, + hasListeners); MOZ_ALWAYS_TRUE(NS_SUCCEEDED( NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))); @@ -291,7 +225,7 @@ WorkerDebuggerManager::UnregisterDebugger(WorkerPrivate* aWorkerPrivate) UnregisterDebuggerMainThread(aWorkerPrivate); } else { nsCOMPtr runnable = - new UnregisterDebuggerMainThreadRunnable(aWorkerPrivate); + new UnregisterDebuggerMainThreadRunnable(this, aWorkerPrivate); MOZ_ALWAYS_TRUE(NS_SUCCEEDED( NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))); diff --git a/dom/workers/WorkerDebuggerManager.h b/dom/workers/WorkerDebuggerManager.h index 2ba6a75441c..2b3d1b5646a 100644 --- a/dom/workers/WorkerDebuggerManager.h +++ b/dom/workers/WorkerDebuggerManager.h @@ -9,7 +9,6 @@ #include "Workers.h" -#include "nsIObserver.h" #include "nsIWorkerDebuggerManager.h" #include "nsServiceManagerUtils.h" @@ -25,8 +24,7 @@ BEGIN_WORKERS_NAMESPACE class WorkerDebugger; -class WorkerDebuggerManager final : public nsIObserver, - public nsIWorkerDebuggerManager +class WorkerDebuggerManager final : public nsIWorkerDebuggerManager { Mutex mMutex; @@ -37,58 +35,54 @@ class WorkerDebuggerManager final : public nsIObserver, nsTArray> mDebuggers; public: - static already_AddRefed - GetInstance(); - static WorkerDebuggerManager* - GetOrCreate(); - - static WorkerDebuggerManager* - Get(); + GetOrCreateService() + { + nsCOMPtr manager = + do_GetService(WORKERDEBUGGERMANAGER_CONTRACTID); + return static_cast(manager.get()); + } WorkerDebuggerManager(); - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER + NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIWORKERDEBUGGERMANAGER - nsresult - Init(); + void ClearListeners(); - void - Shutdown(); + void RegisterDebugger(WorkerPrivate* aWorkerPrivate); - void - RegisterDebugger(WorkerPrivate* aWorkerPrivate); + void UnregisterDebugger(WorkerPrivate* aWorkerPrivate); - void - RegisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate, - bool aNotifyListeners); + void RegisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate, + bool aNotifyListeners); - void - UnregisterDebugger(WorkerPrivate* aWorkerPrivate); - - void - UnregisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate); + void UnregisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate); private: virtual ~WorkerDebuggerManager(); }; +inline nsresult +ClearWorkerDebuggerManagerListeners() +{ + RefPtr manager = + WorkerDebuggerManager::GetOrCreateService(); + if (!manager) { + return NS_ERROR_FAILURE; + } + + manager->ClearListeners(); + return NS_OK; +} + inline nsresult RegisterWorkerDebugger(WorkerPrivate* aWorkerPrivate) { - WorkerDebuggerManager* manager; - - if (NS_IsMainThread()) { - manager = WorkerDebuggerManager::GetOrCreate(); - if (!manager) { - NS_WARNING("Failed to create worker debugger manager!"); - return NS_ERROR_FAILURE; - } - } - else { - manager = WorkerDebuggerManager::Get(); + RefPtr manager = + WorkerDebuggerManager::GetOrCreateService(); + if (!manager) { + return NS_ERROR_FAILURE; } manager->RegisterDebugger(aWorkerPrivate); @@ -98,17 +92,10 @@ RegisterWorkerDebugger(WorkerPrivate* aWorkerPrivate) inline nsresult UnregisterWorkerDebugger(WorkerPrivate* aWorkerPrivate) { - WorkerDebuggerManager* manager; - - if (NS_IsMainThread()) { - manager = WorkerDebuggerManager::GetOrCreate(); - if (!manager) { - NS_WARNING("Failed to create worker debugger manager!"); - return NS_ERROR_FAILURE; - } - } - else { - manager = WorkerDebuggerManager::Get(); + RefPtr manager = + WorkerDebuggerManager::GetOrCreateService(); + if (!manager) { + return NS_ERROR_FAILURE; } manager->UnregisterDebugger(aWorkerPrivate); diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index 098c770e53c..43c829c80e8 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -322,8 +322,7 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(QuotaManagerService, QuotaManagerService::FactoryCreate) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(ServiceWorkerManager, ServiceWorkerManager::GetInstance) -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WorkerDebuggerManager, - WorkerDebuggerManager::GetInstance) +NS_GENERIC_FACTORY_CONSTRUCTOR(WorkerDebuggerManager) #ifdef MOZ_WIDGET_GONK NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(SystemWorkerManager, From d1c3eed1b29e041fae1dc3fb8b489932d43aa383 Mon Sep 17 00:00:00 2001 From: Mike Taylor Date: Thu, 4 Feb 2016 17:11:41 -0600 Subject: [PATCH 50/72] Bug 1245997. Remove -webkit-mask-mode alias. r=dholbert This has not yet been implemented in WebKit, hence there shouldn't be any legacy compat concerns. --- layout/style/nsCSSPropAliasList.h | 4 ---- layout/style/test/property_database.js | 7 ------- 2 files changed, 11 deletions(-) diff --git a/layout/style/nsCSSPropAliasList.h b/layout/style/nsCSSPropAliasList.h index e03bac56c69..6726da05605 100644 --- a/layout/style/nsCSSPropAliasList.h +++ b/layout/style/nsCSSPropAliasList.h @@ -366,10 +366,6 @@ CSS_PROP_ALIAS(-webkit-mask-image, mask_image, WebkitMaskImage, WEBKIT_PREFIX_PREF) -CSS_PROP_ALIAS(-webkit-mask-mode, - mask_mode, - WebkitMaskMode, - WEBKIT_PREFIX_PREF) CSS_PROP_ALIAS(-webkit-mask-origin, mask_origin, WebkitMaskOrigin, diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index ca2697872d7..b8a3d3ed4f4 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -7250,13 +7250,6 @@ if (IsCSSPropertyPrefEnabled("layout.css.prefixes.webkit")) { alias_for: "mask-image", subproperties: [ "mask-image" ], }; - gCSSProperties["-webkit-mask-mode"] = { - domProp: "webkitMaskMode", - inherited: false, - type: CSS_TYPE_SHORTHAND_AND_LONGHAND, - alias_for: "mask-mode", - subproperties: [ "mask-mode" ], - }; gCSSProperties["-webkit-mask-origin"] = { domProp: "webkitMaskOrigin", inherited: false, From 9d79527f475b4dd0ddd129e4f4cbd6b1464b3953 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Tue, 2 Feb 2016 14:15:37 -0500 Subject: [PATCH 51/72] Bug 1245269 - Part 1: Make clang-plugin build with clang 3.8 and newer; r=mystor --- build/clang-plugin/clang-plugin.cpp | 33 +++++++++++++++++++---------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/build/clang-plugin/clang-plugin.cpp b/build/clang-plugin/clang-plugin.cpp index 9d442bdfc94..778e4e49548 100644 --- a/build/clang-plugin/clang-plugin.cpp +++ b/build/clang-plugin/clang-plugin.cpp @@ -28,6 +28,17 @@ typedef std::unique_ptr ASTConsumerPtr; typedef ASTConsumer *ASTConsumerPtr; #endif +#if CLANG_VERSION_FULL < 308 +// In clang 3.8, a number of AST matchers were renamed to better match the +// respective AST node. We use the new names, and #define them to the old +// ones for compatibility with older versions. +#define cxxConstructExpr constructExpr +#define cxxConstructorDecl constructorDecl +#define cxxMethodDecl methodDecl +#define cxxNewExpr newExpr +#define cxxRecordDecl recordDecl +#endif + namespace { using namespace clang::ast_matchers; @@ -893,7 +904,7 @@ bool isPlacementNew(const CXXNewExpr *Expr) { DiagnosticsMatcher::DiagnosticsMatcher() { astMatcher.addMatcher(varDecl().bind("node"), &scopeChecker); - astMatcher.addMatcher(newExpr().bind("node"), &scopeChecker); + astMatcher.addMatcher(cxxNewExpr().bind("node"), &scopeChecker); astMatcher.addMatcher(materializeTemporaryExpr().bind("node"), &scopeChecker); astMatcher.addMatcher( callExpr(callee(functionDecl(heapAllocator()))).bind("node"), @@ -919,7 +930,7 @@ DiagnosticsMatcher::DiagnosticsMatcher() { .bind("call"), &arithmeticArgChecker); astMatcher.addMatcher( - constructExpr( + cxxConstructExpr( allOf(hasDeclaration(noArithmeticExprInArgs()), anyOf(hasDescendant( binaryOperator( @@ -938,7 +949,7 @@ DiagnosticsMatcher::DiagnosticsMatcher() { .bind("call"), &arithmeticArgChecker); - astMatcher.addMatcher(recordDecl(hasTrivialCtorDtor()).bind("node"), + astMatcher.addMatcher(cxxRecordDecl(hasTrivialCtorDtor()).bind("node"), &trivialCtorDtorChecker); astMatcher.addMatcher( @@ -981,12 +992,12 @@ DiagnosticsMatcher::DiagnosticsMatcher() { // conversions as 'operator _Bool', but newer clang versions recognize these // as 'operator bool'. astMatcher.addMatcher( - methodDecl(anyOf(hasName("operator bool"), hasName("operator _Bool"))) + cxxMethodDecl(anyOf(hasName("operator bool"), hasName("operator _Bool"))) .bind("node"), &explicitOperatorBoolChecker); astMatcher.addMatcher( - recordDecl(allOf(decl().bind("decl"), hasRefCntMember())), + cxxRecordDecl(allOf(decl().bind("decl"), hasRefCntMember())), &noDuplicateRefCntMemberChecker); astMatcher.addMatcher( @@ -1005,20 +1016,20 @@ DiagnosticsMatcher::DiagnosticsMatcher() { &nonMemMovableChecker); astMatcher.addMatcher( - constructorDecl(isInterestingImplicitCtor(), - ofClass(allOf(isConcreteClass(), decl().bind("class"))), - unless(isMarkedImplicit())) + cxxConstructorDecl(isInterestingImplicitCtor(), + ofClass(allOf(isConcreteClass(), decl().bind("class"))), + unless(isMarkedImplicit())) .bind("ctor"), &explicitImplicitChecker); astMatcher.addMatcher(varDecl(hasType(autoNonAutoableType())).bind("node"), &noAutoTypeChecker); - astMatcher.addMatcher(constructorDecl(isExplicitMoveConstructor()).bind("node"), + astMatcher.addMatcher(cxxConstructorDecl(isExplicitMoveConstructor()).bind("node"), &noExplicitMoveConstructorChecker); - astMatcher.addMatcher(constructExpr(hasDeclaration( - constructorDecl( + astMatcher.addMatcher(cxxConstructExpr(hasDeclaration( + cxxConstructorDecl( isCompilerProvidedCopyConstructor(), ofClass(hasRefCntMember())))).bind("node"), &refCountedCopyConstructorChecker); From 5f41a8ae9c171cc0e288baacbeae98319e1e766e Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Wed, 3 Feb 2016 13:33:33 -0500 Subject: [PATCH 52/72] Bug 1245269 - Part 2: Add a configure check for the existence of the new AST Matcher API names; r=glandium --- build/autoconf/clang-plugin.m4 | 21 +++++++++++++++++++++ build/clang-plugin/clang-plugin.cpp | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/build/autoconf/clang-plugin.m4 b/build/autoconf/clang-plugin.m4 index 5618a1c312b..cfc971c8754 100644 --- a/build/autoconf/clang-plugin.m4 +++ b/build/autoconf/clang-plugin.m4 @@ -48,6 +48,27 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then CLANG_LDFLAGS="-lclangASTMatchers" fi + dnl Check for the new ASTMatcher API names. Since this happened in the + dnl middle of the 3.8 cycle, our CLANG_VERSION_FULL is impossible to use + dnl correctly, so we have to detect this at configure time. + AC_CACHE_CHECK(for new ASTMatcher names, + ac_cv_have_new_ASTMatcher_names, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + _SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="${LLVM_CXXFLAGS}" + AC_TRY_COMPILE([#include "clang/ASTMatchers/ASTMatchers.h"], + [clang::ast_matchers::cxxConstructExpr();], + ac_cv_have_new_ASTMatcher_names="yes", + ac_cv_have_new_ASTMatcher_names="no") + CXXFLAGS="$_SAVE_CXXFLAGS" + AC_LANG_RESTORE + ]) + if test "$ac_cv_have_new_ASTMatcher_names" = "yes"; then + LLVM_CXXFLAGS="$LLVM_CXXFLAGS -DHAVE_NEW_ASTMATCHER_NAMES" + fi + AC_DEFINE(MOZ_CLANG_PLUGIN) fi diff --git a/build/clang-plugin/clang-plugin.cpp b/build/clang-plugin/clang-plugin.cpp index 778e4e49548..8a2b90d72c9 100644 --- a/build/clang-plugin/clang-plugin.cpp +++ b/build/clang-plugin/clang-plugin.cpp @@ -28,7 +28,7 @@ typedef std::unique_ptr ASTConsumerPtr; typedef ASTConsumer *ASTConsumerPtr; #endif -#if CLANG_VERSION_FULL < 308 +#ifndef HAVE_NEW_ASTMATCHER_NAMES // In clang 3.8, a number of AST matchers were renamed to better match the // respective AST node. We use the new names, and #define them to the old // ones for compatibility with older versions. From ab1bf1e0f2ab1523d1f53f3d9325b070b0c5f4c3 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Fri, 5 Feb 2016 10:29:26 -0500 Subject: [PATCH 53/72] Reformat clang-plugin.cpp using clang-format, no bug --- build/clang-plugin/clang-plugin.cpp | 87 +++++++++++++++-------------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/build/clang-plugin/clang-plugin.cpp b/build/clang-plugin/clang-plugin.cpp index 8a2b90d72c9..586533fcf8f 100644 --- a/build/clang-plugin/clang-plugin.cpp +++ b/build/clang-plugin/clang-plugin.cpp @@ -5,8 +5,8 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecursiveASTVisitor.h" -#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/Version.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendPluginRegistry.h" @@ -986,7 +986,8 @@ DiagnosticsMatcher::DiagnosticsMatcher() { // lambda, where the declaration they reference is not inside the lambda. // This excludes arguments and local variables, leaving only captured // variables. - astMatcher.addMatcher(lambdaExpr().bind("lambda"), &refCountedInsideLambdaChecker); + astMatcher.addMatcher(lambdaExpr().bind("lambda"), + &refCountedInsideLambdaChecker); // Older clang versions such as the ones used on the infra recognize these // conversions as 'operator _Bool', but newer clang versions recognize these @@ -1015,24 +1016,26 @@ DiagnosticsMatcher::DiagnosticsMatcher() { .bind("specialization"), &nonMemMovableChecker); - astMatcher.addMatcher( - cxxConstructorDecl(isInterestingImplicitCtor(), - ofClass(allOf(isConcreteClass(), decl().bind("class"))), - unless(isMarkedImplicit())) - .bind("ctor"), - &explicitImplicitChecker); + astMatcher.addMatcher(cxxConstructorDecl(isInterestingImplicitCtor(), + ofClass(allOf(isConcreteClass(), + decl().bind("class"))), + unless(isMarkedImplicit())) + .bind("ctor"), + &explicitImplicitChecker); astMatcher.addMatcher(varDecl(hasType(autoNonAutoableType())).bind("node"), &noAutoTypeChecker); - astMatcher.addMatcher(cxxConstructorDecl(isExplicitMoveConstructor()).bind("node"), - &noExplicitMoveConstructorChecker); + astMatcher.addMatcher( + cxxConstructorDecl(isExplicitMoveConstructor()).bind("node"), + &noExplicitMoveConstructorChecker); - astMatcher.addMatcher(cxxConstructExpr(hasDeclaration( - cxxConstructorDecl( - isCompilerProvidedCopyConstructor(), - ofClass(hasRefCntMember())))).bind("node"), - &refCountedCopyConstructorChecker); + astMatcher.addMatcher( + cxxConstructExpr( + hasDeclaration(cxxConstructorDecl(isCompilerProvidedCopyConstructor(), + ofClass(hasRefCntMember())))) + .bind("node"), + &refCountedCopyConstructorChecker); } // These enum variants determine whether an allocation has occured in the code. @@ -1047,7 +1050,8 @@ enum AllocationVariety { // XXX Currently the Decl* in the AutomaticTemporaryMap is unused, but it // probably will be used at some point in the future, in order to produce better // error messages. -typedef DenseMap AutomaticTemporaryMap; +typedef DenseMap + AutomaticTemporaryMap; AutomaticTemporaryMap AutomaticTemporaries; void DiagnosticsMatcher::ScopeChecker::run( @@ -1059,9 +1063,11 @@ void DiagnosticsMatcher::ScopeChecker::run( SourceLocation Loc; QualType T; - if (const ParmVarDecl *D = Result.Nodes.getNodeAs("parm_vardecl")) { + if (const ParmVarDecl *D = + Result.Nodes.getNodeAs("parm_vardecl")) { if (const Expr *Default = D->getDefaultArg()) { - if (const MaterializeTemporaryExpr *E = dyn_cast(Default)) { + if (const MaterializeTemporaryExpr *E = + dyn_cast(Default)) { // We have just found a ParmVarDecl which has, as its default argument, // a MaterializeTemporaryExpr. We mark that MaterializeTemporaryExpr as // automatic, by adding it to the AutomaticTemporaryMap. @@ -1100,18 +1106,17 @@ void DiagnosticsMatcher::ScopeChecker::run( // XXX We maybe should mark these lifetimes as being due to a temporary // which has had its lifetime extended, to improve the error messages. switch (E->getStorageDuration()) { - case SD_FullExpression: - { - // Check if this temporary is allocated as a default argument! - // if it is, we want to pretend that it is automatic. - AutomaticTemporaryMap::iterator AutomaticTemporary = AutomaticTemporaries.find(E); - if (AutomaticTemporary != AutomaticTemporaries.end()) { - Variety = AV_Automatic; - } else { - Variety = AV_Temporary; - } + case SD_FullExpression: { + // Check if this temporary is allocated as a default argument! + // if it is, we want to pretend that it is automatic. + AutomaticTemporaryMap::iterator AutomaticTemporary = + AutomaticTemporaries.find(E); + if (AutomaticTemporary != AutomaticTemporaries.end()) { + Variety = AV_Automatic; + } else { + Variety = AV_Temporary; } - break; + } break; case SD_Automatic: Variety = AV_Automatic; break; @@ -1176,8 +1181,8 @@ void DiagnosticsMatcher::ScopeChecker::run( case AV_Temporary: GlobalClass.reportErrorIfPresent(Diag, T, Loc, GlobalID, TemporaryNoteID); HeapClass.reportErrorIfPresent(Diag, T, Loc, HeapID, TemporaryNoteID); - NonTemporaryClass.reportErrorIfPresent(Diag, T, Loc, - NonTemporaryID, TemporaryNoteID); + NonTemporaryClass.reportErrorIfPresent(Diag, T, Loc, NonTemporaryID, + TemporaryNoteID); break; case AV_Heap: @@ -1287,8 +1292,8 @@ void DiagnosticsMatcher::RefCountedInsideLambdaChecker::run( QualType Pointee = Capture.getCapturedVar()->getType()->getPointeeType(); if (!Pointee.isNull() && isClassRefCounted(Pointee)) { - Diag.Report(Capture.getLocation(), errorID) - << Capture.getCapturedVar() << Pointee; + Diag.Report(Capture.getLocation(), errorID) << Capture.getCapturedVar() + << Pointee; Diag.Report(Capture.getLocation(), noteID); } } @@ -1456,7 +1461,7 @@ void DiagnosticsMatcher::NoExplicitMoveConstructorChecker::run( // Everything we needed to know was checked in the matcher - we just report // the error here const CXXConstructorDecl *D = - Result.Nodes.getNodeAs("node"); + Result.Nodes.getNodeAs("node"); Diag.Report(D->getLocation(), ErrorID); } @@ -1468,16 +1473,16 @@ void DiagnosticsMatcher::RefCountedCopyConstructorChecker::run( DiagnosticIDs::Error, "Invalid use of compiler-provided copy constructor " "on refcounted type"); unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, "The default copy constructor also copies the " - "default mRefCnt property, leading to reference " - "count imbalance issues. Please provide your own " - "copy constructor which only copies the fields which " - "need to be copied"); + DiagnosticIDs::Note, + "The default copy constructor also copies the " + "default mRefCnt property, leading to reference " + "count imbalance issues. Please provide your own " + "copy constructor which only copies the fields which " + "need to be copied"); // Everything we needed to know was checked in the matcher - we just report // the error here - const CXXConstructExpr *E = - Result.Nodes.getNodeAs("node"); + const CXXConstructExpr *E = Result.Nodes.getNodeAs("node"); Diag.Report(E->getLocation(), ErrorID); Diag.Report(E->getLocation(), NoteID); From d6b9089f6d07e6dd899de9fdfe77cf762b8982c1 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 5 Feb 2016 10:41:08 -0500 Subject: [PATCH 54/72] Bug 1243824. Add support for static functions and attributes on JSXrays. r=bholley --- js/xpconnect/tests/chrome/test_xrayToJS.xul | 133 +++++++- js/xpconnect/wrappers/XrayWrapper.cpp | 321 +++++++++++++------- 2 files changed, 331 insertions(+), 123 deletions(-) diff --git a/js/xpconnect/tests/chrome/test_xrayToJS.xul b/js/xpconnect/tests/chrome/test_xrayToJS.xul index cbcd427d235..bb15ea3f5f2 100644 --- a/js/xpconnect/tests/chrome/test_xrayToJS.xul +++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul @@ -135,7 +135,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 // We could also test DataView and Iterator here for completeness, but it's // more trouble than it's worth. - SimpleTest.finish(); } @@ -148,6 +147,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 var isNightlyBuild = version.endsWith("a1"); var isReleaseBuild = !version.includes("a"); var gPrototypeProperties = {}; + var gConstructorProperties = {}; + function constructorProps(arr) { + // Some props live on all constructors + return arr.concat(["prototype", "length", "name"]); + } gPrototypeProperties['Date'] = ["getTime", "getTimezoneOffset", "getYear", "getFullYear", "getUTCFullYear", "getMonth", "getUTCMonth", "getDate", "getUTCDate", "getDay", "getUTCDay", @@ -160,30 +164,47 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 "toLocaleDateString", "toLocaleTimeString", "toDateString", "toTimeString", "toISOString", "toJSON", "toSource", "toString", "valueOf", "constructor", "toGMTString", Symbol.toPrimitive]; + gConstructorProperties['Date'] = constructorProps(["UTC", "parse", "now"]); gPrototypeProperties['Object'] = ["constructor", "toSource", "toString", "toLocaleString", "valueOf", "watch", "unwatch", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__", "__proto__"]; + gConstructorProperties['Object'] = + constructorProps(["setPrototypeOf", "getOwnPropertyDescriptor", "keys", + "is", "defineProperty", "defineProperties", "create", + "getOwnPropertyNames", "getOwnPropertySymbols", + "preventExtensions", "freeze", "isFrozen", "seal", + "isSealed", "assign", "getPrototypeOf", "values", + "entries", "isExtensible"]) gPrototypeProperties['Array'] = ["length", "toSource", "toString", "toLocaleString", "join", "reverse", "sort", "push", "pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf", "includes", "forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "find", "findIndex", "copyWithin", "fill", Symbol.iterator, "entries", "keys", "constructor"]; + gConstructorProperties['Array'] = + constructorProps(["join", "reverse", "sort", "push", "pop", "shift", + "unshift", "splice", "concat", "slice", "isArray", + "lastIndexOf", "indexOf", "forEach", "map", "filter", + "every", "some", "reduce", "reduceRight", "from", "of"]); for (var c of typedArrayClasses) { gPrototypeProperties[c] = ["constructor", "BYTES_PER_ELEMENT"]; + gConstructorProperties[c] = constructorProps(["BYTES_PER_ELEMENT"]); } gPrototypeProperties['TypedArray'] = ["length", "buffer", "byteLength", "byteOffset", Symbol.iterator, "subarray", "set", "copyWithin", "find", "findIndex", "forEach","indexOf", "lastIndexOf", "includes", "reverse", "join", "every", "some", "reduce", "reduceRight", "entries", "keys", "values", "slice", "map", "filter"]; + // There is no TypedArray constructor, looks like. + is(window.TypedArray, undefined, "If this ever changes, add to this test!"); for (var c of errorObjectClasses) { gPrototypeProperties[c] = ["constructor", "name", // We don't actually resolve these empty data properties // onto the Xray prototypes, but we list them here to make // the test happy. "lineNumber", "columnNumber", "fileName", "message", "stack"]; + gConstructorProperties[c] = constructorProps([]); } // toString and toSource only live on the parent proto (Error.prototype). gPrototypeProperties['Error'].push('toString'); @@ -192,14 +213,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 gPrototypeProperties['Function'] = ["constructor", "toSource", "toString", "apply", "call", "bind", "isGenerator", "length", "name", "arguments", "caller"]; - gPrototypeProperties['Function'] = - ["constructor", "toSource", "toString", "apply", "call", "bind", - "isGenerator", "length", "name", "arguments", "caller"]; + gConstructorProperties['Function'] = constructorProps([]) gPrototypeProperties['RegExp'] = ["constructor", "toSource", "toString", "compile", "exec", "test", "flags", "global", "ignoreCase", "multiline", "source", "sticky", "unicode", "lastIndex"]; + gConstructorProperties['RegExp'] = + constructorProps(["input", "multiline", "lastMatch", "lastParen", + "leftContext", "rightContext", "$1", "$2", "$3", "$4", + "$5", "$6", "$7", "$8", "$9", "$_", "$*", "$&", "$+", + "$`", "$'"]) // Sort an array that may contain symbols as well as strings. function sortProperties(arr) { @@ -213,6 +237,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 // again to sort them). for (var c of Object.keys(gPrototypeProperties)) sortProperties(gPrototypeProperties[c]); + for (var c of Object.keys(gConstructorProperties)) + sortProperties(gConstructorProperties[c]); function filterOut(array, props) { return array.filter(p => props.indexOf(p) == -1); @@ -265,7 +291,57 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 } } - function testXray(classname, xray, xray2, propsToSkip) { + function testCtorCallables(ctorCallables, xrayCtor, localCtor) { + for (let name of ctorCallables) { + // Don't try to test Function.prototype, since that is in fact a callable + // but doesn't really do the things we expect callables to do here + // (e.g. it's in the wrong global, since it gets Xrayed itself). + if (name == "prototype" && localCtor.name == "Function") { + continue; + } + info(`Running tests for property: ${localCtor.name}.${name}`); + // Test both methods and getter properties. + function lookupCallable(obj) { + let desc = null; + do { + desc = Object.getOwnPropertyDescriptor(obj, name); + obj = Object.getPrototypeOf(obj); + } while (!desc); + return desc.get || desc.value; + }; + + ok(xrayCtor.hasOwnProperty(name), "ctor should have the property as own"); + let method = lookupCallable(xrayCtor); + is(typeof method, 'function', "Methods from ctor Xrays are functions"); + is(global(method), window, "Methods from ctor Xrays are local"); + ok(method instanceof Function, + "instanceof works on methods from ctor Xrays"); + is(lookupCallable(xrayCtor), method, + "Holder caching works properly on ctors"); + let local = lookupCallable(localCtor); + is(method.length, local.length, + "Function.length identical for method from ctor"); + // Don't try to do the return-value check on Date.now(), since there is + // absolutely no reason it should return the same value each time. + // + // Also don't try to do the return-value check on Regexp.lastMatch and + // Regexp["$&"] (which are aliases), because they get state off the global + // they live in, as far as I can tell, so testing them over Xrays will be + // wrong: on the Xray they will actaully get the lastMatch of _our_ + // global, not the Xrayed one. + if (method.length == 0 && + !(localCtor.name == "Date" && name == "now") && + !(localCtor.name == "RegExp" && (name == "lastMatch" || name == "$&"))) { + is(method.call(xrayCtor) + "", local.call(xrayCtor) + "", + "Xray and local method results stringify identically on constructors"); + is(method.call(xrayCtor) + "", + lookupCallable(xrayCtor.wrappedJSObject).call(xrayCtor.wrappedJSObject) + "", + "Xray and waived method results stringify identically"); + } + } + } + + function testXray(classname, xray, xray2, propsToSkip, ctorPropsToSkip = []) { propsToSkip = propsToSkip || []; let xrayProto = Object.getPrototypeOf(xray); let localProto = window[classname].prototype; @@ -294,13 +370,39 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 protoProps.toSource(), "getOwnPropertyNames works"); is(Object.getOwnPropertySymbols(xrayProto).map(uneval).sort().toSource(), gPrototypeProperties[classname].filter(id => typeof id !== "string").map(uneval).sort().toSource(), - protoProps.toSource(), "getOwnPropertySymbols works"); + "getOwnPropertySymbols works"); is(xrayProto.constructor, iwin[classname], "constructor property works"); xrayProto.expando = 42; is(xray.expando, 42, "Xrayed instances see proto expandos"); is(xray2.expando, 42, "Xrayed instances see proto expandos"); + + // Now test constructors + localCtor = window[classname]; + xrayCtor = xrayProto.constructor; + // We already checked that this is the same as iwin[classname] + + let desiredCtorProps = + Object.getOwnPropertyNames(localCtor).sort(); + is(desiredCtorProps.toSource(), + gConstructorProperties[classname].filter(id => typeof id === "string").toSource(), + "A property on the " + classname + + " constructor has changed! You need a security audit from an XPConnect peer"); + is(Object.getOwnPropertySymbols(localCtor).map(uneval).sort().toSource(), + gConstructorProperties[classname].filter(id => typeof id !== "string").map(uneval).sort().toSource(), + "A symbol-keyed property on the " + classname + + " constructor has been changed! You need a security audit from an XPConnect peer"); + + let ctorProps = filterOut(desiredCtorProps, ctorPropsToSkip); + let ctorCallables = ctorProps.filter(name => propertyIsGetter(localCtor, name, classname) || + typeof localCtor[name] == 'function'); + testCtorCallables(ctorCallables, xrayCtor, localCtor); + is(Object.getOwnPropertyNames(xrayCtor).sort().toSource(), + ctorProps.toSource(), "getOwnPropertyNames works on Xrayed ctors"); + is(Object.getOwnPropertySymbols(xrayCtor).map(uneval).sort().toSource(), + gConstructorProperties[classname].filter(id => typeof id !== "string").map(uneval).sort().toSource(), + "getOwnPropertySymbols works on Xrayed ctors"); } function testDate() { @@ -357,7 +459,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 // |own| data property. So we add it to the ignore list here, and check it // separately. let propsToSkip = ['length']; - testXray('Array', new iwin.Array(20), new iwin.Array(), propsToSkip); + // On the constructor, we want to skip all the non-standard "generic" + // functions. We're trying to remove them anyway; no point doing extra work + // to expose them over Xrays. + let ctorPropsToSkip = ["join", "reverse", "sort", "push", "pop", "shift", + "unshift", "splice", "concat", "slice"]; + testXray('Array', new iwin.Array(20), new iwin.Array(), propsToSkip, + ctorPropsToSkip); let symbolProps = ''; uniqueSymbol = iwin.eval('var uniqueSymbol = Symbol("uniqueSymbol"); uniqueSymbol'); @@ -593,7 +701,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 } function testRegExp() { - testXray('RegExp', new iwin.RegExp('foo'), new iwin.RegExp()); + // RegExp statics are very weird, and in particular RegExp has static + // properties that have to do with the last regexp execution in the global. + // Xraying those makes no sense, so we just skip constructor properties for + // RegExp xrays. + let ctorPropsToSkip = ["input", "multiline", "lastMatch", "lastParen", + "leftContext", "rightContext", "$1", "$2", "$3", + "$4", "$5", "$6", "$7", "$8", "$9", "$_", "$*", "$&", + "$+", "$`", "$'"]; + testXray('RegExp', new iwin.RegExp('foo'), new iwin.RegExp(), [], + ctorPropsToSkip); // Test the self-hosted |flags| property, toString, and toSource. for (var flags of ["", "g", "i", "m", "y", "gimy"]) { diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 410977c29cb..4ab4192af12 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -373,6 +373,112 @@ bool JSXrayTraits::getOwnPropertyFromTargetIfSafe(JSContext* cx, return true; } +// Returns true on success (in the JSAPI sense), false on failure. If true is +// returned, desc.object() will indicate whether we actually resolved +// the property. +// +// id is the property id we're looking for. +// holder is the object to define the property on. +// fs is the relevant JSFunctionSpec*. +// ps is the relevant JSPropertySpec*. +// desc is the descriptor we're resolving into. +static bool +TryResolvePropertyFromSpecs(JSContext* cx, HandleId id, HandleObject holder, + const JSFunctionSpec* fs, + const JSPropertySpec* ps, + MutableHandle desc) +{ + // Scan through the functions. + const JSFunctionSpec* fsMatch = nullptr; + for ( ; fs && fs->name; ++fs) { + if (PropertySpecNameEqualsId(fs->name, id)) { + fsMatch = fs; + break; + } + } + if (fsMatch) { + // Generate an Xrayed version of the method. + RootedFunction fun(cx, JS::NewFunctionFromSpec(cx, fsMatch, id)); + if (!fun) + return false; + + // The generic Xray machinery only defines non-own properties of the target on + // the holder. This is broken, and will be fixed at some point, but for now we + // need to cache the value explicitly. See the corresponding call to + // JS_GetOwnPropertyDescriptorById at the top of + // JSXrayTraits::resolveOwnProperty. + RootedObject funObj(cx, JS_GetFunctionObject(fun)); + return JS_DefinePropertyById(cx, holder, id, funObj, 0) && + JS_GetOwnPropertyDescriptorById(cx, holder, id, desc); + } + + // Scan through the properties. + const JSPropertySpec* psMatch = nullptr; + for ( ; ps && ps->name; ++ps) { + if (PropertySpecNameEqualsId(ps->name, id)) { + psMatch = ps; + break; + } + } + if (psMatch) { + desc.value().setUndefined(); + RootedFunction getterObj(cx); + RootedFunction setterObj(cx); + unsigned flags = psMatch->flags; + if (psMatch->isSelfHosted()) { + getterObj = JS::GetSelfHostedFunction(cx, psMatch->getter.selfHosted.funname, id, 0); + if (!getterObj) + return false; + desc.setGetterObject(JS_GetFunctionObject(getterObj)); + if (psMatch->setter.selfHosted.funname) { + MOZ_ASSERT(flags & JSPROP_SETTER); + setterObj = JS::GetSelfHostedFunction(cx, psMatch->setter.selfHosted.funname, id, 0); + if (!setterObj) + return false; + desc.setSetterObject(JS_GetFunctionObject(setterObj)); + } + } else { + desc.setGetter(JS_CAST_NATIVE_TO(psMatch->getter.native.op, + JSGetterOp)); + desc.setSetter(JS_CAST_NATIVE_TO(psMatch->setter.native.op, + JSSetterOp)); + } + desc.setAttributes(flags); + + // The generic Xray machinery only defines non-own properties on the holder. + // This is broken, and will be fixed at some point, but for now we need to + // cache the value explicitly. See the corresponding call to + // JS_GetPropertyById at the top of JSXrayTraits::resolveOwnProperty. + // + // Note also that the public-facing API here doesn't give us a way to + // pass along JITInfo. It's probably ok though, since Xrays are already + // pretty slow. + return JS_DefinePropertyById(cx, holder, id, + UndefinedHandleValue, + // This particular descriptor, unlike most, + // actually stores JSNatives directly, + // since we just set it up. Do NOT pass + // JSPROP_PROPOP_ACCESSORS here! + desc.attributes(), + JS_PROPERTYOP_GETTER(desc.getter()), + JS_PROPERTYOP_SETTER(desc.setter())) && + JS_GetOwnPropertyDescriptorById(cx, holder, id, desc); + } + + return true; +} + +static bool +ShouldResolveStaticProperties(JSProtoKey key) +{ + // Don't try to resolve static properties on RegExp, because they + // have issues. In particular, some of them grab state off the + // global of the RegExp constructor that describes the last regexp + // evaluation in that global, which is not a useful thing to do + // over Xrays. + return key != JSProto_RegExp; +} + bool JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, HandleObject wrapper, HandleObject holder, @@ -385,6 +491,18 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, if (!ok || desc.object()) return ok; + // The non-HasPrototypes semantics implemented by traditional Xrays are kind + // of broken with respect to |own|-ness and the holder. The common code + // muddles through by only checking the holder for non-|own| lookups, but + // that doesn't work for us. So we do an explicit holder check here, and hope + // that this mess gets fixed up soon. + if (!JS_GetOwnPropertyDescriptorById(cx, holder, id, desc)) + return false; + if (desc.object()) { + desc.object().set(wrapper); + return true; + } + RootedObject target(cx, getTargetObject(wrapper)); JSProtoKey key = getProtoKey(holder); if (!isPrototype(holder)) { @@ -432,22 +550,44 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, RootedString fname(cx, JS_GetFunctionId(JS_GetObjectFunction(target))); FillPropertyDescriptor(desc, wrapper, JSPROP_PERMANENT | JSPROP_READONLY, fname ? StringValue(fname) : JS_GetEmptyStringValue(cx)); - } else if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTOTYPE)) { - // Handle the 'prototype' property to make xrayedGlobal.StandardClass.prototype work. + } else { + // Look for various static properties/methods and the + // 'prototype' property. JSProtoKey standardConstructor = constructorFor(holder); if (standardConstructor != JSProto_Null) { - RootedObject standardProto(cx); - { - JSAutoCompartment ac(cx, target); - if (!JS_GetClassPrototype(cx, standardConstructor, &standardProto)) + // Handle the 'prototype' property to make + // xrayedGlobal.StandardClass.prototype work. + if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTOTYPE)) { + RootedObject standardProto(cx); + { + JSAutoCompartment ac(cx, target); + if (!JS_GetClassPrototype(cx, standardConstructor, &standardProto)) + return false; + MOZ_ASSERT(standardProto); + } + + if (!JS_WrapObject(cx, &standardProto)) return false; - MOZ_ASSERT(standardProto); + FillPropertyDescriptor(desc, wrapper, JSPROP_PERMANENT | JSPROP_READONLY, + ObjectValue(*standardProto)); + return true; + } + + if (ShouldResolveStaticProperties(standardConstructor)) { + const js::Class* clasp = js::ProtoKeyToClass(standardConstructor); + MOZ_ASSERT(clasp->spec.defined()); + + if (!TryResolvePropertyFromSpecs(cx, id, holder, + clasp->spec.constructorFunctions(), + clasp->spec.constructorProperties(), desc)) { + return false; + } + + if (desc.object()) { + desc.object().set(wrapper); + return true; + } } - if (!JS_WrapObject(cx, &standardProto)) - return false; - FillPropertyDescriptor(desc, wrapper, JSPROP_PERMANENT | JSPROP_READONLY, - ObjectValue(*standardProto)); - return true; } } } else if (IsErrorObjectKey(key)) { @@ -486,18 +626,6 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, return true; } - // The non-HasPrototypes semantics implemented by traditional Xrays are kind - // of broken with respect to |own|-ness and the holder. The common code - // muddles through by only checking the holder for non-|own| lookups, but - // that doesn't work for us. So we do an explicit holder check here, and hope - // that this mess gets fixed up soon. - if (!JS_GetOwnPropertyDescriptorById(cx, holder, id, desc)) - return false; - if (desc.object()) { - desc.object().set(wrapper); - return true; - } - // Handle the 'constructor' property. if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_CONSTRUCTOR)) { RootedObject constructor(cx); @@ -532,80 +660,17 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, const js::Class* clasp = js::GetObjectClass(target); MOZ_ASSERT(clasp->spec.defined()); - // Scan through the functions. Indexed array properties are handled above. - const JSFunctionSpec* fsMatch = nullptr; - for (const JSFunctionSpec* fs = clasp->spec.prototypeFunctions(); fs && fs->name; ++fs) { - if (PropertySpecNameEqualsId(fs->name, id)) { - fsMatch = fs; - break; - } - } - if (fsMatch) { - // Generate an Xrayed version of the method. - RootedFunction fun(cx, JS::NewFunctionFromSpec(cx, fsMatch, id)); - if (!fun) - return false; - - // The generic Xray machinery only defines non-own properties of the target on - // the holder. This is broken, and will be fixed at some point, but for now we - // need to cache the value explicitly. See the corresponding call to - // JS_GetOwnPropertyDescriptorById at the top of this function. - RootedObject funObj(cx, JS_GetFunctionObject(fun)); - return JS_DefinePropertyById(cx, holder, id, funObj, 0) && - JS_GetOwnPropertyDescriptorById(cx, holder, id, desc); + // Indexed array properties are handled above, so we can just work with the + // class spec here. + if (!TryResolvePropertyFromSpecs(cx, id, holder, + clasp->spec.prototypeFunctions(), + clasp->spec.prototypeProperties(), + desc)) { + return false; } - // Scan through the properties. - const JSPropertySpec* psMatch = nullptr; - for (const JSPropertySpec* ps = clasp->spec.prototypeProperties(); ps && ps->name; ++ps) { - if (PropertySpecNameEqualsId(ps->name, id)) { - psMatch = ps; - break; - } - } - if (psMatch) { - desc.value().setUndefined(); - RootedFunction getterObj(cx); - RootedFunction setterObj(cx); - unsigned flags = psMatch->flags; - if (psMatch->isSelfHosted()) { - getterObj = JS::GetSelfHostedFunction(cx, psMatch->getter.selfHosted.funname, id, 0); - if (!getterObj) - return false; - desc.setGetterObject(JS_GetFunctionObject(getterObj)); - if (psMatch->setter.selfHosted.funname) { - MOZ_ASSERT(flags & JSPROP_SETTER); - setterObj = JS::GetSelfHostedFunction(cx, psMatch->setter.selfHosted.funname, id, 0); - if (!setterObj) - return false; - desc.setSetterObject(JS_GetFunctionObject(setterObj)); - } - } else { - desc.setGetter(JS_CAST_NATIVE_TO(psMatch->getter.native.op, - JSGetterOp)); - desc.setSetter(JS_CAST_NATIVE_TO(psMatch->setter.native.op, - JSSetterOp)); - } - desc.setAttributes(flags); - - // The generic Xray machinery only defines non-own properties on the holder. - // This is broken, and will be fixed at some point, but for now we need to - // cache the value explicitly. See the corresponding call to - // JS_GetPropertyById at the top of this function. - // - // Note also that the public-facing API here doesn't give us a way to - // pass along JITInfo. It's probably ok though, since Xrays are already - // pretty slow. - return JS_DefinePropertyById(cx, holder, id, - UndefinedHandleValue, - // This particular descriptor, unlike most, - // actually stores JSNatives directly, - // since we just set it up. Do NOT pass - // JSPROP_PROPOP_ACCESSORS here! - desc.attributes(), - JS_PROPERTYOP_GETTER(desc.getter()), - JS_PROPERTYOP_SETTER(desc.setter())) && - JS_GetOwnPropertyDescriptorById(cx, holder, id, desc); + if (desc.object()) { + desc.object().set(wrapper); } return true; @@ -718,6 +783,33 @@ MaybeAppend(jsid id, unsigned flags, AutoIdVector& props) return props.append(id); } +// Append the names from the given function and property specs to props. +static bool +AppendNamesFromFunctionAndPropertySpecs(JSContext* cx, + const JSFunctionSpec* fs, + const JSPropertySpec* ps, + unsigned flags, + AutoIdVector& props) +{ + // Convert the method and property names to jsids and pass them to the caller. + for ( ; fs && fs->name; ++fs) { + jsid id; + if (!PropertySpecNameToPermanentId(cx, fs->name, &id)) + return false; + if (!MaybeAppend(id, flags, props)) + return false; + } + for ( ; ps && ps->name; ++ps) { + jsid id; + if (!PropertySpecNameToPermanentId(cx, ps->name, &id)) + return false; + if (!MaybeAppend(id, flags, props)) + return false; + } + + return true; +} + bool JSXrayTraits::enumerateNames(JSContext* cx, HandleObject wrapper, unsigned flags, AutoIdVector& props) @@ -765,10 +857,23 @@ JSXrayTraits::enumerateNames(JSContext* cx, HandleObject wrapper, unsigned flags return false; if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_NAME))) return false; - // Handle the .prototype property on standard constructors. - if (constructorFor(holder) != JSProto_Null) { + // Handle the .prototype property and static properties on standard + // constructors. + JSProtoKey standardConstructor = constructorFor(holder); + if (standardConstructor != JSProto_Null) { if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTOTYPE))) return false; + + if (ShouldResolveStaticProperties(standardConstructor)) { + const js::Class* clasp = js::ProtoKeyToClass(standardConstructor); + MOZ_ASSERT(clasp->spec.defined()); + + if (!AppendNamesFromFunctionAndPropertySpecs( + cx, clasp->spec.constructorFunctions(), + clasp->spec.constructorProperties(), flags, props)) { + return false; + } + } } } else if (IsErrorObjectKey(key)) { if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_FILENAME)) || @@ -804,23 +909,9 @@ JSXrayTraits::enumerateNames(JSContext* cx, HandleObject wrapper, unsigned flags const js::Class* clasp = js::GetObjectClass(target); MOZ_ASSERT(clasp->spec.defined()); - // Convert the method and property names to jsids and pass them to the caller. - for (const JSFunctionSpec* fs = clasp->spec.prototypeFunctions(); fs && fs->name; ++fs) { - jsid id; - if (!PropertySpecNameToPermanentId(cx, fs->name, &id)) - return false; - if (!MaybeAppend(id, flags, props)) - return false; - } - for (const JSPropertySpec* ps = clasp->spec.prototypeProperties(); ps && ps->name; ++ps) { - jsid id; - if (!PropertySpecNameToPermanentId(cx, ps->name, &id)) - return false; - if (!MaybeAppend(id, flags, props)) - return false; - } - - return true; + return AppendNamesFromFunctionAndPropertySpecs( + cx, clasp->spec.prototypeFunctions(), + clasp->spec.prototypeProperties(), flags, props); } JSObject* From d8dc417eceb8b6fd22015762a422c27fca1e0b69 Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Fri, 5 Feb 2016 16:49:49 +0100 Subject: [PATCH 55/72] Bug 241788 - Add missing run_next_test() to xpcshell-test a=testonly --- netwerk/test/unit/test_standardurl.js | 1 + 1 file changed, 1 insertion(+) diff --git a/netwerk/test/unit/test_standardurl.js b/netwerk/test/unit/test_standardurl.js index 9d186efad5d..5db8ad432ce 100644 --- a/netwerk/test/unit/test_standardurl.js +++ b/netwerk/test/unit/test_standardurl.js @@ -305,4 +305,5 @@ add_test(function test_filterWhitespace() { var url = stringToURL(" \r\n\th\nt\rt\tp://ex\r\n\tample.com/path\r\n\t/\r\n\tto the/fil\r\n\te.e\r\n\txt?que\r\n\try#ha\r\n\tsh \r\n\t "); do_check_eq(url.spec, "http://example.com/path/to%20the/file.ext?query#hash"); + run_next_test(); }); From 15ee532089021693d760c0073e98350b3335f7c8 Mon Sep 17 00:00:00 2001 From: Morgan Phillips Date: Fri, 5 Feb 2016 09:50:52 -0600 Subject: [PATCH 56/72] Bug 1245961 - Throw a TypeError if less than one argument is supplied to isCompilableUnit;r=fitzgen --- js/src/jit-test/tests/debug/Debugger-isCompilableUnit.js | 8 ++++++++ js/src/vm/Debugger.cpp | 3 +++ 2 files changed, 11 insertions(+) diff --git a/js/src/jit-test/tests/debug/Debugger-isCompilableUnit.js b/js/src/jit-test/tests/debug/Debugger-isCompilableUnit.js index d872541c191..9653805c484 100644 --- a/js/src/jit-test/tests/debug/Debugger-isCompilableUnit.js +++ b/js/src/jit-test/tests/debug/Debugger-isCompilableUnit.js @@ -48,3 +48,11 @@ for (var code of compilable_units) { for (var code of non_compilable_units) { assertEq(Debugger.isCompilableUnit(code), false); } + +// Supplying no arguments should throw a type error +assertThrowsInstanceOf(() => { + Debugger.isCompilableUnit(); +}, TypeError); + +// Supplying extra arguments should be fine +assertEq(Debugger.isCompilableUnit("", 1, 2, 3, 4, {}, []), true); diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index f9f832e5ac3..0fecd9bed33 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -4528,6 +4528,9 @@ Debugger::isCompilableUnit(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); + if (!args.requireAtLeast(cx, "Debugger.isCompilableUnit", 1)) + return false; + if (!args[0].isString()) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE, "Debugger.isCompilableUnit", From 83d9f44d6d4f8ce071580c6bde7eb04de61065fe Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Fri, 5 Feb 2016 08:18:47 -0800 Subject: [PATCH 57/72] Back out d1779fe421c3 (bug 1034290) for UnicodeDecodeErrors in things run by the reftest harness CLOSED TREE --- build/automation.py.in | 14 +- build/mobile/b2gautomation.py | 29 +- build/mobile/remoteautomation.py | 36 +-- layout/tools/reftest/Makefile.in | 1 - layout/tools/reftest/jar.mn | 1 - layout/tools/reftest/mach_commands.py | 2 + layout/tools/reftest/output.py | 144 --------- layout/tools/reftest/reftest.js | 295 ++++++++++-------- layout/tools/reftest/reftestcommandline.py | 7 +- layout/tools/reftest/remotereftest.py | 20 +- layout/tools/reftest/runreftest.py | 183 +++++++---- layout/tools/reftest/runreftestb2g.py | 7 +- layout/tools/reftest/runreftestmulet.py | 39 ++- testing/modules/StructuredLog.jsm | 32 +- testing/mozbase/mozleak/mozleak/leaklog.py | 16 +- .../mozlog/mozlog/formatters/tbplformatter.py | 15 +- testing/mozbase/mozlog/mozlog/logtypes.py | 4 +- .../mozbase/mozlog/mozlog/structuredlog.py | 5 +- 18 files changed, 370 insertions(+), 480 deletions(-) delete mode 100644 layout/tools/reftest/output.py diff --git a/build/automation.py.in b/build/automation.py.in index c5f1ad9f417..e92f1740ac1 100644 --- a/build/automation.py.in +++ b/build/automation.py.in @@ -396,7 +396,7 @@ class Automation(object): self.log.info("Can't trigger Breakpad, just killing process") self.killPid(processPID) - def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath, outputHandler=None): + def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath): """ Look for timeout or crashes and return the status after the process terminates """ stackFixerFunction = None didTimeout = False @@ -436,12 +436,7 @@ class Automation(object): while line != "" and not didTimeout: if stackFixerFunction: line = stackFixerFunction(line) - - if outputHandler is None: - self.log.info(line.rstrip().decode("UTF-8", "ignore")) - else: - outputHandler(line) - + self.log.info(line.rstrip().decode("UTF-8", "ignore")) if "TEST-START" in line and "|" in line: self.lastTestSeen = line.split("|")[1].strip() if not debuggerInfo and "TEST-UNEXPECTED-FAIL" in line and "Test timed out" in line: @@ -535,7 +530,7 @@ class Automation(object): debuggerInfo = None, symbolsPath = None, timeout = -1, maxTime = None, onLaunch = None, detectShutdownLeaks = False, screenshotOnFail=False, testPath=None, bisectChunk=None, - valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None, outputHandler=None): + valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None): """ Run the app, log the duration it took to execute, return the status code. Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds. @@ -584,8 +579,7 @@ class Automation(object): # app is launched. onLaunch() - status = self.waitForFinish(proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath, - outputHandler=outputHandler) + status = self.waitForFinish(proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath) self.log.info("INFO | automation.py | Application ran for: %s", str(datetime.now() - startTime)) # Do a final check for zombie child processes. diff --git a/build/mobile/b2gautomation.py b/build/mobile/b2gautomation.py index 545e8bdd770..75a93c6e08a 100644 --- a/build/mobile/b2gautomation.py +++ b/build/mobile/b2gautomation.py @@ -209,31 +209,23 @@ class B2GRemoteAutomation(Automation): return app, args def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, - debuggerInfo, symbolsPath, outputHandler=None): + debuggerInfo, symbolsPath): """ Wait for tests to finish (as evidenced by a signature string in logcat), or for a given amount of time to elapse with no output. """ timeout = timeout or 120 while True: - lines = proc.getStdoutLines(timeout) - if lines: - currentlog = '\n'.join(lines) - - if outputHandler: - for line in lines: - outputHandler(line) - else: - print(currentlog) - + currentlog = proc.getStdoutLines(timeout) + if currentlog: + print currentlog # Match the test filepath from the last TEST-START line found in the new # log content. These lines are in the form: # ... INFO TEST-START | /filepath/we/wish/to/capture.html\n testStartFilenames = re.findall(r"TEST-START \| ([^\s]*)", currentlog) if testStartFilenames: self.lastTestSeen = testStartFilenames[-1] - if (outputHandler and outputHandler.suite_finished) or ( - hasattr(self, 'logFinish') and self.logFinish in currentlog): + if hasattr(self, 'logFinish') and self.logFinish in currentlog: return 0 else: self.log.info("TEST-UNEXPECTED-FAIL | %s | application timed " @@ -442,12 +434,11 @@ class B2GRemoteAutomation(Automation): break # wait 'timeout' for any additional lines - if not lines: - try: - lines.append(self.queue.get(True, timeout)) - except Queue.Empty: - pass - return lines + try: + lines.append(self.queue.get(True, timeout)) + except Queue.Empty: + pass + return '\n'.join(lines) def wait(self, timeout=None): # this should never happen diff --git a/build/mobile/remoteautomation.py b/build/mobile/remoteautomation.py index bf9342c480a..c402031b3ae 100644 --- a/build/mobile/remoteautomation.py +++ b/build/mobile/remoteautomation.py @@ -95,7 +95,7 @@ class RemoteAutomation(Automation): return env - def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath, outputHandler=None): + def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath): """ Wait for tests to finish. If maxTime seconds elapse or no output is detected for timeout seconds, kill the process and fail the test. @@ -307,21 +307,20 @@ class RemoteAutomation(Automation): return pid def read_stdout(self): - """ - Fetch the full remote log file using devicemanager, process them and - return whether there were any new log entries since the last call. + """ Fetch the full remote log file using devicemanager and return just + the new log entries since the last call (as a list of messages or lines). """ if not self.dm.fileExists(self.proc): - return False + return [] try: newLogContent = self.dm.pullFile(self.proc, self.stdoutlen) except DMError: # we currently don't retry properly in the pullFile # function in dmSUT, so an error here is not necessarily # the end of the world - return False + return [] if not newLogContent: - return False + return [] self.stdoutlen += len(newLogContent) @@ -330,27 +329,26 @@ class RemoteAutomation(Automation): if testStartFilenames: self.lastTestSeen = testStartFilenames[-1] print newLogContent - return True + return [newLogContent] self.logBuffer += newLogContent lines = self.logBuffer.split('\n') - - if lines: - # We only keep the last (unfinished) line in the buffer - self.logBuffer = lines[-1] - del lines[-1] - if not lines: - return False + return + # We only keep the last (unfinished) line in the buffer + self.logBuffer = lines[-1] + del lines[-1] + messages = [] for line in lines: # This passes the line to the logger (to be logged or buffered) # and returns a list of structured messages (dict) parsed_messages = self.messageLogger.write(line) for message in parsed_messages: - if isinstance(message, dict) and message.get('action') == 'test_start': + if message['action'] == 'test_start': self.lastTestSeen = message['test'] - return True + messages += parsed_messages + return messages @property def getLastTestSeen(self): @@ -376,10 +374,10 @@ class RemoteAutomation(Automation): # too long, only do it every 60 seconds if (not slowLog) or (timer % 60 == 0): startRead = datetime.datetime.now() - hasOutput = self.read_stdout() + messages = self.read_stdout() if (datetime.datetime.now() - startRead) > datetime.timedelta(seconds=5): slowLog = True - if hasOutput: + if messages: noOutputTimer = 0 time.sleep(interval) timer += interval diff --git a/layout/tools/reftest/Makefile.in b/layout/tools/reftest/Makefile.in index 9b52b80e107..07776f1e7ad 100644 --- a/layout/tools/reftest/Makefile.in +++ b/layout/tools/reftest/Makefile.in @@ -12,7 +12,6 @@ _HARNESS_FILES = \ $(srcdir)/runreftestb2g.py \ $(srcdir)/runreftestmulet.py \ $(srcdir)/gaia_lock_screen.js \ - $(srcdir)/output.py \ automation.py \ $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanager.py \ $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py \ diff --git a/layout/tools/reftest/jar.mn b/layout/tools/reftest/jar.mn index 776e9f77c65..8a38a910c5b 100644 --- a/layout/tools/reftest/jar.mn +++ b/layout/tools/reftest/jar.mn @@ -2,7 +2,6 @@ reftest.jar: % content reftest %content/ * content/reftest-content.js (reftest-content.js) content/httpd.jsm (../../../netwerk/test/httpserver/httpd.js) - content/StructuredLog.jsm (../../../testing/modules/StructuredLog.jsm) #ifdef BOOTSTRAP * content/reftest.jsm (reftest.js) #else diff --git a/layout/tools/reftest/mach_commands.py b/layout/tools/reftest/mach_commands.py index b3b2bc5ebd4..eecff54b396 100644 --- a/layout/tools/reftest/mach_commands.py +++ b/layout/tools/reftest/mach_commands.py @@ -203,6 +203,8 @@ class ReftestRunner(MozbuildObject): if not kwargs["runTestsInParallel"]: kwargs["logFile"] = "%s.log" % kwargs["suite"] + # Remove the stdout handler from the internal logger and let mach deal with it + runreftest.log.removeHandler(runreftest.log.handlers[0]) self.log_manager.enable_unstructured() try: rv = runreftest.run(**kwargs) diff --git a/layout/tools/reftest/output.py b/layout/tools/reftest/output.py deleted file mode 100644 index a356a50d850..00000000000 --- a/layout/tools/reftest/output.py +++ /dev/null @@ -1,144 +0,0 @@ -# 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/. - -import json -import os -import threading - -from mozlog.formatters import TbplFormatter -from mozrunner.utils import get_stack_fixer_function - - -class ReftestFormatter(TbplFormatter): - """ - Formatter designed to preserve the legacy "tbpl" format in reftest. - - This is needed for both the reftest-analyzer and mozharness log parsing. - We can change this format when both reftest-analyzer and mozharness have - been changed to read structured logs. - """ - - def __call__(self, data): - if 'component' in data and data['component'] == 'mozleak': - # Output from mozleak requires that no prefix be added - # so that mozharness will pick up these failures. - return "%s\n" % data['message'] - - formatted = TbplFormatter.__call__(self, data) - if data['action'] == 'process_output': - return formatted - return 'REFTEST %s' % formatted - - def log(self, data): - prefix = "%s |" % data['level'].upper() - return "%s %s\n" % (prefix, data['message']) - - def test_end(self, data): - extra = data.get('extra', {}) - status = data['status'] - - status_msg = "TEST-" - if 'expected' in data: - status_msg += "UNEXPECTED-%s" % status - else: - if status != "PASS": - status_msg += "KNOWN-" - status_msg += status - if extra.get('status_msg') == 'Random': - status_msg += "(EXPECTED RANDOM)" - test = self.id_str(data['test']) - if 'message' in data: - status_details = data['message'] - elif isinstance(data['test'], tuple): - status_details = 'image comparison ({})'.format(data['test'][1]) - else: - status_details = '(LOAD ONLY)' - - output_text = "%s | %s | %s" % (status_msg, test, status_details) - if 'differences' in extra: - diff_msg = (", max difference: %(max_difference)s" - ", number of differing pixels: %(differences)s") % extra - diagnostic_data = ("REFTEST IMAGE 1 (TEST): %(image1)s\n" - "REFTEST IMAGE 2 (REFERENCE): %(image2)s") % extra - output_text += '%s\n%s' % (diff_msg, diagnostic_data) - elif "image1" in extra: - diagnostic_data = "REFTEST IMAGE: %(image1)s" % extra - output_text += '\n%s' % diagnostic_data - - output_text += "\nREFTEST TEST-END | %s" % test - return "%s\n" % output_text - - def process_output(self, data): - return "%s\n" % data["data"] - - def suite_end(self, data): - lines = [] - summary = data['extra']['results'] - summary['success'] = summary['Pass'] + summary['LoadOnly'] - lines.append("Successful: %(success)s (%(Pass)s pass, %(LoadOnly)s load only)" % - summary) - summary['unexpected'] = (summary['Exception'] + summary['FailedLoad'] + - summary['UnexpectedFail'] + summary['UnexpectedPass'] + - summary['AssertionUnexpected'] + - summary['AssertionUnexpectedFixed']) - lines.append(("Unexpected: %(unexpected)s (%(UnexpectedFail)s unexpected fail, " - "%(UnexpectedPass)s unexpected pass, " - "%(AssertionUnexpected)s unexpected asserts, " - "%(FailedLoad)s failed load, " - "%(Exception)s exception)") % summary) - summary['known'] = (summary['KnownFail'] + summary['AssertionKnown'] + - summary['Random'] + summary['Skip'] + summary['Slow']) - lines.append(("Known problems: %(known)s (" + - "%(KnownFail)s known fail, " + - "%(AssertionKnown)s known asserts, " + - "%(Random)s random, " + - "%(Skip)s skipped, " + - "%(Slow)s slow)") % summary) - lines = ["REFTEST INFO | %s" % s for s in lines] - lines.append("REFTEST SUITE-END | Shutdown") - return "INFO | Result summary:\n{}\n".format('\n'.join(lines)) - - def id_str(self, test_id): - if isinstance(test_id, basestring): - return test_id - return test_id[0] - - -class OutputHandler(object): - """Process the output of a process during a test run and translate - raw data logged from reftest.js to an appropriate structured log action, - where applicable. - """ - - def __init__(self, log, utilityPath, symbolsPath=None): - self.stack_fixer_function = get_stack_fixer_function(utilityPath, symbolsPath) - self.log = log - # needed for b2gautomation.py - self.suite_finished = False - - def __call__(self, line): - # need to return processed messages to appease remoteautomation.py - if not line.strip(): - return [] - - try: - data = json.loads(line) - except ValueError: - self.verbatim(line) - return [line] - - if isinstance(data, dict) and 'action' in data: - if data['action'] == 'suite_end': - self.suite_finished = True - - self.log.log_raw(data) - else: - self.verbatim(json.dumps(data)) - - return [data] - - def verbatim(self, line): - if self.stack_fixer_function: - line = self.stack_fixer_function(line.encode('utf-8', 'replace')) - self.log.process_output(threading.current_thread().name, line) diff --git a/layout/tools/reftest/reftest.js b/layout/tools/reftest/reftest.js index 19bf9607066..728a1b74eb8 100644 --- a/layout/tools/reftest/reftest.js +++ b/layout/tools/reftest/reftest.js @@ -38,7 +38,6 @@ const NS_OBSERVER_SERVICE_CONTRACTID = CU.import("resource://gre/modules/FileUtils.jsm"); CU.import("chrome://reftest/content/httpd.jsm", this); -CU.import("chrome://reftest/content/StructuredLog.jsm", this); CU.import("resource://gre/modules/Services.jsm"); CU.import("resource://gre/modules/NetUtil.jsm"); @@ -100,7 +99,6 @@ var gTotalTests = 0; var gState; var gCurrentURL; var gTestLog = []; -var gLogLevel; var gServer; var gCount = 0; var gAssertionCount = 0; @@ -165,6 +163,10 @@ var gNoCanvasCache = false; var gRecycledCanvases = new Array(); +// By default we just log to stdout +var gDumpLog = dump; +var gVerbose = false; + // Only dump the sandbox once, because it doesn't depend on the // manifest URL (yet!). var gDumpedConditionSandbox = false; @@ -179,27 +181,25 @@ function HasUnexpectedResult() gTestResults.AssertionUnexpectedFixed > 0; } -// By default we just log to stdout -var gDumpFn = dump; -var gDumpRawLog = function(record) { - // Dump JSON representation of data on a single line - var line = JSON.stringify(record); - gDumpFn("\n" + line + "\n"); -} -var logger = new StructuredLogger('reftest', gDumpRawLog); - -function TestBuffer(str) +function LogWarning(str) { - logger.debug(str); + gDumpLog("REFTEST INFO | " + str + "\n"); gTestLog.push(str); } -function FlushTestBuffer() +function LogInfo(str) { - // In debug mode, we've dumped all these messages already. - if (gLogLevel !== 'debug') { + if (gVerbose) + gDumpLog("REFTEST INFO | " + str + "\n"); + gTestLog.push(str); +} + +function FlushTestLog() +{ + if (!gVerbose) { + // In verbose mode, we've dumped all these messages already. for (var i = 0; i < gTestLog.length; ++i) { - logger.info("Saved log: " + gTestLog[i]); + gDumpLog("REFTEST INFO | Saved log: " + gTestLog[i] + "\n"); } } gTestLog = []; @@ -244,7 +244,7 @@ function getTestPlugin(aName) { return tags[i]; } - logger.warning("Failed to find the test-plugin."); + LogWarning("Failed to find the test-plugin."); return null; } @@ -257,6 +257,7 @@ this.OnRefTestLoad = function OnRefTestLoad(win) var env = CC["@mozilla.org/process/environment;1"]. getService(CI.nsIEnvironment); + gVerbose = !!env.get("MOZ_REFTEST_VERBOSE"); var prefs = Components.classes["@mozilla.org/preferences-service;1"]. getService(Components.interfaces.nsIPrefBranch); @@ -278,12 +279,6 @@ this.OnRefTestLoad = function OnRefTestLoad(win) gBrowserIsIframe = false; } - try { - gLogLevel = prefs.getCharPref("reftest.logLevel"); - } catch (e) { - gLogLevel ='info'; - } - if (win === undefined || win == null) { win = window; } @@ -327,7 +322,7 @@ this.OnRefTestLoad = function OnRefTestLoad(win) plugin1.enabledState = CI.nsIPluginTag.STATE_ENABLED; plugin2.enabledState = CI.nsIPluginTag.STATE_ENABLED; } else { - logger.warning("Could not get test plugin tags."); + LogWarning("Could not get test plugin tags."); } gBrowserMessageManager = gBrowser.QueryInterface(CI.nsIFrameLoaderOwner) @@ -344,7 +339,7 @@ function InitAndStartRefTests() var prefs = Components.classes["@mozilla.org/preferences-service;1"]. getService(Components.interfaces.nsIPrefBranch); } catch(e) { - logger.error("EXCEPTION: " + e); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + e + "\n"); } try { @@ -366,7 +361,7 @@ function InitAndStartRefTests() var f = FileUtils.File(logFile); var mfl = FileUtils.openFileOutputStream(f, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE); // Set to mirror to stdout as well as the file - gDumpFn = function (msg) { + gDumpLog = function (msg) { #ifdef BOOTSTRAP #ifdef REFTEST_B2G dump(msg); @@ -381,7 +376,7 @@ function InitAndStartRefTests() } catch(e) { // If there is a problem, just use stdout - gDumpFn = dump; + gDumpLog = dump; } } } catch(e) {} @@ -432,7 +427,7 @@ function InitAndStartRefTests() } catch (ex) { //gBrowser.loadURI('data:text/plain,' + ex); ++gTestResults.Exception; - logger.error("EXCEPTION: " + ex); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n"); DoneTests(); } @@ -470,7 +465,7 @@ function StartTests() var prefs = Components.classes["@mozilla.org/preferences-service;1"]. getService(Components.interfaces.nsIPrefBranch); } catch(e) { - logger.error("EXCEPTION: " + e); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + e + "\n"); } try { @@ -518,7 +513,7 @@ function StartTests() var manifests = JSON.parse(prefs.getCharPref("reftest.manifests")); gURLFilterRegex = manifests[null]; } catch(e) { - logger.error("Unable to find reftest.manifests pref. Please ensure your profile is setup properly"); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | Unable to find reftest.manifests pref. Please ensure your profile is setup properly\n"); DoneTests(); } @@ -530,7 +525,7 @@ function StartTests() // process includes before reading the included manifest again manifestURLs.sort(function(a,b) {return a.length - b.length}) manifestURLs.forEach(function(manifestURL) { - logger.info("Reading manifest " + manifestURL); + gDumpLog("Reading manifest " + manifestURL + "\n"); var filter = manifests[manifestURL] ? new RegExp(manifests[manifestURL]) : null; ReadTopManifest(manifestURL, [globalFilter, filter, false]); }); @@ -539,7 +534,6 @@ function StartTests() // Filter tests which will be skipped to get a more even distribution when chunking // tURLs is a temporary array containing all active tests var tURLs = new Array(); - var tIDs = new Array(); for (var i = 0; i < gURLs.length; ++i) { if (gURLs[i].expected == EXPECTED_DEATH) continue; @@ -551,10 +545,9 @@ function StartTests() continue; tURLs.push(gURLs[i]); - tIDs.push(gURLs[i].identifier); } - logger.suiteStart(tIDs, {"skipped": gURLs.length - tURLs.length}); + gDumpLog("REFTEST INFO | Discovered " + gURLs.length + " tests, after filtering SKIP tests, we have " + tURLs.length + "\n"); if (gTotalChunks > 0 && gThisChunk > 0) { // Calculate start and end indices of this chunk if tURLs array were @@ -569,8 +562,8 @@ function StartTests() end = gThisChunk == gTotalChunks ? gURLs.length : gURLs.indexOf(tURLs[end + 1]) - 1; gURLs = gURLs.slice(start, end); - logger.info("Running chunk " + gThisChunk + " out of " + gTotalChunks + " chunks. " + - "tests " + (start+1) + "-" + end + "/" + gURLs.length); + gDumpLog("REFTEST INFO | Running chunk " + gThisChunk + " out of " + gTotalChunks + " chunks. "); + gDumpLog("tests " + (start+1) + "-" + end + "/" + gURLs.length + "\n"); } if (gShuffle) { @@ -587,7 +580,7 @@ function StartTests() } catch (ex) { //gBrowser.loadURI('data:text/plain,' + ex); ++gTestResults.Exception; - logger.error("EXCEPTION: " + ex); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n"); DoneTests(); } } @@ -600,7 +593,7 @@ function OnRefTestUnload() plugin1.enabledState = gTestPluginEnabledStates[0]; plugin2.enabledState = gTestPluginEnabledStates[1]; } else { - logger.warning("Failed to get test plugin tags."); + LogWarning("Failed to get test plugin tags."); } } @@ -756,8 +749,8 @@ function BuildConditionSandbox(aURL) { } if (!gDumpedConditionSandbox) { - logger.info("Dumping JSON representation of sandbox"); - logger.info(JSON.stringify(CU.waiveXrays(sandbox))); + dump("REFTEST INFO | Dumping JSON representation of sandbox \n"); + dump("REFTEST INFO | " + JSON.stringify(CU.waiveXrays(sandbox)) + " \n"); gDumpedConditionSandbox = true; } @@ -818,12 +811,6 @@ function AddTestItem(aTest, aFilter) if (gFocusFilterMode == FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS && aTest.needsFocus) return; - - if (aTest.url2 !== null) - aTest.identifier = [aTest.prettyPath, aTest.type, aTest.url2.spec]; - else - aTest.identifier = aTest.prettyPath; - gURLs.push(aTest); } @@ -850,7 +837,8 @@ function ReadManifest(aURL, inherited_status, aFilter) var inputStream = channel.open2(); if (channel instanceof Components.interfaces.nsIHttpChannel && channel.responseStatus != 200) { - logger.error("HTTP ERROR : " + channel.responseStatus); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | HTTP ERROR : " + + channel.responseStatus + "\n"); } var streamBuf = getStreamContent(inputStream); inputStream.close(); @@ -1250,20 +1238,19 @@ function StartCurrentTest() // make sure we don't run tests that are expected to kill the browser while (gURLs.length > 0) { var test = gURLs[0]; - logger.testStart(test.identifier); if (test.expected == EXPECTED_DEATH) { ++gTestResults.Skip; - logger.testEnd(test.identifier, "SKIP"); + gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + " | (SKIP)\n"); gURLs.shift(); } else if (test.needsFocus && !Focus()) { // FIXME: Marking this as a known fail is dangerous! What // if it starts failing all the time? ++gTestResults.Skip; - logger.testEnd(test.identifier, "SKIP", null, "(COULDN'T GET FOCUS)"); + gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + " | (SKIPPED; COULDN'T GET FOCUS)\n"); gURLs.shift(); } else if (test.slow && !gRunSlowTests) { ++gTestResults.Slow; - logger.testEnd(test.identifier, "SKIP", null, "(SLOW)"); + gDumpLog("REFTEST TEST-KNOWN-SLOW | " + test.url1.spec + " | (SLOW)\n"); gURLs.shift(); } else { break; @@ -1279,6 +1266,7 @@ function StartCurrentTest() gRepeat--; StartTests(); } else { + gDumpLog("REFTEST TEST-START | " + gURLs[0].prettyPath + "\n"); if (gURLs[0].chaosMode) { gWindowUtils.enterChaosMode(); } @@ -1344,30 +1332,32 @@ function StartCurrentURI(aState) } else if (ps.type == PREF_INTEGER) { prefs.setIntPref(ps.name, value); } - logger.info("SET PREFERENCE pref(" + ps.name + "," + value + ")"); + gDumpLog("SET PREFERENCE pref(" + ps.name + "," + value + ")\n"); } }); } catch (e) { if (e == "bad pref") { var test = gURLs[0]; if (test.expected == EXPECTED_FAIL) { - logger.testEnd(test.identifier, "FAIL", "FAIL", - "(SKIPPED; " + badPref + " not known or wrong type)"); + gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + + " | (SKIPPED; " + badPref + " not known or wrong type)\n"); ++gTestResults.Skip; } else { - logger.testEnd(test.identifier, "FAIL", "PASS", - badPref + " not known or wrong type"); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + test.url1.spec + + " | " + badPref + " not known or wrong type\n"); ++gTestResults.UnexpectedFail; } - - // skip the test that had a bad preference - gURLs.shift(); - StartCurrentTest(); - return; } else { throw e; } } + if (badPref != undefined) { + // skip the test that had a bad preference + gURLs.shift(); + + StartCurrentTest(); + return; + } } if (prefSettings.length == 0 && @@ -1380,11 +1370,9 @@ function StartCurrentURI(aState) gContainingWindow.setTimeout(RecordResult, 0); } else { var currentTest = gTotalTests - gURLs.length; - // Log this to preserve the same overall log format, - // should be removed if the format is updated - gDumpFn("REFTEST TEST-LOAD | " + gCurrentURL + " | " + currentTest + " / " + gTotalTests + - " (" + Math.floor(100 * (currentTest / gTotalTests)) + "%)\n"); - TestBuffer("START " + gCurrentURL); + gDumpLog("REFTEST TEST-LOAD | " + gCurrentURL + " | " + currentTest + " / " + gTotalTests + + " (" + Math.floor(100 * (currentTest / gTotalTests)) + "%)\n"); + LogInfo("START " + gCurrentURL); var type = gURLs[0].type if (TYPE_SCRIPT == type) { SendLoadScriptTest(gCurrentURL, gLoadTimeout); @@ -1396,10 +1384,37 @@ function StartCurrentURI(aState) function DoneTests() { - logger.suiteEnd(extra={'results': gTestResults}); - logger.info("Slowest test took " + gSlowestTestTime + "ms (" + gSlowestTestURL + ")"); - logger.info("Total canvas count = " + gRecycledCanvases.length); + gDumpLog("REFTEST FINISHED: Slowest test took " + gSlowestTestTime + + "ms (" + gSlowestTestURL + ")\n"); + gDumpLog("REFTEST INFO | Result summary:\n"); + var count = gTestResults.Pass + gTestResults.LoadOnly; + gDumpLog("REFTEST INFO | Successful: " + count + " (" + + gTestResults.Pass + " pass, " + + gTestResults.LoadOnly + " load only)\n"); + count = gTestResults.Exception + gTestResults.FailedLoad + + gTestResults.UnexpectedFail + gTestResults.UnexpectedPass + + gTestResults.AssertionUnexpected + + gTestResults.AssertionUnexpectedFixed; + gDumpLog("REFTEST INFO | Unexpected: " + count + " (" + + gTestResults.UnexpectedFail + " unexpected fail, " + + gTestResults.UnexpectedPass + " unexpected pass, " + + gTestResults.AssertionUnexpected + " unexpected asserts, " + + gTestResults.AssertionUnexpectedFixed + " unexpected fixed asserts, " + + gTestResults.FailedLoad + " failed load, " + + gTestResults.Exception + " exception)\n"); + count = gTestResults.KnownFail + gTestResults.AssertionKnown + + gTestResults.Random + gTestResults.Skip + gTestResults.Slow; + gDumpLog("REFTEST INFO | Known problems: " + count + " (" + + gTestResults.KnownFail + " known fail, " + + gTestResults.AssertionKnown + " known asserts, " + + gTestResults.Random + " random, " + + gTestResults.Skip + " skipped, " + + gTestResults.Slow + " slow)\n"); + + gDumpLog("REFTEST INFO | Total canvas count = " + gRecycledCanvases.length + "\n"); + + gDumpLog("REFTEST TEST-START | Shutdown\n"); function onStopped() { let appStartup = CC["@mozilla.org/toolkit/app-startup;1"].getService(CI.nsIAppStartup); appStartup.quit(CI.nsIAppStartup.eForceQuit); @@ -1447,7 +1462,7 @@ function DoDrawWindow(ctx, x, y, w, h) // browser element flags |= ctx.DRAWWINDOW_USE_WIDGET_LAYERS; } else if (gBrowserIsRemote) { - logger.error(gCurrentURL + " | can't drawWindow remote content"); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | can't drawWindow remote content\n"); ++gTestResults.Exception; } @@ -1460,21 +1475,22 @@ function DoDrawWindow(ctx, x, y, w, h) } else { // Output a special warning because we need to be able to detect // this whenever it happens. - logger.error("WARNING: USE_WIDGET_LAYERS disabled"); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | WARNING: USE_WIDGET_LAYERS disabled\n"); } - logger.info("drawWindow flags = " + flagsStr + - "; window size = " + gContainingWindow.innerWidth + "," + gContainingWindow.innerHeight + - "; test browser size = " + testRect.width + "," + testRect.height); + gDumpLog("REFTEST INFO | drawWindow flags = " + flagsStr + + "; window size = " + gContainingWindow.innerWidth + "," + gContainingWindow.innerHeight + + "; test browser size = " + testRect.width + "," + testRect.height + + "\n"); } - TestBuffer("DoDrawWindow " + x + "," + y + "," + w + "," + h); + LogInfo("DoDrawWindow " + x + "," + y + "," + w + "," + h); ctx.drawWindow(gContainingWindow, x, y, w, h, "rgb(255,255,255)", gDrawWindowFlags); } function InitCurrentCanvasWithSnapshot() { - TestBuffer("Initializing canvas snapshot"); + LogInfo("Initializing canvas snapshot"); if (gURLs[0].type == TYPE_LOAD || gURLs[0].type == TYPE_SCRIPT) { // We don't want to snapshot this kind of test @@ -1492,7 +1508,7 @@ function InitCurrentCanvasWithSnapshot() function UpdateCurrentCanvasForInvalidation(rects) { - TestBuffer("Updating canvas for invalidation"); + LogInfo("Updating canvas for invalidation"); if (!gCurrentCanvas) { return; @@ -1522,7 +1538,7 @@ function UpdateCurrentCanvasForInvalidation(rects) function UpdateWholeCurrentCanvasForInvalidation() { - TestBuffer("Updating entire canvas for invalidation"); + LogInfo("Updating entire canvas for invalidation"); if (!gCurrentCanvas) { return; @@ -1534,7 +1550,7 @@ function UpdateWholeCurrentCanvasForInvalidation() function RecordResult(testRunTime, errorMsg, scriptResults) { - TestBuffer("RecordResult fired"); + LogInfo("RecordResult fired"); // Keep track of which test was slowest, and how long it took. if (testRunTime > gSlowestTestTime) { @@ -1544,26 +1560,26 @@ function RecordResult(testRunTime, errorMsg, scriptResults) // Not 'const ...' because of 'EXPECTED_*' value dependency. var outputs = {}; + const randomMsg = "(EXPECTED RANDOM)"; outputs[EXPECTED_PASS] = { - true: {s: ["PASS", "PASS"], n: "Pass"}, - false: {s: ["FAIL", "PASS"], n: "UnexpectedFail"} + true: {s: "TEST-PASS" , n: "Pass"}, + false: {s: "TEST-UNEXPECTED-FAIL" , n: "UnexpectedFail"} }; outputs[EXPECTED_FAIL] = { - true: {s: ["PASS", "FAIL"], n: "UnexpectedPass"}, - false: {s: ["FAIL", "FAIL"], n: "KnownFail"} + true: {s: "TEST-UNEXPECTED-PASS" , n: "UnexpectedPass"}, + false: {s: "TEST-KNOWN-FAIL" , n: "KnownFail"} }; outputs[EXPECTED_RANDOM] = { - true: {s: ["PASS", "PASS"], n: "Random"}, - false: {s: ["FAIL", "FAIL"], n: "Random"} + true: {s: "TEST-PASS" + randomMsg , n: "Random"}, + false: {s: "TEST-KNOWN-FAIL" + randomMsg, n: "Random"} }; outputs[EXPECTED_FUZZY] = outputs[EXPECTED_PASS]; var output; - var extra; if (gURLs[0].type == TYPE_LOAD) { ++gTestResults.LoadOnly; - logger.testEnd(gURLs[0].identifier, "PASS", "PASS", "(LOAD ONLY)"); + gDumpLog("REFTEST TEST-PASS | " + gURLs[0].prettyPath + " | (LOAD ONLY)\n"); gCurrentCanvas = null; FinishTestItem(); return; @@ -1581,14 +1597,17 @@ function RecordResult(testRunTime, errorMsg, scriptResults) if (!gURLs[0].allowSilentFail) errorMsg = "No test results reported. (SCRIPT)\n"; else - logger.info("An expected silent failure occurred"); + gDumpLog("REFTEST INFO | An expected silent failure occurred \n"); } if (errorMsg) { output = outputs[expected][false]; - extra = { status_msg: output.n }; ++gTestResults[output.n]; - logger.testEnd(gURLs[0].identifier, output.s[0], output.s[1], errorMsg, null, extra); + var result = "REFTEST " + output.s + " | " + + gURLs[0].prettyPath + " | " + // the URL being tested + errorMsg; + + gDumpLog(result); FinishTestItem(); return; } @@ -1608,15 +1627,16 @@ function RecordResult(testRunTime, errorMsg, scriptResults) var index = 0; scriptResults.forEach(function(result) { var output = outputPair[result.passed]; - var extra = { status_msg: output.n }; ++gTestResults[output.n]; - logger.testEnd(gURLs[0].identifier, output.s[0], output.s[1], - result.description + " item " + (++index), null, extra); + result = "REFTEST " + output.s + " | " + + gURLs[0].prettyPath + " | " + // the URL being tested + result.description + " item " + (++index) + "\n"; + gDumpLog(result); }); if (anyFailed && expected == EXPECTED_PASS) { - FlushTestBuffer(); + FlushTestLog(); } FinishTestItem(); @@ -1628,7 +1648,7 @@ function RecordResult(testRunTime, errorMsg, scriptResults) gCurrentCanvas = gURICanvases[gCurrentURL]; } if (gCurrentCanvas == null) { - logger.error(gCurrentURL, "program error managing snapshots"); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | program error managing snapshots\n"); ++gTestResults.Exception; } if (gState == 1) { @@ -1671,7 +1691,7 @@ function RecordResult(testRunTime, errorMsg, scriptResults) throw "Inconsistent result from compareCanvases."; } equal = expected == EXPECTED_FUZZY; - logger.info("REFTEST fuzzy match"); + gDumpLog("REFTEST fuzzy match\n"); } var failedExtraCheck = gFailedNoPaint || gFailedOpaqueLayer || gFailedAssignedLayer; @@ -1680,7 +1700,6 @@ function RecordResult(testRunTime, errorMsg, scriptResults) var test_passed = (equal == (gURLs[0].type == TYPE_REFTEST_EQUAL)) && !failedExtraCheck; output = outputs[expected][test_passed]; - extra = { status_msg: output.n }; ++gTestResults[output.n]; @@ -1699,21 +1718,39 @@ function RecordResult(testRunTime, errorMsg, scriptResults) failures.push("failed reftest-assigned-layer: " + gFailedAssignedLayerMessages.join(", ")); } var failureString = failures.join(", "); - logger.testEnd(gURLs[0].identifier, output.s[0], output.s[1], failureString, null, extra); + if (expected == EXPECTED_FAIL) { + gDumpLog("REFTEST TEST-KNOWN-FAIL | " + gURLs[0].prettyPath + " | " + failureString + "\n"); + } else { + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gURLs[0].prettyPath + " | " + failureString + "\n"); + } } else { + var result = "REFTEST " + output.s + " | " + + gURLs[0].prettyPath + " | "; // the URL being tested + switch (gURLs[0].type) { + case TYPE_REFTEST_NOTEQUAL: + result += "image comparison (!=)"; + break; + case TYPE_REFTEST_EQUAL: + result += "image comparison (==)"; + break; + } + if (!test_passed && expected == EXPECTED_PASS || !test_passed && expected == EXPECTED_FUZZY || test_passed && expected == EXPECTED_FAIL) { if (!equal) { - extra.max_difference = maxDifference.value; - extra.differences = differences; - extra.image1 = gCanvas1.toDataURL(); - extra.image2 = gCanvas2.toDataURL(); + result += ", max difference: " + maxDifference.value + ", number of differing pixels: " + differences + "\n"; + result += "REFTEST IMAGE 1 (TEST): " + gCanvas1.toDataURL() + "\n"; + result += "REFTEST IMAGE 2 (REFERENCE): " + gCanvas2.toDataURL() + "\n"; } else { - extra.image1 = gCanvas1.toDataURL(); + result += "\n"; + result += "REFTEST IMAGE: " + gCanvas1.toDataURL() + "\n"; } + } else { + result += "\n"; } - logger.testEnd(gURLs[0].identifier, output.s[0], output.s[1], null, null, extra); + + gDumpLog(result); if (gURLs[0].prefSettings1.length == 0) { UpdateCanvasCache(gURLs[0].url1, gCanvas1); @@ -1724,7 +1761,7 @@ function RecordResult(testRunTime, errorMsg, scriptResults) } if ((!test_passed && expected == EXPECTED_PASS) || (test_passed && expected == EXPECTED_FAIL)) { - FlushTestBuffer(); + FlushTestLog(); } CleanUpCrashDumpFiles(); @@ -1741,10 +1778,11 @@ function LoadFailed(why) // Once bug 896840 is fixed, this can go away, but for now it will give log // output that is TBPL starable for bug 789751 and bug 720452. if (!why) { - logger.error("load failed with unknown reason"); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | load failed with unknown reason\n"); } - logger.testEnd(gURLs[0]["url" + gState].spec, "FAIL", "PASS", "load failed: " + why); - FlushTestBuffer(); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + + gURLs[0]["url" + gState].spec + " | load failed: " + why + "\n"); + FlushTestLog(); FinishTestItem(); } @@ -1781,9 +1819,11 @@ function FindUnexpectedCrashDumpFiles() if (!foundCrashDumpFile) { ++gTestResults.UnexpectedFail; foundCrashDumpFile = true; - logger.testEnd(gCurrentURL, "FAIL", "PASS", "This test left crash dumps behind, but we weren't expecting it to!"); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + + " | This test left crash dumps behind, but we weren't expecting it to!\n"); } - logger.info("Found unexpected crash dump file " + path); + gDumpLog("REFTEST INFO | Found unexpected crash dump file " + path + + ".\n"); gUnexpectedCrashDumpFiles[path] = true; } } @@ -1800,7 +1840,7 @@ function FinishTestItem() { // Replace document with BLANK_URL_FOR_CLEARING in case there are // assertions when unloading. - logger.debug("Loading a blank page"); + gDumpLog("REFTEST INFO | Loading a blank page\n"); // After clearing, content will notify us of the assertion count // and tests will continue. SendClear(); @@ -1835,25 +1875,26 @@ function DoAssertionCheck(numAsserts) if (numAsserts < minAsserts) { ++gTestResults.AssertionUnexpectedFixed; - gDumpFn("REFTEST TEST-UNEXPECTED-PASS | " + gURLs[0].prettyPath + - " | assertion count" + numAsserts + " is less than " + - expectedAssertions + "\n"); + gDumpLog("REFTEST TEST-UNEXPECTED-PASS | " + gURLs[0].prettyPath + + " | assertion count " + numAsserts + " is less than " + + expectedAssertions + "\n"); } else if (numAsserts > maxAsserts) { ++gTestResults.AssertionUnexpected; - gDumpFn("REFTEST TEST-UNEXPECTED-FAIL | " + gURLs[0].prettyPath + - " | assertion count " + numAsserts + " is more than " + - expectedAssertions + "\n"); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gURLs[0].prettyPath + + " | assertion count " + numAsserts + " is more than " + + expectedAssertions + "\n"); } else if (numAsserts != 0) { ++gTestResults.AssertionKnown; - gDumpFn("REFTEST TEST-KNOWN-FAIL | " + gURLs[0].prettyPath + - "assertion count " + numAsserts + " matches " + - expectedAssertions + "\n"); + gDumpLog("REFTEST TEST-KNOWN-FAIL | " + gURLs[0].prettyPath + + " | assertion count " + numAsserts + " matches " + + expectedAssertions + "\n"); } } if (gURLs[0].chaosMode) { gWindowUtils.leaveChaosMode(); } + gDumpLog("REFTEST TEST-END | " + gURLs[0].prettyPath + "\n"); // And start the next test. gURLs.shift(); @@ -1882,7 +1923,7 @@ function RestoreChangedPreferences() } else if (ps.type == PREF_INTEGER) { prefs.setIntPref(ps.name, value); } - logger.info("RESTORE PREFERENCE pref(" + ps.name + "," + value + ")"); + gDumpLog("RESTORE PREFERENCE pref(" + ps.name + "," + value + ")\n"); }); gPrefsToRestore = []; } @@ -1963,7 +2004,7 @@ function RecvContentReady() function RecvException(what) { - logger.error(gCurrentURL + " | " + what); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | " + what + "\n"); ++gTestResults.Exception; } @@ -1995,13 +2036,13 @@ function RecvInitCanvasWithSnapshot() function RecvLog(type, msg) { - msg = "[CONTENT] " + msg; + msg = "[CONTENT] "+ msg; if (type == "info") { - TestBuffer(msg); + LogInfo(msg); } else if (type == "warning") { - logger.warning(msg); + LogWarning(msg); } else { - logger.error("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | unknown log type " + type + "\n"); + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | unknown log type " + type + "\n"); ++gTestResults.Exception; } } diff --git a/layout/tools/reftest/reftestcommandline.py b/layout/tools/reftest/reftestcommandline.py index 28e8b4f5f41..df7b63d3eca 100644 --- a/layout/tools/reftest/reftestcommandline.py +++ b/layout/tools/reftest/reftestcommandline.py @@ -1,11 +1,8 @@ import argparse import os -import sys from collections import OrderedDict from urlparse import urlparse -import mozlog - here = os.path.abspath(os.path.dirname(__file__)) @@ -210,8 +207,6 @@ class ReftestArgumentsParser(argparse.ArgumentParser): nargs="*", help="Path to test file, manifest file, or directory containing tests") - mozlog.commandline.add_logging_group(self) - def get_ip(self): import moznetwork if os.name != "nt": @@ -240,6 +235,8 @@ class ReftestArgumentsParser(argparse.ArgumentParser): self.error("Failed to determine test suite; supply --suite to set this explicitly") def validate(self, options, reftest): + import sys + if not options.tests: # Can't just set this in the argument parser because mach will set a default self.error("Must supply at least one path to a manifest file, test directory, or test file to run.") diff --git a/layout/tools/reftest/remotereftest.py b/layout/tools/reftest/remotereftest.py index 9f2feff87b1..5ab8f0fd985 100644 --- a/layout/tools/reftest/remotereftest.py +++ b/layout/tools/reftest/remotereftest.py @@ -8,21 +8,19 @@ import time import tempfile import traceback +# We need to know our current directory so that we can serve our test files from it. +SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(__file__))) + +from runreftest import RefTest, ReftestResolver +from automation import Automation import devicemanager import droid import mozinfo import moznetwork -from automation import Automation from remoteautomation import RemoteAutomation, fennecLogcatFilters -from output import OutputHandler -from runreftest import RefTest, ReftestResolver import reftestcommandline -# We need to know our current directory so that we can serve our test files from it. -SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(__file__))) - - class RemoteReftestResolver(ReftestResolver): def absManifestPath(self, path): script_abs_path = os.path.join(SCRIPT_DIRECTORY, path) @@ -148,13 +146,6 @@ class RemoteReftest(RefTest): self.automation.deleteANRs() self.automation.deleteTombstones() - self._populate_logger(options) - outputHandler = OutputHandler(self.log, options.utilityPath, options.symbolsPath) - # RemoteAutomation.py's 'messageLogger' is also used by mochitest. Mimic a mochitest - # MessageLogger object to re-use this code path. - outputHandler.write = outputHandler.__call__ - self.automation._processArgs['messageLogger'] = outputHandler - def findPath(self, paths, filename = None): for path in paths: p = path @@ -454,3 +445,4 @@ def main(): if __name__ == "__main__": sys.exit(main()) + diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py index 457f4242014..1cfadb8b446 100644 --- a/layout/tools/reftest/runreftest.py +++ b/layout/tools/reftest/runreftest.py @@ -26,23 +26,26 @@ import mozcrash import mozdebug import mozinfo import mozleak -import mozlog import mozprocess import mozprofile import mozrunner from mozrunner.utils import get_stack_fixer_function, test_environment from mozscreenshot import printstatus, dump_screen -from output import OutputHandler, ReftestFormatter import reftestcommandline -here = os.path.abspath(os.path.dirname(__file__)) +# set up logging handler a la automation.py.in for compatability +import logging +log = logging.getLogger() -try: - from mozbuild.base import MozbuildObject - build_obj = MozbuildObject.from_environment(cwd=here) -except ImportError: - build_obj = None + +def resetGlobalLog(): + while log.handlers: + log.removeHandler(log.handlers[0]) + handler = logging.StreamHandler(sys.stdout) + log.setLevel(logging.INFO) + log.addHandler(handler) +resetGlobalLog() def categoriesToRegex(categoryList): @@ -200,21 +203,6 @@ class RefTest(object): self.lastTestSeen = 'reftest' self.haveDumpedScreen = False self.resolver = self.resolver_cls() - self.log = None - - def _populate_logger(self, options): - if self.log: - return - - mozlog.commandline.log_formatters["tbpl"] = (ReftestFormatter, - "Reftest specific formatter for the" - "benefit of legacy log parsers and" - "tools such as the reftest analyzer") - fmt_options = {} - if not options.log_tbpl_level and os.environ.get('MOZ_REFTEST_VERBOSE'): - options.log_tbpl_level = fmt_options['level'] = 'debug' - self.log = mozlog.commandline.setup_logging( - "reftest harness", options, {"tbpl": sys.stdout}, fmt_options) def update_mozinfo(self): """walk up directories to find mozinfo.json update the info""" @@ -267,7 +255,6 @@ class RefTest(object): if options.runUntilFailure: prefs['reftest.runUntilFailure'] = True prefs['reftest.focusFilterMode'] = options.focusFilterMode - prefs['reftest.logLevel'] = options.log_tbpl_level or 'info' prefs['reftest.manifests'] = json.dumps(manifests) # Ensure that telemetry is disabled, so we don't connect to the telemetry @@ -344,7 +331,7 @@ class RefTest(object): return profile def environment(self, **kwargs): - kwargs['log'] = self.log + kwargs['log'] = log return test_environment(**kwargs) def buildBrowserEnv(self, options, profileDir): @@ -373,11 +360,11 @@ class RefTest(object): def killNamedOrphans(self, pname): """ Kill orphan processes matching the given command name """ - self.log.info("Checking for orphan %s processes..." % pname) + log.info("Checking for orphan %s processes..." % pname) def _psInfo(line): if pname in line: - self.log.info(line) + log.info(line) process = mozprocess.ProcessHandler(['ps', '-f'], processOutputLine=_psInfo) process.run() @@ -388,13 +375,13 @@ class RefTest(object): if len(parts) == 3 and parts[0].isdigit(): pid = int(parts[0]) if parts[2] == pname and parts[1] == '1': - self.log.info("killing %s orphan with pid %d" % (pname, pid)) + log.info("killing %s orphan with pid %d" % (pname, pid)) try: os.kill( pid, getattr(signal, "SIGKILL", signal.SIGTERM)) except Exception as e: - self.log.info("Failed to kill process %d: %s" % - (pid, str(e))) + log.info("Failed to kill process %d: %s" % + (pid, str(e))) process = mozprocess.ProcessHandler(['ps', '-o', 'pid,ppid,comm'], processOutputLine=_psKill) process.run() @@ -405,8 +392,6 @@ class RefTest(object): shutil.rmtree(profileDir, True) def runTests(self, tests, options, cmdlineArgs=None): - self._populate_logger(options) - # Despite our efforts to clean up servers started by this script, in practice # we still see infrequent cases where a process is orphaned and interferes # with future tests, typically because the old server is keeping the port in use. @@ -499,16 +484,17 @@ class RefTest(object): """handle process output timeout""" # TODO: bug 913975 : _processOutput should call self.processOutputLine # one more time one timeout (I think) - self.log.error("%s | application timed out after %d seconds with no output" % (self.lastTestSeen, int(timeout))) + log.error("TEST-UNEXPECTED-FAIL | %s | application timed out after %d seconds with no output" % + (self.lastTestSeen, int(timeout))) self.killAndGetStack( proc, utilityPath, debuggerInfo, dump_screen=not debuggerInfo) def dumpScreen(self, utilityPath): if self.haveDumpedScreen: - self.log.info("Not taking screenshot here: see the one that was previously logged") + log.info("Not taking screenshot here: see the one that was previously logged") return self.haveDumpedScreen = True - dump_screen(utilityPath, self.log) + dump_screen(utilityPath, log) def killAndGetStack(self, process, utilityPath, debuggerInfo, dump_screen=False): """ @@ -536,11 +522,75 @@ class RefTest(object): process.kill(sig=signal.SIGABRT) except OSError: # https://bugzilla.mozilla.org/show_bug.cgi?id=921509 - self.log.info("Can't trigger Breakpad, process no longer exists") + log.info("Can't trigger Breakpad, process no longer exists") return - self.log.info("Can't trigger Breakpad, just killing process") + log.info("Can't trigger Breakpad, just killing process") process.kill() + # output processing + + class OutputHandler(object): + + """line output handler for mozrunner""" + + def __init__(self, harness, utilityPath, symbolsPath=None, dump_screen_on_timeout=True): + """ + harness -- harness instance + dump_screen_on_timeout -- whether to dump the screen on timeout + """ + self.harness = harness + self.utilityPath = utilityPath + self.symbolsPath = symbolsPath + self.dump_screen_on_timeout = dump_screen_on_timeout + self.stack_fixer_function = self.stack_fixer() + + def processOutputLine(self, line): + """per line handler of output for mozprocess""" + for handler in self.output_handlers(): + line = handler(line) + __call__ = processOutputLine + + def output_handlers(self): + """returns ordered list of output handlers""" + return [self.fix_stack, + self.format, + self.record_last_test, + self.handle_timeout_and_dump_screen, + self.log, + ] + + def stack_fixer(self): + """ + return get_stack_fixer_function, if any, to use on the output lines + """ + return get_stack_fixer_function(self.utilityPath, self.symbolsPath) + + # output line handlers: + # these take a line and return a line + def fix_stack(self, line): + if self.stack_fixer_function: + return self.stack_fixer_function(line) + return line + + def format(self, line): + """format the line""" + return line.rstrip().decode("UTF-8", "ignore") + + def record_last_test(self, line): + """record last test on harness""" + if "TEST-START" in line and "|" in line: + self.harness.lastTestSeen = line.split("|")[1].strip() + return line + + def handle_timeout_and_dump_screen(self, line): + if self.dump_screen_on_timeout and "TEST-UNEXPECTED-FAIL" in line and "Test timed out" in line: + self.harness.dumpScreen(self.utilityPath) + return line + + def log(self, line): + log.info(line) + return line + def runApp(self, profile, binary, cmdargs, env, timeout=None, debuggerInfo=None, symbolsPath=None, options=None, @@ -556,14 +606,10 @@ class RefTest(object): interactive = debuggerInfo.interactive debug_args = [debuggerInfo.path] + debuggerInfo.args - def record_last_test(message): - """Records the last test seen by this harness for the benefit of crash logging.""" - if message['action'] == 'test_start': - self.lastTestSeen = message['test'] - - self.log.add_handler(record_last_test) - - outputHandler = OutputHandler(self.log, options.utilityPath, symbolsPath=symbolsPath) + outputHandler = self.OutputHandler(harness=self, + utilityPath=options.utilityPath, + symbolsPath=symbolsPath, + dump_screen_on_timeout=not debuggerInfo) kp_kwargs = { 'kill_on_timeout': False, @@ -593,18 +639,21 @@ class RefTest(object): interactive=interactive, outputTimeout=timeout) proc = runner.process_handler - status = runner.wait() runner.process_handler = None + if timeout is None: + didTimeout = False + else: + didTimeout = proc.didTimeout if status: - self.log.error("TEST-UNEXPECTED-FAIL | %s | application terminated with exit code %s" % (self.lastTestSeen, status)) + log.info("TEST-UNEXPECTED-FAIL | %s | application terminated with exit code %s", + self.lastTestSeen, status) else: self.lastTestSeen = 'Main app process exited normally' - crashed = mozcrash.log_crashes(self.log, os.path.join(profile.profile, 'minidumps'), - symbolsPath, test=self.lastTestSeen) - + crashed = mozcrash.check_for_crashes(os.path.join(profile.profile, "minidumps"), + symbolsPath, test_name=self.lastTestSeen) runner.cleanup() if not status and crashed: status = 1 @@ -618,7 +667,7 @@ class RefTest(object): profileDir = None try: - if cmdlineArgs is None: + if cmdlineArgs == None: cmdlineArgs = [] profile = self.createReftestProfile(options, manifests) profileDir = profile.profile # name makes more sense @@ -626,6 +675,7 @@ class RefTest(object): # browser environment browserEnv = self.buildBrowserEnv(options, profileDir) + log.info("REFTEST INFO | runreftest.py | Running tests: start.\n") status = self.runApp(profile, binary=options.app, cmdargs=cmdlineArgs, @@ -638,9 +688,11 @@ class RefTest(object): debuggerInfo=debuggerInfo) mozleak.process_leak_log(self.leakLogFile, leak_thresholds=options.leakThresholds, + log=log, stack_fixer=get_stack_fixer_function(options.utilityPath, options.symbolsPath), ) + log.info("\nREFTEST INFO | runreftest.py | Running tests: end.") finally: self.cleanup(profileDir) return status @@ -660,28 +712,31 @@ class RefTest(object): dest = os.path.join(profileDir, os.path.basename(abspath)) shutil.copytree(abspath, dest) else: - self.log.warning( - "runreftest.py | Failed to copy %s to profile" % abspath) + log.warning( + "WARNING | runreftest.py | Failed to copy %s to profile", abspath) continue def run(**kwargs): - parser = reftestcommandline.DesktopArgumentsParser() - # Mach gives us kwargs; this is a way to turn them back into an # options object - parser.set_defaults(**kwargs) - - if 'tests' in kwargs: - options = parser.parse_args(kwargs["tests"]) - else: - options = parser.parse_args() - + parser = reftestcommandline.DesktopArgumentsParser() reftest = RefTest() + parser.set_defaults(**kwargs) + options = parser.parse_args(kwargs["tests"]) parser.validate(options, reftest) - return reftest.runTests(options.tests, options) +def main(): + parser = reftestcommandline.DesktopArgumentsParser() + reftest = RefTest() + + options = parser.parse_args() + parser.validate(options, reftest) + + sys.exit(reftest.runTests(options.tests, options)) + + if __name__ == "__main__": - sys.exit(run()) + main() diff --git a/layout/tools/reftest/runreftestb2g.py b/layout/tools/reftest/runreftestb2g.py index 41f3d72874a..b7aa9b3d25a 100644 --- a/layout/tools/reftest/runreftestb2g.py +++ b/layout/tools/reftest/runreftestb2g.py @@ -16,7 +16,6 @@ if here not in sys.path: from automation import Automation from b2gautomation import B2GRemoteAutomation from runreftestmulet import run_test_harness as run_mulet_reftests -from output import OutputHandler from remotereftest import RemoteReftestResolver, ReftestServer from runreftest import RefTest import reftestcommandline @@ -312,8 +311,6 @@ class B2GRemoteReftest(RefTest): timeout=None, debuggerInfo=None, symbolsPath=None, options=None, valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None): - - outputHandler = OutputHandler(self.log, options.utilityPath, options.symbolsPath) status = self.automation.runApp(None, env, binary, profile.profile, @@ -322,8 +319,7 @@ class B2GRemoteReftest(RefTest): xrePath=options.xrePath, debuggerInfo=debuggerInfo, symbolsPath=symbolsPath, - timeout=timeout, - outputHandler=outputHandler) + timeout=timeout) return status @@ -384,6 +380,7 @@ def run_remote_reftests(parser, options): auto.setProduct("b2g") auto.test_script = os.path.join(here, 'b2g_start_script.js') auto.test_script_args = [options.remoteWebServer, options.httpPort] + auto.logFinish = "REFTEST TEST-START | Shutdown" reftest = B2GRemoteReftest(auto, dm, options, here) parser.validate(options, reftest) diff --git a/layout/tools/reftest/runreftestmulet.py b/layout/tools/reftest/runreftestmulet.py index d611b62902b..1ffc9bee92d 100644 --- a/layout/tools/reftest/runreftestmulet.py +++ b/layout/tools/reftest/runreftestmulet.py @@ -20,10 +20,11 @@ import mozinfo import mozlog from runreftest import RefTest -from output import OutputHandler import reftestcommandline +log = mozlog.unstructured.getLogger('REFTEST') + class MuletReftest(RefTest): build_type = "mulet" marionette = None @@ -58,11 +59,7 @@ class MuletReftest(RefTest): self.profile = self.create_profile(options, manifests, profile_to_clone=options.profile) env = self.buildBrowserEnv(options, self.profile.profile) - - self._populate_logger(options) - outputHandler = OutputHandler(self.log, options.utilityPath, symbolsPath=options.symbolsPath) - - kp_kwargs = { 'processOutputLine': [outputHandler], + kp_kwargs = { 'processOutputLine': [self._on_output], 'onTimeout': [self._on_timeout], 'kill_on_timeout': False } @@ -74,7 +71,7 @@ class MuletReftest(RefTest): options.timeout = 300 self.timeout = options.timeout + 30.0 - self.log.info("%s | Running tests: start." % os.path.basename(__file__)) + log.info("%s | Running tests: start.", os.path.basename(__file__)) cmd, args = self.build_command_line(options.app, ignore_window_size=options.ignoreWindowSize, browser_arg=options.browser_arg) @@ -89,9 +86,9 @@ class MuletReftest(RefTest): status = 0 try: self.runner.start(outputTimeout=self.timeout) - self.log.info("%s | Application pid: %d" % ( + log.info("%s | Application pid: %d", os.path.basename(__file__), - self.runner.process_handler.pid)) + self.runner.process_handler.pid) # kick starts the reftest harness self.run_marionette_script() @@ -101,13 +98,13 @@ class MuletReftest(RefTest): self.runner.cleanup() if status > 0: - self.log.testFail("%s | application terminated with exit code %s" % ( - self.last_test, status)) + log.testFail("%s | application terminated with exit code %s", + self.last_test, status) elif status < 0: - self.log.info("%s | application killed with signal %s" % ( - self.last_test, -status)) + log.info("%s | application killed with signal %s", + self.last_test, -status) - self.log.info("%s | Running tests: end." % os.path.basename(__file__)) + log.info("%s | Running tests: end.", os.path.basename(__file__)) return status def create_profile(self, options, manifests, profile_to_clone=None): @@ -162,13 +159,22 @@ class MuletReftest(RefTest): args += ['-chrome', 'chrome://b2g/content/shell.html'] return cmd, args + def _on_output(self, line): + sys.stdout.write("%s\n" % line) + sys.stdout.flush() + + # TODO use structured logging + if "TEST-START" in line and "|" in line: + self.last_test = line.split("|")[1].strip() + def _on_timeout(self): msg = "%s | application timed out after %s seconds with no output" - self.log.testFail(msg % (self.last_test, self.timeout)) + log.testFail(msg % (self.last_test, self.timeout)) # kill process to get a stack self.runner.stop(sig=signal.SIGABRT) + def _unlockScreen(self): self.marionette.set_context(self.marionette.CONTEXT_CONTENT) self.marionette.import_script(os.path.abspath( @@ -177,11 +183,10 @@ class MuletReftest(RefTest): self.marionette.execute_async_script('GaiaLockScreen.unlock()') def _wait_for_homescreen(self, timeout): - self.log.info("Waiting for home screen to load") + log.info("Waiting for home screen to load") Wait(self.marionette, timeout).until(expected.element_present( By.CSS_SELECTOR, '#homescreen[loading-state=false]')) - def run_test_harness(parser, options): marionette_args = {} if options.marionette: diff --git a/testing/modules/StructuredLog.jsm b/testing/modules/StructuredLog.jsm index bfa51a2b570..830f59f78a6 100644 --- a/testing/modules/StructuredLog.jsm +++ b/testing/modules/StructuredLog.jsm @@ -87,35 +87,17 @@ StructuredLogger.prototype = { this._logData("test_end", data); }, - suiteStart: function (tests, runinfo=null, versioninfo=null, deviceinfo=null, extra=null) { + suiteStart: function (tests, runinfo=null) { var data = {tests: tests}; if (runinfo !== null) { data.runinfo = runinfo; } - if (versioninfo !== null) { - data.versioninfo = versioninfo; - } - - if (deviceinfo !== null) { - data.deviceinfo = deviceinfo; - } - - if (extra !== null) { - data.extra = extra; - } - this._logData("suite_start", data); }, - suiteEnd: function (extra=null) { - var data = {}; - - if (extra !== null) { - data.extra = extra; - } - - this._logData("suite_end", data); + suiteEnd: function () { + this._logData("suite_end"); }, @@ -160,14 +142,6 @@ StructuredLogger.prototype = { this.log("CRITICAL", message, extra); }, - processOutput: function(thread, message) { - this._logData('process_output', { - message: message, - thread: thread, - }); - }, - - _logData: function (action, data={}) { var allData = { action: action, diff --git a/testing/mozbase/mozleak/mozleak/leaklog.py b/testing/mozbase/mozleak/mozleak/leaklog.py index 73a25d6476e..c72de250778 100644 --- a/testing/mozbase/mozleak/mozleak/leaklog.py +++ b/testing/mozbase/mozleak/mozleak/leaklog.py @@ -10,15 +10,9 @@ import sys import mozinfo import mozrunner.utils - -def _get_default_logger(): - from mozlog import get_default_logger - log = get_default_logger(component='mozleak') - - if not log: - import logging - log = logging.getLogger(__name__) - return log +def _raw_log(): + import logging + return logging.getLogger(__name__) # Do not add anything to this list, unless one of the existing leaks below @@ -136,7 +130,7 @@ def process_single_leak_file(leakLogFileName, processType, leakThreshold, r"\s*-?\d+\s+(?P-?\d+)") # The class name can contain spaces. We remove trailing whitespace later. - log = log or _get_default_logger() + log = log or _raw_log() processString = "%s process:" % processType expectedLeaks = expectedTabProcessLeakCounts() if processType == 'tab' else {} @@ -282,7 +276,7 @@ def process_leak_log(leak_log_file, leak_thresholds=None, in the list ignore_missing_leaks. """ - log = log or _get_default_logger() + log = log or _raw_log() leakLogFile = leak_log_file if not os.path.exists(leakLogFile): diff --git a/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py b/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py index ca450adf4cd..ec5abc569c5 100644 --- a/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py +++ b/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py @@ -5,7 +5,6 @@ from .base import BaseFormatter from .process import strstatus - class TbplFormatter(BaseFormatter): """Formatter that formats logs in the legacy formatting format used by TBPL This is intended to be used to preserve backward compatibility with existing tools @@ -103,12 +102,12 @@ class TbplFormatter(BaseFormatter): def test_end(self, data): test_id = self.test_id(data["test"]) - duration_msg = "" + time_msg = "" if test_id in self.test_start_times: start_time = self.test_start_times.pop(test_id) time = data["time"] - start_time - duration_msg = "took %ims" % time + time_msg = "took %ims" % time if "expected" in data: message = data.get("message", "") @@ -120,20 +119,18 @@ class TbplFormatter(BaseFormatter): message = message[:-1] failure_line = "TEST-UNEXPECTED-%s | %s | %s\n" % ( - data["status"], self.id_str(test_id), message) + data["status"], test_id, message) if data["expected"] not in ("PASS", "OK"): expected_msg = "expected %s | " % data["expected"] else: expected_msg = "" - info_line = "TEST-INFO %s%s\n" % (expected_msg, duration_msg) + info_line = "TEST-INFO %s%s\n" % (expected_msg, time_msg) return failure_line + info_line - sections = ["TEST-%s" % data['status'], self.id_str(test_id)] - if duration_msg: - sections.append(duration_msg) - return ' | '.join(sections) + '\n' + return "TEST-%s | %s | %s\n" % ( + data["status"], test_id, time_msg) def suite_end(self, data): start_time = self.suite_start_time diff --git a/testing/mozbase/mozlog/mozlog/logtypes.py b/testing/mozbase/mozlog/mozlog/logtypes.py index dc516c98864..4d458e2b30b 100644 --- a/testing/mozbase/mozlog/mozlog/logtypes.py +++ b/testing/mozbase/mozlog/mozlog/logtypes.py @@ -132,9 +132,9 @@ class TestId(DataType): def convert(self, data): if isinstance(data, unicode): return data - elif isinstance(data, bytes): + elif isinstance(data, str): return data.decode("utf-8", "replace") - elif isinstance(data, (tuple, list)): + elif isinstance(data, tuple): # This is really a bit of a hack; should really split out convertors from the # fields they operate on func = Unicode(None).convert diff --git a/testing/mozbase/mozlog/mozlog/structuredlog.py b/testing/mozbase/mozlog/mozlog/structuredlog.py index fd5279b0823..adabdc31eac 100644 --- a/testing/mozbase/mozlog/mozlog/structuredlog.py +++ b/testing/mozbase/mozlog/mozlog/structuredlog.py @@ -238,8 +238,7 @@ class StructuredLogger(object): @log_action(List("tests", Unicode), Dict("run_info", default=None, optional=True), Dict("version_info", default=None, optional=True), - Dict("device_info", default=None, optional=True), - Dict("extra", default=None, optional=True)) + Dict("device_info", default=None, optional=True)) def suite_start(self, data): """Log a suite_start message @@ -253,7 +252,7 @@ class StructuredLogger(object): self._log_data("suite_start", data) - @log_action(Dict("extra", default=None, optional=True)) + @log_action() def suite_end(self, data): """Log a suite_end message""" if not self._ensure_suite_state('suite_end', data): From e749b02e9eaa6ad291736b01269b6af2f1f269bd Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Fri, 29 Jan 2016 11:47:58 -0500 Subject: [PATCH 58/72] Bug 1241906 - Spdy deadlock on suspended channel r=hurley --- netwerk/protocol/http/SpdySession31.cpp | 14 ++++++++++++-- netwerk/protocol/http/SpdyStream31.cpp | 7 +++++++ netwerk/protocol/http/SpdyStream31.h | 1 + netwerk/protocol/http/nsHttpConnection.cpp | 14 +++++++++----- netwerk/protocol/http/nsHttpTransaction.cpp | 9 +++++++-- netwerk/protocol/http/nsHttpTransaction.h | 2 ++ 6 files changed, 38 insertions(+), 9 deletions(-) diff --git a/netwerk/protocol/http/SpdySession31.cpp b/netwerk/protocol/http/SpdySession31.cpp index 97efc0e9c41..3f442837b71 100644 --- a/netwerk/protocol/http/SpdySession31.cpp +++ b/netwerk/protocol/http/SpdySession31.cpp @@ -2102,6 +2102,13 @@ SpdySession31::WriteSegments(nsAHttpSegmentWriter *writer, SpdyStream31 *stream = mInputFrameDataStream; mSegmentWriter = writer; rv = mInputFrameDataStream->WriteSegments(this, count, countWritten); + bool channelPipeFull = false; + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { + LOG3(("SpdySession31::WriteSegments session=%p stream=%p 0x%X " + "stream channel pipe full\n", + this, stream, stream ? stream->StreamID() : 0)); + channelPipeFull = mInputFrameDataStream->ChannelPipeFull(); + } mSegmentWriter = nullptr; mLastDataReadEpoch = mLastReadEpoch; @@ -2137,10 +2144,13 @@ SpdySession31::WriteSegments(nsAHttpSegmentWriter *writer, } if (NS_FAILED(rv)) { - LOG3(("SpdySession31 %p data frame read failure %x\n", this, rv)); + LOG3(("SpdySession31::WriteSegments session=%p stream=%p 0x%X " + "data frame read failure %x pipefull=%d\n", + this, stream, stream ? stream->StreamID() : 0, rv, channelPipeFull)); // maybe just blocked reading from network - if (rv == NS_BASE_STREAM_WOULD_BLOCK) + if ((rv == NS_BASE_STREAM_WOULD_BLOCK) && !channelPipeFull) { rv = NS_OK; + } } return rv; diff --git a/netwerk/protocol/http/SpdyStream31.cpp b/netwerk/protocol/http/SpdyStream31.cpp index b3f6eaf386d..746e5d57b85 100644 --- a/netwerk/protocol/http/SpdyStream31.cpp +++ b/netwerk/protocol/http/SpdyStream31.cpp @@ -229,6 +229,13 @@ SpdyStream31::WriteSegments(nsAHttpSegmentWriter *writer, return rv; } +bool +SpdyStream31::ChannelPipeFull() +{ + nsHttpTransaction *trans = mTransaction ? mTransaction->QueryHttpTransaction() : nullptr; + return trans ? trans->ChannelPipeFull() : false; +} + void SpdyStream31::CreatePushHashKey(const nsCString &scheme, const nsCString &hostHeader, diff --git a/netwerk/protocol/http/SpdyStream31.h b/netwerk/protocol/http/SpdyStream31.h index 6408c5cf145..5502e938005 100644 --- a/netwerk/protocol/http/SpdyStream31.h +++ b/netwerk/protocol/http/SpdyStream31.h @@ -88,6 +88,7 @@ public: int64_t LocalWindow() { return mLocalWindow; } bool BlockedOnRwin() { return mBlockedOnRwin; } + bool ChannelPipeFull(); // A pull stream has an implicit sink, a pushed stream has a sink // once it is matched to a pull stream. diff --git a/netwerk/protocol/http/nsHttpConnection.cpp b/netwerk/protocol/http/nsHttpConnection.cpp index 968938855c8..9ecaf866db0 100644 --- a/netwerk/protocol/http/nsHttpConnection.cpp +++ b/netwerk/protocol/http/nsHttpConnection.cpp @@ -1765,23 +1765,27 @@ nsHttpConnection::OnSocketReadable() break; } + mSocketInCondition = NS_OK; rv = mTransaction->WriteSegments(this, nsIOService::gDefaultSegmentSize, &n); + LOG(("nsHttpConnection::OnSocketReadable %p trans->ws rv=%x n=%d socketin=%x\n", + this, rv, n, mSocketInCondition)); if (NS_FAILED(rv)) { // if the transaction didn't want to take any more data, then // wait for the transaction to call ResumeRecv. - if (rv == NS_BASE_STREAM_WOULD_BLOCK) + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { rv = NS_OK; + } again = false; - } - else { + } else { mCurrentBytesRead += n; mTotalBytesRead += n; if (NS_FAILED(mSocketInCondition)) { // continue waiting for the socket if necessary... - if (mSocketInCondition == NS_BASE_STREAM_WOULD_BLOCK) + if (mSocketInCondition == NS_BASE_STREAM_WOULD_BLOCK) { rv = ResumeRecv(); - else + } else { rv = mSocketInCondition; + } again = false; } } diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp index a1e03e28797..e25b581d072 100644 --- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -127,6 +127,7 @@ nsHttpTransaction::nsHttpTransaction() , mContentDecoding(false) , mContentDecodingCheck(false) , mDeferredSendProgress(false) + , mWaitingOnPipeOut(false) , mReportedStart(false) , mReportedResponseHeader(false) , mForTakeResponseHead(nullptr) @@ -832,9 +833,10 @@ nsHttpTransaction::WriteSegments(nsAHttpSegmentWriter *writer, if (rv == NS_BASE_STREAM_WOULD_BLOCK) { nsCOMPtr target; gHttpHandler->GetSocketThreadTarget(getter_AddRefs(target)); - if (target) + if (target) { mPipeOut->AsyncWait(this, 0, 0, target); - else { + mWaitingOnPipeOut = true; + } else { NS_ERROR("no socket thread event target"); rv = NS_ERROR_UNEXPECTED; } @@ -2179,6 +2181,7 @@ NS_IMPL_QUERY_INTERFACE(nsHttpTransaction, NS_IMETHODIMP nsHttpTransaction::OnInputStreamReady(nsIAsyncInputStream *out) { + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); if (mConnection) { mConnection->TransactionHasDataToWrite(this); nsresult rv = mConnection->ResumeSend(); @@ -2196,6 +2199,8 @@ nsHttpTransaction::OnInputStreamReady(nsIAsyncInputStream *out) NS_IMETHODIMP nsHttpTransaction::OnOutputStreamReady(nsIAsyncOutputStream *out) { + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + mWaitingOnPipeOut = false; if (mConnection) { mConnection->TransactionHasDataToRecv(this); nsresult rv = mConnection->ResumeRecv(); diff --git a/netwerk/protocol/http/nsHttpTransaction.h b/netwerk/protocol/http/nsHttpTransaction.h index b7021dc1311..ce82230ba4d 100644 --- a/netwerk/protocol/http/nsHttpTransaction.h +++ b/netwerk/protocol/http/nsHttpTransaction.h @@ -143,6 +143,7 @@ public: } void SetPushedStream(Http2PushedStream *push) { mPushedStream = push; } uint32_t InitialRwin() const { return mInitialRwin; }; + bool ChannelPipeFull() { return mWaitingOnPipeOut; } // Locked methods to get and set timing info const TimingStruct Timings(); @@ -306,6 +307,7 @@ private: bool mContentDecoding; bool mContentDecodingCheck; bool mDeferredSendProgress; + bool mWaitingOnPipeOut; // mClosed := transaction has been explicitly closed // mTransactionDone := transaction ran to completion or was interrupted From 3967d94028974a80b1460092d863df821c30af44 Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Fri, 5 Feb 2016 11:17:24 -0500 Subject: [PATCH 59/72] Bug 1241906 - test for suspended spdy3.1 channel r=hurley --- netwerk/test/unit/test_spdy.js | 23 +++++++++++++++++++---- testing/xpcshell/moz-spdy/moz-spdy.js | 2 ++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/netwerk/test/unit/test_spdy.js b/netwerk/test/unit/test_spdy.js index b569f0ed552..709d0d9dd5d 100644 --- a/netwerk/test/unit/test_spdy.js +++ b/netwerk/test/unit/test_spdy.js @@ -21,6 +21,7 @@ var md5s = ['f1b708bba17f1ce948dc979f4d7092bc', var bigListenerData = generateContent(128 * 1024); var bigListenerMD5 = '8f607cfdd2c87d6a7eedb657dafbd836'; +var hugeListenerData = generateContent(800 * 1024); function checkIsSpdy(request) { try { @@ -151,9 +152,6 @@ SpdyBigListener.prototype.onDataAvailable = function(request, ctx, stream, off, this.onDataAvailableFired = true; this.isSpdyConnection = checkIsSpdy(request); this.buffer = this.buffer.concat(read_stream(stream, cnt)); - // We know the server should send us the same data as our big post will be, - // so the md5 should be the same - do_check_eq(bigListenerMD5, request.getResponseHeader("X-Expected-MD5")); }; SpdyBigListener.prototype.onStopRequest = function(request, ctx, status) { @@ -162,7 +160,14 @@ SpdyBigListener.prototype.onStopRequest = function(request, ctx, status) { do_check_true(this.isSpdyConnection); // Don't want to flood output, so don't use do_check_eq - do_check_true(this.buffer == bigListenerData); + if (request.originalURI.spec == "https://localhost:" + serverPort + "/big") { + // We know the server should send us the same data as our big post will be, + // so the md5 should be the same + do_check_eq(bigListenerMD5, request.getResponseHeader("X-Expected-MD5")); + do_check_true(this.buffer == bigListenerData); + } else { + do_check_true(this.buffer == hugeListenerData); + } run_next_test(); do_test_finished(); @@ -298,6 +303,15 @@ function test_spdy_big() { chan.asyncOpen2(listener); } +// Make sure we handle big GETs with suspend/resume +function test_spdy_big_and_slow() { + var chan = makeChan("https://localhost:" + serverPort + "/huge"); + var listener = new SpdyBigListener(); + chan.asyncOpen2(listener); + chan.suspend(); + do_timeout(750, chan.resume); +} + // Support for doing a POST function do_post(content, chan, listener) { var stream = Cc["@mozilla.org/io/string-input-stream;1"] @@ -348,6 +362,7 @@ var tests = [ test_spdy_post_big , test_spdy_header , test_spdy_multiplex , test_spdy_big + , test_spdy_big_and_slow , test_spdy_post // cleanup , test_complete diff --git a/testing/xpcshell/moz-spdy/moz-spdy.js b/testing/xpcshell/moz-spdy/moz-spdy.js index e7ece7051bd..5ca27022eb9 100644 --- a/testing/xpcshell/moz-spdy/moz-spdy.js +++ b/testing/xpcshell/moz-spdy/moz-spdy.js @@ -155,6 +155,8 @@ function handleRequest(req, res) { hash.update(content); var md5 = hash.digest('hex'); res.setHeader("X-Expected-MD5", md5); + } else if (u.pathname == "/huge") { + content = getHugeContent(800 * 1024); } else if (u.pathname == "/post") { if (req.method != "POST") { res.writeHead(405); From 22dfc698ecbd9c95d40a76fa22161d3eb18484cb Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Fri, 5 Feb 2016 10:11:46 -0800 Subject: [PATCH 60/72] Bug 1239861. Part 2 Properly resize DXGI swap chain buffer size. r=bas --- gfx/layers/d3d11/CompositorD3D11.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gfx/layers/d3d11/CompositorD3D11.cpp b/gfx/layers/d3d11/CompositorD3D11.cpp index 065164f0088..04156dcab7a 100644 --- a/gfx/layers/d3d11/CompositorD3D11.cpp +++ b/gfx/layers/d3d11/CompositorD3D11.cpp @@ -1386,12 +1386,12 @@ CompositorD3D11::VerifyBufferSize() if (newRefCnt > 0) { gfxCriticalError() << "Unexpecting lingering references to backbuffer! RefCnt: " << newRefCnt; } - - hr = mSwapChain->ResizeBuffers(1, mSize.width, mSize.height, - DXGI_FORMAT_B8G8R8A8_UNORM, - 0); } + hr = mSwapChain->ResizeBuffers(1, mSize.width, mSize.height, + DXGI_FORMAT_B8G8R8A8_UNORM, + 0); + mVerifyBuffersFailed = FAILED(hr); if (mVerifyBuffersFailed) { gfxCriticalNote << "D3D11 swap resize buffers failed " << hexa(hr) << " on " << mSize; From b1f3e35480776ad2ec067137e03d7ca92dfe99a4 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Fri, 5 Feb 2016 10:11:48 -0800 Subject: [PATCH 61/72] Bug 1239861. Skip composite if vsync time is before force composite time. r=kats --- gfx/layers/ipc/CompositorParent.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index d553d8c6655..ea5edfc675d 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -508,6 +508,13 @@ CompositorVsyncScheduler::Composite(TimeStamp aVsyncTimestamp) mCurrentCompositeTask = nullptr; } + if ((aVsyncTimestamp < mLastCompose) && !mAsapScheduling) { + // We can sometimes get vsync timestamps that are in the past + // compared to the last compose with force composites. + // In those cases, wait until the next vsync; + return; + } + DispatchTouchEvents(aVsyncTimestamp); DispatchVREvents(aVsyncTimestamp); @@ -545,6 +552,7 @@ CompositorVsyncScheduler::OnForceComposeToTarget() void CompositorVsyncScheduler::ForceComposeToTarget(gfx::DrawTarget* aTarget, const IntRect* aRect) { + MOZ_ASSERT(CompositorParent::IsInCompositorThread()); OnForceComposeToTarget(); mLastCompose = TimeStamp::Now(); ComposeToTarget(aTarget, aRect); @@ -632,6 +640,7 @@ CompositorVsyncScheduler::ScheduleTask(CancelableTask* aTask, int aTime) void CompositorVsyncScheduler::ResumeComposition() { + MOZ_ASSERT(CompositorParent::IsInCompositorThread()); mLastCompose = TimeStamp::Now(); ComposeToTarget(nullptr); } From 99f0a36c52375f5ce6cd60b6c6b108b064072f07 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 5 Feb 2016 13:12:52 -0500 Subject: [PATCH 62/72] Bug 1245674. Null-check mGlobal before dereferencing it in one more place in Promise code. r=smaug --- dom/promise/Promise.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index 0f6efeb908b..0beb6cf58ba 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -2001,7 +2001,7 @@ void Promise::AppendCallbacks(PromiseCallback* aResolveCallback, PromiseCallback* aRejectCallback) { - if (mGlobal->IsDying()) { + if (!mGlobal || mGlobal->IsDying()) { return; } From e4d01c3336c2eed4670bb94a870cc25bb99ecc53 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Fri, 5 Feb 2016 10:12:25 -0800 Subject: [PATCH 63/72] Bug 1244898: Suppress the exception from BeginElement. r=bz --- dom/svg/SVGAnimationElement.cpp | 2 +- dom/svg/crashtests/1244898-1.xhtml | 14 ++++++++++++++ dom/svg/crashtests/crashtests.list | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 dom/svg/crashtests/1244898-1.xhtml diff --git a/dom/svg/SVGAnimationElement.cpp b/dom/svg/SVGAnimationElement.cpp index c9a7e882ec2..5d973b0f0ce 100644 --- a/dom/svg/SVGAnimationElement.cpp +++ b/dom/svg/SVGAnimationElement.cpp @@ -372,7 +372,7 @@ SVGAnimationElement::ActivateByHyperlink() // else, silently fail. We mustn't be part of an SVG document fragment that // is attached to the document tree so there's nothing we can do here } else { - ErrorResult rv; + IgnoredErrorResult rv; BeginElement(rv); } } diff --git a/dom/svg/crashtests/1244898-1.xhtml b/dom/svg/crashtests/1244898-1.xhtml new file mode 100644 index 00000000000..9b89c2c8b81 --- /dev/null +++ b/dom/svg/crashtests/1244898-1.xhtml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/dom/svg/crashtests/crashtests.list b/dom/svg/crashtests/crashtests.list index b6ebda27c93..8ff00ddad7c 100644 --- a/dom/svg/crashtests/crashtests.list +++ b/dom/svg/crashtests/crashtests.list @@ -74,4 +74,5 @@ load 880544-5.svg load 898915-1.svg load 1035248-1.svg load 1035248-2.svg +load 1244898-1.xhtml load zero-size-image.svg From 546821fb9677ce1de2f5880430ff2128992abd56 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Fri, 5 Feb 2016 10:12:25 -0800 Subject: [PATCH 64/72] Bug 1244894: Steal the failed nsresult when bailing early. r=bz --- editor/libeditor/crashtests/1244894.xhtml | 21 +++++++++++++++++++++ editor/libeditor/crashtests/crashtests.list | 1 + editor/libeditor/nsEditor.cpp | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 editor/libeditor/crashtests/1244894.xhtml diff --git a/editor/libeditor/crashtests/1244894.xhtml b/editor/libeditor/crashtests/1244894.xhtml new file mode 100644 index 00000000000..89a24751e9c --- /dev/null +++ b/editor/libeditor/crashtests/1244894.xhtml @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/editor/libeditor/crashtests/crashtests.list b/editor/libeditor/crashtests/crashtests.list index e6dc9fe717e..563f5446b60 100644 --- a/editor/libeditor/crashtests/crashtests.list +++ b/editor/libeditor/crashtests/crashtests.list @@ -66,3 +66,4 @@ needs-focus load 1128787.html load 1134545.html load 1158452.html load 1158651.html +load 1244894.xhtml diff --git a/editor/libeditor/nsEditor.cpp b/editor/libeditor/nsEditor.cpp index ba0c1fa9913..43a3748fe8f 100644 --- a/editor/libeditor/nsEditor.cpp +++ b/editor/libeditor/nsEditor.cpp @@ -3837,7 +3837,7 @@ nsEditor::SplitNodeDeep(nsIContent& aNode, didSplit = true; ErrorResult rv; nsCOMPtr newLeftNode = SplitNode(nodeToSplit, offset, rv); - NS_ENSURE_TRUE(!rv.Failed(), -1); + NS_ENSURE_TRUE(!NS_FAILED(rv.StealNSResult()), -1); rightNode = nodeToSplit; leftNode = newLeftNode; From 6312449cfa5b8c0c47ec9d005bba497d8425d154 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Fri, 5 Feb 2016 10:12:25 -0800 Subject: [PATCH 65/72] Bug 1245927: Innerize before creating DOM files from the file picker. r=baku --- widget/nsBaseFilePicker.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/widget/nsBaseFilePicker.cpp b/widget/nsBaseFilePicker.cpp index b631fb970cb..08935999d22 100644 --- a/widget/nsBaseFilePicker.cpp +++ b/widget/nsBaseFilePicker.cpp @@ -347,7 +347,9 @@ nsBaseFilePicker::GetDomFileOrDirectory(nsISupports** aValue) return NS_OK; } - RefPtr domFile = File::CreateFromFile(mParent, localFile); + auto* innerParent = mParent ? mParent->GetCurrentInnerWindow() : nullptr; + + RefPtr domFile = File::CreateFromFile(innerParent, localFile); domFile->Impl()->SetIsDirectory(mMode == nsIFilePicker::modeGetFolder); nsCOMPtr(domFile).forget(aValue); return NS_OK; From a3b618ba93043d72b644c1e84cc0eb5e7e6ea212 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Fri, 5 Feb 2016 10:12:25 -0800 Subject: [PATCH 66/72] Bug 1245950: Privately inherit from legacy interfaces nsIDOMWindow/nsIDOMWindowInternal. r=smaug If you still need to get to these from C++ for some reason, you need to go through QueryInterface. --- dom/base/nsDocument.cpp | 3 ++- dom/base/nsGlobalWindow.cpp | 4 ++-- dom/base/nsGlobalWindow.h | 2 +- dom/base/nsIDocument.h | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 2a3f759b50f..9d6dfa16729 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -10645,7 +10645,7 @@ nsDocument::SetImagesNeedAnimating(bool aAnimating) } already_AddRefed -nsIDocument::CreateTouch(nsIDOMWindow* aView, +nsIDocument::CreateTouch(nsGlobalWindow* aView, EventTarget* aTarget, int32_t aIdentifier, int32_t aPageX, int32_t aPageY, @@ -10655,6 +10655,7 @@ nsIDocument::CreateTouch(nsIDOMWindow* aView, float aRotationAngle, float aForce) { + MOZ_ASSERT(aView->IsInnerWindow()); RefPtr touch = new Touch(aTarget, aIdentifier, aPageX, aPageY, diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 4b7bbfb2f86..671ce44b363 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -8543,9 +8543,9 @@ public: } #endif - nsCOMPtr window = do_QueryReferent(mWindow); + nsCOMPtr window = do_QueryReferent(mWindow); if (!skipNukeCrossCompartment && window) { - nsGlobalWindow* win = static_cast(window.get()); + nsGlobalWindow* win = nsGlobalWindow::FromSupports(window); nsGlobalWindow* currentInner = win->IsInnerWindow() ? win : win->GetCurrentInnerWindowInternal(); NS_ENSURE_TRUE(currentInner, NS_OK); diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 57e3aa2db2e..8c2627bfc7d 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -306,7 +306,7 @@ private: class nsGlobalWindow : public mozilla::dom::EventTarget, public nsPIDOMWindow, - public nsIDOMWindowInternal, + private nsIDOMWindowInternal, public nsIScriptGlobalObject, public nsIScriptObjectPrincipal, public nsSupportsWeakReference, diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index a0e3b1a5766..98626e971c7 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -2577,7 +2577,7 @@ public: JS::Handle aResult, mozilla::ErrorResult& rv); // Touch event handlers already on nsINode already_AddRefed - CreateTouch(nsIDOMWindow* aView, mozilla::dom::EventTarget* aTarget, + CreateTouch(nsGlobalWindow* aView, mozilla::dom::EventTarget* aTarget, int32_t aIdentifier, int32_t aPageX, int32_t aPageY, int32_t aScreenX, int32_t aScreenY, int32_t aClientX, int32_t aClientY, int32_t aRadiusX, int32_t aRadiusY, From 705307de45f25ee1a7c16b775de775bd3bbe6515 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Fri, 5 Feb 2016 19:31:08 +0100 Subject: [PATCH 67/72] Bug 1245141 - Use new Proxy for AddonManager.addonTypes. r=mossop --- toolkit/mozapps/extensions/AddonManager.jsm | 95 ++++++++++----------- 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/toolkit/mozapps/extensions/AddonManager.jsm b/toolkit/mozapps/extensions/AddonManager.jsm index 43c79462e47..a9346ca895b 100644 --- a/toolkit/mozapps/extensions/AddonManager.jsm +++ b/toolkit/mozapps/extensions/AddonManager.jsm @@ -688,53 +688,6 @@ var AddonManagerInternal = { // Store telemetry details per addon provider telemetryDetails: {}, - // A read-only wrapper around the types dictionary - typesProxy: Proxy.create({ - getOwnPropertyDescriptor: function(aName) { - if (!(aName in AddonManagerInternal.types)) - return undefined; - - return { - value: AddonManagerInternal.types[aName].type, - writable: false, - configurable: false, - enumerable: true - } - }, - - getPropertyDescriptor: function(aName) { - return this.getOwnPropertyDescriptor(aName); - }, - - getOwnPropertyNames: function() { - return Object.keys(AddonManagerInternal.types); - }, - - getPropertyNames: function() { - return this.getOwnPropertyNames(); - }, - - delete: function(aName) { - // Not allowed to delete properties - return false; - }, - - defineProperty: function(aName, aProperty) { - // Ignore attempts to define properties - }, - - fix: function(){ - return undefined; - }, - - // Despite MDC's claims to the contrary, it is required that this trap - // be defined - enumerate: function() { - // All properties are enumerable - return this.getPropertyNames(); - } - }), - recordTimestamp: function(name, value) { this.TelemetryTimestamps.add(name, value); }, @@ -2697,7 +2650,53 @@ var AddonManagerInternal = { }, get addonTypes() { - return this.typesProxy; + // A read-only wrapper around the types dictionary + return new Proxy(this.types, { + defineProperty(target, property, descriptor) { + // Not allowed to define properties + return false; + }, + + deleteProperty(target, property) { + // Not allowed to delete properties + return false; + }, + + get(target, property, receiver) { + if (!target.hasOwnProperty(property)) + return undefined; + + return target[property].type; + }, + + getOwnPropertyDescriptor(target, property) { + if (!target.hasOwnProperty(property)) + return undefined; + + return { + value: target[property].type, + writable: false, + // Claim configurability to maintain the proxy invariants. + configurable: true, + enumerable: true + } + }, + + preventExtensions(target) { + // Not allowed to prevent adding new properties + return false; + }, + + set(target, property, value, receiver) { + // Not allowed to set properties + return false; + }, + + setPrototypeOf(target, prototype) { + // Not allowed to change prototype + return false; + } + }); }, get autoUpdateDefault() { From 91fe068cd88c2f9dc13ae4c45c5a4c123fc418d4 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Thu, 4 Feb 2016 16:09:11 -0800 Subject: [PATCH 68/72] Bug 1237458 - Use MOZ_RELEASE_ASSERT for IPC assertions (r=jld) --- ipc/glue/MessageChannel.cpp | 98 ++++++++++++++++++------------------- ipc/glue/MessageChannel.h | 7 +-- 2 files changed, 53 insertions(+), 52 deletions(-) diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index f27e187eb27..a4b5b7d7cab 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -149,12 +149,12 @@ public: mDirection(direction), mMoved(false) { - MOZ_ASSERT(mMessageName); + MOZ_RELEASE_ASSERT(mMessageName); } InterruptFrame(InterruptFrame&& aOther) { - MOZ_ASSERT(aOther.mMessageName); + MOZ_RELEASE_ASSERT(aOther.mMessageName); mMessageName = aOther.mMessageName; aOther.mMessageName = nullptr; aOther.mMoved = true; @@ -166,7 +166,7 @@ public: ~InterruptFrame() { - MOZ_ASSERT_IF(!mMessageName, mMoved); + MOZ_RELEASE_ASSERT(mMessageName || mMoved); } InterruptFrame& operator=(InterruptFrame&& aOther) @@ -213,7 +213,7 @@ private: int32_t mMessageRoutingId; Semantics mMesageSemantics; Direction mDirection; - DebugOnly mMoved; + bool mMoved; // Disable harmful methods. InterruptFrame(const InterruptFrame& aOther) = delete; @@ -248,7 +248,7 @@ public: ~CxxStackFrame() { mThat.AssertWorkerThread(); - MOZ_ASSERT(!mThat.mCxxStackFrames.empty()); + MOZ_RELEASE_ASSERT(!mThat.mCxxStackFrames.empty()); const InterruptFrame& frame = mThat.mCxxStackFrames.back(); bool exitingSync = frame.IsOutgoingSync(); @@ -328,7 +328,7 @@ MessageChannel::MessageChannel(MessageListener *aListener) #ifdef OS_WIN mEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr); - NS_ASSERTION(mEvent, "CreateEvent failed! Nothing is going to work!"); + MOZ_RELEASE_ASSERT(mEvent, "CreateEvent failed! Nothing is going to work!"); #endif } @@ -337,8 +337,8 @@ MessageChannel::~MessageChannel() MOZ_COUNT_DTOR(ipc::MessageChannel); IPC_ASSERT(mCxxStackFrames.empty(), "mismatched CxxStackFrame ctor/dtors"); #ifdef OS_WIN - DebugOnly ok = CloseHandle(mEvent); - MOZ_ASSERT(ok); + BOOL ok = CloseHandle(mEvent); + MOZ_RELEASE_ASSERT(ok); #endif Clear(); } @@ -466,7 +466,7 @@ MessageChannel::Open(MessageChannel *aTargetChan, MessageLoop *aTargetLoop, Side while (ChannelOpening == mChannelState) mMonitor->Wait(); - NS_ASSERTION(ChannelConnected == mChannelState, "not connected when awoken"); + MOZ_RELEASE_ASSERT(ChannelConnected == mChannelState, "not connected when awoken"); return (ChannelConnected == mChannelState); } @@ -483,8 +483,8 @@ MessageChannel::OnOpenAsSlave(MessageChannel *aTargetChan, Side aSide) mMonitor = aTargetChan->mMonitor; MonitorAutoLock lock(*mMonitor); - NS_ASSERTION(ChannelOpening == aTargetChan->mChannelState, - "Target channel not in the process of opening"); + MOZ_RELEASE_ASSERT(ChannelOpening == aTargetChan->mChannelState, + "Target channel not in the process of opening"); mChannelState = ChannelConnected; aTargetChan->mChannelState = ChannelConnected; aTargetChan->mMonitor->Notify(); @@ -596,7 +596,7 @@ MessageChannel::ShouldDeferMessage(const Message& aMsg) // Unless they're urgent, we always defer async messages. if (!aMsg.is_sync()) { - MOZ_ASSERT(aMsg.priority() == IPC::Message::PRIORITY_NORMAL); + MOZ_RELEASE_ASSERT(aMsg.priority() == IPC::Message::PRIORITY_NORMAL); return true; } @@ -658,10 +658,10 @@ MessageChannel::OnMessageReceivedFromLink(const Message& aMsg) return; } - MOZ_ASSERT(aMsg.transaction_id() == mCurrentTransaction); - MOZ_ASSERT(AwaitingSyncReply()); - MOZ_ASSERT(!mRecvd); - MOZ_ASSERT(!mTimedOutMessageSeqno); + MOZ_RELEASE_ASSERT(aMsg.transaction_id() == mCurrentTransaction); + MOZ_RELEASE_ASSERT(AwaitingSyncReply()); + MOZ_RELEASE_ASSERT(!mRecvd); + MOZ_RELEASE_ASSERT(!mTimedOutMessageSeqno); // Rather than storing errors in mRecvd, we mark them in // mRecvdErrors. We need a counter because multiple replies can arrive @@ -683,8 +683,8 @@ MessageChannel::OnMessageReceivedFromLink(const Message& aMsg) } // Prioritized messages cannot be compressed. - MOZ_ASSERT_IF(aMsg.compress_type() != IPC::Message::COMPRESSION_NONE, - aMsg.priority() == IPC::Message::PRIORITY_NORMAL); + MOZ_RELEASE_ASSERT(aMsg.compress_type() == IPC::Message::COMPRESSION_NONE || + aMsg.priority() == IPC::Message::PRIORITY_NORMAL); bool compress = false; if (aMsg.compress_type() == IPC::Message::COMPRESSION_ENABLED) { @@ -695,8 +695,8 @@ MessageChannel::OnMessageReceivedFromLink(const Message& aMsg) // This message type has compression enabled, and the back of the // queue was the same message type and routed to the same destination. // Replace it with the newer message. - MOZ_ASSERT(mPending.back().compress_type() == - IPC::Message::COMPRESSION_ENABLED); + MOZ_RELEASE_ASSERT(mPending.back().compress_type() == + IPC::Message::COMPRESSION_ENABLED); mPending.pop_back(); } } else if (aMsg.compress_type() == IPC::Message::COMPRESSION_ALL) { @@ -709,7 +709,7 @@ MessageChannel::OnMessageReceivedFromLink(const Message& aMsg) // Erase it. Note that, since we always compress these redundancies, There Can // Be Only One. compress = true; - MOZ_ASSERT((*it).compress_type() == IPC::Message::COMPRESSION_ALL); + MOZ_RELEASE_ASSERT((*it).compress_type() == IPC::Message::COMPRESSION_ALL); mPending.erase((++it).base()); } } @@ -787,8 +787,8 @@ MessageChannel::ProcessPendingRequests(int seqno, int transaction) for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) { Message &msg = *it; - MOZ_ASSERT(mCurrentTransaction == transaction, - "Calling ShouldDeferMessage when cancelled"); + MOZ_RELEASE_ASSERT(mCurrentTransaction == transaction, + "Calling ShouldDeferMessage when cancelled"); bool defer = ShouldDeferMessage(msg); // Only log the interesting messages. @@ -883,7 +883,7 @@ MessageChannel::Send(Message* aMsg, Message* aReply) // Generally only the parent dispatches urgent messages. And the only // sync messages it can send are high-priority. Mainly we want to ensure // here that we don't return false for non-CPOW messages. - MOZ_ASSERT(msg->priority() == IPC::Message::PRIORITY_HIGH); + MOZ_RELEASE_ASSERT(msg->priority() == IPC::Message::PRIORITY_HIGH); IPC_LOG("Sending while dispatching urgent message"); mLastSendError = SyncSendError::SendingCPOWWhileDispatchingUrgent; return false; @@ -893,7 +893,7 @@ MessageChannel::Send(Message* aMsg, Message* aReply) (msg->priority() < DispatchingSyncMessagePriority() || msg->priority() < AwaitingSyncReplyPriority())) { - MOZ_ASSERT(DispatchingSyncMessage() || DispatchingAsyncMessage()); + MOZ_RELEASE_ASSERT(DispatchingSyncMessage() || DispatchingAsyncMessage()); IPC_LOG("Cancel from Send"); CancelMessage *cancel = new CancelMessage(mCurrentTransaction); CancelTransaction(mCurrentTransaction); @@ -924,7 +924,7 @@ MessageChannel::Send(Message* aMsg, Message* aReply) int32_t seqno = msg->seqno(); int prio = msg->priority(); - DebugOnly replyType = msg->type() + 1; + msgid_t replyType = msg->type() + 1; AutoSetValue replies(mAwaitingSyncReply, true); AutoSetValue prioSet(mAwaitingSyncReplyPriority, prio); @@ -967,9 +967,9 @@ MessageChannel::Send(Message* aMsg, Message* aReply) break; } - MOZ_ASSERT(!mTimedOutMessageSeqno); + MOZ_RELEASE_ASSERT(!mTimedOutMessageSeqno); - MOZ_ASSERT(mCurrentTransaction == transaction); + MOZ_RELEASE_ASSERT(mCurrentTransaction == transaction); bool maybeTimedOut = !WaitForSyncNotify(handleWindowsMessages); if (!Connected()) { @@ -1015,12 +1015,12 @@ MessageChannel::Send(Message* aMsg, Message* aReply) } } - MOZ_ASSERT(mRecvd); - MOZ_ASSERT(mRecvd->is_reply(), "expected reply"); - MOZ_ASSERT(!mRecvd->is_reply_error()); - MOZ_ASSERT(mRecvd->type() == replyType, "wrong reply type"); - MOZ_ASSERT(mRecvd->seqno() == seqno); - MOZ_ASSERT(mRecvd->is_sync()); + MOZ_RELEASE_ASSERT(mRecvd); + MOZ_RELEASE_ASSERT(mRecvd->is_reply(), "expected reply"); + MOZ_RELEASE_ASSERT(!mRecvd->is_reply_error()); + MOZ_RELEASE_ASSERT(mRecvd->seqno() == seqno); + MOZ_RELEASE_ASSERT(mRecvd->type() == replyType, "wrong reply type"); + MOZ_RELEASE_ASSERT(mRecvd->is_sync()); *aReply = Move(*mRecvd); mRecvd = nullptr; @@ -1348,7 +1348,7 @@ MessageChannel::OnMaybeDequeueOne() } // We should not be in a transaction yet if we're not blocked. - MOZ_ASSERT(mCurrentTransaction == 0); + MOZ_RELEASE_ASSERT(mCurrentTransaction == 0); DispatchMessage(recvd); return true; @@ -1369,7 +1369,7 @@ MessageChannel::DispatchMessage(const Message &aMsg) AutoEnterTransaction transaction(this, aMsg); int id = aMsg.transaction_id(); - MOZ_ASSERT_IF(aMsg.is_sync(), id == mCurrentTransaction); + MOZ_RELEASE_ASSERT(!aMsg.is_sync() || id == mCurrentTransaction); { MonitorAutoUnlock unlock(*mMonitor); @@ -1401,7 +1401,7 @@ MessageChannel::DispatchSyncMessage(const Message& aMsg, Message*& aReply) int prio = aMsg.priority(); - MOZ_ASSERT_IF(prio > IPC::Message::PRIORITY_NORMAL, NS_IsMainThread()); + MOZ_RELEASE_ASSERT(prio == IPC::Message::PRIORITY_NORMAL || NS_IsMainThread()); MessageChannel* dummy; MessageChannel*& blockingVar = mSide == ChildSide && NS_IsMainThread() ? gParentProcessBlocker : dummy; @@ -1429,7 +1429,7 @@ void MessageChannel::DispatchAsyncMessage(const Message& aMsg) { AssertWorkerThread(); - MOZ_ASSERT(!aMsg.is_interrupt() && !aMsg.is_sync()); + MOZ_RELEASE_ASSERT(!aMsg.is_interrupt() && !aMsg.is_sync()); if (aMsg.routing_id() == MSG_ROUTING_NONE) { NS_RUNTIMEABORT("unhandled special message!"); @@ -1548,7 +1548,7 @@ MessageChannel::MaybeUndeferIncall() IPC_ASSERT(0 < mRemoteStackDepthGuess, "fatal logic error"); --mRemoteStackDepthGuess; - MOZ_ASSERT(call.priority() == IPC::Message::PRIORITY_NORMAL); + MOZ_RELEASE_ASSERT(call.priority() == IPC::Message::PRIORITY_NORMAL); mPending.push_back(call); } @@ -1697,7 +1697,7 @@ MessageChannel::SetReplyTimeoutMs(int32_t aTimeoutMs) void MessageChannel::OnChannelConnected(int32_t peer_id) { - MOZ_ASSERT(!mPeerPidSet); + MOZ_RELEASE_ASSERT(!mPeerPidSet); mPeerPidSet = true; mPeerPid = peer_id; mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mOnChannelConnectedTask)); @@ -1707,7 +1707,7 @@ void MessageChannel::DispatchOnChannelConnected() { AssertWorkerThread(); - MOZ_ASSERT(mPeerPidSet); + MOZ_RELEASE_ASSERT(mPeerPidSet); if (mListener) mListener->OnChannelConnected(mPeerPid); } @@ -2061,7 +2061,7 @@ MessageChannel::DumpInterruptStack(const char* const pfx) const int32_t MessageChannel::GetTopmostMessageRoutingId() const { - MOZ_ASSERT(MessageLoop::current() == mWorkerLoop); + MOZ_RELEASE_ASSERT(MessageLoop::current() == mWorkerLoop); if (mCxxStackFrames.empty()) { return MSG_ROUTING_NONE; } @@ -2147,20 +2147,20 @@ MessageChannel::CancelTransaction(int transaction) // 2. Parent times out H. // 3. Child dispatches H and sends nested message H' (same transaction). // 4. Parent dispatches H' and cancels. - MOZ_ASSERT_IF(mCurrentTransaction, mCurrentTransaction == transaction); + MOZ_RELEASE_ASSERT(!mCurrentTransaction || mCurrentTransaction == transaction); mCurrentTransaction = 0; // During a timeout Send should always fail. - MOZ_ASSERT(!mAwaitingSyncReply); + MOZ_RELEASE_ASSERT(!mAwaitingSyncReply); } else { - MOZ_ASSERT(mCurrentTransaction == transaction); + MOZ_RELEASE_ASSERT(mCurrentTransaction == transaction); mCurrentTransaction = 0; mAwaitingSyncReply = false; mAwaitingSyncReplyPriority = 0; } - DebugOnly foundSync = false; + bool foundSync = false; for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) { Message &msg = *it; @@ -2172,8 +2172,8 @@ MessageChannel::CancelTransaction(int transaction) // avoid processing messages out of order in the short time before it // crashes. if (msg.is_sync() && msg.priority() != IPC::Message::PRIORITY_NORMAL) { - MOZ_ASSERT(!foundSync); - MOZ_ASSERT(msg.transaction_id() != transaction); + MOZ_RELEASE_ASSERT(!foundSync); + MOZ_RELEASE_ASSERT(msg.transaction_id() != transaction); IPC_LOG("Removing msg from queue seqno=%d xid=%d", msg.seqno(), msg.transaction_id()); foundSync = true; it = mPending.erase(it); @@ -2207,7 +2207,7 @@ MessageChannel::CancelCurrentTransaction() } IPC_LOG("Cancel requested: current xid=%d", mCurrentTransaction); - MOZ_ASSERT(DispatchingSyncMessage()); + MOZ_RELEASE_ASSERT(DispatchingSyncMessage()); CancelMessage *cancel = new CancelMessage(mCurrentTransaction); CancelTransaction(mCurrentTransaction); mLink->SendMessage(cancel); diff --git a/ipc/glue/MessageChannel.h b/ipc/glue/MessageChannel.h index 27b6e5ae078..ee733dc43dc 100644 --- a/ipc/glue/MessageChannel.h +++ b/ipc/glue/MessageChannel.h @@ -624,8 +624,9 @@ class MessageChannel : HasResultCodes if (!aMessage.is_sync()) return; - MOZ_ASSERT_IF(mChan->mSide == ParentSide && mOldTransaction != aMessage.transaction_id(), - !mOldTransaction || aMessage.priority() > mChan->AwaitingSyncReplyPriority()); + MOZ_DIAGNOSTIC_ASSERT( + !(mChan->mSide == ParentSide && mOldTransaction != aMessage.transaction_id()) || + !mOldTransaction || aMessage.priority() > mChan->AwaitingSyncReplyPriority()); mChan->mCurrentTransaction = aMessage.transaction_id(); } ~AutoEnterTransaction() { @@ -776,7 +777,7 @@ class MessageChannel : HasResultCodes // safely. This is necessary to be able to cancel notification if we are // closed at the same time. RefPtr mOnChannelConnectedTask; - DebugOnly mPeerPidSet; + bool mPeerPidSet; int32_t mPeerPid; }; From c2526eb33dbbb9196eb51ac03bc40a2096533cdf Mon Sep 17 00:00:00 2001 From: Gregory Szorc Date: Fri, 5 Feb 2016 10:51:41 -0800 Subject: [PATCH 69/72] Bug 1246040 - Change architecture detection on CentOS; r=glandium This fails under Docker otherwise. platform.architecture() uses the architecture of the Python executable, which should be fine assuming the system-installed Python is being used. Even if the user installed their own Python, running a 32-bit Python on a 64-bit system feels like something that would be extremely rare. DONTBUILD (NPOTB) --- python/mozboot/mozboot/centos.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/mozboot/mozboot/centos.py b/python/mozboot/mozboot/centos.py index d99e56dae57..62f0a6ffe63 100644 --- a/python/mozboot/mozboot/centos.py +++ b/python/mozboot/mozboot/centos.py @@ -54,9 +54,8 @@ class CentOSBootstrapper(BaseBootstrapper): self.dnf_groupinstall(*self.browser_group_packages) self.dnf_install(*self.browser_packages) - kern = platform.uname() yasm = 'http://pkgs.repoforge.org/yasm/yasm-1.1.0-1.el6.rf.i686.rpm' - if 'x86_64' in kern[2]: + if platform.architecture()[0] == '64bit': yasm = 'http://pkgs.repoforge.org/yasm/yasm-1.1.0-1.el6.rf.x86_64.rpm' self.run_as_root(['rpm', '-ivh', yasm]) From c8ef515f7126c7a369f2e236abededcc993b7876 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 5 Feb 2016 11:42:55 -0800 Subject: [PATCH 70/72] Backed out changeset 4fa1296bd773 (bug 1104916) for win debug m(oth) permafails CLOSED TREE --- dom/base/nsGkAtomList.h | 1 - dom/ipc/PBrowser.ipdl | 7 +- dom/ipc/TabChild.cpp | 24 +---- dom/ipc/TabChild.h | 6 +- dom/ipc/TabParent.cpp | 20 +--- dom/ipc/TabParent.h | 3 - layout/base/nsPresContext.cpp | 48 ---------- layout/base/nsPresContext.h | 16 ---- layout/style/nsCSSKeywordList.h | 4 - layout/style/nsMediaFeatures.cpp | 45 --------- layout/style/nsStyleConsts.h | 6 -- layout/style/test/chrome/chrome.ini | 1 - .../style/test/chrome/test_display_mode.html | 94 ------------------- layout/style/test/test_media_queries.html | 8 -- xpfe/appshell/nsWebShellWindow.cpp | 5 - 15 files changed, 11 insertions(+), 277 deletions(-) delete mode 100644 layout/style/test/chrome/test_display_mode.html diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index 69dde410a57..2c8f91a2c4a 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -309,7 +309,6 @@ GK_ATOM(disableOutputEscaping, "disable-output-escaping") GK_ATOM(disabled, "disabled") GK_ATOM(disablehistory, "disablehistory") GK_ATOM(display, "display") -GK_ATOM(displayMode, "display-mode") GK_ATOM(distinct, "distinct") GK_ATOM(div, "div") GK_ATOM(dl, "dl") diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index c44694261ae..db35c241ba4 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -564,8 +564,7 @@ child: TextureFactoryIdentifier textureFactoryIdentifier, uint64_t layersId, nullable PRenderFrame renderFrame, - bool parentIsActive, - nsSizeMode sizeMode); + bool parentIsActive); async LoadURL(nsCString uri, BrowserConfiguration config, ShowInfo info); @@ -573,14 +572,12 @@ child: async CacheFileDescriptor(nsString path, FileDescriptor fd); - async UpdateDimensions(CSSRect rect, CSSSize size, + async UpdateDimensions(CSSRect rect, CSSSize size, nsSizeMode sizeMode, ScreenOrientationInternal orientation, LayoutDeviceIntPoint chromeDisp) compressall; async UpdateFrame(FrameMetrics frame); - async SizeModeChanged(nsSizeMode sizeMode); - // The following methods correspond to functions on the GeckoContentController // interface in gfx/layers/apz/public/GeckoContentController.h. Refer to documentation // in that file for these functions. diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 5f828055306..a002f707a8f 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -1448,7 +1448,7 @@ TabChild::DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier, PRenderFrameChild* aRenderFrame, const ShowInfo& aShowInfo) { RecvShow(ScreenIntSize(0, 0), aShowInfo, aTextureFactoryIdentifier, - aLayersId, aRenderFrame, mParentIsActive, nsSizeMode_Normal); + aLayersId, aRenderFrame, mParentIsActive); mDidFakeShow = true; } @@ -1560,12 +1560,10 @@ TabChild::RecvShow(const ScreenIntSize& aSize, const TextureFactoryIdentifier& aTextureFactoryIdentifier, const uint64_t& aLayersId, PRenderFrameChild* aRenderFrame, - const bool& aParentIsActive, - const nsSizeMode& aSizeMode) + const bool& aParentIsActive) { MOZ_ASSERT((!mDidFakeShow && aRenderFrame) || (mDidFakeShow && !aRenderFrame)); - mPuppetWidget->SetSizeMode(aSizeMode); if (mDidFakeShow) { ApplyShowInfo(aInfo); RecvParentActivated(aParentIsActive); @@ -1601,6 +1599,7 @@ TabChild::RecvShow(const ScreenIntSize& aSize, bool TabChild::RecvUpdateDimensions(const CSSRect& rect, const CSSSize& size, + const nsSizeMode& sizeMode, const ScreenOrientationInternal& orientation, const LayoutDeviceIntPoint& chromeDisp) { @@ -1627,6 +1626,7 @@ TabChild::RecvUpdateDimensions(const CSSRect& rect, const CSSSize& size, baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height, true); + mPuppetWidget->SetSizeMode(sizeMode); mPuppetWidget->Resize(screenRect.x + chromeDisp.x, screenRect.y + chromeDisp.y, screenSize.width, screenSize.height, true); @@ -1634,22 +1634,6 @@ TabChild::RecvUpdateDimensions(const CSSRect& rect, const CSSSize& size, return true; } -bool -TabChild::RecvSizeModeChanged(const nsSizeMode& aSizeMode) -{ - mPuppetWidget->SetSizeMode(aSizeMode); - nsCOMPtr document(GetDocument()); - nsCOMPtr presShell = document->GetShell(); - if (presShell) { - nsPresContext* presContext = presShell->GetPresContext(); - if (presContext) { - presContext->MediaFeatureValuesChangedAllDocuments(eRestyle_Subtree, - NS_STYLE_HINT_REFLOW); - } - } - return true; -} - bool TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics) { diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index 08dfb703079..42af6977f05 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -323,16 +323,14 @@ public: const TextureFactoryIdentifier& aTextureFactoryIdentifier, const uint64_t& aLayersId, PRenderFrameChild* aRenderFrame, - const bool& aParentIsActive, - const nsSizeMode& aSizeMode) override; + const bool& aParentIsActive) override; virtual bool RecvUpdateDimensions(const CSSRect& aRect, const CSSSize& aSize, + const nsSizeMode& aSizeMode, const ScreenOrientationInternal& aOrientation, const LayoutDeviceIntPoint& aChromeDisp) override; - virtual bool - RecvSizeModeChanged(const nsSizeMode& aSizeMode) override; virtual bool RecvUpdateFrame(const layers::FrameMetrics& aFrameMetrics) override; diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 501afec7ab5..3b0928980d4 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -279,7 +279,6 @@ TabParent::TabParent(nsIContentParent* aManager, , mDPI(0) , mDefaultScale(0) , mUpdatedDimensions(false) - , mSizeMode(nsSizeMode_Normal) , mManager(aManager) , mDocShellIsActive(false) , mMarkedDestroying(false) @@ -895,14 +894,8 @@ TabParent::Show(const ScreenIntSize& size, bool aParentIsActive) } } - nsCOMPtr container = mFrameElement->OwnerDoc()->GetContainer(); - nsCOMPtr baseWindow = do_QueryInterface(container); - nsCOMPtr mainWidget; - baseWindow->GetMainWidget(getter_AddRefs(mainWidget)); - mSizeMode = mainWidget ? mainWidget->SizeMode() : nsSizeMode_Normal; - Unused << SendShow(size, GetShowInfo(), textureFactoryIdentifier, - layersId, renderFrame, aParentIsActive, mSizeMode); + layersId, renderFrame, aParentIsActive); } bool @@ -913,6 +906,7 @@ TabParent::RecvSetDimensions(const uint32_t& aFlags, MOZ_ASSERT(!(aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER), "We should never see DIM_FLAGS_SIZE_INNER here!"); + nsCOMPtr widget = GetWidget(); NS_ENSURE_TRUE(mFrameElement, true); nsCOMPtr docShell = mFrameElement->OwnerDoc()->GetDocShell(); NS_ENSURE_TRUE(docShell, true); @@ -996,19 +990,11 @@ TabParent::UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size) CSSRect unscaledRect = devicePixelRect / widgetScale; CSSSize unscaledSize = devicePixelSize / widgetScale; Unused << SendUpdateDimensions(unscaledRect, unscaledSize, + widget->SizeMode(), orientation, chromeOffset); } } -void -TabParent::SizeModeChanged(const nsSizeMode& aSizeMode) -{ - if (!mIsDestroyed && aSizeMode != mSizeMode) { - mSizeMode = aSizeMode; - Unused << SendSizeModeChanged(aSizeMode); - } -} - void TabParent::UpdateFrame(const FrameMetrics& aFrameMetrics) { diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 29f2332c94b..080ff547c29 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -365,8 +365,6 @@ public: void UpdateDimensions(const nsIntRect& aRect, const ScreenIntSize& aSize); - void SizeModeChanged(const nsSizeMode& aSizeMode); - void UpdateFrame(const layers::FrameMetrics& aFrameMetrics); void UIResolutionChanged(); @@ -672,7 +670,6 @@ protected: float mDPI; CSSToLayoutDeviceScale mDefaultScale; bool mUpdatedDimensions; - nsSizeMode mSizeMode; LayoutDeviceIntPoint mChromeOffset; private: diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 50ebea7c8d5..8bedc64f72f 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -2045,39 +2045,6 @@ nsPresContext::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint, RestyleManager()->PostRebuildAllStyleDataEvent(aExtraHint, aRestyleHint); } -struct MediaFeatureHints -{ - nsRestyleHint restyleHint; - nsChangeHint changeHint; -}; - -static bool -MediaFeatureValuesChangedAllDocumentsCallback(nsIDocument* aDocument, void* aHints) -{ - MediaFeatureHints* hints = static_cast(aHints); - if (nsIPresShell* shell = aDocument->GetShell()) { - if (nsPresContext* pc = shell->GetPresContext()) { - pc->MediaFeatureValuesChangedAllDocuments(hints->restyleHint, - hints->changeHint); - } - } - return true; -} - -void -nsPresContext::MediaFeatureValuesChangedAllDocuments(nsRestyleHint aRestyleHint, - nsChangeHint aChangeHint) -{ - MediaFeatureValuesChanged(aRestyleHint, aChangeHint); - MediaFeatureHints hints = { - aRestyleHint, - aChangeHint - }; - - mDocument->EnumerateSubDocuments(MediaFeatureValuesChangedAllDocumentsCallback, - &hints); -} - void nsPresContext::MediaFeatureValuesChanged(nsRestyleHint aRestyleHint, nsChangeHint aChangeHint) @@ -2175,21 +2142,6 @@ nsPresContext::HandleMediaFeatureValuesChangedEvent() } } -static void -NotifyTabSizeModeChanged(TabParent* aTab, void* aArg) -{ - nsSizeMode* count = static_cast(aArg); - aTab->SizeModeChanged(*count); -} - -void -nsPresContext::SizeModeChanged(nsSizeMode aSizeMode) -{ - nsContentUtils::CallOnAllRemoteChildren(mDocument->GetWindow(), - NotifyTabSizeModeChanged, &aSizeMode); - MediaFeatureValuesChangedAllDocuments(eRestyle_Subtree, NS_STYLE_HINT_REFLOW); -} - nsCompatibility nsPresContext::CompatibilityMode() const { diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index 813a0466a38..d86246ce365 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -21,7 +21,6 @@ #include "nsIObserver.h" #include "nsITimer.h" #include "nsCRT.h" -#include "nsIWidgetListener.h" #include "FramePropertyTable.h" #include "nsGkAtoms.h" #include "nsCycleCollectionParticipant.h" @@ -279,14 +278,6 @@ public: */ void MediaFeatureValuesChanged(nsRestyleHint aRestyleHint, nsChangeHint aChangeHint = nsChangeHint(0)); - /** - * Calls MediaFeatureValuesChanged for this pres context and all descendant - * subdocuments that have a pres context. This should be used for media - * features that must be updated in all subdocuments e.g. display-mode. - */ - void MediaFeatureValuesChangedAllDocuments(nsRestyleHint aRestyleHint, - nsChangeHint aChangeHint = nsChangeHint(0)); - void PostMediaFeatureValuesChangedEvent(); void HandleMediaFeatureValuesChangedEvent(); void FlushPendingMediaFeatureValuesChanged() { @@ -294,13 +285,6 @@ public: MediaFeatureValuesChanged(nsRestyleHint(0)); } - /** - * Updates the size mode on all remote children and recursively notifies this - * document and all subdocuments (including remote children) that a media - * feature value has changed. - */ - void SizeModeChanged(nsSizeMode aSizeMode); - /** * Access compatibility mode for this context. This is the same as * our document's compatibility mode. diff --git a/layout/style/nsCSSKeywordList.h b/layout/style/nsCSSKeywordList.h index fbde7c5b83b..86d716e7f4b 100644 --- a/layout/style/nsCSSKeywordList.h +++ b/layout/style/nsCSSKeywordList.h @@ -169,7 +169,6 @@ CSS_KEY(bottom-outside, bottom_outside) CSS_KEY(break-all, break_all) CSS_KEY(break-word, break_word) CSS_KEY(brightness, brightness) -CSS_KEY(browser, browser) CSS_KEY(bullets, bullets) CSS_KEY(button, button) CSS_KEY(buttonface, buttonface) @@ -281,7 +280,6 @@ CSS_KEY(forwards, forwards) CSS_KEY(fraktur, fraktur) CSS_KEY(from-image, from_image) CSS_KEY(full-width, full_width) -CSS_KEY(fullscreen, fullscreen) CSS_KEY(grab, grab) CSS_KEY(grabbing, grabbing) CSS_KEY(grad, grad) @@ -537,7 +535,6 @@ CSS_KEY(square, square) CSS_KEY(stacked-fractions, stacked_fractions) CSS_KEY(start, start) CSS_KEY(static, static) -CSS_KEY(standalone, standalone) CSS_KEY(status-bar, status_bar) CSS_KEY(step-end, step_end) CSS_KEY(step-start, step_start) @@ -710,7 +707,6 @@ CSS_KEY(menulist-text, menulist_text) CSS_KEY(menulist-textfield, menulist_textfield) CSS_KEY(meterbar, meterbar) CSS_KEY(meterchunk, meterchunk) -CSS_KEY(minimal-ui, minimal_ui) CSS_KEY(range, range) CSS_KEY(range-thumb, range_thumb) CSS_KEY(sans-serif, sans_serif) diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp index 6cc37bd6848..22966c192b8 100644 --- a/layout/style/nsMediaFeatures.cpp +++ b/layout/style/nsMediaFeatures.cpp @@ -17,7 +17,6 @@ #endif #include "nsCSSRuleProcessor.h" #include "nsDeviceContext.h" -#include "nsIBaseWindow.h" #include "nsIDocument.h" using namespace mozilla; @@ -34,14 +33,6 @@ static const nsCSSProps::KTableEntry kScanKeywords[] = { { eCSSKeyword_UNKNOWN, -1 } }; -static const nsCSSProps::KTableEntry kDisplayModeKeywords[] = { - { eCSSKeyword_browser, NS_STYLE_DISPLAY_MODE_BROWSER }, - { eCSSKeyword_minimal_ui, NS_STYLE_DISPLAY_MODE_MINIMAL_UI }, - { eCSSKeyword_standalone, NS_STYLE_DISPLAY_MODE_STANDALONE }, - { eCSSKeyword_fullscreen, NS_STYLE_DISPLAY_MODE_FULLSCREEN }, - { eCSSKeyword_UNKNOWN, -1 } -}; - #ifdef XP_WIN struct WindowsThemeName { LookAndFeel::WindowsTheme id; @@ -310,34 +301,6 @@ GetScan(nsPresContext* aPresContext, const nsMediaFeature*, return NS_OK; } -static nsresult -GetDisplayMode(nsPresContext* aPresContext, const nsMediaFeature*, - nsCSSValue& aResult) -{ - nsCOMPtr container = aPresContext->GetRootPresContext()-> - Document()->GetContainer(); - nsCOMPtr baseWindow = do_QueryInterface(container); - if (!baseWindow) { - aResult.SetIntValue(NS_STYLE_DISPLAY_MODE_BROWSER, eCSSUnit_Enumerated); - return NS_OK; - } - nsCOMPtr mainWidget; - baseWindow->GetMainWidget(getter_AddRefs(mainWidget)); - int32_t displayMode; - nsSizeMode mode = mainWidget ? mainWidget->SizeMode() : nsSizeMode_Normal; - switch (mode) { - case nsSizeMode_Fullscreen: - displayMode = NS_STYLE_DISPLAY_MODE_FULLSCREEN; - break; - default: - displayMode = NS_STYLE_DISPLAY_MODE_BROWSER; - break; - } - - aResult.SetIntValue(displayMode, eCSSUnit_Enumerated); - return NS_OK; -} - static nsresult GetGrid(nsPresContext* aPresContext, const nsMediaFeature*, nsCSSValue& aResult) @@ -567,14 +530,6 @@ nsMediaFeatures::features[] = { { nullptr }, GetGrid }, - { - &nsGkAtoms::displayMode, - nsMediaFeature::eMinMaxNotAllowed, - nsMediaFeature::eEnumerated, - nsMediaFeature::eNoRequirements, - { kDisplayModeKeywords }, - GetDisplayMode - }, // Webkit extensions that we support for de-facto web compatibility // -webkit-{min|max}-device-pixel-ratio (controlled with its own pref): diff --git a/layout/style/nsStyleConsts.h b/layout/style/nsStyleConsts.h index 74b33387a24..ffa27adf5d5 100644 --- a/layout/style/nsStyleConsts.h +++ b/layout/style/nsStyleConsts.h @@ -1205,12 +1205,6 @@ enum class FillMode : uint32_t; #define NS_STYLE_SCAN_PROGRESSIVE 0 #define NS_STYLE_SCAN_INTERLACE 1 -// display-mode -#define NS_STYLE_DISPLAY_MODE_BROWSER 0 -#define NS_STYLE_DISPLAY_MODE_MINIMAL_UI 1 -#define NS_STYLE_DISPLAY_MODE_STANDALONE 2 -#define NS_STYLE_DISPLAY_MODE_FULLSCREEN 3 - } // namespace mozilla #endif /* nsStyleConsts_h___ */ diff --git a/layout/style/test/chrome/chrome.ini b/layout/style/test/chrome/chrome.ini index 37f498d9c7b..6064cce12b2 100644 --- a/layout/style/test/chrome/chrome.ini +++ b/layout/style/test/chrome/chrome.ini @@ -16,7 +16,6 @@ support-files = [test_bug1157097.html] [test_bug1160724.xul] [test_bug535806.xul] -[test_display_mode.html] [test_hover.html] skip-if = buildapp == 'mulet' [test_moz_document_rules.html] diff --git a/layout/style/test/chrome/test_display_mode.html b/layout/style/test/chrome/test_display_mode.html deleted file mode 100644 index 244eefea272..00000000000 --- a/layout/style/test/chrome/test_display_mode.html +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - Test for Display Mode - - - - - - - - -Mozilla Bug 1104916 - -

- -
-
- - diff --git a/layout/style/test/test_media_queries.html b/layout/style/test/test_media_queries.html index 85c7dca8b2e..5f900d79840 100644 --- a/layout/style/test/test_media_queries.html +++ b/layout/style/test/test_media_queries.html @@ -253,14 +253,6 @@ function run() { expression_should_not_be_parseable("max-" + feature); } - var mediatypes = ["browser", "minimal-ui", "standalone", "fullscreen"]; - - mediatypes.forEach(function(type) { - expression_should_be_parseable("display-mode: " + type); - }); - - expression_should_not_be_parseable("display-mode: invalid") - var content_div = document.getElementById("content"); content_div.style.font = "initial"; var em_size = diff --git a/xpfe/appshell/nsWebShellWindow.cpp b/xpfe/appshell/nsWebShellWindow.cpp index b8c102e2ab8..4aa96857f87 100644 --- a/xpfe/appshell/nsWebShellWindow.cpp +++ b/xpfe/appshell/nsWebShellWindow.cpp @@ -365,11 +365,6 @@ nsWebShellWindow::SizeModeChanged(nsSizeMode sizeMode) ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("sizemodechange")); } - nsIPresShell* presShell = GetPresShell(); - if (presShell) { - presShell->GetPresContext()->SizeModeChanged(sizeMode); - } - // Note the current implementation of SetSizeMode just stores // the new state; it doesn't actually resize. So here we store // the state and pass the event on to the OS. The day is coming From 71704ffd8e7b1bc551ec076cd5490f51ec32b0f0 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Fri, 5 Feb 2016 12:24:54 -0800 Subject: [PATCH 71/72] Bug 1245950: Followup to null check before asserting. r=me CLOSED TREE --- dom/base/nsDocument.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 9d6dfa16729..6f48a316103 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -10655,7 +10655,7 @@ nsIDocument::CreateTouch(nsGlobalWindow* aView, float aRotationAngle, float aForce) { - MOZ_ASSERT(aView->IsInnerWindow()); + MOZ_ASSERT_IF(aView, aView->IsInnerWindow()); RefPtr touch = new Touch(aTarget, aIdentifier, aPageX, aPageY, From b5d55205e7f59c34e5c47b5388210e7e27ce0268 Mon Sep 17 00:00:00 2001 From: Nick Alexander Date: Fri, 5 Feb 2016 16:35:45 -0800 Subject: [PATCH 72/72] Backed out changeset 10dfe5e3ded1 (bug 1242213), a=permaorange --- mobile/android/base/AndroidManifest.xml.in | 2 +- mobile/android/base/Makefile.in | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mobile/android/base/AndroidManifest.xml.in b/mobile/android/base/AndroidManifest.xml.in index b4c9f0afae1..b361a4b7946 100644 --- a/mobile/android/base/AndroidManifest.xml.in +++ b/mobile/android/base/AndroidManifest.xml.in @@ -1,7 +1,7 @@ #filter substitution