Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-07-23 16:12:02 +02:00
commit adc11595f6
68 changed files with 1734 additions and 463 deletions

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="78cbbaeb041e5dd25a32c521b3d4ff08735ac139"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="01d86c8cc615658694b114ca5711763efc4ef205"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="78cbbaeb041e5dd25a32c521b3d4ff08735ac139"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="01d86c8cc615658694b114ca5711763efc4ef205"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="31215645c296ba7a62bcb3176f69e0014ab9be07"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="999e945b85c578c503ad445c2285940f16aacdae">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="78cbbaeb041e5dd25a32c521b3d4ff08735ac139"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="01d86c8cc615658694b114ca5711763efc4ef205"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="78cbbaeb041e5dd25a32c521b3d4ff08735ac139"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="01d86c8cc615658694b114ca5711763efc4ef205"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="78cbbaeb041e5dd25a32c521b3d4ff08735ac139"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="01d86c8cc615658694b114ca5711763efc4ef205"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="31215645c296ba7a62bcb3176f69e0014ab9be07"/>

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "eff18c4265f0d8e49e5a2f2d7c9fdb01c87bd42e",
"revision": "097d333ddd568576aa933f9259b7f6ee1f62d41f",
"repo_path": "/integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="78cbbaeb041e5dd25a32c521b3d4ff08735ac139"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="01d86c8cc615658694b114ca5711763efc4ef205"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="78cbbaeb041e5dd25a32c521b3d4ff08735ac139"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="01d86c8cc615658694b114ca5711763efc4ef205"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="78cbbaeb041e5dd25a32c521b3d4ff08735ac139"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="01d86c8cc615658694b114ca5711763efc4ef205"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="31215645c296ba7a62bcb3176f69e0014ab9be07"/>

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="78cbbaeb041e5dd25a32c521b3d4ff08735ac139"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="01d86c8cc615658694b114ca5711763efc4ef205"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -812,7 +812,6 @@ pref("plugin.state.f5 sam inspection host plugin", 2);
// display door hanger if flash not installed
pref("plugins.notifyMissingFlash", true);
pref("browser.preferences.instantApply", true);
#ifdef XP_MACOSX
pref("browser.preferences.animateFadeIn", true);
#else
@ -820,7 +819,17 @@ pref("browser.preferences.animateFadeIn", false);
#endif
// Toggles between the two Preferences implementations, pop-up window and in-content
#ifdef NIGHTLY_BUILD
pref("browser.preferences.inContent", true);
pref("browser.preferences.instantApply", true);
#else
pref("browser.preferences.inContent", false);
#ifdef XP_WIN
pref("browser.preferences.instantApply", false);
#else
pref("browser.preferences.instantApply", true);
#endif
#endif
pref("browser.download.show_plugins_in_list", true);
pref("browser.download.hide_plugins_without_extensions", true);

View File

@ -975,6 +975,10 @@ GK_ATOM(rp, "rp")
GK_ATOM(rt, "rt")
GK_ATOM(rtl, "rtl")
GK_ATOM(ruby, "ruby")
GK_ATOM(rubyBase, "ruby-base")
GK_ATOM(rubyBaseContainer, "ruby-base-container")
GK_ATOM(rubyText, "ruby-text")
GK_ATOM(rubyTextContainer, "ruby-text-container")
GK_ATOM(rule, "rule")
GK_ATOM(rules, "rules")
GK_ATOM(s, "s")
@ -1876,6 +1880,11 @@ GK_ATOM(popupSetFrame, "PopupSetFrame")
GK_ATOM(canvasFrame, "CanvasFrame")
GK_ATOM(rangeFrame, "RangeFrame")
GK_ATOM(rootFrame, "RootFrame")
GK_ATOM(rubyBaseContainerFrame, "RubyBaseContainerFrame")
GK_ATOM(rubyBaseFrame, "RubyBaseFrame")
GK_ATOM(rubyFrame, "RubyFrame")
GK_ATOM(rubyTextContainerFrame, "RubyTextContainerFrame")
GK_ATOM(rubyTextFrame, "RubyTextFrame")
GK_ATOM(scrollFrame, "ScrollFrame")
GK_ATOM(scrollbarFrame, "ScrollbarFrame")
GK_ATOM(sequenceFrame, "SequenceFrame")

View File

@ -169,7 +169,7 @@ public:
}
NS_ENSURE_TRUE(sBtAvrcpInterface, NS_OK);
sBtAvrcpInterface->GetElementAttrRsp(mNumAttr, attrs);
sBtAvrcpInterface->GetElementAttrRsp(mNumAttr, attrs, nullptr);
return NS_OK;
}
@ -492,6 +492,75 @@ static btrc_callbacks_t sBtAvrcpCallbacks = {
};
#endif
#if ANDROID_VERSION > 17
class InitAvrcpResultHandler MOZ_FINAL : public BluetoothAvrcpResultHandler
{
public:
InitAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
void OnError(bt_status_t aStatus) MOZ_OVERRIDE
{
BT_WARNING("BluetoothAvrcpInterface::Init failed: %d",
(int)aStatus);
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
}
}
void Init() MOZ_OVERRIDE
{
if (mRes) {
mRes->Init();
}
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
#endif
class InitA2dpResultHandler MOZ_FINAL : public BluetoothA2dpResultHandler
{
public:
InitA2dpResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
void OnError(bt_status_t aStatus) MOZ_OVERRIDE
{
BT_WARNING("BluetoothA2dpInterface::Init failed: %d",
(int)aStatus);
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
}
}
void Init() MOZ_OVERRIDE
{
#if ANDROID_VERSION > 17
/* Also init AVRCP if it's available, ... */
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
NS_ENSURE_TRUE_VOID(btInf);
sBtAvrcpInterface = btInf->GetBluetoothAvrcpInterface();
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
sBtAvrcpInterface->Init(&sBtAvrcpCallbacks,
new InitAvrcpResultHandler(mRes));
#else
/* ...or signal success otherwise. */
if (mRes) {
mRes->Init();
}
#endif
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
/*
* This function will be only called when Bluetooth is turning on.
* It is important to register a2dp callbacks before enable() gets called.
@ -508,24 +577,7 @@ BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
sBtA2dpInterface = btInf->GetBluetoothA2dpInterface();
NS_ENSURE_TRUE_VOID(sBtA2dpInterface);
int ret = sBtA2dpInterface->Init(&sBtA2dpCallbacks);
if (ret != BT_STATUS_SUCCESS) {
BT_LOGR("Warning: failed to init a2dp module");
}
#if ANDROID_VERSION > 17
sBtAvrcpInterface = btInf->GetBluetoothAvrcpInterface();
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
ret = sBtAvrcpInterface->Init(&sBtAvrcpCallbacks);
if (ret != BT_STATUS_SUCCESS) {
BT_LOGR("Warning: failed to init avrcp module");
}
#endif
if (aRes) {
aRes->Init();
}
sBtA2dpInterface->Init(&sBtA2dpCallbacks, new InitA2dpResultHandler(aRes));
}
BluetoothA2dpManager::~BluetoothA2dpManager()
@ -599,6 +651,99 @@ BluetoothA2dpManager::Get()
return sBluetoothA2dpManager;
}
#if ANDROID_VERSION > 17
class CleanupAvrcpResultHandler MOZ_FINAL : public BluetoothAvrcpResultHandler
{
public:
CleanupAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
void OnError(bt_status_t aStatus) MOZ_OVERRIDE
{
BT_WARNING("BluetoothAvrcpInterface::Cleanup failed: %d",
(int)aStatus);
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
}
}
void Cleanup() MOZ_OVERRIDE
{
sBtAvrcpInterface = nullptr;
if (mRes) {
mRes->Deinit();
}
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
#endif
class CleanupA2dpResultHandler MOZ_FINAL : public BluetoothA2dpResultHandler
{
public:
CleanupA2dpResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
void OnError(bt_status_t aStatus) MOZ_OVERRIDE
{
BT_WARNING("BluetoothA2dpInterface::Cleanup failed: %d",
(int)aStatus);
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
}
}
void Cleanup() MOZ_OVERRIDE
{
sBtA2dpInterface = nullptr;
#if ANDROID_VERSION > 17
/* Cleanup AVRCP if it's available and initialized, ...*/
if (sBtAvrcpInterface) {
sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
} else
#endif
if (mRes) {
/* ...or simply signal success from here. */
mRes->Deinit();
}
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
class CleanupA2dpResultHandlerRunnable MOZ_FINAL : public nsRunnable
{
public:
CleanupA2dpResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
NS_IMETHOD Run() MOZ_OVERRIDE
{
sBtA2dpInterface = nullptr;
#if ANDROID_VERSION > 17
/* Cleanup AVRCP if it's available and initialized, ...*/
if (sBtAvrcpInterface) {
sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
} else
#endif
if (mRes) {
/* ...or simply signal success from here. */
mRes->Deinit();
}
return NS_OK;
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
// static
void
BluetoothA2dpManager::DeinitA2dpInterface(BluetoothProfileResultHandler* aRes)
@ -606,17 +751,14 @@ BluetoothA2dpManager::DeinitA2dpInterface(BluetoothProfileResultHandler* aRes)
MOZ_ASSERT(NS_IsMainThread());
if (sBtA2dpInterface) {
sBtA2dpInterface->Cleanup();
sBtA2dpInterface = nullptr;
}
#if ANDROID_VERSION > 17
if (sBtAvrcpInterface) {
sBtAvrcpInterface->Cleanup();
sBtAvrcpInterface = nullptr;
}
#endif
if (aRes) {
aRes->Deinit();
sBtA2dpInterface->Cleanup(new CleanupA2dpResultHandler(aRes));
} else if (aRes) {
// We dispatch a runnable here to make the profile resource handler
// behave as if A2DP was initialized.
nsRefPtr<nsRunnable> r = new CleanupA2dpResultHandlerRunnable(aRes);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
}
}
}
@ -629,6 +771,29 @@ BluetoothA2dpManager::HandleShutdown()
sBluetoothA2dpManager = nullptr;
}
void
BluetoothA2dpManager::OnConnectError()
{
MOZ_ASSERT(NS_IsMainThread());
mController->NotifyCompletion(NS_LITERAL_STRING(ERR_CONNECTION_FAILED));
mController = nullptr;
mDeviceAddress.Truncate();
}
class ConnectResultHandler MOZ_FINAL : public BluetoothA2dpResultHandler
{
public:
void OnError(bt_status_t aStatus) MOZ_OVERRIDE
{
BT_LOGR("BluetoothA2dpInterface::Connect failed: %d", (int)aStatus);
NS_ENSURE_TRUE_VOID(sBluetoothA2dpManager);
sBluetoothA2dpManager->OnConnectError();
}
};
void
BluetoothA2dpManager::Connect(const nsAString& aDeviceAddress,
BluetoothProfileController* aController)
@ -660,14 +825,29 @@ BluetoothA2dpManager::Connect(const nsAString& aDeviceAddress,
bt_bdaddr_t remoteAddress;
StringToBdAddressType(aDeviceAddress, &remoteAddress);
bt_status_t result = sBtA2dpInterface->Connect(&remoteAddress);
if (BT_STATUS_SUCCESS != result) {
BT_LOGR("Failed to connect: %x", result);
aController->NotifyCompletion(NS_LITERAL_STRING(ERR_CONNECTION_FAILED));
return;
}
sBtA2dpInterface->Connect(&remoteAddress, new ConnectResultHandler());
}
void
BluetoothA2dpManager::OnDisconnectError()
{
MOZ_ASSERT(NS_IsMainThread());
mController->NotifyCompletion(NS_LITERAL_STRING(ERR_DISCONNECTION_FAILED));
}
class DisconnectResultHandler MOZ_FINAL : public BluetoothA2dpResultHandler
{
public:
void OnError(bt_status_t aStatus) MOZ_OVERRIDE
{
BT_LOGR("BluetoothA2dpInterface::Disconnect failed: %d", (int)aStatus);
NS_ENSURE_TRUE_VOID(sBluetoothA2dpManager);
sBluetoothA2dpManager->OnDisconnectError();
}
};
void
BluetoothA2dpManager::Disconnect(BluetoothProfileController* aController)
{
@ -702,12 +882,7 @@ BluetoothA2dpManager::Disconnect(BluetoothProfileController* aController)
bt_bdaddr_t remoteAddress;
StringToBdAddressType(mDeviceAddress, &remoteAddress);
bt_status_t result = sBtA2dpInterface->Disconnect(&remoteAddress);
if (BT_STATUS_SUCCESS != result) {
BT_LOGR("Failed to disconnect: %x", result);
aController->NotifyCompletion(NS_LITERAL_STRING(ERR_DISCONNECTION_FAILED));
return;
}
sBtA2dpInterface->Disconnect(&remoteAddress, new DisconnectResultHandler());
}
void
@ -939,7 +1114,7 @@ BluetoothA2dpManager::UpdateMetaData(const nsAString& aTitle,
mTrackChangedNotifyType = BTRC_NOTIFICATION_TYPE_CHANGED;
sBtAvrcpInterface->RegisterNotificationRsp(BTRC_EVT_TRACK_CHANGE,
BTRC_NOTIFICATION_TYPE_CHANGED,
&param);
&param, nullptr);
if (mPlayPosChangedNotifyType == BTRC_NOTIFICATION_TYPE_INTERIM) {
param.song_pos = mPosition;
// EVENT_PLAYBACK_POS_CHANGED shall be notified if changed current track
@ -947,7 +1122,7 @@ BluetoothA2dpManager::UpdateMetaData(const nsAString& aTitle,
sBtAvrcpInterface->RegisterNotificationRsp(
BTRC_EVT_PLAY_POS_CHANGED,
BTRC_NOTIFICATION_TYPE_CHANGED,
&param);
&param, nullptr);
}
}
@ -975,7 +1150,7 @@ BluetoothA2dpManager::UpdatePlayStatus(uint32_t aDuration,
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
// always update playstatus first
sBtAvrcpInterface->GetPlayStatusRsp((btrc_play_status_t)aPlayStatus,
aDuration, aPosition);
aDuration, aPosition, nullptr);
// when play status changed, send both play status and position
if (mPlayStatus != aPlayStatus &&
mPlayStatusChangedNotifyType == BTRC_NOTIFICATION_TYPE_INTERIM) {
@ -984,7 +1159,7 @@ BluetoothA2dpManager::UpdatePlayStatus(uint32_t aDuration,
mPlayStatusChangedNotifyType = BTRC_NOTIFICATION_TYPE_CHANGED;
sBtAvrcpInterface->RegisterNotificationRsp(BTRC_EVT_PLAY_STATUS_CHANGED,
BTRC_NOTIFICATION_TYPE_CHANGED,
&param);
&param, nullptr);
}
if (mPosition != aPosition &&
@ -994,7 +1169,7 @@ BluetoothA2dpManager::UpdatePlayStatus(uint32_t aDuration,
mPlayPosChangedNotifyType = BTRC_NOTIFICATION_TYPE_CHANGED;
sBtAvrcpInterface->RegisterNotificationRsp(BTRC_EVT_PLAY_POS_CHANGED,
BTRC_NOTIFICATION_TYPE_CHANGED,
&param);
&param, nullptr);
}
mDuration = aDuration;
@ -1062,7 +1237,7 @@ BluetoothA2dpManager::UpdateRegisterNotification(int aEventId, int aParam)
sBtAvrcpInterface->RegisterNotificationRsp((btrc_event_id_t)aEventId,
BTRC_NOTIFICATION_TYPE_INTERIM,
&param);
&param, nullptr);
#endif
}

