diff options
author | Timothy Flynn <trflynn89@pm.me> | 2021-07-19 14:36:30 -0400 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-07-22 09:10:44 +0200 |
commit | eaa1360eee1c9276310074f1087fbb5ac733b55c (patch) | |
tree | 44cf67bc3c74e55ea6eb1bf0108aa41bbd4e8e22 /Userland/Libraries | |
parent | ef2ff5f88bc7a887593a7a785ccf7480ab354a43 (diff) | |
download | serenity-eaa1360eee1c9276310074f1087fbb5ac733b55c.zip |
LibJS: Implement StringPad abstract operation with UTF-16 code units
Affects String.prototype.padStart and String.prototype.padEnd.
Diffstat (limited to 'Userland/Libraries')
3 files changed, 51 insertions, 7 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp index 36fa791af3..12daf89f10 100644 --- a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -399,14 +399,19 @@ enum class PadPlacement { }; // 22.1.3.15.1 StringPad ( O, maxLength, fillString, placement ), https://tc39.es/ecma262/#sec-stringpad -static Value pad_string(GlobalObject& global_object, const String& string, PadPlacement placement) +static Value pad_string(GlobalObject& global_object, String const& string, PadPlacement placement) { auto& vm = global_object.vm(); + + auto utf16_string = AK::utf8_to_utf16(string); + Utf16View utf16_string_view { utf16_string }; + auto string_length = utf16_string_view.length_in_code_units(); + auto max_length = vm.argument(0).to_length(global_object); if (vm.exception()) return {}; - if (max_length <= string.length()) - return js_string(vm, string); + if (max_length <= string_length) + return js_string(vm, utf16_string_view); String fill_string = " "; if (!vm.argument(1).is_undefined()) { @@ -414,15 +419,22 @@ static Value pad_string(GlobalObject& global_object, const String& string, PadPl if (vm.exception()) return {}; if (fill_string.is_empty()) - return js_string(vm, string); + return js_string(vm, utf16_string_view); } - auto fill_length = max_length - string.length(); + auto utf16_fill_string = AK::utf8_to_utf16(fill_string); + Utf16View utf16_fill_view { utf16_fill_string }; + auto fill_code_units = utf16_fill_view.length_in_code_units(); + auto fill_length = max_length - string_length; StringBuilder filler_builder; - while (filler_builder.length() < fill_length) + for (size_t i = 0; i < fill_length / fill_code_units; ++i) filler_builder.append(fill_string); - auto filler = filler_builder.build().substring(0, fill_length); + + utf16_fill_view = utf16_fill_view.substring_view(0, fill_length % fill_code_units); + filler_builder.append(utf16_fill_view.to_utf8(Utf16View::AllowInvalidCodeUnits::Yes)); + + auto filler = filler_builder.build(); auto formatted = placement == PadPlacement::Start ? String::formatted("{}{}", filler, string) diff --git a/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.padEnd.js b/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.padEnd.js index a103084c3a..80d4d051fe 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.padEnd.js +++ b/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.padEnd.js @@ -16,3 +16,19 @@ test("basic functionality", () => { expect(s.padEnd(10, "bar")).toBe("foobarbarb"); expect(s.padEnd(10, "123456789")).toBe("foo1234567"); }); + +test("UTF-16", () => { + var s = "😀"; + expect(s).toHaveLength(2); + expect(s.padEnd(-1)).toBe("😀"); + expect(s.padEnd(0)).toBe("😀"); + expect(s.padEnd(1)).toBe("😀"); + expect(s.padEnd(2)).toBe("😀"); + expect(s.padEnd(3)).toBe("😀 "); + expect(s.padEnd(10)).toBe("😀 "); + + expect(s.padEnd(2, "😀")).toBe("😀"); + expect(s.padEnd(3, "😀")).toBe("😀\ud83d"); + expect(s.padEnd(4, "😀")).toBe("😀😀"); + expect(s.padEnd(5, "😀")).toBe("😀😀\ud83d"); +}); diff --git a/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.padStart.js b/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.padStart.js index a2f0f0b710..e290f11772 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.padStart.js +++ b/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.padStart.js @@ -16,3 +16,19 @@ test("basic functionality", () => { expect(s.padStart(10, "bar")).toBe("barbarbfoo"); expect(s.padStart(10, "123456789")).toBe("1234567foo"); }); + +test("UTF-16", () => { + var s = "😀"; + expect(s).toHaveLength(2); + expect(s.padStart(-1)).toBe("😀"); + expect(s.padStart(0)).toBe("😀"); + expect(s.padStart(1)).toBe("😀"); + expect(s.padStart(2)).toBe("😀"); + expect(s.padStart(3)).toBe(" 😀"); + expect(s.padStart(10)).toBe(" 😀"); + + expect(s.padStart(2, "😀")).toBe("😀"); + expect(s.padStart(3, "😀")).toBe("\ud83d😀"); + expect(s.padStart(4, "😀")).toBe("😀😀"); + expect(s.padStart(5, "😀")).toBe("😀\ud83d😀"); +}); |