Bug 1514664 - Implement TextEncoder.encodeInto(). r=emk.
authorHenri Sivonen <hsivonen@hsivonen.fi>
Mon, 17 Dec 2018 18:44:43 +0200
changeset 453411 f7ecf49bb4c0b11031475afa4f3b82c47828b2e7
parent 453410 58fad84cc31ae44e802e742ad9f4eac5bb4284bc
child 453412 3c73631c8237077acb3795e51a2a2ea6016247df
push id111092
push userhsivonen@mozilla.com
push dateFri, 11 Jan 2019 10:35:55 +0000
treeherdermozilla-inbound@3c73631c8237 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemk
bugs1514664
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1514664 - Implement TextEncoder.encodeInto(). r=emk.
dom/encoding/TextEncoder.cpp
dom/encoding/TextEncoder.h
dom/webidl/TextEncoder.webidl
intl/encoding_glue/src/lib.rs
xpcom/string/nsReadableUtils.h
--- a/dom/encoding/TextEncoder.cpp
+++ b/dom/encoding/TextEncoder.cpp
@@ -45,14 +45,25 @@ void TextEncoder::Encode(JSContext* aCx,
   if (!outView) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
   aRetval.set(outView);
 }
 
+void TextEncoder::EncodeInto(const nsAString& aSrc, const Uint8Array& aDst,
+                             TextEncoderEncodeIntoResult& aResult) {
+  aDst.ComputeLengthAndData();
+  size_t read;
+  size_t written;
+  Tie(read, written) = ConvertUTF16toUTF8Partial(
+      aSrc, MakeSpan(reinterpret_cast<char*>(aDst.Data()), aDst.Length()));
+  aResult.mRead.Construct() = read;
+  aResult.mWritten.Construct() = written;
+}
+
 void TextEncoder::GetEncoding(nsAString& aEncoding) {
   aEncoding.AssignLiteral("utf-8");
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/encoding/TextEncoder.h
+++ b/dom/encoding/TextEncoder.h
@@ -55,14 +55,17 @@ class TextEncoder final : public NonRefc
    * @param aObj       the wrapper of the TextEncoder
    * @param aString    utf-16 code units to be encoded.
    * @return JSObject* The Uint8Array wrapped in a JS object.  Returned via
    *                   the aRetval out param.
    */
   void Encode(JSContext* aCx, JS::Handle<JSObject*> aObj,
               const nsAString& aString, JS::MutableHandle<JSObject*> aRetval,
               ErrorResult& aRv);
+
+  void EncodeInto(const nsAString& aSrc, const Uint8Array& aDst,
+                  TextEncoderEncodeIntoResult& aResult);
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_textencoder_h_
--- a/dom/webidl/TextEncoder.webidl
+++ b/dom/webidl/TextEncoder.webidl
@@ -5,23 +5,33 @@
  *
  * The origin of this IDL file is
  * http://encoding.spec.whatwg.org/#interface-textencoder
  *
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+dictionary TextEncoderEncodeIntoResult {
+  unsigned long long read;
+  unsigned long long written;
+};
+
 [Constructor, Exposed=(Window,Worker)]
 interface TextEncoder {
   [Constant]
   readonly attribute DOMString encoding;
   /*
    * This is spec-wise USVString but marking it as
    * DOMString to avoid duplicate work. Since the
    * UTF-16 to UTF-8 converter performs processing
    * that's equivalent to first converting a
    * DOMString to a USVString, let's avoid having
    * the binding code doing it, too.
    */
   [NewObject]
   Uint8Array encode(optional DOMString input = "");
+
+  /*
+   * The same comment about USVString as above applies here.
+   */
+  TextEncoderEncodeIntoResult encodeInto(DOMString source, Uint8Array destination);
 };
--- a/intl/encoding_glue/src/lib.rs
+++ b/intl/encoding_glue/src/lib.rs
@@ -598,16 +598,31 @@ pub unsafe extern "C" fn encoding_mem_co
 ) -> usize {
     encoding_rs::mem::convert_utf16_to_utf8(
         ::std::slice::from_raw_parts(src, src_len),
         ::std::slice::from_raw_parts_mut(dst, dst_len),
     )
 }
 
 #[no_mangle]