View File

@ -34,6 +34,9 @@ public:
static void DeinitA2dpInterface(BluetoothProfileResultHandler* aRes);
virtual ~BluetoothA2dpManager();
void OnConnectError();
void OnDisconnectError();
// A2DP-specific functions
void HandleSinkPropertyChanged(const BluetoothSignal& aSignal);

View File

@ -847,6 +847,37 @@ struct interface_traits<BluetoothA2dpInterface>
}
};
typedef
BluetoothInterfaceRunnable0<BluetoothA2dpResultHandler, void>
BluetoothA2dpResultRunnable;
typedef
BluetoothInterfaceRunnable1<BluetoothA2dpResultHandler, void, bt_status_t>
BluetoothA2dpErrorRunnable;
static nsresult
DispatchBluetoothA2dpResult(
BluetoothA2dpResultHandler* aRes,
void (BluetoothA2dpResultHandler::*aMethod)(),
bt_status_t aStatus)
{
MOZ_ASSERT(aRes);
nsRunnable* runnable;
if (aStatus == BT_STATUS_SUCCESS) {
runnable = new BluetoothA2dpResultRunnable(aRes, aMethod);
} else {
runnable = new BluetoothA2dpErrorRunnable(aRes,
&BluetoothA2dpResultHandler::OnError, aStatus);
}
nsresult rv = NS_DispatchToMainThread(runnable);
if (NS_FAILED(rv)) {
BT_WARNING("NS_DispatchToMainThread failed: %X", rv);
}
return rv;
}
BluetoothA2dpInterface::BluetoothA2dpInterface(
const btav_interface_t* aInterface)
: mInterface(aInterface)
@ -857,28 +888,51 @@ BluetoothA2dpInterface::BluetoothA2dpInterface(
BluetoothA2dpInterface::~BluetoothA2dpInterface()
{ }
bt_status_t
BluetoothA2dpInterface::Init(btav_callbacks_t* aCallbacks)
void
BluetoothA2dpInterface::Init(btav_callbacks_t* aCallbacks,
BluetoothA2dpResultHandler* aRes)
{
return mInterface->init(aCallbacks);
bt_status_t status = mInterface->init(aCallbacks);
if (aRes) {
DispatchBluetoothA2dpResult(aRes, &BluetoothA2dpResultHandler::Init,
status);
}
}
void
BluetoothA2dpInterface::Cleanup()
BluetoothA2dpInterface::Cleanup(BluetoothA2dpResultHandler* aRes)
{
mInterface->cleanup();
if (aRes) {
DispatchBluetoothA2dpResult(aRes, &BluetoothA2dpResultHandler::Cleanup,
BT_STATUS_SUCCESS);
}
}
bt_status_t
BluetoothA2dpInterface::Connect(bt_bdaddr_t *aBdAddr)
void
BluetoothA2dpInterface::Connect(bt_bdaddr_t *aBdAddr,
BluetoothA2dpResultHandler* aRes)
{
return mInterface->connect(aBdAddr);
bt_status_t status = mInterface->connect(aBdAddr);
if (aRes) {
DispatchBluetoothA2dpResult(aRes, &BluetoothA2dpResultHandler::Connect,
status);
}
}
bt_status_t
BluetoothA2dpInterface::Disconnect(bt_bdaddr_t *aBdAddr)
void
BluetoothA2dpInterface::Disconnect(bt_bdaddr_t *aBdAddr,
BluetoothA2dpResultHandler* aRes)
{
return mInterface->disconnect(aBdAddr);
bt_status_t status = mInterface->disconnect(aBdAddr);
if (aRes) {
DispatchBluetoothA2dpResult(aRes, &BluetoothA2dpResultHandler::Disconnect,
status);
}
}
//
@ -897,6 +951,37 @@ struct interface_traits<BluetoothAvrcpInterface>
}
};
typedef
BluetoothInterfaceRunnable0<BluetoothAvrcpResultHandler, void>
BluetoothAvrcpResultRunnable;
typedef
BluetoothInterfaceRunnable1<BluetoothAvrcpResultHandler, void, bt_status_t>
BluetoothAvrcpErrorRunnable;
static nsresult
DispatchBluetoothAvrcpResult(
BluetoothAvrcpResultHandler* aRes,
void (BluetoothAvrcpResultHandler::*aMethod)(),
bt_status_t aStatus)
{
MOZ_ASSERT(aRes);
nsRunnable* runnable;
if (aStatus == BT_STATUS_SUCCESS) {
runnable = new BluetoothAvrcpResultRunnable(aRes, aMethod);
} else {
runnable = new BluetoothAvrcpErrorRunnable(aRes,
&BluetoothAvrcpResultHandler::OnError, aStatus);
}
nsresult rv = NS_DispatchToMainThread(runnable);
if (NS_FAILED(rv)) {
BT_WARNING("NS_DispatchToMainThread failed: %X", rv);
}
return rv;
}
BluetoothAvrcpInterface::BluetoothAvrcpInterface(
const btrc_interface_t* aInterface)
: mInterface(aInterface)
@ -907,86 +992,157 @@ BluetoothAvrcpInterface::BluetoothAvrcpInterface(
BluetoothAvrcpInterface::~BluetoothAvrcpInterface()
{ }
bt_status_t
BluetoothAvrcpInterface::Init(btrc_callbacks_t* aCallbacks)
void
BluetoothAvrcpInterface::Init(btrc_callbacks_t* aCallbacks,
BluetoothAvrcpResultHandler* aRes)
{
return mInterface->init(aCallbacks);
bt_status_t status = mInterface->init(aCallbacks);
if (aRes) {
DispatchBluetoothAvrcpResult(aRes, &BluetoothAvrcpResultHandler::Init,
status);
}
}
void
BluetoothAvrcpInterface::Cleanup()
BluetoothAvrcpInterface::Cleanup(BluetoothAvrcpResultHandler* aRes)
{
mInterface->cleanup();
if (aRes) {
DispatchBluetoothAvrcpResult(aRes, &BluetoothAvrcpResultHandler::Cleanup,
BT_STATUS_SUCCESS);
}
}
bt_status_t
void
BluetoothAvrcpInterface::GetPlayStatusRsp(btrc_play_status_t aPlayStatus,
uint32_t aSongLen, uint32_t aSongPos)
uint32_t aSongLen, uint32_t aSongPos,
BluetoothAvrcpResultHandler* aRes)
{
return mInterface->get_play_status_rsp(aPlayStatus, aSongLen, aSongPos);
bt_status_t status = mInterface->get_play_status_rsp(aPlayStatus, aSongLen,
aSongPos);
if (aRes) {
DispatchBluetoothAvrcpResult(
aRes, &BluetoothAvrcpResultHandler::GetPlayStatusRsp, status);
}
}
bt_status_t
BluetoothAvrcpInterface::ListPlayerAppAttrRsp(int aNumAttr,
btrc_player_attr_t* aPAttrs)
void
BluetoothAvrcpInterface::ListPlayerAppAttrRsp(
int aNumAttr, btrc_player_attr_t* aPAttrs,
BluetoothAvrcpResultHandler* aRes)
{
return mInterface->list_player_app_attr_rsp(aNumAttr, aPAttrs);
bt_status_t status = mInterface->list_player_app_attr_rsp(aNumAttr, aPAttrs);
if (aRes) {
DispatchBluetoothAvrcpResult(
aRes, &BluetoothAvrcpResultHandler::ListPlayerAppAttrRsp, status);
}
}
bt_status_t
BluetoothAvrcpInterface::ListPlayerAppValueRsp(int aNumVal, uint8_t* aPVals)
void
BluetoothAvrcpInterface::ListPlayerAppValueRsp(
int aNumVal, uint8_t* aPVals, BluetoothAvrcpResultHandler* aRes)
{
return mInterface->list_player_app_value_rsp(aNumVal, aPVals);
bt_status_t status = mInterface->list_player_app_value_rsp(aNumVal, aPVals);
if (aRes) {
DispatchBluetoothAvrcpResult(
aRes, &BluetoothAvrcpResultHandler::ListPlayerAppValueRsp, status);
}
}
bt_status_t
BluetoothAvrcpInterface::GetPlayerAppValueRsp(btrc_player_settings_t* aPVals)
void
BluetoothAvrcpInterface::GetPlayerAppValueRsp(
btrc_player_settings_t* aPVals, BluetoothAvrcpResultHandler* aRes)
{
return mInterface->get_player_app_value_rsp(aPVals);
bt_status_t status = mInterface->get_player_app_value_rsp(aPVals);
if (aRes) {
DispatchBluetoothAvrcpResult(
aRes, &BluetoothAvrcpResultHandler::GetPlayerAppValueRsp, status);
}
}
bt_status_t
BluetoothAvrcpInterface::GetPlayerAppAttrTextRsp(int aNumAttr,
btrc_player_setting_text_t* aPAttrs)
void
BluetoothAvrcpInterface::GetPlayerAppAttrTextRsp(
int aNumAttr, btrc_player_setting_text_t* aPAttrs,
BluetoothAvrcpResultHandler* aRes)
{
return mInterface->get_player_app_attr_text_rsp(aNumAttr, aPAttrs);
bt_status_t status = mInterface->get_player_app_attr_text_rsp(aNumAttr,
aPAttrs);
if (aRes) {
DispatchBluetoothAvrcpResult(
aRes, &BluetoothAvrcpResultHandler::GetPlayerAppAttrTextRsp, status);
}
}
bt_status_t
BluetoothAvrcpInterface::GetPlayerAppValueTextRsp(int aNumVal,
btrc_player_setting_text_t* aPVals)
void
BluetoothAvrcpInterface::GetPlayerAppValueTextRsp(
int aNumVal, btrc_player_setting_text_t* aPVals,
BluetoothAvrcpResultHandler* aRes)
{
return mInterface->get_player_app_value_text_rsp(aNumVal, aPVals);
bt_status_t status = mInterface->get_player_app_value_text_rsp(aNumVal,
aPVals);
if (aRes) {
DispatchBluetoothAvrcpResult(
aRes, &BluetoothAvrcpResultHandler::GetPlayerAppValueTextRsp, status);
}
}
bt_status_t
BluetoothAvrcpInterface::GetElementAttrRsp(uint8_t aNumAttr,
btrc_element_attr_val_t* aPAttrs)
void
BluetoothAvrcpInterface::GetElementAttrRsp(
uint8_t aNumAttr, btrc_element_attr_val_t* aPAttrs,
BluetoothAvrcpResultHandler* aRes)
{
return mInterface->get_element_attr_rsp(aNumAttr, aPAttrs);
bt_status_t status = mInterface->get_element_attr_rsp(aNumAttr, aPAttrs);
if (aRes) {
DispatchBluetoothAvrcpResult(
aRes, &BluetoothAvrcpResultHandler::GetElementAttrRsp, status);
}
}
bt_status_t
BluetoothAvrcpInterface::SetPlayerAppValueRsp(btrc_status_t aRspStatus)
void
BluetoothAvrcpInterface::SetPlayerAppValueRsp(
btrc_status_t aRspStatus, BluetoothAvrcpResultHandler* aRes)
{
return mInterface->set_player_app_value_rsp(aRspStatus);
bt_status_t status = mInterface->set_player_app_value_rsp(aRspStatus);
if (aRes) {
DispatchBluetoothAvrcpResult(
aRes, &BluetoothAvrcpResultHandler::SetPlayerAppValueRsp, status);
}
}
bt_status_t
BluetoothAvrcpInterface::RegisterNotificationRsp(btrc_event_id_t aEventId,
btrc_notification_type_t aType, btrc_register_notification_t* aPParam)
void
BluetoothAvrcpInterface::RegisterNotificationRsp(
btrc_event_id_t aEventId, btrc_notification_type_t aType,
btrc_register_notification_t* aPParam, BluetoothAvrcpResultHandler* aRes)
{
return mInterface->register_notification_rsp(aEventId, aType, aPParam);
bt_status_t status = mInterface->register_notification_rsp(aEventId, aType,
aPParam);
if (aRes) {
DispatchBluetoothAvrcpResult(
aRes, &BluetoothAvrcpResultHandler::RegisterNotificationRsp, status);
}
}
bt_status_t
BluetoothAvrcpInterface::SetVolume(uint8_t aVolume)
void
BluetoothAvrcpInterface::SetVolume(uint8_t aVolume,
BluetoothAvrcpResultHandler* aRes)
{
#if ANDROID_VERSION >= 19
return mInterface->set_volume(aVolume);
bt_status_t status = mInterface->set_volume(aVolume);
#else
return BT_STATUS_UNSUPPORTED;
bt_status_t status = BT_STATUS_UNSUPPORTED;
#endif
if (aRes) {
DispatchBluetoothAvrcpResult(
aRes, &BluetoothAvrcpResultHandler::SetVolume, status);
}
}
#endif

View File

