зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland. a=merge CLOSED TREE
This commit is contained in:
Коммит
4eaaa7bc4c
|
@ -111,9 +111,13 @@ void XULListboxAccessible::Value(nsString& aValue) const {
|
||||||
RefPtr<Element> element;
|
RefPtr<Element> element;
|
||||||
select->GetSelectedItem(getter_AddRefs(element));
|
select->GetSelectedItem(getter_AddRefs(element));
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem =
|
if (element) {
|
||||||
element->AsXULSelectControlItem();
|
nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem =
|
||||||
if (selectedItem) selectedItem->GetLabel(aValue);
|
element->AsXULSelectControlItem();
|
||||||
|
if (selectedItem) {
|
||||||
|
selectedItem->GetLabel(aValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,6 +180,9 @@ bool XULListboxAccessible::IsRowSelected(uint32_t aRowIdx) {
|
||||||
RefPtr<Element> element;
|
RefPtr<Element> element;
|
||||||
nsresult rv = control->GetItemAtIndex(aRowIdx, getter_AddRefs(element));
|
nsresult rv = control->GetItemAtIndex(aRowIdx, getter_AddRefs(element));
|
||||||
NS_ENSURE_SUCCESS(rv, false);
|
NS_ENSURE_SUCCESS(rv, false);
|
||||||
|
if (!element) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
|
nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
|
||||||
element->AsXULSelectControlItem();
|
element->AsXULSelectControlItem();
|
||||||
|
@ -337,6 +344,9 @@ void XULListboxAccessible::SelectRow(uint32_t aRowIdx) {
|
||||||
|
|
||||||
RefPtr<Element> item;
|
RefPtr<Element> item;
|
||||||
control->GetItemAtIndex(aRowIdx, getter_AddRefs(item));
|
control->GetItemAtIndex(aRowIdx, getter_AddRefs(item));
|
||||||
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm =
|
nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm =
|
||||||
item->AsXULSelectControlItem();
|
item->AsXULSelectControlItem();
|
||||||
|
@ -351,6 +361,9 @@ void XULListboxAccessible::UnselectRow(uint32_t aRowIdx) {
|
||||||
|
|
||||||
RefPtr<Element> item;
|
RefPtr<Element> item;
|
||||||
control->GetItemAtIndex(aRowIdx, getter_AddRefs(item));
|
control->GetItemAtIndex(aRowIdx, getter_AddRefs(item));
|
||||||
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm =
|
nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm =
|
||||||
item->AsXULSelectControlItem();
|
item->AsXULSelectControlItem();
|
||||||
|
|
|
@ -57,9 +57,6 @@ method PushSubscription.unsubscribe
|
||||||
// window.sidebar
|
// window.sidebar
|
||||||
attribute Window.sidebar
|
attribute Window.sidebar
|
||||||
|
|
||||||
// External interface
|
|
||||||
method External.AddSearchProvider
|
|
||||||
|
|
||||||
// AppCache API
|
// AppCache API
|
||||||
method OfflineResourceList.swapCache
|
method OfflineResourceList.swapCache
|
||||||
method OfflineResourceList.update
|
method OfflineResourceList.update
|
||||||
|
|
|
@ -50,3 +50,4 @@ DEPRECATED_OPERATION(CreateImageBitmapCanvasRenderingContext2D)
|
||||||
DEPRECATED_OPERATION(MozRequestFullScreenDeprecatedPrefix)
|
DEPRECATED_OPERATION(MozRequestFullScreenDeprecatedPrefix)
|
||||||
DEPRECATED_OPERATION(MozfullscreenchangeDeprecatedPrefix)
|
DEPRECATED_OPERATION(MozfullscreenchangeDeprecatedPrefix)
|
||||||
DEPRECATED_OPERATION(MozfullscreenerrorDeprecatedPrefix)
|
DEPRECATED_OPERATION(MozfullscreenerrorDeprecatedPrefix)
|
||||||
|
DEPRECATED_OPERATION(External_AddSearchProvider)
|
||||||
|
|
|
@ -368,3 +368,5 @@ MozRequestFullScreenDeprecatedPrefixWarning=mozRequestFullScreen() is deprecated
|
||||||
MozfullscreenchangeDeprecatedPrefixWarning=onmozfullscreenchange is deprecated.
|
MozfullscreenchangeDeprecatedPrefixWarning=onmozfullscreenchange is deprecated.
|
||||||
# LOCALIZATION NOTE (MozfullscreenerrorDeprecatedPrefixWarning): Do not translate onmozfullscreenerror.
|
# LOCALIZATION NOTE (MozfullscreenerrorDeprecatedPrefixWarning): Do not translate onmozfullscreenerror.
|
||||||
MozfullscreenerrorDeprecatedPrefixWarning=onmozfullscreenerror is deprecated.
|
MozfullscreenerrorDeprecatedPrefixWarning=onmozfullscreenerror is deprecated.
|
||||||
|
# LOCALIZATION NOTE(External_AddSearchProviderWarning): Do not translate AddSearchProvider.
|
||||||
|
External_AddSearchProviderWarning=AddSearchProvider is deprecated.
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
[NoInterfaceObject, JSImplementation="@mozilla.org/sidebar;1"]
|
[NoInterfaceObject, JSImplementation="@mozilla.org/sidebar;1"]
|
||||||
interface External
|
interface External
|
||||||
{
|
{
|
||||||
[UseCounter]
|
[Deprecated="External_AddSearchProvider"]
|
||||||
void AddSearchProvider(DOMString aDescriptionURL);
|
void AddSearchProvider(DOMString aDescriptionURL);
|
||||||
void IsSearchProviderInstalled();
|
void IsSearchProviderInstalled();
|
||||||
};
|
};
|
||||||
|
|
|
@ -2991,6 +2991,13 @@ void WorkerPrivate::ShutdownGCTimers() {
|
||||||
bool WorkerPrivate::InterruptCallback(JSContext* aCx) {
|
bool WorkerPrivate::InterruptCallback(JSContext* aCx) {
|
||||||
MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible, data);
|
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));
|
MOZ_ASSERT(!JS_IsExceptionPending(aCx));
|
||||||
|
|
||||||
bool mayContinue = true;
|
bool mayContinue = true;
|
||||||
|
@ -3004,9 +3011,17 @@ bool WorkerPrivate::InterruptCallback(JSContext* aCx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mayFreeze = data->mFrozen;
|
bool mayFreeze = data->mFrozen;
|
||||||
if (mayFreeze) {
|
|
||||||
|
{
|
||||||
MutexAutoLock lock(mMutex);
|
MutexAutoLock lock(mMutex);
|
||||||
mayFreeze = mStatus <= Running;
|
|
||||||
|
if (mayFreeze) {
|
||||||
|
mayFreeze = mStatus <= Running;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mStatus >= Canceling) {
|
||||||
|
mayContinue = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mayContinue || !mayFreeze) {
|
if (!mayContinue || !mayFreeze) {
|
||||||
|
@ -3510,10 +3525,11 @@ bool WorkerPrivate::RunCurrentSyncLoop() {
|
||||||
|
|
||||||
auto result = ProcessAllControlRunnablesLocked();
|
auto result = ProcessAllControlRunnablesLocked();
|
||||||
if (result != ProcessAllControlRunnablesResult::Nothing) {
|
if (result != ProcessAllControlRunnablesResult::Nothing) {
|
||||||
// XXXkhuey how should we handle Abort here? See Bug 1003730.
|
// The state of the world may have changed. Recheck it if we need to
|
||||||
|
// continue.
|
||||||
// The state of the world may have changed. Recheck it.
|
normalRunnablesPending =
|
||||||
normalRunnablesPending = NS_HasPendingEvents(mThread);
|
result == ProcessAllControlRunnablesResult::MayContinue &&
|
||||||
|
NS_HasPendingEvents(mThread);
|
||||||
|
|
||||||
// NB: If we processed a NotifyRunnable, we might have run
|
// NB: If we processed a NotifyRunnable, we might have run
|
||||||
// non-control runnables, one of which may have shut down the
|
// non-control runnables, one of which may have shut down the
|
||||||
|
|
|
@ -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>
|
|
@ -101,6 +101,7 @@ load 1423767.html
|
||||||
needs-focus load 1423776.html
|
needs-focus load 1423776.html
|
||||||
needs-focus load 1424450.html
|
needs-focus load 1424450.html
|
||||||
load 1425091.html
|
load 1425091.html
|
||||||
|
load 1441619.html
|
||||||
load 1443664.html
|
load 1443664.html
|
||||||
skip-if(Android) needs-focus load 1444630.html
|
skip-if(Android) needs-focus load 1444630.html
|
||||||
load 1446451.html
|
load 1446451.html
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace mozilla {
|
||||||
using namespace mozilla::intl;
|
using namespace mozilla::intl;
|
||||||
|
|
||||||
nsCString* DateTimeFormat::mLocale = nullptr;
|
nsCString* DateTimeFormat::mLocale = nullptr;
|
||||||
|
nsDataHashtable<nsCStringHashKey, UDateFormat*>* DateTimeFormat::mFormatCache;
|
||||||
|
|
||||||
/*static*/ nsresult DateTimeFormat::Initialize() {
|
/*static*/ nsresult DateTimeFormat::Initialize() {
|
||||||
if (mLocale) {
|
if (mLocale) {
|
||||||
|
@ -74,142 +75,170 @@ nsCString* DateTimeFormat::mLocale = nullptr;
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the date style for the formatter.
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
nsAutoString skeletonDate;
|
|
||||||
nsAutoString patternDate;
|
nsAutoCString key;
|
||||||
bool haveSkeleton = true;
|
key.AppendInt((int)aDateFormatSelector);
|
||||||
switch (aDateFormatSelector) {
|
key.Append(':');
|
||||||
case kDateFormatLong:
|
key.AppendInt((int)aTimeFormatSelector);
|
||||||
rv = OSPreferences::GetInstance()->GetDateTimePattern(
|
if (aTimeParameters) {
|
||||||
mozIOSPreferences::dateTimeFormatStyleLong,
|
key.Append(':');
|
||||||
mozIOSPreferences::dateTimeFormatStyleNone,
|
key.AppendInt(aTimeParameters->tp_gmt_offset);
|
||||||
nsDependentCString(mLocale->get()), patternDate);
|
key.Append(':');
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
key.AppendInt(aTimeParameters->tp_dst_offset);
|
||||||
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;
|
if (mFormatCache && mFormatCache->Count() == kMaxCachedFormats) {
|
||||||
if (haveSkeleton) {
|
// Don't allow a pathological page to extend the cache unreasonably.
|
||||||
// Get pattern for skeleton.
|
NS_WARNING("flushing UDateFormat cache");
|
||||||
UDateTimePatternGenerator* patternGenerator =
|
DeleteCache();
|
||||||
udatpg_open(mLocale->get(), &status);
|
}
|
||||||
if (U_SUCCESS(status)) {
|
if (!mFormatCache) {
|
||||||
int32_t patternLength;
|
mFormatCache =
|
||||||
patternDate.SetLength(DATETIME_FORMAT_INITIAL_LEN);
|
new nsDataHashtable<nsCStringHashKey, UDateFormat*>(kMaxCachedFormats);
|
||||||
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 (status == U_BUFFER_OVERFLOW_ERROR) {
|
UDateFormat*& dateTimeFormat = mFormatCache->GetOrInsert(key);
|
||||||
status = U_ZERO_ERROR;
|
|
||||||
udatpg_getBestPattern(
|
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,
|
patternGenerator,
|
||||||
reinterpret_cast<const UChar*>(skeletonDate.BeginReading()),
|
reinterpret_cast<const UChar*>(skeletonDate.BeginReading()),
|
||||||
skeletonDate.Length(),
|
skeletonDate.Length(),
|
||||||
reinterpret_cast<UChar*>(patternDate.BeginWriting()), patternLength,
|
reinterpret_cast<UChar*>(patternDate.BeginWriting()),
|
||||||
&status);
|
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.
|
if (aTimeParameters) {
|
||||||
nsAutoString patternTime;
|
dateTimeFormat =
|
||||||
switch (aTimeFormatSelector) {
|
udat_open(UDAT_PATTERN, UDAT_PATTERN, mLocale->get(),
|
||||||
case kTimeFormatSeconds:
|
reinterpret_cast<const UChar*>(timeZoneID.BeginReading()),
|
||||||
rv = OSPreferences::GetInstance()->GetDateTimePattern(
|
timeZoneID.Length(),
|
||||||
mozIOSPreferences::dateTimeFormatStyleNone,
|
reinterpret_cast<const UChar*>(pattern.BeginReading()),
|
||||||
mozIOSPreferences::dateTimeFormatStyleLong,
|
pattern.Length(), &status);
|
||||||
nsDependentCString(mLocale->get()), patternTime);
|
} else {
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
dateTimeFormat =
|
||||||
break;
|
udat_open(UDAT_PATTERN, UDAT_PATTERN, mLocale->get(), nullptr, -1,
|
||||||
case kTimeFormatNoSeconds:
|
reinterpret_cast<const UChar*>(pattern.BeginReading()),
|
||||||
rv = OSPreferences::GetInstance()->GetDateTimePattern(
|
pattern.Length(), &status);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
if (U_SUCCESS(status) && dateTimeFormat) {
|
||||||
aStringOut.SetLength(DATETIME_FORMAT_INITIAL_LEN);
|
aStringOut.SetLength(DATETIME_FORMAT_INITIAL_LEN);
|
||||||
dateTimeLen =
|
dateTimeLen =
|
||||||
|
@ -230,14 +259,21 @@ nsCString* DateTimeFormat::mLocale = nullptr;
|
||||||
rv = NS_ERROR_FAILURE;
|
rv = NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dateTimeFormat) {
|
|
||||||
udat_close(dateTimeFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
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() {
|
/*static*/ void DateTimeFormat::Shutdown() {
|
||||||
|
DeleteCache();
|
||||||
if (mLocale) {
|
if (mLocale) {
|
||||||
delete mLocale;
|
delete mLocale;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "gtest/MozGtestFriend.h"
|
#include "gtest/MozGtestFriend.h"
|
||||||
|
#include "nsDataHashtable.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "prtime.h"
|
#include "prtime.h"
|
||||||
#include "unicode/udat.h"
|
#include "unicode/udat.h"
|
||||||
|
@ -55,6 +56,8 @@ class DateTimeFormat {
|
||||||
DateTimeFormat() = delete;
|
DateTimeFormat() = delete;
|
||||||
|
|
||||||
static nsresult Initialize();
|
static nsresult Initialize();
|
||||||
|
static void DeleteCache();
|
||||||
|
static const size_t kMaxCachedFormats = 15;
|
||||||
|
|
||||||
FRIEND_TEST(DateTimeFormat, FormatPRExplodedTime);
|
FRIEND_TEST(DateTimeFormat, FormatPRExplodedTime);
|
||||||
FRIEND_TEST(DateTimeFormat, DateFormatSelectors);
|
FRIEND_TEST(DateTimeFormat, DateFormatSelectors);
|
||||||
|
@ -69,6 +72,7 @@ class DateTimeFormat {
|
||||||
const PRTimeParameters* aTimeParameters, nsAString& aStringOut);
|
const PRTimeParameters* aTimeParameters, nsAString& aStringOut);
|
||||||
|
|
||||||
static nsCString* mLocale;
|
static nsCString* mLocale;
|
||||||
|
static nsDataHashtable<nsCStringHashKey, UDateFormat*>* mFormatCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -333,11 +333,34 @@ OSPreferences::GetDateTimePattern(int32_t aDateFormatStyle,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ReadDateTimePattern(dateStyle, timeStyle, aLocale, aRetVal)) {
|
// Create a cache key from the locale + style options
|
||||||
if (!GetDateTimePatternForStyle(dateStyle, timeStyle, aLocale, aRetVal)) {
|
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;
|
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;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#define mozilla_intl_IntlOSPreferences_h__
|
#define mozilla_intl_IntlOSPreferences_h__
|
||||||
|
|
||||||
#include "mozilla/StaticPtr.h"
|
#include "mozilla/StaticPtr.h"
|
||||||
|
#include "nsDataHashtable.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
#include "unicode/uloc.h"
|
#include "unicode/uloc.h"
|
||||||
|
@ -97,6 +98,9 @@ class OSPreferences : public mozIOSPreferences {
|
||||||
nsTArray<nsCString> mSystemLocales;
|
nsTArray<nsCString> mSystemLocales;
|
||||||
nsTArray<nsCString> mRegionalPrefsLocales;
|
nsTArray<nsCString> mRegionalPrefsLocales;
|
||||||
|
|
||||||
|
const size_t kMaxCachedPatterns = 15;
|
||||||
|
nsDataHashtable<nsCStringHashKey, nsString> mPatternCache;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual ~OSPreferences();
|
virtual ~OSPreferences();
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ JSObject* SymbolObject::initClass(JSContext* cx, Handle<GlobalObject*> global,
|
||||||
WellKnownSymbols* wks = cx->runtime()->wellKnownSymbols;
|
WellKnownSymbols* wks = cx->runtime()->wellKnownSymbols;
|
||||||
for (size_t i = 0; i < JS::WellKnownSymbolLimit; i++) {
|
for (size_t i = 0; i < JS::WellKnownSymbolLimit; i++) {
|
||||||
#ifndef NIGHTLY_BUILD
|
#ifndef NIGHTLY_BUILD
|
||||||
if (i == SymbolCode::matchAll) {
|
if (i == static_cast<size_t>(SymbolCode::matchAll)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -5133,12 +5133,10 @@ void js::gc::DelayCrossCompartmentGrayMarking(JSObject* src) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCRuntime::markIncomingCrossCompartmentPointers(MarkColor color) {
|
void GCRuntime::markIncomingCrossCompartmentPointers(MarkColor color) {
|
||||||
MOZ_ASSERT(color == MarkColor::Black || color == MarkColor::Gray);
|
gcstats::AutoPhase ap(
|
||||||
|
stats(),
|
||||||
static const gcstats::PhaseKind statsPhases[] = {
|
color == MarkColor::Black ? gcstats::PhaseKind::SWEEP_MARK_INCOMING_BLACK
|
||||||
gcstats::PhaseKind::SWEEP_MARK_INCOMING_BLACK,
|
: gcstats::PhaseKind::SWEEP_MARK_INCOMING_GRAY);
|
||||||
gcstats::PhaseKind::SWEEP_MARK_INCOMING_GRAY};
|
|
||||||
gcstats::AutoPhase ap1(stats(), statsPhases[unsigned(color)]);
|
|
||||||
|
|
||||||
bool unlinkList = color == MarkColor::Gray;
|
bool unlinkList = color == MarkColor::Gray;
|
||||||
|
|
||||||
|
@ -5325,7 +5323,7 @@ IncrementalProgress GCRuntime::markGrayReferencesInCurrentGroup(
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return marker.markUntilBudgetExhausted(budget) ? Finished : NotFinished;
|
return markUntilBudgetExhausted(budget, gcstats::PhaseKind::SWEEP_MARK_GRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
IncrementalProgress GCRuntime::endMarkingSweepGroup(FreeOp* fop,
|
IncrementalProgress GCRuntime::endMarkingSweepGroup(FreeOp* fop,
|
||||||
|
|
|
@ -3546,7 +3546,7 @@ void UnmarkGrayTracer::onChild(const JS::GCCellPtr& thing) {
|
||||||
// case, push any cells in zones that are currently being marked onto the
|
// case, push any cells in zones that are currently being marked onto the
|
||||||
// mark stack and they will eventually get marked black.
|
// mark stack and they will eventually get marked black.
|
||||||
Zone* zone = tenured.zone();
|
Zone* zone = tenured.zone();
|
||||||
if (zone->needsIncrementalBarrier()) {
|
if (zone->isGCMarkingBlackAndGray()) {
|
||||||
if (!cell->isMarkedBlack()) {
|
if (!cell->isMarkedBlack()) {
|
||||||
Cell* tmp = cell;
|
Cell* tmp = cell;
|
||||||
TraceManuallyBarrieredGenericPointerEdge(zone->barrierTracer(), &tmp,
|
TraceManuallyBarrieredGenericPointerEdge(zone->barrierTracer(), &tmp,
|
||||||
|
@ -3557,7 +3557,6 @@ void UnmarkGrayTracer::onChild(const JS::GCCellPtr& thing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(!zone->isGCMarkingBlackAndGray());
|
|
||||||
if (!tenured.isMarkedGray()) {
|
if (!tenured.isMarkedGray()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -488,9 +488,6 @@ skip script test262/language/expressions/await/async-generator-interleaved.js
|
||||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1321616
|
# https://bugzilla.mozilla.org/show_bug.cgi?id=1321616
|
||||||
skip script test262/annexB/built-ins/Function/createdynfn-html-close-comment-params.js
|
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
|
# https://bugzilla.mozilla.org/show_bug.cgi?id=1462745
|
||||||
skip script test262/annexB/language/function-code/block-decl-nested-blocks-with-fun-decl.js
|
skip script test262/annexB/language/function-code/block-decl-nested-blocks-with-fun-decl.js
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ class WptreportHandler(object):
|
||||||
"""
|
"""
|
||||||
self.formatter.suite_start({
|
self.formatter.suite_start({
|
||||||
"time": time(),
|
"time": time(),
|
||||||
|
"run_info": {},
|
||||||
})
|
})
|
||||||
|
|
||||||
def suite_end(self):
|
def suite_end(self):
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
// Global functions are configurable in a browser environment.
|
if (typeof getBuildConfiguration === "undefined") {
|
||||||
var functionDeclarationsConfigurable = typeof document !== "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" };
|
var o = { f: "string-f" };
|
||||||
with (o) {
|
with (o) {
|
||||||
|
|
|
@ -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>
|
|
@ -29,6 +29,7 @@ open class BaseSessionTest(noErrorCollector: Boolean = false) {
|
||||||
const val CONTENT_CRASH_URL = "about:crashcontent"
|
const val CONTENT_CRASH_URL = "about:crashcontent"
|
||||||
const val DOWNLOAD_HTML_PATH = "/assets/www/download.html"
|
const val DOWNLOAD_HTML_PATH = "/assets/www/download.html"
|
||||||
const val FORMS_HTML_PATH = "/assets/www/forms.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 HELLO_HTML_PATH = "/assets/www/hello.html"
|
||||||
const val HELLO2_HTML_PATH = "/assets/www/hello2.html"
|
const val HELLO2_HTML_PATH = "/assets/www/hello2.html"
|
||||||
const val INPUTS_PATH = "/assets/www/inputs.html"
|
const val INPUTS_PATH = "/assets/www/inputs.html"
|
||||||
|
|
|
@ -335,6 +335,9 @@ class ContentDelegateTest : BaseSessionTest() {
|
||||||
InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS ->
|
InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS ->
|
||||||
arrayOf(View.AUTOFILL_HINT_EMAIL_ADDRESS)
|
arrayOf(View.AUTOFILL_HINT_EMAIL_ADDRESS)
|
||||||
InputType.TYPE_CLASS_PHONE -> arrayOf(View.AUTOFILL_HINT_PHONE)
|
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
|
else -> null
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -455,6 +458,71 @@ class ContentDelegateTest : BaseSessionTest() {
|
||||||
countAutoFillNodes({ it.isFocused }), equalTo(0))
|
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() {
|
private fun goFullscreen() {
|
||||||
sessionRule.setPrefsUntilTestEnd(mapOf("full-screen-api.allow-trusted-requests-only" to false))
|
sessionRule.setPrefsUntilTestEnd(mapOf("full-screen-api.allow-trusted-requests-only" to false))
|
||||||
mainSession.loadTestPath(FULLSCREEN_PATH)
|
mainSession.loadTestPath(FULLSCREEN_PATH)
|
||||||
|
|
|
@ -654,6 +654,7 @@ public final class SessionTextInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 26 && "INPUT".equals(tag)) {
|
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) {
|
switch (type) {
|
||||||
case "email":
|
case "email":
|
||||||
structure.setAutofillHints(new String[] { View.AUTOFILL_HINT_EMAIL_ADDRESS });
|
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.setAutofillHints(new String[] { View.AUTOFILL_HINT_PHONE });
|
||||||
structure.setInputType(InputType.TYPE_CLASS_PHONE);
|
structure.setInputType(InputType.TYPE_CLASS_PHONE);
|
||||||
break;
|
break;
|
||||||
case "text":
|
|
||||||
structure.setInputType(InputType.TYPE_CLASS_TEXT |
|
|
||||||
InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT);
|
|
||||||
break;
|
|
||||||
case "url":
|
case "url":
|
||||||
structure.setInputType(InputType.TYPE_CLASS_TEXT |
|
structure.setInputType(InputType.TYPE_CLASS_TEXT |
|
||||||
InputType.TYPE_TEXT_VARIATION_URI);
|
InputType.TYPE_TEXT_VARIATION_URI);
|
||||||
break;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ ChromeUtils.import("resource://gre/modules/GeckoViewUtils.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
DeferredTask: "resource://gre/modules/DeferredTask.jsm",
|
DeferredTask: "resource://gre/modules/DeferredTask.jsm",
|
||||||
FormLikeFactory: "resource://gre/modules/FormLikeFactory.jsm",
|
FormLikeFactory: "resource://gre/modules/FormLikeFactory.jsm",
|
||||||
|
LoginManagerContent: "resource://gre/modules/LoginManagerContent.jsm",
|
||||||
});
|
});
|
||||||
|
|
||||||
GeckoViewUtils.initLogging("AutoFill", this);
|
GeckoViewUtils.initLogging("AutoFill", this);
|
||||||
|
@ -78,7 +79,7 @@ class GeckoViewAutoFill {
|
||||||
|
|
||||||
let sendFocusEvent = false;
|
let sendFocusEvent = false;
|
||||||
const window = aFormLike.rootElement.ownerGlobal;
|
const window = aFormLike.rootElement.ownerGlobal;
|
||||||
const getInfo = (element, parent, root) => {
|
const getInfo = (element, parent, root, usernameField) => {
|
||||||
let info = this._autoFillInfos.get(element);
|
let info = this._autoFillInfos.get(element);
|
||||||
if (info) {
|
if (info) {
|
||||||
return info;
|
return info;
|
||||||
|
@ -99,17 +100,28 @@ class GeckoViewAutoFill {
|
||||||
.filter(attr => attr.localName !== "value")
|
.filter(attr => attr.localName !== "value")
|
||||||
.map(attr => ({[attr.localName]: attr.value}))),
|
.map(attr => ({[attr.localName]: attr.value}))),
|
||||||
origin: element.ownerDocument.location.origin,
|
origin: element.ownerDocument.location.origin,
|
||||||
|
autofillhint: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (element === usernameField) {
|
||||||
|
info.autofillhint = "username"; // AUTOFILL_HINT_USERNAME
|
||||||
|
}
|
||||||
|
|
||||||
this._autoFillInfos.set(element, info);
|
this._autoFillInfos.set(element, info);
|
||||||
this._autoFillElements.set(info.id, Cu.getWeakReference(element));
|
this._autoFillElements.set(info.id, Cu.getWeakReference(element));
|
||||||
sendFocusEvent |= (element === element.ownerDocument.activeElement);
|
sendFocusEvent |= (element === element.ownerDocument.activeElement);
|
||||||
return info;
|
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.root = rootInfo.id;
|
||||||
rootInfo.children = aFormLike.elements.map(
|
rootInfo.children = aFormLike.elements
|
||||||
element => getInfo(element, rootInfo.id, rootInfo.id));
|
.filter(element => (!usernameField || element.type != "text" ||
|
||||||
|
element == usernameField))
|
||||||
|
.map(element => getInfo(element, rootInfo.id, rootInfo.id, usernameField));
|
||||||
|
|
||||||
this._eventDispatcher.dispatch("GeckoView:AddAutoFill", rootInfo, {
|
this._eventDispatcher.dispatch("GeckoView:AddAutoFill", rootInfo, {
|
||||||
onSuccess: responses => {
|
onSuccess: responses => {
|
||||||
|
|
|
@ -5990,8 +5990,6 @@ pref("dom.datatransfer.mozAtAPIs", true);
|
||||||
pref("prio.enabled", false);
|
pref("prio.enabled", false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef NIGHTLY_BUILD
|
// External.AddSearchProvider is deprecated and it will be removed in the next
|
||||||
pref("dom.sidebar.enabled", false);
|
// cycles.
|
||||||
#else
|
|
||||||
pref("dom.sidebar.enabled", true);
|
pref("dom.sidebar.enabled", true);
|
||||||
#endif
|
|
||||||
|
|
|
@ -1197,9 +1197,15 @@ void nsHtml5StreamParser::DoDataAvailableBuffer(mozilla::Buffer<uint8_t>&& aBuff
|
||||||
DoDataAvailable(mBufferedLocalFileData.LastElement());
|
DoDataAvailable(mBufferedLocalFileData.LastElement());
|
||||||
} else {
|
} else {
|
||||||
// Truncation OK, because the constant is small enough.
|
// 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 span = aBuffer.AsSpan();
|
||||||
auto head = span.To(LOCAL_FILE_UTF_8_BUFFER_SIZE);
|
auto head = span.To(untilBoundary);
|
||||||
auto tail = span.From(LOCAL_FILE_UTF_8_BUFFER_SIZE);
|
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
|
// We make a theoretically useless copy here, because avoiding
|
||||||
// the copy adds too much complexity.
|
// the copy adds too much complexity.
|
||||||
Maybe<Buffer<uint8_t>> maybe = Buffer<uint8_t>::CopyFrom(head);
|
Maybe<Buffer<uint8_t>> maybe = Buffer<uint8_t>::CopyFrom(head);
|
||||||
|
|
|
@ -1333,6 +1333,33 @@ var LoginManagerContent = {
|
||||||
return true;
|
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
|
* Verify if a field is a valid login form field and
|
||||||
* returns some information about it's FormLike.
|
* returns some information about it's FormLike.
|
||||||
|
@ -1352,14 +1379,9 @@ var LoginManagerContent = {
|
||||||
!aField.ownerDocument) {
|
!aField.ownerDocument) {
|
||||||
return null;
|
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] =
|
let [usernameField, newPasswordField] =
|
||||||
this._getFormFields(form, false, recipes);
|
this.getUserNameAndPasswordFields(aField);
|
||||||
|
|
||||||
// If we are not verifying a password field, we want
|
// If we are not verifying a password field, we want
|
||||||
// to use aField as the username field.
|
// to use aField as the username field.
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ run-if = buildapp == "browser"
|
||||||
[test_getFormFields.js]
|
[test_getFormFields.js]
|
||||||
[test_getPasswordFields.js]
|
[test_getPasswordFields.js]
|
||||||
[test_getPasswordOrigin.js]
|
[test_getPasswordOrigin.js]
|
||||||
|
[test_getUserNameAndPasswordFields.js]
|
||||||
[test_isOriginMatching.js]
|
[test_isOriginMatching.js]
|
||||||
[test_legacy_empty_formSubmitURL.js]
|
[test_legacy_empty_formSubmitURL.js]
|
||||||
[test_legacy_validation.js]
|
[test_legacy_validation.js]
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
var EXPORTED_SYMBOLS = ["MockDocument"];
|
var EXPORTED_SYMBOLS = ["MockDocument"];
|
||||||
|
|
||||||
const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm", {});
|
const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm", {});
|
||||||
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
|
||||||
|
|
||||||
const MockDocument = {
|
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) {
|
createTestDocumentFromFile(aDocumentURL, aFile) {
|
||||||
let fileStream = Cc["@mozilla.org/network/file-input-stream;1"].
|
let fileStream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||||
createInstance(Ci.nsIFileInputStream);
|
createInstance(Ci.nsIFileInputStream);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче