mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1660392 - [l10nregistry] part3: Enable L10nRegistry IPC. r=nika,emilio,platform-i18n-reviewers,dminor
Depends on D102096 Differential Revision: https://phabricator.services.mozilla.com/D105572
This commit is contained in:
parent
f42090a25a
commit
d3b0c08941
@ -91,6 +91,7 @@
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/hal_sandbox/PHalChild.h"
|
||||
#include "mozilla/intl/L10nRegistry.h"
|
||||
#include "mozilla/intl/LocaleService.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/Endpoint.h"
|
||||
@ -1330,11 +1331,14 @@ void ContentChild::InitXPCOM(
|
||||
|
||||
RecvSetOffline(aXPCOMInit.isOffline());
|
||||
RecvSetConnectivity(aXPCOMInit.isConnected());
|
||||
// XXX(Bug 1633675) The LocaleService calls could also move the arguments.
|
||||
|
||||
LocaleService::GetInstance()->AssignAppLocales(aXPCOMInit.appLocales());
|
||||
LocaleService::GetInstance()->AssignRequestedLocales(
|
||||
aXPCOMInit.requestedLocales());
|
||||
|
||||
L10nRegistry::RegisterFileSourcesFromParentProcess(
|
||||
aXPCOMInit.l10nFileSources());
|
||||
|
||||
RecvSetCaptivePortalState(aXPCOMInit.captivePortalState());
|
||||
RecvBidiKeyboardNotify(aXPCOMInit.isLangRTL(),
|
||||
aXPCOMInit.haveBidiKeyboards());
|
||||
@ -2355,6 +2359,12 @@ mozilla::ipc::IPCResult ContentChild::RecvRegisterStringBundles(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvUpdateL10nFileSources(
|
||||
nsTArray<mozilla::dom::L10nFileSourceDescriptor>&& aDescriptors) {
|
||||
L10nRegistry::RegisterFileSourcesFromParentProcess(aDescriptors);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvUpdateSharedData(
|
||||
const FileDescriptor& aMapFile, const uint32_t& aMapSize,
|
||||
nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys) {
|
||||
|
@ -331,6 +331,9 @@ class ContentChild final : public PContentChild,
|
||||
mozilla::ipc::IPCResult RecvRegisterStringBundles(
|
||||
nsTArray<StringBundleDescriptor>&& stringBundles);
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateL10nFileSources(
|
||||
nsTArray<L10nFileSourceDescriptor>&& aDescriptors);
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateSharedData(
|
||||
const FileDescriptor& aMapFile, const uint32_t& aMapSize,
|
||||
nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys);
|
||||
|
@ -135,6 +135,7 @@
|
||||
#include "mozilla/gfx/GPUProcessManager.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/hal_sandbox/PHalParent.h"
|
||||
#include "mozilla/intl/L10nRegistry.h"
|
||||
#include "mozilla/intl/LocaleService.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
@ -2875,6 +2876,9 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
|
||||
LocaleService::GetInstance()->GetRequestedLocales(
|
||||
xpcomInit.requestedLocales());
|
||||
|
||||
L10nRegistry::GetParentProcessFileSourceDescriptors(
|
||||
xpcomInit.l10nFileSources());
|
||||
|
||||
nsCOMPtr<nsIClipboard> clipboard(
|
||||
do_GetService("@mozilla.org/widget/clipboard;1"));
|
||||
MOZ_ASSERT(clipboard, "No clipboard?");
|
||||
|
@ -325,6 +325,13 @@ struct GMPCapabilityData
|
||||
GMPAPITags[] capabilities;
|
||||
};
|
||||
|
||||
struct L10nFileSourceDescriptor {
|
||||
nsCString name;
|
||||
nsCString[] locales;
|
||||
nsCString prePath;
|
||||
nsCString[] index;
|
||||
};
|
||||
|
||||
struct XPCOMInitData
|
||||
{
|
||||
bool isOffline;
|
||||
@ -341,6 +348,7 @@ struct XPCOMInitData
|
||||
GfxInfoFeatureStatus[] gfxFeatureStatus;
|
||||
nsCString[] appLocales;
|
||||
nsCString[] requestedLocales;
|
||||
L10nFileSourceDescriptor[] l10nFileSources;
|
||||
DynamicScalarDefinition[] dynamicScalarDefs;
|
||||
SystemParameterKVPair[] systemParameters;
|
||||
};
|
||||
@ -650,6 +658,8 @@ child:
|
||||
async UpdateAppLocales(nsCString[] appLocales);
|
||||
async UpdateRequestedLocales(nsCString[] requestedLocales);
|
||||
|
||||
async UpdateL10nFileSources(L10nFileSourceDescriptor[] sources);
|
||||
|
||||
async RegisterStringBundles(StringBundleDescriptor[] stringBundles);
|
||||
|
||||
async UpdateSharedData(FileDescriptor mapFile, uint32_t aSize,
|
||||
|
@ -11,9 +11,14 @@
|
||||
#include "nsString.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "FluentResource.h"
|
||||
#include "nsICategoryManager.h"
|
||||
#include "mozilla/SimpleEnumerator.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace mozilla::intl {
|
||||
@ -227,6 +232,44 @@ already_AddRefed<FluentBundleAsyncIterator> L10nRegistry::GenerateBundles(
|
||||
return do_AddRef(new FluentBundleAsyncIterator(mGlobal, std::move(iter)));
|
||||
}
|
||||
|
||||
/* static */
|
||||
void L10nRegistry::GetParentProcessFileSourceDescriptors(
|
||||
nsTArray<L10nFileSourceDescriptor>& aRetVal) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
nsTArray<ffi::L10nFileSourceDescriptor> sources;
|
||||
ffi::l10nregistry_get_parent_process_sources(&sources);
|
||||
for (const auto& source : sources) {
|
||||
auto descriptor = aRetVal.AppendElement();
|
||||
descriptor->name() = source.name;
|
||||
descriptor->locales().AppendElements(std::move(source.locales));
|
||||
descriptor->prePath() = source.pre_path;
|
||||
descriptor->index().AppendElements(std::move(source.index));
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void L10nRegistry::RegisterFileSourcesFromParentProcess(
|
||||
const nsTArray<L10nFileSourceDescriptor>& aDescriptors) {
|
||||
// This means that in content processes the L10nRegistry
|
||||
// service instance is created eagerly, not lazily.
|
||||
// It is necessary so that the instance can store the sources
|
||||
// provided in the IPC init, which, in turn, is necessary
|
||||
// for the service to be avialable for sync bundle generation.
|
||||
//
|
||||
// L10nRegistry is lightweight and performs no operations, so
|
||||
// we believe this behavior to be acceptable.
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
nsTArray<ffi::L10nFileSourceDescriptor> sources;
|
||||
for (const auto& desc : aDescriptors) {
|
||||
auto source = sources.AppendElement();
|
||||
source->name = desc.name();
|
||||
source->locales.AppendElements(desc.locales());
|
||||
source->pre_path = desc.prePath();
|
||||
source->index.AppendElements(desc.index());
|
||||
}
|
||||
ffi::l10nregistry_register_parent_process_sources(&sources);
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult L10nRegistry::Load(const nsACString& aPath,
|
||||
nsIStreamLoaderObserver* aObserver) {
|
||||
@ -324,6 +367,18 @@ nsresult L10nRegistryLoadSync(const nsACString* aPath, void** aData,
|
||||
return mozilla::intl::L10nRegistry::LoadSync(*aPath, aData, aSize);
|
||||
}
|
||||
|
||||
void L10nRegistrySendUpdateL10nFileSources() {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
nsTArray<L10nFileSourceDescriptor> sources;
|
||||
L10nRegistry::GetParentProcessFileSourceDescriptors(sources);
|
||||
|
||||
nsTArray<ContentParent*> parents;
|
||||
ContentParent::GetAll(parents);
|
||||
for (ContentParent* parent : parents) {
|
||||
Unused << parent->SendUpdateL10nFileSources(sources);
|
||||
}
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
} // namespace mozilla::intl
|
||||
|
@ -12,10 +12,15 @@
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/dom/L10nRegistryBinding.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/intl/RegistryBindings.h"
|
||||
#include "mozilla/intl/FluentBindings.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla::dom {
|
||||
class L10nFileSourceDescriptor;
|
||||
}
|
||||
|
||||
namespace mozilla::intl {
|
||||
|
||||
class FluentBundleAsyncIterator final : public nsWrapperCache {
|
||||
@ -78,6 +83,11 @@ class L10nRegistry final : public nsWrapperCache {
|
||||
static already_AddRefed<L10nRegistry> GetInstance(
|
||||
const dom::GlobalObject& aGlobal);
|
||||
|
||||
static void GetParentProcessFileSourceDescriptors(
|
||||
nsTArray<dom::L10nFileSourceDescriptor>& aRetVal);
|
||||
static void RegisterFileSourcesFromParentProcess(
|
||||
const nsTArray<dom::L10nFileSourceDescriptor>& aDescriptors);
|
||||
|
||||
static nsresult Load(const nsACString& aPath,
|
||||
nsIStreamLoaderObserver* aObserver);
|
||||
static nsresult LoadSync(const nsACString& aPath, void** aData,
|
||||
|
@ -41,9 +41,7 @@ XPIDL_SOURCES += [
|
||||
|
||||
XPIDL_MODULE = "locale"
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
"/dom/base",
|
||||
]
|
||||
include("/ipc/chromium/chromium-config.mozbuild")
|
||||
|
||||
USE_LIBS += ["intlcomponents"]
|
||||
|
||||
|
@ -7,3 +7,4 @@ mod fetcher;
|
||||
pub mod load;
|
||||
mod registry;
|
||||
mod source;
|
||||
mod xpcom_utils;
|
||||
|
@ -8,7 +8,7 @@ use std::mem;
|
||||
use std::rc::Rc;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::{env::GeckoEnvironment, fetcher::GeckoFileFetcher};
|
||||
use crate::{env::GeckoEnvironment, fetcher::GeckoFileFetcher, xpcom_utils::is_parent_process};
|
||||
use fluent_fallback::generator::BundleGenerator;
|
||||
use futures_channel::mpsc::{unbounded, UnboundedSender};
|
||||
pub use l10nregistry::{
|
||||
@ -40,30 +40,28 @@ impl BundleAdapter for GeckoBundleAdapter {
|
||||
}
|
||||
|
||||
thread_local!(static L10N_REGISTRY: Rc<GeckoL10nRegistry> = {
|
||||
let env = GeckoEnvironment;
|
||||
let mut reg = L10nRegistry::with_provider(env);
|
||||
let sources = if is_parent_process() {
|
||||
let packaged_locales = get_packaged_locales();
|
||||
let entries = get_l10n_registry_category_entries();
|
||||
|
||||
let packaged_locales = vec!["en-US".parse().unwrap()];
|
||||
Some(entries
|
||||
.into_iter()
|
||||
.map(|entry| {
|
||||
FileSource::new(
|
||||
entry.entry.to_string(),
|
||||
packaged_locales.clone(),
|
||||
entry.value.to_string(),
|
||||
Default::default(),
|
||||
GeckoFileFetcher,
|
||||
)
|
||||
})
|
||||
.collect())
|
||||
|
||||
let toolkit_fs = FileSource::new(
|
||||
"0-toolkit".to_owned(),
|
||||
packaged_locales.clone(),
|
||||
"resource://gre/localization/{locale}/".to_owned(),
|
||||
Default::default(),
|
||||
GeckoFileFetcher,
|
||||
);
|
||||
let browser_fs = FileSource::new(
|
||||
"5-browser".to_owned(),
|
||||
packaged_locales,
|
||||
"resource://app/localization/{locale}/".to_owned(),
|
||||
Default::default(),
|
||||
GeckoFileFetcher,
|
||||
);
|
||||
let _ = reg.set_adapt_bundle(GeckoBundleAdapter::default()).report_error();
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let _ = reg.register_sources(vec![toolkit_fs, browser_fs]).report_error();
|
||||
|
||||
Rc::new(reg)
|
||||
create_l10n_registry(sources)
|
||||
});
|
||||
|
||||
pub type GeckoL10nRegistry = L10nRegistry<GeckoEnvironment, GeckoBundleAdapter>;
|
||||
@ -82,6 +80,79 @@ impl<V> GeckoReportError<V, L10nRegistrySetupError> for Result<V, L10nRegistrySe
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct L10nFileSourceDescriptor {
|
||||
name: nsCString,
|
||||
locales: ThinVec<nsCString>,
|
||||
pre_path: nsCString,
|
||||
index: ThinVec<nsCString>,
|
||||
}
|
||||
|
||||
fn get_l10n_registry_category_entries() -> Vec<crate::xpcom_utils::CategoryEntry> {
|
||||
crate::xpcom_utils::get_category_entries(&nsCString::from("l10n-registry")).unwrap_or_default()
|
||||
}
|
||||
|
||||
fn get_packaged_locales() -> Vec<LanguageIdentifier> {
|
||||
crate::xpcom_utils::get_packaged_locales()
|
||||
.map(|locales| {
|
||||
locales
|
||||
.into_iter()
|
||||
.map(|s| s.to_utf8().parse().expect("Failed to parse locale."))
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn create_l10n_registry(sources: Option<Vec<FileSource>>) -> Rc<GeckoL10nRegistry> {
|
||||
let env = GeckoEnvironment;
|
||||
let mut reg = L10nRegistry::with_provider(env);
|
||||
|
||||
reg.set_adapt_bundle(GeckoBundleAdapter::default())
|
||||
.expect("Failed to set bundle adaptation closure.");
|
||||
|
||||
if let Some(sources) = sources {
|
||||
reg.register_sources(sources)
|
||||
.expect("Failed to register sources.");
|
||||
}
|
||||
Rc::new(reg)
|
||||
}
|
||||
|
||||
pub fn set_l10n_registry(new_sources: &ThinVec<L10nFileSourceDescriptor>) {
|
||||
L10N_REGISTRY.with(|reg| {
|
||||
let new_source_names: Vec<_> = new_sources
|
||||
.iter()
|
||||
.map(|d| d.name.to_utf8().to_string())
|
||||
.collect();
|
||||
let old_sources = reg.get_source_names().unwrap();
|
||||
|
||||
let mut sources_to_be_removed = vec![];
|
||||
for name in &old_sources {
|
||||
if !new_source_names.contains(&name) {
|
||||
sources_to_be_removed.push(name);
|
||||
}
|
||||
}
|
||||
reg.remove_sources(sources_to_be_removed).unwrap();
|
||||
|
||||
let mut add_sources = vec![];
|
||||
for desc in new_sources {
|
||||
if !old_sources.contains(&desc.name.to_string()) {
|
||||
add_sources.push(FileSource::new(
|
||||
desc.name.to_string(),
|
||||
desc.locales
|
||||
.iter()
|
||||
.map(|s| s.to_utf8().parse().unwrap())
|
||||
.collect(),
|
||||
desc.pre_path.to_string(),
|
||||
Default::default(),
|
||||
GeckoFileFetcher,
|
||||
));
|
||||
}
|
||||
}
|
||||
reg.register_sources(add_sources).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
pub fn get_l10n_registry() -> Rc<GeckoL10nRegistry> {
|
||||
L10N_REGISTRY.with(|reg| reg.clone())
|
||||
}
|
||||
@ -109,6 +180,51 @@ pub extern "C" fn l10nregistry_instance_get() -> *const GeckoL10nRegistry {
|
||||
Rc::into_raw(reg)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn l10nregistry_get_parent_process_sources(
|
||||
sources: &mut ThinVec<L10nFileSourceDescriptor>,
|
||||
) {
|
||||
debug_assert!(
|
||||
is_parent_process(),
|
||||
"This should be called only in parent process."
|
||||
);
|
||||
|
||||
// If at the point when the first content process is being initialized, the parent
|
||||
// process `L10nRegistryService` has not been initialized yet, this will trigger it.
|
||||
//
|
||||
// This is architecturally imperfect, but acceptable for simplicity reasons because
|
||||
// `L10nRegistry` instance is cheap and mainly servers as a store of state.
|
||||
let reg = get_l10n_registry();
|
||||
for name in reg.get_source_names().unwrap() {
|
||||
let source = reg.get_source(&name).unwrap().unwrap();
|
||||
let descriptor = L10nFileSourceDescriptor {
|
||||
name: source.name.as_str().into(),
|
||||
locales: source
|
||||
.locales()
|
||||
.iter()
|
||||
.map(|l| l.to_string().into())
|
||||
.collect(),
|
||||
pre_path: source.pre_path.as_str().into(),
|
||||
index: source
|
||||
.get_index()
|
||||
.map(|index| index.into_iter().map(|s| s.into()).collect())
|
||||
.unwrap_or_default(),
|
||||
};
|
||||
sources.push(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn l10nregistry_register_parent_process_sources(
|
||||
sources: &ThinVec<L10nFileSourceDescriptor>,
|
||||
) {
|
||||
debug_assert!(
|
||||
!is_parent_process(),
|
||||
"This should be called only in content process."
|
||||
);
|
||||
set_l10n_registry(sources);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn l10nregistry_addref(reg: &GeckoL10nRegistry) {
|
||||
let raw = Rc::from_raw(reg);
|
||||
@ -131,6 +247,20 @@ pub extern "C" fn l10nregistry_get_available_locales(
|
||||
}
|
||||
}
|
||||
|
||||
fn broadcast_settings_if_parent(reg: &GeckoL10nRegistry) {
|
||||
if !is_parent_process() {
|
||||
return;
|
||||
}
|
||||
|
||||
L10N_REGISTRY.with(|reg_service| {
|
||||
if std::ptr::eq(Rc::as_ptr(reg_service), reg) {
|
||||
unsafe {
|
||||
L10nRegistrySendUpdateL10nFileSources();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn l10nregistry_register_sources(
|
||||
reg: &GeckoL10nRegistry,
|
||||
@ -139,6 +269,8 @@ pub extern "C" fn l10nregistry_register_sources(
|
||||
let _ = reg
|
||||
.register_sources(sources.iter().map(|&s| s.clone()).collect())
|
||||
.report_error();
|
||||
|
||||
broadcast_settings_if_parent(reg);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -149,6 +281,7 @@ pub extern "C" fn l10nregistry_update_sources(
|
||||
let _ = reg
|
||||
.update_sources(sources.iter().map(|&s| s.clone()).collect())
|
||||
.report_error();
|
||||
broadcast_settings_if_parent(reg);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -163,6 +296,7 @@ pub unsafe extern "C" fn l10nregistry_remove_sources(
|
||||
|
||||
let sources = std::slice::from_raw_parts(sources_elements, sources_length);
|
||||
let _ = reg.remove_sources(sources.to_vec()).report_error();
|
||||
broadcast_settings_if_parent(reg);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -204,6 +338,8 @@ pub extern "C" fn l10nregistry_get_source(
|
||||
#[no_mangle]
|
||||
pub extern "C" fn l10nregistry_clear_sources(reg: &GeckoL10nRegistry) {
|
||||
let _ = reg.clear_sources().report_error();
|
||||
|
||||
broadcast_settings_if_parent(reg);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -337,3 +473,7 @@ pub extern "C" fn fluent_bundle_async_iterator_next(
|
||||
callback(promise, std::ptr::null_mut());
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn L10nRegistrySendUpdateL10nFileSources();
|
||||
}
|
||||
|
104
intl/l10n/rust/l10nregistry-ffi/src/xpcom_utils.rs
Normal file
104
intl/l10n/rust/l10nregistry-ffi/src/xpcom_utils.rs
Normal file
@ -0,0 +1,104 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use cstr::cstr;
|
||||
use nsstring::{nsACString, nsCString};
|
||||
use std::marker::PhantomData;
|
||||
use thin_vec::ThinVec;
|
||||
use xpcom::{
|
||||
get_service, getter_addrefs,
|
||||
interfaces::{
|
||||
mozILocaleService, nsICategoryEntry, nsICategoryManager, nsISimpleEnumerator, nsIXULRuntime,
|
||||
},
|
||||
RefPtr, XpCom,
|
||||
};
|
||||
|
||||
pub struct IterSimpleEnumerator<T> {
|
||||
enumerator: RefPtr<nsISimpleEnumerator>,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: XpCom> IterSimpleEnumerator<T> {
|
||||
/// Convert a `nsISimpleEnumerator` into a rust `Iterator` type.
|
||||
pub fn new(enumerator: RefPtr<nsISimpleEnumerator>) -> Self {
|
||||
IterSimpleEnumerator {
|
||||
enumerator,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: XpCom + 'static> Iterator for IterSimpleEnumerator<T> {
|
||||
type Item = RefPtr<T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut more = false;
|
||||
unsafe {
|
||||
self.enumerator
|
||||
.HasMoreElements(&mut more)
|
||||
.to_result()
|
||||
.ok()?
|
||||
}
|
||||
if !more {
|
||||
return None;
|
||||
}
|
||||
|
||||
let element = getter_addrefs(|p| unsafe { self.enumerator.GetNext(p) }).ok()?;
|
||||
element.query_interface::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
fn process_type() -> u32 {
|
||||
if let Some(appinfo) = xpcom::services::get_XULRuntime() {
|
||||
let mut process_type = nsIXULRuntime::PROCESS_TYPE_DEFAULT as u32;
|
||||
if unsafe { appinfo.GetProcessType(&mut process_type).succeeded() } {
|
||||
return process_type;
|
||||
}
|
||||
}
|
||||
nsIXULRuntime::PROCESS_TYPE_DEFAULT as u32
|
||||
}
|
||||
|
||||
pub fn is_parent_process() -> bool {
|
||||
process_type() == nsIXULRuntime::PROCESS_TYPE_DEFAULT as u32
|
||||
}
|
||||
|
||||
pub fn get_packaged_locales() -> Option<ThinVec<nsCString>> {
|
||||
let locale_service =
|
||||
get_service::<mozILocaleService>(cstr!("@mozilla.org/intl/localeservice;1"))?;
|
||||
let mut locales = ThinVec::new();
|
||||
unsafe {
|
||||
locale_service
|
||||
.GetPackagedLocales(&mut locales)
|
||||
.to_result()
|
||||
.ok()?;
|
||||
}
|
||||
Some(locales)
|
||||
}
|
||||
|
||||
pub struct CategoryEntry {
|
||||
pub entry: nsCString,
|
||||
pub value: nsCString,
|
||||
}
|
||||
|
||||
pub fn get_category_entries(category: &nsACString) -> Option<Vec<CategoryEntry>> {
|
||||
let category_manager =
|
||||
get_service::<nsICategoryManager>(cstr!("@mozilla.org/categorymanager;1"))?;
|
||||
|
||||
let enumerator =
|
||||
getter_addrefs(|p| unsafe { category_manager.EnumerateCategory(category, p) }).ok()?;
|
||||
|
||||
Some(
|
||||
IterSimpleEnumerator::<nsICategoryEntry>::new(enumerator)
|
||||
.map(|ientry| {
|
||||
let mut entry = nsCString::new();
|
||||
let mut value = nsCString::new();
|
||||
unsafe {
|
||||
let _ = ientry.GetEntry(&mut *entry);
|
||||
let _ = ientry.GetValue(&mut *value);
|
||||
}
|
||||
CategoryEntry { entry, value }
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user