@ -181,16 +181,37 @@ private:
// Bluetooth Advanced Audio Interface
//
class BluetoothA2dpResultHandler
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BluetoothA2dpResultHandler)
virtual ~BluetoothA2dpResultHandler() { }
virtual void OnError(bt_status_t aStatus)
{
BT_WARNING("received error code %d", (int)aStatus);
}
virtual void Init() { }
virtual void Cleanup() { }
virtual void Connect() { }
virtual void Disconnect() { }
};
class BluetoothA2dpInterface
{
public:
friend class BluetoothInterface;
bt_status_t Init(btav_callbacks_t *aCallbacks);
void Cleanup();
void Init(btav_callbacks_t *aCallbacks,
BluetoothA2dpResultHandler* aRes);
void Cleanup(BluetoothA2dpResultHandler* aRes);
bt_status_t Connect(bt_bdaddr_t *aBdAddr);
bt_status_t Disconnect(bt_bdaddr_t *aBdAddr);
void Connect(bt_bdaddr_t *aBdAddr,
BluetoothA2dpResultHandler* aRes);
void Disconnect(bt_bdaddr_t *aBdAddr,
BluetoothA2dpResultHandler* aRes);
protected:
BluetoothA2dpInterface(const btav_interface_t* aInterface);
@ -204,37 +225,79 @@ private:
// Bluetooth AVRCP Interface
//
class BluetoothAvrcpResultHandler
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BluetoothAvrcpResultHandler)
virtual ~BluetoothAvrcpResultHandler() { }
virtual void OnError(bt_status_t aStatus)
{
BT_WARNING("received error code %d", (int)aStatus);
}
virtual void Init() { }
virtual void Cleanup() { }
virtual void GetPlayStatusRsp() { }
virtual void ListPlayerAppAttrRsp() { }
virtual void ListPlayerAppValueRsp() { }
virtual void GetPlayerAppValueRsp() { }
virtual void GetPlayerAppAttrTextRsp() { }
virtual void GetPlayerAppValueTextRsp() { }
virtual void GetElementAttrRsp() { }
virtual void SetPlayerAppValueRsp() { }
virtual void RegisterNotificationRsp() { }
virtual void SetVolume() { }
};
class BluetoothAvrcpInterface
{
#if ANDROID_VERSION >= 18
public:
friend class BluetoothInterface;
bt_status_t Init(btrc_callbacks_t* aCallbacks);
void Cleanup();
void Init(btrc_callbacks_t* aCallbacks,
BluetoothAvrcpResultHandler* aRes);
void Cleanup(BluetoothAvrcpResultHandler* aRes);
bt_status_t GetPlayStatusRsp(btrc_play_status_t aPlayStatus,
uint32_t aSongLen, uint32_t aSongPos);
void GetPlayStatusRsp(btrc_play_status_t aPlayStatus,
uint32_t aSongLen, uint32_t aSongPos,
BluetoothAvrcpResultHandler* aRes);
bt_status_t ListPlayerAppAttrRsp(int aNumAttr, btrc_player_attr_t* aPAttrs);
bt_status_t ListPlayerAppValueRsp(int aNumVal, uint8_t* aPVals);
void ListPlayerAppAttrRsp(int aNumAttr, btrc_player_attr_t* aPAttrs,
BluetoothAvrcpResultHandler* aRes);
void ListPlayerAppValueRsp(int aNumVal, uint8_t* aPVals,
BluetoothAvrcpResultHandler* aRes);
bt_status_t GetPlayerAppValueRsp(btrc_player_settings_t* aPVals);
bt_status_t GetPlayerAppAttrTextRsp(int aNumAttr,
btrc_player_setting_text_t* aPAttrs);
bt_status_t GetPlayerAppValueTextRsp(int aNumVal,
btrc_player_setting_text_t* aPVals);
void GetPlayerAppValueRsp(btrc_player_settings_t* aPVals,
BluetoothAvrcpResultHandler* aRes);
void GetPlayerAppAttrTextRsp(int aNumAttr,
btrc_player_setting_text_t* aPAttrs,
BluetoothAvrcpResultHandler* aRes);
void GetPlayerAppValueTextRsp(int aNumVal,
btrc_player_setting_text_t* aPVals,
BluetoothAvrcpResultHandler* aRes);
bt_status_t GetElementAttrRsp(uint8_t aNumAttr,
btrc_element_attr_val_t* aPAttrs);
void GetElementAttrRsp(uint8_t aNumAttr, btrc_element_attr_val_t* aPAttrs,
BluetoothAvrcpResultHandler* aRes);
bt_status_t SetPlayerAppValueRsp(btrc_status_t aRspStatus);
void SetPlayerAppValueRsp(btrc_status_t aRspStatus,
BluetoothAvrcpResultHandler* aRes);
bt_status_t RegisterNotificationRsp(btrc_event_id_t aEventId,
btrc_notification_type_t aType,
btrc_register_notification_t* aPParam);
void RegisterNotificationRsp(btrc_event_id_t aEventId,
btrc_notification_type_t aType,
btrc_register_notification_t* aPParam,
BluetoothAvrcpResultHandler* aRes);
bt_status_t SetVolume(uint8_t aVolume);
void SetVolume(uint8_t aVolume, BluetoothAvrcpResultHandler* aRes);
protected:
BluetoothAvrcpInterface(const btrc_interface_t* aInterface);

View File

@ -62,6 +62,11 @@
#include "nsBoxLayout.h"
#include "nsFlexContainerFrame.h"
#include "nsGridContainerFrame.h"
#include "nsRubyFrame.h"
#include "nsRubyBaseFrame.h"
#include "nsRubyBaseContainerFrame.h"
#include "nsRubyTextFrame.h"
#include "nsRubyTextContainerFrame.h"
#include "nsImageFrame.h"
#include "nsIObjectLoadingContent.h"
#include "nsTArray.h"
@ -1877,6 +1882,15 @@ nsCSSFrameConstructor::GetParentType(nsIAtom* aFrameType)
if (aFrameType == nsGkAtoms::tableColGroupFrame) {
return eTypeColGroup;
}
if (aFrameType == nsGkAtoms::rubyBaseContainerFrame) {
return eTypeRubyBaseContainer;
}
if (aFrameType == nsGkAtoms::rubyTextContainerFrame) {
return eTypeRubyTextContainer;
}
if (aFrameType == nsGkAtoms::rubyFrame) {
return eTypeRuby;
}
return eTypeBlock;
}
@ -2251,7 +2265,7 @@ NeedFrameFor(const nsFrameConstructorState& aState,
// should be considered ignorable just because they evaluate to
// whitespace.
// We could handle all this in CreateNeededTablePseudos or some other place
// We could handle all this in CreateNeededPseudos or some other place
// after we build our frame construction items, but that would involve
// creating frame construction items for whitespace kids of
// eExcludesIgnorableWhitespace frames, where we know we'll be dropping them
@ -4529,6 +4543,21 @@ nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay,
FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame) },
{ NS_STYLE_DISPLAY_INLINE_GRID,
FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame) },
{ NS_STYLE_DISPLAY_RUBY,
FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT,
NS_NewRubyFrame) },
{ NS_STYLE_DISPLAY_RUBY_BASE,
FCDATA_DECL(FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer),
NS_NewRubyBaseFrame) },
{ NS_STYLE_DISPLAY_RUBY_BASE_CONTAINER,
FCDATA_DECL(FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
NS_NewRubyBaseContainerFrame) },
{ NS_STYLE_DISPLAY_RUBY_TEXT,
FCDATA_DECL(FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer),
NS_NewRubyTextFrame) },
{ NS_STYLE_DISPLAY_RUBY_TEXT_CONTAINER,
FCDATA_DECL(FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
NS_NewRubyTextContainerFrame) },
{ NS_STYLE_DISPLAY_TABLE,
FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable) },
{ NS_STYLE_DISPLAY_INLINE_TABLE,
@ -8315,6 +8344,12 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext,
} else if (nsGkAtoms::flexContainerFrame == frameType) {
newFrame = NS_NewFlexContainerFrame(shell, styleContext);
newFrame->Init(content, aParentFrame, aFrame);
//TODO: Add conditionals for rubyFrame and rubyBaseContainerFrame
// once their reflow methods are advanced enough to return
// non-complete statuses
} else if (nsGkAtoms::rubyTextContainerFrame == frameType) {
newFrame = NS_NewRubyTextContainerFrame(shell, styleContext);
newFrame->Init(content, aParentFrame, aFrame);
} else {
NS_RUNTIMEABORT("unexpected frame type");
}
@ -8983,6 +9018,41 @@ nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
FULL_CTOR_FCDATA(FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS,
&nsCSSFrameConstructor::ConstructTable),
&nsCSSAnonBoxes::table
},
{ // Ruby
FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
FCDATA_USE_CHILD_ITEMS |
FCDATA_SKIP_FRAMESET,
NS_NewRubyFrame),
&nsCSSAnonBoxes::ruby
},
{ // Ruby Base
FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer) |
FCDATA_SKIP_FRAMESET,
NS_NewRubyBaseFrame),
&nsCSSAnonBoxes::rubyBase
},
{ // Ruby Base Container
FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby) |
FCDATA_SKIP_FRAMESET,
NS_NewRubyBaseContainerFrame),
&nsCSSAnonBoxes::rubyBaseContainer
},
{ // Ruby Text
FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer) |
FCDATA_SKIP_FRAMESET,
NS_NewRubyTextFrame),
&nsCSSAnonBoxes::rubyText
},
{ // Ruby Text Container
FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby) |
FCDATA_SKIP_FRAMESET,
NS_NewRubyTextContainerFrame),
&nsCSSAnonBoxes::rubyTextContainer
}
};
@ -9115,9 +9185,9 @@ nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
* contain only items for frames that can be direct kids of aParentFrame.
*/
void
nsCSSFrameConstructor::CreateNeededTablePseudos(nsFrameConstructorState& aState,
FrameConstructionItemList& aItems,
nsIFrame* aParentFrame)
nsCSSFrameConstructor::CreateNeededPseudos(nsFrameConstructorState& aState,
FrameConstructionItemList& aItems,
nsIFrame* aParentFrame)
{
ParentType ourParentType = GetParentType(aParentFrame);
if (aItems.AllWantParentType(ourParentType)) {
@ -9178,6 +9248,7 @@ nsCSSFrameConstructor::CreateNeededTablePseudos(nsFrameConstructorState& aState,
if ((trailingSpaces && ourParentType != eTypeBlock) ||
(!trailingSpaces && spaceEndIter.item().DesiredParentType() !=
eTypeBlock)) {
//TODO: Add whitespace handling for ruby
bool updateStart = (iter == endIter);
endIter.DeleteItemsTo(spaceEndIter);
NS_ASSERTION(trailingSpaces == endIter.IsDone(), "These should match");
@ -9217,6 +9288,13 @@ nsCSSFrameConstructor::CreateNeededTablePseudos(nsFrameConstructorState& aState,
break;
}
// Don't group ruby base boxes and ruby annotation boxes together
if (ourParentType == eTypeRuby &&
(prevParentType == eTypeRubyTextContainer) !=
(groupingParentType == eTypeRubyTextContainer)) {
break;
}
// Include the whitespace we didn't drop (if any) in the group, since
// this is not the end of the group. Note that this doesn't change
// prevParentType, since if we didn't drop the whitespace then we ended
@ -9236,9 +9314,6 @@ nsCSSFrameConstructor::CreateNeededTablePseudos(nsFrameConstructorState& aState,
// parent type to use depends on ourParentType.
ParentType wrapperType;
switch (ourParentType) {
case eTypeBlock:
wrapperType = eTypeTable;
break;
case eTypeRow:
// The parent type for a cell is eTypeBlock, since that's what a cell
// looks like to its kids.
@ -9252,8 +9327,30 @@ nsCSSFrameConstructor::CreateNeededTablePseudos(nsFrameConstructorState& aState,
wrapperType = groupingParentType == eTypeColGroup ?
eTypeColGroup : eTypeRowGroup;
break;
default:
case eTypeColGroup:
MOZ_CRASH("Colgroups should be suppresing non-col child items");
case eTypeRuby:
if (groupingParentType == eTypeRubyTextContainer) {
wrapperType = eTypeRubyTextContainer;
} else {
wrapperType = eTypeRubyBaseContainer;
}
break;
case eTypeRubyBaseContainer:
wrapperType = eTypeRubyBase;
break;
case eTypeRubyTextContainer:
wrapperType = eTypeRubyText;
break;
default:
NS_ASSERTION(ourParentType == eTypeBlock, "Unrecognized parent type");
if (IsRubyParentType(groupingParentType)) {
wrapperType = eTypeRuby;
} else {
NS_ASSERTION(IsTableParentType(groupingParentType),
"groupingParentType should be either Ruby or table");
wrapperType = eTypeTable;
}
}
const PseudoParentData& pseudoData = sPseudoParentData[wrapperType];
@ -9262,7 +9359,10 @@ nsCSSFrameConstructor::CreateNeededTablePseudos(nsFrameConstructorState& aState,
nsIContent* parentContent = aParentFrame->GetContent();
if (pseudoType == nsCSSAnonBoxes::table &&
parentStyle->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_INLINE) {
(parentStyle->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_INLINE ||
IsRubyParentType(ourParentType) ||
parentStyle->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_RUBY_BASE ||
parentStyle->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_RUBY_TEXT)) {
pseudoType = nsCSSAnonBoxes::inlineTable;
}
@ -9318,7 +9418,7 @@ nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aSta
nsContainerFrame* aParentFrame,
nsFrameItems& aFrameItems)
{
CreateNeededTablePseudos(aState, aItems, aParentFrame);
CreateNeededPseudos(aState, aItems, aParentFrame);
CreateNeededAnonFlexOrGridItems(aState, aItems, aParentFrame);
aItems.SetTriedConstructingFrames();

View File

@ -415,18 +415,24 @@ private:
nsFrameItems& aFrameItems);
private:
/* An enum of possible parent types for anonymous table object construction */
/* An enum of possible parent types for anonymous table or ruby object
construction */
enum ParentType {
eTypeBlock = 0, /* This includes all non-table-related frames */
eTypeRow,
eTypeRowGroup,
eTypeColGroup,
eTypeTable,
eTypeRuby,
eTypeRubyBase,
eTypeRubyBaseContainer,
eTypeRubyText,
eTypeRubyTextContainer,
eParentTypeCount
};
/* 3 bits is enough to handle our ParentType values */
#define FCDATA_PARENT_TYPE_OFFSET 29
/* 4 bits is enough to handle our ParentType values */
#define FCDATA_PARENT_TYPE_OFFSET 28
/* Macro to get the desired parent type out of an mBits member of
FrameConstructionData */
#define FCDATA_DESIRED_PARENT_TYPE(_bits) \
@ -443,6 +449,21 @@ private:
/* Get the parent type for the given nsIFrame type atom */
static ParentType GetParentType(nsIAtom* aFrameType);
static bool IsRubyParentType(ParentType aParentType) {
return (aParentType == eTypeRuby ||
aParentType == eTypeRubyBase ||
aParentType == eTypeRubyBaseContainer ||
aParentType == eTypeRubyText ||
aParentType == eTypeRubyTextContainer);
}
static bool IsTableParentType(ParentType aParentType) {
return (aParentType == eTypeTable ||
aParentType == eTypeRow ||
aParentType == eTypeRowGroup ||
aParentType == eTypeColGroup);
}
/* A constructor function that just creates an nsIFrame object. The caller
is responsible for initializing the object, adding it to frame lists,
constructing frames for the children, etc.
@ -1041,9 +1062,9 @@ private:
* @param aItems the child frame construction items before pseudo creation
* @param aParentFrame the parent frame we're creating pseudos for
*/
inline void CreateNeededTablePseudos(nsFrameConstructorState& aState,
FrameConstructionItemList& aItems,
nsIFrame* aParentFrame);
inline void CreateNeededPseudos(nsFrameConstructorState& aState,
FrameConstructionItemList& aItems,
nsIFrame* aParentFrame);
/**
* Function to adjust aParentFrame to deal with captions.

View File

@ -109,6 +109,7 @@ using mozilla::image::ImageOps;
using mozilla::image::Orientation;
#define GRID_ENABLED_PREF_NAME "layout.css.grid.enabled"
#define RUBY_ENABLED_PREF_NAME "layout.css.ruby.enabled"
#define STICKY_ENABLED_PREF_NAME "layout.css.sticky.enabled"
#define TEXT_ALIGN_TRUE_ENABLED_PREF_NAME "layout.css.text-align-true-value.enabled"
@ -186,6 +187,78 @@ GridEnabledPrefChangeCallback(const char* aPrefName, void* aClosure)
}
}
static void
RubyEnabledPrefChangeCallback(const char* aPrefName, void* aClosure)
{
MOZ_ASSERT(strncmp(aPrefName, RUBY_ENABLED_PREF_NAME,
ArrayLength(RUBY_ENABLED_PREF_NAME)) == 0,
"We only registered this callback for a single pref, so it "
"should only be called for that pref");
static int32_t sIndexOfRubyInDisplayTable;
static int32_t sIndexOfRubyBaseInDisplayTable;
static int32_t sIndexOfRubyBaseContainerInDisplayTable;
static int32_t sIndexOfRubyTextInDisplayTable;
static int32_t sIndexOfRubyTextContainerInDisplayTable;
static bool sAreRubyKeywordIndicesInitialized; // initialized to false
bool isRubyEnabled =
Preferences::GetBool(RUBY_ENABLED_PREF_NAME, false);
if (!sAreRubyKeywordIndicesInitialized) {
// First run: find the position of the ruby display values in
// kDisplayKTable.
sIndexOfRubyInDisplayTable =
nsCSSProps::FindIndexOfKeyword(eCSSKeyword_ruby,
nsCSSProps::kDisplayKTable);
MOZ_ASSERT(sIndexOfRubyInDisplayTable >= 0,
"Couldn't find ruby in kDisplayKTable");
sIndexOfRubyBaseInDisplayTable =
nsCSSProps::FindIndexOfKeyword(eCSSKeyword_ruby_base,
nsCSSProps::kDisplayKTable);
MOZ_ASSERT(sIndexOfRubyBaseInDisplayTable >= 0,
"Couldn't find ruby-base in kDisplayKTable");
sIndexOfRubyBaseContainerInDisplayTable =
nsCSSProps::FindIndexOfKeyword(eCSSKeyword_ruby_base_container,
nsCSSProps::kDisplayKTable);
MOZ_ASSERT(sIndexOfRubyBaseContainerInDisplayTable >= 0,
"Couldn't find ruby-base-container in kDisplayKTable");
sIndexOfRubyTextInDisplayTable =
nsCSSProps::FindIndexOfKeyword(eCSSKeyword_ruby_text,
nsCSSProps::kDisplayKTable);
MOZ_ASSERT(sIndexOfRubyTextInDisplayTable >= 0,
"Couldn't find ruby-text in kDisplayKTable");
sIndexOfRubyTextContainerInDisplayTable =
nsCSSProps::FindIndexOfKeyword(eCSSKeyword_ruby_text_container,
nsCSSProps::kDisplayKTable);
MOZ_ASSERT(sIndexOfRubyTextContainerInDisplayTable >= 0,
"Couldn't find ruby-text-container in kDisplayKTable");
sAreRubyKeywordIndicesInitialized = true;
}
// OK -- now, stomp on or restore the "ruby" entries in kDisplayKTable,
// depending on whether the ruby pref is enabled vs. disabled.
if (sIndexOfRubyInDisplayTable >= 0) {
nsCSSProps::kDisplayKTable[sIndexOfRubyInDisplayTable] =
isRubyEnabled ? eCSSKeyword_ruby : eCSSKeyword_UNKNOWN;
}
if (sIndexOfRubyBaseInDisplayTable >= 0) {
nsCSSProps::kDisplayKTable[sIndexOfRubyBaseInDisplayTable] =
isRubyEnabled ? eCSSKeyword_ruby_base : eCSSKeyword_UNKNOWN;
}
if (sIndexOfRubyBaseContainerInDisplayTable >= 0) {
nsCSSProps::kDisplayKTable[sIndexOfRubyBaseContainerInDisplayTable] =
isRubyEnabled ? eCSSKeyword_ruby_base_container : eCSSKeyword_UNKNOWN;
}
if (sIndexOfRubyTextInDisplayTable >= 0) {
nsCSSProps::kDisplayKTable[sIndexOfRubyTextInDisplayTable] =
isRubyEnabled ? eCSSKeyword_ruby_text : eCSSKeyword_UNKNOWN;
}
if (sIndexOfRubyTextContainerInDisplayTable >= 0) {
nsCSSProps::kDisplayKTable[sIndexOfRubyTextContainerInDisplayTable] =
isRubyEnabled ? eCSSKeyword_ruby_text_container : eCSSKeyword_UNKNOWN;
}
}
// When the pref "layout.css.sticky.enabled" changes, this function is invoked
// to let us update kPositionKTable, to selectively disable or restore the
// entry for "sticky" in that table.
@ -6069,6 +6142,9 @@ nsLayoutUtils::Initialize()
Preferences::RegisterCallback(GridEnabledPrefChangeCallback,
GRID_ENABLED_PREF_NAME);
GridEnabledPrefChangeCallback(GRID_ENABLED_PREF_NAME, nullptr);
Preferences::RegisterCallback(RubyEnabledPrefChangeCallback,
RUBY_ENABLED_PREF_NAME);
RubyEnabledPrefChangeCallback(RUBY_ENABLED_PREF_NAME, nullptr);
Preferences::RegisterCallback(StickyEnabledPrefChangeCallback,
STICKY_ENABLED_PREF_NAME);
StickyEnabledPrefChangeCallback(STICKY_ENABLED_PREF_NAME, nullptr);
@ -6091,6 +6167,8 @@ nsLayoutUtils::Shutdown()
Preferences::UnregisterCallback(GridEnabledPrefChangeCallback,
GRID_ENABLED_PREF_NAME);
Preferences::UnregisterCallback(RubyEnabledPrefChangeCallback,
RUBY_ENABLED_PREF_NAME);
Preferences::UnregisterCallback(StickyEnabledPrefChangeCallback,
STICKY_ENABLED_PREF_NAME);

View File

@ -81,6 +81,11 @@ UNIFIED_SOURCES += [
'nsPageContentFrame.cpp',
'nsPageFrame.cpp',
'nsPlaceholderFrame.cpp',
'nsRubyBaseContainerFrame.cpp',
'nsRubyBaseFrame.cpp',
'nsRubyFrame.cpp',
'nsRubyTextContainerFrame.cpp',
'nsRubyTextFrame.cpp',
'nsSelection.cpp',
'nsSimplePageSequenceFrame.cpp',
'nsSplittableFrame.cpp',

View File

@ -466,7 +466,12 @@ IsFontSizeInflationContainer(nsIFrame* aFrame,
}
nsIContent *content = aFrame->GetContent();
// Ruby text containers are excluded here because they inherit from block
// (should not be considered inline).
bool isInline = (aFrame->GetDisplay() == NS_STYLE_DISPLAY_INLINE ||
(aFrame->StyleDisplay()->IsRubyDisplayType() &&
aFrame->GetDisplay() !=
NS_STYLE_DISPLAY_RUBY_TEXT_CONTAINER) ||
(aFrame->IsFloating() &&
aFrame->GetType() == nsGkAtoms::letterFrame) ||
// Given multiple frames for the same node, only the

View File

@ -115,6 +115,11 @@ FRAME_ID(nsProgressMeterFrame)
FRAME_ID(nsRangeFrame)
FRAME_ID(nsResizerFrame)
FRAME_ID(nsRootBoxFrame)
FRAME_ID(nsRubyBaseContainerFrame)
FRAME_ID(nsRubyBaseFrame)
FRAME_ID(nsRubyFrame)
FRAME_ID(nsRubyTextContainerFrame)
FRAME_ID(nsRubyTextFrame)
FRAME_ID(nsScrollbarButtonFrame)
FRAME_ID(nsScrollbarFrame)
FRAME_ID(nsSelectsAreaFrame)

View File

@ -0,0 +1,49 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code is subject to the terms of the Mozilla Public License
* version 2.0 (the "License"). You can obtain a copy of the License at
* http://mozilla.org/MPL/2.0/. */
/* rendering object for CSS "display: ruby-base-container" */
#include "nsRubyBaseContainerFrame.h"
#include "nsPresContext.h"
#include "nsStyleContext.h"
//----------------------------------------------------------------------
// Frame class boilerplate
// =======================
NS_QUERYFRAME_HEAD(nsRubyBaseContainerFrame)
NS_QUERYFRAME_ENTRY(nsRubyBaseContainerFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
NS_IMPL_FRAMEARENA_HELPERS(nsRubyBaseContainerFrame)
nsContainerFrame*
NS_NewRubyBaseContainerFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext)
{
return new (aPresShell) nsRubyBaseContainerFrame(aContext);
}
//----------------------------------------------------------------------
// nsRubyBaseContainerFrame Method Implementations
// ===============================================
nsIAtom*
nsRubyBaseContainerFrame::GetType() const
{
return nsGkAtoms::rubyBaseContainerFrame;
}
#ifdef DEBUG_FRAME_DUMP
nsresult
nsRubyBaseContainerFrame::GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("RubyBaseContainer"), aResult);
}
#endif

View File

@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code is subject to the terms of the Mozilla Public License
* version 2.0 (the "License"). You can obtain a copy of the License at
* http://mozilla.org/MPL/2.0/. */
/* rendering object for CSS "display: ruby-base-container" */
#ifndef nsRubyBaseContainerFrame_h___
#define nsRubyBaseContainerFrame_h___
#include "nsContainerFrame.h"
/**
* Factory function.
* @return a newly allocated nsRubyBaseContainerFrame (infallible)
*/
nsContainerFrame* NS_NewRubyBaseContainerFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext);
class nsRubyBaseContainerFrame MOZ_FINAL : public nsContainerFrame
{
public:
NS_DECL_FRAMEARENA_HELPERS
NS_DECL_QUERYFRAME_TARGET(nsRubyBaseContainerFrame)
NS_DECL_QUERYFRAME
// nsIFrame overrides
virtual nsIAtom* GetType() const MOZ_OVERRIDE;
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
#endif
protected:
friend nsContainerFrame*
NS_NewRubyBaseContainerFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext);
nsRubyBaseContainerFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
};
#endif /* nsRubyBaseContainerFrame_h___ */

View File

@ -0,0 +1,49 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code is subject to the terms of the Mozilla Public License
* version 2.0 (the "License"). You can obtain a copy of the License at
* http://mozilla.org/MPL/2.0/. */
/* rendering object for CSS "display: ruby-base" */
#include "nsRubyBaseFrame.h"
#include "nsPresContext.h"
#include "nsStyleContext.h"
//----------------------------------------------------------------------
// Frame class boilerplate
// =======================
NS_QUERYFRAME_HEAD(nsRubyBaseFrame)
NS_QUERYFRAME_ENTRY(nsRubyBaseFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
NS_IMPL_FRAMEARENA_HELPERS(nsRubyBaseFrame)
nsContainerFrame*
NS_NewRubyBaseFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext)
{
return new (aPresShell) nsRubyBaseFrame(aContext);
}
//----------------------------------------------------------------------
// nsRubyBaseFrame Method Implementations
// ======================================
nsIAtom*
nsRubyBaseFrame::GetType() const
{
return nsGkAtoms::rubyBaseFrame;
}
#ifdef DEBUG_FRAME_DUMP
nsresult
nsRubyBaseFrame::GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("RubyBase"), aResult);
}
#endif

