Revert "Remove allow_unsafe_buffers in utf8.{cc,h}"

This reverts commit 01f64ee1db43e59b4e94487ef6958d5d2146256d.

Reason for revert: Hit unreachable code

Bug: 351564777
Original change's description:
> Remove allow_unsafe_buffers in utf8.{cc,h}
>
> Bug: 351564777
> Change-Id: I720b5a9d182f901f5a3b650e343c23b9b00df133
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6592120
> Commit-Queue: Jason Leo <cgqaq@chromium.org>
> Reviewed-by: Kent Tamura <tkent@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#1466839}

Bug: 421058580,420998403,421055122,421047021
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Change-Id: Ib7585756c32154b27c6b173a1d7dd5bda5d31ebc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6602433
Auto-Submit: Jason Leo <cgqaq@chromium.org>
Reviewed-by: David Baron <dbaron@chromium.org>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: David Baron <dbaron@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1467009}
diff --git a/third_party/blink/renderer/platform/wtf/text/atomic_string.cc b/third_party/blink/renderer/platform/wtf/text/atomic_string.cc
index 8f8f94e..f43539b 100644
--- a/third_party/blink/renderer/platform/wtf/text/atomic_string.cc
+++ b/third_party/blink/renderer/platform/wtf/text/atomic_string.cc
@@ -79,7 +79,8 @@
   if (bytes.empty()) {
     return g_empty_atom;
   }
-  return AtomicString(AtomicStringTable::Instance().AddUTF8(bytes));
+  return AtomicString(AtomicStringTable::Instance().AddUTF8(
+      bytes.data(), bytes.data() + bytes.size()));
 }
 
 AtomicString AtomicString::FromUTF8(const char* chars) {
@@ -88,7 +89,7 @@
   if (!*chars)
     return g_empty_atom;
   return AtomicString(AtomicStringTable::Instance().AddUTF8(
-      base::as_byte_span(std::string_view(chars))));
+      reinterpret_cast<const uint8_t*>(chars), nullptr));
 }
 
 AtomicString AtomicString::FromUTF8(std::string_view utf8_string) {
diff --git a/third_party/blink/renderer/platform/wtf/text/atomic_string_table.cc b/third_party/blink/renderer/platform/wtf/text/atomic_string_table.cc
index 47a691b1..682f4b6 100644
--- a/third_party/blink/renderer/platform/wtf/text/atomic_string_table.cc
+++ b/third_party/blink/renderer/platform/wtf/text/atomic_string_table.cc
@@ -10,7 +10,6 @@
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string_table.h"
 
 #include "base/containers/heap_array.h"
-#include "base/containers/span.h"
 #include "base/notreached.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_visitor.h"
 #include "third_party/blink/renderer/platform/wtf/text/convert_to_8bit_hash_reader.h"
@@ -441,18 +440,21 @@
 }
 
 scoped_refptr<StringImpl> AtomicStringTable::AddUTF8(
-    base::span<const uint8_t> characters_span) {
+    const uint8_t* characters_start,
+    const uint8_t* characters_end) {
   bool seen_non_ascii = false;
   bool seen_non_latin1 = false;
-
   unsigned utf16_length = unicode::CalculateStringLengthFromUTF8(
-      characters_span, seen_non_ascii, seen_non_latin1);
+      characters_start, characters_end, seen_non_ascii, seen_non_latin1);
   if (!seen_non_ascii) {
-    return Add(characters_span.data(), utf16_length);
+    return Add((const LChar*)characters_start, utf16_length);
   }
 
   auto utf16_buf = base::HeapArray<UChar>::Uninit(utf16_length);
