LibWeb: Implement chardetng-based encoding detection for HTML parsing

This commit is contained in:
Martin Chrástek 2026-05-23 11:00:51 +02:00 committed by Shannon Booth
parent a404efa999
commit cd3c72dfda
101 changed files with 1077 additions and 18 deletions

21
Cargo.lock generated
View file

@ -139,6 +139,17 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "chardetng"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13de944a44b5064ee5d3a5ceccc49a41bfec50f2580e66f82e87703acdb88b53"
dependencies = [
"cfg-if",
"encoding_rs",
"memchr",
]
[[package]]
name = "clap"
version = "4.6.0"
@ -304,6 +315,15 @@ dependencies = [
"syn",
]
[[package]]
name = "encoding_rs"
version = "0.8.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
dependencies = [
"cfg-if",
]
[[package]]
name = "equivalent"
version = "1.0.2"
@ -597,6 +617,7 @@ name = "libweb_rust"
version = "0.1.0"
dependencies = [
"cbindgen",
"chardetng",
"libweb_html_tokenizer",
]

View file

@ -1276,10 +1276,12 @@ if(NOT BUILD_SHARED_LIBS)
# POST_BUILD steps don't track inputs, so when libweb_rust.a changes
# ninja leaves liblagom-web.a alone and the merged archive ends up with
# stale Rust objects. Force the C++ FFI bridge file to depend on the
# Rust archive: when it changes, RustTokenizer.cpp recompiles, LibWeb
# re-archives, and POST_BUILD re-merges the fresh Rust objects.
# stale Rust objects. Force both FFI bridge files to depend on the
# Rust archive: when it changes, they recompile, LibWeb re-archives, and
# POST_BUILD re-merges the fresh Rust objects.
get_target_property(_libweb_rust_lib libweb_rust IMPORTED_LOCATION)
set_property(SOURCE CSS/Parser/RustTokenizer.cpp APPEND PROPERTY OBJECT_DEPENDS ${_libweb_rust_lib})
set_property(SOURCE HTML/Parser/HTMLEncodingDetection.cpp APPEND PROPERTY OBJECT_DEPENDS ${_libweb_rust_lib})
endif()
if (HAS_FONTCONFIG)

View file

@ -321,8 +321,7 @@ String FormAssociatedElement::form_action() const
return html_element.document().url_string();
}
auto document_base_url = html_element.document().base_url();
if (auto maybe_url = document_base_url.complete_url(form_action_attribute.value()); maybe_url.has_value())
if (auto maybe_url = html_element.document().encoding_parse_url(form_action_attribute.value()); maybe_url.has_value())
return maybe_url->to_string();
return {};
}

View file

@ -7,6 +7,7 @@
#include <LibWeb/Bindings/HTMLBaseElement.h>
#include <LibWeb/ContentSecurityPolicy/BlockingAlgorithms.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOMURL/DOMURL.h>
#include <LibWeb/HTML/HTMLBaseElement.h>
namespace Web::HTML {
@ -113,8 +114,8 @@ String HTMLBaseElement::href() const
auto url = attribute(AttributeNames::href).value_or(String {});
// 3. Let urlRecord be the result of parsing url with document's fallback base URL, and document's character encoding. (Thus, the base element isn't affected by other base elements or itself.)
// FIXME: Pass in document's character encoding.
auto url_record = document.fallback_base_url().complete_url(url);
auto encoding = document.encoding_or_default();
auto url_record = DOMURL::parse(url, document.fallback_base_url(), encoding.bytes_as_string_view());
// 4. If urlRecord is failure, return url.
if (!url_record.has_value())

View file

@ -680,7 +680,7 @@ String HTMLFormElement::action() const
return document().url_string();
}
if (auto maybe_url = document().base_url().complete_url(form_action_attribute.value()); maybe_url.has_value())
if (auto maybe_url = document().encoding_parse_url(form_action_attribute.value()); maybe_url.has_value())
return maybe_url->to_string();
return {};
}

View file