View File

@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code is subject to the terms of the Mozilla Public License
* version 2.0 (the "License"). You can obtain a copy of the License at
* http://mozilla.org/MPL/2.0/. */
/* rendering object for CSS "display: ruby-base" */
#ifndef nsRubyBaseFrame_h___
#define nsRubyBaseFrame_h___
#include "nsContainerFrame.h"
/**
* Factory function.
* @return a newly allocated nsRubyBaseFrame (infallible)
*/
nsContainerFrame* NS_NewRubyBaseFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext);
class nsRubyBaseFrame MOZ_FINAL : public nsContainerFrame
{
public:
NS_DECL_FRAMEARENA_HELPERS
NS_DECL_QUERYFRAME_TARGET(nsRubyBaseFrame)
NS_DECL_QUERYFRAME
// nsIFrame overrides
virtual nsIAtom* GetType() const MOZ_OVERRIDE;
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
#endif
protected:
friend nsContainerFrame* NS_NewRubyBaseFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext);
nsRubyBaseFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
};
#endif /* nsRubyBaseFrame_h___ */

View File

@ -0,0 +1,55 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code is subject to the terms of the Mozilla Public License
* version 2.0 (the "License"). You can obtain a copy of the License at
* http://mozilla.org/MPL/2.0/. */
/* rendering object for CSS "display: ruby" */
#include "nsRubyFrame.h"
#include "nsPresContext.h"
#include "nsStyleContext.h"
//----------------------------------------------------------------------
// Frame class boilerplate
// =======================
NS_QUERYFRAME_HEAD(nsRubyFrame)
NS_QUERYFRAME_ENTRY(nsRubyFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
NS_IMPL_FRAMEARENA_HELPERS(nsRubyFrame)
nsContainerFrame*
NS_NewRubyFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext)
{
return new (aPresShell) nsRubyFrame(aContext);
}
//----------------------------------------------------------------------
// nsRubyFrame Method Implementations
// ==================================
nsIAtom*
nsRubyFrame::GetType() const
{
return nsGkAtoms::rubyFrame;
}
bool
nsRubyFrame::IsFrameOfType(uint32_t aFlags) const
{
return nsContainerFrame::IsFrameOfType(aFlags &
~(nsIFrame::eBidiInlineContainer | nsIFrame::eLineParticipant));
}
#ifdef DEBUG_FRAME_DUMP
nsresult
nsRubyFrame::GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("Ruby"), aResult);
}
#endif

