diff --git a/Cargo.lock b/Cargo.lock index 5b1ebad204d8..3d3f5c803c48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1303,6 +1303,15 @@ dependencies = [ "unic-langid", ] +[[package]] +name = "fluent-ffi" +version = "0.1.0" +dependencies = [ + "fluent", + "nsstring", + "unic-langid", +] + [[package]] name = "fluent-langneg" version = "0.12.1" @@ -1659,6 +1668,7 @@ dependencies = [ "encoding_glue", "env_logger", "fluent", + "fluent-ffi", "fluent-langneg", "fluent-langneg-ffi", "fog", diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 402b58de9132..82ed33a7e570 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -289,6 +289,11 @@ DOMInterfaces = { 'concrete': True, }, +'FluentResource': { + 'headerFile': 'mozilla/intl/FluentResource.h', + 'nativeType': 'mozilla::intl::FluentResource', +}, + 'FontFaceSet': { 'implicitJSContext': [ 'load' ], }, diff --git a/dom/chrome-webidl/Fluent.webidl b/dom/chrome-webidl/Fluent.webidl new file mode 100644 index 000000000000..df459d27ac9f --- /dev/null +++ b/dom/chrome-webidl/Fluent.webidl @@ -0,0 +1,9 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +[ChromeOnly, Exposed=Window] +interface FluentResource { + constructor(UTF8String source); +}; diff --git a/dom/chrome-webidl/moz.build b/dom/chrome-webidl/moz.build index c182516dbf98..7b73eda834a4 100644 --- a/dom/chrome-webidl/moz.build +++ b/dom/chrome-webidl/moz.build @@ -44,6 +44,7 @@ WEBIDL_FILES = [ 'DominatorTree.webidl', 'DOMLocalization.webidl', 'Flex.webidl', + 'Fluent.webidl', 'HeapSnapshot.webidl', 'InspectorUtils.webidl', 'IteratorResult.webidl', diff --git a/intl/l10n/FluentBindings.h b/intl/l10n/FluentBindings.h new file mode 100644 index 000000000000..f569f02c8c93 --- /dev/null +++ b/intl/l10n/FluentBindings.h @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_intl_l10n_FluentBindings_h +#define mozilla_intl_l10n_FluentBindings_h + +#include "mozilla/intl/fluent_ffi_generated.h" + +#include "mozilla/RefPtr.h" + +namespace mozilla { + +template <> +struct RefPtrTraits { + static void AddRef(const intl::ffi::FluentResource* aPtr) { + intl::ffi::fluent_resource_addref(aPtr); + } + static void Release(const intl::ffi::FluentResource* aPtr) { + intl::ffi::fluent_resource_release(aPtr); + } +}; + +} // namespace mozilla + +#endif diff --git a/intl/l10n/FluentResource.cpp b/intl/l10n/FluentResource.cpp new file mode 100644 index 000000000000..94211a86b859 --- /dev/null +++ b/intl/l10n/FluentResource.cpp @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsContentUtils.h" +#include "FluentResource.h" + +using namespace mozilla::dom; + +namespace mozilla { +namespace intl { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FluentResource, mParent) + +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(FluentResource, AddRef) +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(FluentResource, Release) + +FluentResource::FluentResource(nsISupports* aParent, const nsACString& aSource) + : mParent(aParent), + mRaw(dont_AddRef(ffi::fluent_resource_new(&aSource, &mHasErrors))) { + MOZ_COUNT_CTOR(FluentResource); +} + +already_AddRefed FluentResource::Constructor( + const GlobalObject& aGlobal, const nsACString& aSource) { + RefPtr res = + new FluentResource(aGlobal.GetAsSupports(), aSource); + + if (res->mHasErrors) { + nsContentUtils::LogSimpleConsoleError( + NS_LITERAL_STRING("Errors encountered while parsing Fluent Resource."), + "chrome", false, true /* from chrome context*/); + } + return res.forget(); +} + +JSObject* FluentResource::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) { + return FluentResource_Binding::Wrap(aCx, this, aGivenProto); +} + +FluentResource::~FluentResource() { MOZ_COUNT_DTOR(FluentResource); }; + +} // namespace intl +} // namespace mozilla diff --git a/intl/l10n/FluentResource.h b/intl/l10n/FluentResource.h new file mode 100644 index 000000000000..d51ce9f76c59 --- /dev/null +++ b/intl/l10n/FluentResource.h @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_intl_l10n_FluentResource_h +#define mozilla_intl_l10n_FluentResource_h + +#include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/ErrorResult.h" +#include "nsCycleCollectionParticipant.h" +#include "nsWrapperCache.h" +#include "mozilla/dom/FluentBinding.h" +#include "mozilla/intl/FluentBindings.h" + +namespace mozilla { +namespace intl { + +class FluentResource : public nsWrapperCache { + public: + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(FluentResource) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(FluentResource) + + explicit FluentResource(nsISupports* aParent, const nsACString& aSource); + + static already_AddRefed Constructor( + const dom::GlobalObject& aGlobal, const nsACString& aSource); + + JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + nsISupports* GetParentObject() const { return mParent; } + + const ffi::FluentResource* Raw() const { return mRaw; } + + protected: + virtual ~FluentResource(); + + nsCOMPtr mParent; + const RefPtr mRaw; + bool mHasErrors; +}; + +} // namespace intl +} // namespace mozilla + +#endif diff --git a/intl/l10n/moz.build b/intl/l10n/moz.build index 0f4bc114b969..6518e63cc220 100644 --- a/intl/l10n/moz.build +++ b/intl/l10n/moz.build @@ -5,10 +5,13 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXPORTS.mozilla.intl += [ + 'FluentBindings.h', + 'FluentResource.h', 'Localization.h', ] UNIFIED_SOURCES += [ + 'FluentResource.cpp', 'Localization.cpp', ] @@ -32,6 +35,21 @@ LOCAL_INCLUDES += [ '/dom/base', ] +if CONFIG['COMPILE_ENVIRONMENT']: + GENERATED_FILES += [ + 'fluent_ffi_generated.h', + ] + + EXPORTS.mozilla.intl += [ + '!fluent_ffi_generated.h', + ] + + ffi_generated = GENERATED_FILES['fluent_ffi_generated.h'] + ffi_generated.script = '/build/RunCbindgen.py:generate' + ffi_generated.inputs = [ + '/intl/l10n/rust/fluent-ffi', + ] + XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell.ini'] MOCHITEST_CHROME_MANIFESTS += ['test/mochitest/chrome.ini'] diff --git a/intl/l10n/rust/fluent-ffi/Cargo.toml b/intl/l10n/rust/fluent-ffi/Cargo.toml new file mode 100644 index 000000000000..d91380a5ce02 --- /dev/null +++ b/intl/l10n/rust/fluent-ffi/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "fluent-ffi" +version = "0.1.0" +authors = ["Zibi Braniecki "] +edition = "2018" + +[dependencies] +fluent = { version = "0.11" , features = ["fluent-pseudo"] } +unic-langid = "0.8" +nsstring = { path = "../../../../xpcom/rust/nsstring" } diff --git a/intl/l10n/rust/fluent-ffi/cbindgen.toml b/intl/l10n/rust/fluent-ffi/cbindgen.toml new file mode 100644 index 000000000000..c33a7308e79e --- /dev/null +++ b/intl/l10n/rust/fluent-ffi/cbindgen.toml @@ -0,0 +1,18 @@ +header = """/* 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/. */""" +autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen. See RunCbindgen.py */ +#ifndef mozilla_intl_l10n_FluentBindings_h +#error "Don't include this file directly, instead include FluentBindings.h" +#endif +""" +include_version = true +braces = "SameLine" +line_length = 100 +tab_width = 2 +language = "C++" +namespaces = ["mozilla", "intl", "ffi"] + +[parse] +parse_deps = true +exclude = ["fxhash"] diff --git a/intl/l10n/rust/fluent-ffi/src/lib.rs b/intl/l10n/rust/fluent-ffi/src/lib.rs new file mode 100644 index 000000000000..ea4696c18aa0 --- /dev/null +++ b/intl/l10n/rust/fluent-ffi/src/lib.rs @@ -0,0 +1,3 @@ +mod resource; + +pub use resource::*; diff --git a/intl/l10n/rust/fluent-ffi/src/resource.rs b/intl/l10n/rust/fluent-ffi/src/resource.rs new file mode 100644 index 000000000000..ed205990a698 --- /dev/null +++ b/intl/l10n/rust/fluent-ffi/src/resource.rs @@ -0,0 +1,38 @@ +/* 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/. */ + +pub use fluent::FluentResource; +use nsstring::nsACString; +use std::mem; +use std::rc::Rc; + +#[no_mangle] +pub unsafe extern "C" fn fluent_resource_new( + name: &nsACString, + has_errors: &mut bool, +) -> *const FluentResource { + let res = match FluentResource::try_new(name.to_string()) { + Ok(res) => { + *has_errors = false; + res + } + Err((res, _)) => { + *has_errors = true; + res + } + }; + Rc::into_raw(Rc::new(res)) +} + +#[no_mangle] +pub unsafe extern "C" fn fluent_resource_addref(res: &FluentResource) { + let raw = Rc::from_raw(res); + mem::forget(Rc::clone(&raw)); + mem::forget(raw); +} + +#[no_mangle] +pub unsafe extern "C" fn fluent_resource_release(res: &FluentResource) { + let _ = Rc::from_raw(res); +} diff --git a/toolkit/library/rust/shared/Cargo.toml b/toolkit/library/rust/shared/Cargo.toml index 659ac05d40df..1bfd18ef77c0 100644 --- a/toolkit/library/rust/shared/Cargo.toml +++ b/toolkit/library/rust/shared/Cargo.toml @@ -55,6 +55,7 @@ fluent-langneg = { version = "0.12.1", features = ["cldr"] } fluent-langneg-ffi = { path = "../../../../intl/locale/rust/fluent-langneg-ffi" } fluent = { version = "0.11" , features = ["fluent-pseudo"] } +fluent-ffi = { path = "../../../../intl/l10n/rust/fluent-ffi" } [build-dependencies] rustc_version = "0.2" diff --git a/toolkit/library/rust/shared/lib.rs b/toolkit/library/rust/shared/lib.rs index 438277888454..ceb3b110cc5e 100644 --- a/toolkit/library/rust/shared/lib.rs +++ b/toolkit/library/rust/shared/lib.rs @@ -68,6 +68,7 @@ extern crate fluent_langneg; extern crate fluent_langneg_ffi; extern crate fluent; +extern crate fluent_ffi; #[cfg(feature = "remote")] extern crate remote;