@ -8,12 +8,13 @@
#include <AK/CharacterTypes.h>
#include <AK/GenericLexer.h>
#include <AK/StringView.h>
#include <AK/Utf8View.h>
#include <LibTextCodec/Decoder.h>
#include <LibURL/URL.h>
#include <LibWeb/DOM/Attr.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/MIME.h>
#include <LibWeb/HTML/Parser/HTMLEncodingDetection.h>
#include <LibWeb/HTML/Parser/RustFFI.h>
#include <LibWeb/Infra/CharacterTypes.h>
namespace Web::HTML {
@ -459,6 +460,23 @@ Optional<ByteString> run_bom_sniff(ReadonlyBytes input)
return {};
}
ByteString extract_tld_hint(URL::URL const& url)
{
// Extract the rightmost DNS label from the URL's host as a TLD hint for chardetng.
// chardetng uses this to improve detection accuracy for country-code TLDs (.jp, .ru, .cn, …).
// Skip IP addresses — only domain names have meaningful TLDs.
auto const& maybe_host = url.host();
if (!maybe_host.has_value() || !maybe_host->is_domain())
return {};
auto host_string = maybe_host->serialize();
StringView host_view = host_string;
auto last_dot = host_view.find_last('.');
StringView tld_label = last_dot.has_value()
? host_view.substring_view(*last_dot + 1)
: host_view;
return tld_label.is_empty() ? ByteString {} : ByteString { tld_label };
}
// https://html.spec.whatwg.org/multipage/parsing.html#determining-the-character-encoding
ByteString run_encoding_sniffing_algorithm(DOM::Document& document, ReadonlyBytes input, Optional<MimeSniff::MimeType> maybe_mime_type)
{
@ -499,12 +517,27 @@ ByteString run_encoding_sniffing_algorithm(DOM::Document& document, ReadonlyByte
// 7. Otherwise, if the user agent has information on the likely encoding for this page, e.g. based on the encoding of the page when it was last visited, then return
// that encoding, with the confidence tentative.
// 8. FIXME: The user agent may attempt to autodetect the character encoding from applying frequency analysis or other algorithms to the data stream. Such algorithms
// may use information about the resource other than the resource's contents, including the address of the resource. If autodetection succeeds in determining a
// character encoding, and that encoding is a supported encoding, then return that encoding, with the confidence tentative. [UNIVCHARDET]
if (!Utf8View(StringView(input)).validate()) {
// FIXME: As soon as Locale is supported, this should sometimes return a different encoding based on the locale.
return "windows-1252";
// 8. The user agent may attempt to autodetect the character encoding from applying frequency analysis
// or other algorithms to the data stream. Such algorithms may use information about the resource
// other than the resource's contents, including the address of the resource.
// If autodetection succeeds in determining a character encoding, and that encoding is a supported encoding,
// then return that encoding, with the confidence tentative. [UNIVCHARDET]
auto tld_hint = extract_tld_hint(document.url());
u8 const* tld_data = tld_hint.is_empty() ? nullptr : reinterpret_cast<u8 const*>(tld_hint.characters());
size_t tld_size = tld_hint.length();
u8 const* encoding_name_ptr = nullptr;
size_t encoding_name_len = 0;
if (Parser::rust_detect_encoding(
input.data(), input.size(),
tld_data, tld_size,
&encoding_name_ptr, &encoding_name_len)) {
auto detected = StringView { reinterpret_cast<char const*>(encoding_name_ptr), encoding_name_len };
auto standardized = TextCodec::get_standardized_encoding(detected);
if (standardized.has_value())
return ByteString { standardized.value() };
}
// 9. Otherwise, return an implementation-defined or user-specified default character encoding, with the confidence tentative.

View file

@ -10,6 +10,7 @@
#include <AK/ByteString.h>
#include <AK/Optional.h>
#include <LibGC/Ptr.h>
#include <LibURL/URL.h>
#include <LibWeb/Forward.h>
#include <LibWeb/MimeSniff/MimeType.h>
@ -19,6 +20,13 @@ Optional<StringView> extract_character_encoding_from_meta_element(ByteString con
GC::Ptr<DOM::Attr> prescan_get_attribute(DOM::Document&, ReadonlyBytes input, size_t& position);
Optional<ByteString> run_prescan_byte_stream_algorithm(DOM::Document&, ReadonlyBytes input);
Optional<ByteString> run_bom_sniff(ReadonlyBytes input);
ByteString run_encoding_sniffing_algorithm(DOM::Document&, ReadonlyBytes input, Optional<MimeSniff::MimeType> maybe_mime_type = {});
// Extracts the rightmost DNS label from a URL's host as a TLD hint for chardetng.
// Returns an empty string if the host is absent or is an IP address. chardetng treats
// an absent/empty TLD as equivalent to ".com".
ByteString extract_tld_hint(URL::URL const&);
ByteString run_encoding_sniffing_algorithm(DOM::Document&, ReadonlyBytes input,
Optional<MimeSniff::MimeType> maybe_mime_type = {});
}

View file

@ -10,6 +10,7 @@ crate-type = ["staticlib"]
# python3 Meta/CMake/flatpak/generate-cargo-sources.py
[dependencies]
libweb_html_tokenizer = { path = "../HTML/Parser/Rust" }
chardetng = "1.0.0"
[build-dependencies]
cbindgen = "0.29"

View file

@ -24,7 +24,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let base_config = cbindgen::Config::from_file(manifest_dir.join("cbindgen.toml"))?;
// CSS tokenizer header — namespace Web::CSS::Parser::FFI, CSS types only.
let mut css_config = base_config;
let mut css_config = base_config.clone();
css_config.namespaces = Some(vec![
"Web".to_string(),
"CSS".to_string(),
@ -51,5 +51,27 @@ fn main() -> Result<(), Box<dyn Error>> {
},
);
// Encoding-detection header — namespace Web::HTML::Parser, rust_detect_encoding only.
let mut html_config = base_config;
html_config.namespaces = Some(vec!["Web".to_string(), "HTML".to_string(), "Parser".to_string()]);
html_config.export.include = vec!["rust_detect_encoding".to_string()];
cbindgen::generate_with_config(&manifest_dir, html_config).map_or_else(
|error| match error {
cbindgen::Error::ParseSyntaxError { .. } => {}
other => panic!("{other:?}"),
},
|bindings| {
let html_header_dir = out_dir.join("HTML").join("Parser");
std::fs::create_dir_all(&html_header_dir).unwrap();
bindings.write_to_file(html_header_dir.join("RustFFI.h"));
if ffi_out_dir != out_dir {
let dest = ffi_out_dir.join("HTML").join("Parser");
std::fs::create_dir_all(&dest).unwrap();
bindings.write_to_file(dest.join("RustFFI.h"));
}
},
);
Ok(())
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2026-present, the Ladybird developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
use chardetng::{EncodingDetector, Iso2022JpDetection, Utf8Detection};
/// Attempts to detect the character encoding of a byte stream using frequency analysis.
///
/// This implements step 8 of the WHATWG encoding sniffing algorithm:
/// https://html.spec.whatwg.org/multipage/parsing.html#determining-the-character-encoding
///
/// # Safety
/// - `input` and `input_len` must describe a valid byte slice (or `input` may be null if
/// `input_len` is 0)
/// - `tld` if non-null, must describe a valid byte slice of `tld_len` bytes containing the
/// rightmost DNS label of the resource's host, with no dots, no uppercase, and only ASCII
/// characters — these constraints are required by chardetng and must be validated by the caller
/// - `out_encoding_name` and `out_encoding_name_len` must be non-null writable pointers
///
/// Returns `true` if an encoding was detected (always, unless the input pointer is invalid).
/// When `true` is returned, `*out_encoding_name` is set to a pointer into a static ASCII
/// string naming the detected encoding (e.g. `"windows-1252"`, `"Shift_JIS"`), and
/// `*out_encoding_name_len` is set to its byte length. The pointer is valid for the lifetime
/// of the process. When `false` is returned (only on null-pointer error), the output pointers
/// are left unmodified.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_detect_encoding(
input: *const u8,
input_len: usize,
tld: *const u8,
tld_len: usize,
out_encoding_name: *mut *const u8,
out_encoding_name_len: *mut usize,
) -> bool {
unsafe {
crate::abort_on_panic(|| {
let Some(input_slice) = crate::bytes_from_raw(input, input_len) else {
return false;
};
let tld_slice = if tld.is_null() || tld_len == 0 {
None
} else {
Some(std::slice::from_raw_parts(tld, tld_len))
};
// Web browsers must use `Iso2022JpDetection::Deny` and `Utf8Detection::Deny` to
// prevent charset confusion attacks. See the chardetng documentation for details.
// Japanese pages using ISO-2022-JP will have declared it in a <meta> tag, which
// is detected in step 5 (prescan) before this step is reached.
// We always call `guess()` even for pure-ASCII input because chardetng still
// tracks ESC sequences (ISO-2022-JP uses 7-bit escapes) and returns the
// correct locale-based fallback (windows-1252 for generic TLD) with
// `Utf8Detection::Deny` when no distinctive non-ASCII encoding evidence is found.
let mut detector = EncodingDetector::new(Iso2022JpDetection::Deny);
// Pass last=false because the caller may only be providing a sniff-bytes prefix
// of a longer stream. chardetng docs: "If you want to perform detection on just
// the prefix of a longer stream, do not pass last=true."
detector.feed(input_slice, false);
// `Utf8Detection::Deny`: chardetng never returns UTF-8 here; valid-UTF-8
// content (including pure ASCII) gets the TLD-based default (windows-1252
// for generic), while content in a non-UTF-8 encoding gets that encoding.
let encoding = detector.guess(tld_slice, Utf8Detection::Deny);
let name = encoding.name().as_bytes();
*out_encoding_name = name.as_ptr();
*out_encoding_name_len = name.len();
true
})
}
}

View file

@ -8,6 +8,7 @@
mod rust_allocator;
mod css_tokenizer;
mod encoding_detection;
pub use libweb_html_tokenizer as html_tokenizer;

View file

@ -110,6 +110,13 @@
"sha256": "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801",
"dest": "cargo/vendor/cfg-if-1.0.4"
},
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/chardetng/chardetng-1.0.0.crate",
"sha256": "13de944a44b5064ee5d3a5ceccc49a41bfec50f2580e66f82e87703acdb88b53",
"dest": "cargo/vendor/chardetng-1.0.0"
},
{
"type": "archive",
"archive-type": "tar-gzip",
@ -229,6 +236,13 @@
"sha256": "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0",
"dest": "cargo/vendor/displaydoc-0.2.5"
},
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/encoding_rs/encoding_rs-0.8.35.crate",
"sha256": "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3",
"dest": "cargo/vendor/encoding_rs-0.8.35"
},
{
"type": "archive",
"archive-type": "tar-gzip",
@ -898,6 +912,7 @@
"echo '{\"files\": {}, \"package\": \"5abbd6eeda6885048d357edc66748eea6e0268e3dd11f326fff5bd248d779c26\"}' > cargo/vendor/calendrical_calculations-0.2.4/.cargo-checksum.json",
"echo '{\"files\": {}, \"package\": \"befbfd072a8e81c02f8c507aefce431fe5e7d051f83d48a23ffc9b9fe5a11799\"}' > cargo/vendor/cbindgen-0.29.2/.cargo-checksum.json",
"echo '{\"files\": {}, \"package\": \"9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801\"}' > cargo/vendor/cfg-if-1.0.4/.cargo-checksum.json",
"echo '{\"files\": {}, \"package\": \"13de944a44b5064ee5d3a5ceccc49a41bfec50f2580e66f82e87703acdb88b53\"}' > cargo/vendor/chardetng-1.0.0/.cargo-checksum.json",
"echo '{\"files\": {}, \"package\": \"b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351\"}' > cargo/vendor/clap-4.6.0/.cargo-checksum.json",
"echo '{\"files\": {}, \"package\": \"714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f\"}' > cargo/vendor/clap_builder-4.6.0/.cargo-checksum.json",
"echo '{\"files\": {}, \"package\": \"c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9\"}' > cargo/vendor/clap_lex-1.1.0/.cargo-checksum.json",
@ -915,6 +930,7 @@
"echo '{\"files\": {}, \"package\": \"4d55612bebcf16ff7306c8a6f5bdb6d45662b8aa1ee058ecce8807ad87db719b\"}' > cargo/vendor/cranelift-module-0.116.1/.cargo-checksum.json",
"echo '{\"files\": {}, \"package\": \"b8dee82f3f1f2c4cba9177f1cc5e350fe98764379bcd29340caa7b01f85076c7\"}' > cargo/vendor/cranelift-native-0.116.1/.cargo-checksum.json",
"echo '{\"files\": {}, \"package\": \"97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0\"}' > cargo/vendor/displaydoc-0.2.5/.cargo-checksum.json",
"echo '{\"files\": {}, \"package\": \"75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3\"}' > cargo/vendor/encoding_rs-0.8.35/.cargo-checksum.json",
"echo '{\"files\": {}, \"package\": \"877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f\"}' > cargo/vendor/equivalent-1.0.2/.cargo-checksum.json",
"echo '{\"files\": {}, \"package\": \"39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb\"}' > cargo/vendor/errno-0.3.14/.cargo-checksum.json",
"echo '{\"files\": {}, \"package\": \"2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649\"}' > cargo/vendor/fallible-iterator-0.3.0/.cargo-checksum.json",

View file

@ -1,4 +1,4 @@
PASS: inserted class argument invalidates descendant fanout | styleInvalidations=2, fullStyleInvalidations=0, elementStyleRecomputations=13, elementStyleNoopRecomputations=5, elementInheritedStyleRecomputations=0, elementInheritedStyleNoopRecomputations=0, hasAncestorWalkInvocations=1, hasInvalidationMetadataCandidates=1, hasMatchInvocations=2, hasResultCacheHits=0, hasResultCacheMisses=2
PASS: inserted class argument invalidates descendant fanout | styleInvalidations=2, fullStyleInvalidations=0, elementStyleRecomputations=14, elementStyleNoopRecomputations=5, elementInheritedStyleRecomputations=0, elementInheritedStyleNoopRecomputations=0, hasAncestorWalkInvocations=1, hasInvalidationMetadataCandidates=1, hasMatchInvocations=2, hasResultCacheHits=0, hasResultCacheMisses=2
PASS: removed class argument invalidates descendant fanout | styleInvalidations=2, fullStyleInvalidations=0, elementStyleRecomputations=3, elementStyleNoopRecomputations=2, elementInheritedStyleRecomputations=0, elementInheritedStyleNoopRecomputations=0, hasAncestorWalkInvocations=1, hasInvalidationMetadataCandidates=0, hasMatchInvocations=2, hasResultCacheHits=0, hasResultCacheMisses=2
PASS: inserted id argument invalidates descendant fanout | styleInvalidations=3, fullStyleInvalidations=0, elementStyleRecomputations=4, elementStyleNoopRecomputations=2, elementInheritedStyleRecomputations=0, elementInheritedStyleNoopRecomputations=0, hasAncestorWalkInvocations=1, hasInvalidationMetadataCandidates=1, hasMatchInvocations=2, hasResultCacheHits=0, hasResultCacheMisses=2
PASS: removed id argument invalidates descendant fanout | styleInvalidations=2, fullStyleInvalidations=0, elementStyleRecomputations=3, elementStyleNoopRecomputations=2, elementInheritedStyleRecomputations=0, elementInheritedStyleNoopRecomputations=0, hasAncestorWalkInvocations=1, hasInvalidationMetadataCandidates=0, hasMatchInvocations=2, hasResultCacheHits=0, hasResultCacheMisses=2

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Check detection result

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>ar ISO-8859-6</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>çÐÇ çè ÇÎÊÈÇÑ ÊÑåêÒ ÇäÃÍÑá.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "ISO-8859-6", 'Expected ISO-8859-6');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>ar windows-1256</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>åÐÇ åæ ÇÎÊÈÇÑ ÊÑãíÒ ÇáÃÍÑÝ.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1256", 'Expected windows-1256');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>ca windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Es tracta duna prova de codificació de caràcters.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,15 @@
<!doctype html>
<title>el ISO-8859-7</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Ðñüêåéôáé ãéá äïêéìÞ êùäéêïðïßçóçò ÷áñáêôÞñùí: ¶ñçò
<!-- I needed to work capital alpha with tonos into the test somehow... --></p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "ISO-8859-7", 'Expected ISO-8859-7');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,15 @@
<!doctype html>
<title>el windows-1253</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Ðñüêåéôáé ãéá äïêéìÞ êùäéêïðïßçóçò ÷áñáêôÞñùí: ¢ñçò
<!-- I needed to work capital alpha with tonos into the test somehow... --></p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1253", 'Expected windows-1253');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>en windows-1252 copyright sign</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Copyright © 2021</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>en windows-1252 euro sign</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>It costs €9.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>en windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Ive made an encoding test.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>es windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p></p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>es windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Nª Sª</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>es windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>n.º1</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>es windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>42.º</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>fa windows-1256</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Ç&#1740;ä &#1740;˜ ÊÓÊ ÑãÒ<C3A3>ÐÇÑ&#1740; ˜ÇÑǘÊÑ ÇÓÊ.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1256", 'Expected windows-1256');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>fi windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Tämä on merkkikoodaustesti.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>he ISO-8859-8</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>.íéååú ãåãé÷ ïçáî åäæ</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "ISO-8859-8", 'Expected ISO-8859-8');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>he windows-1255</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>æäå îáçï ÷éãåã úååéí.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1255", 'Expected windows-1255');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>is windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Þetta er kóðunarpróf á staf. Fyrir sum tungumál sem nota latneska stafi þurfum við meira inntak til að taka ákvörðunina.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>fi windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Nº1</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>it windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>42º</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>it windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>IIIª</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>it windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Questo è un test di codifica dei caratteri.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>ja EUC-JP</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>これは矢机悸赋です。</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "EUC-JP", 'Expected EUC-JP');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>ja ISO-2022-JP</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>$B$3$l$OJ8;z<B83$G$9!#(B</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252 due to ISO-2022-JP no longer getting detected');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>ja Shift_JIS</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>これは文字実験です。</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "Shift_JIS", 'Expected Shift_JIS');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>ja Shift_JIS half-width katakana</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>ʰÄÞ³ª±Ê°ÄÞ³ª±Ê°ÄÞ³ª±Ê°ÄÞ³ª±Ê°ÄÞ³ª±</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "Shift_JIS", 'Expected Shift_JIS');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>ko EUC-KR</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>이것은 문자 인코딩 테스트입니다.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "EUC-KR", 'Expected EUC-KR');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>lt windows-1257</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Tai simboliø kodavimo testas. Kai kurioms kalboms, naudojanèioms lotyniðkus raðmenis, mums reikia daugiau informacijos, kad galëtume priimti sprendimà.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1257", 'Expected windows-1257');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>lv windows-1257</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Ðis ir rakstzîmju kodçðanas tests. Daþâs valodâs, kurâs tiek izmantotas latîòu valodas burti, lçmuma pieòemðanai mums ir nepiecieðams vairâk ieguldîjuma.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1257", 'Expected windows-1257');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>nbsp even windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>No-break    spaces</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>nbsp odd windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>No-break      spaces</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>pl ISO-8859-2</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>To jest test kodowania znaków. W przypadku niektórych jêzyków, które u¿ywaj± znaków ³aciñskich, potrzebujemy wiêcej danych, aby podj±æ decyzjê.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "ISO-8859-2", 'Expected ISO-8859-2');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>pl windows-1250</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>To jest test kodowania znaków. W przypadku niektórych jêzyków, które u¿ywaj¹ znaków ³aciñskich, potrzebujemy wiêcej danych, aby podj¹æ decyzjê.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1250", 'Expected windows-1250');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>pt windows-1252</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Este é um teste de codificação de caracteres.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1252", 'Expected windows-1252');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>ru IBM866</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p><EFBFBD>â® â¥áâ ª®¤¨à®¢ª¨ ᨬ¢®«®¢.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "IBM866", 'Expected IBM866');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>ru ISO-8859-5</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>ÍâÞ âÕáâ ÚÞÔØàÞÒÚØ áØÜÒÞÛÞÒ.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "ISO-8859-5", 'Expected ISO-8859-5');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>th windows-874</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>¹Õè¤×Í¡Ò÷´Êͺ¡ÒÃà¢éÒÃËÑÊÍÑ¡¢ÃÐ</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-874", 'Expected windows-874');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>tr windows-1254</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Bu bir karakter kodlama testidir. Latince karakterleri kullanan bazý dillerde karar vermek için daha fazla girdiye ihtiyacýmýz var.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1254", 'Expected windows-1254');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>uk KOI8-U</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>ãÅ ÔÅÓÔ ÎÁ ËÏÄÕ×ÁÎÎÑ ÓÉÍ×Ï̦×.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "KOI8-U", 'Expected KOI8-U');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>uk windows-1251</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Öå òåñò íà êîäóâàííÿ ñèìâîë³â.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1251", 'Expected windows-1251');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>UTF-8</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>これは文字実験です。</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_not_equals(document.characterSet.toUpperCase(), "UTF-8", 'Must not detect UTF-8');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>vi windows-1258</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>Ðây laÌ môòt thýÒ nghiêòm maÞ hoìa kyì týò.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1258", 'Expected windows-1258');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>yi windows-1255</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>ãàÈñ àéæ àÇ èòñè ôÏàÇø ÷àÈãéøåðâ ôåï ëàÇøàÇ÷èòø.</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "windows-1255", 'Expected windows-1255');
}, "Check detection result");
done();
};
</script>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>zh Big5</title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<p>這是一個字符編碼測試。</p>
<script>
setup({explicit_done:true});
onload = function() {
test(function() {
assert_equals(document.characterSet, "Big5", 'Expected Big5');
}, "Check detection result");
done();
};
</script>

Some files were not shown because too many files have changed in this diff Show more