View File

@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code is subject to the terms of the Mozilla Public License
* version 2.0 (the "License"). You can obtain a copy of the License at
* http://mozilla.org/MPL/2.0/. */
/* rendering object for CSS "display: ruby" */
#ifndef nsRubyFrame_h___
#define nsRubyFrame_h___
#include "nsContainerFrame.h"
/**
* Factory function.
* @return a newly allocated nsRubyFrame (infallible)
*/
nsContainerFrame* NS_NewRubyFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext);
class nsRubyFrame MOZ_FINAL : public nsContainerFrame
{
public:
NS_DECL_FRAMEARENA_HELPERS
NS_DECL_QUERYFRAME_TARGET(nsRubyFrame)
NS_DECL_QUERYFRAME
// nsIFrame overrides
virtual nsIAtom* GetType() const MOZ_OVERRIDE;
virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE;
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
#endif
protected:
friend nsContainerFrame* NS_NewRubyFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext);
nsRubyFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
};
#endif /* nsRubyFrame_h___ */

View File

@ -0,0 +1,49 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code is subject to the terms of the Mozilla Public License
* version 2.0 (the "License"). You can obtain a copy of the License at
* http://mozilla.org/MPL/2.0/. */
/* rendering object for CSS "display: ruby-text-container" */
#include "nsRubyTextContainerFrame.h"
#include "nsPresContext.h"
#include "nsStyleContext.h"
//----------------------------------------------------------------------
// Frame class boilerplate
// =======================
NS_QUERYFRAME_HEAD(nsRubyTextContainerFrame)
NS_QUERYFRAME_ENTRY(nsRubyTextContainerFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
NS_IMPL_FRAMEARENA_HELPERS(nsRubyTextContainerFrame)
nsContainerFrame*
NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext)
{
return new (aPresShell) nsRubyTextContainerFrame(aContext);
}
//----------------------------------------------------------------------
// nsRubyTextContainerFrame Method Implementations
// ===============================================
nsIAtom*
nsRubyTextContainerFrame::GetType() const
{
return nsGkAtoms::rubyTextContainerFrame;
}
#ifdef DEBUG_FRAME_DUMP
nsresult
nsRubyTextContainerFrame::GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("RubyTextContainer"), aResult);
}
#endif

View File

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code is subject to the terms of the Mozilla Public License
* version 2.0 (the "License"). You can obtain a copy of the License at
* http://mozilla.org/MPL/2.0/. */
/* rendering object for CSS "display: ruby-text-container" */
#ifndef nsRubyTextContainerFrame_h___
#define nsRubyTextContainerFrame_h___
#include "nsBlockFrame.h"
/**
* Factory function.
* @return a newly allocated nsRubyTextContainerFrame (infallible)
*/
nsContainerFrame* NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext);
// If this is ever changed to be inline again, the code in
// nsFrame::IsFontSizeInflationContainer should be updated to stop excluding
// this from being considered inline.
class nsRubyTextContainerFrame MOZ_FINAL : public nsBlockFrame
{
public:
NS_DECL_FRAMEARENA_HELPERS
NS_DECL_QUERYFRAME_TARGET(nsRubyTextContainerFrame)
NS_DECL_QUERYFRAME
// nsIFrame overrides
virtual nsIAtom* GetType() const MOZ_OVERRIDE;
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
#endif
protected:
friend nsContainerFrame*
NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext);
nsRubyTextContainerFrame(nsStyleContext* aContext) : nsBlockFrame(aContext) {}
};
#endif /* nsRubyTextContainerFrame_h___ */

View File

@ -0,0 +1,49 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code is subject to the terms of the Mozilla Public License
* version 2.0 (the "License"). You can obtain a copy of the License at
* http://mozilla.org/MPL/2.0/. */
/* rendering object for CSS "display: ruby-text" */
#include "nsRubyTextFrame.h"
#include "nsPresContext.h"
#include "nsStyleContext.h"
//----------------------------------------------------------------------
// Frame class boilerplate
// =======================
NS_QUERYFRAME_HEAD(nsRubyTextFrame)
NS_QUERYFRAME_ENTRY(nsRubyTextFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
NS_IMPL_FRAMEARENA_HELPERS(nsRubyTextFrame)
nsContainerFrame*
NS_NewRubyTextFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext)
{
return new (aPresShell) nsRubyTextFrame(aContext);
}
//----------------------------------------------------------------------
// nsRubyTextFrame Method Implementations
// ======================================
nsIAtom*
nsRubyTextFrame::GetType() const
{
return nsGkAtoms::rubyTextFrame;
}
#ifdef DEBUG_FRAME_DUMP
nsresult
nsRubyTextFrame::GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("RubyText"), aResult);
}
#endif

View File

@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code is subject to the terms of the Mozilla Public License
* version 2.0 (the "License"). You can obtain a copy of the License at
* http://mozilla.org/MPL/2.0/. */
/* rendering object for CSS "display: ruby-text" */
#ifndef nsRubyTextFrame_h___
#define nsRubyTextFrame_h___
#include "nsContainerFrame.h"
/**
* Factory function.
* @return a newly allocated nsRubyTextFrame (infallible)
*/
nsContainerFrame* NS_NewRubyTextFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext);
class nsRubyTextFrame MOZ_FINAL : public nsContainerFrame
{
public:
NS_DECL_FRAMEARENA_HELPERS
NS_DECL_QUERYFRAME_TARGET(nsRubyTextFrame)
NS_DECL_QUERYFRAME
// nsIFrame overrides
virtual nsIAtom* GetType() const MOZ_OVERRIDE;
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
#endif
protected:
friend nsContainerFrame* NS_NewRubyTextFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext);
nsRubyTextFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
};
#endif /* nsRubyTextFrame_h___ */

View File

@ -164,7 +164,9 @@ function do_test() {
"table", "inline-table", "table-row-group", "table-header-group", "table-footer-group", "table-row",
"table-column-group", "table-column", "table-cell", "table-caption", "-moz-box", "-moz-inline-box",
"-moz-grid", "-moz-inline-grid", "-moz-grid-group", "-moz-grid-line", "-moz-stack", "-moz-inline-stack",
"-moz-deck", "-moz-popup", "-moz-groupbox", "flex", "inline-flex", "grid", "inline-grid" ];
"-moz-deck", "-moz-popup", "-moz-groupbox", "flex", "inline-flex", "grid",
"inline-grid", "ruby", "ruby-base", "ruby-base-container", "ruby-text",
"ruby-text-container" ];
ok(testValues(values, expected), "property display's values.");
// test property

View File

@ -70,6 +70,12 @@ CSS_ANON_BOX(anonymousFlexItem, ":-moz-anonymous-flex-item")
// an anonymous block, which is then treated as a grid item.
CSS_ANON_BOX(anonymousGridItem, ":-moz-anonymous-grid-item")
CSS_ANON_BOX(ruby, ":-moz-ruby")
CSS_ANON_BOX(rubyBase, ":-moz-ruby-base")
CSS_ANON_BOX(rubyBaseContainer, ":-moz-ruby-base-container")
CSS_ANON_BOX(rubyText, ":-moz-ruby-text")
CSS_ANON_BOX(rubyTextContainer, ":-moz-ruby-text-container")
#ifdef MOZ_XUL
CSS_ANON_BOX(moztreecolumn, ":-moz-tree-column")
CSS_ANON_BOX(moztreerow, ":-moz-tree-row")

View File

@ -430,6 +430,10 @@ CSS_KEY(row-resize, row_resize)
CSS_KEY(row-reverse, row_reverse)
CSS_KEY(rtl, rtl)
CSS_KEY(ruby, ruby)
CSS_KEY(ruby-base, ruby_base)
CSS_KEY(ruby-base-container, ruby_base_container)
CSS_KEY(ruby-text, ruby_text)
CSS_KEY(ruby-text-container, ruby_text_container)
CSS_KEY(running, running)
CSS_KEY(s, s)
CSS_KEY(s-resize, s_resize)

View File

@ -1044,41 +1044,47 @@ const KTableValue nsCSSProps::kDirectionKTable[] = {
};
KTableValue nsCSSProps::kDisplayKTable[] = {
eCSSKeyword_none, NS_STYLE_DISPLAY_NONE,
eCSSKeyword_inline, NS_STYLE_DISPLAY_INLINE,
eCSSKeyword_block, NS_STYLE_DISPLAY_BLOCK,
eCSSKeyword_inline_block, NS_STYLE_DISPLAY_INLINE_BLOCK,
eCSSKeyword_list_item, NS_STYLE_DISPLAY_LIST_ITEM,
eCSSKeyword_table, NS_STYLE_DISPLAY_TABLE,
eCSSKeyword_inline_table, NS_STYLE_DISPLAY_INLINE_TABLE,
eCSSKeyword_table_row_group, NS_STYLE_DISPLAY_TABLE_ROW_GROUP,
eCSSKeyword_table_header_group, NS_STYLE_DISPLAY_TABLE_HEADER_GROUP,
eCSSKeyword_table_footer_group, NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP,
eCSSKeyword_table_row, NS_STYLE_DISPLAY_TABLE_ROW,
eCSSKeyword_table_column_group, NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP,
eCSSKeyword_table_column, NS_STYLE_DISPLAY_TABLE_COLUMN,
eCSSKeyword_table_cell, NS_STYLE_DISPLAY_TABLE_CELL,
eCSSKeyword_table_caption, NS_STYLE_DISPLAY_TABLE_CAPTION,
eCSSKeyword_none, NS_STYLE_DISPLAY_NONE,
eCSSKeyword_inline, NS_STYLE_DISPLAY_INLINE,
eCSSKeyword_block, NS_STYLE_DISPLAY_BLOCK,
eCSSKeyword_inline_block, NS_STYLE_DISPLAY_INLINE_BLOCK,
eCSSKeyword_list_item, NS_STYLE_DISPLAY_LIST_ITEM,
eCSSKeyword_table, NS_STYLE_DISPLAY_TABLE,
eCSSKeyword_inline_table, NS_STYLE_DISPLAY_INLINE_TABLE,
eCSSKeyword_table_row_group, NS_STYLE_DISPLAY_TABLE_ROW_GROUP,
eCSSKeyword_table_header_group, NS_STYLE_DISPLAY_TABLE_HEADER_GROUP,
eCSSKeyword_table_footer_group, NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP,
eCSSKeyword_table_row, NS_STYLE_DISPLAY_TABLE_ROW,
eCSSKeyword_table_column_group, NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP,
eCSSKeyword_table_column, NS_STYLE_DISPLAY_TABLE_COLUMN,
eCSSKeyword_table_cell, NS_STYLE_DISPLAY_TABLE_CELL,
eCSSKeyword_table_caption, NS_STYLE_DISPLAY_TABLE_CAPTION,
// Make sure this is kept in sync with the code in
// nsCSSFrameConstructor::ConstructXULFrame
eCSSKeyword__moz_box, NS_STYLE_DISPLAY_BOX,
eCSSKeyword__moz_inline_box, NS_STYLE_DISPLAY_INLINE_BOX,
eCSSKeyword__moz_box, NS_STYLE_DISPLAY_BOX,
eCSSKeyword__moz_inline_box, NS_STYLE_DISPLAY_INLINE_BOX,
#ifdef MOZ_XUL
eCSSKeyword__moz_grid, NS_STYLE_DISPLAY_XUL_GRID,
eCSSKeyword__moz_inline_grid, NS_STYLE_DISPLAY_INLINE_XUL_GRID,
eCSSKeyword__moz_grid_group, NS_STYLE_DISPLAY_XUL_GRID_GROUP,
eCSSKeyword__moz_grid_line, NS_STYLE_DISPLAY_XUL_GRID_LINE,
eCSSKeyword__moz_stack, NS_STYLE_DISPLAY_STACK,
eCSSKeyword__moz_inline_stack, NS_STYLE_DISPLAY_INLINE_STACK,
eCSSKeyword__moz_deck, NS_STYLE_DISPLAY_DECK,
eCSSKeyword__moz_popup, NS_STYLE_DISPLAY_POPUP,
eCSSKeyword__moz_groupbox, NS_STYLE_DISPLAY_GROUPBOX,
eCSSKeyword__moz_grid, NS_STYLE_DISPLAY_XUL_GRID,
eCSSKeyword__moz_inline_grid, NS_STYLE_DISPLAY_INLINE_XUL_GRID,
eCSSKeyword__moz_grid_group, NS_STYLE_DISPLAY_XUL_GRID_GROUP,
eCSSKeyword__moz_grid_line, NS_STYLE_DISPLAY_XUL_GRID_LINE,
eCSSKeyword__moz_stack, NS_STYLE_DISPLAY_STACK,
eCSSKeyword__moz_inline_stack, NS_STYLE_DISPLAY_INLINE_STACK,
eCSSKeyword__moz_deck, NS_STYLE_DISPLAY_DECK,
eCSSKeyword__moz_popup, NS_STYLE_DISPLAY_POPUP,
eCSSKeyword__moz_groupbox, NS_STYLE_DISPLAY_GROUPBOX,
#endif
eCSSKeyword_flex, NS_STYLE_DISPLAY_FLEX,
eCSSKeyword_inline_flex, NS_STYLE_DISPLAY_INLINE_FLEX,
eCSSKeyword_flex, NS_STYLE_DISPLAY_FLEX,
eCSSKeyword_inline_flex, NS_STYLE_DISPLAY_INLINE_FLEX,
// The next two entries are controlled by the layout.css.grid.enabled pref.
eCSSKeyword_grid, NS_STYLE_DISPLAY_GRID,
eCSSKeyword_inline_grid, NS_STYLE_DISPLAY_INLINE_GRID,
eCSSKeyword_grid, NS_STYLE_DISPLAY_GRID,
eCSSKeyword_inline_grid, NS_STYLE_DISPLAY_INLINE_GRID,
// The next five entries are controlled by the layout.css.ruby.enabled pref.
eCSSKeyword_ruby, NS_STYLE_DISPLAY_RUBY,
eCSSKeyword_ruby_base, NS_STYLE_DISPLAY_RUBY_BASE,
eCSSKeyword_ruby_base_container, NS_STYLE_DISPLAY_RUBY_BASE_CONTAINER,
eCSSKeyword_ruby_text, NS_STYLE_DISPLAY_RUBY_TEXT,
eCSSKeyword_ruby_text_container, NS_STYLE_DISPLAY_RUBY_TEXT_CONTAINER,
eCSSKeyword_UNKNOWN,-1
};

