Long overdue update of string types in CSS.

First step towards writing unsafe string annotations is to stop
using unsafe forms.

-- introduce CFX_CSSNumber apart from CFX_CSSNumberValue.
-- avoid discrete pointer/length pairs.
-- use std::optional<> for results.

Change-Id: I338387acfeec26fcc233600394409d7efea3c915
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/117011
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
diff --git a/core/fxcrt/css/cfx_cssdata.cpp b/core/fxcrt/css/cfx_cssdata.cpp
index 0659a59..40aacf3 100644
--- a/core/fxcrt/css/cfx_cssdata.cpp
+++ b/core/fxcrt/css/cfx_cssdata.cpp
@@ -31,14 +31,14 @@
 #undef CSS_PROP_VALUE____
 
 const CFX_CSSData::LengthUnit kLengthUnitTable[] = {
-    {L"cm", CFX_CSSNumberValue::Unit::kCentiMeters},
-    {L"em", CFX_CSSNumberValue::Unit::kEMS},
-    {L"ex", CFX_CSSNumberValue::Unit::kEXS},
-    {L"in", CFX_CSSNumberValue::Unit::kInches},
-    {L"mm", CFX_CSSNumberValue::Unit::kMilliMeters},
-    {L"pc", CFX_CSSNumberValue::Unit::kPicas},
-    {L"pt", CFX_CSSNumberValue::Unit::kPoints},
-    {L"px", CFX_CSSNumberValue::Unit::kPixels},
+    {L"cm", CFX_CSSNumber::Unit::kCentiMeters},
+    {L"em", CFX_CSSNumber::Unit::kEMS},
+    {L"ex", CFX_CSSNumber::Unit::kEXS},
+    {L"in", CFX_CSSNumber::Unit::kInches},
+    {L"mm", CFX_CSSNumber::Unit::kMilliMeters},
+    {L"pc", CFX_CSSNumber::Unit::kPicas},
+    {L"pt", CFX_CSSNumber::Unit::kPoints},
+    {L"px", CFX_CSSNumber::Unit::kPixels},
 };
 
 // 16 colours from CSS 2.0 + alternate spelling of grey/gray.
diff --git a/core/fxcrt/css/cfx_cssdata.h b/core/fxcrt/css/cfx_cssdata.h
index c129cfe..af21c5a 100644
--- a/core/fxcrt/css/cfx_cssdata.h
+++ b/core/fxcrt/css/cfx_cssdata.h
@@ -28,7 +28,7 @@
 
   struct LengthUnit {
     const wchar_t* value;  // Raw, POD struct.
-    CFX_CSSNumberValue::Unit type;
+    CFX_CSSNumber::Unit type;
   };
 
   struct Color {
diff --git a/core/fxcrt/css/cfx_cssdeclaration.cpp b/core/fxcrt/css/cfx_cssdeclaration.cpp
index 7077bac..87aee28 100644
--- a/core/fxcrt/css/cfx_cssdeclaration.cpp
+++ b/core/fxcrt/css/cfx_cssdeclaration.cpp
@@ -30,115 +30,96 @@
   return (FXSYS_HexCharToInt(hexHigh) << 4) + FXSYS_HexCharToInt(hexLow);
 }
 
