diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js
index 26a73e17309..10ac9276b1b 100644
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -1063,6 +1063,7 @@ var CaptivePortalLoginHelper = {
init: function init() {
Services.obs.addObserver(this, 'captive-portal-login', false);
Services.obs.addObserver(this, 'captive-portal-login-abort', false);
+ Services.obs.addObserver(this, 'captive-portal-login-success', false);
},
handleEvent: function handleEvent(detail) {
Services.captivePortalDetector.cancelLogin(detail.id);
diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml
index 47e6a69982d..9d80900ac61 100644
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -19,13 +19,13 @@
-
+
-
+
diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml
index ecb55ffcf80..ba513c79811 100644
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -17,10 +17,10 @@
-
+
-
+
diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml
index aaaca03bc04..5e6c6c4d723 100644
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml
index 47e6a69982d..9d80900ac61 100644
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -19,13 +19,13 @@
-
+
-
+
diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml
index 47866ce231c..6a580b3ca94 100644
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -17,10 +17,10 @@
-
+
-
+
@@ -118,7 +118,7 @@
-
+
diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json
index 784f0ff6598..a738b422118 100644
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
- "revision": "46fb0be835267316bda52a12dedab53978456833",
+ "revision": "01ae06e7d0c3c72d51e6801986339d6c06229c9b",
"repo_path": "/integration/gaia-central"
}
diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml
index 22476a46c8e..7e18dfe5e80 100644
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -17,12 +17,12 @@
-
+
-
+
diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml
index c9011e222a5..1b13fc66046 100644
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml
index a48be446cf5..ba850f5505f 100644
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -17,10 +17,10 @@
-
+
-
+
diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml
index e36744852f8..84e455f83e4 100644
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -17,12 +17,12 @@
-
+
-
+
diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h
index c7ad63de0e1..ca15e67032f 100644
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -2031,8 +2031,9 @@ GK_ATOM(x_symbol, "x-symbol")
GK_ATOM(az, "az")
GK_ATOM(ba, "ba")
GK_ATOM(crh, "crh")
-GK_ATOM(nl, "nl")
GK_ATOM(el, "el")
+GK_ATOM(ga_ie, "ga-ie")
+GK_ATOM(nl, "nl")
// Names for editor transactions
GK_ATOM(TypingTxnName, "Typing")
diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp
index 7b0a931719e..3ec6f6f07c1 100644
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -181,9 +181,7 @@ nsDOMWindowUtils::GetLayerTransaction()
NS_IMETHODIMP
nsDOMWindowUtils::GetImageAnimationMode(uint16_t *aMode)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
NS_ENSURE_ARG_POINTER(aMode);
*aMode = 0;
@@ -198,9 +196,7 @@ nsDOMWindowUtils::GetImageAnimationMode(uint16_t *aMode)
NS_IMETHODIMP
nsDOMWindowUtils::SetImageAnimationMode(uint16_t aMode)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsPresContext* presContext = GetPresContext();
if (presContext) {
@@ -215,9 +211,7 @@ nsDOMWindowUtils::GetDocCharsetIsForced(bool *aIsForced)
{
*aIsForced = false;
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsIDocument* doc = GetDocument();
*aIsForced = doc &&
@@ -229,9 +223,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::GetDocumentMetadata(const nsAString& aName,
nsAString& aValue)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsIDocument* doc = GetDocument();
if (doc) {
@@ -247,9 +239,7 @@ nsDOMWindowUtils::GetDocumentMetadata(const nsAString& aName,
NS_IMETHODIMP
nsDOMWindowUtils::Redraw(uint32_t aCount, uint32_t *aDurationOut)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
if (aCount == 0)
aCount = 1;
@@ -328,9 +318,7 @@ nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx,
nsIDOMElement* aElement,
uint32_t aPriority)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsIPresShell* presShell = GetPresShell();
if (!presShell) {
@@ -453,9 +441,7 @@ nsDOMWindowUtils::SetDisplayPortBaseForElement(int32_t aX,
int32_t aHeight,
nsIDOMElement* aElement)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsIPresShell* presShell = GetPresShell();
if (!presShell) {
@@ -505,9 +491,7 @@ nsDOMWindowUtils::SetResolution(float aXResolution, float aYResolution)
NS_IMETHODIMP
nsDOMWindowUtils::GetResolution(float* aXResolution, float* aYResolution)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsIPresShell* presShell = GetPresShell();
if (!presShell) {
@@ -529,9 +513,7 @@ nsDOMWindowUtils::GetResolution(float* aXResolution, float* aYResolution)
NS_IMETHODIMP
nsDOMWindowUtils::GetIsResolutionSet(bool* aIsResolutionSet) {
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsIPresShell* presShell = GetPresShell();
if (!presShell) {
@@ -715,9 +697,7 @@ nsDOMWindowUtils::SendMouseEventCommon(const nsAString& aType,
bool *aPreventDefault,
bool aIsSynthesized)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// get the widget to send the event to
nsPoint offset;
@@ -810,9 +790,7 @@ nsDOMWindowUtils::SendPointerEvent(const nsAString& aType,
uint8_t aOptionalArgCount,
bool* aPreventDefault)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// get the widget to send the event to
nsPoint offset;
@@ -884,9 +862,7 @@ nsDOMWindowUtils::SendWheelEvent(float aX,
int32_t aLineOrPageDeltaY,
uint32_t aOptions)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// get the widget to send the event to
nsPoint offset;
@@ -1022,9 +998,7 @@ nsDOMWindowUtils::SendTouchEventCommon(const nsAString& aType,
bool aToWindow,
bool* aPreventDefault)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// get the widget to send the event to
nsPoint offset;
@@ -1100,9 +1074,7 @@ nsDOMWindowUtils::SendKeyEvent(const nsAString& aType,
uint32_t aAdditionalFlags,
bool* aDefaultActionTaken)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// get the widget to send the event to
nsCOMPtr widget = GetWidget();
@@ -1214,9 +1186,7 @@ nsDOMWindowUtils::SendNativeKeyEvent(int32_t aNativeKeyboardLayout,
const nsAString& aCharacters,
const nsAString& aUnmodifiedCharacters)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// get the widget to send the event to
nsCOMPtr widget = GetWidget();
@@ -1234,9 +1204,7 @@ nsDOMWindowUtils::SendNativeMouseEvent(int32_t aScreenX,
int32_t aModifierFlags,
nsIDOMElement* aElement)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// get the widget to send the event to
nsCOMPtr widget = GetWidgetForElement(aElement);
@@ -1258,9 +1226,7 @@ nsDOMWindowUtils::SendNativeMouseScrollEvent(int32_t aScreenX,
uint32_t aAdditionalFlags,
nsIDOMElement* aElement)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// get the widget to send the event to
nsCOMPtr widget = GetWidgetForElement(aElement);
@@ -1284,9 +1250,7 @@ nsDOMWindowUtils::SendNativeTouchPoint(uint32_t aPointerId,
double aPressure,
uint32_t aOrientation)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr widget = GetWidget();
if (!widget) {
@@ -1308,9 +1272,7 @@ nsDOMWindowUtils::SendNativeTouchTap(int32_t aScreenX,
int32_t aScreenY,
bool aLongTap)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr widget = GetWidget();
if (!widget) {
@@ -1322,9 +1284,7 @@ nsDOMWindowUtils::SendNativeTouchTap(int32_t aScreenX,
NS_IMETHODIMP
nsDOMWindowUtils::ClearNativeTouchSequence()
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr widget = GetWidget();
if (!widget) {
@@ -1336,9 +1296,7 @@ nsDOMWindowUtils::ClearNativeTouchSequence()
NS_IMETHODIMP
nsDOMWindowUtils::ActivateNativeMenuItemAt(const nsAString& indexString)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// get the widget to send the event to
nsCOMPtr widget = GetWidget();
@@ -1351,9 +1309,7 @@ nsDOMWindowUtils::ActivateNativeMenuItemAt(const nsAString& indexString)
NS_IMETHODIMP
nsDOMWindowUtils::ForceUpdateNativeMenuAt(const nsAString& indexString)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// get the widget to send the event to
nsCOMPtr widget = GetWidget();
@@ -1407,9 +1363,7 @@ nsDOMWindowUtils::GetWidgetForElement(nsIDOMElement* aElement)
NS_IMETHODIMP
nsDOMWindowUtils::Focus(nsIDOMElement* aElement)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
@@ -1429,13 +1383,7 @@ nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener *aListener,
{
PROFILER_LABEL("nsDOMWindowUtils", "GarbageCollect",
js::ProfileEntry::Category::GC);
-
- // Always permit this in debug builds.
-#ifndef DEBUG
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
-#endif
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsJSContext::GarbageCollectNow(JS::gcreason::DOM_UTILS);
nsJSContext::CycleCollectNow(aListener, aExtraForgetSkippableCalls);
@@ -1447,12 +1395,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener *aListener,
int32_t aExtraForgetSkippableCalls)
{
- // Always permit this in debug builds.
-#ifndef DEBUG
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
-#endif
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsJSContext::CycleCollectNow(aListener, aExtraForgetSkippableCalls);
return NS_OK;
@@ -1461,9 +1404,7 @@ nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener *aListener,
NS_IMETHODIMP
nsDOMWindowUtils::RunNextCollectorTimer()
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsJSContext::RunNextCollectorTimer();
@@ -1479,9 +1420,7 @@ nsDOMWindowUtils::SendSimpleGestureEvent(const nsAString& aType,
int32_t aModifiers,
uint32_t aClickCount)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// get the widget to send the event to
nsPoint offset;
@@ -1546,9 +1485,7 @@ nsDOMWindowUtils::ElementFromPoint(float aX, float aY,
bool aFlushLayout,
nsIDOMElement** aReturn)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr doc = GetDocument();
NS_ENSURE_STATE(doc);
@@ -1568,9 +1505,7 @@ nsDOMWindowUtils::NodesFromRect(float aX, float aY,
bool aFlushLayout,
nsIDOMNodeList** aReturn)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr doc = GetDocument();
NS_ENSURE_STATE(doc);
@@ -1583,9 +1518,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::GetTranslationNodes(nsIDOMNode* aRoot,
nsITranslationNodeList** aRetVal)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
NS_ENSURE_ARG_POINTER(aRetVal);
nsCOMPtr root = do_QueryInterface(aRoot);
@@ -1686,9 +1619,7 @@ nsDOMWindowUtils::CompareCanvases(nsIDOMHTMLCanvasElement *aCanvas1,
uint32_t* aMaxDifference,
uint32_t* retVal)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
if (aCanvas1 == nullptr ||
aCanvas2 == nullptr ||
@@ -1754,9 +1685,7 @@ nsDOMWindowUtils::CompareCanvases(nsIDOMHTMLCanvasElement *aCanvas1,
NS_IMETHODIMP
nsDOMWindowUtils::GetIsMozAfterPaintPending(bool *aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
NS_ENSURE_ARG_POINTER(aResult);
*aResult = false;
@@ -1770,9 +1699,7 @@ nsDOMWindowUtils::GetIsMozAfterPaintPending(bool *aResult)
NS_IMETHODIMP
nsDOMWindowUtils::ClearMozAfterPaintEvents()
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsPresContext* presContext = GetPresContext();
if (!presContext)
@@ -1784,9 +1711,7 @@ nsDOMWindowUtils::ClearMozAfterPaintEvents()
NS_IMETHODIMP
nsDOMWindowUtils::DisableNonTestMouseEvents(bool aDisable)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
@@ -1801,9 +1726,7 @@ nsDOMWindowUtils::DisableNonTestMouseEvents(bool aDisable)
NS_IMETHODIMP
nsDOMWindowUtils::SuppressEventHandling(bool aSuppress)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr doc = GetDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
@@ -1819,9 +1742,7 @@ nsDOMWindowUtils::SuppressEventHandling(bool aSuppress)
static nsresult
getScrollXYAppUnits(nsWeakPtr aWindow, bool aFlushLayout, nsPoint& aScrollPos) {
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(aWindow);
nsCOMPtr doc = window ? window->GetExtantDoc() : nullptr;
@@ -1869,9 +1790,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::GetScrollbarSize(bool aFlushLayout, int32_t* aWidth,
int32_t* aHeight)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
*aWidth = 0;
*aHeight = 0;
@@ -1900,9 +1819,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::GetBoundsWithoutFlushing(nsIDOMElement *aElement,
nsIDOMClientRect** aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
@@ -1928,9 +1845,7 @@ nsDOMWindowUtils::GetBoundsWithoutFlushing(nsIDOMElement *aElement,
NS_IMETHODIMP
nsDOMWindowUtils::GetRootBounds(nsIDOMClientRect** aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsIDocument* doc = GetDocument();
NS_ENSURE_STATE(doc);
@@ -1961,9 +1876,7 @@ nsDOMWindowUtils::GetRootBounds(nsIDOMClientRect** aResult)
NS_IMETHODIMP
nsDOMWindowUtils::GetIMEIsOpen(bool *aState)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
NS_ENSURE_ARG_POINTER(aState);
@@ -1987,9 +1900,7 @@ nsDOMWindowUtils::GetIMEIsOpen(bool *aState)
NS_IMETHODIMP
nsDOMWindowUtils::GetIMEStatus(uint32_t *aState)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
NS_ENSURE_ARG_POINTER(aState);
@@ -2005,9 +1916,7 @@ nsDOMWindowUtils::GetIMEStatus(uint32_t *aState)
NS_IMETHODIMP
nsDOMWindowUtils::GetFocusedInputType(char** aType)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
NS_ENSURE_ARG_POINTER(aType);
@@ -2025,9 +1934,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::FindElementWithViewId(nsViewID aID,
nsIDOMElement** aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsRefPtr content = nsLayoutUtils::FindContentFor(aID);
return content ? CallQueryInterface(content, aResult) : NS_OK;
@@ -2056,9 +1963,7 @@ nsDOMWindowUtils::GetFullZoom(float* aFullZoom)
{
*aFullZoom = 1.0f;
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsPresContext* presContext = GetPresContext();
if (!presContext) {
@@ -2076,9 +1981,7 @@ nsDOMWindowUtils::DispatchDOMEventViaPresShell(nsIDOMNode* aTarget,
bool aTrusted,
bool* aRetVal)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
NS_ENSURE_STATE(aEvent);
aEvent->SetTrusted(aTrusted);
@@ -2117,9 +2020,7 @@ nsDOMWindowUtils::SendCompositionEvent(const nsAString& aType,
const nsAString& aData,
const nsAString& aLocale)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// get the widget to send the event to
nsCOMPtr widget = GetWidget();
@@ -2160,9 +2061,7 @@ nsDOMWindowUtils::CreateCompositionStringSynthesizer(
NS_ENSURE_ARG_POINTER(aResult);
*aResult = nullptr;
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(window, NS_ERROR_NOT_AVAILABLE);
@@ -2180,9 +2079,7 @@ nsDOMWindowUtils::SendQueryContentEvent(uint32_t aType,
{
*aResult = nullptr;
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
@@ -2282,9 +2179,7 @@ nsDOMWindowUtils::SendSelectionSetEvent(uint32_t aOffset,
{
*aResult = false;
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// get the widget to send the event to
nsCOMPtr widget = GetWidget();
@@ -2313,9 +2208,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::SendContentCommandEvent(const nsAString& aType,
nsITransferable * aTransferable)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// get the widget to send the event to
nsCOMPtr widget = GetWidget();
@@ -2353,9 +2246,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::GetClassName(JS::Handle aObject, JSContext* aCx,
char** aName)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// Our argument must be a non-null object.
if (aObject.isPrimitive()) {
@@ -2374,9 +2265,7 @@ nsDOMWindowUtils::GetVisitedDependentComputedStyle(
{
aResult.Truncate();
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
@@ -2396,9 +2285,7 @@ nsDOMWindowUtils::GetVisitedDependentComputedStyle(
NS_IMETHODIMP
nsDOMWindowUtils::EnterModalState()
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
@@ -2410,9 +2297,7 @@ nsDOMWindowUtils::EnterModalState()
NS_IMETHODIMP
nsDOMWindowUtils::LeaveModalState()
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
@@ -2424,9 +2309,7 @@ nsDOMWindowUtils::LeaveModalState()
NS_IMETHODIMP
nsDOMWindowUtils::IsInModalState(bool *retval)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
@@ -2440,9 +2323,7 @@ nsDOMWindowUtils::GetParent(JS::Handle aObject,
JSContext* aCx,
JS::MutableHandle aParent)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// First argument must be an object.
if (aObject.isPrimitive()) {
@@ -2465,9 +2346,7 @@ nsDOMWindowUtils::GetParent(JS::Handle aObject,
NS_IMETHODIMP
nsDOMWindowUtils::GetOuterWindowID(uint64_t *aWindowID)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
@@ -2480,9 +2359,7 @@ nsDOMWindowUtils::GetOuterWindowID(uint64_t *aWindowID)
NS_IMETHODIMP
nsDOMWindowUtils::GetCurrentInnerWindowID(uint64_t *aWindowID)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(window, NS_ERROR_NOT_AVAILABLE);
@@ -2500,9 +2377,7 @@ nsDOMWindowUtils::GetCurrentInnerWindowID(uint64_t *aWindowID)
NS_IMETHODIMP
nsDOMWindowUtils::SuspendTimeouts()
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
@@ -2515,9 +2390,7 @@ nsDOMWindowUtils::SuspendTimeouts()
NS_IMETHODIMP
nsDOMWindowUtils::ResumeTimeouts()
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
@@ -2530,9 +2403,7 @@ nsDOMWindowUtils::ResumeTimeouts()
NS_IMETHODIMP
nsDOMWindowUtils::GetLayerManagerType(nsAString& aType)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr widget = GetWidget();
if (!widget)
@@ -2550,9 +2421,7 @@ nsDOMWindowUtils::GetLayerManagerType(nsAString& aType)
NS_IMETHODIMP
nsDOMWindowUtils::GetLayerManagerRemote(bool* retval)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr widget = GetWidget();
if (!widget)
@@ -2569,9 +2438,7 @@ nsDOMWindowUtils::GetLayerManagerRemote(bool* retval)
NS_IMETHODIMP
nsDOMWindowUtils::StartFrameTimeRecording(uint32_t *startIndex)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
NS_ENSURE_ARG_POINTER(startIndex);
@@ -2598,9 +2465,7 @@ nsDOMWindowUtils::StopFrameTimeRecording(uint32_t startIndex,
uint32_t *frameCount,
float **frameIntervals)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
NS_ENSURE_ARG_POINTER(frameCount);
NS_ENSURE_ARG_POINTER(frameIntervals);
@@ -2630,9 +2495,7 @@ nsDOMWindowUtils::StopFrameTimeRecording(uint32_t startIndex,
NS_IMETHODIMP
nsDOMWindowUtils::BeginTabSwitch()
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr widget = GetWidget();
if (!widget)
@@ -2673,9 +2536,7 @@ ComputeAnimationValue(nsCSSProperty aProperty,
NS_IMETHODIMP
nsDOMWindowUtils::AdvanceTimeAndRefresh(int64_t aMilliseconds)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsRefreshDriver* driver = GetPresContext()->RefreshDriver();
driver->AdvanceTimeAndRefresh(aMilliseconds);
@@ -2691,9 +2552,7 @@ nsDOMWindowUtils::AdvanceTimeAndRefresh(int64_t aMilliseconds)
NS_IMETHODIMP
nsDOMWindowUtils::RestoreNormalRefresh()
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// Kick the compositor out of test mode before the refresh driver, so that
// the refresh driver doesn't send an update that gets ignored by the
@@ -2712,9 +2571,7 @@ nsDOMWindowUtils::RestoreNormalRefresh()
NS_IMETHODIMP
nsDOMWindowUtils::GetIsTestControllingRefreshes(bool *aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsPresContext* pc = GetPresContext();
*aResult =
@@ -2779,9 +2636,7 @@ nsDOMWindowUtils::ComputeAnimationDistance(nsIDOMElement* aElement,
const nsAString& aValue2,
double* aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsresult rv;
nsCOMPtr content = do_QueryInterface(aElement, &rv);
@@ -2825,9 +2680,7 @@ nsDOMWindowUtils::RenderDocument(const nsRect& aRect,
nscolor aBackgroundColor,
gfxContext* aThebesContext)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr doc = GetDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
@@ -2843,9 +2696,7 @@ nsDOMWindowUtils::RenderDocument(const nsRect& aRect,
NS_IMETHODIMP
nsDOMWindowUtils::GetCursorType(int16_t *aCursor)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
NS_ENSURE_ARG_POINTER(aCursor);
@@ -2878,9 +2729,7 @@ nsDOMWindowUtils::GetCursorType(int16_t *aCursor)
NS_IMETHODIMP
nsDOMWindowUtils::GetDisplayDPI(float *aDPI)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr widget = GetWidget();
if (!widget)
@@ -2896,9 +2745,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::GetOuterWindowWithId(uint64_t aWindowID,
nsIDOMWindow** aWindow)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// XXX This method is deprecated. See bug 865664.
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
@@ -2915,9 +2762,7 @@ nsDOMWindowUtils::GetOuterWindowWithId(uint64_t aWindowID,
NS_IMETHODIMP
nsDOMWindowUtils::GetContainerElement(nsIDOMElement** aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
@@ -2933,9 +2778,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::WrapDOMFile(nsIFile *aFile,
nsIDOMFile **aDOMFile)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
if (!aFile) {
return NS_ERROR_FAILURE;
@@ -2980,9 +2823,7 @@ CheckLeafLayers(Layer* aLayer, const nsIntPoint& aOffset, nsIntRegion* aCoveredR
NS_IMETHODIMP
nsDOMWindowUtils::LeafLayersPartitionWindow(bool* aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
*aResult = true;
#ifdef DEBUG
@@ -3014,9 +2855,7 @@ nsDOMWindowUtils::LeafLayersPartitionWindow(bool* aResult)
NS_IMETHODIMP
nsDOMWindowUtils::GetMayHaveTouchEventListeners(bool* aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
@@ -3029,9 +2868,7 @@ nsDOMWindowUtils::GetMayHaveTouchEventListeners(bool* aResult)
NS_IMETHODIMP
nsDOMWindowUtils::CheckAndClearPaintedState(nsIDOMElement* aElement, bool* aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
if (!aElement) {
return NS_ERROR_INVALID_ARG;
@@ -3066,9 +2903,7 @@ nsDOMWindowUtils::CheckAndClearPaintedState(nsIDOMElement* aElement, bool* aResu
NS_IMETHODIMP
nsDOMWindowUtils::EnableDialogs()
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
@@ -3117,9 +2952,7 @@ GetFileOrBlob(const nsAString& aName, JS::Handle aBlobParts,
JS::Handle aParameters, JSContext* aCx,
uint8_t aOptionalArgCount, nsISupports** aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsresult rv;
@@ -3152,9 +2985,7 @@ nsDOMWindowUtils::GetFile(const nsAString& aName, JS::Handle aBlobPar
JS::Handle aParameters, JSContext* aCx,
uint8_t aOptionalArgCount, nsIDOMFile** aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr file;
nsresult rv = GetFileOrBlob(aName, aBlobParts, aParameters, aCx,
@@ -3172,9 +3003,7 @@ nsDOMWindowUtils::GetBlob(JS::Handle aBlobParts,
JS::Handle aParameters, JSContext* aCx,
uint8_t aOptionalArgCount, nsIDOMBlob** aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr blob;
nsresult rv = GetFileOrBlob(NullString(), aBlobParts, aParameters, aCx,
@@ -3191,9 +3020,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::GetFileId(JS::Handle aFile, JSContext* aCx,
int64_t* aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
if (!aFile.isPrimitive()) {
JSObject* obj = aFile.toObjectOrNull();
@@ -3225,9 +3052,7 @@ nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName, int64_t aId,
int32_t* aSliceRefCnt, JSContext* aCx,
bool* aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
@@ -3268,9 +3093,7 @@ nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName, int64_t aId,
NS_IMETHODIMP
nsDOMWindowUtils::IsIncrementalGCEnabled(JSContext* cx, bool* aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
*aResult = JS::IsIncrementalGCEnabled(JS_GetRuntime(cx));
return NS_OK;
@@ -3279,9 +3102,7 @@ nsDOMWindowUtils::IsIncrementalGCEnabled(JSContext* cx, bool* aResult)
NS_IMETHODIMP
nsDOMWindowUtils::StartPCCountProfiling(JSContext* cx)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
js::StartPCCountProfiling(cx);
return NS_OK;
@@ -3290,9 +3111,7 @@ nsDOMWindowUtils::StartPCCountProfiling(JSContext* cx)
NS_IMETHODIMP
nsDOMWindowUtils::StopPCCountProfiling(JSContext* cx)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
js::StopPCCountProfiling(cx);
return NS_OK;
@@ -3301,9 +3120,7 @@ nsDOMWindowUtils::StopPCCountProfiling(JSContext* cx)
NS_IMETHODIMP
nsDOMWindowUtils::PurgePCCounts(JSContext* cx)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
js::PurgePCCounts(cx);
return NS_OK;
@@ -3312,9 +3129,7 @@ nsDOMWindowUtils::PurgePCCounts(JSContext* cx)
NS_IMETHODIMP
nsDOMWindowUtils::GetPCCountScriptCount(JSContext* cx, int32_t *result)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
*result = js::GetPCCountScriptCount(cx);
return NS_OK;
@@ -3323,9 +3138,7 @@ nsDOMWindowUtils::GetPCCountScriptCount(JSContext* cx, int32_t *result)
NS_IMETHODIMP
nsDOMWindowUtils::GetPCCountScriptSummary(int32_t script, JSContext* cx, nsAString& result)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
JSString *text = js::GetPCCountScriptSummary(cx, script);
if (!text)
@@ -3342,9 +3155,7 @@ nsDOMWindowUtils::GetPCCountScriptSummary(int32_t script, JSContext* cx, nsAStri
NS_IMETHODIMP
nsDOMWindowUtils::GetPCCountScriptContents(int32_t script, JSContext* cx, nsAString& result)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
JSString *text = js::GetPCCountScriptContents(cx, script);
if (!text)
@@ -3361,9 +3172,7 @@ nsDOMWindowUtils::GetPCCountScriptContents(int32_t script, JSContext* cx, nsAStr
NS_IMETHODIMP
nsDOMWindowUtils::GetPaintingSuppressed(bool *aPaintingSuppressed)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
@@ -3380,9 +3189,7 @@ nsDOMWindowUtils::GetPaintingSuppressed(bool *aPaintingSuppressed)
NS_IMETHODIMP
nsDOMWindowUtils::GetPlugins(JSContext* cx, JS::MutableHandle aPlugins)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr doc = GetDocument();
NS_ENSURE_STATE(doc);
@@ -3476,9 +3283,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::SetContentDocumentFixedPositionMargins(float aTop, float aRight,
float aBottom, float aLeft)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
if (!(aTop >= 0.0f && aRight >= 0.0f && aBottom >= 0.0f && aLeft >= 0.0f)) {
return NS_ERROR_ILLEGAL_VALUE;
@@ -3502,9 +3307,7 @@ nsresult
nsDOMWindowUtils::RemoteFrameFullscreenChanged(nsIDOMElement* aFrameElement,
const nsAString& aNewOrigin)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr doc = GetDocument();
NS_ENSURE_STATE(doc);
@@ -3516,9 +3319,7 @@ nsDOMWindowUtils::RemoteFrameFullscreenChanged(nsIDOMElement* aFrameElement,
nsresult
nsDOMWindowUtils::RemoteFrameFullscreenReverted()
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr doc = GetDocument();
NS_ENSURE_STATE(doc);
@@ -3530,9 +3331,7 @@ nsDOMWindowUtils::RemoteFrameFullscreenReverted()
nsresult
nsDOMWindowUtils::ExitFullscreen()
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsIDocument::ExitFullscreen(nullptr, /* async */ false);
return NS_OK;
@@ -3543,9 +3342,7 @@ nsDOMWindowUtils::SelectAtPoint(float aX, float aY, uint32_t aSelectBehavior,
bool *_retval)
{
*_retval = false;
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsSelectionAmount amount;
switch (aSelectBehavior) {
@@ -3635,9 +3432,7 @@ convertSheetType(uint32_t aSheetType)
NS_IMETHODIMP
nsDOMWindowUtils::LoadSheet(nsIURI *aSheetURI, uint32_t aSheetType)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
NS_ENSURE_ARG_POINTER(aSheetURI);
NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
@@ -3655,9 +3450,7 @@ nsDOMWindowUtils::LoadSheet(nsIURI *aSheetURI, uint32_t aSheetType)
NS_IMETHODIMP
nsDOMWindowUtils::RemoveSheet(nsIURI *aSheetURI, uint32_t aSheetType)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
NS_ENSURE_ARG_POINTER(aSheetURI);
NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
@@ -3676,9 +3469,7 @@ nsDOMWindowUtils::RemoveSheet(nsIURI *aSheetURI, uint32_t aSheetType)
NS_IMETHODIMP
nsDOMWindowUtils::GetIsHandlingUserInput(bool* aHandlingUserInput)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
*aHandlingUserInput = EventStateManager::IsHandlingUserInput();
@@ -3688,9 +3479,7 @@ nsDOMWindowUtils::GetIsHandlingUserInput(bool* aHandlingUserInput)
NS_IMETHODIMP
nsDOMWindowUtils::AllowScriptsToClose()
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
static_cast(window.get())->AllowScriptsToClose();
@@ -3700,9 +3489,7 @@ nsDOMWindowUtils::AllowScriptsToClose()
NS_IMETHODIMP
nsDOMWindowUtils::GetIsParentWindowMainWidgetVisible(bool* aIsVisible)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// this should reflect the "is parent window visible" logic in
// nsWindowWatcher::OpenWindowInternal()
@@ -3737,9 +3524,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::IsNodeDisabledForEvents(nsIDOMNode* aNode, bool* aRetVal)
{
*aRetVal = false;
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr n = do_QueryInterface(aNode);
nsINode* node = n;
while (node) {
@@ -3791,9 +3576,7 @@ nsDOMWindowUtils::DispatchEventToChromeOnly(nsIDOMEventTarget* aTarget,
bool* aRetVal)
{
*aRetVal = false;
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
NS_ENSURE_STATE(aTarget && aEvent);
aEvent->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
aTarget->DispatchEvent(aEvent, aRetVal);
@@ -3803,9 +3586,7 @@ nsDOMWindowUtils::DispatchEventToChromeOnly(nsIDOMEventTarget* aTarget,
NS_IMETHODIMP
nsDOMWindowUtils::RunInStableState(nsIRunnable *runnable)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr appShell(do_GetService(kAppShellCID));
if (!appShell) {
@@ -3818,9 +3599,7 @@ nsDOMWindowUtils::RunInStableState(nsIRunnable *runnable)
NS_IMETHODIMP
nsDOMWindowUtils::RunBeforeNextEvent(nsIRunnable *runnable)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr appShell(do_GetService(kAppShellCID));
if (!appShell) {
@@ -3835,9 +3614,7 @@ nsDOMWindowUtils::GetOMTAStyle(nsIDOMElement* aElement,
const nsAString& aProperty,
nsAString& aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr element = do_QueryInterface(aElement);
if (!element) {
@@ -3898,9 +3675,7 @@ nsDOMWindowUtils::GetOMTAOrComputedStyle(nsIDOMElement* aElement,
const nsAString& aProperty,
nsAString& aResult)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
// Try to get OMTA style
nsresult rv = GetOMTAStyle(aElement, aProperty, aResult);
@@ -3925,9 +3700,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::GetContentAPZTestData(JSContext* aContext,
JS::MutableHandleValue aOutContentTestData)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
if (nsIWidget* widget = GetWidget()) {
nsRefPtr lm = widget->GetLayerManager();
@@ -3946,9 +3719,7 @@ NS_IMETHODIMP
nsDOMWindowUtils::GetCompositorAPZTestData(JSContext* aContext,
JS::MutableHandleValue aOutCompositorTestData)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
if (nsIWidget* widget = GetWidget()) {
nsRefPtr lm = widget->GetLayerManager();
@@ -3968,9 +3739,7 @@ nsDOMWindowUtils::GetCompositorAPZTestData(JSContext* aContext,
NS_IMETHODIMP
nsDOMWindowUtils::GetAudioMuted(bool* aMuted)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
@@ -3981,9 +3750,7 @@ nsDOMWindowUtils::GetAudioMuted(bool* aMuted)
NS_IMETHODIMP
nsDOMWindowUtils::SetAudioMuted(bool aMuted)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
@@ -3994,9 +3761,7 @@ nsDOMWindowUtils::SetAudioMuted(bool aMuted)
NS_IMETHODIMP
nsDOMWindowUtils::GetAudioVolume(float* aVolume)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
@@ -4007,9 +3772,7 @@ nsDOMWindowUtils::GetAudioVolume(float* aVolume)
NS_IMETHODIMP
nsDOMWindowUtils::SetAudioVolume(float aVolume)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp
index 7dec36d5446..6f9343d8914 100644
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1176,10 +1176,23 @@ ContentParent::ShutDownProcess(bool aCloseWithError)
// shut down the cycle collector. But by then it's too late to release any
// CC'ed objects, so we need to null them out here, while we still can. See
// bug 899761.
- if (mMessageManager) {
- mMessageManager->Disconnect();
- mMessageManager = nullptr;
- }
+ ShutDownMessageManager();
+}
+
+void
+ContentParent::ShutDownMessageManager()
+{
+ if (!mMessageManager) {
+ return;
+ }
+
+ mMessageManager->ReceiveMessage(
+ static_cast(mMessageManager.get()),
+ CHILD_PROCESS_SHUTDOWN_MESSAGE, false,
+ nullptr, nullptr, nullptr, nullptr);
+
+ mMessageManager->Disconnect();
+ mMessageManager = nullptr;
}
void
@@ -1305,12 +1318,8 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
mForceKillTask = nullptr;
}
- nsRefPtr ppm = mMessageManager;
- if (ppm) {
- ppm->ReceiveMessage(static_cast(ppm.get()),
- CHILD_PROCESS_SHUTDOWN_MESSAGE, false,
- nullptr, nullptr, nullptr, nullptr);
- }
+ ShutDownMessageManager();
+
nsRefPtr kungFuDeathGrip(this);
nsCOMPtr obs = mozilla::services::GetObserverService();
if (obs) {
@@ -1321,10 +1330,6 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
}
}
- if (ppm) {
- ppm->Disconnect();
- }
-
// Tell the memory reporter manager that this ContentParent is going away.
nsRefPtr mgr =
nsMemoryReporterManager::GetOrCreate();
diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h
index 8c7f943f389..47d03b0c9f1 100644
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -334,6 +334,10 @@ private:
*/
void ShutDownProcess(bool aCloseWithError);
+ // Perform any steps necesssary to gracefully shtudown the message
+ // manager and null out mMessageManager.
+ void ShutDownMessageManager();
+
PCompositorParent*
AllocPCompositorParent(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess) MOZ_OVERRIDE;
diff --git a/dom/messages/SystemMessagePermissionsChecker.jsm b/dom/messages/SystemMessagePermissionsChecker.jsm
index cd37ba03e22..359ee3f5bfe 100644
--- a/dom/messages/SystemMessagePermissionsChecker.jsm
+++ b/dom/messages/SystemMessagePermissionsChecker.jsm
@@ -56,6 +56,9 @@ this.SystemMessagePermissionsTable = {
"bluetooth": []
},
"connection": { },
+ "captive-portal": {
+ "wifi-manage": []
+ },
"dummy-system-message": { }, // for system message testing framework
"headset-button": { },
"icc-stkcommand": {
diff --git a/dom/settings/tests/test_settings_blobs.html b/dom/settings/tests/test_settings_blobs.html
index f2b557775cc..fa5c0cea76c 100644
--- a/dom/settings/tests/test_settings_blobs.html
+++ b/dom/settings/tests/test_settings_blobs.html
@@ -45,7 +45,7 @@ function onFailure() {
let mozSettings = window.navigator.mozSettings;
let req;
-let storedBlob = new Blob([""], {"type": "text/xml"});
+let storedBlob = new Blob(['12345'], {"type": "text/plain"});
function checkBlob(blob) {
try {
diff --git a/dom/wifi/test/marionette/head.js b/dom/wifi/test/marionette/head.js
new file mode 100644
index 00000000000..ef37b2a2a9e
--- /dev/null
+++ b/dom/wifi/test/marionette/head.js
@@ -0,0 +1,731 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let Promise = SpecialPowers.Cu.import('resource://gre/modules/Promise.jsm').Promise;
+
+const STOCK_HOSTAPD_NAME = 'goldfish-hostapd';
+const HOSTAPD_CONFIG_PATH = '/data/misc/wifi/hostapd/';
+
+const HOSTAPD_COMMON_CONFIG = {
+ driver: 'test',
+ ctrl_interface: '/data/misc/wifi/hostapd',
+ test_socket: 'DIR:/data/misc/wifi/sockets',
+ hw_mode: 'b',
+ channel: '2',
+};
+
+const HOSTAPD_CONFIG_LIST = [
+ { ssid: 'ap0' },
+
+ { ssid: 'ap1',
+ wpa: 1,
+ wpa_pairwise: 'TKIP CCMP',
+ wpa_passphrase: '12345678'
+ },
+
+ { ssid: 'ap2',
+ wpa: 2,
+ rsn_pairwise: 'CCMP',
+ wpa_passphrase: '12345678',
+ },
+];
+
+let gTestSuite = (function() {
+ let suite = {};
+
+ // Private member variables of the returned object |suite|.
+ let wifiManager;
+ let wifiOrigEnabled;
+ let pendingEmulatorShellCount = 0;
+
+ /**
+ * Send emulator shell command with safe guard.
+ *
+ * We should only call |finish()| after all emulator command transactions
+ * end, so here comes with the pending counter. Resolve when the emulator
+ * gives positive response, and reject otherwise.
+ *
+ * Fulfill params:
+ * result -- an array of emulator response lines.
+ * Reject params:
+ * result -- an array of emulator response lines.
+ *
+ * @param aCommand
+ * A string command to be passed to emulator through its telnet console.
+ *
+ * @return A deferred promise.
+ */
+ function runEmulatorShellSafe(aCommand) {
+ let deferred = Promise.defer();
+
+ ++pendingEmulatorShellCount;
+ runEmulatorShell(aCommand, function(aResult) {
+ --pendingEmulatorShellCount;
+
+ ok(true, "Emulator shell response: " + JSON.stringify(aResult));
+ if (Array.isArray(aResult)) {
+ deferred.resolve(aResult);
+ } else {
+ deferred.reject(aResult);
+ }
+ });
+
+ return deferred.promise;
+ }
+
+ /**
+ * Wait for one named MozWifiManager event.
+ *
+ * Resolve if that named event occurs. Never reject.
+ *
+ * Fulfill params: the DOMEvent passed.
+ *
+ * @param aEventName
+ * A string event name.
+ *
+ * @return A deferred promise.
+ */
+ function waitForWifiManagerEventOnce(aEventName) {
+ let deferred = Promise.defer();
+
+ wifiManager.addEventListener(aEventName, function onevent(aEvent) {
+ wifiManager.removeEventListener(aEventName, onevent);
+
+ ok(true, "WifiManager event '" + aEventName + "' got.");
+ deferred.resolve(aEvent);
+ });
+
+ return deferred.promise;
+ }
+
+ /**
+ * Get the detail of currently running processes containing the given name.
+ *
+ * Use shell command 'ps' to get the desired process's detail. Never reject.
+ *
+ * Fulfill params:
+ * result -- an array of { pname, pid }
+ *
+ * @param aProcessName
+ * The process to get the detail.
+ *
+ * @return A deferred promise.
+ */
+ function getProcessDetail(aProcessName) {
+ return runEmulatorShellSafe(['ps'])
+ .then(processes => {
+ // Sample 'ps' output:
+ //
+ // USER PID PPID VSIZE RSS WCHAN PC NAME
+ // root 1 0 284 204 c009e6c4 0000deb4 S /init
+ // root 2 0 0 0 c0052c64 00000000 S kthreadd
+ // root 3 2 0 0 c0044978 00000000 S ksoftirqd/0
+ //
+ let detail = [];
+
+ processes.shift(); // Skip the first line.
+ for (let i = 0; i < processes.length; i++) {
+ let tokens = processes[i].split(/\s+/);
+ let pname = tokens[tokens.length - 1];
+ let pid = tokens[1];
+ if (-1 !== pname.indexOf(aProcessName)) {
+ detail.push({ pname: pname, pid: pid });
+ }
+ }
+
+ return detail;
+ });
+ }
+
+ /**
+ * Add required permissions for wifi testing. Never reject.
+ *
+ * The permissions required for wifi testing are 'wifi-manage' and 'settings-write'.
+ * Never reject.
+ *
+ * Fulfill params: (none)
+ *
+ * @return A deferred promise.
+ */
+ function addRequiredPermissions() {
+ let deferred = Promise.defer();
+
+ let permissions = [{ 'type': 'wifi-manage', 'allow': 1, 'context': window.document },
+ { 'type': 'settings-write', 'allow': 1, 'context': window.document }];
+
+ SpecialPowers.pushPermissions(permissions, function() {
+ deferred.resolve();
+ });
+
+ return deferred.promise;
+ }
+
+ /**
+ * Wrap DOMRequest onsuccess/onerror events to Promise resolve/reject.
+ *
+ * Fulfill params: A DOMEvent.
+ * Reject params: A DOMEvent.
+ *
+ * @param aRequest
+ * A DOMRequest instance.
+ *
+ * @return A deferred promise.
+ */
+ function wrapDomRequestAsPromise(aRequest) {
+ let deferred = Promise.defer();
+
+ ok(aRequest instanceof DOMRequest,
+ "aRequest is instanceof " + aRequest.constructor);
+
+ aRequest.addEventListener("success", function(aEvent) {
+ deferred.resolve(aEvent);
+ });
+ aRequest.addEventListener("error", function(aEvent) {
+ deferred.reject(aEvent);
+ });
+
+ return deferred.promise;
+ }
+
+ /**
+ * Ensure wifi is enabled/disabled.
+ *
+ * Issue a wifi enable/disable request if wifi is not in the desired state;
+ * return a resolved promise otherwise. Note that you cannot rely on this
+ * function to test the correctness of enabling/disabling wifi.
+ * (use requestWifiEnabled instead)
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @return a resolved promise or deferred promise.
+ */
+ function ensureWifiEnabled(aEnabled) {
+ if (wifiManager.enabled === aEnabled) {
+ log('Already ' + (aEnabled ? 'enabled' : 'disabled'));
+ return Promise.resolve();
+ }
+ return requestWifiEnabled(aEnabled);
+ }
+
+ /**
+ * Issue a request to enable/disable wifi.
+ *
+ * For current design, this function will attempt to enable/disable wifi by
+ * writing 'wifi.enabled' regardless of the wifi state.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @return A deferred promise.
+ */
+ function requestWifiEnabled(aEnabled) {
+ return Promise.all([
+ waitForWifiManagerEventOnce(aEnabled ? 'enabled' : 'disabled'),
+ setSettings({ 'wifi.enabled': aEnabled }),
+ ]);
+ }
+
+ /**
+ * Issue a request to scan all wifi available networks.
+ *
+ * Resolve when we get the scan result; reject when any error
+ * occurs.
+ *
+ * Fulfill params: An array of MozWifiNetwork
+ * Reject params: (none)
+ *
+ * @return A deferred promise.
+ */
+ function requestWifiScan() {
+ let request = wifiManager.getNetworks();
+ return wrapDomRequestAsPromise(request)
+ .then(event => event.target.result);
+ }
+
+ /**
+ * Request wifi scan and verify the scan result as well.
+ *
+ * Issue a wifi scan request and check if the result is expected.
+ * Since the old APs may be cached and the newly added APs may be
+ * still not scan-able, a couple of attempts are acceptable.
+ * Resolve if we eventually get the expected scan result; reject otherwise.
+ *
+ * Fulfill params: The scan result, which is an array of MozWifiNetwork
+ * Reject params: (none)
+ *
+ * @param aRetryCnt
+ * The maxmimum number of attempts until we get the expected scan result.
+ * @param aExpectedNetworks
+ * An array of object, each of which contains at least the |ssid| property.
+ *
+ * @return A deferred promise.
+ */
+ function testWifiScanWithRetry(aRetryCnt, aExpectedNetworks) {
+
+ // Check if every single ssid of each |aScanResult| exists in |aExpectedNetworks|
+ // as well as the length of |aScanResult| equals to |aExpectedNetworks|.
+ function isScanResultExpected(aScanResult) {
+ if (aScanResult.length !== aExpectedNetworks.length) {
+ return false;
+ }
+
+ for (let i = 0; i < aScanResult.length; i++) {
+ if (-1 === getFirstIndexBySsid(aScanResult[i].ssid, aExpectedNetworks)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ return requestWifiScan()
+ .then(function (networks) {
+ if (isScanResultExpected(networks, aExpectedNetworks)) {
+ return networks;
+ }
+ if (aRetryCnt > 0) {
+ return testWifiScanWithRetry(aRetryCnt - 1, aExpectedNetworks);
+ }
+ throw 'Unexpected scan result!';
+ });
+ }
+
+ /**
+ * Set mozSettings values.
+ *
+ * Resolve if that mozSettings value is set successfully, reject otherwise.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @param aSettings
+ * An object of format |{key1: value1, key2: value2, ...}|.
+ * @param aAllowError [optional]
+ * A boolean value. If set to true, an error response won't be treated
+ * as test failure. Default: false.
+ *
+ * @return A deferred promise.
+ */
+ function setSettings(aSettings, aAllowError) {
+ let request = window.navigator.mozSettings.createLock().set(aSettings);
+ return wrapDomRequestAsPromise(request)
+ .then(function resolve() {
+ ok(true, "setSettings(" + JSON.stringify(aSettings) + ")");
+ }, function reject() {
+ ok(aAllowError, "setSettings(" + JSON.stringify(aSettings) + ")");
+ });
+ }
+
+ /**
+ * Start hostapd processes with given configuration list.
+ *
+ * For starting one hostapd, we need to generate a specific config file
+ * then launch a hostapd process with the confg file path passed. The
+ * config file is generated by two sources: one is the common
+ * part (HOSTAPD_COMMON_CONFIG) and the other is from the given |aConfigList|.
+ * Resolve when all the hostpads are requested to start. It is not guaranteed
+ * that all the hostapds will be up and running successfully. Never reject.
+ *
+ * Fulfill params: (none)
+ *
+ * @param aConfigList
+ * An array of config objects, each property in which will be
+ * output to the confg file with the format: [key]=[value] in one line.
+ * See http://hostap.epitest.fi/cgit/hostap/plain/hostapd/hostapd.conf
+ * for more information.
+ *
+ * @return A deferred promise.
+ */
+ function startHostapds(aConfigList) {
+
+ function createConfigFromCommon(aIndex) {
+ // Create an copy of HOSTAPD_COMMON_CONFIG.
+ let config = JSON.parse(JSON.stringify(HOSTAPD_COMMON_CONFIG));
+
+ // Add user config.
+ for (let key in aConfigList[aIndex]) {
+ config[key] = aConfigList[aIndex][key];
+ }
+
+ // 'interface' is a required field but no need of being configurable
+ // for a test case. So we initialize this field on our own.
+ config.interface = 'AP-' + aIndex;
+
+ return config;
+ }
+
+ function startOneHostapd(aIndex) {
+ let configFileName = HOSTAPD_CONFIG_PATH + 'ap' + aIndex + '.conf';
+ return writeHostapdConfFile(configFileName, createConfigFromCommon(aIndex))
+ .then(() => runEmulatorShellSafe(['hostapd', '-B', configFileName]))
+ .then(function (reply) {
+ // It may fail at the first time due to the previous ungracefully terminated one.
+ if (reply[0] === 'bind(PF_UNIX): Address already in use') {
+ return startOneHostapd(aIndex);
+ }
+ });
+ }
+
+ return Promise.all(aConfigList.map(function(aConfig, aIndex) {
+ return startOneHostapd(aIndex);
+ }));
+ }
+
+ /**
+ * Kill all the running hostapd processes.
+ *
+ * Use shell command 'kill -9' to kill all hostapds. Never reject.
+ *
+ * Fulfill params: (none)
+ *
+ * @return A deferred promise.
+ */
+ function killAllHostapd() {
+ return getProcessDetail('hostapd')
+ .then(function (runningHostapds) {
+ let promises = runningHostapds.map(runningHostapd => {
+ return runEmulatorShellSafe(['kill', '-9', runningHostapd.pid]);
+ });
+ return Promise.all(promises);
+ });
+ }
+
+ /**
+ * Write out the config file to the given path.
+ *
+ * For each key/value pair in |aConfig|,
+ *
+ * [key]=[value]
+ *
+ * will be output to one new line. Never reject.
+ *
+ * Fulfill params: (none)
+ *
+ * @param aFilePath
+ * The file path that we desire the config file to be located.
+ *
+ * @param aConfig
+ * The config object.
+ *
+ * @return A deferred promise.
+ */
+ function writeHostapdConfFile(aFilePath, aConfig) {
+ let content = '';
+ for (let key in aConfig) {
+ if (aConfig.hasOwnProperty(key)) {
+ content += (key + '=' + aConfig[key] + '\n');
+ }
+ }
+ return writeFile(aFilePath, content);
+ }
+
+ /**
+ * Write file to the given path filled with given content.
+ *
+ * For now it is implemented by shell command 'echo'. Also, if the
+ * content contains whitespace, we need to quote the content to
+ * avoid error. Never reject.
+ *
+ * Fulfill params: (none)
+ *
+ * @param aFilePath
+ * The file path that we desire the file to be located.
+ *
+ * @param aContent
+ * The content as string which should be written to the file.
+ *
+ * @return A deferred promise.
+ */
+ function writeFile(aFilePath, aContent) {
+ if (-1 === aContent.indexOf(' ')) {
+ aContent = '"' + aContent + '"';
+ }
+ return runEmulatorShellSafe(['echo', aContent, '>', aFilePath]);
+ }
+
+ /**
+ * Check if a init service is running or not.
+ *
+ * Check the android property 'init.svc.[aServiceName]' to determine if
+ * a init service is running. Reject if the propery is neither 'running'
+ * nor 'stopped'.
+ *
+ * Fulfill params:
+ * result -- |true| if the init service is running; |false| otherwise.
+ * Reject params: (none)
+ *
+ * @param aServiceName
+ * The init service name.
+ *
+ * @return A deferred promise.
+ */
+ function isInitServiceRunning(aServiceName) {
+ return runEmulatorShellSafe(['getprop', 'init.svc.' + aServiceName])
+ .then(function (result) {
+ if ('running' !== result[0] && 'stopped' !== result[0]) {
+ throw 'Init service running state should be "running" or "stopped".';
+ }
+ return 'running' === result[0];
+ });
+ }
+
+ /**
+ * Wait for timeout.
+ *
+ * Resolve when the given duration elapsed. Never reject.
+ *
+ * Fulfill params: (none)
+ *
+ * @param aTimeoutMs
+ * The duration after which the timeout event should occurs.
+ *
+ * @return A deferred promise.
+ */
+ function waitForTimeout(aTimeoutMs) {
+ let deferred = Promise.defer();
+
+ setTimeout(function() {
+ deferred.resolve();
+ }, aTimeoutMs);
+
+ return deferred.promise;
+ }
+
+ /**
+ * Start or stop an init service.
+ *
+ * Use shell command 'start'/'stop' to start/stop an init service.
+ * The running state will also be checked after we start/stop the service.
+ * Resolve if the service is successfully started/stopped; Reject otherwise.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @param aServiceName
+ * The name of the service we want to start/stop.
+ *
+ * @param aStart
+ * |true| for starting the init service. |false| for stopping.
+ *
+ * @return A deferred promise.
+ */
+ function startStopInitService(aServiceName, aStart) {
+ let retryCnt = 5;
+
+ return runEmulatorShellSafe([aStart ? 'start' : 'stop', aServiceName])
+ .then(() => isInitServiceRunning(aServiceName))
+ .then(function onIsServiceRunningResolved(aIsRunning) {
+ if (aStart === aIsRunning) {
+ return;
+ }
+
+ if (retryCnt-- > 0) {
+ log('Failed to ' + (aStart ? 'start ' : 'stop ') + aServiceName +
+ '. Retry: ' + retryCnt);
+
+ return waitForTimeout(500)
+ .then(() => isInitServiceRunning(aServiceName))
+ .then(onIsServiceRunningResolved);
+ }
+
+ throw 'Failed to ' + (aStart ? 'start' : 'stop') + ' ' + aServiceName;
+ });
+ }
+
+ /**
+ * Start the stock hostapd.
+ *
+ * Since the stock hostapd is an init service, use |startStopInitService| to
+ * start it. Note that we might fail to start the stock hostapd at the first time
+ * for unknown reason so give it the second chance to start again.
+ * Resolve when we are eventually successful to start the stock hostapd; Reject
+ * otherwise.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @return A deferred promise.
+ */
+ function startStockHostapd() {
+ return startStopInitService(STOCK_HOSTAPD_NAME, true)
+ .then(null, function onreject() {
+ log('Failed to restart goldfish-hostapd at the first time. Try again!');
+ return startStopInitService((STOCK_HOSTAPD_NAME), true);
+ });
+ }
+
+ /**
+ * Stop the stock hostapd.
+ *
+ * Since the stock hostapd is an init service, use |startStopInitService| to
+ * stop it.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @return A deferred promise.
+ */
+ function stopStockHostapd() {
+ return startStopInitService(STOCK_HOSTAPD_NAME, false);
+ }
+
+ /**
+ * Get the index of the first matching entry by |ssid|.
+ *
+ * Find the index of the first entry of |aArray| which property |ssid|
+ * is same as |aSsid|.
+ *
+ * @param aSsid
+ * The ssid that we want to match.
+ * @param aArray
+ * An array of objects, each of which should have the property |ssid|.
+ *
+ * @return The 0-based index of first matching entry if found; -1 otherwise.
+ */
+ function getFirstIndexBySsid(aSsid, aArray) {
+ for (let i = 0; i < aArray.length; i++) {
+ if (aArray[i].ssid === aSsid) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Count the number of running process and verify if the count is expected.
+ *
+ * Return a promise that resolves when the process has expected number
+ * of running instances and rejects otherwise.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @param aOrigWifiEnabled
+ * Boolean which indicates wifi was originally enabled.
+ *
+ * @return A deferred promise.
+ */
+ function verifyNumOfProcesses(aProcessName, aExpectedNum) {
+ return getProcessDetail(aProcessName)
+ .then(function (detail) {
+ if (detail.length === aExpectedNum) {
+ return;
+ }
+ throw 'Unexpected number of running processes:' + aProcessName +
+ ', expected: ' + aExpectedNum + ', actual: ' + detail.length;
+ });
+ }
+
+ /**
+ * Clean up all the allocated resources and running services for the test.
+ *
+ * After the test no matter success or failure, we should
+ * 1) Restore to the wifi original state (enabled or disabled)
+ * 2) Wait until all pending emulator shell commands are done.
+ *
+ * |finsih| will be called in the end.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @return A deferred promise.
+ */
+ function cleanUp() {
+ waitFor(function() {
+ return ensureWifiEnabled(wifiOrigEnabled)
+ .then(finish);
+ }, function() {
+ return pendingEmulatorShellCount === 0;
+ });
+ }
+
+ /**
+ * Init the test environment.
+ *
+ * Mainly add the required permissions and initialize the wifiManager
+ * and the orignal state of wifi. Reject if failing to create
+ * window.navigator.mozWifiManager; resolve if all is well.
+ *
+ * |finsih| will be called in the end.
+ *
+ * Fulfill params: (none)
+ * Reject params: The reject reason.
+ *
+ * @return A deferred promise.
+ */
+ function initTestEnvironment() {
+ return addRequiredPermissions()
+ .then(function() {
+ wifiManager = window.navigator.mozWifiManager;
+ if (!wifiManager) {
+ throw 'window.navigator.mozWifiManager is NULL';
+ }
+ wifiOrigEnabled = wifiManager.enabled;
+ });
+ }
+
+ //---------------------------------------------------
+ // Public test suite functions
+ //---------------------------------------------------
+ suite.getWifiManager = (() => wifiManager);
+ suite.ensureWifiEnabled = ensureWifiEnabled;
+ suite.requestWifiEnabled = requestWifiEnabled;
+ suite.startHostapds = startHostapds;
+ suite.getProcessDetail = getProcessDetail;
+ suite.killAllHostapd = killAllHostapd;
+ suite.wrapDomRequestAsPromise = wrapDomRequestAsPromise;
+ suite.waitForWifiManagerEventOnce = waitForWifiManagerEventOnce;
+ suite.verifyNumOfProcesses = verifyNumOfProcesses;
+ suite.testWifiScanWithRetry = testWifiScanWithRetry;
+ suite.getFirstIndexBySsid = getFirstIndexBySsid;
+
+ /**
+ * Common test routine.
+ *
+ * Start a test with the given test case chain. The test environment will be
+ * settled down before the test. After the test, all the affected things will
+ * be restored.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @param aTestCaseChain
+ * The test case entry point, which can be a function or a promise.
+ *
+ * @return A deferred promise.
+ */
+ suite.doTest = function(aTestCaseChain) {
+ return initTestEnvironment()
+ .then(aTestCaseChain)
+ .then(function onresolve() {
+ cleanUp();
+ }, function onreject(aReason) {
+ ok(false, 'Promise rejects during test' + (aReason ? '(' + aReason + ')' : ''));
+ cleanUp();
+ });
+ };
+
+ /**
+ * Common test routine without the presence of stock hostapd.
+ *
+ * Same as doTest except stopping the stock hostapd before test
+ * and restarting it after test.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @param aTestCaseChain
+ * The test case entry point, which can be a function or a promise.
+ *
+ * @return A deferred promise.
+ */
+ suite.doTestWithoutStockAp = function(aTestCaseChain) {
+ return suite.doTest(function() {
+ return stopStockHostapd()
+ .then(aTestCaseChain)
+ .then(startStockHostapd);
+ });
+ };
+
+ return suite;
+})();
diff --git a/dom/wifi/test/marionette/manifest.ini b/dom/wifi/test/marionette/manifest.ini
new file mode 100644
index 00000000000..f74e51c1388
--- /dev/null
+++ b/dom/wifi/test/marionette/manifest.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+b2g = true
+browser = false
+qemu = true
+
+[test_wifi_enable.js]
+[test_wifi_scan.js]
+[test_wifi_associate.js]
diff --git a/dom/wifi/test/marionette/test_wifi_associate.js b/dom/wifi/test/marionette/test_wifi_associate.js
new file mode 100644
index 00000000000..1c7fc6a0590
--- /dev/null
+++ b/dom/wifi/test/marionette/test_wifi_associate.js
@@ -0,0 +1,121 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = 'head.js';
+
+const SCAN_RETRY_CNT = 5;
+
+/**
+ * Test wifi association.
+ *
+ * Associate with the given network object which is obtained by
+ * MozWifiManager.getNetworks() (i.e. MozWifiNetwork).
+ * Resolve when the 'connected' status change event is received.
+ * Note that we might see other events like 'connecting'
+ * before 'connected'. So we need to call |waitForWifiManagerEventOnce|
+ * again whenever non 'connected' event is seen. Never reject.
+ *
+ * Fulfill params: (none)
+ *
+ * @param aNetwork
+ * An object of MozWifiNetwork.
+ *
+ * @return A deferred promise.
+ */
+function testAssociate(aNetwork) {
+ if (!setPasswordIfNeeded(aNetwork)) {
+ throw 'Failed to set password';
+ }
+
+ function waitForConnected() {
+ return gTestSuite.waitForWifiManagerEventOnce('statuschange')
+ .then(function onstatuschange(event) {
+ log("event.status: " + event.status);
+ log("event.network.ssid: " + (event.network ? event.network.ssid : ''));
+
+ if ("connected" === event.status &&
+ event.network.ssid === aNetwork.ssid) {
+ return; // Got expected 'connected' event from aNetwork.ssid.
+ }
+
+ log('Not expected "connected" statuschange event. Wait again!');
+ return waitForConnected();
+ });
+ }
+
+ let promises = [];
+
+ // Register the event listerner to wait for 'connected' event first
+ // to avoid racing issue.
+ promises.push(waitForConnected());
+
+ // Then we do the association.
+ let request = gTestSuite.getWifiManager().associate(aNetwork);
+ promises.push(gTestSuite.wrapDomRequestAsPromise(request));
+
+ return Promise.all(promises);
+}
+
+/**
+ * Convert the given MozWifiNetwork object array to testAssociate chain.
+ *
+ * @param aNetworks
+ * An array of MozWifiNetwork which we want to convert.
+ *
+ * @return A promise chain which "then"s testAssociate accordingly.
+ */
+function convertToTestAssociateChain(aNetworks) {
+ let chain = Promise.resolve();
+
+ aNetworks.forEach(function (aNetwork) {
+ chain = chain.then(() => testAssociate(aNetwork));
+ });
+
+ return chain;
+}
+
+/**
+ * Set the password for associating the given network if needed.
+ *
+ * Set the password by looking up HOSTAPD_CONFIG_LIST. This function
+ * will also set |keyManagement| properly.
+ *
+ * @param aNetwork
+ * The MozWifiNetwork object.
+ *
+ * @return |true| if either insesure or successfully set the password/keyManagement.
+ * |false| if the given network is not found in HOSTAPD_CONFIG_LIST.
+ */
+function setPasswordIfNeeded(aNetwork) {
+ let i = gTestSuite.getFirstIndexBySsid(aNetwork.ssid, HOSTAPD_CONFIG_LIST);
+ if (-1 === i) {
+ log('unknown ssid: ' + aNetwork.ssid);
+ return false; // Error!
+ }
+
+ if (!aNetwork.security.length) {
+ return true; // No need to set password.
+ }
+
+ let security = aNetwork.security[0];
+ if (/PSK$/.test(security)) {
+ aNetwork.psk = HOSTAPD_CONFIG_LIST[i].wpa_passphrase;
+ aNetwork.keyManagement = 'WPA-PSK';
+ } else if (/WEP$/.test(security)) {
+ aNetwork.wep = HOSTAPD_CONFIG_LIST[i].wpa_passphrase;
+ aNetwork.keyManagement = 'WEP';
+ }
+
+ return true;
+}
+
+gTestSuite.doTestWithoutStockAp(function() {
+ return gTestSuite.ensureWifiEnabled(true)
+ .then(() => gTestSuite.startHostapds(HOSTAPD_CONFIG_LIST))
+ .then(() => gTestSuite.verifyNumOfProcesses('hostapd', HOSTAPD_CONFIG_LIST.length))
+ .then(() => gTestSuite.testWifiScanWithRetry(SCAN_RETRY_CNT, HOSTAPD_CONFIG_LIST))
+ .then(networks => convertToTestAssociateChain(networks))
+ .then(gTestSuite.killAllHostapd)
+ .then(() => gTestSuite.verifyNumOfProcesses('hostapd', 0));
+});
diff --git a/dom/wifi/test/marionette/test_wifi_enable.js b/dom/wifi/test/marionette/test_wifi_enable.js
new file mode 100644
index 00000000000..6a1bec7a298
--- /dev/null
+++ b/dom/wifi/test/marionette/test_wifi_enable.js
@@ -0,0 +1,11 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = 'head.js';
+
+gTestSuite.doTest(function() {
+ return Promise.resolve()
+ .then(() => gTestSuite.ensureWifiEnabled(false))
+ .then(() => gTestSuite.requestWifiEnabled(true));
+});
\ No newline at end of file
diff --git a/dom/wifi/test/marionette/test_wifi_scan.js b/dom/wifi/test/marionette/test_wifi_scan.js
new file mode 100644
index 00000000000..4bb7d1a3d5d
--- /dev/null
+++ b/dom/wifi/test/marionette/test_wifi_scan.js
@@ -0,0 +1,43 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = 'head.js';
+
+const SCAN_RETRY_CNT = 5;
+
+/**
+ * Test scan with no AP present.
+ *
+ * The precondition is:
+ * 1) Wifi is enabled.
+ * 2) All the hostapds are turned off.
+ *
+ * @return deferred promise.
+ */
+function testScanNoAp() {
+ return gTestSuite.testWifiScanWithRetry(SCAN_RETRY_CNT, []);
+}
+
+/**
+ * Test scan with APs present.
+ *
+ * The precondition is:
+ * 1) Wifi is enabled.
+ * 2) All the hostapds are turned off.
+ *
+ * @return deferred promise.
+ */
+function testScanWithAps() {
+ return gTestSuite.startHostapds(HOSTAPD_CONFIG_LIST)
+ .then(() => gTestSuite.verifyNumOfProcesses('hostapd', HOSTAPD_CONFIG_LIST.length))
+ .then(() => gTestSuite.testWifiScanWithRetry(SCAN_RETRY_CNT, HOSTAPD_CONFIG_LIST))
+ .then(gTestSuite.killAllHostapd)
+ .then(() => gTestSuite.verifyNumOfProcesses('hostapd', 0));
+}
+
+gTestSuite.doTestWithoutStockAp(function() {
+ return gTestSuite.ensureWifiEnabled(true)
+ .then(testScanNoAp)
+ .then(testScanWithAps);
+});
diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp
index e6d89bf6d74..20f8ca6bd8c 100644
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -268,6 +268,7 @@ GLContextEGL::~GLContextEGL()
#endif
sEGLLibrary.fDestroyContext(EGL_DISPLAY(), mContext);
+ sEGLLibrary.UnsetCachedCurrentContext();
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 17
if (!mIsOffscreen) {
@@ -381,7 +382,18 @@ GLContextEGL::MakeCurrentImpl(bool aForce) {
// Assume that EGL has the same problem as WGL does,
// where MakeCurrent with an already-current context is
// still expensive.
- if (aForce || sEGLLibrary.fGetCurrentContext() != mContext) {
+ bool hasDifferentContext = false;
+ if (sEGLLibrary.CachedCurrentContext() != mContext) {
+ // even if the cached context doesn't match the current one
+ // might still
+ if (sEGLLibrary.fGetCurrentContext() != mContext) {
+ hasDifferentContext = true;
+ } else {
+ sEGLLibrary.SetCachedCurrentContext(mContext);
+ }
+ }
+
+ if (aForce || hasDifferentContext) {
EGLSurface surface = mSurfaceOverride != EGL_NO_SURFACE
? mSurfaceOverride
: mSurface;
@@ -402,7 +414,11 @@ GLContextEGL::MakeCurrentImpl(bool aForce) {
printf_stderr("EGL Error: 0x%04x\n", eglError);
#endif
}
+ } else {
+ sEGLLibrary.SetCachedCurrentContext(mContext);
}
+ } else {
+ MOZ_ASSERT(sEGLLibrary.CachedCurrentContextMatches());
}
return succeeded;
diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp
index 9eb895fe3f5..3a484189fbc 100644
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -6,6 +6,7 @@
#include "gfxCrashReporterUtils.h"
#include "mozilla/Preferences.h"
+#include "mozilla/Assertions.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsPrintfCString.h"
@@ -20,6 +21,9 @@ namespace mozilla {
namespace gl {
GLLibraryEGL sEGLLibrary;
+#ifdef MOZ_B2G
+ThreadLocal GLLibraryEGL::sCurrentContext;
+#endif
// should match the order of EGLExtensions, and be null-terminated.
static const char *sEGLExtensionNames[] = {
@@ -104,6 +108,11 @@ GLLibraryEGL::EnsureInitialized()
mozilla::ScopedGfxFeatureReporter reporter("EGL");
+#ifdef MOZ_B2G
+ if (!sCurrentContext.init())
+ MOZ_CRASH("Tls init failed");
+#endif
+
#ifdef XP_WIN
#ifdef MOZ_WEBGL
if (!mEGLLibrary) {
diff --git a/gfx/gl/GLLibraryEGL.h b/gfx/gl/GLLibraryEGL.h
index d34e2f67037..eaabf32681d 100644
--- a/gfx/gl/GLLibraryEGL.h
+++ b/gfx/gl/GLLibraryEGL.h
@@ -10,7 +10,7 @@
#endif
#include "GLLibraryLoader.h"
-
+#include "mozilla/ThreadLocal.h"
#include "nsIFile.h"
#include
@@ -529,6 +529,33 @@ public:
static void AfterGLCall(const char* glFunction);
#endif
+#ifdef MOZ_B2G
+ EGLContext CachedCurrentContext() {
+ return sCurrentContext.get();
+ }
+ void UnsetCachedCurrentContext() {
+ sCurrentContext.set(nullptr);
+ }
+ void SetCachedCurrentContext(EGLContext aCtx) {
+ sCurrentContext.set(aCtx);
+ }
+ bool CachedCurrentContextMatches() {
+ return sCurrentContext.get() == fGetCurrentContext();
+ }
+
+private:
+ static ThreadLocal sCurrentContext;
+public:
+
+#else
+ EGLContext CachedCurrentContext() {
+ return nullptr;
+ }
+ void UnsetCachedCurrentContext() {}
+ void SetCachedCurrentContext(EGLContext aCtx) { }
+ bool CachedCurrentContextMatches() { return true; }
+#endif
+
private:
bool mInitialized;
PRLibrary* mEGLLibrary;
diff --git a/gfx/layers/LayerTreeInvalidation.cpp b/gfx/layers/LayerTreeInvalidation.cpp
index 470f29b4183..567171a9766 100644
--- a/gfx/layers/LayerTreeInvalidation.cpp
+++ b/gfx/layers/LayerTreeInvalidation.cpp
@@ -69,12 +69,12 @@ AddRegion(nsIntRegion& aDest, const nsIntRegion& aSource)
aDest.SimplifyOutward(20);
}
+
static nsIntRegion
-TransformRegion(const nsIntRegion& aRegion, const gfx3DMatrix& aTransform)
+TransformRegion(nsIntRegion& aRegion, const gfx3DMatrix& aTransform)
{
- nsIntRegion result;
- AddTransformedRegion(result, aRegion, aTransform);
- return result;
+ aRegion.Transform(aTransform);
+ return aRegion;
}
/**
diff --git a/gfx/src/nsRegion.cpp b/gfx/src/nsRegion.cpp
index 12daef16d30..e91a2877932 100644
--- a/gfx/src/nsRegion.cpp
+++ b/gfx/src/nsRegion.cpp
@@ -6,7 +6,8 @@
#include "nsRegion.h"
#include "nsPrintfCString.h"
#include "nsTArray.h"
-
+#include "gfx3DMatrix.h"
+#include "gfxUtils.h"
bool nsRegion::Contains(const nsRegion& aRgn) const
{
@@ -445,6 +446,44 @@ nsRegion& nsRegion::ScaleInverseRoundOut (float aXScale, float aYScale)
return *this;
}
+static nsIntRect
+TransformRect(const nsIntRect& aRect, const gfx3DMatrix& aTransform)
+{
+ if (aRect.IsEmpty()) {
+ return nsIntRect();
+ }
+
+ gfxRect rect(aRect.x, aRect.y, aRect.width, aRect.height);
+ rect = aTransform.TransformBounds(rect);
+ rect.RoundOut();
+
+ nsIntRect intRect;
+ if (!gfxUtils::GfxRectToIntRect(rect, &intRect)) {
+ return nsIntRect();
+ }
+
+ return intRect;
+}
+
+nsRegion& nsRegion::Transform (const gfx3DMatrix &aTransform)
+{
+ int n;
+ pixman_box32_t *boxes = pixman_region32_rectangles(&mImpl, &n);
+ for (int i=0; i> 8) & 0xff;
switch (block) {
case 0x05:
@@ -188,12 +188,15 @@ gfxAndroidPlatform::GetCommonFallbackFonts(const uint32_t aCh,
aFontList.AppendElement("Droid Sans Arabic");
break;
case 0x09:
+ aFontList.AppendElement("Noto Sans Devanagari");
aFontList.AppendElement("Droid Sans Devanagari");
break;
case 0x0b:
+ aFontList.AppendElement("Noto Sans Tamil");
aFontList.AppendElement("Droid Sans Tamil");
break;
case 0x0e:
+ aFontList.AppendElement("Noto Sans Thai");
aFontList.AppendElement("Droid Sans Thai");
break;
case 0x10: case 0x2d:
diff --git a/gfx/thebes/gfxDWriteFonts.cpp b/gfx/thebes/gfxDWriteFonts.cpp
index 38c16bdd664..f188da3ca35 100644
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -7,9 +7,7 @@
#include "mozilla/MemoryReporting.h"
-#include "gfxHarfBuzzShaper.h"
#include
-#include "gfxGraphiteShaper.h"
#include "gfxDWriteFontList.h"
#include "gfxContext.h"
#include
@@ -106,14 +104,6 @@ gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry,
}
ComputeMetrics(anAAOption);
-
- if (FontCanSupportGraphite()) {
- mGraphiteShaper = new gfxGraphiteShaper(this);
- }
-
- if (FontCanSupportHarfBuzz()) {
- mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
- }
}
gfxDWriteFont::~gfxDWriteFont()
@@ -134,32 +124,6 @@ gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
&mStyle, mNeedsBold, anAAOption);
}
-bool
-gfxDWriteFont::ShapeText(gfxContext *aContext,
- const char16_t *aText,
- uint32_t aOffset,
- uint32_t aLength,
- int32_t aScript,
- gfxShapedText *aShapedText,
- bool aPreferPlatformShaping)
-{
- bool ok = false;
-
- if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
- ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
- aScript, aShapedText);
- }
-
- if (!ok && mHarfBuzzShaper) {
- ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
- aScript, aShapedText);
- }
-
- PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
-
- return ok;
-}
-
const gfxFont::Metrics&
gfxDWriteFont::GetMetrics()
{
diff --git a/gfx/thebes/gfxDWriteFonts.h b/gfx/thebes/gfxDWriteFonts.h
index 8ee972b553d..a2adea8ebf2 100644
--- a/gfx/thebes/gfxDWriteFonts.h
+++ b/gfx/thebes/gfxDWriteFonts.h
@@ -71,14 +71,6 @@ public:
virtual cairo_scaled_font_t *GetCairoScaledFont();
protected:
- virtual bool ShapeText(gfxContext *aContext,
- const char16_t *aText,
- uint32_t aOffset,
- uint32_t aLength,
- int32_t aScript,
- gfxShapedText *aShapedText,
- bool aPreferPlatformShaping = false);
-
bool GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics);
void ComputeMetrics(AntialiasOption anAAOption);
diff --git a/gfx/thebes/gfxFT2Fonts.cpp b/gfx/thebes/gfxFT2Fonts.cpp
index cb5088bcacd..fdc0e0e40cc 100644
--- a/gfx/thebes/gfxFT2Fonts.cpp
+++ b/gfx/thebes/gfxFT2Fonts.cpp
@@ -24,8 +24,6 @@
#include "gfxFT2Utils.h"
#include "gfxFT2FontList.h"
#include
-#include "gfxHarfBuzzShaper.h"
-#include "gfxGraphiteShaper.h"
#include "nsGkAtoms.h"
#include "nsTArray.h"
#include "nsUnicodeRange.h"
@@ -44,42 +42,20 @@
*/
bool
-gfxFT2Font::ShapeText(gfxContext *aContext,
+gfxFT2Font::ShapeText(gfxContext *aContext,
const char16_t *aText,
- uint32_t aOffset,
- uint32_t aLength,
- int32_t aScript,
- gfxShapedText *aShapedText,
- bool aPreferPlatformShaping)
+ uint32_t aOffset,
+ uint32_t aLength,
+ int32_t aScript,
+ gfxShapedText *aShapedText)
{
- bool ok = false;
-
- if (FontCanSupportGraphite()) {
- if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
- if (!mGraphiteShaper) {
- mGraphiteShaper = new gfxGraphiteShaper(this);
- }
- ok = mGraphiteShaper->ShapeText(aContext, aText,
- aOffset, aLength,
- aScript, aShapedText);
- }
- }
-
- if (!ok) {
- if (!mHarfBuzzShaper) {
- mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
- }
- ok = mHarfBuzzShaper->ShapeText(aContext, aText,
- aOffset, aLength,
- aScript, aShapedText);
- }
-
- if (!ok) {
+ if (!gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
+ aShapedText)) {
+ // harfbuzz must have failed(?!), just render raw glyphs
AddRange(aText, aOffset, aLength, aShapedText);
+ PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
}
- PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
-
return true;
}
diff --git a/gfx/thebes/gfxFT2Fonts.h b/gfx/thebes/gfxFT2Fonts.h
index 871b9397f9a..f0e390c5a60 100644
--- a/gfx/thebes/gfxFT2Fonts.h
+++ b/gfx/thebes/gfxFT2Fonts.h
@@ -77,8 +77,7 @@ protected:
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
- gfxShapedText *aShapedText,
- bool aPreferPlatformShaping);
+ gfxShapedText *aShapedText);
void FillGlyphDataForChar(uint32_t ch, CachedGlyphData *gd);
diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp
index 024f3bee0a6..3d4c1b68a83 100644
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -23,6 +23,7 @@
#include "gfxTypes.h"
#include "gfxContext.h"
#include "gfxFontMissingGlyphs.h"
+#include "gfxGraphiteShaper.h"
#include "gfxHarfBuzzShaper.h"
#include "gfxUserFontSet.h"
#include "gfxPlatformFontList.h"
@@ -44,6 +45,8 @@
#include "gfxMathTable.h"
#include "gfx2DGlue.h"
+#include "GreekCasing.h"
+
#if defined(XP_MACOSX)
#include "nsCocoaFeatures.h"
#endif
@@ -3942,8 +3945,7 @@ gfxFont::ShapeText(gfxContext *aContext,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
- gfxShapedText *aShapedText,
- bool aPreferPlatformShaping)
+ gfxShapedText *aShapedText)
{
nsDependentCSubstring ascii((const char*)aText, aLength);
nsAutoString utf16;
@@ -3952,7 +3954,7 @@ gfxFont::ShapeText(gfxContext *aContext,
return false;
}
return ShapeText(aContext, utf16.BeginReading(), aOffset, aLength,
- aScript, aShapedText, aPreferPlatformShaping);
+ aScript, aShapedText);
}
bool
@@ -3961,30 +3963,29 @@ gfxFont::ShapeText(gfxContext *aContext,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
- gfxShapedText *aShapedText,
- bool aPreferPlatformShaping)
+ gfxShapedText *aShapedText)
{
bool ok = false;
- if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
- ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
- aScript, aShapedText);
+ if (FontCanSupportGraphite()) {
+ if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
+ if (!mGraphiteShaper) {
+ mGraphiteShaper = new gfxGraphiteShaper(this);
+ }
+ ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
+ aScript, aShapedText);
+ }
}
- if (!ok && mHarfBuzzShaper && !aPreferPlatformShaping) {
+ if (!ok) {
+ if (!mHarfBuzzShaper) {
+ mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
+ }
ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
aScript, aShapedText);
}
- if (!ok) {
- if (!mPlatformShaper) {
- CreatePlatformShaper();
- }
- if (mPlatformShaper) {
- ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength,
- aScript, aShapedText);
- }
- }
+ NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text");
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
@@ -5709,8 +5710,8 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
// capitals where the accent is to be removed (bug 307039).
// These are handled by using the full-size font with the
// uppercasing transform.
- GreekCasing::State state;
- ch2 = GreekCasing::UpperCase(ch, state);
+ mozilla::GreekCasing::State state;
+ ch2 = mozilla::GreekCasing::UpperCase(ch, state);
if (ch != ch2) {
chCase = kSpecialUpper;
}
diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h
index cc9bde759ce..41f65b31be3 100644
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -1470,12 +1470,12 @@ public:
// Shape a piece of text and store the resulting glyph data into
// aShapedText. Parameters aOffset/aLength indicate the range of
// aShapedText to be updated; aLength is also the length of aText.
- virtual bool ShapeText(gfxContext *aContext,
+ virtual bool ShapeText(gfxContext *aContext,
const char16_t *aText,
- uint32_t aOffset,
- uint32_t aLength,
- int32_t aScript,
- gfxShapedText *aShapedText) = 0;
+ uint32_t aOffset,
+ uint32_t aLength,
+ int32_t aScript,
+ gfxShapedText *aShapedText) = 0;
gfxFont *GetFont() const { return mFont; }
@@ -1976,8 +1976,7 @@ protected:
uint32_t aOffset, // dest offset in gfxShapedText
uint32_t aLength,
int32_t aScript,
- gfxShapedText *aShapedText, // where to store the result
- bool aPreferPlatformShaping = false);
+ gfxShapedText *aShapedText); // where to store the result
// Call the appropriate shaper to generate glyphs for aText and store
// them into aShapedText.
@@ -1986,8 +1985,7 @@ protected:
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
- gfxShapedText *aShapedText,
- bool aPreferPlatformShaping = false);
+ gfxShapedText *aShapedText);
// Helper to adjust for synthetic bold and set character-type flags
// in the shaped text; implementations of ShapeText should call this
@@ -2146,19 +2144,14 @@ protected:
// measurement by mathml code
nsAutoPtr mNonAAFont;
- // we may switch between these shapers on the fly, based on the script
- // of the text run being shaped
- nsAutoPtr mPlatformShaper;
+ // we create either or both of these shapers when needed, depending
+ // whether the font has graphite tables, and whether graphite shaping
+ // is actually enabled
nsAutoPtr mHarfBuzzShaper;
nsAutoPtr mGraphiteShaper;
mozilla::RefPtr mAzureScaledFont;
- // Create a default platform text shaper for this font.
- // (TODO: This should become pure virtual once all font backends have
- // been updated.)
- virtual void CreatePlatformShaper() { }
-
// Helper for subclasses that want to initialize standard metrics from the
// tables of sfnt (TrueType/OpenType) fonts.
// This will use mFUnitsConvFactor if it is already set, else compute it
diff --git a/gfx/thebes/gfxGDIFont.cpp b/gfx/thebes/gfxGDIFont.cpp
index a410ff974bd..926fbb536d6 100644
--- a/gfx/thebes/gfxGDIFont.cpp
+++ b/gfx/thebes/gfxGDIFont.cpp
@@ -8,9 +8,7 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/WindowsVersion.h"
-#include "gfxHarfBuzzShaper.h"
#include
-#include "gfxGraphiteShaper.h"
#include "gfxWindowsPlatform.h"
#include "gfxContext.h"
#include "mozilla/Preferences.h"
@@ -51,10 +49,6 @@ gfxGDIFont::gfxGDIFont(GDIFontEntry *aFontEntry,
mSpaceGlyph(0),
mNeedsBold(aNeedsBold)
{
- if (FontCanSupportGraphite()) {
- mGraphiteShaper = new gfxGraphiteShaper(this);
- }
- mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
}
gfxGDIFont::~gfxGDIFont()
@@ -79,13 +73,12 @@ gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
}
bool
-gfxGDIFont::ShapeText(gfxContext *aContext,
+gfxGDIFont::ShapeText(gfxContext *aContext,
const char16_t *aText,
- uint32_t aOffset,
- uint32_t aLength,
- int32_t aScript,
- gfxShapedText *aShapedText,
- bool aPreferPlatformShaping)
+ uint32_t aOffset,
+ uint32_t aLength,
+ int32_t aScript,
+ gfxShapedText *aShapedText)
{
if (!mMetrics) {
Initialize();
@@ -104,7 +97,7 @@ gfxGDIFont::ShapeText(gfxContext *aContext,
}
return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
- aShapedText, aPreferPlatformShaping);
+ aShapedText);
}
const gfxFont::Metrics&
diff --git a/gfx/thebes/gfxGDIFont.h b/gfx/thebes/gfxGDIFont.h
index 3b979c41387..13839599b1c 100644
--- a/gfx/thebes/gfxGDIFont.h
+++ b/gfx/thebes/gfxGDIFont.h
@@ -71,13 +71,12 @@ public:
protected:
/* override to ensure the cairo font is set up properly */
- virtual bool ShapeText(gfxContext *aContext,
+ virtual bool ShapeText(gfxContext *aContext,
const char16_t *aText,
- uint32_t aOffset,
- uint32_t aLength,
- int32_t aScript,
- gfxShapedText *aShapedText,
- bool aPreferPlatformShaping);
+ uint32_t aOffset,
+ uint32_t aLength,
+ int32_t aScript,
+ gfxShapedText *aShapedText);
void Initialize(); // creates metrics and Cairo fonts
diff --git a/gfx/thebes/gfxMacFont.cpp b/gfx/thebes/gfxMacFont.cpp
index 3b7f752c5db..23e8301534e 100644
--- a/gfx/thebes/gfxMacFont.cpp
+++ b/gfx/thebes/gfxMacFont.cpp
@@ -8,9 +8,7 @@
#include "mozilla/MemoryReporting.h"
#include "gfxCoreTextShaper.h"
-#include "gfxHarfBuzzShaper.h"
#include
-#include "gfxGraphiteShaper.h"
#include "gfxPlatformMac.h"
#include "gfxContext.h"
#include "gfxFontUtils.h"
@@ -106,13 +104,6 @@ gfxMacFont::gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyl
NS_WARNING(warnBuf);
#endif
}
-
- if (FontCanSupportGraphite()) {
- mGraphiteShaper = new gfxGraphiteShaper(this);
- }
- if (FontCanSupportHarfBuzz()) {
- mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
- }
}
gfxMacFont::~gfxMacFont()
@@ -126,29 +117,31 @@ gfxMacFont::~gfxMacFont()
}
bool
-gfxMacFont::ShapeText(gfxContext *aContext,
+gfxMacFont::ShapeText(gfxContext *aContext,
const char16_t *aText,
- uint32_t aOffset,
- uint32_t aLength,
- int32_t aScript,
- gfxShapedText *aShapedText,
- bool aPreferPlatformShaping)
+ uint32_t aOffset,
+ uint32_t aLength,
+ int32_t aScript,
+ gfxShapedText *aShapedText)
{
if (!mIsValid) {
NS_WARNING("invalid font! expect incorrect text rendering");
return false;
}
- bool requiresAAT =
- static_cast(GetFontEntry())->RequiresAATLayout();
- return gfxFont::ShapeText(aContext, aText, aOffset, aLength,
- aScript, aShapedText, requiresAAT);
-}
+ if (static_cast(GetFontEntry())->RequiresAATLayout()) {
+ if (!mCoreTextShaper) {
+ mCoreTextShaper = new gfxCoreTextShaper(this);
+ }
+ if (mCoreTextShaper->ShapeText(aContext, aText, aOffset, aLength,
+ aScript, aShapedText)) {
+ PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
+ return true;
+ }
+ }
-void
-gfxMacFont::CreatePlatformShaper()
-{
- mPlatformShaper = new gfxCoreTextShaper(this);
+ return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
+ aShapedText);
}
bool
diff --git a/gfx/thebes/gfxMacFont.h b/gfx/thebes/gfxMacFont.h
index 0e88c5d0f06..3942213c039 100644
--- a/gfx/thebes/gfxMacFont.h
+++ b/gfx/thebes/gfxMacFont.h
@@ -51,16 +51,13 @@ public:
virtual FontType GetType() const { return FONT_TYPE_MAC; }
protected:
- virtual void CreatePlatformShaper();
-
// override to prefer CoreText shaping with fonts that depend on AAT
- virtual bool ShapeText(gfxContext *aContext,
+ virtual bool ShapeText(gfxContext *aContext,
const char16_t *aText,
- uint32_t aOffset,
- uint32_t aLength,
- int32_t aScript,
- gfxShapedText *aShapedText,
- bool aPreferPlatformShaping = false);
+ uint32_t aOffset,
+ uint32_t aLength,
+ int32_t aScript,
+ gfxShapedText *aShapedText);
void InitMetrics();
void InitMetricsFromPlatform();
@@ -76,6 +73,8 @@ protected:
cairo_font_face_t *mFontFace;
+ nsAutoPtr mCoreTextShaper;
+
Metrics mMetrics;
uint32_t mSpaceGlyph;
};
diff --git a/gfx/thebes/gfxPangoFonts.cpp b/gfx/thebes/gfxPangoFonts.cpp
index abfc5e7c71e..2dbd0c233d8 100644
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -20,8 +20,6 @@
#include "gfxFT2Utils.h"
#include "harfbuzz/hb.h"
#include "harfbuzz/hb-ot.h"
-#include "gfxHarfBuzzShaper.h"
-#include "gfxGraphiteShaper.h"
#include "nsUnicodeProperties.h"
#include "nsUnicodeScriptCodes.h"
#include "gfxFontconfigUtils.h"
@@ -663,14 +661,6 @@ public:
protected:
virtual already_AddRefed GetSmallCapsFont();
- virtual bool ShapeText(gfxContext *aContext,
- const char16_t *aText,
- uint32_t aOffset,
- uint32_t aLength,
- int32_t aScript,
- gfxShapedText *aShapedText,
- bool aPreferPlatformShaping);
-
private:
gfxFcFont(cairo_scaled_font_t *aCairoFont, gfxFcFontEntry *aFontEntry,
const gfxFontStyle *aFontStyle);
@@ -1632,42 +1622,6 @@ gfxFcFont::GetSmallCapsFont()
return font.forget();
}
-bool
-gfxFcFont::ShapeText(gfxContext *aContext,
- const char16_t *aText,
- uint32_t aOffset,
- uint32_t aLength,
- int32_t aScript,
- gfxShapedText *aShapedText,
- bool aPreferPlatformShaping)
-{
- bool ok = false;
-
- if (FontCanSupportGraphite()) {
- if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
- if (!mGraphiteShaper) {
- mGraphiteShaper = new gfxGraphiteShaper(this);
- }
- ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
- aScript, aShapedText);
- }
- }
-
- if (!ok) {
- if (!mHarfBuzzShaper) {
- mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
- }
- ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
- aScript, aShapedText);
- }
-
- NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text");
-
- PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
-
- return ok;
-}
-
/* static */ void
gfxPangoFontGroup::Shutdown()
{
diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp
index 8b189d4b479..dcf30752181 100644
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -724,6 +724,9 @@ gfxUtils::TransformRectToRect(const gfxRect& aFrom, const IntPoint& aToTopLeft,
return m;
}
+/* This function is sort of shitty. We truncate doubles
+ * to ints then convert those ints back to doubles to make sure that
+ * they equal the doubles that we got in. */
bool
gfxUtils::GfxRectToIntRect(const gfxRect& aIn, nsIntRect* aOut)
{
diff --git a/intl/unicharutil/util/GreekCasing.cpp b/intl/unicharutil/util/GreekCasing.cpp
new file mode 100644
index 00000000000..5c805c27566
--- /dev/null
+++ b/intl/unicharutil/util/GreekCasing.cpp
@@ -0,0 +1,268 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GreekCasing.h"
+#include "nsUnicharUtils.h"
+
+// Custom uppercase mapping for Greek; see bug 307039 for details
+#define GREEK_LOWER_ALPHA 0x03B1
+#define GREEK_LOWER_ALPHA_TONOS 0x03AC
+#define GREEK_LOWER_ALPHA_OXIA 0x1F71
+#define GREEK_LOWER_EPSILON 0x03B5
+#define GREEK_LOWER_EPSILON_TONOS 0x03AD
+#define GREEK_LOWER_EPSILON_OXIA 0x1F73
+#define GREEK_LOWER_ETA 0x03B7
+#define GREEK_LOWER_ETA_TONOS 0x03AE
+#define GREEK_LOWER_ETA_OXIA 0x1F75
+#define GREEK_LOWER_IOTA 0x03B9
+#define GREEK_LOWER_IOTA_TONOS 0x03AF
+#define GREEK_LOWER_IOTA_OXIA 0x1F77
+#define GREEK_LOWER_IOTA_DIALYTIKA 0x03CA
+#define GREEK_LOWER_IOTA_DIALYTIKA_TONOS 0x0390
+#define GREEK_LOWER_IOTA_DIALYTIKA_OXIA 0x1FD3
+#define GREEK_LOWER_OMICRON 0x03BF
+#define GREEK_LOWER_OMICRON_TONOS 0x03CC
+#define GREEK_LOWER_OMICRON_OXIA 0x1F79
+#define GREEK_LOWER_UPSILON 0x03C5
+#define GREEK_LOWER_UPSILON_TONOS 0x03CD
+#define GREEK_LOWER_UPSILON_OXIA 0x1F7B
+#define GREEK_LOWER_UPSILON_DIALYTIKA 0x03CB
+#define GREEK_LOWER_UPSILON_DIALYTIKA_TONOS 0x03B0
+#define GREEK_LOWER_UPSILON_DIALYTIKA_OXIA 0x1FE3
+#define GREEK_LOWER_OMEGA 0x03C9
+#define GREEK_LOWER_OMEGA_TONOS 0x03CE
+#define GREEK_LOWER_OMEGA_OXIA 0x1F7D
+#define GREEK_UPPER_ALPHA 0x0391
+#define GREEK_UPPER_EPSILON 0x0395
+#define GREEK_UPPER_ETA 0x0397
+#define GREEK_UPPER_IOTA 0x0399
+#define GREEK_UPPER_IOTA_DIALYTIKA 0x03AA
+#define GREEK_UPPER_OMICRON 0x039F
+#define GREEK_UPPER_UPSILON 0x03A5
+#define GREEK_UPPER_UPSILON_DIALYTIKA 0x03AB
+#define GREEK_UPPER_OMEGA 0x03A9
+#define GREEK_UPPER_ALPHA_TONOS 0x0386
+#define GREEK_UPPER_ALPHA_OXIA 0x1FBB
+#define GREEK_UPPER_EPSILON_TONOS 0x0388
+#define GREEK_UPPER_EPSILON_OXIA 0x1FC9
+#define GREEK_UPPER_ETA_TONOS 0x0389
+#define GREEK_UPPER_ETA_OXIA 0x1FCB
+#define GREEK_UPPER_IOTA_TONOS 0x038A
+#define GREEK_UPPER_IOTA_OXIA 0x1FDB
+#define GREEK_UPPER_OMICRON_TONOS 0x038C
+#define GREEK_UPPER_OMICRON_OXIA 0x1FF9
+#define GREEK_UPPER_UPSILON_TONOS 0x038E
+#define GREEK_UPPER_UPSILON_OXIA 0x1FEB
+#define GREEK_UPPER_OMEGA_TONOS 0x038F
+#define GREEK_UPPER_OMEGA_OXIA 0x1FFB
+#define COMBINING_ACUTE_ACCENT 0x0301
+#define COMBINING_DIAERESIS 0x0308
+#define COMBINING_ACUTE_TONE_MARK 0x0341
+#define COMBINING_GREEK_DIALYTIKA_TONOS 0x0344
+
+namespace mozilla {
+
+uint32_t
+GreekCasing::UpperCase(uint32_t aCh, GreekCasing::State& aState)
+{
+ switch (aCh) {
+ case GREEK_UPPER_ALPHA:
+ case GREEK_LOWER_ALPHA:
+ aState = kAlpha;
+ return GREEK_UPPER_ALPHA;
+
+ case GREEK_UPPER_EPSILON:
+ case GREEK_LOWER_EPSILON:
+ aState = kEpsilon;
+ return GREEK_UPPER_EPSILON;
+
+ case GREEK_UPPER_ETA:
+ case GREEK_LOWER_ETA:
+ aState = kEta;
+ return GREEK_UPPER_ETA;
+
+ case GREEK_UPPER_IOTA:
+ aState = kIota;
+ return GREEK_UPPER_IOTA;
+
+ case GREEK_UPPER_OMICRON:
+ case GREEK_LOWER_OMICRON:
+ aState = kOmicron;
+ return GREEK_UPPER_OMICRON;
+
+ case GREEK_UPPER_UPSILON:
+ switch (aState) {
+ case kOmicron:
+ aState = kOmicronUpsilon;
+ break;
+ default:
+ aState = kUpsilon;
+ break;
+ }
+ return GREEK_UPPER_UPSILON;
+
+ case GREEK_UPPER_OMEGA:
+ case GREEK_LOWER_OMEGA:
+ aState = kOmega;
+ return GREEK_UPPER_OMEGA;
+
+ // iota and upsilon may be the second vowel of a diphthong
+ case GREEK_LOWER_IOTA:
+ switch (aState) {
+ case kAlphaAcc:
+ case kEpsilonAcc:
+ case kOmicronAcc:
+ case kUpsilonAcc:
+ aState = kStart;
+ return GREEK_UPPER_IOTA_DIALYTIKA;
+ default:
+ break;
+ }
+ aState = kIota;
+ return GREEK_UPPER_IOTA;
+
+ case GREEK_LOWER_UPSILON:
+ switch (aState) {
+ case kAlphaAcc:
+ case kEpsilonAcc:
+ case kEtaAcc:
+ case kOmicronAcc:
+ aState = kStart;
+ return GREEK_UPPER_UPSILON_DIALYTIKA;
+ case kOmicron:
+ aState = kOmicronUpsilon;
+ break;
+ default:
+ aState = kUpsilon;
+ break;
+ }
+ return GREEK_UPPER_UPSILON;
+
+ case GREEK_UPPER_IOTA_DIALYTIKA:
+ case GREEK_LOWER_IOTA_DIALYTIKA:
+ case GREEK_UPPER_UPSILON_DIALYTIKA:
+ case GREEK_LOWER_UPSILON_DIALYTIKA:
+ case COMBINING_DIAERESIS:
+ aState = kDiaeresis;
+ return ToUpperCase(aCh);
+
+ // remove accent if it follows a vowel or diaeresis,
+ // and set appropriate state for diphthong detection
+ case COMBINING_ACUTE_ACCENT:
+ case COMBINING_ACUTE_TONE_MARK:
+ switch (aState) {
+ case kAlpha:
+ aState = kAlphaAcc;
+ return uint32_t(-1); // omit this char from result string
+ case kEpsilon:
+ aState = kEpsilonAcc;
+ return uint32_t(-1);
+ case kEta:
+ aState = kEtaAcc;
+ return uint32_t(-1);
+ case kIota:
+ aState = kIotaAcc;
+ return uint32_t(-1);
+ case kOmicron:
+ aState = kOmicronAcc;
+ return uint32_t(-1);
+ case kUpsilon:
+ aState = kUpsilonAcc;
+ return uint32_t(-1);
+ case kOmicronUpsilon:
+ aState = kStart; // this completed a diphthong
+ return uint32_t(-1);
+ case kOmega:
+ aState = kOmegaAcc;
+ return uint32_t(-1);
+ case kDiaeresis:
+ aState = kStart;
+ return uint32_t(-1);
+ default:
+ break;
+ }
+ break;
+
+ // combinations with dieresis+accent just strip the accent,
+ // and reset to start state (don't form diphthong with following vowel)
+ case GREEK_LOWER_IOTA_DIALYTIKA_TONOS:
+ case GREEK_LOWER_IOTA_DIALYTIKA_OXIA:
+ aState = kStart;
+ return GREEK_UPPER_IOTA_DIALYTIKA;
+
+ case GREEK_LOWER_UPSILON_DIALYTIKA_TONOS:
+ case GREEK_LOWER_UPSILON_DIALYTIKA_OXIA:
+ aState = kStart;
+ return GREEK_UPPER_UPSILON_DIALYTIKA;
+
+ case COMBINING_GREEK_DIALYTIKA_TONOS:
+ aState = kStart;
+ return COMBINING_DIAERESIS;
+
+ // strip accents from vowels, and note the vowel seen so that we can detect
+ // diphthongs where diaeresis needs to be added
+ case GREEK_LOWER_ALPHA_TONOS:
+ case GREEK_LOWER_ALPHA_OXIA:
+ case GREEK_UPPER_ALPHA_TONOS:
+ case GREEK_UPPER_ALPHA_OXIA:
+ aState = kAlphaAcc;
+ return GREEK_UPPER_ALPHA;
+
+ case GREEK_LOWER_EPSILON_TONOS:
+ case GREEK_LOWER_EPSILON_OXIA:
+ case GREEK_UPPER_EPSILON_TONOS:
+ case GREEK_UPPER_EPSILON_OXIA:
+ aState = kEpsilonAcc;
+ return GREEK_UPPER_EPSILON;
+
+ case GREEK_LOWER_ETA_TONOS:
+ case GREEK_LOWER_ETA_OXIA:
+ case GREEK_UPPER_ETA_TONOS:
+ case GREEK_UPPER_ETA_OXIA:
+ aState = kEtaAcc;
+ return GREEK_UPPER_ETA;
+
+ case GREEK_LOWER_IOTA_TONOS:
+ case GREEK_LOWER_IOTA_OXIA:
+ case GREEK_UPPER_IOTA_TONOS:
+ case GREEK_UPPER_IOTA_OXIA:
+ aState = kIotaAcc;
+ return GREEK_UPPER_IOTA;
+
+ case GREEK_LOWER_OMICRON_TONOS:
+ case GREEK_LOWER_OMICRON_OXIA:
+ case GREEK_UPPER_OMICRON_TONOS:
+ case GREEK_UPPER_OMICRON_OXIA:
+ aState = kOmicronAcc;
+ return GREEK_UPPER_OMICRON;
+
+ case GREEK_LOWER_UPSILON_TONOS:
+ case GREEK_LOWER_UPSILON_OXIA:
+ case GREEK_UPPER_UPSILON_TONOS:
+ case GREEK_UPPER_UPSILON_OXIA:
+ switch (aState) {
+ case kOmicron:
+ aState = kStart; // this completed a diphthong
+ break;
+ default:
+ aState = kUpsilonAcc;
+ break;
+ }
+ return GREEK_UPPER_UPSILON;
+
+ case GREEK_LOWER_OMEGA_TONOS:
+ case GREEK_LOWER_OMEGA_OXIA:
+ case GREEK_UPPER_OMEGA_TONOS:
+ case GREEK_UPPER_OMEGA_OXIA:
+ aState = kOmegaAcc;
+ return GREEK_UPPER_OMEGA;
+ }
+
+ // all other characters just reset the state, and use standard mappings
+ aState = kStart;
+ return ToUpperCase(aCh);
+}
+
+} // namespace mozilla
diff --git a/intl/unicharutil/util/GreekCasing.h b/intl/unicharutil/util/GreekCasing.h
new file mode 100644
index 00000000000..5a25c789849
--- /dev/null
+++ b/intl/unicharutil/util/GreekCasing.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GreekCasing_h_
+#define GreekCasing_h_
+
+#include
+
+namespace mozilla {
+
+class GreekCasing {
+ // When doing an Uppercase transform in Greek, we need to keep track of the
+ // current state while iterating through the string, to recognize and process
+ // diphthongs correctly. For clarity, we define a state for each vowel and
+ // each vowel with accent, although a few of these do not actually need any
+ // special treatment and could be folded into kStart.
+private:
+ enum GreekStates {
+ kStart,
+ kAlpha,
+ kEpsilon,
+ kEta,
+ kIota,
+ kOmicron,
+ kUpsilon,
+ kOmega,
+ kAlphaAcc,
+ kEpsilonAcc,
+ kEtaAcc,
+ kIotaAcc,
+ kOmicronAcc,
+ kUpsilonAcc,
+ kOmegaAcc,
+ kOmicronUpsilon,
+ kDiaeresis
+ };
+
+public:
+ class State {
+ public:
+ State()
+ : mState(kStart)
+ {
+ }
+
+ State(const GreekStates& aState)
+ : mState(aState)
+ {
+ }
+
+ void Reset()
+ {
+ mState = kStart;
+ }
+
+ operator GreekStates() const
+ {
+ return mState;
+ }
+
+ private:
+ GreekStates mState;
+ };
+
+ static uint32_t UpperCase(uint32_t aCh, State& aState);
+};
+
+} // namespace mozilla
+
+#endif
diff --git a/intl/unicharutil/util/IrishCasing.cpp b/intl/unicharutil/util/IrishCasing.cpp
new file mode 100644
index 00000000000..6c66ff51710
--- /dev/null
+++ b/intl/unicharutil/util/IrishCasing.cpp
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/******************************************************************************
+
+This file provides a finite state machine to support Irish Gaelic uppercasing
+rules.
+
+The caller will need to iterate through a string, passing a State variable
+along with the current character to each UpperCase call and checking the flags
+that are returned:
+
+ If aMarkPos is true, caller must remember the current index in the string as
+ a possible target for a future action.
+
+ If aAction is non-zero, then one or more characters from the marked index are
+ to be modified:
+ 1 lowercase the marked letter
+ 2 lowercase the marked letter and its successor
+ 3 lowercase the marked letter, and delete its successor
+
+
+### Rules from https://bugzilla.mozilla.org/show_bug.cgi?id=1014639,
+### comments 1 and 4:
+
+v = [a,á,e,é,i,í,o,ó,u,ú]
+V = [A,Á,E,É,I,Í,O,Ó,U,Ú]
+
+bhf -> bhF
+bhF -> bhF
+bp -> bP
+bP -> bP
+dt -> dT
+dT -> dT
+gc -> gC
+gC -> gC
+h{V} -> h{V}
+mb -> mB
+mB -> mB
+n-{v} -> n{V}
+n{V} -> n{V}
+nd -> nD
+nD -> nD
+ng -> nG
+nG -> nG
+t-{v} -> t{V}
+t{V} -> t{V}
+ts{v} -> tS{V}
+tS{v} -> tS{V}
+tS{V} -> tS{V}
+tsl -> tSL
+tSl -> tSL
+tSL -> tSL
+tsn -> tSN
+tSn -> tSN
+tSN -> tSN
+tsr -> tSR
+tSr -> tSR
+tSR -> tSR
+
+### Create table of states and actions for each input class.
+
+Start (non-word) state is #; generic in-word state is _, once we know there's
+no special action to do in this word.
+
+ # _ b bh d g h m n n- t t- ts
+input\state
+b b' _ _ _ _ _ _ 1 _ _ _ _ _
+B _ _ _ _ _ _ _ 1 _ _ _ _ _
+c _ _ _ _ _ 1 _ _ _ _ _ _ _
+C _ _ _ _ _ 1 _ _ _ _ _ _ _
+d d' _ _ _ _ _ _ _ 1 _ _ _ _
+D _ _ _ _ _ _ _ _ 1 _ _ _ _
+f _ _ _ 2 _ _ _ _ _ _ _ _ _
+F _ _ _ 2 _ _ _ _ _ _ _ _ _
+g g' _ _ _ _ _ _ _ 1 _ _ _ _
+G _ _ _ _ _ _ _ _ 1 _ _ _ _
+h h' _ bh _ _ _ _ _ _ _ _ _ _
+l _ _ _ _ _ _ _ _ _ _ _ _ 1
+L _ _ _ _ _ _ _ _ _ _ _ _ 1
+m m' _ _ _ _ _ _ _ _ _ _ _ _
+n n' _ _ _ _ _ _ _ _ _ _ _ 1
+N _ _ _ _ _ _ _ _ _ _ _ _ 1
+p _ _ 1 _ _ _ _ _ _ _ _ _ _
+P _ _ 1 _ _ _ _ _ _ _ _ _ _
+r _ _ _ _ _ _ _ _ _ _ _ _ 1
+R _ _ _ _ _ _ _ _ _ _ _ _ 1
+s _ _ _ _ _ _ _ _ _ _ ts _ _
+S _ _ _ _ _ _ _ _ _ _ ts _ _
+t t' _ _ _ 1 _ _ _ _ _ _ _ _
+T _ _ _ _ 1 _ _ _ _ _ _ _ _
+vowel _ _ _ _ _ _ _ _ _ 1d _ 1d 1
+Vowel _ _ _ _ _ _ 1 _ 1 _ 1 _ 1
+hyph _ _ _ _ _ _ _ _ n- _ t- _ _
+letter _ _ _ _ _ _ _ _ _ _ _ _ _
+other # # # # # # # # # # # # #
+
+Actions:
+ 1 lowercase one letter at start of word
+ 2 lowercase two letters at start of word
+ 1d lowercase one letter at start of word, and delete next
+ (and then go to state _, nothing further to do in this word)
+
+else just go to the given state; suffix ' indicates mark start-of-word.
+
+### Consolidate identical states and classes:
+
+ 0 1 2 3 4 5 6 7 8 9 A B
+ # _ b bh d g h m n [nt]- t ts
+input\state
+b b' _ _ _ _ _ _ 1 _ _ _ _
+B _ _ _ _ _ _ _ 1 _ _ _ _
+[cC] _ _ _ _ _ 1 _ _ _ _ _ _
+d d' _ _ _ _ _ _ _ 1 _ _ _
+[DG] _ _ _ _ _ _ _ _ 1 _ _ _
+[fF] _ _ _ 2 _ _ _ _ _ _ _ _
+g g' _ _ _ _ _ _ _ 1 _ _ _
+h h' _ bh _ _ _ _ _ _ _ _ _
+[lLNrR] _ _ _ _ _ _ _ _ _ _ _ 1
+m m' _ _ _ _ _ _ _ _ _ _ _
+n n' _ _ _ _ _ _ _ _ _ _ 1
+[pP] _ _ 1 _ _ _ _ _ _ _ _ _
+[sS] _ _ _ _ _ _ _ _ _ _ ts _
+t t' _ _ _ 1 _ _ _ _ _ _ _
+T _ _ _ _ 1 _ _ _ _ _ _ _
+vowel _ _ _ _ _ _ _ _ _ 1d _ 1
+Vowel _ _ _ _ _ _ 1 _ 1 _ 1 1
+hyph _ _ _ _ _ _ _ _ [nt-] _ [nt-] _
+letter _ _ _ _ _ _ _ _ _ _ _ _
+other # # # # # # # # # # # #
+
+So we have 20 input classes, and 12 states.
+
+State table array will contain bytes that encode action and new state:
+
+ 0x80 - bit flag: mark start-of-word position
+ 0x40 - currently unused
+ 0x30 - action mask: 4 values
+ 0x00 - do nothing
+ 0x10 - lowercase one letter
+ 0x20 - lowercase two letters
+ 0x30 - lowercase one, delete one
+ 0x0F - next-state mask
+******************************************************************************/
+
+#include "IrishCasing.h"
+
+#include "nsUnicodeProperties.h"
+#include "nsUnicharUtils.h"
+
+namespace mozilla {
+
+const uint8_t
+IrishCasing::sUppercaseStateTable[kNumClasses][kNumStates] = {
+// # _ b bh d g h m n [nt]- t ts
+ { 0x82, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01, 0x01 }, // b
+ { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01, 0x01 }, // B
+ { 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, // [cC]
+ { 0x84, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01 }, // d
+ { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01 }, // [DG]
+ { 0x01, 0x01, 0x01, 0x21, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, // [fF]
+ { 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01 }, // g
+ { 0x86, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, // h
+ { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11 }, // [lLNrR]
+ { 0x87, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, // m
+ { 0x88, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11 }, // n
+ { 0x01, 0x01, 0x11, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, // [pP]
+ { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0B, 0x01 }, // [sS]
+ { 0x8A, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, // t
+ { 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, // T
+ { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x31, 0x01, 0x11 }, // vowel
+ { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x11, 0x01, 0x11, 0x11 }, // Vowel
+ { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x01, 0x09, 0x01 }, // hyph
+ { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, // letter
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // other
+};
+
+#define HYPHEN 0x2010
+#define NO_BREAK_HYPHEN 0x2011
+#define a_ACUTE 0x00e1
+#define e_ACUTE 0x00e9
+#define i_ACUTE 0x00ed
+#define o_ACUTE 0x00f3
+#define u_ACUTE 0x00fa
+#define A_ACUTE 0x00c1
+#define E_ACUTE 0x00c9
+#define I_ACUTE 0x00cd
+#define O_ACUTE 0x00d3
+#define U_ACUTE 0x00da
+
+const uint8_t IrishCasing::sLcClasses[26] = {
+ kClass_vowel, kClass_b, kClass_cC, kClass_d, kClass_vowel,
+ kClass_fF, kClass_g, kClass_h, kClass_vowel, kClass_letter,
+ kClass_letter, kClass_lLNrR, kClass_m, kClass_n, kClass_vowel,
+ kClass_pP, kClass_letter, kClass_lLNrR, kClass_sS, kClass_t,
+ kClass_vowel, kClass_letter, kClass_letter, kClass_letter, kClass_letter,
+ kClass_letter
+};
+
+const uint8_t IrishCasing::sUcClasses[26] = {
+ kClass_Vowel, kClass_B, kClass_cC, kClass_DG, kClass_Vowel,
+ kClass_fF, kClass_DG, kClass_letter, kClass_Vowel, kClass_letter,
+ kClass_letter, kClass_lLNrR, kClass_letter, kClass_lLNrR, kClass_Vowel,
+ kClass_pP, kClass_letter, kClass_lLNrR, kClass_sS, kClass_T,
+ kClass_Vowel, kClass_letter, kClass_letter, kClass_letter, kClass_letter,
+ kClass_letter
+};
+
+uint32_t
+IrishCasing::UpperCase(uint32_t aCh, State& aState,
+ bool& aMarkPos, uint8_t& aAction)
+{
+ using mozilla::unicode::GetGenCategory;
+ uint8_t cls;
+
+ if (aCh >= 'a' && aCh <= 'z') {
+ cls = sLcClasses[aCh - 'a'];
+ } else if (aCh >= 'A' && aCh <= 'Z') {
+ cls = sUcClasses[aCh - 'A'];
+ } else if (GetGenCategory(aCh) == nsIUGenCategory::kLetter) {
+ if (aCh == a_ACUTE || aCh == e_ACUTE || aCh == i_ACUTE ||
+ aCh == o_ACUTE || aCh == u_ACUTE) {
+ cls = kClass_vowel;
+ } else if (aCh == A_ACUTE || aCh == E_ACUTE || aCh == I_ACUTE ||
+ aCh == O_ACUTE || aCh == U_ACUTE) {
+ cls = kClass_Vowel;
+ } else {
+ cls = kClass_letter;
+ }
+ } else if (aCh == '-' || aCh == HYPHEN || aCh == NO_BREAK_HYPHEN) {
+ cls = kClass_hyph;
+ } else {
+ cls = kClass_other;
+ }
+
+ uint8_t stateEntry = sUppercaseStateTable[cls][aState];
+ aMarkPos = !!(stateEntry & kMarkPositionFlag);
+ aAction = (stateEntry & kActionMask) >> kActionShift;
+ aState = (stateEntry & kNextStateMask);
+
+ return ToUpperCase(aCh);
+}
+
+} // namespace mozilla
diff --git a/intl/unicharutil/util/IrishCasing.h b/intl/unicharutil/util/IrishCasing.h
new file mode 100644
index 00000000000..a4b2edc2920
--- /dev/null
+++ b/intl/unicharutil/util/IrishCasing.h
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef IrishCasing_h_
+#define IrishCasing_h_
+
+#include
+
+namespace mozilla {
+
+class IrishCasing {
+private:
+ enum IrishStates {
+ kState_Start,
+ kState_InWord,
+ kState_b,
+ kState_bh,
+ kState_d,
+ kState_g,
+ kState_h,
+ kState_m,
+ kState_n,
+ kState_nt_,
+ kState_t,
+ kState_ts,
+ kNumStates
+ };
+
+ enum IrishClasses {
+ kClass_b,
+ kClass_B,
+ kClass_cC,
+ kClass_d,
+ kClass_DG,
+ kClass_fF,
+ kClass_g,
+ kClass_h,
+ kClass_lLNrR,
+ kClass_m,
+ kClass_n,
+ kClass_pP,
+ kClass_sS,
+ kClass_t,
+ kClass_T,
+ kClass_vowel,
+ kClass_Vowel,
+ kClass_hyph,
+ kClass_letter,
+ kClass_other,
+ kNumClasses
+ };
+
+public:
+ class State {
+ friend class IrishCasing;
+
+ public:
+ State()
+ : mState(kState_Start)
+ {
+ }
+
+ State(const IrishStates& aState)
+ : mState(aState)
+ {
+ }
+
+ void Reset()
+ {
+ mState = kState_Start;
+ }
+
+ operator IrishStates() const
+ {
+ return mState;
+ }
+
+ private:
+ State(uint8_t aState)
+ : mState(IrishStates(aState))
+ {
+ }
+
+ uint8_t GetClass(uint32_t aCh);
+
+ IrishStates mState;
+ };
+
+ enum {
+ kMarkPositionFlag = 0x80,
+ kActionMask = 0x30,
+ kActionShift = 4,
+ kNextStateMask = 0x0f
+ };
+
+ static const uint8_t sUppercaseStateTable[kNumClasses][kNumStates];
+ static const uint8_t sLcClasses[26];
+ static const uint8_t sUcClasses[26];
+
+ static uint32_t UpperCase(uint32_t aCh, State& aState,
+ bool& aMarkPos, uint8_t& aAction);
+};
+
+} // namespace mozilla
+
+#endif
diff --git a/intl/unicharutil/util/moz.build b/intl/unicharutil/util/moz.build
index 508c53f7667..3444abce2f2 100644
--- a/intl/unicharutil/util/moz.build
+++ b/intl/unicharutil/util/moz.build
@@ -7,7 +7,9 @@
DIRS += ['internal']
EXPORTS += [
+ 'GreekCasing.h',
'ICUUtils.h',
+ 'IrishCasing.h',
'nsBidiUtils.h',
'nsSpecialCasingData.h',
'nsUnicharUtils.h',
diff --git a/intl/unicharutil/util/nsUnicharUtils.cpp b/intl/unicharutil/util/nsUnicharUtils.cpp
index 420797fc9b0..f82902f0fbf 100644
--- a/intl/unicharutil/util/nsUnicharUtils.cpp
+++ b/intl/unicharutil/util/nsUnicharUtils.cpp
@@ -214,263 +214,6 @@ ToTitleCase(uint32_t aChar)
return mozilla::unicode::GetTitlecaseForLower(aChar);
}
-// Custom uppercase mapping for Greek; see bug 307039 for details
-#define GREEK_LOWER_ALPHA 0x03B1
-#define GREEK_LOWER_ALPHA_TONOS 0x03AC
-#define GREEK_LOWER_ALPHA_OXIA 0x1F71
-#define GREEK_LOWER_EPSILON 0x03B5
-#define GREEK_LOWER_EPSILON_TONOS 0x03AD
-#define GREEK_LOWER_EPSILON_OXIA 0x1F73
-#define GREEK_LOWER_ETA 0x03B7
-#define GREEK_LOWER_ETA_TONOS 0x03AE
-#define GREEK_LOWER_ETA_OXIA 0x1F75
-#define GREEK_LOWER_IOTA 0x03B9
-#define GREEK_LOWER_IOTA_TONOS 0x03AF
-#define GREEK_LOWER_IOTA_OXIA 0x1F77
-#define GREEK_LOWER_IOTA_DIALYTIKA 0x03CA
-#define GREEK_LOWER_IOTA_DIALYTIKA_TONOS 0x0390
-#define GREEK_LOWER_IOTA_DIALYTIKA_OXIA 0x1FD3
-#define GREEK_LOWER_OMICRON 0x03BF
-#define GREEK_LOWER_OMICRON_TONOS 0x03CC
-#define GREEK_LOWER_OMICRON_OXIA 0x1F79
-#define GREEK_LOWER_UPSILON 0x03C5
-#define GREEK_LOWER_UPSILON_TONOS 0x03CD
-#define GREEK_LOWER_UPSILON_OXIA 0x1F7B
-#define GREEK_LOWER_UPSILON_DIALYTIKA 0x03CB
-#define GREEK_LOWER_UPSILON_DIALYTIKA_TONOS 0x03B0
-#define GREEK_LOWER_UPSILON_DIALYTIKA_OXIA 0x1FE3
-#define GREEK_LOWER_OMEGA 0x03C9
-#define GREEK_LOWER_OMEGA_TONOS 0x03CE
-#define GREEK_LOWER_OMEGA_OXIA 0x1F7D
-#define GREEK_UPPER_ALPHA 0x0391
-#define GREEK_UPPER_EPSILON 0x0395
-#define GREEK_UPPER_ETA 0x0397
-#define GREEK_UPPER_IOTA 0x0399
-#define GREEK_UPPER_IOTA_DIALYTIKA 0x03AA
-#define GREEK_UPPER_OMICRON 0x039F
-#define GREEK_UPPER_UPSILON 0x03A5
-#define GREEK_UPPER_UPSILON_DIALYTIKA 0x03AB
-#define GREEK_UPPER_OMEGA 0x03A9
-#define GREEK_UPPER_ALPHA_TONOS 0x0386
-#define GREEK_UPPER_ALPHA_OXIA 0x1FBB
-#define GREEK_UPPER_EPSILON_TONOS 0x0388
-#define GREEK_UPPER_EPSILON_OXIA 0x1FC9
-#define GREEK_UPPER_ETA_TONOS 0x0389
-#define GREEK_UPPER_ETA_OXIA 0x1FCB
-#define GREEK_UPPER_IOTA_TONOS 0x038A
-#define GREEK_UPPER_IOTA_OXIA 0x1FDB
-#define GREEK_UPPER_OMICRON_TONOS 0x038C
-#define GREEK_UPPER_OMICRON_OXIA 0x1FF9
-#define GREEK_UPPER_UPSILON_TONOS 0x038E
-#define GREEK_UPPER_UPSILON_OXIA 0x1FEB
-#define GREEK_UPPER_OMEGA_TONOS 0x038F
-#define GREEK_UPPER_OMEGA_OXIA 0x1FFB
-#define COMBINING_ACUTE_ACCENT 0x0301
-#define COMBINING_DIAERESIS 0x0308
-#define COMBINING_ACUTE_TONE_MARK 0x0341
-#define COMBINING_GREEK_DIALYTIKA_TONOS 0x0344
-
-uint32_t
-GreekCasing::UpperCase(uint32_t aCh, GreekCasing::State& aState)
-{
- switch (aCh) {
- case GREEK_UPPER_ALPHA:
- case GREEK_LOWER_ALPHA:
- aState = kAlpha;
- return GREEK_UPPER_ALPHA;
-
- case GREEK_UPPER_EPSILON:
- case GREEK_LOWER_EPSILON:
- aState = kEpsilon;
- return GREEK_UPPER_EPSILON;
-
- case GREEK_UPPER_ETA:
- case GREEK_LOWER_ETA:
- aState = kEta;
- return GREEK_UPPER_ETA;
-
- case GREEK_UPPER_IOTA:
- aState = kIota;
- return GREEK_UPPER_IOTA;
-
- case GREEK_UPPER_OMICRON:
- case GREEK_LOWER_OMICRON:
- aState = kOmicron;
- return GREEK_UPPER_OMICRON;
-
- case GREEK_UPPER_UPSILON:
- switch (aState) {
- case kOmicron:
- aState = kOmicronUpsilon;
- break;
- default:
- aState = kUpsilon;
- break;
- }
- return GREEK_UPPER_UPSILON;
-
- case GREEK_UPPER_OMEGA:
- case GREEK_LOWER_OMEGA:
- aState = kOmega;
- return GREEK_UPPER_OMEGA;
-
- // iota and upsilon may be the second vowel of a diphthong
- case GREEK_LOWER_IOTA:
- switch (aState) {
- case kAlphaAcc:
- case kEpsilonAcc:
- case kOmicronAcc:
- case kUpsilonAcc:
- aState = kStart;
- return GREEK_UPPER_IOTA_DIALYTIKA;
- default:
- break;
- }
- aState = kIota;
- return GREEK_UPPER_IOTA;
-
- case GREEK_LOWER_UPSILON:
- switch (aState) {
- case kAlphaAcc:
- case kEpsilonAcc:
- case kEtaAcc:
- case kOmicronAcc:
- aState = kStart;
- return GREEK_UPPER_UPSILON_DIALYTIKA;
- case kOmicron:
- aState = kOmicronUpsilon;
- break;
- default:
- aState = kUpsilon;
- break;
- }
- return GREEK_UPPER_UPSILON;
-
- case GREEK_UPPER_IOTA_DIALYTIKA:
- case GREEK_LOWER_IOTA_DIALYTIKA:
- case GREEK_UPPER_UPSILON_DIALYTIKA:
- case GREEK_LOWER_UPSILON_DIALYTIKA:
- case COMBINING_DIAERESIS:
- aState = kDiaeresis;
- return ToUpperCase(aCh);
-
- // remove accent if it follows a vowel or diaeresis,
- // and set appropriate state for diphthong detection
- case COMBINING_ACUTE_ACCENT:
- case COMBINING_ACUTE_TONE_MARK:
- switch (aState) {
- case kAlpha:
- aState = kAlphaAcc;
- return uint32_t(-1); // omit this char from result string
- case kEpsilon:
- aState = kEpsilonAcc;
- return uint32_t(-1);
- case kEta:
- aState = kEtaAcc;
- return uint32_t(-1);
- case kIota:
- aState = kIotaAcc;
- return uint32_t(-1);
- case kOmicron:
- aState = kOmicronAcc;
- return uint32_t(-1);
- case kUpsilon:
- aState = kUpsilonAcc;
- return uint32_t(-1);
- case kOmicronUpsilon:
- aState = kStart; // this completed a diphthong
- return uint32_t(-1);
- case kOmega:
- aState = kOmegaAcc;
- return uint32_t(-1);
- case kDiaeresis:
- aState = kStart;
- return uint32_t(-1);
- default:
- break;
- }
- break;
-
- // combinations with dieresis+accent just strip the accent,
- // and reset to start state (don't form diphthong with following vowel)
- case GREEK_LOWER_IOTA_DIALYTIKA_TONOS:
- case GREEK_LOWER_IOTA_DIALYTIKA_OXIA:
- aState = kStart;
- return GREEK_UPPER_IOTA_DIALYTIKA;
-
- case GREEK_LOWER_UPSILON_DIALYTIKA_TONOS:
- case GREEK_LOWER_UPSILON_DIALYTIKA_OXIA:
- aState = kStart;
- return GREEK_UPPER_UPSILON_DIALYTIKA;
-
- case COMBINING_GREEK_DIALYTIKA_TONOS:
- aState = kStart;
- return COMBINING_DIAERESIS;
-
- // strip accents from vowels, and note the vowel seen so that we can detect
- // diphthongs where diaeresis needs to be added
- case GREEK_LOWER_ALPHA_TONOS:
- case GREEK_LOWER_ALPHA_OXIA:
- case GREEK_UPPER_ALPHA_TONOS:
- case GREEK_UPPER_ALPHA_OXIA:
- aState = kAlphaAcc;
- return GREEK_UPPER_ALPHA;
-
- case GREEK_LOWER_EPSILON_TONOS:
- case GREEK_LOWER_EPSILON_OXIA:
- case GREEK_UPPER_EPSILON_TONOS:
- case GREEK_UPPER_EPSILON_OXIA:
- aState = kEpsilonAcc;
- return GREEK_UPPER_EPSILON;
-
- case GREEK_LOWER_ETA_TONOS:
- case GREEK_LOWER_ETA_OXIA:
- case GREEK_UPPER_ETA_TONOS:
- case GREEK_UPPER_ETA_OXIA:
- aState = kEtaAcc;
- return GREEK_UPPER_ETA;
-
- case GREEK_LOWER_IOTA_TONOS:
- case GREEK_LOWER_IOTA_OXIA:
- case GREEK_UPPER_IOTA_TONOS:
- case GREEK_UPPER_IOTA_OXIA:
- aState = kIotaAcc;
- return GREEK_UPPER_IOTA;
-
- case GREEK_LOWER_OMICRON_TONOS:
- case GREEK_LOWER_OMICRON_OXIA:
- case GREEK_UPPER_OMICRON_TONOS:
- case GREEK_UPPER_OMICRON_OXIA:
- aState = kOmicronAcc;
- return GREEK_UPPER_OMICRON;
-
- case GREEK_LOWER_UPSILON_TONOS:
- case GREEK_LOWER_UPSILON_OXIA:
- case GREEK_UPPER_UPSILON_TONOS:
- case GREEK_UPPER_UPSILON_OXIA:
- switch (aState) {
- case kOmicron:
- aState = kStart; // this completed a diphthong
- break;
- default:
- aState = kUpsilonAcc;
- break;
- }
- return GREEK_UPPER_UPSILON;
-
- case GREEK_LOWER_OMEGA_TONOS:
- case GREEK_LOWER_OMEGA_OXIA:
- case GREEK_UPPER_OMEGA_TONOS:
- case GREEK_UPPER_OMEGA_OXIA:
- aState = kOmegaAcc;
- return GREEK_UPPER_OMEGA;
- }
-
- // all other characters just reset the state, and use standard mappings
- aState = kStart;
- return ToUpperCase(aCh);
-}
-
int32_t
CaseInsensitiveCompare(const char16_t *a,
const char16_t *b,
diff --git a/intl/unicharutil/util/nsUnicharUtils.h b/intl/unicharutil/util/nsUnicharUtils.h
index ec49c4ca066..3f33c851da8 100644
--- a/intl/unicharutil/util/nsUnicharUtils.h
+++ b/intl/unicharutil/util/nsUnicharUtils.h
@@ -37,63 +37,6 @@ inline bool IsLowerCase(uint32_t c) {
return ToUpperCase(c) != c;
}
-class GreekCasing {
- // When doing an Uppercase transform in Greek, we need to keep track of the
- // current state while iterating through the string, to recognize and process
- // diphthongs correctly. For clarity, we define a state for each vowel and
- // each vowel with accent, although a few of these do not actually need any
- // special treatment and could be folded into kStart.
-private:
- enum GreekStates {
- kStart,
- kAlpha,
- kEpsilon,
- kEta,
- kIota,
- kOmicron,
- kUpsilon,
- kOmega,
- kAlphaAcc,
- kEpsilonAcc,
- kEtaAcc,
- kIotaAcc,
- kOmicronAcc,
- kUpsilonAcc,
- kOmegaAcc,
- kOmicronUpsilon,
- kDiaeresis
- };
-
-public:
- class State {
- public:
- State()
- : mState(kStart)
- {
- }
-
- State(const GreekStates& aState)
- : mState(aState)
- {
- }
-
- void Reset()
- {
- mState = kStart;
- }
-
- operator GreekStates() const
- {
- return mState;
- }
-
- private:
- GreekStates mState;
- };
-
- static uint32_t UpperCase(uint32_t aCh, State& aState);
-};
-
#ifdef MOZILLA_INTERNAL_API
class nsCaseInsensitiveStringComparator : public nsStringComparator
diff --git a/intl/unicharutil/util/objs.mozbuild b/intl/unicharutil/util/objs.mozbuild
index b832a15eb64..d5c8a31ba31 100644
--- a/intl/unicharutil/util/objs.mozbuild
+++ b/intl/unicharutil/util/objs.mozbuild
@@ -4,7 +4,9 @@
# 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/.
-intl_unicharutil_util_lcppsrcs = []
+intl_unicharutil_util_lcppsrcs = [
+ 'GreekCasing.cpp',
+]
if CONFIG['ENABLE_INTL_API']:
intl_unicharutil_util_lcppsrcs += [
@@ -12,6 +14,7 @@ if CONFIG['ENABLE_INTL_API']:
]
intl_unicharutil_util_lcppsrcs += [
+ 'IrishCasing.cpp',
'nsBidiUtils.cpp',
'nsSpecialCasingData.cpp',
'nsUnicharUtils.cpp',
diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp
index ec37c297f69..db955571a38 100644
--- a/layout/generic/nsTextRunTransformations.cpp
+++ b/layout/generic/nsTextRunTransformations.cpp
@@ -17,6 +17,8 @@
#include "nsTextFrameUtils.h"
#include "nsIPersistentProperties2.h"
#include "nsNetUtil.h"
+#include "GreekCasing.h"
+#include "IrishCasing.h"
// Unicode characters needing special casing treatment in tr/az languages
#define LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE 0x0130
@@ -224,9 +226,10 @@ GetParametersForInner(nsTransformedTextRun* aTextRun, uint32_t* aFlags,
// same setting here, if the behavior is shared by other languages.
enum LanguageSpecificCasingBehavior {
eLSCB_None, // default non-lang-specific behavior
- eLSCB_Turkish, // preserve dotted/dotless-i distinction in uppercase
eLSCB_Dutch, // treat "ij" digraph as a unit for capitalization
- eLSCB_Greek // strip accent when uppercasing Greek vowels
+ eLSCB_Greek, // strip accent when uppercasing Greek vowels
+ eLSCB_Irish, // keep prefix letters as lowercase when uppercasing Irish
+ eLSCB_Turkish // preserve dotted/dotless-i distinction in uppercase
};
static LanguageSpecificCasingBehavior
@@ -245,6 +248,9 @@ GetCasingFor(const nsIAtom* aLang)
if (aLang == nsGkAtoms::el) {
return eLSCB_Greek;
}
+ if (aLang == nsGkAtoms::ga_ie) {
+ return eLSCB_Irish;
+ }
return eLSCB_None;
}
@@ -277,7 +283,9 @@ nsCaseTransformTextRunFactory::TransformString(
const nsIAtom* lang = aLanguage;
LanguageSpecificCasingBehavior languageSpecificCasing = GetCasingFor(lang);
- GreekCasing::State greekState;
+ mozilla::GreekCasing::State greekState;
+ mozilla::IrishCasing::State irishState;
+ uint32_t irishMark = uint32_t(-1); // location of possible prefix letter(s)
for (uint32_t i = 0; i < length; ++i) {
uint32_t ch = str[i];
@@ -292,11 +300,14 @@ nsCaseTransformTextRunFactory::TransformString(
lang = styleContext->StyleFont()->mLanguage;
languageSpecificCasing = GetCasingFor(lang);
greekState.Reset();
+ irishState.Reset();
+ irishMark = uint32_t(-1);
}
}
int extraChars = 0;
const mozilla::unicode::MultiCharMapping *mcm;
+ bool inhibitBreakBefore = false; // have we just deleted preceding hyphen?
if (NS_IS_HIGH_SURROGATE(ch) && i < length - 1 &&
NS_IS_LOW_SURROGATE(str[i + 1])) {
@@ -396,10 +407,63 @@ nsCaseTransformTextRunFactory::TransformString(
}
if (languageSpecificCasing == eLSCB_Greek) {
- ch = GreekCasing::UpperCase(ch, greekState);
+ ch = mozilla::GreekCasing::UpperCase(ch, greekState);
break;
}
+ if (languageSpecificCasing == eLSCB_Irish) {
+ bool mark;
+ uint8_t action;
+ ch = mozilla::IrishCasing::UpperCase(ch, irishState, mark, action);
+ if (mark) {
+ irishMark = aConvertedString.Length();
+ break;
+ } else if (action) {
+ nsString& str = aConvertedString; // shorthand
+ switch (action) {
+ case 1:
+ // lowercase a single prefix letter
+ NS_ASSERTION(str.Length() > 0 && irishMark < str.Length(),
+ "bad irishMark!");
+ str.SetCharAt(ToLowerCase(str[irishMark]), irishMark);
+ irishMark = uint32_t(-1);
+ break;
+ case 2:
+ // lowercase two prefix letters (immediately before current pos)
+ NS_ASSERTION(str.Length() >= 2 && irishMark == str.Length() - 2,
+ "bad irishMark!");
+ str.SetCharAt(ToLowerCase(str[irishMark]), irishMark);
+ str.SetCharAt(ToLowerCase(str[irishMark + 1]), irishMark + 1);
+ irishMark = uint32_t(-1);
+ break;
+ case 3:
+ // lowercase one prefix letter, and delete following hyphen
+ // (which must be the immediately-preceding char)
+ NS_ASSERTION(str.Length() >= 2 && irishMark == str.Length() - 2,
+ "bad irishMark!");
+ str.Replace(irishMark, 2, ToLowerCase(str[irishMark]));
+ aDeletedCharsArray[irishMark + 1] = true;
+ // Remove the trailing entries (corresponding to the deleted hyphen)
+ // from the auxiliary arrays.
+ aCharsToMergeArray.SetLength(aCharsToMergeArray.Length() - 1);
+ if (aTextRun) {
+ aStyleArray->SetLength(aStyleArray->Length() - 1);
+ aCanBreakBeforeArray->SetLength(aCanBreakBeforeArray->Length() - 1);
+ inhibitBreakBefore = true;
+ }
+ mergeNeeded = true;
+ irishMark = uint32_t(-1);
+ break;
+ }
+ // ch has been set to the uppercase for current char;
+ // No need to check for SpecialUpper here as none of the characters
+ // that could trigger an Irish casing action have special mappings.
+ break;
+ }
+ // If we didn't have any special action to perform, fall through
+ // to check for special uppercase (ß)
+ }
+
mcm = mozilla::unicode::SpecialUpper(ch);
if (mcm) {
int j = 0;
@@ -467,7 +531,8 @@ nsCaseTransformTextRunFactory::TransformString(
aCharsToMergeArray.AppendElement(false);
if (aTextRun) {
aStyleArray->AppendElement(styleContext);
- aCanBreakBeforeArray->AppendElement(aTextRun->CanBreakLineBefore(i));
+ aCanBreakBeforeArray->AppendElement(inhibitBreakBefore ? false :
+ aTextRun->CanBreakLineBefore(i));
}
if (IS_IN_BMP(ch)) {
diff --git a/layout/reftests/text-transform/irish-uppercase-1-ref.html b/layout/reftests/text-transform/irish-uppercase-1-ref.html
new file mode 100644
index 00000000000..a9dc7ddc12c
--- /dev/null
+++ b/layout/reftests/text-transform/irish-uppercase-1-ref.html
@@ -0,0 +1,120 @@
+
+
+
+
+Test for Irish uppercasing
+
+
+
+ ORD NA bhFOCAL
+/ COSÁN NA bhFILÍ
+/ ÁR bPOBAL
+/ NÓRA NA bPORTACH
+/ I dTOSACH BÁIRE
+/ AN GHAEILGE I dTUAISCEART NA hÉIREANN
+/ AS AN gCEANTAR SIN
+/ I gCONTAE NA MÍ AGUS I gCONAMARA
+/ DÉ hAOINE
+/ OIRTHEAR NA hÁISE
+/ PARLAIMINT NA hEORPA
+/ POBLACHT NA hÉIREANN
+/ EALAÍN NA hIODÁILE
+/ NA hÍOSÁNAIGH
+/ ACADAMH NA hOLLSCOLAÍOCHTA
+/ TÍR NA hÓIGE
+/ TOGHCHÁN NA hUACHTARÁNACHTA
+/ NA hÚDARÁIS CHÁNACH
+/ I mBUN MO MHACHNAMH
+/ I mBÉAL FEIRSTE AGUS I mBAILE ÁTHA CLIATH
+/ ÁR nACMHAINNÍ UISCE
+/ EOLAÍOCHT NA nÁBHAR
+/ LUCHT NA nEALAÍON
+/ CEOL NA nÉAN
+/ ORD NA nIMEACHTAÍ
+/ LUCHT ADHARTHA NA nÍOMHÁNNA
+/ GNÉITHE DÁR nOIDHREACHT
+/ CULTÚR NA nÓG
+/ OCHT nUAIRE SA LÁ
+/ FORMHÓR NA nÚDARÁS
+/ ÁR nATHAIR
+/ CLÁR NA nÁBHAR
+/ LOCH nEATHACH
+/ CUMANN NA nÉIREANNACH AONTAITHE
+/ GRÉASÁN NA nIONTAS
+/ NÓIBHÍSEACHT NA nÍOSÁNACH
+/ I gCEANTAR NA nOILEÁN
+/ TÍR NA nÓG
+/ BAILE NA nULTACH
+/ GORT NA nÚLL
+/ CEOL NA nDAOINE
+/ I nDÚN NA nGALL
+/ TÁIM I nGRÁ LEAT
+/ LABHAIR SÉ I nGAEILGE!
+/ CÉN tAM É?
+/ TÁ AN tÁDH ORM INNIU!
+/ DEN OBAIR AN tEOLAS
+/ AN tÉILEAMH A ÍOC
+/ AN tINNEALL CUARDAIGH IS FEARR
+/ AN tÍOCHTAR A CHUR IN UACHTAR
+/ TABHAIR AN tORDÚ SEO DÓ!
+/ TÁ AN tÓR BUÍ AIGE.
+/ AN tUISCE BEATHA AR AN TÁBLA.
+/ AN tÚRSCÉAL IS DEIREANAÍ
+/ AN tACHT OIDEACHAIS
+/ AN tÁIVÉ MÁIRIA
+/ AN tEARRACH ARABACH
+/ AN tÉIRÍ AMACH
+/ AN tIMEALL
+/ AN tÍOSÁNACH PEADAR CANISIUS
+/ AN tOILEÁNACH
+/ AN tÓR MUIRE
+/ AN tUASAL ÉAMON Ó CUÍV
+/ AN tÚDARÁS UM BÓITHRE NÁISIÚNTA
+/ AR AON tSLÍ
+/ BÉAL ÁTHA AN tSLÉIBHE
+/ AMACH ÓN tSNÁTHAID
+/ BANRÍON AN tSNEACHTA
+/ AR AN tSRÁID
+/ CAINT AN tSRÁIDBHAILE
+/ CORA CRUA AN tSAOIL
+/ BHOLADH AN tSÁILE
+/ UAIR SA tSEACHTAIN
+/ DEIREADH AN tSÉASÚIR
+/ FEAR AN tSIOPA
+/ AN tSÍOCHÁIN A CHOIMEÁD
+/ AN tSOCHAÍ FAISNÉISE
+/ GAOTH AN tSÓLÁIS
+/ IS BEAG AN tSUIM IAD
+/ INFHEICTHE AG AN tSÚIL
+/ CNOC AN tSAMHRAIDH
+/ CIONN tSÁILE
+/ AN tSEIRBHÍS PHOIBLÍ
+/ BAILE AN tSÉIPÉIL
+/ AN tSIRIA
+/ AN tSÍN
+/ OIFIG AN tSOLÁTHAIR
+/ POLL AN tSÓMAIS
+/ EOLAIRE AN tSUÍMH
+/ CASADH AN tSÚGÁIN
+/ SCRÍOBHFAIDH
+/ PREABPHAS
+/ ÚSÁIDTEAR
+/ SNAGCHEOL
+/ STÁITSE IMBOLC
+/ IN-ATHNUAITE AGATSA
+/ TEANGA DHOMHANDA
+/ RÉALTSRUTH
+/ NA HATAÍ
+/ NA HATAÍ
+/ ÁR NATHAIR
+/ ÁR NATHAIR
+/ T-LÉINE
+/ TORC ALLTA
+/ TSK TSK TSK A CHARA
+
+
diff --git a/layout/reftests/text-transform/irish-uppercase-1.html b/layout/reftests/text-transform/irish-uppercase-1.html
new file mode 100644
index 00000000000..9e4743917ee
--- /dev/null
+++ b/layout/reftests/text-transform/irish-uppercase-1.html
@@ -0,0 +1,120 @@
+
+
+
+
+Test for Irish uppercasing
+
+
+
+ ord na bhfocal
+/ Cosán na bhFilí
+/ ár bpobal
+/ Nóra na bPortach
+/ i dtosach báire
+/ An Ghaeilge i dTuaisceart na hÉireann
+/ as an gceantar sin
+/ I gContae na Mí agus i gConamara
+/ Dé hAoine
+/ Oirthear na hÁise
+/ Parlaimint na hEorpa
+/ Poblacht na hÉireann
+/ Ealaín na hIodáile
+/ na hÍosánaigh
+/ Acadamh na hOllscolaíochta
+/ Tír na hÓige
+/ toghchán na hUachtaránachta
+/ na hÚdaráis Chánach
+/ I mbun mo mhachnamh
+/ I mBéal Feirste agus i mBaile Átha Cliath
+/ ár n-acmhainní uisce
+/ eolaíocht na n-ábhar
+/ lucht na n-ealaíon
+/ ceol na n-éan
+/ ord na n-imeachtaí
+/ lucht adhartha na n-íomhánna
+/ gnéithe dár n-oidhreacht
+/ cultúr na n-óg
+/ ocht n-uaire sa lá
+/ formhór na n-údarás
+/ Ár nAthair
+/ Clár na nÁbhar
+/ Loch nEathach
+/ Cumann na nÉireannach Aontaithe
+/ Gréasán na nIontas
+/ nóibhíseacht na nÍosánach
+/ i gCeantar na nOileán
+/ Tír na nÓg
+/ Baile na nUltach
+/ Gort na nÚll
+/ ceol na ndaoine
+/ i nDún na nGall
+/ táim i ngrá leat
+/ labhair sé i nGaeilge!
+/ cén t-am é?
+/ tá an t-ádh orm inniu!
+/ Den obair an t-eolas
+/ An t-éileamh a íoc
+/ an t-inneall cuardaigh is fearr
+/ an t-íochtar a chur in uachtar
+/ Tabhair an t-ordú seo dó!
+/ Tá an t-ór buí aige.
+/ an t-uisce beatha ar an tábla.
+/ an t-úrscéal is deireanaí
+/ An tAcht Oideachais
+/ an tÁivé Máiria
+/ An tEarrach Arabach
+/ An tÉirí Amach
+/ An tImeall
+/ An tÍosánach Peadar Canisius
+/ An tOileánach
+/ An tÓr Muire
+/ an tUasal Éamon Ó Cuív
+/ An tÚdarás um Bóithre Náisiúnta
+/ ar aon tslí
+/ Béal Átha an tSléibhe
+/ Amach ón tsnáthaid
+/ Banríon an tSneachta
+/ ar an tsráid
+/ Caint an tSráidbhaile
+/ cora crua an tsaoil
+/ bholadh an tsáile
+/ uair sa tseachtain
+/ deireadh an tséasúir
+/ fear an tsiopa
+/ an tsíocháin a choimeád
+/ an tsochaí faisnéise
+/ gaoth an tsóláis
+/ Is beag an tsuim iad
+/ infheicthe ag an tsúil
+/ Cnoc an tSamhraidh
+/ Cionn tSáile
+/ an tSeirbhís Phoiblí
+/ Baile an tSéipéil
+/ An tSiria
+/ An tSín
+/ Oifig an tSoláthair
+/ Poll an tSómais
+/ Eolaire an tSuímh
+/ Casadh an tSúgáin
+/ scríobhfaidh
+/ preabphas
+/ úsáidtear
+/ snagcheol
+/ Stáitse Imbolc
+/ in-athnuaite agatsa
+/ Teanga Dhomhanda
+/ Réaltsruth
+/ na hataí
+/ Na Hataí
+/ ár nathair
+/ Ár Nathair
+/ t-léine
+/ torc allta
+/ tsk tsk tsk a chara
+
+
diff --git a/layout/reftests/text-transform/reftest.list b/layout/reftests/text-transform/reftest.list
index f36280e9e01..be23faf642d 100644
--- a/layout/reftests/text-transform/reftest.list
+++ b/layout/reftests/text-transform/reftest.list
@@ -28,6 +28,7 @@ HTTP(..) != small-caps-turkish-1.html small-caps-turkish-1-notref.html
== greek-uppercase-1.html greek-uppercase-1-ref.html
== greek-uppercase-2.html greek-uppercase-2-ref.html
HTTP(..) == greek-small-caps-1.html greek-small-caps-1-ref.html
+== irish-uppercase-1.html irish-uppercase-1-ref.html
== fullwidth-1.html fullwidth-1-ref.html
== fullwidth-2.html fullwidth-2-ref.html
== fullwidth-all.html fullwidth-all-ref.html
diff --git a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
index b820ab2c5f1..29b43c29d12 100644
--- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
+++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
@@ -133,16 +133,13 @@ VcmSIPCCBinding::VcmSIPCCBinding ()
class VcmIceOpaque : public NrIceOpaque {
public:
- VcmIceOpaque(cc_streamid_t stream_id,
- cc_call_handle_t call_handle,
+ VcmIceOpaque(cc_call_handle_t call_handle,
uint16_t level) :
- stream_id_(stream_id),
call_handle_(call_handle),
level_(level) {}
virtual ~VcmIceOpaque() {}
- cc_streamid_t stream_id_;
cc_call_handle_t call_handle_;
uint16_t level_;
};
@@ -172,8 +169,8 @@ void VcmSIPCCBinding::CandidateReady(NrIceMediaStream* stream,
MOZ_ASSERT(opaque);
VcmIceOpaque *vcm_opaque = static_cast(opaque);
- CSFLogDebug(logTag, "Candidate ready on call %u, level %u",
- vcm_opaque->call_handle_, vcm_opaque->level_);
+ CSFLogDebug(logTag, "Candidate ready on call %u, level %u: %s",
+ vcm_opaque->call_handle_, vcm_opaque->level_, candidate.c_str());
char *candidate_tmp = (char *)malloc(candidate.size() + 1);
if (!candidate_tmp)
@@ -595,11 +592,15 @@ static short vcmRxAllocICE_s(TemporaryRef ctx_in,
*candidatesp = nullptr;
*candidate_ctp = 0;
- // Set the opaque so we can correlate events.
- stream->SetOpaque(new VcmIceOpaque(stream_id, call_handle, level));
+ // This can be called multiple times; don't connect to the signal more than
+ // once (see bug 1018473 for an explanation).
+ if (!stream->opaque()) {
+ // Set the opaque so we can correlate events.
+ stream->SetOpaque(new VcmIceOpaque(call_handle, level));
- // Attach ourself to the candidate signal.
- VcmSIPCCBinding::connectCandidateSignal(stream);
+ // Attach ourself to the candidate signal.
+ VcmSIPCCBinding::connectCandidateSignal(stream);
+ }
std::vector candidates = stream->GetCandidates();
CSFLogDebug( logTag, "%s: Got %lu candidates", __FUNCTION__, (unsigned long) candidates.size());
diff --git a/media/webrtc/signaling/test/signaling_unittests.cpp b/media/webrtc/signaling/test/signaling_unittests.cpp
index 13887fea34d..763631a272a 100644
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -477,6 +477,12 @@ TestObserver::OnIceCandidate(uint16_t level,
{
std::cout << name << ": onIceCandidate [" << level << "/"
<< mid << "] " << candidate << std::endl;
+
+ // Check for duplicates.
+ for (auto it = candidates.begin(); it != candidates.end(); ++it) {
+ EXPECT_NE(*it, candidate) << "Duplicate candidate";
+ }
+
candidates.push_back(candidate);
return NS_OK;
}
diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js
index 4ea7c8937f7..060b83cfe69 100644
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3144,7 +3144,7 @@ pref("font.name.monospace.ko", "Fira Mono OT");
pref("font.name.serif.th", "Charis SIL Compact");
pref("font.name.sans-serif.th", "Fira Sans OT");
pref("font.name.monospace.th", "Fira Mono OT");
-pref("font.name-list.sans-serif.th", "Fira Sans OT, Droid Sans Thai");
+pref("font.name-list.sans-serif.th", "Fira Sans OT, Noto Sans Thai, Droid Sans Thai");
pref("font.name.serif.tr", "Charis SIL Compact");
pref("font.name.sans-serif.tr", "Fira Sans OT");
diff --git a/testing/marionette/client/marionette/tests/unit-tests.ini b/testing/marionette/client/marionette/tests/unit-tests.ini
index 86c3b63398e..9174d6c47fd 100644
--- a/testing/marionette/client/marionette/tests/unit-tests.ini
+++ b/testing/marionette/client/marionette/tests/unit-tests.ini
@@ -26,3 +26,4 @@ skip = false
[include:../../../../../dom/system/tests/marionette/manifest.ini]
[include:../../../../../dom/nfc/tests/marionette/manifest.ini]
[include:../../../../../dom/events/test/marionette/manifest.ini]
+[include:../../../../../dom/wifi/test/marionette/manifest.ini]
diff --git a/testing/xpcshell/xpcshell_b2g.ini b/testing/xpcshell/xpcshell_b2g.ini
index 7773dafe67a..5f797c8c315 100644
--- a/testing/xpcshell/xpcshell_b2g.ini
+++ b/testing/xpcshell/xpcshell_b2g.ini
@@ -8,6 +8,7 @@
[include:dom/system/gonk/tests/xpcshell.ini]
[include:dom/wappush/tests/xpcshell.ini]
[include:toolkit/components/osfile/tests/xpcshell/xpcshell.ini]
+[include:toolkit/components/captivedetect/test/unit/xpcshell.ini]
[include:toolkit/devtools/apps/tests/unit/xpcshell.ini]
[include:toolkit/devtools/debugger/tests/unit/xpcshell.ini]
[include:toolkit/devtools/qrcode/tests/unit/xpcshell.ini]
diff --git a/toolkit/components/captivedetect/captivedetect.js b/toolkit/components/captivedetect/captivedetect.js
index af1bd232665..24ac45b719d 100644
--- a/toolkit/components/captivedetect/captivedetect.js
+++ b/toolkit/components/captivedetect/captivedetect.js
@@ -10,6 +10,10 @@ const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
+XPCOMUtils.defineLazyServiceGetter(this, "gSysMsgr",
+ "@mozilla.org/system-message-internal;1",
+ "nsISystemMessagesInternal");
+
const DEBUG = false; // set to true to show debug messages
const kCAPTIVEPORTALDETECTOR_CONTRACTID = '@mozilla.org/toolkit/captive-detector;1';
@@ -17,6 +21,9 @@ const kCAPTIVEPORTALDETECTOR_CID = Components.ID('{d9cd00ba-aa4d-47b1-879
const kOpenCaptivePortalLoginEvent = 'captive-portal-login';
const kAbortCaptivePortalLoginEvent = 'captive-portal-login-abort';
+const kCaptivePortalLoginSuccessEvent = 'captive-portal-login-success';
+
+const kCaptivePortalSystemMessage = 'captive-portal';
function URLFetcher(url, timeout) {
let self = this;
@@ -332,6 +339,7 @@ CaptivePortalDetector.prototype = {
this._loginObserver.attach();
this._runningRequest['eventId'] = id;
this._sendEvent(kOpenCaptivePortalLoginEvent, details);
+ gSysMsgr.broadcastMessage(kCaptivePortalSystemMessage, {});
},
_mayRetry: function _mayRetry() {
@@ -350,6 +358,16 @@ CaptivePortalDetector.prototype = {
this._runningRequest.callback.complete(success);
}
+ // Only when the request has a event id and |success| is true
+ // do we need to notify the login-success event.
+ if (this._runningRequest.hasOwnProperty('eventId') && success) {
+ let details = {
+ type: kCaptivePortalLoginSuccessEvent,
+ id: this._runningRequest['eventId'],
+ };
+ this._sendEvent(kCaptivePortalLoginSuccessEvent, details);
+ }
+
// Continue the following request
this._runningRequest['complete'] = true;
this._removeRequest(this._runningRequest.interfaceName);
diff --git a/toolkit/components/captivedetect/test/unit/test_captive_portal_found.js b/toolkit/components/captivedetect/test/unit/test_captive_portal_found.js
index f8dbea40b85..457b0ad438c 100644
--- a/toolkit/components/captivedetect/test/unit/test_captive_portal_found.js
+++ b/toolkit/components/captivedetect/test/unit/test_captive_portal_found.js
@@ -32,6 +32,13 @@ function fakeUIResponse() {
do_check_eq(++step, 2);
}
}, 'captive-portal-login', false);
+
+ Services.obs.addObserver(function observe(subject, topic, data) {
+ if (topic === 'captive-portal-login-success') {
+ do_check_eq(++step, 4);
+ gServer.stop(do_test_finished);
+ }
+ }, 'captive-portal-login-success', false);
}
function test_portal_found() {
@@ -44,9 +51,11 @@ function test_portal_found() {
gCaptivePortalDetector.finishPreparation(kInterfaceName);
},
complete: function complete(success) {
+ // Since this is a synchronous callback, it must happen before
+ // 'captive-portal-login-success' is received.
+ // (Check captivedetect.js::executeCallback
do_check_eq(++step, 3);
do_check_true(success);
- gServer.stop(do_test_finished);
},
};
diff --git a/toolkit/components/captivedetect/test/unit/test_captive_portal_found_303.js b/toolkit/components/captivedetect/test/unit/test_captive_portal_found_303.js
index 857bb23c768..f0715d49a71 100644
--- a/toolkit/components/captivedetect/test/unit/test_captive_portal_found_303.js
+++ b/toolkit/components/captivedetect/test/unit/test_captive_portal_found_303.js
@@ -34,6 +34,13 @@ function fakeUIResponse() {
do_check_eq(++step, 2);
}
}, 'captive-portal-login', false);
+
+ Services.obs.addObserver(function observe(subject, topic, data) {
+ if (topic === 'captive-portal-login-success') {
+ do_check_eq(++step, 4);
+ gServer.stop(do_test_finished);
+ }
+ }, 'captive-portal-login-success', false);
}
function test_portal_found() {
@@ -48,7 +55,6 @@ function test_portal_found() {
complete: function complete(success) {
do_check_eq(++step, 3);
do_check_true(success);
- gServer.stop(do_test_finished);
},
};
@@ -57,12 +63,4 @@ function test_portal_found() {
function run_test() {
run_captivedetect_test(xhr_handler, fakeUIResponse, test_portal_found);
-
- server = new HttpServer();
- server.registerPathHandler(kCanonicalSitePath, xhr_handler);
- server.start(4444);
-
- fakeUIResponse();
-
- test_portal_found();
}
diff --git a/toolkit/components/captivedetect/test/unit/test_multiple_requests.js b/toolkit/components/captivedetect/test/unit/test_multiple_requests.js
index 63d8e66ebb9..2a45d371b40 100644
--- a/toolkit/components/captivedetect/test/unit/test_multiple_requests.js
+++ b/toolkit/components/captivedetect/test/unit/test_multiple_requests.js
@@ -10,6 +10,7 @@ const kOtherInterfaceName = 'ril';
var server;
var step = 0;
var loginFinished = false;
+var loginSuccessCount = 0;
function xhr_handler(metadata, response) {
response.setStatusLine(metadata.httpVersion, 200, 'OK');
@@ -33,6 +34,16 @@ function fakeUIResponse() {
do_check_eq(++step, 2);
}
}, 'captive-portal-login', false);
+
+ Services.obs.addObserver(function observe(subject, topic, data) {
+ if (topic === 'captive-portal-login-success') {
+ loginSuccessCount++;
+ if (loginSuccessCount > 1) {
+ throw "We should only receive 'captive-portal-login-success' once";
+ }
+ do_check_eq(++step, 4);
+ }
+ }, 'captive-portal-login-success', false);
}
function test_multiple_requests() {
@@ -53,11 +64,11 @@ function test_multiple_requests() {
let otherCallback = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
prepare: function prepare() {
- do_check_eq(++step, 4);
+ do_check_eq(++step, 5);
gCaptivePortalDetector.finishPreparation(kOtherInterfaceName);
},
complete: function complete(success) {
- do_check_eq(++step, 5);
+ do_check_eq(++step, 6);
do_check_true(success);
gServer.stop(do_test_finished);
}
diff --git a/widget/shared/NativeKeyToDOMCodeName.h b/widget/shared/NativeKeyToDOMCodeName.h
index a75e20dcd48..ecb16427b50 100644
--- a/widget/shared/NativeKeyToDOMCodeName.h
+++ b/widget/shared/NativeKeyToDOMCodeName.h
@@ -694,36 +694,31 @@ CODE_MAP_X11(Pause, 0x007F)
CODE_MAP_ANDROID(Pause, 0x0077)
// Media keys
-
-// NOTE: Following media keys which cause scancode 0xE000 on Windows should be
-// mapped with virtual keycode.
-// See KeyboardLayout::ConvertScanCodeToCodeNameIndex() for the detail.
-
-// CODE_MAP_WIN(BrowserBack, 0xE000) // VK_BROWSER_BACK
+CODE_MAP_WIN(BrowserBack, 0xE06A)
CODE_MAP_X11(BrowserBack, 0x00A6)
CODE_MAP_ANDROID(BrowserBack, 0x009E)
-// CODE_MAP_WIN(BrowserFavorites, 0xE000) // VK_BROWSER_FAVORITES
+CODE_MAP_WIN(BrowserFavorites, 0xE066)
CODE_MAP_X11(BrowserFavorites, 0x00A4)
CODE_MAP_ANDROID(BrowserFavorites, 0x009C)
-// CODE_MAP_WIN(BrowserForward, 0xE000) // VK_BROWSER_FORWARD
+CODE_MAP_WIN(BrowserForward, 0xE069)
CODE_MAP_X11(BrowserForward, 0x00A7)
CODE_MAP_ANDROID(BrowserForward, 0x009F)
-// CODE_MAP_WIN(BrowserHome, 0xE000) // VK_BROWSER_HOME
+CODE_MAP_WIN(BrowserHome, 0xE032)
CODE_MAP_X11(BrowserHome, 0x00B4)
// CODE_MAP_ANDROID(BrowserHome) // not available? works as Home key.
-// CODE_MAP_WIN(BrowserRefresh, 0xE000) // VK_BROWSER_REFRESH
+CODE_MAP_WIN(BrowserRefresh, 0xE067)
CODE_MAP_X11(BrowserRefresh, 0x00B5)
CODE_MAP_ANDROID(BrowserRefresh, 0x00AD)
-// CODE_MAP_WIN(BrowserSearch, 0xE000) // VK_BROWSER_SEARCH
+CODE_MAP_WIN(BrowserSearch, 0xE065)
CODE_MAP_X11(BrowserSearch, 0x00E1)
CODE_MAP_ANDROID(BrowserSearch, 0x00D9)
-// CODE_MAP_WIN(BrowserStop, 0xE000) // VK_BROWSER_STOP
+CODE_MAP_WIN(BrowserStop, 0xE068)
CODE_MAP_X11(BrowserStop, 0x0088)
CODE_MAP_ANDROID(BrowserStop, 0x0080)
@@ -732,35 +727,35 @@ CODE_MAP_ANDROID(BrowserStop, 0x0080)
CODE_MAP_X11(Eject, 0x00A9)
CODE_MAP_ANDROID(Eject, 0x00A1)
-// CODE_MAP_WIN(LaunchApp1, 0xE000) // VK_LAUNCH_APP1
+CODE_MAP_WIN(LaunchApp1, 0xE06B)
CODE_MAP_X11(LaunchApp1, 0x0098)
CODE_MAP_ANDROID(LaunchApp1, 0x0090)
-// CODE_MAP_WIN(LaunchApp2, 0xE000) // VK_LAUNCH_APP2
+CODE_MAP_WIN(LaunchApp2, 0xE021)
CODE_MAP_X11(LaunchApp2, 0x0094)
// CODE_MAP_ANDROID(LaunchApp2) // not available?
-// CODE_MAP_WIN(LaunchMail, 0xE000) // VK_LAUNCH_MAIL
+CODE_MAP_WIN(LaunchMail, 0xE06C)
CODE_MAP_X11(LaunchMail, 0x00A3)
// CODE_MAP_ANDROID(LaunchMail) // not available?
-// CODE_MAP_WIN(MediaPlayPause, 0xE000) // VK_MEDIA_PLAY_PAUSE
+CODE_MAP_WIN(MediaPlayPause, 0xE022)
CODE_MAP_X11(MediaPlayPause, 0x00AC)
CODE_MAP_ANDROID(MediaPlayPause, 0x00A4)
-// CODE_MAP_WIN(MediaSelect, 0xE000) // VK_LAUNCH_MEDIA_SELECT
+CODE_MAP_WIN(MediaSelect, 0xE06D)
CODE_MAP_X11(MediaSelect, 0x00B3)
// CODE_MAP_ANDROID(MediaSelect) // not available?
-// CODE_MAP_WIN(MediaStop, 0xE000) // VK_MEDIA_STOP
+CODE_MAP_WIN(MediaStop, 0xE024)
CODE_MAP_X11(MediaStop, 0x00AE)
CODE_MAP_ANDROID(MediaStop, 0x00A6)
-// CODE_MAP_WIN(MediaTrackNext, 0xE000) // VK_MEDIA_NEXT_TRACK
+CODE_MAP_WIN(MediaTrackNext, 0xE019)
CODE_MAP_X11(MediaTrackNext, 0x00AB)
CODE_MAP_ANDROID(MediaTrackNext, 0x00A3)
-// CODE_MAP_WIN(MediaTrackPrevious, 0xE000) // VK_MEDIA_PREV_TRACK
+CODE_MAP_WIN(MediaTrackPrevious, 0xE010)
CODE_MAP_X11(MediaTrackPrevious, 0x00AD)
CODE_MAP_ANDROID(MediaTrackPrevious, 0x00A5)
@@ -773,17 +768,17 @@ CODE_MAP_ANDROID(Power, 0x0074)
// CODE_MAP_X11(Sleep) // not available?
CODE_MAP_ANDROID(Sleep, 0x008E)
-// CODE_MAP_WIN(VolumeDown, 0xE000) // VK_VOLUME_DOWN
+CODE_MAP_WIN(VolumeDown, 0xE02E)
CODE_MAP_MAC(VolumeDown, kVK_VolumeDown) // not available?
CODE_MAP_X11(VolumeDown, 0x007A)
CODE_MAP_ANDROID(VolumeDown, 0x0072)
-// CODE_MAP_WIN(VolumeMute, 0xE000) // VK_VOLUME_MUTE
+CODE_MAP_WIN(VolumeMute, 0xE020)
CODE_MAP_MAC(VolumeMute, kVK_Mute) // not available?
CODE_MAP_X11(VolumeMute, 0x0079)
CODE_MAP_ANDROID(VolumeMute, 0x0071)
-// CODE_MAP_WIN(VolumeUp, 0xE000) // VK_VOLUME_UP
+CODE_MAP_WIN(VolumeUp, 0xE030)
CODE_MAP_MAC(VolumeUp, kVK_VolumeUp) // not available?
CODE_MAP_X11(VolumeUp, 0x007B)
CODE_MAP_ANDROID(VolumeUp, 0x0073) // side of body, not on keyboard
diff --git a/widget/windows/KeyboardLayout.cpp b/widget/windows/KeyboardLayout.cpp
index ef4498413f8..2b2da8b6c35 100644
--- a/widget/windows/KeyboardLayout.cpp
+++ b/widget/windows/KeyboardLayout.cpp
@@ -40,6 +40,11 @@
#include
#endif
+// In WinUser.h, MAPVK_VK_TO_VSC_EX is defined only when WINVER >= 0x0600
+#ifndef MAPVK_VK_TO_VSC_EX
+#define MAPVK_VK_TO_VSC_EX (4)
+#endif
+
namespace mozilla {
namespace widget {
@@ -584,15 +589,25 @@ NativeKey::NativeKey(nsWindowBase* aWidget,
mKeyboardLayout = keyboardLayout->GetLayout();
mScanCode = WinUtils::GetScanCode(mMsg.lParam);
mIsExtended = WinUtils::IsExtendedScanCode(mMsg.lParam);
- // On WinXP and WinServer2003, we cannot compute the virtual keycode for
- // extended keys due to the API limitation.
- bool canComputeVirtualKeyCodeFromScanCode =
- (!mIsExtended || IsVistaOrLater());
switch (mMsg.message) {
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP: {
+ // If the key message is sent from other application like a11y tools, the
+ // scancode value might not be set proper value. Then, probably the value
+ // is 0.
+ // NOTE: If the virtual keycode can be caused by both non-extended key
+ // and extended key, the API returns the non-extended key's
+ // scancode. E.g., VK_LEFT causes "4" key on numpad.
+ if (!mScanCode) {
+ uint16_t scanCodeEx = ComputeScanCodeExFromVirtualKeyCode(mMsg.wParam);
+ if (scanCodeEx) {
+ mScanCode = static_cast(scanCodeEx & 0xFF);
+ uint8_t extended = static_cast((scanCodeEx & 0xFF00) >> 8);
+ mIsExtended = (extended == 0xE0) || (extended == 0xE1);
+ }
+ }
// First, resolve the IME converted virtual keycode to its original
// keycode.
if (mMsg.wParam == VK_PROCESSKEY) {
@@ -648,7 +663,7 @@ NativeKey::NativeKey(nsWindowBase* aWidget,
break;
}
- if (!canComputeVirtualKeyCodeFromScanCode) {
+ if (!CanComputeVirtualKeyCodeFromScanCode()) {
// The right control key and the right alt key are extended keys.
// Therefore, we never get VK_RCONTRL and VK_RMENU for the result of
// MapVirtualKeyEx() on WinXP or WinServer2003.
@@ -679,11 +694,9 @@ NativeKey::NativeKey(nsWindowBase* aWidget,
// Otherwise, compute the virtual keycode with MapVirtualKeyEx().
mVirtualKeyCode = ComputeVirtualKeyCodeFromScanCodeEx();
- // The result might be unexpected value due to the scan code is
- // wrong. For example, any key messages can be generated by
- // SendMessage() or PostMessage() from applications. So, it's possible
- // failure. Then, let's respect the extended flag even if it might be
- // set intentionally.
+ // Following code shouldn't be used now because we compute scancode value
+ // if we detect that the sender doesn't set proper scancode.
+ // However, the detection might fail. Therefore, let's keep using this.
switch (mOriginalVirtualKeyCode) {
case VK_CONTROL:
if (mVirtualKeyCode != VK_LCONTROL &&
@@ -711,9 +724,13 @@ NativeKey::NativeKey(nsWindowBase* aWidget,
case WM_CHAR:
case WM_UNICHAR:
case WM_SYSCHAR:
+ // NOTE: If other applications like a11y tools sends WM_*CHAR without
+ // scancode, we cannot compute virtual keycode. I.e., with such
+ // applications, we cannot generate proper KeyboardEvent.code value.
+
// We cannot compute the virtual key code from WM_CHAR message on WinXP
// if it's caused by an extended key.
- if (!canComputeVirtualKeyCodeFromScanCode) {
+ if (!CanComputeVirtualKeyCodeFromScanCode()) {
break;
}
mVirtualKeyCode = mOriginalVirtualKeyCode =
@@ -732,11 +749,9 @@ NativeKey::NativeKey(nsWindowBase* aWidget,
keyboardLayout->ConvertNativeKeyCodeToDOMKeyCode(mOriginalVirtualKeyCode);
mKeyNameIndex =
keyboardLayout->ConvertNativeKeyCodeToKeyNameIndex(mOriginalVirtualKeyCode);
- // Even on WinXP or WinServer 2003, we should use extended flag for computing
- // the DOM code value since it's really our internal code.
mCodeNameIndex =
KeyboardLayout::ConvertScanCodeToCodeNameIndex(
- mIsExtended ? (0xE000 | mScanCode) : mScanCode, mOriginalVirtualKeyCode);
+ GetScanCodeWithExtendedFlag());
keyboardLayout->InitNativeKey(*this, mModKeyState);
@@ -875,6 +890,18 @@ NativeKey::GetKeyLocation() const
}
}
+bool
+NativeKey::CanComputeVirtualKeyCodeFromScanCode() const
+{
+ // Vista or later supports ScanCodeEx.
+ if (IsVistaOrLater()) {
+ return true;
+ }
+ // Otherwise, MapVirtualKeyEx() can compute virtual keycode only with
+ // non-extended key.
+ return !mIsExtended;
+}
+
uint8_t
NativeKey::ComputeVirtualKeyCodeFromScanCode() const
{
@@ -885,14 +912,24 @@ NativeKey::ComputeVirtualKeyCodeFromScanCode() const
uint8_t
NativeKey::ComputeVirtualKeyCodeFromScanCodeEx() const
{
- // NOTE: WinXP doesn't support mapping scan code to virtual keycode of
- // extended keys.
- NS_ENSURE_TRUE(!mIsExtended || IsVistaOrLater(), 0);
+ if (NS_WARN_IF(!CanComputeVirtualKeyCodeFromScanCode())) {
+ return 0;
+ }
return static_cast(
::MapVirtualKeyEx(GetScanCodeWithExtendedFlag(), MAPVK_VSC_TO_VK_EX,
mKeyboardLayout));
}
+uint16_t
+NativeKey::ComputeScanCodeExFromVirtualKeyCode(UINT aVirtualKeyCode) const
+{
+ return static_cast(
+ ::MapVirtualKeyEx(aVirtualKeyCode,
+ IsVistaOrLater() ? MAPVK_VK_TO_VSC_EX :
+ MAPVK_VK_TO_VSC,
+ mKeyboardLayout));
+}
+
char16_t
NativeKey::ComputeUnicharFromScanCode() const
{
@@ -2629,8 +2666,7 @@ KeyboardLayout::ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const
// static
CodeNameIndex
-KeyboardLayout::ConvertScanCodeToCodeNameIndex(UINT aScanCode,
- UINT aVirtualKeyCode)
+KeyboardLayout::ConvertScanCodeToCodeNameIndex(UINT aScanCode)
{
switch (aScanCode) {
@@ -2641,49 +2677,6 @@ KeyboardLayout::ConvertScanCodeToCodeNameIndex(UINT aScanCode,
#undef NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX
- // Some special keys cuases 0xE000 of scan code. Then, we should compute
- // the code value with virtual keycode.
- case 0xE000:
- switch (aVirtualKeyCode) {
- case VK_BROWSER_BACK:
- return CODE_NAME_INDEX_BrowserBack;
- case VK_BROWSER_FAVORITES:
- return CODE_NAME_INDEX_BrowserFavorites;
- case VK_BROWSER_FORWARD:
- return CODE_NAME_INDEX_BrowserForward;
- case VK_BROWSER_HOME:
- return CODE_NAME_INDEX_BrowserHome;
- case VK_BROWSER_REFRESH:
- return CODE_NAME_INDEX_BrowserRefresh;
- case VK_BROWSER_SEARCH:
- return CODE_NAME_INDEX_BrowserSearch;
- case VK_BROWSER_STOP:
- return CODE_NAME_INDEX_BrowserStop;
- case VK_LAUNCH_APP1: // my computer
- return CODE_NAME_INDEX_LaunchApp1;
- case VK_LAUNCH_APP2: // calculator
- return CODE_NAME_INDEX_LaunchApp2;
- case VK_LAUNCH_MAIL:
- return CODE_NAME_INDEX_LaunchMail;
- case VK_LAUNCH_MEDIA_SELECT:
- return CODE_NAME_INDEX_MediaSelect;
- case VK_MEDIA_PLAY_PAUSE:
- return CODE_NAME_INDEX_MediaPlayPause;
- case VK_MEDIA_STOP:
- return CODE_NAME_INDEX_MediaStop;
- case VK_MEDIA_NEXT_TRACK:
- return CODE_NAME_INDEX_MediaTrackNext;
- case VK_MEDIA_PREV_TRACK:
- return CODE_NAME_INDEX_MediaTrackPrevious;
- case VK_VOLUME_MUTE:
- return CODE_NAME_INDEX_VolumeMute;
- case VK_VOLUME_DOWN:
- return CODE_NAME_INDEX_VolumeDown;
- case VK_VOLUME_UP:
- return CODE_NAME_INDEX_VolumeUp;
- default:
- return CODE_NAME_INDEX_UNKNOWN;
- }
default:
return CODE_NAME_INDEX_UNKNOWN;
}
diff --git a/widget/windows/KeyboardLayout.h b/widget/windows/KeyboardLayout.h
index 45e413d60b3..e9a39197b5f 100644
--- a/widget/windows/KeyboardLayout.h
+++ b/widget/windows/KeyboardLayout.h
@@ -382,6 +382,11 @@ private:
*/
bool GetFollowingCharMessage(MSG& aCharMsg) const;
+ /**
+ * Whether the key event can compute virtual keycode from the scancode value.
+ */
+ bool CanComputeVirtualKeyCodeFromScanCode() const;
+
/**
* Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK.
*/
@@ -392,6 +397,11 @@ private:
*/
uint8_t ComputeVirtualKeyCodeFromScanCodeEx() const;
+ /**
+ * Wraps MapVirtualKeyEx() with MAPVK_VK_TO_VSC_EX or MAPVK_VK_TO_VSC.
+ */
+ uint16_t ComputeScanCodeExFromVirtualKeyCode(UINT aVirtualKeyCode) const;
+
/**
* Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK and MAPVK_VK_TO_CHAR.
*/
@@ -565,13 +575,8 @@ public:
* ConvertScanCodeToCodeNameIndex() returns CodeNameIndex value for
* the given scan code. aScanCode can be over 0xE000 since this method
* doesn't use Windows API.
- *
- * NOTE: Some special keys always generate 0xE000 for the scan code but
- * the virtual keycode indicates the key. In such case, this method
- * computes CodeNameIndex from aVirtualKeyCode.
*/
- static CodeNameIndex ConvertScanCodeToCodeNameIndex(UINT aScanCode,
- UINT aVirtualKeyCode);
+ static CodeNameIndex ConvertScanCodeToCodeNameIndex(UINT aScanCode);
HKL GetLayout() const
{