View File

@ -181,6 +181,36 @@ nsRuleNode::EnsureBlockDisplay(uint8_t& display,
}
}
// EnsureInlineDisplay:
// - if the display value (argument) is not an inline type
// then we set it to a valid inline display value
/* static */
void
nsRuleNode::EnsureInlineDisplay(uint8_t& display)
{
// see if the display value is already inline
switch (display) {
case NS_STYLE_DISPLAY_BLOCK :
display = NS_STYLE_DISPLAY_INLINE_BLOCK;
break;
case NS_STYLE_DISPLAY_TABLE :
display = NS_STYLE_DISPLAY_INLINE_TABLE;
break;
case NS_STYLE_DISPLAY_FLEX :
display = NS_STYLE_DISPLAY_INLINE_FLEX;
break;
case NS_STYLE_DISPLAY_GRID :
display = NS_STYLE_DISPLAY_INLINE_GRID;
break;
case NS_STYLE_DISPLAY_BOX:
display = NS_STYLE_DISPLAY_INLINE_BOX;
break;
case NS_STYLE_DISPLAY_STACK:
display = NS_STYLE_DISPLAY_INLINE_STACK;
break;
}
}
static nscoord CalcLengthWith(const nsCSSValue& aValue,
nscoord aFontSize,
const nsStyleFont* aStyleFont,

View File

@ -674,6 +674,7 @@ public:
static void EnsureBlockDisplay(uint8_t& display,
bool aConvertListItem = false);
static void EnsureInlineDisplay(uint8_t& display);
// Transition never returns null; on out of memory it'll just return |this|.
nsRuleNode* Transition(nsIStyleRule* aRule, uint8_t aLevel,

View File

@ -416,6 +416,11 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
#define NS_STYLE_DISPLAY_INLINE_FLEX 30
#define NS_STYLE_DISPLAY_GRID 31
#define NS_STYLE_DISPLAY_INLINE_GRID 32
#define NS_STYLE_DISPLAY_RUBY 33
#define NS_STYLE_DISPLAY_RUBY_BASE 34
#define NS_STYLE_DISPLAY_RUBY_BASE_CONTAINER 35
#define NS_STYLE_DISPLAY_RUBY_TEXT 36
#define NS_STYLE_DISPLAY_RUBY_TEXT_CONTAINER 37
// See nsStylePosition
#define NS_STYLE_ALIGN_CONTENT_FLEX_START 0

View File

@ -356,12 +356,11 @@ nsStyleContext::ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup)
// # The computed 'display' of a flex item is determined
// # by applying the table in CSS 2.1 Chapter 9.7.
// ...which converts inline-level elements to their block-level equivalents.
// Any direct children of elements with Ruby display values which are
// block-level are converted to their inline-level equivalents.
if (!aSkipParentDisplayBasedStyleFixup && mParent) {
const nsStyleDisplay* parentDisp = mParent->StyleDisplay();
if ((parentDisp->mDisplay == NS_STYLE_DISPLAY_FLEX ||
parentDisp->mDisplay == NS_STYLE_DISPLAY_INLINE_FLEX ||
parentDisp->mDisplay == NS_STYLE_DISPLAY_GRID ||
parentDisp->mDisplay == NS_STYLE_DISPLAY_INLINE_GRID) &&
if (parentDisp->IsFlexOrGridDisplayType() &&
GetPseudo() != nsCSSAnonBoxes::mozNonElement) {
uint8_t displayVal = disp->mDisplay;
// Skip table parts.
@ -394,6 +393,16 @@ nsStyleContext::ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup)
static_cast<nsStyleDisplay*>(GetUniqueStyleData(eStyleStruct_Display));
mutable_display->mDisplay = displayVal;
}
}
} else if (parentDisp->IsRubyDisplayType()) {
uint8_t displayVal = disp->mDisplay;
nsRuleNode::EnsureInlineDisplay(displayVal);
// The display change should only occur for "in-flow" children
if (displayVal != disp->mDisplay &&
!disp->IsOutOfFlowStyle()) {
nsStyleDisplay *mutable_display =
static_cast<nsStyleDisplay*>(GetUniqueStyleData(eStyleStruct_Display));
mutable_display->mDisplay = displayVal;
}
}
}

View File