+pub unsafe extern "C" fn encoding_mem_convert_utf16_to_utf8_partial(
+    src: *const u16,
+    src_len: *mut usize,
+    dst: *mut u8,
+    dst_len: *mut usize,
+) {
+    let (read, written) = encoding_rs::mem::convert_utf16_to_utf8_partial(
+        ::std::slice::from_raw_parts(src, *src_len),
+        ::std::slice::from_raw_parts_mut(dst, *dst_len),
+    );
+    *src_len = read;
+    *dst_len = written;
+}
+
+#[no_mangle]
 pub unsafe extern "C" fn encoding_mem_convert_utf8_to_utf16(
     src: *const u8,
     src_len: usize,
     dst: *mut u16,
     dst_len: usize,
 ) -> usize {
     encoding_rs::mem::convert_utf8_to_utf16(
         ::std::slice::from_raw_parts(src, src_len),
--- a/xpcom/string/nsReadableUtils.h
+++ b/xpcom/string/nsReadableUtils.h
@@ -10,16 +10,17 @@
 
 /**
  * I guess all the routines in this file are all mis-named.
  * According to our conventions, they should be |NS_xxx|.
  */
 
 #include "mozilla/Assertions.h"
 #include "nsAString.h"
+#include "mozilla/Tuple.h"
 
 #include "nsTArrayForwardDeclare.h"
 
 // Can't include mozilla/Encoding.h here. The implementations are in
 // the encoding_rs and encoding_glue crates.
 extern "C" {
 size_t encoding_utf8_valid_up_to(uint8_t const* buffer, size_t buffer_len);
 
@@ -47,16 +48,20 @@ size_t encoding_mem_convert_utf8_to_lati
                                                  size_t dst_len);
 
 void encoding_mem_convert_latin1_to_utf16(const char* src, size_t src_len,
                                           char16_t* dst, size_t dst_len);
 
 size_t encoding_mem_convert_utf16_to_utf8(const char16_t* src, size_t src_len,
                                           char* dst, size_t dst_len);
 
+void encoding_mem_convert_utf16_to_utf8_partial(const char16_t* src,
+                                                size_t* src_len, char* dst,
+                                                size_t* dst_len);
+
 size_t encoding_mem_convert_utf8_to_utf16(const char* src, size_t src_len,
                                           char16_t* dst, size_t dst_len);
 }
 
 // From the nsstring crate
 extern "C" {
 bool nsstring_fallible_append_utf8_impl(nsAString* aThis, const char* aOther,
                                         size_t aOtherLen, size_t aOldLen);
@@ -135,16 +140,37 @@ inline void ConvertLatin1toUTF16(mozilla
  */
 inline size_t ConvertUTF16toUTF8(mozilla::Span<const char16_t> aSource,
                                  mozilla::Span<char> aDest) {
   return encoding_mem_convert_utf16_to_utf8(
       aSource.Elements(), aSource.Length(), aDest.Elements(), aDest.Length());
 }
 
 /**
+ * Lone surrogates are replaced with the REPLACEMENT CHARACTER.
+ *
+ * The conversion is guaranteed to be complete if the length of aDest is
+ * at least the length of aSource times three.
+ *
+ * The output is always valid UTF-8 ending on scalar value boundary
+ * even in the case of partial conversion.
+ *
+ * Returns the number of code units read and the number of code
+ * units written.
+ */
+inline mozilla::Tuple<size_t, size_t> ConvertUTF16toUTF8Partial(
+    mozilla::Span<const char16_t> aSource, mozilla::Span<char> aDest) {
+  size_t srcLen = aSource.Length();
+  size_t dstLen = aDest.Length();
+  encoding_mem_convert_utf16_to_utf8_partial(aSource.Elements(), &srcLen,
+                                             aDest.Elements(), &dstLen);
+  return mozilla::MakeTuple(srcLen, dstLen);
+}
+
+/**
  * Malformed byte sequences are replaced with the REPLACEMENT CHARACTER.
  *
  * The length of aDest must at least one greater than the length of aSource.
  *
  * Returns the number of code units written.
  */
 inline size_t ConvertUTF8toUTF16(mozilla::Span<const char> aSource,
                                  mozilla::Span<char16_t> aDest) {