-  if (unicode::ConvertUTF8ToUTF16(characters_span, utf16_buf).status !=
+  base::span<const uint8_t> source_buffer(
+      reinterpret_cast<const uint8_t*>(characters_start),
+      static_cast<size_t>(characters_end - characters_start));
+  if (unicode::ConvertUTF8ToUTF16(source_buffer, utf16_buf).status !=
       unicode::kConversionOK) {
     NOTREACHED();
   }
diff --git a/third_party/blink/renderer/platform/wtf/text/atomic_string_table.h b/third_party/blink/renderer/platform/wtf/text/atomic_string_table.h
index 356d7b3..58f9e3e 100644
--- a/third_party/blink/renderer/platform/wtf/text/atomic_string_table.h
+++ b/third_party/blink/renderer/platform/wtf/text/atomic_string_table.h
@@ -50,7 +50,9 @@
 
   // Adding UTF8.
   // Returns null if the characters contain invalid utf8 sequences.
-  scoped_refptr<StringImpl> AddUTF8(base::span<const uint8_t> characters_span);
+  // Pass null as `characters_end` to automatically detect the length.
+  scoped_refptr<StringImpl> AddUTF8(const uint8_t* characters_start,
+                                    const uint8_t* characters_end);
 
   // Returned as part of the WeakFind*() APIs below. Represents the result of
   // the non-creating lookup within the AtomicStringTable. See the WeakFind*()
diff --git a/third_party/blink/renderer/platform/wtf/text/utf8.cc b/third_party/blink/renderer/platform/wtf/text/utf8.cc
index 1ed210e..752ed90 100644
--- a/third_party/blink/renderer/platform/wtf/text/utf8.cc
+++ b/third_party/blink/renderer/platform/wtf/text/utf8.cc
@@ -24,6 +24,11 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
 #include "third_party/blink/renderer/platform/wtf/text/utf8.h"
 
 #include <unicode/utf16.h>
@@ -39,7 +44,7 @@
 
 namespace {
 
-inline size_t InlineUTF8SequenceLengthNonASCII(uint8_t b0) {
+inline int InlineUTF8SequenceLengthNonASCII(uint8_t b0) {
   if ((b0 & 0xC0) != 0xC0)
     return 0;
   if ((b0 & 0xE0) == 0xC0)
@@ -51,7 +56,7 @@
   return 0;
 }
 
-inline size_t InlineUTF8SequenceLength(uint8_t b0) {
+inline int InlineUTF8SequenceLength(uint8_t b0) {
   return IsASCII(b0) ? 1 : InlineUTF8SequenceLengthNonASCII(b0);
 }
 
@@ -60,106 +65,104 @@
 // as many entries in this table as there are UTF-8 sequence types.
 // (I.e., one byte sequence, two byte... etc.). Remember that sequences
 // for *legal* UTF-8 will be 4 or fewer bytes total.
-static constexpr std::array<uint8_t, 7> kFirstByteMark = {
-    0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
+const unsigned char kFirstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0,
+                                         0xF0, 0xF8, 0xFC};
 
-ConversionStatus ConvertLatin1ToUTF8Internal(base::span<const LChar>& source,
-                                             base::span<uint8_t>& target) {
+ConversionStatus ConvertLatin1ToUTF8(const LChar** source_start,
+                                     const LChar* source_end,
+                                     char** target_start,
+                                     char* target_end) {
   ConversionStatus status = kConversionOK;
-  size_t source_cursor = 0;
-  size_t target_cursor = 0;
-  size_t target_end = target.size();
-
-  while (source_cursor < source.size()) {
+  const LChar* source = *source_start;
+  char* target = *target_start;
+  while (source < source_end) {
     UChar32 ch;
     uint8_t bytes_to_write = 0;
     const UChar32 kByteMask = 0xBF;
     const UChar32 kByteMark = 0x80;
-    const size_t old_source_cursor = source_cursor;
-    ch = static_cast<UChar32>(source[source_cursor++]);
+    const LChar* old_source =
+        source;  // In case we have to back up because of target overflow.
+    ch = static_cast<UChar32>(*source++);
 
     // Figure out how many bytes the result will require
-    if (ch < static_cast<UChar32>(0x80)) {
+    if (ch < (UChar32)0x80)
       bytes_to_write = 1;
-    } else {
+    else
       bytes_to_write = 2;
-    }
 
-    target_cursor += bytes_to_write;
-    if (target_cursor > target_end) {
-      source_cursor = old_source_cursor;  // Back up source index!
-      target_cursor -= bytes_to_write;
+    target += bytes_to_write;
+    if (target > target_end) {
+      source = old_source;  // Back up source pointer!
+      target -= bytes_to_write;
       status = kTargetExhausted;
       break;
     }
     switch (bytes_to_write) {
       case 2:
-        target[--target_cursor] =
-            static_cast<uint8_t>((ch | kByteMark) & kByteMask);
+        *--target = (char)((ch | kByteMark) & kByteMask);
         ch >>= 6;
         [[fallthrough]];
       case 1:
-        target[--target_cursor] =
-            static_cast<uint8_t>(ch | kFirstByteMark[bytes_to_write]);
+        *--target = (char)(ch | kFirstByteMark[bytes_to_write]);
     }
-    target_cursor += bytes_to_write;
+    target += bytes_to_write;
   }
-  source = source.subspan(source_cursor);
-  target = target.subspan(target_cursor);
+  *source_start = source;
+  *target_start = target;
   return status;
 }
 
-ConversionStatus ConvertUTF16ToUTF8Internal(base::span<const UChar>& source,
-                                            base::span<uint8_t>& target,
-                                            bool strict) {
+ConversionStatus ConvertUTF16ToUTF8(const UChar** source_start,
+                                    const UChar* source_end,
+                                    char** target_start,
+                                    char* target_end,
+                                    bool strict) {
   ConversionStatus status = kConversionOK;
-  size_t source_cursor = 0;
-  size_t target_cursor = 0;
-  size_t source_end = source.size();
-  size_t target_end = target.size();
-
-  while (source_cursor < source_end) {
+  const UChar* source = *source_start;
+  char* target = *target_start;
+  while (source < source_end) {
     UChar32 ch;
     uint8_t bytes_to_write = 0;
     const UChar32 kByteMask = 0xBF;
     const UChar32 kByteMark = 0x80;
-    const size_t old_source_cursor = source_cursor;
-    ch = static_cast<UChar32>(source[source_cursor++]);
+    const UChar* old_source =
+        source;  // In case we have to back up because of target overflow.
+    ch = static_cast<UChar32>(*source++);
     // If we have a surrogate pair, convert to UChar32 first.
     if (ch >= 0xD800 && ch <= 0xDBFF) {
       // If the 16 bits following the high surrogate are in the source buffer...
-      if (source_cursor < source_end) {
-        UChar32 ch2 = static_cast<UChar32>(source[source_cursor]);
+      if (source < source_end) {
+        UChar32 ch2 = static_cast<UChar32>(*source);
         // If it's a low surrogate, convert to UChar32.
         if (ch2 >= 0xDC00 && ch2 <= 0xDFFF) {
           ch = ((ch - 0xD800) << 10) + (ch2 - 0xDC00) + 0x0010000;
-          ++source_cursor;
+          ++source;
         } else if (strict) {  // it's an unpaired high surrogate
-          --source_cursor;    // return to the illegal value itself
+          --source;           // return to the illegal value itself
           status = kSourceIllegal;
           break;
         }
-      } else {  // We don't have the 16 bits following the high surrogate.
-        --source_cursor;  // return to the high surrogate
+      } else {     // We don't have the 16 bits following the high surrogate.
+        --source;  // return to the high surrogate
         status = kSourceExhausted;
         break;
       }
     } else if (strict) {
       // UTF-16 surrogate values are illegal in UTF-32
       if (ch >= 0xDC00 && ch <= 0xDFFF) {
-        --source_cursor;  // return to the illegal value itself
+        --source;  // return to the illegal value itself
         status = kSourceIllegal;
         break;
       }
     }
     // Figure out how many bytes the result will require
-    if (ch < static_cast<UChar32>(0x80)) {
+    if (ch < (UChar32)0x80) {
       bytes_to_write = 1;
-    } else if (ch < static_cast<UChar32>(0x800)) {
+    } else if (ch < (UChar32)0x800) {
       bytes_to_write = 2;
-    } else if (ch < static_cast<UChar32>(0x10000)) {
+    } else if (ch < (UChar32)0x10000) {
       bytes_to_write = 3;
-    } else if (ch < static_cast<UChar32>(0x110000)) {
+    } else if (ch < (UChar32)0x110000) {
       bytes_to_write = 4;
     } else {
       // Surrogate pairs cannot represent codepoints higher than 0x10FFFF, so
@@ -167,66 +170,59 @@
       NOTREACHED();
     }
 
-    target_cursor += bytes_to_write;
-    if (target_cursor > target_end) {
-      source_cursor = old_source_cursor;  // Back up source index!
-      target_cursor -= bytes_to_write;
+    target += bytes_to_write;
+    if (target > target_end) {
+      source = old_source;  // Back up source pointer!
+      target -= bytes_to_write;
       status = kTargetExhausted;
       break;
     }
     switch (bytes_to_write) {
       case 4:
-        target[--target_cursor] =
-            static_cast<uint8_t>((ch | kByteMark) & kByteMask);
+        *--target = (char)((ch | kByteMark) & kByteMask);
         ch >>= 6;
         [[fallthrough]];
       case 3:
-        target[--target_cursor] =
-            static_cast<uint8_t>((ch | kByteMark) & kByteMask);
+        *--target = (char)((ch | kByteMark) & kByteMask);
         ch >>= 6;
         [[fallthrough]];
       case 2:
-        target[--target_cursor] =
-            static_cast<uint8_t>((ch | kByteMark) & kByteMask);
+        *--target = (char)((ch | kByteMark) & kByteMask);
         ch >>= 6;
         [[fallthrough]];
       case 1:
-        target[--target_cursor] =
-            static_cast<uint8_t>(ch | kFirstByteMark[bytes_to_write]);
+        *--target = (char)(ch | kFirstByteMark[bytes_to_write]);
     }
-    target_cursor += bytes_to_write;
+    target += bytes_to_write;
   }
-  source = source.subspan(source_cursor);
-  target = target.subspan(target_cursor);
+  *source_start = source;
+  *target_start = target;
   return status;
 }
 
 // This must be called with the length pre-determined by the first byte.
 // If presented with a length > 4, this returns false.  The Unicode
 // definition of UTF-8 goes up to 4-byte sequences.
-bool IsLegalUTF8(const base::span<const uint8_t> source) {
-  uint8_t a;
-  size_t src_cursor = source.size();
-  switch (source.size()) {
+bool IsLegalUTF8(const unsigned char* source, int length) {
+  unsigned char a;
+  const unsigned char* srcptr = source + length;
+  switch (length) {
     default:
       return false;
     case 4:
-      if ((a = (source[--src_cursor])) < 0x80 || a > 0xBF) {
+      if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
         return false;
-      }
       [[fallthrough]];
     case 3:
-      if ((a = (source[--src_cursor])) < 0x80 || a > 0xBF) {
+      if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
         return false;
-      }
       [[fallthrough]];
     case 2:
-      if ((a = (source[--src_cursor])) > 0xBF) {
+      if ((a = (*--srcptr)) > 0xBF)
         return false;
-      }
 
       // no fall-through in this inner switch
-      switch (source[src_cursor]) {
+      switch (*source) {
         case 0xE0:
           if (a < 0xA0)
             return false;
@@ -250,85 +246,79 @@
       [[fallthrough]];
 
     case 1:
-      if ((a = source[0]) >= 0x80 && a < 0xC2) {
+      if (*source >= 0x80 && *source < 0xC2)
         return false;
-      }
   }
-  if (source[0] > 0xF4) {
+  if (*source > 0xF4)
     return false;
-  }
   return true;
 }
 
 // Magic values subtracted from a buffer value during UTF8 conversion.
 // This table contains as many values as there might be trailing bytes
 // in a UTF-8 sequence.
-static constexpr std::array<UChar32, 6> kOffsetsFromUTF8 = {
-    0x00000000UL,
-    0x00003080UL,
-    0x000E2080UL,
-    0x03C82080UL,
-    static_cast<UChar32>(0xFA082080UL),
-    static_cast<UChar32>(0x82082080UL)};
+const UChar32 kOffsetsFromUTF8[6] = {0x00000000UL,
+                                     0x00003080UL,
+                                     0x000E2080UL,
+                                     0x03C82080UL,
+                                     static_cast<UChar32>(0xFA082080UL),
+                                     static_cast<UChar32>(0x82082080UL)};
 
-inline UChar32 ReadUTF8Sequence(base::span<const uint8_t> source,
-                                size_t length) {
+inline UChar32 ReadUTF8Sequence(const uint8_t*& sequence, unsigned length) {
   UChar32 character = 0;
-  size_t sequence_cursor = 0;
 
   switch (length) {
     case 6:
-      character += source[sequence_cursor++];
+      character += *sequence++;
       character <<= 6;
       [[fallthrough]];
     case 5:
-      character += source[sequence_cursor++];
+      character += *sequence++;
       character <<= 6;
       [[fallthrough]];
     case 4:
-      character += source[sequence_cursor++];
+      character += *sequence++;
       character <<= 6;
       [[fallthrough]];
     case 3:
-      character += source[sequence_cursor++];
+      character += *sequence++;
       character <<= 6;
       [[fallthrough]];
     case 2:
-      character += source[sequence_cursor++];
+      character += *sequence++;
       character <<= 6;
       [[fallthrough]];
     case 1:
-      character += source[sequence_cursor++];
+      character += *sequence++;
   }
 
   return character - kOffsetsFromUTF8[length - 1];
 }
 
-ConversionStatus ConvertUTF8ToUTF16Internal(base::span<const uint8_t>& source,
-                                            base::span<UChar>& target,
-                                            bool strict) {
+ConversionStatus ConvertUTF8ToUTF16(const uint8_t** source_start,
+                                    const uint8_t* source_end,
+                                    UChar** target_start,
+                                    UChar* target_end,
+                                    bool strict) {
   ConversionStatus status = kConversionOK;
-  size_t target_cursor = 0;
-  size_t target_end = target.size();
-
-  while (!source.empty()) {
-    size_t utf8_sequence_length = InlineUTF8SequenceLength(source[0]);
-    if (source.size() < utf8_sequence_length) {
+  const uint8_t* source = *source_start;
+  UChar* target = *target_start;
+  while (source < source_end) {
+    int utf8_sequence_length = InlineUTF8SequenceLength(*source);
+    if (source_end - source < utf8_sequence_length) {
       status = kSourceExhausted;
       break;
     }
     // Do this check whether lenient or strict
-    if (!IsLegalUTF8(source.first(utf8_sequence_length))) {
+    if (!IsLegalUTF8(source, utf8_sequence_length)) {
       status = kSourceIllegal;
       break;
     }
 
-    auto original_source = source;
     UChar32 character = ReadUTF8Sequence(source, utf8_sequence_length);
-    source = source.subspan(utf8_sequence_length);
 
-    if (target_cursor >= target_end) {
-      source = original_source;  // Back up source index!
+    if (target >= target_end) {
+      source -= utf8_sequence_length;  // Back up source pointer!
       status = kTargetExhausted;
       break;
     }
@@ -337,23 +327,23 @@
       // UTF-16 surrogate values are illegal in UTF-32
       if (U_IS_SURROGATE(character)) {
         if (strict) {
-          source = original_source;  // return to the illegal value itself
+          source -= utf8_sequence_length;  // return to the illegal value itself
           status = kSourceIllegal;
           break;
         }
-        target[target_cursor++] = kReplacementCharacter;
+        *target++ = kReplacementCharacter;
       } else {
-        target[target_cursor++] = static_cast<UChar>(character);  // normal case
+        *target++ = static_cast<UChar>(character);  // normal case
       }
     } else if (U_IS_SUPPLEMENTARY(character)) {
       // target is a character in range 0xFFFF - 0x10FFFF
-      if (target_cursor + 1 >= target_end) {
-        source = original_source;  // Back up source index!
+      if (target + 1 >= target_end) {
+        source -= utf8_sequence_length;  // Back up source pointer!
         status = kTargetExhausted;
         break;
       }
-      target[target_cursor++] = U16_LEAD(character);
-      target[target_cursor++] = U16_TRAIL(character);
+      *target++ = U16_LEAD(character);
+      *target++ = U16_TRAIL(character);
     } else {
       // This should never happen; InlineUTF8SequenceLength() can never return
       // a value higher than 4, and a 4-byte UTF-8 sequence can never encode
@@ -361,7 +351,8 @@
       NOTREACHED();
     }
   }
-  target = target.subspan(target_cursor);
+  *source_start = source;
+  *target_start = target;
 
   return status;
 }
@@ -370,12 +361,15 @@
 
 ConversionResult<uint8_t> ConvertLatin1ToUTF8(base::span<const LChar> source,
                                               base::span<uint8_t> target) {
-  auto original_source = source;
-  auto original_target = target;
-  auto status = ConvertLatin1ToUTF8Internal(source, target);
+  const LChar* source_start = source.data();
+  auto target_chars = base::as_writable_chars(target);
+  char* target_start = target_chars.data();
+  auto status =
+      ConvertLatin1ToUTF8(&source_start, source_start + source.size(),
+                          &target_start, target_start + target_chars.size());
   return {
-      original_target.first(original_target.size() - target.size()),
-      original_source.size() - source.size(),
+      target.first(static_cast<size_t>(target_start - target_chars.data())),
+      static_cast<size_t>(source_start - source.data()),
       status,
   };
 }
@@ -383,12 +377,15 @@
 ConversionResult<uint8_t> ConvertUTF16ToUTF8(base::span<const UChar> source,
                                              base::span<uint8_t> target,
                                              bool strict) {
-  auto original_source = source;
-  auto original_target = target;
-  auto status = ConvertUTF16ToUTF8Internal(source, target, strict);
+  const UChar* source_start = source.data();
+  auto target_chars = base::as_writable_chars(target);
+  char* target_start = target_chars.data();
+  auto status = ConvertUTF16ToUTF8(&source_start, source_start + source.size(),
+                                   &target_start,
+                                   target_start + target_chars.size(), strict);
   return {
-      original_target.first(original_target.size() - target.size()),
-      original_source.size() - source.size(),
+      target.first(static_cast<size_t>(target_start - target_chars.data())),
+      static_cast<size_t>(source_start - source.data()),
       status,
   };
 }
@@ -396,53 +393,54 @@
 ConversionResult<UChar> ConvertUTF8ToUTF16(base::span<const uint8_t> source,
                                            base::span<UChar> target,
                                            bool strict) {
-  auto original_source = source;
-  auto original_target = target;
-  auto status = ConvertUTF8ToUTF16Internal(source, target, strict);
+  const uint8_t* source_start = source.data();
+  UChar* target_start = target.data();
+  auto status =
+      ConvertUTF8ToUTF16(&source_start, source_start + source.size(),
+                         &target_start, target_start + target.size(), strict);
   return {
-      original_target.first(original_target.size() - target.size()),
-      original_source.size() - source.size(),
+      target.first(static_cast<size_t>(target_start - target.data())),
+      static_cast<size_t>(source_start - source.data()),
       status,
   };
 }
 
-unsigned CalculateStringLengthFromUTF8(base::span<const uint8_t> data,
+unsigned CalculateStringLengthFromUTF8(const uint8_t* data,
+                                       const uint8_t*& data_end,
                                        bool& seen_non_ascii,
                                        bool& seen_non_latin1) {
   seen_non_ascii = false;
   seen_non_latin1 = false;
-  if (data.empty()) {
+  if (!data)
     return 0;
-  }
 
   unsigned utf16_length = 0;
 
-  size_t data_cursor = 0;
-  size_t data_end = data.size();
-
-  while (data_cursor < data_end) {
-    if (IsASCII(data[data_cursor])) {
-      data_cursor++;
+  while (data < data_end || (!data_end && *data)) {
+    if (IsASCII(*data)) {
+      ++data;
       utf16_length++;
       continue;
     }
 
     seen_non_ascii = true;
-    size_t utf8_sequence_length =
-        InlineUTF8SequenceLengthNonASCII(data[data_cursor]);
+    int utf8_sequence_length = InlineUTF8SequenceLengthNonASCII(*data);
 
-    if (data_end - data_cursor < utf8_sequence_length) {
+    if (!data_end) {
+      for (int i = 1; i < utf8_sequence_length; ++i) {
+        if (!data[i])
+          return 0;
+      }
+    } else if (data_end - data < utf8_sequence_length) {
       return 0;
     }
 
-    if (!IsLegalUTF8(data.subspan(data_cursor, utf8_sequence_length))) {
+    if (!IsLegalUTF8(data, utf8_sequence_length)) {
       return 0;
     }
 
-    UChar32 character =
-        ReadUTF8Sequence(data.subspan(data_cursor), utf8_sequence_length);
+    UChar32 character = ReadUTF8Sequence(data, utf8_sequence_length);
     DCHECK(!IsASCII(character));
-    data_cursor += utf8_sequence_length;
 
     if (character > 0xff) {
       seen_non_latin1 = true;
@@ -460,7 +458,7 @@
     }
   }
 
-  data = data.first(data_cursor);
+  data_end = data;
   return utf16_length;
 }
 
diff --git a/third_party/blink/renderer/platform/wtf/text/utf8.h b/third_party/blink/renderer/platform/wtf/text/utf8.h
index 666d518..c4c33ec 100644
--- a/third_party/blink/renderer/platform/wtf/text/utf8.h
+++ b/third_party/blink/renderer/platform/wtf/text/utf8.h
@@ -81,10 +81,10 @@
     bool strict = true);
 
 // Returns the number of UTF-16 code points.
-WTF_EXPORT unsigned CalculateStringLengthFromUTF8(
-    base::span<const uint8_t> data,
-    bool& seen_non_ascii,
-    bool& seen_non_latin1);
+WTF_EXPORT unsigned CalculateStringLengthFromUTF8(const uint8_t* data,
+                                                  const uint8_t*& data_end,
+                                                  bool& seen_non_ascii,
+                                                  bool& seen_non_latin1);
 
 }  // namespace unicode
 }  // namespace WTF