Merge inbound to mozilla-central. a=merge

This commit is contained in:
Brindusan Cristian 2018-12-18 19:34:11 +02:00
commit df66fd18a1
29 changed files with 545 additions and 178 deletions

View File

@ -111,9 +111,13 @@ void XULListboxAccessible::Value(nsString& aValue) const {
RefPtr<Element> element;
select->GetSelectedItem(getter_AddRefs(element));
nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem =
element->AsXULSelectControlItem();
if (selectedItem) selectedItem->GetLabel(aValue);
if (element) {
nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem =
element->AsXULSelectControlItem();
if (selectedItem) {
selectedItem->GetLabel(aValue);
}
}
}
}
@ -176,6 +180,9 @@ bool XULListboxAccessible::IsRowSelected(uint32_t aRowIdx) {
RefPtr<Element> element;
nsresult rv = control->GetItemAtIndex(aRowIdx, getter_AddRefs(element));
NS_ENSURE_SUCCESS(rv, false);
if (!element) {
return false;
}
nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
element->AsXULSelectControlItem();
@ -337,6 +344,9 @@ void XULListboxAccessible::SelectRow(uint32_t aRowIdx) {
RefPtr<Element> item;
control->GetItemAtIndex(aRowIdx, getter_AddRefs(item));
if (!item) {
return;
}
nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm =
item->AsXULSelectControlItem();
@ -351,6 +361,9 @@ void XULListboxAccessible::UnselectRow(uint32_t aRowIdx) {
RefPtr<Element> item;
control->GetItemAtIndex(aRowIdx, getter_AddRefs(item));
if (!item) {
return;
}
nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm =
item->AsXULSelectControlItem();

View File

@ -57,9 +57,6 @@ method PushSubscription.unsubscribe
// window.sidebar
attribute Window.sidebar
// External interface
method External.AddSearchProvider
// AppCache API
method OfflineResourceList.swapCache
method OfflineResourceList.update

View File

@ -50,3 +50,4 @@ DEPRECATED_OPERATION(CreateImageBitmapCanvasRenderingContext2D)
DEPRECATED_OPERATION(MozRequestFullScreenDeprecatedPrefix)
DEPRECATED_OPERATION(MozfullscreenchangeDeprecatedPrefix)
DEPRECATED_OPERATION(MozfullscreenerrorDeprecatedPrefix)
DEPRECATED_OPERATION(External_AddSearchProvider)

View File

@ -368,3 +368,5 @@ MozRequestFullScreenDeprecatedPrefixWarning=mozRequestFullScreen() is deprecated
MozfullscreenchangeDeprecatedPrefixWarning=onmozfullscreenchange is deprecated.
# LOCALIZATION NOTE (MozfullscreenerrorDeprecatedPrefixWarning): Do not translate onmozfullscreenerror.
MozfullscreenerrorDeprecatedPrefixWarning=onmozfullscreenerror is deprecated.
# LOCALIZATION NOTE(External_AddSearchProviderWarning): Do not translate AddSearchProvider.
External_AddSearchProviderWarning=AddSearchProvider is deprecated.

View File

@ -7,7 +7,7 @@
[NoInterfaceObject, JSImplementation="@mozilla.org/sidebar;1"]
interface External
{
[UseCounter]
[Deprecated="External_AddSearchProvider"]
void AddSearchProvider(DOMString aDescriptionURL);
void IsSearchProviderInstalled();
};

View File

@ -2991,6 +2991,13 @@ void WorkerPrivate::ShutdownGCTimers() {
bool WorkerPrivate::InterruptCallback(JSContext* aCx) {
MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible, data);
// If we are here it's because a WorkerControlRunnable has been dispatched.
// The runnable could be processed here or it could have already been
// processed by a sync event loop.
// The most important thing this method must do, is to decide if the JS
// execution should continue or not. If the runnable returns an error or if
// the worker status is >= Canceling, we should stop the JS execution.
MOZ_ASSERT(!JS_IsExceptionPending(aCx));
bool mayContinue = true;
@ -3004,9 +3011,17 @@ bool WorkerPrivate::InterruptCallback(JSContext* aCx) {
}
bool mayFreeze = data->mFrozen;
if (mayFreeze) {
{
MutexAutoLock lock(mMutex);
mayFreeze = mStatus <= Running;
if (mayFreeze) {
mayFreeze = mStatus <= Running;
}
if (mStatus >= Canceling) {
mayContinue = false;
}
}
if (!mayContinue || !mayFreeze) {
@ -3510,10 +3525,11 @@ bool WorkerPrivate::RunCurrentSyncLoop() {
auto result = ProcessAllControlRunnablesLocked();
if (result != ProcessAllControlRunnablesResult::Nothing) {
// XXXkhuey how should we handle Abort here? See Bug 1003730.
// The state of the world may have changed. Recheck it.
normalRunnablesPending = NS_HasPendingEvents(mThread);
// The state of the world may have changed. Recheck it if we need to
// continue.
normalRunnablesPending =
result == ProcessAllControlRunnablesResult::MayContinue &&
NS_HasPendingEvents(mThread);
// NB: If we processed a NotifyRunnable, we might have run
// non-control runnables, one of which may have shut down the

View File

@ -0,0 +1,12 @@
<html>
<head>
<script>
try { o1 = window.getSelection() } catch (e) {}
try { o2 = document.createRange() } catch (e) {}
try { document.head.replaceWith('', document.documentElement) } catch (e) {}
try { o1.addRange(o2) } catch (e) {}
try { document.designMode = 'on' } catch (e) {}
try { o1.focusNode.execCommand('justifyleft', false, null) } catch (e) {}
</script>
</head>
</html>

View File

@ -101,6 +101,7 @@ load 1423767.html
needs-focus load 1423776.html
needs-focus load 1424450.html
load 1425091.html
load 1441619.html
load 1443664.html
skip-if(Android) needs-focus load 1444630.html
load 1446451.html

View File

@ -16,6 +16,7 @@ namespace mozilla {
using namespace mozilla::intl;
nsCString* DateTimeFormat::mLocale = nullptr;
nsDataHashtable<nsCStringHashKey, UDateFormat*>* DateTimeFormat::mFormatCache;
/*static*/ nsresult DateTimeFormat::Initialize() {
if (mLocale) {
@ -74,142 +75,170 @@ nsCString* DateTimeFormat::mLocale = nullptr;
return rv;
}
// Get the date style for the formatter.
nsAutoString skeletonDate;
nsAutoString patternDate;
bool haveSkeleton = true;
switch (aDateFormatSelector) {
case kDateFormatLong:
rv = OSPreferences::GetInstance()->GetDateTimePattern(
mozIOSPreferences::dateTimeFormatStyleLong,
mozIOSPreferences::dateTimeFormatStyleNone,
nsDependentCString(mLocale->get()), patternDate);
NS_ENSURE_SUCCESS(rv, rv);
haveSkeleton = false;
break;
case kDateFormatShort:
rv = OSPreferences::GetInstance()->GetDateTimePattern(
mozIOSPreferences::dateTimeFormatStyleShort,
mozIOSPreferences::dateTimeFormatStyleNone,
nsDependentCString(mLocale->get()), patternDate);
NS_ENSURE_SUCCESS(rv, rv);
haveSkeleton = false;
break;
case kDateFormatYearMonth:
skeletonDate.AssignLiteral("yyyyMM");
break;
case kDateFormatYearMonthLong:
skeletonDate.AssignLiteral("yyyyMMMM");
break;
case kDateFormatMonthLong:
skeletonDate.AssignLiteral("MMMM");
break;
case kDateFormatWeekday:
skeletonDate.AssignLiteral("EEE");
break;
case kDateFormatNone:
haveSkeleton = false;
break;
default:
NS_ERROR("Unknown nsDateFormatSelector");
return NS_ERROR_ILLEGAL_VALUE;
UErrorCode status = U_ZERO_ERROR;
nsAutoCString key;
key.AppendInt((int)aDateFormatSelector);
key.Append(':');
key.AppendInt((int)aTimeFormatSelector);
if (aTimeParameters) {
key.Append(':');
key.AppendInt(aTimeParameters->tp_gmt_offset);
key.Append(':');
key.AppendInt(aTimeParameters->tp_dst_offset);
}
UErrorCode status = U_ZERO_ERROR;
if (haveSkeleton) {
// Get pattern for skeleton.
UDateTimePatternGenerator* patternGenerator =
udatpg_open(mLocale->get(), &status);
if (U_SUCCESS(status)) {
int32_t patternLength;
patternDate.SetLength(DATETIME_FORMAT_INITIAL_LEN);
patternLength = udatpg_getBestPattern(
patternGenerator,
reinterpret_cast<const UChar*>(skeletonDate.BeginReading()),
skeletonDate.Length(),
reinterpret_cast<UChar*>(patternDate.BeginWriting()),
DATETIME_FORMAT_INITIAL_LEN, &status);
patternDate.SetLength(patternLength);
if (mFormatCache && mFormatCache->Count() == kMaxCachedFormats) {
// Don't allow a pathological page to extend the cache unreasonably.
NS_WARNING("flushing UDateFormat cache");
DeleteCache();
}
if (!mFormatCache) {
mFormatCache =
new nsDataHashtable<nsCStringHashKey, UDateFormat*>(kMaxCachedFormats);
}
if (status == U_BUFFER_OVERFLOW_ERROR) {
status = U_ZERO_ERROR;
udatpg_getBestPattern(
UDateFormat*& dateTimeFormat = mFormatCache->GetOrInsert(key);
if (!dateTimeFormat) {
// We didn't have a cached formatter for this key, so create one.
// Get the date style for the formatter.
nsAutoString skeletonDate;
nsAutoString patternDate;
bool haveSkeleton = true;
switch (aDateFormatSelector) {
case kDateFormatLong:
rv = OSPreferences::GetInstance()->GetDateTimePattern(
mozIOSPreferences::dateTimeFormatStyleLong,
mozIOSPreferences::dateTimeFormatStyleNone,
nsDependentCString(mLocale->get()), patternDate);
NS_ENSURE_SUCCESS(rv, rv);
haveSkeleton = false;
break;
case kDateFormatShort:
rv = OSPreferences::GetInstance()->GetDateTimePattern(
mozIOSPreferences::dateTimeFormatStyleShort,
mozIOSPreferences::dateTimeFormatStyleNone,
nsDependentCString(mLocale->get()), patternDate);
NS_ENSURE_SUCCESS(rv, rv);
haveSkeleton = false;
break;
case kDateFormatYearMonth:
skeletonDate.AssignLiteral("yyyyMM");
break;
case kDateFormatYearMonthLong:
skeletonDate.AssignLiteral("yyyyMMMM");
break;
case kDateFormatMonthLong:
skeletonDate.AssignLiteral("MMMM");
break;
case kDateFormatWeekday:
skeletonDate.AssignLiteral("EEE");
break;
case kDateFormatNone:
haveSkeleton = false;
break;
default:
NS_ERROR("Unknown nsDateFormatSelector");
return NS_ERROR_ILLEGAL_VALUE;
}
if (haveSkeleton) {
// Get pattern for skeleton.
UDateTimePatternGenerator* patternGenerator =
udatpg_open(mLocale->get(), &status);
if (U_SUCCESS(status)) {
int32_t patternLength;
patternDate.SetLength(DATETIME_FORMAT_INITIAL_LEN);
patternLength = udatpg_getBestPattern(
patternGenerator,
reinterpret_cast<const UChar*>(skeletonDate.BeginReading()),
skeletonDate.Length(),
reinterpret_cast<UChar*>(patternDate.BeginWriting()), patternLength,
&status);
reinterpret_cast<UChar*>(patternDate.BeginWriting()),
DATETIME_FORMAT_INITIAL_LEN, &status);
patternDate.SetLength(patternLength);
if (status == U_BUFFER_OVERFLOW_ERROR) {
status = U_ZERO_ERROR;
udatpg_getBestPattern(
patternGenerator,
reinterpret_cast<const UChar*>(skeletonDate.BeginReading()),
skeletonDate.Length(),
reinterpret_cast<UChar*>(patternDate.BeginWriting()),
patternLength, &status);
}
}
udatpg_close(patternGenerator);
}
// Get the time style for the formatter.
nsAutoString patternTime;
switch (aTimeFormatSelector) {
case kTimeFormatSeconds:
rv = OSPreferences::GetInstance()->GetDateTimePattern(
mozIOSPreferences::dateTimeFormatStyleNone,
mozIOSPreferences::dateTimeFormatStyleLong,
nsDependentCString(mLocale->get()), patternTime);
NS_ENSURE_SUCCESS(rv, rv);
break;
case kTimeFormatNoSeconds:
rv = OSPreferences::GetInstance()->GetDateTimePattern(
mozIOSPreferences::dateTimeFormatStyleNone,
mozIOSPreferences::dateTimeFormatStyleShort,
nsDependentCString(mLocale->get()), patternTime);
NS_ENSURE_SUCCESS(rv, rv);
break;
case kTimeFormatNone:
break;
default:
NS_ERROR("Unknown nsTimeFormatSelector");
return NS_ERROR_ILLEGAL_VALUE;
}
nsAutoString pattern;
if (patternTime.Length() == 0) {
pattern.Assign(patternDate);
} else if (patternDate.Length() == 0) {
pattern.Assign(patternTime);
} else {
OSPreferences::GetDateTimeConnectorPattern(
nsDependentCString(mLocale->get()), pattern);
int32_t index = pattern.Find("{1}");
if (index != kNotFound) pattern.Replace(index, 3, patternDate);
index = pattern.Find("{0}");
if (index != kNotFound) pattern.Replace(index, 3, patternTime);
}
// Generate date/time string.
nsAutoString timeZoneID(u"GMT");
if (aTimeParameters) {
int32_t totalOffsetMinutes =
(aTimeParameters->tp_gmt_offset + aTimeParameters->tp_dst_offset) /
60;
if (totalOffsetMinutes != 0) {
char sign = totalOffsetMinutes < 0 ? '-' : '+';
int32_t hours = abs(totalOffsetMinutes) / 60;
int32_t minutes = abs(totalOffsetMinutes) % 60;
timeZoneID.AppendPrintf("%c%02d:%02d", sign, hours, minutes);
}
}
udatpg_close(patternGenerator);
}
// Get the time style for the formatter.
nsAutoString patternTime;
switch (aTimeFormatSelector) {
case kTimeFormatSeconds:
rv = OSPreferences::GetInstance()->GetDateTimePattern(
mozIOSPreferences::dateTimeFormatStyleNone,
mozIOSPreferences::dateTimeFormatStyleLong,
nsDependentCString(mLocale->get()), patternTime);
NS_ENSURE_SUCCESS(rv, rv);
break;
case kTimeFormatNoSeconds:
rv = OSPreferences::GetInstance()->GetDateTimePattern(
mozIOSPreferences::dateTimeFormatStyleNone,
mozIOSPreferences::dateTimeFormatStyleShort,
nsDependentCString(mLocale->get()), patternTime);
NS_ENSURE_SUCCESS(rv, rv);
break;
case kTimeFormatNone:
break;
default:
NS_ERROR("Unknown nsTimeFormatSelector");
return NS_ERROR_ILLEGAL_VALUE;
}
nsAutoString pattern;
if (patternTime.Length() == 0) {
pattern.Assign(patternDate);
} else if (patternDate.Length() == 0) {
pattern.Assign(patternTime);
} else {
OSPreferences::GetDateTimeConnectorPattern(
nsDependentCString(mLocale->get()), pattern);
int32_t index = pattern.Find("{1}");
if (index != kNotFound) pattern.Replace(index, 3, patternDate);
index = pattern.Find("{0}");
if (index != kNotFound) pattern.Replace(index, 3, patternTime);
}
// Generate date/time string.
nsAutoString timeZoneID(u"GMT");
if (aTimeParameters) {
int32_t totalOffsetMinutes =
(aTimeParameters->tp_gmt_offset + aTimeParameters->tp_dst_offset) / 60;
if (totalOffsetMinutes != 0) {
char sign = totalOffsetMinutes < 0 ? '-' : '+';
int32_t hours = abs(totalOffsetMinutes) / 60;
int32_t minutes = abs(totalOffsetMinutes) % 60;
timeZoneID.AppendPrintf("%c%02d:%02d", sign, hours, minutes);
if (aTimeParameters) {
dateTimeFormat =
udat_open(UDAT_PATTERN, UDAT_PATTERN, mLocale->get(),
reinterpret_cast<const UChar*>(timeZoneID.BeginReading()),
timeZoneID.Length(),
reinterpret_cast<const UChar*>(pattern.BeginReading()),
pattern.Length(), &status);
} else {
dateTimeFormat =
udat_open(UDAT_PATTERN, UDAT_PATTERN, mLocale->get(), nullptr, -1,
reinterpret_cast<const UChar*>(pattern.BeginReading()),
pattern.Length(), &status);
}
}
UDateFormat* dateTimeFormat;
if (aTimeParameters) {
dateTimeFormat =
udat_open(UDAT_PATTERN, UDAT_PATTERN, mLocale->get(),
reinterpret_cast<const UChar*>(timeZoneID.BeginReading()),
timeZoneID.Length(),
reinterpret_cast<const UChar*>(pattern.BeginReading()),
pattern.Length(), &status);
} else {
dateTimeFormat =
udat_open(UDAT_PATTERN, UDAT_PATTERN, mLocale->get(), nullptr, -1,
reinterpret_cast<const UChar*>(pattern.BeginReading()),
pattern.Length(), &status);
}
if (U_SUCCESS(status) && dateTimeFormat) {
aStringOut.SetLength(DATETIME_FORMAT_INITIAL_LEN);
dateTimeLen =
@ -230,14 +259,21 @@ nsCString* DateTimeFormat::mLocale = nullptr;
rv = NS_ERROR_FAILURE;
}
if (dateTimeFormat) {
udat_close(dateTimeFormat);
}
return rv;
}
/*static*/ void DateTimeFormat::DeleteCache() {
if (mFormatCache) {
for (auto i = mFormatCache->Iter(); !i.Done(); i.Next()) {
udat_close(i.Data());
}
delete mFormatCache;
mFormatCache = nullptr;
}
}
/*static*/ void DateTimeFormat::Shutdown() {
DeleteCache();
if (mLocale) {
delete mLocale;
}

View File

@ -9,6 +9,7 @@
#include <time.h>
#include "gtest/MozGtestFriend.h"
#include "nsDataHashtable.h"
#include "nsString.h"
#include "prtime.h"
#include "unicode/udat.h"
@ -55,6 +56,8 @@ class DateTimeFormat {
DateTimeFormat() = delete;
static nsresult Initialize();
static void DeleteCache();
static const size_t kMaxCachedFormats = 15;
FRIEND_TEST(DateTimeFormat, FormatPRExplodedTime);
FRIEND_TEST(DateTimeFormat, DateFormatSelectors);
@ -69,6 +72,7 @@ class DateTimeFormat {
const PRTimeParameters* aTimeParameters, nsAString& aStringOut);
static nsCString* mLocale;
static nsDataHashtable<nsCStringHashKey, UDateFormat*>* mFormatCache;
};
} // namespace mozilla

View File

@ -333,11 +333,34 @@ OSPreferences::GetDateTimePattern(int32_t aDateFormatStyle,
return NS_OK;
}
if (!ReadDateTimePattern(dateStyle, timeStyle, aLocale, aRetVal)) {
if (!GetDateTimePatternForStyle(dateStyle, timeStyle, aLocale, aRetVal)) {
// Create a cache key from the locale + style options
nsAutoCString key(aLocale);
key.Append(':');
key.AppendInt(aDateFormatStyle);
key.Append(':');
key.AppendInt(aTimeFormatStyle);
nsString pattern;
if (mPatternCache.Get(key, &pattern)) {
aRetVal = pattern;
return NS_OK;
}
if (!ReadDateTimePattern(dateStyle, timeStyle, aLocale, pattern)) {
if (!GetDateTimePatternForStyle(dateStyle, timeStyle, aLocale, pattern)) {
return NS_ERROR_FAILURE;
}
}
if (mPatternCache.Count() == kMaxCachedPatterns) {
// Don't allow unlimited cache growth; just throw it away in the case of
// pathological behavior where a page keeps requesting different formats
// and locales.
NS_WARNING("flushing DateTimePattern cache");
mPatternCache.Clear();
}
mPatternCache.Put(key, pattern);
aRetVal = pattern;
return NS_OK;
}

View File

@ -7,6 +7,7 @@
#define mozilla_intl_IntlOSPreferences_h__
#include "mozilla/StaticPtr.h"
#include "nsDataHashtable.h"
#include "nsString.h"
#include "nsTArray.h"
#include "unicode/uloc.h"
@ -97,6 +98,9 @@ class OSPreferences : public mozIOSPreferences {
nsTArray<nsCString> mSystemLocales;
nsTArray<nsCString> mRegionalPrefsLocales;
const size_t kMaxCachedPatterns = 15;
nsDataHashtable<nsCStringHashKey, nsString> mPatternCache;
private:
virtual ~OSPreferences();

View File

@ -65,7 +65,7 @@ JSObject* SymbolObject::initClass(JSContext* cx, Handle<GlobalObject*> global,
WellKnownSymbols* wks = cx->runtime()->wellKnownSymbols;
for (size_t i = 0; i < JS::WellKnownSymbolLimit; i++) {
#ifndef NIGHTLY_BUILD
if (i == SymbolCode::matchAll) {
if (i == static_cast<size_t>(SymbolCode::matchAll)) {
continue;
}
#endif

View File

@ -5133,12 +5133,10 @@ void js::gc::DelayCrossCompartmentGrayMarking(JSObject* src) {
}
void GCRuntime::markIncomingCrossCompartmentPointers(MarkColor color) {
MOZ_ASSERT(color == MarkColor::Black || color == MarkColor::Gray);
static const gcstats::PhaseKind statsPhases[] = {
gcstats::PhaseKind::SWEEP_MARK_INCOMING_BLACK,
gcstats::PhaseKind::SWEEP_MARK_INCOMING_GRAY};
gcstats::AutoPhase ap1(stats(), statsPhases[unsigned(color)]);
gcstats::AutoPhase ap(
stats(),
color == MarkColor::Black ? gcstats::PhaseKind::SWEEP_MARK_INCOMING_BLACK
: gcstats::PhaseKind::SWEEP_MARK_INCOMING_GRAY);
bool unlinkList = color == MarkColor::Gray;
@ -5325,7 +5323,7 @@ IncrementalProgress GCRuntime::markGrayReferencesInCurrentGroup(
}
#endif
return marker.markUntilBudgetExhausted(budget) ? Finished : NotFinished;
return markUntilBudgetExhausted(budget, gcstats::PhaseKind::SWEEP_MARK_GRAY);
}
IncrementalProgress GCRuntime::endMarkingSweepGroup(FreeOp* fop,

View File

@ -3546,7 +3546,7 @@ void UnmarkGrayTracer::onChild(const JS::GCCellPtr& thing) {
// case, push any cells in zones that are currently being marked onto the
// mark stack and they will eventually get marked black.
Zone* zone = tenured.zone();
if (zone->needsIncrementalBarrier()) {
if (zone->isGCMarkingBlackAndGray()) {
if (!cell->isMarkedBlack()) {
Cell* tmp = cell;
TraceManuallyBarrieredGenericPointerEdge(zone->barrierTracer(), &tmp,
@ -3557,7 +3557,6 @@ void UnmarkGrayTracer::onChild(const JS::GCCellPtr& thing) {
return;
}
MOZ_ASSERT(!zone->isGCMarkingBlackAndGray());
if (!tenured.isMarkedGray()) {
return;
}

View File

@ -488,9 +488,6 @@ skip script test262/language/expressions/await/async-generator-interleaved.js
# https://bugzilla.mozilla.org/show_bug.cgi?id=1321616
skip script test262/annexB/built-ins/Function/createdynfn-html-close-comment-params.js
# https://bugzilla.mozilla.org/show_bug.cgi?id=1462741
skip script test262/built-ins/Function/prototype/toString/well-known-intrinsic-object-functions.js
# https://bugzilla.mozilla.org/show_bug.cgi?id=1462745
skip script test262/annexB/language/function-code/block-decl-nested-blocks-with-fun-decl.js

View File

@ -28,6 +28,7 @@ class WptreportHandler(object):
"""
self.formatter.suite_start({
"time": time(),
"run_info": {},
})
def suite_end(self):

View File

@ -1,5 +1,10 @@
// Global functions are configurable in a browser environment.
var functionDeclarationsConfigurable = typeof document !== "undefined";
if (typeof getBuildConfiguration === "undefined") {
var getBuildConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getBuildConfiguration;
}
// Global functions are configurable in a browser environment on nightly.
var functionDeclarationsConfigurable = typeof document !== "undefined" &&
!getBuildConfiguration().release_or_beta;
var o = { f: "string-f" };
with (o) {

View File

@ -0,0 +1,19 @@
<html>
<head><title>Forms2</title></head>
<body>
<form>
<input type="text" id="firstname">
<input type="text" id="lastname">
<input type="text" id="user1" value="foo">
<input type="password" id="pass1" value="foo">
</form>
<iframe id="iframe"></iframe>
<script>
addEventListener("load", function(e) {
if (window.parent === window) {
document.getElementById("iframe").contentWindow.location.href = window.location.href;
}
});
</script>
</body>
</html>

View File

@ -29,6 +29,7 @@ open class BaseSessionTest(noErrorCollector: Boolean = false) {
const val CONTENT_CRASH_URL = "about:crashcontent"
const val DOWNLOAD_HTML_PATH = "/assets/www/download.html"
const val FORMS_HTML_PATH = "/assets/www/forms.html"
const val FORMS2_HTML_PATH = "/assets/www/forms2.html"
const val HELLO_HTML_PATH = "/assets/www/hello.html"
const val HELLO2_HTML_PATH = "/assets/www/hello2.html"
const val INPUTS_PATH = "/assets/www/inputs.html"

View File

@ -335,6 +335,9 @@ class ContentDelegateTest : BaseSessionTest() {
InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS ->
arrayOf(View.AUTOFILL_HINT_EMAIL_ADDRESS)
InputType.TYPE_CLASS_PHONE -> arrayOf(View.AUTOFILL_HINT_PHONE)
InputType.TYPE_CLASS_TEXT or
InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT ->
arrayOf(View.AUTOFILL_HINT_USERNAME)
else -> null
}))
@ -455,6 +458,71 @@ class ContentDelegateTest : BaseSessionTest() {
countAutoFillNodes({ it.isFocused }), equalTo(0))
}
@WithDevToolsAPI
@Test fun autofill_userpass() {
if (Build.VERSION.SDK_INT < 26) {
return
}
mainSession.loadTestPath(FORMS2_HTML_PATH)
// Wait for the auto-fill nodes to populate.
sessionRule.waitUntilCalled(object : Callbacks.TextInputDelegate {
@AssertCalled(count = 2)
override fun notifyAutoFill(session: GeckoSession, notification: Int, virtualId: Int) {
}
})
mainSession.evaluateJS("$('#pass1').focus()")
sessionRule.waitUntilCalled(object : Callbacks.TextInputDelegate {
@AssertCalled(count = 1)
override fun notifyAutoFill(session: GeckoSession, notification: Int, virtualId: Int) {
}
})
val rootNode = ViewNode.newInstance()
val rootStructure = ViewNodeBuilder.newInstance(AssistStructure(), rootNode,
/* async */ false) as ViewStructure
// Perform auto-fill and return number of auto-fills performed.
fun checkAutoFillChild(child: AssistStructure.ViewNode): Int {
var sum = 0
// Seal the node info instance so we can perform actions on it.
if (child.childCount > 0) {
for (i in 0 until child.childCount) {
sum += checkAutoFillChild(child.getChildAt(i))
}
}
if (child === rootNode) {
return sum
}
assertThat("ID should be valid", child.id, not(equalTo(View.NO_ID)))
if (EditText::class.java.name == child.className) {
val htmlInfo = child.htmlInfo
assertThat("Should have HTML tag", htmlInfo.tag, equalTo("input"))
if (child.autofillHints == null) {
return sum
}
child.autofillHints.forEach {
when (it) {
View.AUTOFILL_HINT_USERNAME, View.AUTOFILL_HINT_PASSWORD -> {
sum++
}
}
}
}
return sum
}
mainSession.textInput.onProvideAutofillVirtualStructure(rootStructure, 0)
// form and iframe have each 2 hints.
assertThat("autofill hint count",
checkAutoFillChild(rootNode), equalTo(4))
}
private fun goFullscreen() {
sessionRule.setPrefsUntilTestEnd(mapOf("full-screen-api.allow-trusted-requests-only" to false))
mainSession.loadTestPath(FULLSCREEN_PATH)

View File

@ -654,6 +654,7 @@ public final class SessionTextInput {
}
if (Build.VERSION.SDK_INT >= 26 && "INPUT".equals(tag)) {
// LastPass will fill password to the feild that setAutofillHints is unset and setInputType is set.
switch (type) {
case "email":
structure.setAutofillHints(new String[] { View.AUTOFILL_HINT_EMAIL_ADDRESS });
@ -672,14 +673,18 @@ public final class SessionTextInput {
structure.setAutofillHints(new String[] { View.AUTOFILL_HINT_PHONE });
structure.setInputType(InputType.TYPE_CLASS_PHONE);
break;
case "text":
structure.setInputType(InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT);
break;
case "url":
structure.setInputType(InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_VARIATION_URI);
break;
case "text":
final String autofillhint = bundle.getString("autofillhint", "");
if (autofillhint.equals("username")) {
structure.setAutofillHints(new String[] { View.AUTOFILL_HINT_USERNAME });
structure.setInputType(InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT);
}
break;
}
}
}

View File

@ -12,6 +12,7 @@ ChromeUtils.import("resource://gre/modules/GeckoViewUtils.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
DeferredTask: "resource://gre/modules/DeferredTask.jsm",
FormLikeFactory: "resource://gre/modules/FormLikeFactory.jsm",
LoginManagerContent: "resource://gre/modules/LoginManagerContent.jsm",
});
GeckoViewUtils.initLogging("AutoFill", this);
@ -78,7 +79,7 @@ class GeckoViewAutoFill {
let sendFocusEvent = false;
const window = aFormLike.rootElement.ownerGlobal;
const getInfo = (element, parent, root) => {
const getInfo = (element, parent, root, usernameField) => {
let info = this._autoFillInfos.get(element);
if (info) {
return info;
@ -99,17 +100,28 @@ class GeckoViewAutoFill {
.filter(attr => attr.localName !== "value")
.map(attr => ({[attr.localName]: attr.value}))),
origin: element.ownerDocument.location.origin,
autofillhint: "",
};
if (element === usernameField) {
info.autofillhint = "username"; // AUTOFILL_HINT_USERNAME
}
this._autoFillInfos.set(element, info);
this._autoFillElements.set(info.id, Cu.getWeakReference(element));
sendFocusEvent |= (element === element.ownerDocument.activeElement);
return info;
};
const rootInfo = getInfo(aFormLike.rootElement, null, undefined);
let [usernameField] =
LoginManagerContent.getUserNameAndPasswordFields(aFormLike.elements[0]);
const rootInfo = getInfo(aFormLike.rootElement, null, undefined, null);
rootInfo.root = rootInfo.id;
rootInfo.children = aFormLike.elements.map(
element => getInfo(element, rootInfo.id, rootInfo.id));
rootInfo.children = aFormLike.elements
.filter(element => (!usernameField || element.type != "text" ||
element == usernameField))
.map(element => getInfo(element, rootInfo.id, rootInfo.id, usernameField));
this._eventDispatcher.dispatch("GeckoView:AddAutoFill", rootInfo, {
onSuccess: responses => {

View File

@ -5990,8 +5990,6 @@ pref("dom.datatransfer.mozAtAPIs", true);
pref("prio.enabled", false);
#endif
#ifdef NIGHTLY_BUILD
pref("dom.sidebar.enabled", false);
#else
// External.AddSearchProvider is deprecated and it will be removed in the next
// cycles.
pref("dom.sidebar.enabled", true);
#endif

View File

@ -1197,9 +1197,15 @@ void nsHtml5StreamParser::DoDataAvailableBuffer(mozilla::Buffer<uint8_t>&& aBuff
DoDataAvailable(mBufferedLocalFileData.LastElement());
} else {
// Truncation OK, because the constant is small enough.
size_t overBoundary =
bufferedPlusLength.value() - LOCAL_FILE_UTF_8_BUFFER_SIZE;
MOZ_RELEASE_ASSERT(overBoundary < aBuffer.Length());
size_t untilBoundary = aBuffer.Length() - overBoundary;
auto span = aBuffer.AsSpan();
auto head = span.To(LOCAL_FILE_UTF_8_BUFFER_SIZE);
auto tail = span.From(LOCAL_FILE_UTF_8_BUFFER_SIZE);
auto head = span.To(untilBoundary);
auto tail = span.From(untilBoundary);
MOZ_RELEASE_ASSERT(mLocalFileBytesBuffered + untilBoundary ==
LOCAL_FILE_UTF_8_BUFFER_SIZE);
// We make a theoretically useless copy here, because avoiding
// the copy adds too much complexity.
Maybe<Buffer<uint8_t>> maybe = Buffer<uint8_t>::CopyFrom(head);

View File

@ -1333,6 +1333,33 @@ var LoginManagerContent = {
return true;
},
/**
* Returns the username and password fields found in the form by input
* element into form.
*
* @param {HTMLInputElement} aField
* A form field into form.
* @return {Array} [usernameField, newPasswordField, oldPasswordField]
*
* More detail of these values is same as _getFormFields.
*/
getUserNameAndPasswordFields(aField) {
// If the element is not a proper form field, return null.
if (ChromeUtils.getClassName(aField) !== "HTMLInputElement" ||
(aField.type != "password" && !LoginHelper.isUsernameFieldType(aField)) ||
aField.nodePrincipal.isNullPrincipal ||
!aField.ownerDocument) {
return [null, null, null];
}
let form = LoginFormFactory.createFromField(aField);
let doc = aField.ownerDocument;
let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
let recipes = LoginRecipesContent.getRecipes(formOrigin, doc.defaultView);
return this._getFormFields(form, false, recipes);
},
/**
* Verify if a field is a valid login form field and
* returns some information about it's FormLike.
@ -1352,14 +1379,9 @@ var LoginManagerContent = {
!aField.ownerDocument) {
return null;
}
let form = LoginFormFactory.createFromField(aField);
let doc = aField.ownerDocument;
let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
let recipes = LoginRecipesContent.getRecipes(formOrigin, doc.defaultView);
let [usernameField, newPasswordField] =
this._getFormFields(form, false, recipes);
this.getUserNameAndPasswordFields(aField);
// If we are not verifying a password field, we want
// to use aField as the username field.

View File

@ -0,0 +1,118 @@
/*
* Test for LoginManagerContent.getUserNameAndPasswordFields
*/
"use strict";
// Services.prefs.setBoolPref("signon.debug", true);
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
const LMCBackstagePass = ChromeUtils.import("resource://gre/modules/LoginManagerContent.jsm", {});
const { LoginManagerContent, LoginFormFactory } = LMCBackstagePass;
const TESTCASES = [
{
description: "1 password field outside of a <form>",
document: `<input id="pw1" type=password>`,
returnedFieldIDs: [null, "pw1", null],
},
{
description: "1 text field outside of a <form> without a password field",
document: `<input id="un1">`,
returnedFieldIDs: [null, null, null],
},
{
description: "1 username & password field outside of a <form>",
document: `<input id="un1">
<input id="pw1" type=password>`,
returnedFieldIDs: ["un1", "pw1", null],
},
{
description: "1 username & password field in a <form>",
document: `<form>
<input id="un1">
<input id="pw1" type=password>
</form>`,
returnedFieldIDs: ["un1", "pw1", null],
},
{
description: "4 empty password fields outside of a <form>",
document: `<input id="pw1" type=password>
<input id="pw2" type=password>
<input id="pw3" type=password>
<input id="pw4" type=password>`,
returnedFieldIDs: [null, null, null],
},
{
description: "Form with 1 password field",
document: `<form><input id="pw1" type=password></form>`,
returnedFieldIDs: [null, "pw1", null],
},
{
description: "Form with 2 password fields",
document: `<form><input id="pw1" type=password><input id='pw2' type=password></form>`,
returnedFieldIDs: [null, "pw1", null],
},
{
description: "1 password field in a form, 1 outside (not processed)",
document: `<form><input id="pw1" type=password></form><input id="pw2" type=password>`,
returnedFieldIDs: [null, "pw1", null],
},
{
description: "1 password field in a form, 1 text field outside (not processed)",
document: `<form><input id="pw1" type=password></form><input>`,
returnedFieldIDs: [null, "pw1", null],
},
{
description: "1 text field in a form, 1 password field outside (not processed)",
document: `<form><input></form><input id="pw1" type=password>`,
returnedFieldIDs: [null, null, null],
},
{
description: "2 password fields outside of a <form> with 1 linked via @form",
document: `<input id="pw1" type=password><input id="pw2" type=password form='form1'>
<form id="form1"></form>`,
returnedFieldIDs: [null, "pw1", null],
},
];
for (let tc of TESTCASES) {
info("Sanity checking the testcase: " + tc.description);
(function() {
let testcase = tc;
add_task(async function() {
info("Starting testcase: " + testcase.description);
let document = MockDocument.createTestDocument("http://localhost:8080/test/",
testcase.document);
let input = document.querySelector("input");
MockDocument.mockOwnerDocumentProperty(input, document, "http://localhost:8080/test/");
MockDocument.mockNodePrincipalProperty(input, "http://localhost:8080/test/");
// Additional mock to cache recipes
let win = {};
Object.defineProperty(document, "defaultView", {
value: win,
});
let formOrigin = LMCBackstagePass.LoginUtils._getPasswordOrigin(document.documentURI);
LoginRecipesContent.cacheRecipes(formOrigin, win, new Set());
let actual = LoginManagerContent.getUserNameAndPasswordFields(input);
Assert.strictEqual(testcase.returnedFieldIDs.length, 3,
"getUserNameAndPasswordFields returns 3 elements");
for (let i = 0; i < testcase.returnedFieldIDs.length; i++) {
let expectedID = testcase.returnedFieldIDs[i];
if (expectedID === null) {
Assert.strictEqual(actual[i], expectedID,
"Check returned field " + i + " is null");
} else {
Assert.strictEqual(actual[i].id, expectedID,
"Check returned field " + i + " ID");
}
}
});
})();
}

View File

@ -23,6 +23,7 @@ run-if = buildapp == "browser"
[test_getFormFields.js]
[test_getPasswordFields.js]
[test_getPasswordOrigin.js]
[test_getUserNameAndPasswordFields.js]
[test_isOriginMatching.js]
[test_legacy_empty_formSubmitURL.js]
[test_legacy_validation.js]

View File

@ -7,6 +7,7 @@
var EXPORTED_SYMBOLS = ["MockDocument"];
const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm", {});
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
const MockDocument = {
/**
@ -64,6 +65,13 @@ const MockDocument = {
});
},
mockNodePrincipalProperty(aElement, aURL) {
Object.defineProperty(aElement, "nodePrincipal", {
value: Services.scriptSecurityManager.createCodebasePrincipal(
Services.io.newURI(aURL), {}),
});
},
createTestDocumentFromFile(aDocumentURL, aFile) {
let fileStream = Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(Ci.nsIFileInputStream);