-bool ParseCSSNumber(const wchar_t* pszValue,
-                    size_t nValueLen,
-                    float* pValue,
-                    CFX_CSSNumberValue::Unit* pOutUnit) {
-  DCHECK(pszValue);
-  DCHECK_NE(nValueLen, 0);
+std::optional<CFX_CSSNumber> ParseCSSNumber(WideStringView view) {
+  DCHECK(!view.IsEmpty());
 
   size_t nUsedLen = 0;
-  *pValue = FXSYS_wcstof(pszValue, nValueLen, &nUsedLen);
-  if (nUsedLen == 0 || !isfinite(*pValue))
-    return false;
-
-  nValueLen -= nUsedLen;
-  pszValue += nUsedLen;
-  *pOutUnit = CFX_CSSNumberValue::Unit::kNumber;
-  if (nValueLen >= 1 && *pszValue == '%') {
-    *pOutUnit = CFX_CSSNumberValue::Unit::kPercent;
-  } else if (nValueLen == 2) {
-    const CFX_CSSData::LengthUnit* pUnit =
-        CFX_CSSData::GetLengthUnitByName(WideStringView(pszValue, 2));
-    if (pUnit)
-      *pOutUnit = pUnit->type;
+  float value =
+      FXSYS_wcstof(view.unterminated_c_str(), view.GetLength(), &nUsedLen);
+  if (nUsedLen == 0 || !isfinite(value)) {
+    return std::nullopt;
   }
-  return true;
+  view = view.Substr(nUsedLen);
+  if (view.Front() == '%') {  // NOTE: empty-tolerant Front().
+    return CFX_CSSNumber{CFX_CSSNumber::Unit::kPercent, value};
+  }
+  if (view.GetLength() == 2) {
+    const CFX_CSSData::LengthUnit* pUnit =
+        CFX_CSSData::GetLengthUnitByName(view.First(2));
+    if (pUnit) {
+      return CFX_CSSNumber{pUnit->type, value};
+    }
+  }
+  return CFX_CSSNumber{CFX_CSSNumber::Unit::kNumber, value};
 }
 
 }  // namespace
 
 // static
-bool CFX_CSSDeclaration::ParseCSSString(const wchar_t* pszValue,
-                                        size_t nValueLen,
-                                        size_t* nOffset,
-                                        size_t* nLength) {
-  DCHECK(pszValue);
-  DCHECK_NE(nValueLen, 0);
-
-  *nOffset = 0;
-  *nLength = nValueLen;
-  if (nValueLen >= 2) {
-    wchar_t first = pszValue[0];
-    wchar_t last = pszValue[nValueLen - 1];
+std::optional<WideStringView> CFX_CSSDeclaration::ParseCSSString(
+    WideStringView value) {
+  if (value.GetLength() >= 2) {
+    wchar_t first = value.Front();
+    wchar_t last = value.Back();
     if ((first == '\"' && last == '\"') || (first == '\'' && last == '\'')) {
-      *nOffset = 1;
-      *nLength -= 2;
+      value = value.Substr(1, value.GetLength() - 2);
     }
   }
-  return nValueLen > 0;
+  if (value.IsEmpty()) {
+    return std::nullopt;
+  }
+  return value;
 }
 
 // static.
-bool CFX_CSSDeclaration::ParseCSSColor(const wchar_t* pszValue,
-                                       size_t nValueLen,
-                                       FX_ARGB* dwColor) {
-  DCHECK_NE(nValueLen, 0);
-  DCHECK(dwColor);
-
-  if (*pszValue == '#') {
-    switch (nValueLen) {
+std::optional<FX_ARGB> CFX_CSSDeclaration::ParseCSSColor(WideStringView value) {
+  if (value.Front() == '#') {  // Note: empty-tolerant Front().
+    switch (value.GetLength()) {
       case 4: {
-        uint8_t red = Hex2Dec((uint8_t)pszValue[1], (uint8_t)pszValue[1]);
-        uint8_t green = Hex2Dec((uint8_t)pszValue[2], (uint8_t)pszValue[2]);
-        uint8_t blue = Hex2Dec((uint8_t)pszValue[3], (uint8_t)pszValue[3]);
-        *dwColor = ArgbEncode(255, red, green, blue);
-        return true;
+        uint8_t red = Hex2Dec((uint8_t)value[1], (uint8_t)value[1]);
+        uint8_t green = Hex2Dec((uint8_t)value[2], (uint8_t)value[2]);
+        uint8_t blue = Hex2Dec((uint8_t)value[3], (uint8_t)value[3]);
+        return ArgbEncode(255, red, green, blue);
       }
       case 7: {
-        uint8_t red = Hex2Dec((uint8_t)pszValue[1], (uint8_t)pszValue[2]);
-        uint8_t green = Hex2Dec((uint8_t)pszValue[3], (uint8_t)pszValue[4]);
-        uint8_t blue = Hex2Dec((uint8_t)pszValue[5], (uint8_t)pszValue[6]);
-        *dwColor = ArgbEncode(255, red, green, blue);
-        return true;
+        uint8_t red = Hex2Dec((uint8_t)value[1], (uint8_t)value[2]);
+        uint8_t green = Hex2Dec((uint8_t)value[3], (uint8_t)value[4]);
+        uint8_t blue = Hex2Dec((uint8_t)value[5], (uint8_t)value[6]);
+        return ArgbEncode(255, red, green, blue);
       }
       default:
-        return false;
+        return std::nullopt;
     }
   }
 
-  if (nValueLen >= 10) {
-    if (pszValue[nValueLen - 1] != ')' || FXSYS_wcsnicmp(L"rgb(", pszValue, 4))
-      return false;
-
+  if (value.GetLength() >= 10) {
+    if (!value.First(4).EqualsASCIINoCase("rgb(") || value.Back() != ')') {
+      return std::nullopt;
+    }
     uint8_t rgb[3] = {0};
-    float fValue;
-    CFX_CSSValue::PrimitiveType eType;
-    CFX_CSSValueListParser list(pszValue + 4, nValueLen - 5, ',');
+    CFX_CSSValueListParser list(value.Substr(4, value.GetLength() - 5), ',');
     for (int32_t i = 0; i < 3; ++i) {
-      if (!list.NextValue(&eType, &pszValue, &nValueLen))
-        return false;
-      if (eType != CFX_CSSValue::PrimitiveType::kNumber)
-        return false;
-      CFX_CSSNumberValue::Unit eNumType;
-      if (!ParseCSSNumber(pszValue, nValueLen, &fValue, &eNumType))
-        return false;
-
-      rgb[i] = eNumType == CFX_CSSNumberValue::Unit::kPercent
-                   ? FXSYS_roundf(fValue * 2.55f)
-                   : FXSYS_roundf(fValue);
+      auto maybe_value = list.NextValue();
+      if (!maybe_value.has_value() ||
+          maybe_value.value().type != CFX_CSSValue::PrimitiveType::kNumber) {
+        return std::nullopt;
+      }
+      auto maybe_number = ParseCSSNumber(maybe_value.value().string_view);
+      if (!maybe_number.has_value()) {
+        return std::nullopt;
+      }
+      rgb[i] = maybe_number.value().unit == CFX_CSSNumber::Unit::kPercent
+                   ? FXSYS_roundf(maybe_number.value().value * 2.55f)
+                   : FXSYS_roundf(maybe_number.value().value);
     }
-    *dwColor = ArgbEncode(255, rgb[0], rgb[1], rgb[2]);
-    return true;
+    return ArgbEncode(255, rgb[0], rgb[1], rgb[2]);
   }
 
-  const CFX_CSSData::Color* pColor =
-      CFX_CSSData::GetColorByName(WideStringView(pszValue, nValueLen));
-  if (!pColor)
-    return false;
-
-  *dwColor = pColor->value;
-  return true;
+  const CFX_CSSData::Color* pColor = CFX_CSSData::GetColorByName(value);
+  if (!pColor) {
+    return std::nullopt;
+  }
+  return pColor->value;
 }
 
 CFX_CSSDeclaration::CFX_CSSDeclaration() = default;
@@ -163,7 +144,7 @@
   auto pHolder = std::make_unique<CFX_CSSPropertyHolder>();
   pHolder->bImportant = bImportant;
   pHolder->eProperty = eProperty;
-  pHolder->pValue = pValue;
+  pHolder->pValue = std::move(pValue);
   properties_.push_back(std::move(pHolder));
 }
 
@@ -171,15 +152,13 @@
                                      WideStringView value) {
   DCHECK(!value.IsEmpty());
 
-  const wchar_t* pszValue = value.unterminated_c_str();
-  size_t nValueLen = value.GetLength();
   bool bImportant = false;
-  if (nValueLen >= 10 && pszValue[nValueLen - 10] == '!' &&
-      FXSYS_wcsnicmp(L"important", pszValue + nValueLen - 9, 9) == 0) {
-    nValueLen -= 10;
-    if (nValueLen == 0)
+  WideStringView last_ten = value.Last(10);  // NOTE: empty-tolerant Last().
+  if (last_ten.EqualsASCIINoCase("!important")) {
+    value = value.First(value.GetLength() - 10);
+    if (value.IsEmpty()) {
       return;
-
+    }
     bImportant = true;
   }
   const CFX_CSSValueTypeMask dwType = property->dwTypes;
@@ -193,22 +172,22 @@
       };
       for (CFX_CSSVALUETYPE guess : kValueGuessOrder) {
         const CFX_CSSValueTypeMask dwMatch = dwType & guess;
-        if (dwMatch == 0)
+        if (dwMatch == 0) {
           continue;
-
+        }
         RetainPtr<CFX_CSSValue> pCSSValue;
         switch (dwMatch) {
           case CFX_CSSVALUETYPE_MaybeNumber:
-            pCSSValue = ParseNumber(pszValue, nValueLen);
+            pCSSValue = ParseNumber(value);
             break;
           case CFX_CSSVALUETYPE_MaybeEnum:
-            pCSSValue = ParseEnum(pszValue, nValueLen);
+            pCSSValue = ParseEnum(value);
             break;
           case CFX_CSSVALUETYPE_MaybeColor:
-            pCSSValue = ParseColor(pszValue, nValueLen);
+            pCSSValue = ParseColor(value);
             break;
           case CFX_CSSVALUETYPE_MaybeString:
-            pCSSValue = ParseString(pszValue, nValueLen);
+            pCSSValue = ParseString(value);
             break;
           default:
             break;
@@ -217,65 +196,57 @@
           AddPropertyHolder(property->eName, pCSSValue, bImportant);
           return;
         }
-
-        if ((dwType & ~guess) == CFX_CSSVALUETYPE_Primitive)
+        if ((dwType & ~guess) == CFX_CSSVALUETYPE_Primitive) {
           return;
+        }
       }
       break;
     }
     case CFX_CSSVALUETYPE_Shorthand: {
-      RetainPtr<CFX_CSSValue> pWidth;
       switch (property->eName) {
-        case CFX_CSSProperty::Font:
-          ParseFontProperty(pszValue, nValueLen, bImportant);
+        case CFX_CSSProperty::Font: {
+          ParseFontProperty(value, bImportant);
           return;
-        case CFX_CSSProperty::Border:
-          if (ParseBorderProperty(pszValue, nValueLen, pWidth)) {
-            AddPropertyHolder(CFX_CSSProperty::BorderLeftWidth, pWidth,
-                              bImportant);
-            AddPropertyHolder(CFX_CSSProperty::BorderTopWidth, pWidth,
-                              bImportant);
-            AddPropertyHolder(CFX_CSSProperty::BorderRightWidth, pWidth,
-                              bImportant);
-            AddPropertyHolder(CFX_CSSProperty::BorderBottomWidth, pWidth,
-                              bImportant);
-            return;
-          }
+        }
+        case CFX_CSSProperty::Border: {
+          RetainPtr<CFX_CSSValue> pWidth = ParseBorderProperty(value);
+          AddPropertyHolder(CFX_CSSProperty::BorderLeftWidth, pWidth,
+                            bImportant);
+          AddPropertyHolder(CFX_CSSProperty::BorderTopWidth, pWidth,
+                            bImportant);
+          AddPropertyHolder(CFX_CSSProperty::BorderRightWidth, pWidth,
+                            bImportant);
+          AddPropertyHolder(CFX_CSSProperty::BorderBottomWidth, pWidth,
+                            bImportant);
+          return;
+        }
+        case CFX_CSSProperty::BorderLeft: {
+          AddPropertyHolder(CFX_CSSProperty::BorderLeftWidth,
+                            ParseBorderProperty(value), bImportant);
           break;
-        case CFX_CSSProperty::BorderLeft:
-          if (ParseBorderProperty(pszValue, nValueLen, pWidth)) {
-            AddPropertyHolder(CFX_CSSProperty::BorderLeftWidth, pWidth,
-                              bImportant);
-            return;
-          }
-          break;
-        case CFX_CSSProperty::BorderTop:
-          if (ParseBorderProperty(pszValue, nValueLen, pWidth)) {
-            AddPropertyHolder(CFX_CSSProperty::BorderTopWidth, pWidth,
-                              bImportant);
-            return;
-          }
-          break;
-        case CFX_CSSProperty::BorderRight:
-          if (ParseBorderProperty(pszValue, nValueLen, pWidth)) {
-            AddPropertyHolder(CFX_CSSProperty::BorderRightWidth, pWidth,
-                              bImportant);
-            return;
-          }
-          break;
-        case CFX_CSSProperty::BorderBottom:
-          if (ParseBorderProperty(pszValue, nValueLen, pWidth)) {
-            AddPropertyHolder(CFX_CSSProperty::BorderBottomWidth, pWidth,
-                              bImportant);
-            return;
-          }
-          break;
+        }
+        case CFX_CSSProperty::BorderTop: {
+          AddPropertyHolder(CFX_CSSProperty::BorderTopWidth,
+                            ParseBorderProperty(value), bImportant);
+          return;
+        }
+        case CFX_CSSProperty::BorderRight: {
+          AddPropertyHolder(CFX_CSSProperty::BorderRightWidth,
+                            ParseBorderProperty(value), bImportant);
+          return;
+        }
+        case CFX_CSSProperty::BorderBottom: {
+          AddPropertyHolder(CFX_CSSProperty::BorderBottomWidth,
+                            ParseBorderProperty(value), bImportant);
+          return;
+        }
         default:
           break;
       }
-    } break;
+      break;
+    }
     case CFX_CSSVALUETYPE_List:
-      ParseValueListProperty(property, pszValue, nValueLen, bImportant);
+      ParseValueListProperty(property, value, bImportant);
       return;
     default:
       NOTREACHED_NORETURN();
@@ -288,103 +259,98 @@
       std::make_unique<CFX_CSSCustomProperty>(prop, value));
 }
 
-RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseNumber(const wchar_t* pszValue,
-                                                        size_t nValueLen) {
-  float fValue;
-  CFX_CSSNumberValue::Unit eUnit;
-  if (!ParseCSSNumber(pszValue, nValueLen, &fValue, &eUnit))
+RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseNumber(WideStringView view) {
+  std::optional<CFX_CSSNumber> maybe_number = ParseCSSNumber(view);
+  if (!maybe_number.has_value()) {
     return nullptr;
-  return pdfium::MakeRetain<CFX_CSSNumberValue>(eUnit, fValue);
+  }
+  return pdfium::MakeRetain<CFX_CSSNumberValue>(maybe_number.value());
 }
 
-RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseEnum(const wchar_t* pszValue,
-                                                      size_t nValueLen) {
+RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseEnum(WideStringView value) {
   const CFX_CSSData::PropertyValue* pValue =
-      CFX_CSSData::GetPropertyValueByName(WideStringView(pszValue, nValueLen));
+      CFX_CSSData::GetPropertyValueByName(value);
   return pValue ? pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName) : nullptr;
 }
 
-RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseColor(const wchar_t* pszValue,
-                                                       size_t nValueLen) {
-  FX_ARGB dwColor;
-  if (!ParseCSSColor(pszValue, nValueLen, &dwColor))
+RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseColor(WideStringView value) {
+  auto maybe_color = ParseCSSColor(value);
+  if (!maybe_color.has_value()) {
     return nullptr;
-  return pdfium::MakeRetain<CFX_CSSColorValue>(dwColor);
+  }
+  return pdfium::MakeRetain<CFX_CSSColorValue>(maybe_color.value());
 }
 
-RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseString(const wchar_t* pszValue,
-                                                        size_t nValueLen) {
-  size_t iOffset;
-  if (!ParseCSSString(pszValue, nValueLen, &iOffset, &nValueLen))
+RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseString(WideStringView value) {
+  auto maybe_string = ParseCSSString(value);
+  if (!maybe_string.has_value() || maybe_string.value().IsEmpty()) {
     return nullptr;
-
-  if (nValueLen == 0)
-    return nullptr;
-
-  return pdfium::MakeRetain<CFX_CSSStringValue>(
-      WideString(pszValue + iOffset, nValueLen));
+  }
+  return pdfium::MakeRetain<CFX_CSSStringValue>(maybe_string.value());
 }
 
 void CFX_CSSDeclaration::ParseValueListProperty(
     const CFX_CSSData::Property* pProperty,
-    const wchar_t* pszValue,
-    size_t nValueLen,
+    WideStringView value,
     bool bImportant) {
   wchar_t separator =
       (pProperty->eName == CFX_CSSProperty::FontFamily) ? ',' : ' ';
-  CFX_CSSValueListParser parser(pszValue, nValueLen, separator);
-
+  CFX_CSSValueListParser parser(value, separator);
   const CFX_CSSValueTypeMask dwType = pProperty->dwTypes;
-  CFX_CSSValue::PrimitiveType eType;
   std::vector<RetainPtr<CFX_CSSValue>> list;
-  while (parser.NextValue(&eType, &pszValue, &nValueLen)) {
-    switch (eType) {
+  while (1) {
+    auto maybe_next = parser.NextValue();
+    if (!maybe_next.has_value()) {
+      break;
+    }
+    switch (maybe_next.value().type) {
       case CFX_CSSValue::PrimitiveType::kNumber:
         if (dwType & CFX_CSSVALUETYPE_MaybeNumber) {
-          float fValue;
-          CFX_CSSNumberValue::Unit eNumType;
-          if (ParseCSSNumber(pszValue, nValueLen, &fValue, &eNumType))
+          auto maybe_number = ParseCSSNumber(maybe_next.value().string_view);
+          if (maybe_number.has_value()) {
             list.push_back(
-                pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue));
+                pdfium::MakeRetain<CFX_CSSNumberValue>(maybe_number.value()));
+          }
         }
         break;
       case CFX_CSSValue::PrimitiveType::kString:
         if (dwType & CFX_CSSVALUETYPE_MaybeColor) {
-          FX_ARGB dwColor;
-          if (ParseCSSColor(pszValue, nValueLen, &dwColor)) {
-            list.push_back(pdfium::MakeRetain<CFX_CSSColorValue>(dwColor));
+          auto maybe_color = ParseCSSColor(maybe_next.value().string_view);
+          if (maybe_color.has_value()) {
+            list.push_back(
+                pdfium::MakeRetain<CFX_CSSColorValue>(maybe_color.value()));
             continue;
           }
         }
         if (dwType & CFX_CSSVALUETYPE_MaybeEnum) {
-          const CFX_CSSData::PropertyValue* pValue =
+          const CFX_CSSData::PropertyValue* pPropValue =
               CFX_CSSData::GetPropertyValueByName(
-                  WideStringView(pszValue, nValueLen));
-          if (pValue) {
-            list.push_back(pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName));
+                  maybe_next.value().string_view);
+          if (pPropValue) {
+            list.push_back(
+                pdfium::MakeRetain<CFX_CSSEnumValue>(pPropValue->eName));
             continue;
           }
         }
         if (dwType & CFX_CSSVALUETYPE_MaybeString) {
           list.push_back(pdfium::MakeRetain<CFX_CSSStringValue>(
-              WideString(pszValue, nValueLen)));
+              maybe_next.value().string_view));
         }
         break;
       case CFX_CSSValue::PrimitiveType::kRGB:
         if (dwType & CFX_CSSVALUETYPE_MaybeColor) {
-          FX_ARGB dwColor;
-          if (ParseCSSColor(pszValue, nValueLen, &dwColor)) {
-            list.push_back(pdfium::MakeRetain<CFX_CSSColorValue>(dwColor));
-          }
+          FX_ARGB color =
+              ParseCSSColor(maybe_next.value().string_view).value_or(0);
+          list.push_back(pdfium::MakeRetain<CFX_CSSColorValue>(color));
         }
         break;
       default:
         break;
     }
   }
-  if (list.empty())
+  if (list.empty()) {
     return;
-
+  }
   switch (pProperty->eName) {
     case CFX_CSSProperty::BorderWidth:
       Add4ValuesProperty(list, bImportant, CFX_CSSProperty::BorderLeftWidth,
@@ -406,7 +372,7 @@
       return;
     default: {
       auto value_list = pdfium::MakeRetain<CFX_CSSValueList>(std::move(list));
-      AddPropertyHolder(pProperty->eName, value_list, bImportant);
+      AddPropertyHolder(pProperty->eName, std::move(value_list), bImportant);
       return;
     }
   }
@@ -449,38 +415,37 @@
   }
 }
 
-bool CFX_CSSDeclaration::ParseBorderProperty(
-    const wchar_t* pszValue,
-    size_t nValueLen,
-    RetainPtr<CFX_CSSValue>& pWidth) const {
-  pWidth.Reset(nullptr);
-
-  CFX_CSSValue::PrimitiveType eType;
-  CFX_CSSValueListParser parser(pszValue, nValueLen, ' ');
-  while (parser.NextValue(&eType, &pszValue, &nValueLen)) {
-    switch (eType) {
+RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseBorderProperty(
+    WideStringView value) const {
+  RetainPtr<CFX_CSSValue> pWidth;
+  CFX_CSSValueListParser parser(value, ' ');
+  while (1) {
+    auto maybe_next = parser.NextValue();
+    if (!maybe_next.has_value()) {
+      break;
+    }
+    switch (maybe_next.value().type) {
       case CFX_CSSValue::PrimitiveType::kNumber: {
-        if (pWidth)
+        if (pWidth) {
           continue;
-
-        float fValue;
-        CFX_CSSNumberValue::Unit eNumType;
-        if (ParseCSSNumber(pszValue, nValueLen, &fValue, &eNumType))
-          pWidth = pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue);
+        }
+        auto maybe_number = ParseCSSNumber(maybe_next.value().string_view);
+        if (maybe_number.has_value()) {
+          pWidth = pdfium::MakeRetain<CFX_CSSNumberValue>(maybe_number.value());
+        }
         break;
       }
       case CFX_CSSValue::PrimitiveType::kString: {
         const CFX_CSSData::Color* pColorItem =
-            CFX_CSSData::GetColorByName(WideStringView(pszValue, nValueLen));
-        if (pColorItem)
+            CFX_CSSData::GetColorByName(maybe_next.value().string_view);
+        if (pColorItem) {
           continue;
-
+        }
         const CFX_CSSData::PropertyValue* pValue =
-            CFX_CSSData::GetPropertyValueByName(
-                WideStringView(pszValue, nValueLen));
-        if (!pValue)
+            CFX_CSSData::GetPropertyValueByName(maybe_next.value().string_view);
+        if (!pValue) {
           continue;
-
+        }
         switch (pValue->eName) {
           case CFX_CSSPropertyValue::Thin:
           case CFX_CSSPropertyValue::Thick:
@@ -497,30 +462,31 @@
         break;
     }
   }
-  if (!pWidth) {
-    pWidth = pdfium::MakeRetain<CFX_CSSNumberValue>(
-        CFX_CSSNumberValue::Unit::kNumber, 0.0f);
+  if (pWidth) {
+    return pWidth;
   }
-  return true;
+  return pdfium::MakeRetain<CFX_CSSNumberValue>(
+      CFX_CSSNumber{CFX_CSSNumber::Unit::kNumber, 0.0f});
 }
 
-void CFX_CSSDeclaration::ParseFontProperty(const wchar_t* pszValue,
-                                           size_t nValueLen,
+void CFX_CSSDeclaration::ParseFontProperty(WideStringView value,
                                            bool bImportant) {
-  CFX_CSSValueListParser parser(pszValue, nValueLen, '/');
   RetainPtr<CFX_CSSValue> pStyle;
   RetainPtr<CFX_CSSValue> pVariant;
   RetainPtr<CFX_CSSValue> pWeight;
   RetainPtr<CFX_CSSValue> pFontSize;
   RetainPtr<CFX_CSSValue> pLineHeight;
   std::vector<RetainPtr<CFX_CSSValue>> family_list;
-  CFX_CSSValue::PrimitiveType eType;
-  while (parser.NextValue(&eType, &pszValue, &nValueLen)) {
-    switch (eType) {
+  CFX_CSSValueListParser parser(value, '/');
+  while (1) {
+    auto maybe_next = parser.NextValue();
+    if (!maybe_next.has_value()) {
+      break;
+    }
+    switch (maybe_next.value().type) {
       case CFX_CSSValue::PrimitiveType::kString: {
         const CFX_CSSData::PropertyValue* pValue =
-            CFX_CSSData::GetPropertyValueByName(
-                WideStringView(pszValue, nValueLen));
+            CFX_CSSData::GetPropertyValueByName(maybe_next.value().string_view);
         if (pValue) {
           switch (pValue->eName) {
             case CFX_CSSPropertyValue::XxSmall:
@@ -569,18 +535,18 @@
         }
         if (pFontSize) {
           family_list.push_back(pdfium::MakeRetain<CFX_CSSStringValue>(
-              WideString(pszValue, nValueLen)));
+              maybe_next.value().string_view));
         }
         parser.UseCommaSeparator();
         break;
       }
       case CFX_CSSValue::PrimitiveType::kNumber: {
-        float fValue;
-        CFX_CSSNumberValue::Unit eNumType;
-        if (!ParseCSSNumber(pszValue, nValueLen, &fValue, &eNumType))
+        auto maybe_number = ParseCSSNumber(maybe_next.value().string_view);
+        if (!maybe_number.has_value()) {
           break;
-        if (eType == CFX_CSSValue::PrimitiveType::kNumber) {
-          switch (static_cast<int32_t>(fValue)) {
+        }
+        if (maybe_number.value().unit == CFX_CSSNumber::Unit::kNumber) {
+          switch (static_cast<int32_t>(maybe_number.value().value)) {
             case 100:
             case 200:
             case 300:
@@ -592,16 +558,18 @@
             case 900:
               if (!pWeight) {
                 pWeight = pdfium::MakeRetain<CFX_CSSNumberValue>(
-                    CFX_CSSNumberValue::Unit::kNumber, fValue);
+                    maybe_number.value());
               }
               continue;
           }
         }
-        if (!pFontSize)
-          pFontSize = pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue);
-        else if (!pLineHeight)
+        if (!pFontSize) {
+          pFontSize =
+              pdfium::MakeRetain<CFX_CSSNumberValue>(maybe_number.value());
+        } else if (!pLineHeight) {
           pLineHeight =
-              pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue);
+              pdfium::MakeRetain<CFX_CSSNumberValue>(maybe_number.value());
+        }
         break;
       }
       default:
diff --git a/core/fxcrt/css/cfx_cssdeclaration.h b/core/fxcrt/css/cfx_cssdeclaration.h
index eef58e0..21bce28 100644
--- a/core/fxcrt/css/cfx_cssdeclaration.h
+++ b/core/fxcrt/css/cfx_cssdeclaration.h
@@ -8,10 +8,12 @@
 #define CORE_FXCRT_CSS_CFX_CSSDECLARATION_H_
 
 #include <memory>
+#include <optional>
 #include <vector>
 
 #include "core/fxcrt/css/cfx_cssdata.h"
 #include "core/fxcrt/retain_ptr.h"
+#include "core/fxcrt/widestring.h"
 
 class CFX_CSSPropertyHolder;
 class CFX_CSSCustomProperty;
@@ -23,13 +25,8 @@
   using const_custom_iterator =
       std::vector<std::unique_ptr<CFX_CSSCustomProperty>>::const_iterator;
 
-  static bool ParseCSSString(const wchar_t* pszValue,
-                             size_t nValueLen,
-                             size_t* nOffset,
-                             size_t* nLength);
-  static bool ParseCSSColor(const wchar_t* pszValue,
-                            size_t nValueLen,
-                            FX_ARGB* dwColor);
+  static std::optional<WideStringView> ParseCSSString(WideStringView value);
+  static std::optional<FX_ARGB> ParseCSSColor(WideStringView value);
 
   CFX_CSSDeclaration();
   ~CFX_CSSDeclaration();
@@ -37,6 +34,7 @@
   RetainPtr<CFX_CSSValue> GetProperty(CFX_CSSProperty eProperty,
                                       bool* bImportant) const;
 
+  bool empty() const { return properties_.empty(); }
   const_prop_iterator begin() const { return properties_.begin(); }
   const_prop_iterator end() const { return properties_.end(); }
 
@@ -45,27 +43,21 @@
   }
   const_custom_iterator custom_end() const { return custom_properties_.end(); }
 
-  bool empty() const { return properties_.empty(); }
-
   void AddProperty(const CFX_CSSData::Property* property, WideStringView value);
   void AddProperty(const WideString& prop, const WideString& value);
-
   size_t PropertyCountForTesting() const;
 
-  FX_ARGB ParseColorForTest(const wchar_t* pszValue,
-                            size_t nValueLen,
-                            FX_ARGB* dwColor) const;
+  std::optional<FX_ARGB> ParseColorForTest(WideStringView value);
 
  private:
-  void ParseFontProperty(const wchar_t* pszValue,
-                         size_t nValueLen,
-                         bool bImportant);
-  bool ParseBorderProperty(const wchar_t* pszValue,
-                           size_t nValueLen,
-                           RetainPtr<CFX_CSSValue>& pWidth) const;
+  void ParseFontProperty(WideStringView value, bool bImportant);
+
+  // Never returns nullptr, instead returns a CSSValue representing zero
+  // if the input cannot be parsed.
+  RetainPtr<CFX_CSSValue> ParseBorderProperty(WideStringView value) const;
+
   void ParseValueListProperty(const CFX_CSSData::Property* pProperty,
-                              const wchar_t* pszValue,
-                              size_t nValueLen,
+                              WideStringView value,
                               bool bImportant);
   void Add4ValuesProperty(const std::vector<RetainPtr<CFX_CSSValue>>& list,
                           bool bImportant,
@@ -73,12 +65,10 @@
                           CFX_CSSProperty eTop,
                           CFX_CSSProperty eRight,
                           CFX_CSSProperty eBottom);
-  RetainPtr<CFX_CSSValue> ParseNumber(const wchar_t* pszValue,
-                                      size_t nValueLen);
-  RetainPtr<CFX_CSSValue> ParseEnum(const wchar_t* pszValue, size_t nValueLen);
-  RetainPtr<CFX_CSSValue> ParseColor(const wchar_t* pszValue, size_t nValueLen);
-  RetainPtr<CFX_CSSValue> ParseString(const wchar_t* pszValue,
-                                      size_t nValueLen);
+  RetainPtr<CFX_CSSValue> ParseNumber(WideStringView value);
+  RetainPtr<CFX_CSSValue> ParseEnum(WideStringView value);
+  RetainPtr<CFX_CSSValue> ParseColor(WideStringView value);
+  RetainPtr<CFX_CSSValue> ParseString(WideStringView value);
   void AddPropertyHolder(CFX_CSSProperty eProperty,
                          RetainPtr<CFX_CSSValue> pValue,
                          bool bImportant);
diff --git a/core/fxcrt/css/cfx_cssdeclaration_unittest.cpp b/core/fxcrt/css/cfx_cssdeclaration_unittest.cpp
index 5868063..aa4fd54 100644
--- a/core/fxcrt/css/cfx_cssdeclaration_unittest.cpp
+++ b/core/fxcrt/css/cfx_cssdeclaration_unittest.cpp
@@ -4,58 +4,66 @@
 
 #include "core/fxcrt/css/cfx_cssdeclaration.h"
 
+#include <optional>
+
 #include "testing/gtest/include/gtest/gtest.h"
 
 TEST(CFX_CSSDeclarationTest, HexEncodingParsing) {
-  FX_ARGB color;
+  std::optional<FX_ARGB> maybe_color;
 
   // Length value invalid.
-  EXPECT_FALSE(CFX_CSSDeclaration::ParseCSSColor(L"#000", 3, &color));
-  EXPECT_FALSE(CFX_CSSDeclaration::ParseCSSColor(L"#000000", 5, &color));
-  EXPECT_FALSE(CFX_CSSDeclaration::ParseCSSColor(L"#000000", 8, &color));
+  EXPECT_FALSE(CFX_CSSDeclaration::ParseCSSColor(L"#00"));
+  EXPECT_FALSE(CFX_CSSDeclaration::ParseCSSColor(L"#0000"));
+  EXPECT_FALSE(CFX_CSSDeclaration::ParseCSSColor(L"#0000000"));
 
   // Invalid characters
-  EXPECT_TRUE(CFX_CSSDeclaration::ParseCSSColor(L"#zxytlm", 7, &color));
-  EXPECT_EQ(0, FXARGB_R(color));
-  EXPECT_EQ(0, FXARGB_G(color));
-  EXPECT_EQ(0, FXARGB_B(color));
+  maybe_color = CFX_CSSDeclaration::ParseCSSColor(L"#zxytlm");
+  ASSERT_TRUE(maybe_color.has_value());
+  EXPECT_EQ(0, FXARGB_R(maybe_color.value()));
+  EXPECT_EQ(0, FXARGB_G(maybe_color.value()));
+  EXPECT_EQ(0, FXARGB_B(maybe_color.value()));
 
-  EXPECT_TRUE(CFX_CSSDeclaration::ParseCSSColor(L"#000", 4, &color));
-  EXPECT_EQ(0, FXARGB_R(color));
-  EXPECT_EQ(0, FXARGB_G(color));
-  EXPECT_EQ(0, FXARGB_B(color));
+  maybe_color = CFX_CSSDeclaration::ParseCSSColor(L"#000");
+  ASSERT_TRUE(maybe_color.has_value());
+  EXPECT_EQ(0, FXARGB_R(maybe_color.value()));
+  EXPECT_EQ(0, FXARGB_G(maybe_color.value()));
+  EXPECT_EQ(0, FXARGB_B(maybe_color.value()));
 
-  EXPECT_TRUE(CFX_CSSDeclaration::ParseCSSColor(L"#FFF", 4, &color));
-  EXPECT_EQ(255, FXARGB_R(color));
-  EXPECT_EQ(255, FXARGB_G(color));
-  EXPECT_EQ(255, FXARGB_B(color));
+  maybe_color = CFX_CSSDeclaration::ParseCSSColor(L"#FFF");
+  ASSERT_TRUE(maybe_color.has_value());
+  EXPECT_EQ(255, FXARGB_R(maybe_color.value()));
+  EXPECT_EQ(255, FXARGB_G(maybe_color.value()));
+  EXPECT_EQ(255, FXARGB_B(maybe_color.value()));
 
-  EXPECT_TRUE(CFX_CSSDeclaration::ParseCSSColor(L"#F0F0F0", 7, &color));
-  EXPECT_EQ(240, FXARGB_R(color));
-  EXPECT_EQ(240, FXARGB_G(color));
-  EXPECT_EQ(240, FXARGB_B(color));
+  maybe_color = CFX_CSSDeclaration::ParseCSSColor(L"#F0F0F0");
+  ASSERT_TRUE(maybe_color.has_value());
+  EXPECT_EQ(240, FXARGB_R(maybe_color.value()));
+  EXPECT_EQ(240, FXARGB_G(maybe_color.value()));
+  EXPECT_EQ(240, FXARGB_B(maybe_color.value()));
 
   // Upper and lower case characters.
-  EXPECT_TRUE(CFX_CSSDeclaration::ParseCSSColor(L"#1b2F3c", 7, &color));
-  EXPECT_EQ(27, FXARGB_R(color));
-  EXPECT_EQ(47, FXARGB_G(color));
-  EXPECT_EQ(60, FXARGB_B(color));
+  maybe_color = CFX_CSSDeclaration::ParseCSSColor(L"#1b2F3c");
+  ASSERT_TRUE(maybe_color.has_value());
+  EXPECT_EQ(27, FXARGB_R(maybe_color.value()));
+  EXPECT_EQ(47, FXARGB_G(maybe_color.value()));
+  EXPECT_EQ(60, FXARGB_B(maybe_color.value()));
 }
 
 TEST(CFX_CSSDeclarationTest, RGBEncodingParsing) {
-  FX_ARGB color;
+  std::optional<FX_ARGB> maybe_color;
 
   // Invalid input for rgb() syntax.
-  EXPECT_FALSE(CFX_CSSDeclaration::ParseCSSColor(L"blahblahblah", 11, &color));
+  EXPECT_FALSE(CFX_CSSDeclaration::ParseCSSColor(L"blahblahblah"));
 
-  EXPECT_TRUE(CFX_CSSDeclaration::ParseCSSColor(L"rgb(0, 0, 0)", 12, &color));
-  EXPECT_EQ(0, FXARGB_R(color));
-  EXPECT_EQ(0, FXARGB_G(color));
-  EXPECT_EQ(0, FXARGB_B(color));
+  maybe_color = CFX_CSSDeclaration::ParseCSSColor(L"rgb(0, 0, 0)");
+  ASSERT_TRUE(maybe_color.has_value());
+  EXPECT_EQ(0, FXARGB_R(maybe_color.value()));
+  EXPECT_EQ(0, FXARGB_G(maybe_color.value()));
+  EXPECT_EQ(0, FXARGB_B(maybe_color.value()));
 
-  EXPECT_TRUE(
-      CFX_CSSDeclaration::ParseCSSColor(L"rgb(128,255,48)", 15, &color));
-  EXPECT_EQ(128, FXARGB_R(color));
-  EXPECT_EQ(255, FXARGB_G(color));
-  EXPECT_EQ(48, FXARGB_B(color));
+  maybe_color = CFX_CSSDeclaration::ParseCSSColor(L"rgb(128,255,48)");
+  ASSERT_TRUE(maybe_color.has_value());
+  EXPECT_EQ(128, FXARGB_R(maybe_color.value()));
+  EXPECT_EQ(255, FXARGB_G(maybe_color.value()));
+  EXPECT_EQ(48, FXARGB_B(maybe_color.value()));
 }
diff --git a/core/fxcrt/css/cfx_cssnumbervalue.cpp b/core/fxcrt/css/cfx_cssnumbervalue.cpp
index 72ae775..665257f 100644
--- a/core/fxcrt/css/cfx_cssnumbervalue.cpp
+++ b/core/fxcrt/css/cfx_cssnumbervalue.cpp
@@ -8,34 +8,35 @@
 
 #include <math.h>
 
-CFX_CSSNumberValue::CFX_CSSNumberValue(Unit unit, float value)
-    : CFX_CSSValue(PrimitiveType::kNumber), unit_(unit), value_(value) {
-  if (unit_ == Unit::kNumber && fabs(value_) < 0.001f)
-    value_ = 0.0f;
+CFX_CSSNumberValue::CFX_CSSNumberValue(CFX_CSSNumber number)
+    : CFX_CSSValue(PrimitiveType::kNumber), number_(number) {
+  if (number_.unit == CFX_CSSNumber::Unit::kNumber &&
+      fabs(number_.value) < 0.001f) {
+    number_.value = 0.0f;
+  }
 }
 
 CFX_CSSNumberValue::~CFX_CSSNumberValue() = default;
 
 float CFX_CSSNumberValue::Apply(float percentBase) const {
-  switch (unit_) {
-    case Unit::kPixels:
-    case Unit::kNumber:
-      return value_ * 72 / 96;
-    case Unit::kEMS:
-    case Unit::kEXS:
-      return value_ * percentBase;
-    case Unit::kPercent:
-      return value_ * percentBase / 100.0f;
-    case Unit::kCentiMeters:
-      return value_ * 28.3464f;
-    case Unit::kMilliMeters:
-      return value_ * 2.8346f;
-    case Unit::kInches:
-      return value_ * 72.0f;
-    case Unit::kPicas:
-      return value_ / 12.0f;
-    case Unit::kPoints:
-      return value_;
+  switch (number_.unit) {
+    case CFX_CSSNumber::Unit::kPixels:
+    case CFX_CSSNumber::Unit::kNumber:
+      return number_.value * 72 / 96;
+    case CFX_CSSNumber::Unit::kEMS:
+    case CFX_CSSNumber::Unit::kEXS:
+      return number_.value * percentBase;
+    case CFX_CSSNumber::Unit::kPercent:
+      return number_.value * percentBase / 100.0f;
+    case CFX_CSSNumber::Unit::kCentiMeters:
+      return number_.value * 28.3464f;
+    case CFX_CSSNumber::Unit::kMilliMeters:
+      return number_.value * 2.8346f;
+    case CFX_CSSNumber::Unit::kInches:
+      return number_.value * 72.0f;
+    case CFX_CSSNumber::Unit::kPicas:
+      return number_.value / 12.0f;
+    case CFX_CSSNumber::Unit::kPoints:
+      return number_.value;
   }
-  return value_;
 }
diff --git a/core/fxcrt/css/cfx_cssnumbervalue.h b/core/fxcrt/css/cfx_cssnumbervalue.h
index 3b2556b..a1a4861 100644
--- a/core/fxcrt/css/cfx_cssnumbervalue.h
+++ b/core/fxcrt/css/cfx_cssnumbervalue.h
@@ -9,8 +9,7 @@
 
 #include "core/fxcrt/css/cfx_cssvalue.h"
 
-class CFX_CSSNumberValue final : public CFX_CSSValue {
- public:
+struct CFX_CSSNumber {
   enum class Unit {
     kNumber,
     kPercent,
@@ -24,16 +23,21 @@
     kPicas,
   };
 
-  CFX_CSSNumberValue(Unit unit, float value);
+  Unit unit;
+  float value;
+};
+
+class CFX_CSSNumberValue final : public CFX_CSSValue {
+ public:
+  explicit CFX_CSSNumberValue(CFX_CSSNumber number);
   ~CFX_CSSNumberValue() override;
 
-  Unit unit() const { return unit_; }
-  float value() const { return value_; }
+  CFX_CSSNumber::Unit unit() const { return number_.unit; }
+  float value() const { return number_.value; }
   float Apply(float percentBase) const;
 
  private:
-  Unit unit_;
-  float value_;
+  CFX_CSSNumber number_;
 };
 
 #endif  // CORE_FXCRT_CSS_CFX_CSSNUMBERVALUE_H_
diff --git a/core/fxcrt/css/cfx_cssstringvalue.cpp b/core/fxcrt/css/cfx_cssstringvalue.cpp
index 7fbb6b0..ce60f80 100644
--- a/core/fxcrt/css/cfx_cssstringvalue.cpp
+++ b/core/fxcrt/css/cfx_cssstringvalue.cpp
@@ -6,7 +6,7 @@
 
 #include "core/fxcrt/css/cfx_cssstringvalue.h"
 
-CFX_CSSStringValue::CFX_CSSStringValue(const WideString& value)
+CFX_CSSStringValue::CFX_CSSStringValue(WideStringView value)
     : CFX_CSSValue(PrimitiveType::kString), value_(value) {}
 
 CFX_CSSStringValue::~CFX_CSSStringValue() = default;
diff --git a/core/fxcrt/css/cfx_cssstringvalue.h b/core/fxcrt/css/cfx_cssstringvalue.h
index afc2d31..1d014ba 100644
--- a/core/fxcrt/css/cfx_cssstringvalue.h
+++ b/core/fxcrt/css/cfx_cssstringvalue.h
@@ -12,7 +12,9 @@
 
 class CFX_CSSStringValue final : public CFX_CSSValue {
  public:
-  explicit CFX_CSSStringValue(const WideString& value);
+  // Callers always have views, so do the copy here instead of requiring
+  // each of them to create a WideString.
+  explicit CFX_CSSStringValue(WideStringView value);
   ~CFX_CSSStringValue() override;
 
   const WideString Value() const { return value_; }
diff --git a/core/fxcrt/css/cfx_cssstyleselector.cpp b/core/fxcrt/css/cfx_cssstyleselector.cpp
index a835410..6458eb7 100644
--- a/core/fxcrt/css/cfx_cssstyleselector.cpp
+++ b/core/fxcrt/css/cfx_cssstyleselector.cpp
@@ -209,7 +209,7 @@
     case CFX_CSSProperty::LineHeight:
       if (eType == CFX_CSSValue::PrimitiveType::kNumber) {
         RetainPtr<CFX_CSSNumberValue> v = pValue.As<CFX_CSSNumberValue>();
-        if (v->unit() == CFX_CSSNumberValue::Unit::kNumber) {
+        if (v->unit() == CFX_CSSNumber::Unit::kNumber) {
           pComputedStyle->m_InheritedData.m_fLineHeight =
               v->value() * pComputedStyle->m_InheritedData.m_fFontSize;
         } else {
@@ -361,7 +361,7 @@
             CFX_CSSLengthUnit::Normal);
       } else if (eType == CFX_CSSValue::PrimitiveType::kNumber) {
         if (pValue.AsRaw<CFX_CSSNumberValue>()->unit() ==
-            CFX_CSSNumberValue::Unit::kPercent) {
+            CFX_CSSNumber::Unit::kPercent) {
           break;
         }
 
@@ -376,7 +376,7 @@
             CFX_CSSLengthUnit::Normal);
       } else if (eType == CFX_CSSValue::PrimitiveType::kNumber) {
         if (pValue.AsRaw<CFX_CSSNumberValue>()->unit() ==
-            CFX_CSSNumberValue::Unit::kPercent) {
+            CFX_CSSNumber::Unit::kPercent) {
           break;
         }
         SetLengthWithPercent(pComputedStyle->m_InheritedData.m_WordSpacing,
@@ -470,7 +470,7 @@
     float fFontSize) {
   if (eType == CFX_CSSValue::PrimitiveType::kNumber) {
     RetainPtr<CFX_CSSNumberValue> v = pValue.As<CFX_CSSNumberValue>();
-    if (v->unit() == CFX_CSSNumberValue::Unit::kPercent) {
+    if (v->unit() == CFX_CSSNumber::Unit::kPercent) {
       width.Set(CFX_CSSLengthUnit::Percent,
                 pValue.AsRaw<CFX_CSSNumberValue>()->value() / 100.0f);
       return width.NonZero();
diff --git a/core/fxcrt/css/cfx_cssstylesheet_unittest.cpp b/core/fxcrt/css/cfx_cssstylesheet_unittest.cpp
index 77ba6a0..4457024 100644
--- a/core/fxcrt/css/cfx_cssstylesheet_unittest.cpp
+++ b/core/fxcrt/css/cfx_cssstylesheet_unittest.cpp
@@ -55,9 +55,7 @@
     EXPECT_EQ(decl_->PropertyCountForTesting(), decl_count);
   }
 
-  void VerifyFloat(CFX_CSSProperty prop,
-                   float val,
-                   CFX_CSSNumberValue::Unit unit) {
+  void VerifyFloat(CFX_CSSProperty prop, float val, CFX_CSSNumber::Unit unit) {
     DCHECK(decl_);
 
     bool important;
@@ -153,13 +151,13 @@
   EXPECT_EQ(4u, decl_->PropertyCountForTesting());
 
   VerifyFloat(CFX_CSSProperty::BorderLeftWidth, 10.0f,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
   VerifyFloat(CFX_CSSProperty::BorderRightWidth, 10.0f,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
   VerifyFloat(CFX_CSSProperty::BorderTopWidth, 10.0f,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
   VerifyFloat(CFX_CSSProperty::BorderBottomWidth, 10.0f,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
 
   style = sheet_->GetRule(1);
   ASSERT_TRUE(style);
@@ -181,14 +179,12 @@
   decl_ = style->GetDeclaration();
   ASSERT_TRUE(decl_);
   EXPECT_EQ(4u, decl_->PropertyCountForTesting());
-  VerifyFloat(CFX_CSSProperty::PaddingLeft, 0.0f,
-              CFX_CSSNumberValue::Unit::kNumber);
+  VerifyFloat(CFX_CSSProperty::PaddingLeft, 0.0f, CFX_CSSNumber::Unit::kNumber);
   VerifyFloat(CFX_CSSProperty::PaddingRight, 0.0f,
-              CFX_CSSNumberValue::Unit::kNumber);
-  VerifyFloat(CFX_CSSProperty::PaddingTop, 0.0f,
-              CFX_CSSNumberValue::Unit::kNumber);
+              CFX_CSSNumber::Unit::kNumber);
+  VerifyFloat(CFX_CSSProperty::PaddingTop, 0.0f, CFX_CSSNumber::Unit::kNumber);
   VerifyFloat(CFX_CSSProperty::PaddingBottom, 0.0f,
-              CFX_CSSNumberValue::Unit::kNumber);
+              CFX_CSSNumber::Unit::kNumber);
 }
 
 TEST_F(CFX_CSSStyleSheetTest, ParseChildSelectors) {
@@ -220,13 +216,13 @@
   EXPECT_EQ(4u, decl_->PropertyCountForTesting());
 
   VerifyFloat(CFX_CSSProperty::BorderLeftWidth, 10.0f,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
   VerifyFloat(CFX_CSSProperty::BorderRightWidth, 10.0f,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
   VerifyFloat(CFX_CSSProperty::BorderTopWidth, 10.0f,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
   VerifyFloat(CFX_CSSProperty::BorderBottomWidth, 10.0f,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
 }
 
 TEST_F(CFX_CSSStyleSheetTest, ParseUnhandledSelectors) {
@@ -254,31 +250,31 @@
 TEST_F(CFX_CSSStyleSheetTest, ParseBorder) {
   LoadAndVerifyDecl(L"a { border: 5px; }", {L"a"}, 4);
   VerifyFloat(CFX_CSSProperty::BorderLeftWidth, 5.0,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
   VerifyFloat(CFX_CSSProperty::BorderRightWidth, 5.0,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
   VerifyFloat(CFX_CSSProperty::BorderTopWidth, 5.0,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
   VerifyFloat(CFX_CSSProperty::BorderBottomWidth, 5.0,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
 }
 
 TEST_F(CFX_CSSStyleSheetTest, ParseBorderFull) {
   LoadAndVerifyDecl(L"a { border: 5px solid red; }", {L"a"}, 4);
   VerifyFloat(CFX_CSSProperty::BorderLeftWidth, 5.0,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
   VerifyFloat(CFX_CSSProperty::BorderRightWidth, 5.0,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
   VerifyFloat(CFX_CSSProperty::BorderTopWidth, 5.0,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
   VerifyFloat(CFX_CSSProperty::BorderBottomWidth, 5.0,
-              CFX_CSSNumberValue::Unit::kPixels);
+              CFX_CSSNumber::Unit::kPixels);
 }
 
 TEST_F(CFX_CSSStyleSheetTest, ParseBorderLeft) {
   LoadAndVerifyDecl(L"a { border-left: 2.5pc; }", {L"a"}, 1);
   VerifyFloat(CFX_CSSProperty::BorderLeftWidth, 2.5,
-              CFX_CSSNumberValue::Unit::kPicas);
+              CFX_CSSNumber::Unit::kPicas);
 }
 
 TEST_F(CFX_CSSStyleSheetTest, ParseBorderLeftThick) {
@@ -289,38 +285,38 @@
 TEST_F(CFX_CSSStyleSheetTest, ParseBorderRight) {
   LoadAndVerifyDecl(L"a { border-right: 2.5pc; }", {L"a"}, 1);
   VerifyFloat(CFX_CSSProperty::BorderRightWidth, 2.5,
-              CFX_CSSNumberValue::Unit::kPicas);
+              CFX_CSSNumber::Unit::kPicas);
 }
 
 TEST_F(CFX_CSSStyleSheetTest, ParseBorderTop) {
   LoadAndVerifyDecl(L"a { border-top: 2.5pc; }", {L"a"}, 1);
   VerifyFloat(CFX_CSSProperty::BorderTopWidth, 2.5,
-              CFX_CSSNumberValue::Unit::kPicas);
+              CFX_CSSNumber::Unit::kPicas);
 }
 
 TEST_F(CFX_CSSStyleSheetTest, ParseBorderBottom) {
   LoadAndVerifyDecl(L"a { border-bottom: 2.5pc; }", {L"a"}, 1);
   VerifyFloat(CFX_CSSProperty::BorderBottomWidth, 2.5,
-              CFX_CSSNumberValue::Unit::kPicas);
+              CFX_CSSNumber::Unit::kPicas);
 }
 
 TEST_F(CFX_CSSStyleSheetTest, ParseWithCommentsInSelector) {
   LoadAndVerifyDecl(L"/**{*/a/**}*/ { border-bottom: 2.5pc; }", {L"a"}, 1);
   VerifyFloat(CFX_CSSProperty::BorderBottomWidth, 2.5,
-              CFX_CSSNumberValue::Unit::kPicas);
+              CFX_CSSNumber::Unit::kPicas);
 }
 
 TEST_F(CFX_CSSStyleSheetTest, ParseWithCommentsInProperty) {
   LoadAndVerifyDecl(L"a { /*}*/border-bottom: 2.5pc; }", {L"a"}, 1);
   VerifyFloat(CFX_CSSProperty::BorderBottomWidth, 2.5,
-              CFX_CSSNumberValue::Unit::kPicas);
+              CFX_CSSNumber::Unit::kPicas);
 }
 
 TEST_F(CFX_CSSStyleSheetTest, ParseWithCommentsInValue) {
   LoadAndVerifyDecl(L"a { border-bottom: /*;*/2.5pc;/* color:red;*/ }", {L"a"},
                     1);
   VerifyFloat(CFX_CSSProperty::BorderBottomWidth, 2.5,
-              CFX_CSSNumberValue::Unit::kPicas);
+              CFX_CSSNumber::Unit::kPicas);
 }
 
 TEST_F(CFX_CSSStyleSheetTest, ParseWithUnterminatedCommentInSelector) {
diff --git a/core/fxcrt/css/cfx_cssvaluelistparser.cpp b/core/fxcrt/css/cfx_cssvaluelistparser.cpp
index 9c6dce8..ac5471e 100644
--- a/core/fxcrt/css/cfx_cssvaluelistparser.cpp
+++ b/core/fxcrt/css/cfx_cssvaluelistparser.cpp
@@ -11,55 +11,58 @@
 #include "core/fxcrt/fx_extension.h"
 #include "core/fxcrt/fx_system.h"
 
-CFX_CSSValueListParser::CFX_CSSValueListParser(const wchar_t* psz,
-                                               size_t nLen,
+CFX_CSSValueListParser::CFX_CSSValueListParser(WideStringView list,
                                                wchar_t separator)
-    : m_Separator(separator), m_pCur(psz), m_pEnd(psz + nLen) {
-  DCHECK(psz);
-  DCHECK_NE(nLen, 0);
+    : m_Separator(separator),
+      m_pCur(list.unterminated_c_str()),
+      m_pEnd(list.unterminated_c_str() + list.GetLength()) {
+  DCHECK_NE(m_pCur, m_pEnd);
 }
 
-bool CFX_CSSValueListParser::NextValue(CFX_CSSValue::PrimitiveType* eType,
-                                       const wchar_t** pStart,
-                                       size_t* nLength) {
-  while (m_pCur < m_pEnd && (*m_pCur <= ' ' || *m_pCur == m_Separator))
+std::optional<CFX_CSSValueListParser::Result>
+CFX_CSSValueListParser::NextValue() {
+  while (m_pCur < m_pEnd && (*m_pCur <= ' ' || *m_pCur == m_Separator)) {
     ++m_pCur;
-
-  if (m_pCur >= m_pEnd)
-    return false;
-
-  *eType = CFX_CSSValue::PrimitiveType::kUnknown;
-  *pStart = m_pCur;
-  *nLength = 0;
+  }
+  if (m_pCur >= m_pEnd) {
+    return std::nullopt;
+  }
+  auto eType = CFX_CSSValue::PrimitiveType::kUnknown;
+  const wchar_t* pStart = m_pCur;
+  size_t nLength = 0;
   wchar_t wch = *m_pCur;
   if (wch == '#') {
-    *nLength = SkipToChar(' ');
-    if (*nLength == 4 || *nLength == 7)
-      *eType = CFX_CSSValue::PrimitiveType::kRGB;
+    nLength = SkipToChar(' ');
+    if (nLength == 4 || nLength == 7) {
+      eType = CFX_CSSValue::PrimitiveType::kRGB;
+    }
   } else if (FXSYS_IsDecimalDigit(wch) || wch == '.' || wch == '-' ||
              wch == '+') {
-    while (m_pCur < m_pEnd && (*m_pCur > ' ' && *m_pCur != m_Separator))
+    while (m_pCur < m_pEnd && (*m_pCur > ' ' && *m_pCur != m_Separator)) {
       ++m_pCur;
-
-    *nLength = m_pCur - *pStart;
-    *eType = CFX_CSSValue::PrimitiveType::kNumber;
+    }
+    nLength = m_pCur - pStart;
+    eType = CFX_CSSValue::PrimitiveType::kNumber;
   } else if (wch == '\"' || wch == '\'') {
-    ++(*pStart);
-    m_pCur++;
-    *nLength = SkipToChar(wch);
-    m_pCur++;
-    *eType = CFX_CSSValue::PrimitiveType::kString;
+    ++pStart;
+    ++m_pCur;
+    nLength = SkipToChar(wch);
+    ++m_pCur;
+    eType = CFX_CSSValue::PrimitiveType::kString;
   } else if (m_pEnd - m_pCur > 5 && m_pCur[3] == '(') {
     if (FXSYS_wcsnicmp(L"rgb", m_pCur, 3) == 0) {
-      *nLength = SkipToChar(')') + 1;
-      m_pCur++;
-      *eType = CFX_CSSValue::PrimitiveType::kRGB;
+      nLength = SkipToChar(')') + 1;
+      ++m_pCur;
+      eType = CFX_CSSValue::PrimitiveType::kRGB;
     }
   } else {
-    *nLength = SkipToCharMatchingParens(m_Separator);
-    *eType = CFX_CSSValue::PrimitiveType::kString;
+    nLength = SkipToCharMatchingParens(m_Separator);
+    eType = CFX_CSSValue::PrimitiveType::kString;
   }
-  return m_pCur <= m_pEnd && *nLength > 0;
+  if (m_pCur <= m_pEnd && nLength > 0) {
+    return Result{eType, WideStringView(pStart, nLength)};
+  }
+  return std::nullopt;
 }
 
 size_t CFX_CSSValueListParser::SkipToChar(wchar_t wch) {
diff --git a/core/fxcrt/css/cfx_cssvaluelistparser.h b/core/fxcrt/css/cfx_cssvaluelistparser.h
index 050d002..e6deb88 100644
--- a/core/fxcrt/css/cfx_cssvaluelistparser.h
+++ b/core/fxcrt/css/cfx_cssvaluelistparser.h
@@ -9,15 +9,21 @@
 
 #include <stdint.h>
 
+#include <optional>
+
 #include "core/fxcrt/css/cfx_cssvalue.h"
+#include "core/fxcrt/widestring.h"
 
 class CFX_CSSValueListParser {
  public:
-  CFX_CSSValueListParser(const wchar_t* psz, size_t nLen, wchar_t separator);
+  struct Result {
+    CFX_CSSValue::PrimitiveType type = CFX_CSSValue::PrimitiveType::kUnknown;
+    WideStringView string_view;
+  };
 
-  bool NextValue(CFX_CSSValue::PrimitiveType* eType,
-                 const wchar_t** pStart,
-                 size_t* nLength);
+  CFX_CSSValueListParser(WideStringView list, wchar_t separator);
+
+  std::optional<Result> NextValue();
   void UseCommaSeparator() { m_Separator = ','; }
 
  private:
diff --git a/core/fxcrt/css/cfx_cssvaluelistparser_unittest.cpp b/core/fxcrt/css/cfx_cssvaluelistparser_unittest.cpp
index 93d0e4a..f8e6e60 100644
--- a/core/fxcrt/css/cfx_cssvaluelistparser_unittest.cpp
+++ b/core/fxcrt/css/cfx_cssvaluelistparser_unittest.cpp
@@ -12,130 +12,132 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 TEST(CFX_CSSValueListParserTest, rgb_short) {
-  CFX_CSSValue::PrimitiveType type;
-  const wchar_t* start;
-  size_t len;
+  auto parser = std::make_unique<CFX_CSSValueListParser>(L"#abc", L' ');
+  auto maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kRGB, maybe_next.value().type);
+  EXPECT_EQ(L"#abc", maybe_next.value().string_view);
+  EXPECT_FALSE(parser->NextValue());
 
-  auto parser = std::make_unique<CFX_CSSValueListParser>(L"#abc", 4, L' ');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kRGB, type);
-  EXPECT_EQ(L"#abc", WideString(start, len));
-  EXPECT_FALSE(parser->NextValue(&type, &start, &len));
+  parser = std::make_unique<CFX_CSSValueListParser>(L"#abcdef", L' ');
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kRGB, maybe_next.value().type);
+  EXPECT_EQ(L"#abcdef", maybe_next.value().string_view);
 
-  parser = std::make_unique<CFX_CSSValueListParser>(L"#abcdef", 7, L' ');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kRGB, type);
-  EXPECT_EQ(L"#abcdef", WideString(start, len));
-  EXPECT_FALSE(parser->NextValue(&type, &start, &len));
+  parser = std::make_unique<CFX_CSSValueListParser>(L"rgb(1, 255, 4)", L' ');
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kRGB, maybe_next.value().type);
+  EXPECT_EQ(L"rgb(1, 255, 4)", maybe_next.value().string_view);
 
-  parser =
-      std::make_unique<CFX_CSSValueListParser>(L"rgb(1, 255, 4)", 14, L' ');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kRGB, type);
-  EXPECT_EQ(L"rgb(1, 255, 4)", WideString(start, len));
-
-  parser = std::make_unique<CFX_CSSValueListParser>(L"#abcdefghij", 11, L' ');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kUnknown, type);
-  EXPECT_EQ(L"#abcdefghij", WideString(start, len));
-  EXPECT_FALSE(parser->NextValue(&type, &start, &len));
+  parser = std::make_unique<CFX_CSSValueListParser>(L"#abcdefghij", L' ');
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kUnknown, maybe_next.value().type);
+  EXPECT_EQ(L"#abcdefghij", maybe_next.value().string_view);
+  EXPECT_FALSE(parser->NextValue());
 }
 
 TEST(CFX_CSSValueListParserTest, number_parsing) {
-  CFX_CSSValue::PrimitiveType type;
-  const wchar_t* start;
-  size_t len;
+  auto parser = std::make_unique<CFX_CSSValueListParser>(L"1234", L' ');
+  auto maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, maybe_next.value().type);
+  EXPECT_EQ(L"1234", maybe_next.value().string_view);
 
-  auto parser = std::make_unique<CFX_CSSValueListParser>(L"1234", 4, L' ');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, type);
-  EXPECT_EQ(L"1234", WideString(start, len));
+  parser = std::make_unique<CFX_CSSValueListParser>(L"-1234", L' ');
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, maybe_next.value().type);
+  EXPECT_EQ(L"-1234", maybe_next.value().string_view);
 
-  parser = std::make_unique<CFX_CSSValueListParser>(L"-1234", 5, L' ');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, type);
-  EXPECT_EQ(L"-1234", WideString(start, len));
+  parser = std::make_unique<CFX_CSSValueListParser>(L"+1234", L' ');
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, maybe_next.value().type);
+  EXPECT_EQ(L"+1234", maybe_next.value().string_view);
 
-  parser = std::make_unique<CFX_CSSValueListParser>(L"+1234", 5, L' ');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, type);
-  EXPECT_EQ(L"+1234", WideString(start, len));
+  parser = std::make_unique<CFX_CSSValueListParser>(L".1234", L' ');
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, maybe_next.value().type);
+  EXPECT_EQ(L".1234", maybe_next.value().string_view);
 
-  parser = std::make_unique<CFX_CSSValueListParser>(L".1234", 5, L' ');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, type);
-  EXPECT_EQ(L".1234", WideString(start, len));
-
-  parser = std::make_unique<CFX_CSSValueListParser>(L"4321.1234", 9, L' ');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, type);
-  EXPECT_EQ(L"4321.1234", WideString(start, len));
+  parser = std::make_unique<CFX_CSSValueListParser>(L"4321.1234", L' ');
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, maybe_next.value().type);
+  EXPECT_EQ(L"4321.1234", maybe_next.value().string_view);
 
   // TODO(dsinclair): These should probably fail but currently don't.
-  parser = std::make_unique<CFX_CSSValueListParser>(L"4321.12.34", 10, L' ');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, type);
-  EXPECT_EQ(L"4321.12.34", WideString(start, len));
+  parser = std::make_unique<CFX_CSSValueListParser>(L"4321.12.34", L' ');
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, maybe_next.value().type);
+  EXPECT_EQ(L"4321.12.34", maybe_next.value().string_view);
 
-  parser = std::make_unique<CFX_CSSValueListParser>(L"43a1.12.34", 10, L' ');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, type);
-  EXPECT_EQ(L"43a1.12.34", WideString(start, len));
+  parser = std::make_unique<CFX_CSSValueListParser>(L"43a1.12.34", L' ');
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, maybe_next.value().type);
+  EXPECT_EQ(L"43a1.12.34", maybe_next.value().string_view);
 }
 
 TEST(CFX_CSSValueListParserTest, string_parsing) {
-  CFX_CSSValue::PrimitiveType type;
-  const wchar_t* start;
-  size_t len;
-
-  auto parser = std::make_unique<CFX_CSSValueListParser>(L"'string'", 8, L' ');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kString, type);
-  EXPECT_EQ(L"string", WideString(start, len));
+  auto parser = std::make_unique<CFX_CSSValueListParser>(L"'string'", L' ');
+  auto maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kString, maybe_next.value().type);
+  EXPECT_EQ(L"string", maybe_next.value().string_view);
 
   parser =
-      std::make_unique<CFX_CSSValueListParser>(L"\"another string\"", 16, L' ');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kString, type);
-  EXPECT_EQ(L"another string", WideString(start, len));
+      std::make_unique<CFX_CSSValueListParser>(L"\"another string\"", L' ');
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kString, maybe_next.value().type);
+  EXPECT_EQ(L"another string", maybe_next.value().string_view);
 
-  parser = std::make_unique<CFX_CSSValueListParser>(L"standalone", 10, L' ');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kString, type);
-  EXPECT_EQ(L"standalone", WideString(start, len));
+  parser = std::make_unique<CFX_CSSValueListParser>(L"standalone", L' ');
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kString, maybe_next.value().type);
+  EXPECT_EQ(L"standalone", maybe_next.value().string_view);
 }
 
 TEST(CFX_CSSValueListParserTest, multiparsing) {
-  CFX_CSSValue::PrimitiveType type;
-  const wchar_t* start;
-  size_t len;
+  auto parser = std::make_unique<CFX_CSSValueListParser>(L"1, 2, 3", L',');
+  auto maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, maybe_next.value().type);
+  EXPECT_EQ(L"1", maybe_next.value().string_view);
 
-  auto parser = std::make_unique<CFX_CSSValueListParser>(L"1, 2, 3", 7, L',');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, type);
-  EXPECT_EQ(L"1", WideString(start, len));
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, maybe_next.value().type);
+  EXPECT_EQ(L"2", maybe_next.value().string_view);
 
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, type);
-  EXPECT_EQ(L"2", WideString(start, len));
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, maybe_next.value().type);
+  EXPECT_EQ(L"3", maybe_next.value().string_view);
 
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, type);
-  EXPECT_EQ(L"3", WideString(start, len));
+  EXPECT_FALSE(parser->NextValue());
 
-  EXPECT_FALSE(parser->NextValue(&type, &start, &len));
+  parser =
+      std::make_unique<CFX_CSSValueListParser>(L"'str', rgb(1, 2, 3), 4", L',');
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kString, maybe_next.value().type);
+  EXPECT_EQ(L"str", maybe_next.value().string_view);
 
-  parser = std::make_unique<CFX_CSSValueListParser>(L"'str', rgb(1, 2, 3), 4",
-                                                    22, L',');
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kString, type);
-  EXPECT_EQ(L"str", WideString(start, len));
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kRGB, maybe_next.value().type);
+  EXPECT_EQ(L"rgb(1, 2, 3)", maybe_next.value().string_view);
 
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kRGB, type);
-  EXPECT_EQ(L"rgb(1, 2, 3)", WideString(start, len));
-
-  EXPECT_TRUE(parser->NextValue(&type, &start, &len));
-  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, type);
-  EXPECT_EQ(L"4", WideString(start, len));
+  maybe_next = parser->NextValue();
+  ASSERT_TRUE(maybe_next.has_value());
+  EXPECT_EQ(CFX_CSSValue::PrimitiveType::kNumber, maybe_next.value().type);
+  EXPECT_EQ(L"4", maybe_next.value().string_view);
 }