@ -2061,7 +2061,12 @@ struct nsStyleDisplay {
NS_STYLE_DISPLAY_INLINE_FLEX == aDisplay ||
NS_STYLE_DISPLAY_INLINE_GRID == aDisplay ||
NS_STYLE_DISPLAY_INLINE_XUL_GRID == aDisplay ||
NS_STYLE_DISPLAY_INLINE_STACK == aDisplay;
NS_STYLE_DISPLAY_INLINE_STACK == aDisplay ||
NS_STYLE_DISPLAY_RUBY == aDisplay ||
NS_STYLE_DISPLAY_RUBY_BASE == aDisplay ||
NS_STYLE_DISPLAY_RUBY_BASE_CONTAINER == aDisplay ||
NS_STYLE_DISPLAY_RUBY_TEXT == aDisplay ||
NS_STYLE_DISPLAY_RUBY_TEXT_CONTAINER == aDisplay;
}
bool IsInlineOutsideStyle() const {
@ -2097,6 +2102,25 @@ struct nsStyleDisplay {
NS_STYLE_POSITION_STICKY == mPosition;
}
bool IsRubyDisplayType() const {
return NS_STYLE_DISPLAY_RUBY == mDisplay ||
NS_STYLE_DISPLAY_RUBY_BASE == mDisplay ||
NS_STYLE_DISPLAY_RUBY_BASE_CONTAINER == mDisplay ||
NS_STYLE_DISPLAY_RUBY_TEXT == mDisplay ||
NS_STYLE_DISPLAY_RUBY_TEXT_CONTAINER == mDisplay;
}
bool IsFlexOrGridDisplayType() const {
return NS_STYLE_DISPLAY_FLEX == mDisplay ||
NS_STYLE_DISPLAY_INLINE_FLEX == mDisplay ||
NS_STYLE_DISPLAY_GRID == mDisplay ||
NS_STYLE_DISPLAY_INLINE_GRID == mDisplay;
}
bool IsOutOfFlowStyle() const {
return (IsAbsolutelyPositionedStyle() || IsFloatingStyle());
}
bool IsScrollableOverflow() const {
// mOverflowX and mOverflowY always match when one of them is
// NS_STYLE_OVERFLOW_VISIBLE or NS_STYLE_OVERFLOW_CLIP.

View File

@ -4799,6 +4799,17 @@ if (SpecialPowers.getBoolPref("layout.css.filters.enabled")) {
};
}
if (SpecialPowers.getBoolPref("layout.css.ruby.enabled")) {
// Using unshift to add these values at the beginning.
// Adding them to the end would trigger bug 1038905. The "unshift" should be
// changed to a "push" when this bug is resolved.
gCSSProperties["display"].other_values.unshift("ruby",
"ruby-base",
"ruby-base-container",
"ruby-text",
"ruby-text-container");
}
if (SpecialPowers.getBoolPref("layout.css.grid.enabled")) {
gCSSProperties["display"].other_values.push("grid", "inline-grid");
gCSSProperties["grid-auto-flow"] = {

View File

@ -72,6 +72,23 @@
white-space: inherit;
}
/* Ruby */
*|*::-moz-ruby {
display: ruby;
}
*|*::-moz-ruby-base {
display: ruby-base;
}
*|*::-moz-ruby-text {
display: ruby-text;
}
*|*::-moz-ruby-base-container {
display: ruby-base-container;
}
*|*::-moz-ruby-text-container {
display: ruby-text-container;
}
/* Lists */
*|*::-moz-list-bullet, *|*::-moz-list-number {

View File

@ -748,7 +748,7 @@ public class BrowserApp extends GeckoApp
String title = tab.getDisplayTitle();
Bitmap favicon = tab.getFavicon();
if (url != null && title != null) {
GeckoAppShell.createShortcut(title, url, url, favicon, "");
GeckoAppShell.createShortcut(title, url, favicon);
}
}
}

View File

@ -597,13 +597,6 @@ public abstract class GeckoApp
// Context: Sharing via chrome list (no explicit session is active)
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST);
} else if ("Shortcut:Remove".equals(event)) {
final String url = message.getString("url");
final String origin = message.getString("origin");
final String title = message.getString("title");
final String type = message.getString("shortcutType");
GeckoAppShell.removeShortcut(title, url, origin, type);
} else if ("SystemUI:Visibility".equals(event)) {
setSystemUiVisible(message.getBoolean("visible"));
@ -1515,7 +1508,6 @@ public abstract class GeckoApp
"Sanitize:ClearHistory",
"Session:StatePurged",
"Share:Text",
"Shortcut:Remove",
"SystemUI:Visibility",
"Toast:Show",
"ToggleChrome:Focus",
@ -2050,7 +2042,6 @@ public abstract class GeckoApp
"Sanitize:ClearHistory",
"Session:StatePurged",
"Share:Text",
"Shortcut:Remove",
"SystemUI:Visibility",
"Toast:Show",
"ToggleChrome:Focus",

View File

@ -135,9 +135,6 @@ public class GeckoAppShell
// See also HardwareUtils.LOW_MEMORY_THRESHOLD_MB.
private static final int HIGH_MEMORY_DEVICE_THRESHOLD_MB = 768;
public static final String SHORTCUT_TYPE_WEBAPP = "webapp";
public static final String SHORTCUT_TYPE_BOOKMARK = "bookmark";
static private int sDensityDpi = 0;
static private int sScreenDepth = 0;
@ -254,7 +251,7 @@ public class GeckoAppShell
@Override
public void onFaviconLoaded(String pageUrl, String faviconURL, Bitmap favicon) {
GeckoAppShell.createShortcut(title, url, url, favicon, "");
GeckoAppShell.createShortcut(title, url, favicon);
}
}
@ -781,59 +778,25 @@ public class GeckoAppShell
restartScheduled = true;
}
public static Intent getWebappIntent(String aURI, String aOrigin, String aTitle, Bitmap aIcon) {
Intent intent;
Allocator slots = Allocator.getInstance(getContext());
int index = slots.getIndexForOrigin(aOrigin);
if (index == -1) {
return null;
}
String packageName = slots.getAppForIndex(index);
intent = getContext().getPackageManager().getLaunchIntentForPackage(packageName);
if (aURI != null) {
intent.setData(Uri.parse(aURI));
}
return intent;
}
// "Installs" an application by creating a shortcut
// This is the entry point from AndroidBridge.h
// Creates a homescreen shortcut for a web page.
// This is the entry point from nsIShellService.
@WrapElementForJNI
static void createShortcut(String aTitle, String aURI, String aIconData, String aType) {
if ("webapp".equals(aType)) {
Log.w(LOGTAG, "createShortcut with no unique URI should not be used for aType = webapp!");
}
createShortcut(aTitle, aURI, aURI, aIconData, aType);
}
// For non-webapps.
public static void createShortcut(String aTitle, String aURI, Bitmap aBitmap, String aType) {
createShortcut(aTitle, aURI, aURI, aBitmap, aType);
}
// Internal, for webapps.
static void createShortcut(final String aTitle, final String aURI, final String aUniqueURI, final String aIconData, final String aType) {
static void createShortcut(final String aTitle, final String aURI, final String aIconData) {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
// TODO: use the cache. Bug 961600.
Bitmap icon = FaviconDecoder.getMostSuitableBitmapFromDataURI(aIconData, getPreferredIconSize());
GeckoAppShell.doCreateShortcut(aTitle, aURI, aURI, icon, aType);
GeckoAppShell.doCreateShortcut(aTitle, aURI, icon);
}
});
}
public static void createShortcut(final String aTitle, final String aURI, final String aUniqueURI,
final Bitmap aIcon, final String aType) {
public static void createShortcut(final String aTitle, final String aURI, final Bitmap aBitmap) {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
GeckoAppShell.doCreateShortcut(aTitle, aURI, aUniqueURI, aIcon, aType);
GeckoAppShell.doCreateShortcut(aTitle, aURI, aBitmap);
}
});
}
@ -841,23 +804,17 @@ public class GeckoAppShell
/**
* Call this method only on the background thread.
*/
private static void doCreateShortcut(final String aTitle, final String aURI, final String aUniqueURI,
final Bitmap aIcon, final String aType) {
private static void doCreateShortcut(final String aTitle, final String aURI, final Bitmap aIcon) {
// The intent to be launched by the shortcut.
Intent shortcutIntent;
if (aType.equalsIgnoreCase(SHORTCUT_TYPE_WEBAPP)) {
shortcutIntent = getWebappIntent(aURI, aUniqueURI, aTitle, aIcon);
} else {
shortcutIntent = new Intent();
shortcutIntent.setAction(GeckoApp.ACTION_HOMESCREEN_SHORTCUT);
shortcutIntent.setData(Uri.parse(aURI));
shortcutIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
AppConstants.BROWSER_INTENT_CLASS_NAME);
}
Intent shortcutIntent = new Intent();
shortcutIntent.setAction(GeckoApp.ACTION_HOMESCREEN_SHORTCUT);
shortcutIntent.setData(Uri.parse(aURI));
shortcutIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
AppConstants.BROWSER_INTENT_CLASS_NAME);
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, getLauncherIcon(aIcon, aType));
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, getLauncherIcon(aIcon));
if (aTitle != null) {
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aTitle);
@ -872,41 +829,6 @@ public class GeckoAppShell
getContext().sendBroadcast(intent);
}
public static void removeShortcut(final String aTitle, final String aURI, final String aType) {
removeShortcut(aTitle, aURI, null, aType);
}
public static void removeShortcut(final String aTitle, final String aURI, final String aUniqueURI, final String aType) {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
// the intent to be launched by the shortcut
Intent shortcutIntent;
if (aType.equalsIgnoreCase(SHORTCUT_TYPE_WEBAPP)) {
shortcutIntent = getWebappIntent(aURI, aUniqueURI, "", null);
if (shortcutIntent == null)
return;
} else {
shortcutIntent = new Intent();
shortcutIntent.setAction(GeckoApp.ACTION_HOMESCREEN_SHORTCUT);
shortcutIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
AppConstants.BROWSER_INTENT_CLASS_NAME);
shortcutIntent.setData(Uri.parse(aURI));
}
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
if (aTitle != null)
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aTitle);
else
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aURI);
intent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
getContext().sendBroadcast(intent);
}
});
}
@JNITarget
static public int getPreferredIconSize() {
if (android.os.Build.VERSION.SDK_INT >= 11) {
@ -925,7 +847,7 @@ public class GeckoAppShell
}
}
static private Bitmap getLauncherIcon(Bitmap aSource, String aType) {
static private Bitmap getLauncherIcon(Bitmap aSource) {
final int kOffset = 6;
final int kRadius = 5;
int size = getPreferredIconSize();
@ -941,8 +863,8 @@ public class GeckoAppShell
// If we aren't drawing a favicon, just use an orange color.
paint.setColor(Color.HSVToColor(DEFAULT_LAUNCHER_ICON_HSV));
canvas.drawRoundRect(new RectF(kOffset, kOffset, size - kOffset, size - kOffset), kRadius, kRadius, paint);
} else if (aType.equalsIgnoreCase(SHORTCUT_TYPE_WEBAPP) || aSource.getWidth() >= insetSize || aSource.getHeight() >= insetSize) {
// otherwise, if this is a webapp or if the icons is lare enough, just draw it
} else if (aSource.getWidth() >= insetSize || aSource.getHeight() >= insetSize) {
// Otherwise, if the icon is large enough, just draw it.
Rect iconBounds = new Rect(0, 0, size, size);
canvas.drawBitmap(aSource, null, iconBounds, null);
return bitmap;

View File

@ -22,6 +22,7 @@ import android.util.Log;
import java.io.IOException;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicReference;
public class GeckoThread extends Thread implements GeckoEventListener {
private static final String LOGTAG = "GeckoThread";
@ -34,9 +35,10 @@ public class GeckoThread extends Thread implements GeckoEventListener {
GeckoRunning,
GeckoExiting,
GeckoExited
};
}
private static LaunchState sLaunchState = LaunchState.Launching;
private static AtomicReference<LaunchState> sLaunchState =
new AtomicReference<LaunchState>(LaunchState.Launching);
private static GeckoThread sGeckoThread;
@ -176,8 +178,6 @@ public class GeckoThread extends Thread implements GeckoEventListener {
GeckoAppShell.runGecko(path, args, mUri, type);
}
private static Object sLock = new Object();
@Override
public void handleMessage(String event, JSONObject message) {
if ("Gecko:Ready".equals(event)) {
@ -189,15 +189,11 @@ public class GeckoThread extends Thread implements GeckoEventListener {
@RobocopTarget
public static boolean checkLaunchState(LaunchState checkState) {
synchronized (sLock) {
return sLaunchState == checkState;
}
return sLaunchState.get() == checkState;
}
static void setLaunchState(LaunchState setState) {
synchronized (sLock) {
sLaunchState = setState;
}
sLaunchState.set(setState);
}
/**
@ -205,11 +201,6 @@ public class GeckoThread extends Thread implements GeckoEventListener {
* state is <code>checkState</code>; otherwise do nothing and return false.
*/
static boolean checkAndSetLaunchState(LaunchState checkState, LaunchState setState) {
synchronized (sLock) {
if (sLaunchState != checkState)
return false;
sLaunchState = setState;
return true;
}
return sLaunchState.compareAndSet(checkState, setState);
}
}

View File

@ -105,6 +105,7 @@ skip-if = android_version == "10"
[testJNI]
# [testMozPay] # see bug 945675
[testOrderedBroadcast]
[testResourceSubstitutions]
[testSharedPreferences]
[testSimpleDiscovery]
[testUITelemetry]

View File

@ -0,0 +1,9 @@
package org.mozilla.gecko.tests;
public class testResourceSubstitutions extends JavascriptTest {
public testResourceSubstitutions() {
super("testResourceSubstitutions.js");
}
}

View File

@ -0,0 +1,47 @@
// -*- indent-tabs-mode: nil; js-indent-level: 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/. */
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/Promise.jsm"); /*global Promise */
Cu.import("resource://gre/modules/Services.jsm"); /*global Services */
Cu.import("resource://gre/modules/NetUtil.jsm"); /*global NetUtil */
function readChannel(url) {
let deferred = Promise.defer();
let channel = NetUtil.newChannel(url);
channel.contentType = "text/plain";
NetUtil.asyncFetch(channel, function(inputStream, status) {
if (!Components.isSuccessCode(status)) {
deferred.reject();
return;
}
let content = NetUtil.readInputStreamToString(inputStream, inputStream.available());
deferred.resolve(content);
});
return deferred.promise;
}
add_task(function test_Android() {
let protocolHandler = Services.io
.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
do_check_true(protocolHandler.hasSubstitution("android"));
// This can be any file that we know exists in the root of every APK.
let packageName = yield readChannel("resource://android/package-name.txt");
// It's difficult to fish ANDROID_PACKAGE_NAME from JavaScript, so we test the
// following weaker condition.
let expectedPrefix = "org.mozilla.";
do_check_eq(packageName.substring(0, expectedPrefix.length), expectedPrefix);
});
run_next_test();

View File

@ -110,10 +110,6 @@ public class Allocator {
return findSlotForPrefix(PREFIX_PACKAGE_NAME, packageName);
}
public synchronized int getIndexForOrigin(String origin) {
return findSlotForPrefix(PREFIX_ORIGIN, origin);
}
protected int findSlotForPrefix(String prefix, String value) {
for (int i = 0; i < MAX_WEB_APPS; ++i) {
if (mPrefs.getString(prefix + i, "").equals(value)) {

View File

@ -45,7 +45,7 @@ public class EventListener implements NativeEventListener {
"Webapps:InstallApk",
"Webapps:UninstallApk",
"Webapps:Postinstall",
"Webapps:Open",
"Webapps:Launch",
"Webapps:Uninstall",
"Webapps:GetApkVersions");
}
@ -56,7 +56,7 @@ public class EventListener implements NativeEventListener {
"Webapps:InstallApk",
"Webapps:UninstallApk",
"Webapps:Postinstall",
"Webapps:Open",
"Webapps:Launch",
"Webapps:Uninstall",
"Webapps:GetApkVersions");
}
@ -70,14 +70,8 @@ public class EventListener implements NativeEventListener {
uninstallApk(GeckoAppShell.getGeckoInterface().getActivity(), message);
} else if (event.equals("Webapps:Postinstall")) {
postInstallWebapp(message.getString("apkPackageName"), message.getString("origin"));
} else if (event.equals("Webapps:Open")) {
Intent intent = GeckoAppShell.getWebappIntent(message.getString("manifestURL"),
message.getString("origin"),
"", null);
if (intent == null) {
return;
}
GeckoAppShell.getGeckoInterface().getActivity().startActivity(intent);
} else if (event.equals("Webapps:Launch")) {
launchWebapp(message.getString("packageName"));
} else if (event.equals("Webapps:GetApkVersions")) {
JSONObject obj = new JSONObject();
obj.put("versions", getApkVersions(GeckoAppShell.getGeckoInterface().getActivity(),
@ -95,6 +89,11 @@ public class EventListener implements NativeEventListener {
allocator.putOrigin(index, aOrigin);
}
private void launchWebapp(String aPackageName) {
Intent intent = GeckoAppShell.getContext().getPackageManager().getLaunchIntentForPackage(aPackageName);
GeckoAppShell.getGeckoInterface().getActivity().startActivity(intent);
}
public static void uninstallWebapp(final String packageName) {
// On uninstall, we need to do a couple of things:
// 1. nuke the running app process.

View File

@ -110,8 +110,7 @@ function addApplication(aApp) {
let container = document.createElement("div");
container.className = "app list-item";
container.setAttribute("contextmenu", "appmenu");
container.setAttribute("id", "app-" + aApp.origin);
container.setAttribute("mozApp", aApp.origin);
container.setAttribute("id", "app-" + aApp.manifestURL);
container.setAttribute("title", manifest.name);
let img = document.createElement("img");
@ -140,7 +139,7 @@ function addApplication(aApp) {
}
function onInstall(aEvent) {
let node = document.getElementById("app-" + aEvent.application.origin);
let node = document.getElementById("app-" + aEvent.application.manifestURL);
if (node)
return;
@ -149,7 +148,7 @@ function onInstall(aEvent) {
}
function onUninstall(aEvent) {
let node = document.getElementById("app-" + aEvent.application.origin);
let node = document.getElementById("app-" + aEvent.application.manifestURL);
if (node) {
let parent = node.parentNode;
parent.removeChild(node);

View File

@ -119,8 +119,33 @@ BrowserCLH.prototype = {
}
},
/**
* Register resource://android as the APK root.
*
* Consumers can access Android assets using resource://android/assets/FILENAME.
*/
setResourceSubstitutions: function () {
let registry = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci["nsIChromeRegistry"]);
// Like jar:jar:file:///data/app/org.mozilla.fennec-2.apk!/assets/omni.ja!/chrome/chrome/content/aboutHome.xhtml
let url = registry.convertChromeURL(Services.io.newURI("chrome://browser/content/aboutHome.xhtml", null, null)).spec;
// Like jar:file:///data/app/org.mozilla.fennec-2.apk!/
url = url.substring(4, url.indexOf("!/") + 2);
let protocolHandler = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
protocolHandler.setSubstitution("android", Services.io.newURI(url, null, null));
},
observe: function (subject, topic, data) {
switch (topic) {
case "app-startup":
this.setResourceSubstitutions();
break;
}
},
// QI
QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler,
Ci.nsIObserver]),
// XPCOMUtils factory
classID: Components.ID("{be623d20-d305-11de-8a39-0800200c9a66}")

View File

@ -66,6 +66,7 @@ category wakeup-request PromptService @mozilla.org/embedcomp/prompt-service;1,ns
component {be623d20-d305-11de-8a39-0800200c9a66} BrowserCLH.js application={aa3c5121-dab2-40e2-81ca-7ea25febc110}
contract @mozilla.org/browser/browser-clh;1 {be623d20-d305-11de-8a39-0800200c9a66}
category command-line-handler x-browser @mozilla.org/browser/browser-clh;1
category app-startup BrowserCLH @mozilla.org/browser/browser-clh;1
# ContentDispatchChooser.js
component {5a072a22-1e66-4100-afc1-07aed8b62fc5} ContentDispatchChooser.js

View File

@ -20,7 +20,7 @@ interface nsIShellService : nsISupports
* @param aTitle the user-friendly name of the shortcut.
* @param aURI the URI to open.
* @param aIconData a base64-encoded data: URI representation of the shortcut's icon, as accepted by the favicon decoder.
* @param aIntent how the URI should be opened. Examples: "default", "bookmark" and "webapp"
* @param aIntent obsolete and ignored, but remains for backward compatibility; pass an empty string
*/
void createShortcut(in AString aTitle, in AString aURI, in AString aIconData, in AString aIntent);
};

View File

@ -25,6 +25,6 @@ nsShellService::CreateShortcut(const nsAString& aTitle, const nsAString& aURI,
if (!aTitle.Length() || !aURI.Length() || !aIconData.Length())
return NS_ERROR_FAILURE;
mozilla::widget::android::GeckoAppShell::CreateShortcut(aTitle, aURI, aIconData, aIntent);
mozilla::widget::android::GeckoAppShell::CreateShortcut(aTitle, aURI, aIconData);
return NS_OK;
}

View File

@ -198,13 +198,12 @@ this.WebappManager = {
this.writeDefaultPrefs(file, localeManifest);
},
launch: function({ manifestURL, origin }) {
debug("launchWebapp: " + manifestURL);
launch: function({ apkPackageName }) {
debug("launch: " + apkPackageName);
sendMessageToJava({
type: "Webapps:Open",
manifestURL: manifestURL,
origin: origin
type: "Webapps:Launch",
packageName: apkPackageName,
});
},

View File

@ -13,6 +13,7 @@ import android.view.View;
import org.mozilla.gecko.db.BrowserContract.SearchHistory;
import org.mozilla.search.autocomplete.AcceptsSearchQuery;
import org.mozilla.search.autocomplete.SearchFragment;
/**
* The main entrance for the Android search intent.
@ -58,8 +59,12 @@ public class MainActivity extends FragmentActivity implements AcceptsSearchQuery
public void onSearch(String query) {
startPostsearch();
storeQuery(query);
((PostSearchFragment) getSupportFragmentManager().findFragmentById(R.id.postsearch))
.setUrl("https://search.yahoo.com/search?p=" + Uri.encode(query));
((SearchFragment) getSupportFragmentManager().findFragmentById(R.id.search_fragment))
.setSearchTerm(query);
}
private void startPresearch() {

View File

@ -0,0 +1,123 @@
/* 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/. */
package org.mozilla.search.autocomplete;
import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;
import org.mozilla.search.R;
public class ClearableEditText extends FrameLayout {
private EditText editText;
private Button clearButton;
private InputMethodManager inputMethodManager;
private TextListener listener;
private boolean active;
public interface TextListener {
public void onChange(String text);
public void onSubmit(String text);
}
public ClearableEditText(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.clearable_edit_text, this);
editText = (EditText) findViewById(R.id.edit_text);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (listener != null) {
listener.onChange(s.toString());
}
}
});
// Attach a listener for the "search" key on the keyboard.
editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (listener != null && actionId == EditorInfo.IME_ACTION_SEARCH) {
listener.onSubmit(v.getText().toString());
return true;
}
return false;
}
});
clearButton = (Button) findViewById(R.id.clear_button);
clearButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
editText.setText("");
}
});
inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
}
public void setText(String text) {
editText.setText(text);
// Move cursor to end of search input.
editText.setSelection(text.length());
}
public void setActive(boolean active) {
if (this.active == active) {
return;
}
this.active = active;
clearButton.setVisibility(active ? View.VISIBLE : View.GONE);
editText.setFocusable(active);
editText.setFocusableInTouchMode(active);
if (active) {
editText.requestFocus();
inputMethodManager.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
} else {
editText.clearFocus();
inputMethodManager.hideSoftInputFromWindow(editText.getWindowToken(), 0);
}
}
public void setTextListener(TextListener listener) {
this.listener = listener;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
// When the view is active, pass touch events to child views.
// Otherwise, intercept touch events to allow click listeners on the view to
// fire no matter where the user clicks.
return !active;
}
}

View File

@ -4,7 +4,6 @@
package org.mozilla.search.autocomplete;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
@ -12,21 +11,13 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.text.Editable;
import android.text.SpannableString;
import android.text.TextWatcher;
import android.text.style.ForegroundColorSpan;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import org.mozilla.search.R;
@ -39,8 +30,7 @@ import java.util.List;
* <p/>
* TODO: Add more search providers (other than the dictionary)
*/
public class SearchFragment extends Fragment
implements TextView.OnEditorActionListener, AcceptsJumpTaps {
public class SearchFragment extends Fragment implements AcceptsJumpTaps {
private static final int LOADER_ID_SUGGESTION = 0;
private static final String KEY_SEARCH_TERM = "search_term";
@ -54,16 +44,14 @@ public class SearchFragment extends Fragment
// Color of search term match in search suggestion
private static final int SUGGESTION_HIGHLIGHT_COLOR = 0xFF999999;
private AcceptsSearchQuery searchListener;
private SuggestClient suggestClient;
private SuggestionLoaderCallbacks suggestionLoaderCallbacks;
private InputMethodManager inputMethodManager;
private AutoCompleteAdapter autoCompleteAdapter;
private View mainView;
private View searchBar;
private EditText editText;
private Button clearButton;
private ClearableEditText editText;
private ListView suggestionDropdown;
private State state = State.WAITING;
@ -81,6 +69,12 @@ public class SearchFragment extends Fragment
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof AcceptsSearchQuery) {
searchListener = (AcceptsSearchQuery) activity;
} else {
throw new ClassCastException(activity.toString() + " must implement AcceptsSearchQuery.");
}
// TODO: Don't hard-code this template string (bug 1039758)
final String template = "https://search.yahoo.com/sugg/ff?" +
"output=fxjson&appid=ffm&command=__searchTerms__&nresults=" + SUGGESTION_MAX;
@ -88,7 +82,6 @@ public class SearchFragment extends Fragment
suggestClient = new SuggestClient(activity, template, SUGGESTION_TIMEOUT, SUGGESTION_MAX);
suggestionLoaderCallbacks = new SuggestionLoaderCallbacks();
inputMethodManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
autoCompleteAdapter = new AutoCompleteAdapter(activity, this);
}
@ -96,9 +89,9 @@ public class SearchFragment extends Fragment
public void onDetach() {
super.onDetach();
searchListener = null;
suggestClient = null;
suggestionLoaderCallbacks = null;
inputMethodManager = null;
autoCompleteAdapter = null;
}
@ -115,42 +108,33 @@ public class SearchFragment extends Fragment
}
});
searchBar = mainView.findViewById(R.id.search_bar);
editText = (EditText) mainView.findViewById(R.id.search_bar_edit_text);
// Disable the click listener while the fragment is State.WAITING.
// We can't do this in the layout file because the setOnClickListener
// implementation calls setClickable(true).
mainView.setClickable(false);
final View.OnClickListener transitionToRunningListener = new View.OnClickListener() {
editText = (ClearableEditText) mainView.findViewById(R.id.auto_complete_edit_text);
editText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
transitionToRunning();
}
};
searchBar.setOnClickListener(transitionToRunningListener);
editText.setOnClickListener(transitionToRunningListener);
// Attach a listener for the "search" key on the keyboard.
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
final Bundle args = new Bundle();
args.putString(KEY_SEARCH_TERM, s.toString());
getLoaderManager().restartLoader(LOADER_ID_SUGGESTION, args, suggestionLoaderCallbacks);
}
});
editText.setOnEditorActionListener(this);
clearButton = (Button) mainView.findViewById(R.id.search_bar_clear_button);
clearButton.setOnClickListener(new View.OnClickListener(){
editText.setTextListener(new ClearableEditText.TextListener() {
@Override
public void onClick(View v) {
editText.setText("");
public void onChange(String text) {
if (state == State.RUNNING) {
final Bundle args = new Bundle();
args.putString(KEY_SEARCH_TERM, text);
getLoaderManager().restartLoader(LOADER_ID_SUGGESTION, args, suggestionLoaderCallbacks);
}
}
@Override
public void onSubmit(String text) {
transitionToWaiting();
searchListener.onSearch(text);
}
});
@ -162,7 +146,9 @@ public class SearchFragment extends Fragment
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final Suggestion suggestion = (Suggestion) suggestionDropdown.getItemAtPosition(position);
startSearch(suggestion.value);
transitionToWaiting();
searchListener.onSearch(suggestion.value);
}
});
@ -173,9 +159,7 @@ public class SearchFragment extends Fragment
public void onDestroyView() {
super.onDestroyView();
searchBar = null;
editText = null;
clearButton = null;
if (null != suggestionDropdown) {
suggestionDropdown.setOnItemClickListener(null);
@ -184,78 +168,41 @@ public class SearchFragment extends Fragment
}
}
/**
* Handler for the "search" button on the keyboard.
*/
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
startSearch(v.getText().toString());
return true;
}
return false;
public void onJumpTap(String suggestion) {
setSearchTerm(suggestion);
}
/**
* Send a search intent and put the widget into waiting.
* Sets the search term in the search bar. If the SearchFragment is
* in State.RUNNING, this will also update the search suggestions.
*
* @param searchTerm
*/
private void startSearch(String queryString) {
if (getActivity() instanceof AcceptsSearchQuery) {
editText.setText(queryString);
editText.setSelection(queryString.length());
transitionToWaiting();
((AcceptsSearchQuery) getActivity()).onSearch(queryString);
} else {
throw new RuntimeException("Parent activity does not implement AcceptsSearchQuery.");
}
public void setSearchTerm(String searchTerm) {
editText.setText(searchTerm);
}
private void transitionToWaiting() {
if (state == State.WAITING) {
return;
}
setEditTextFocusable(false);
mainView.setClickable(false);
suggestionDropdown.setVisibility(View.GONE);
clearButton.setVisibility(View.GONE);
state = State.WAITING;
mainView.setClickable(false);
editText.setActive(false);
suggestionDropdown.setVisibility(View.GONE);
}
private void transitionToRunning() {
if (state == State.RUNNING) {
return;
}
setEditTextFocusable(true);
mainView.setClickable(true);
suggestionDropdown.setVisibility(View.VISIBLE);
clearButton.setVisibility(View.VISIBLE);
state = State.RUNNING;
}
private void setEditTextFocusable(boolean focusable) {
editText.setFocusable(focusable);
editText.setFocusableInTouchMode(focusable);
if (focusable) {
editText.requestFocus();
inputMethodManager.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
} else {
editText.clearFocus();
inputMethodManager.hideSoftInputFromWindow(editText.getWindowToken(), 0);
}
}
@Override
public void onJumpTap(String suggestion) {
editText.setText(suggestion);
// Move cursor to end of search input.
editText.setSelection(suggestion.length());
mainView.setClickable(true);
editText.setActive(true);
suggestionDropdown.setVisibility(View.VISIBLE);
}
public static class Suggestion {

View File

@ -0,0 +1,28 @@
<!-- 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/. -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<EditText
android:id="@+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionSearch"
android:inputType="textNoSuggestions|textVisiblePassword"
android:drawableLeft="@drawable/search_icon"
android:drawablePadding="10dp"
android:focusable="false"
android:focusableInTouchMode="false"
android:hint="@string/search_bar_hint"/>
<Button
android:id="@+id/clear_button"
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_gravity="right|center_vertical"
android:layout_marginRight="10dp"
android:background="@drawable/search_clear"
android:visibility="gone"/>
</merge>

View File

@ -8,37 +8,13 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:clickable="false"
tools:context=".autocomplete.AutoCompleteFragment">
<FrameLayout
android:id="@+id/search_bar"
<org.mozilla.search.autocomplete.ClearableEditText
android:id="@+id/auto_complete_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<EditText
android:id="@+id/search_bar_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionSearch"
android:inputType="textNoSuggestions|textVisiblePassword"
android:drawableLeft="@drawable/search_icon"
android:drawablePadding="10dp"
android:focusable="false"
android:focusableInTouchMode="false"
android:hint="@string/search_bar_hint"/>
<Button
android:id="@+id/search_bar_clear_button"
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_gravity="right|center_vertical"
android:layout_marginRight="10dp"
android:background="@drawable/search_clear"
android:visibility="gone"/>
</FrameLayout>
android:padding="10dp"/>
<ListView
android:id="@+id/auto_complete_dropdown"

View File

@ -8,6 +8,7 @@ search_activity_sources = [
'java/org/mozilla/search/autocomplete/AcceptsJumpTaps.java',
'java/org/mozilla/search/autocomplete/AcceptsSearchQuery.java',
'java/org/mozilla/search/autocomplete/AutoCompleteAdapter.java',
'java/org/mozilla/search/autocomplete/ClearableEditText.java',
'java/org/mozilla/search/autocomplete/SearchFragment.java',
'java/org/mozilla/search/autocomplete/SuggestClient.java',
'java/org/mozilla/search/Constants.java',

View File

@ -2000,6 +2000,9 @@ pref("layout.css.overflow-clip-box.enabled", false);
// Is support for CSS grid enabled?
pref("layout.css.grid.enabled", false);
// Is support for CSS Ruby enabled?
pref("layout.css.ruby.enabled", false);
// Is support for CSS box-decoration-break enabled?
pref("layout.css.box-decoration-break.enabled", true);

View File

@ -136,6 +136,9 @@ user_pref("layout.css.report_errors", true);
// Enable CSS Grid for testing
user_pref("layout.css.grid.enabled", true);
// Enable CSS Ruby for testing
user_pref("layout.css.ruby.enabled", true);
// Enable mozContacts
user_pref("dom.mozContacts.enabled", true);
user_pref("dom.navigator-property.disable.mozContacts", false);

View File

@ -108,7 +108,7 @@ void GeckoAppShell::InitStubs(JNIEnv *jEnv) {
jConnectionGetMimeType = getStaticMethod("connectionGetMimeType", "(Ljava/net/URLConnection;)Ljava/lang/String;");
jCreateInputStream = getStaticMethod("createInputStream", "(Ljava/net/URLConnection;)Ljava/io/InputStream;");
jCreateMessageListWrapper = getStaticMethod("createMessageList", "(JJ[Ljava/lang/String;IIZI)V");
jCreateShortcut = getStaticMethod("createShortcut", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
jCreateShortcut = getStaticMethod("createShortcut", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
jDeleteMessageWrapper = getStaticMethod("deleteMessage", "(II)V");
jDisableBatteryNotifications = getStaticMethod("disableBatteryNotifications", "()V");
jDisableNetworkNotifications = getStaticMethod("disableNetworkNotifications", "()V");
@ -348,18 +348,17 @@ void GeckoAppShell::CreateMessageListWrapper(int64_t a0, int64_t a1, jobjectArra
env->PopLocalFrame(nullptr);
}
void GeckoAppShell::CreateShortcut(const nsAString& a0, const nsAString& a1, const nsAString& a2, const nsAString& a3) {
void GeckoAppShell::CreateShortcut(const nsAString& a0, const nsAString& a1, const nsAString& a2) {
JNIEnv *env = AndroidBridge::GetJNIEnv();
if (env->PushLocalFrame(4) != 0) {
if (env->PushLocalFrame(3) != 0) {
AndroidBridge::HandleUncaughtException(env);
MOZ_CRASH("Exception should have caused crash.");
}
jvalue args[4];
jvalue args[3];
args[0].l = AndroidBridge::NewJavaString(env, a0);
args[1].l = AndroidBridge::NewJavaString(env, a1);
args[2].l = AndroidBridge::NewJavaString(env, a2);
args[3].l = AndroidBridge::NewJavaString(env, a3);
env->CallStaticVoidMethodA(mGeckoAppShellClass, jCreateShortcut, args);
AndroidBridge::HandleUncaughtException(env);

View File

@ -30,7 +30,7 @@ public:
static jstring ConnectionGetMimeType(jobject a0);
static jobject CreateInputStream(jobject a0);
static void CreateMessageListWrapper(int64_t a0, int64_t a1, jobjectArray a2, int32_t a3, int32_t a4, bool a5, int32_t a6);
static void CreateShortcut(const nsAString& a0, const nsAString& a1, const nsAString& a2, const nsAString& a3);
static void CreateShortcut(const nsAString& a0, const nsAString& a1, const nsAString& a2);
static void DeleteMessageWrapper(int32_t a0, int32_t a1);
static void DisableBatteryNotifications();
static void DisableNetworkNotifications();