Compare commits

...

24 commits

Author SHA1 Message Date
sideshowbarker
792ece5e7c
Merge 928101482b into 001df24935 2024-11-21 14:29:44 +01:00
Pavel Shliak
001df24935 LibWebSocket: Clean up #include directives
Some checks are pending
CI / Lagom (false, NO_FUZZ, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (false, FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (true, NO_FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Push notes / build (push) Waiting to run
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Pavel Shliak
b60cb699a9 LibMedia: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Pavel Shliak
8d13115d9a LibCrypto: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Pavel Shliak
cd14b215d1 LibDNS: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Pavel Shliak
35764db0b7 LibWasm: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Pavel Shliak
caf7983039 LibHTTP: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Pavel Shliak
cdb54fe504 LibRegex: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Psychpsyo
7f989765f5 LibWeb: Fix MouseEvent position values
The clientX and clientY values are, as per the spec, the offset from
the viewport.
This makes them actually be that and also fixes up the calculations
for offsetX, offsetY, pageX and pageY.
I assume all of these got messed up in some sort of refactor in the
past.

The spec comment from the now-removed
compute_mouse_event_client_offset() function sadly has no convenient
place to be anymore so, for now, it is just gone as well.
Personally, I think it'd make sense to refactor a lot of this file so
that not every mouse event repeats a large chunk of (almost) identical
code. That way there'd be a nice place to put the comment without
repeating it all over the file.
But that is out of the scope of this PR.

Also: I know, offsetX and Y are not fully fixed yet, they still
don't ignore the element's CSS transforms but I am working on that
in a new PR.
2024-11-21 13:22:22 +01:00
Aliaksandr Kalenik
41c172c663 LibWeb: Allow custom properties in getPropertyPriority() 2024-11-21 13:16:08 +01:00
Aliaksandr Kalenik
ac5699c8fc LibWeb: Allow custom properties in CSSStyleDeclaration.removeProperty() 2024-11-21 13:16:08 +01:00
Aliaksandr Kalenik
ce26e5d757 LibWeb: Allow custom properties in CSSStyleDeclaration.getPropertyValue 2024-11-21 13:16:08 +01:00
Aliaksandr Kalenik
3a2cc1aa20 LibWeb: Allow custom properties in CSSStyleDeclaration.setProperty()
This change fixes unhoverable toolbar on https://excalidraw.com/
The problem was that React.js uses setProperty() to add style properties
specified in the "style" attribute in the virtual DOM, and we were
failing to add the CSS variable used to set the "pointer-events" value
to "all".
2024-11-21 13:16:08 +01:00
Aliaksandr Kalenik
0448d4d609 LibWeb: Update property_id_from_string() generator to handle ::Custom 2024-11-21 13:16:08 +01:00
Lucas CHOLLET
a1687854ab LibWeb/CSS: Use double in CSSHWB::to_color()
See previous the commit description for more details about the floating
points operations.

The hwb test cases in `css-color-functions` are now rendered identically
to what firefox does (I haven't checked the others tests, but they
aren't affected by this commit).
2024-11-21 11:59:44 +00:00
Lucas CHOLLET
d1120e1809 LibWeb: Make CSSColorValue resolvers return a double
Without this change the math in `CSSHWB::to_color()` is lacking some
precision to generate the correct value to hand to `Color::from_hsv()`.

More precisely, when converting `hwb(120 20 30)`, the HSV's value would
be calculated as `1 - .3`. However, it turns out that `1 - .3f != .7f`
and `1 - .3f` gives bad results down the road in `Color::from_hsv()`.

This example actually only requires `resolve_with_reference_value()` to
return a double. I changed the two others for symmetry.
2024-11-21 11:59:44 +00:00
Lucas CHOLLET
248e4bb517 LibGfx: Round values in Color::with_opacity()
`svg-gradient-userSpaceOnUse` is now rendered to something closer to
what firefox does, so it is at least some progress.
2024-11-21 11:59:44 +00:00
Lucas CHOLLET
b4ba65c6e5 LibGfx: Round values in Color::from_hsv() 2024-11-21 11:59:44 +00:00
devgianlu
009f328308 LibWeb: Implement ECDH.generateKey 2024-11-21 11:45:22 +01:00
Pavel Shliak
d55caff227 LibFileSystem: Fix Windows build
This reverts part of  b3c253e50f
2024-11-21 11:15:49 +01:00
Feng Yu
570c5f8df2 Documentation: Fix broken link in README 2024-11-21 10:42:45 +01:00
sideshowbarker
928101482b
LibWeb: Fix accessible-name computation for “encapsulation” cases
This change makes Ladybird correctly handle all “encapsulation” tests in
the https://wpt.fyi/results/accname/name/comp_host_language_label.html
set of tests in WPT.

Those all test the requirement that when computing the accessible name
for a <label>-ed form control, then any content (text content or
attribute values) from the control itself that would otherwise be
included in the accessible-name computation for it ancestor <label> must
instead be skipped and not included.

The HTML-AAM spec seems to try to achieve that result by expressing
specific steps for each particular type of form control. But what all
that reduces/optimizes/simplifies down to is just, “skip over self”.

Otherwise, without this change, Ladybird includes that “self” content
from those “encapsulated” elements when doing accessible-name
computation for the elements — which results in AT users hearing
unexpected extra content in the accessible names for those elements.
2024-11-21 05:28:27 +09:00
sideshowbarker
032396ba4d
LibWeb: Fix input@type=button|submit|reset accessible-name computation
This change makes Ladybird conform to the requirements in the HTML-AAM
spec at https://w3c.github.io/html-aam/#accname-computation for the
cases of HTML input@type=button, input@type=submit, and input@type=reset
elements. Otherwise, without this change, Ladybird fails to expose the
expected accessible names for those cases.
2024-11-20 06:55:04 +09:00
sideshowbarker
6ee54ca08a
LibWeb: Fix accessible-name computation for table, fieldset, image input
This change makes Ladybird conform to the requirements in the HTML-AAM
spec at https://w3c.github.io/html-aam/#accname-computation for the
cases of HTML table, fieldset, and input@type=image elements. Otherwise,
without this change, Ladybird fails to expose the expected accessible
names for those cases.
2024-11-20 06:55:01 +09:00
90 changed files with 1997 additions and 179 deletions

View file

@ -35,5 +35,5 @@ you are welcome to ask on [Discord](../README.md#get-in-touch-and-participate).
* [LibWeb: From Loading to Painting](LibWebFromLoadingToPainting.md)
* [LibWeb: Browsing Contexts and Navigables](BrowsingContextsAndNavigables.md)
* [How to Add an IDL File](AddNewIDLFile.md)
* [LibWeb Code Style & Patterns](Browser/Patterns.md)
* [LibWeb Code Style & Patterns](LibWebPatterns.md)
* [CSS Generated Files](CSSGeneratedFiles.md)

View file

@ -8,7 +8,6 @@
#include <AK/Time.h>
#include <AK/Types.h>
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
namespace Crypto::ASN1 {

View file

@ -7,7 +7,6 @@
#pragma once
#include <AK/BitmapView.h>
#include <AK/Result.h>
#include <AK/Types.h>
#include <LibCrypto/ASN1/ASN1.h>
#include <LibCrypto/BigInt/UnsignedBigInteger.h>

View file

@ -6,9 +6,8 @@
#pragma once
#include <AK/ByteBuffer.h>
#include <AK/Span.h>
#include <LibCrypto/ASN1/ASN1.h>
#include <LibCrypto/ASN1/DER.h>
namespace Crypto {

View file

@ -10,7 +10,6 @@
#include <AK/ByteString.h>
#include <AK/Endian.h>
#include <AK/Types.h>
#include <LibCrypto/Hash/HashFunction.h>
namespace Crypto::Authentication {

View file

@ -6,9 +6,8 @@
*/
#include "UnsignedBigIntegerAlgorithms.h"
#include <AK/BigIntBase.h>
#include <AK/BuiltinWrappers.h>
#include <AK/NumericLimits.h>
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
namespace Crypto {

View file

@ -7,7 +7,6 @@
#include "UnsignedBigIntegerAlgorithms.h"
#include <AK/BigIntBase.h>
#include <AK/BuiltinWrappers.h>
namespace Crypto {

View file

@ -9,7 +9,6 @@
#include <AK/Concepts.h>
#include <AK/Span.h>
#include <AK/String.h>
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
namespace Crypto {

View file

@ -9,7 +9,6 @@
#pragma once
#include <AK/BigIntBase.h>
#include <AK/ByteBuffer.h>
#include <AK/ByteString.h>
#include <AK/Concepts.h>
#include <AK/Span.h>

View file

@ -5,7 +5,6 @@
*/
#include <AK/Array.h>
#include <AK/NumericLimits.h>
#include <AK/Span.h>
#include <AK/Types.h>
#include <LibCrypto/Checksum/CRC32.h>

View file

@ -8,7 +8,6 @@
#pragma once
#include <AK/ByteString.h>
#include <AK/Vector.h>
#include <LibCrypto/Cipher/Cipher.h>
#include <LibCrypto/Cipher/Mode/CBC.h>
#include <LibCrypto/Cipher/Mode/CTR.h>

View file

@ -6,7 +6,7 @@
#pragma once
#include <AK/ByteBuffer.h>
#include <AK/Span.h>
namespace Crypto::Cipher {

View file

@ -7,7 +7,6 @@
#pragma once
#include <AK/Optional.h>
#include <AK/Span.h>
#include <AK/Types.h>

View file

@ -6,8 +6,6 @@
#pragma once
#include <AK/Random.h>
namespace Crypto::Curves {
class Curve25519 {

View file

@ -7,7 +7,6 @@
#pragma once
#include <AK/ByteBuffer.h>
#include <LibCrypto/Curves/EllipticCurve.h>
namespace Crypto::Curves {

View file

@ -5,7 +5,6 @@
*/
#include <AK/ByteReader.h>
#include <AK/Endian.h>
#include <AK/Random.h>
#include <LibCrypto/Curves/Curve25519.h>
#include <LibCrypto/Curves/X25519.h>

View file

@ -5,6 +5,7 @@
*/
#include <AK/Debug.h>
#include <AK/Random.h>
#include <LibCrypto/BigInt/Algorithms/UnsignedBigIntegerAlgorithms.h>
#include <LibCrypto/NumberTheory/ModularFunctions.h>

View file

@ -6,7 +6,6 @@
#pragma once
#include <AK/Random.h>
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
namespace Crypto::NumberTheory {

View file

@ -7,12 +7,10 @@
#pragma once
#include <AK/Base64.h>
#include <AK/MaybeOwned.h>
#include <AK/IPv4Address.h>
#include <AK/IPv6Address.h>
#include <AK/RedBlackTree.h>
#include <AK/Time.h>
#include <LibCore/Promise.h>
#include <LibCore/SocketAddress.h>
#include <LibURL/URL.h>
namespace DNS {
namespace Messages {

View file

@ -8,6 +8,7 @@
#include <AK/AtomicRefCounted.h>
#include <AK/HashTable.h>
#include <AK/MaybeOwned.h>
#include <AK/MemoryStream.h>
#include <AK/Random.h>
#include <AK/StringView.h>

View file

@ -15,6 +15,8 @@
# include <sys/disk.h>
#elif defined(AK_OS_LINUX)
# include <linux/fs.h>
#elif defined(AK_OS_WINDOWS)
# include <dirent.h>
#endif
// On Linux distros that use glibc `basename` is defined as a macro that expands to `__xpg_basename`, so we undefine it

View file

@ -400,7 +400,8 @@ public:
constexpr Color with_opacity(float opacity) const
{
return with_alpha(alpha() * opacity);
VERIFY(opacity >= 0 && opacity <= 1);
return with_alpha(static_cast<u8>(round(alpha() * opacity)));
}
constexpr Color darkened(float amount = 0.5f) const
@ -549,9 +550,9 @@ public:
break;
}
u8 out_r = (u8)(r * 255);
u8 out_g = (u8)(g * 255);
u8 out_b = (u8)(b * 255);
auto out_r = static_cast<u8>(round(r * 255));
auto out_g = static_cast<u8>(round(g * 255));
auto out_b = static_cast<u8>(round(b * 255));
return Color(out_r, out_g, out_b);
}

View file

@ -6,6 +6,8 @@
#pragma once
#include <AK/Assertions.h>
#include <AK/StdLibExtras.h>
#include <AK/Types.h>
#include <initializer_list>

View file

@ -8,7 +8,6 @@
#include <AK/Base64.h>
#include <AK/StringBuilder.h>
#include <LibHTTP/HttpRequest.h>
#include <LibURL/Parser.h>
namespace HTTP {

View file

@ -11,7 +11,6 @@
#include <AK/ByteString.h>
#include <AK/Noncopyable.h>
#include <AK/Optional.h>
#include <AK/Vector.h>
#include <LibCore/Forward.h>
#include <LibHTTP/HeaderMap.h>
#include <LibURL/URL.h>

View file

@ -7,8 +7,6 @@
#pragma once
#include <AK/ByteString.h>
#include <AK/HashMap.h>
#include <LibCore/NetworkResponse.h>
#include <LibHTTP/HeaderMap.h>

View file

@ -5,7 +5,6 @@
*/
#include "FFmpegLoader.h"
#include <AK/BitStream.h>
#include <AK/NumericLimits.h>
#include <LibCore/System.h>

View file

@ -13,7 +13,6 @@
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/samplefmt.h>
}
namespace Audio {

View file

@ -7,7 +7,6 @@
#include "PlaybackStream.h"
#include <AK/Platform.h>
#include <LibCore/ThreadedPromise.h>
#if defined(HAVE_PULSEAUDIO)
# include "PlaybackStreamPulseAudio.h"

View file

@ -9,12 +9,9 @@
#include "SampleFormats.h"
#include <AK/AtomicRefCounted.h>
#include <AK/Function.h>
#include <AK/Queue.h>
#include <AK/Time.h>
#include <LibCore/Forward.h>
#include <LibThreading/ConditionVariable.h>
#include <LibThreading/MutexProtected.h>
#include <LibThreading/Thread.h>
#include <LibCore/ThreadedPromise.h>
namespace Audio {

View file

@ -8,6 +8,9 @@
#include "PlaybackStream.h"
#include "PulseAudioWrappers.h"
#include <AK/Queue.h>
#include <LibThreading/ConditionVariable.h>
#include <LibThreading/Mutex.h>
namespace Audio {

View file

@ -8,7 +8,6 @@
#include "Forward.h"
#include "PlaybackStream.h"
#include "SampleFormats.h"
#include <AK/AtomicRefCounted.h>
#include <AK/Error.h>
#include <AK/NonnullRefPtr.h>

View file

@ -5,6 +5,7 @@
*/
#include "SampleFormats.h"
#include <AK/Assertions.h>
namespace Audio {

View file

@ -6,7 +6,6 @@
#pragma once
#include <AK/ByteString.h>
#include <AK/Types.h>
namespace Audio {

View file

@ -4,8 +4,8 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Math.h>
#include <AK/StdLibExtras.h>
#include <LibGfx/Matrix.h>
#include <LibGfx/Matrix3x3.h>
#include <LibGfx/Matrix4x4.h>
#include <LibMedia/Color/ColorPrimaries.h>
#include <LibMedia/Color/TransferCharacteristics.h>

View file

@ -7,6 +7,7 @@
#include <AK/Debug.h>
#include <AK/Function.h>
#include <AK/IntegralMath.h>
#include <AK/Math.h>
#include <AK/Optional.h>
#include <AK/Time.h>

View file

@ -7,9 +7,9 @@
#pragma once
#include <AK/IntegralMath.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/NonnullRefPtr.h>
#include <AK/Optional.h>
#include <AK/OwnPtr.h>
#include <LibCore/MappedFile.h>
#include <LibMedia/DecoderError.h>

View file

@ -13,7 +13,6 @@
#include <AK/Time.h>
#include <LibCore/SharedCircularQueue.h>
#include <LibGfx/Bitmap.h>
#include <LibMedia/Containers/Matroska/Document.h>
#include <LibMedia/Demuxer.h>
#include <LibThreading/ConditionVariable.h>
#include <LibThreading/Mutex.h>

View file

@ -4,8 +4,8 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/FixedArray.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/OwnPtr.h>
#include <LibMedia/Color/ColorConverter.h>
#include "VideoFrame.h"

View file

@ -6,8 +6,6 @@
#pragma once
#include <AK/ByteBuffer.h>
#include <AK/FixedArray.h>
#include <AK/Time.h>
#include <LibGfx/Bitmap.h>
#include <LibGfx/Size.h>

View file

@ -8,15 +8,11 @@
#include "RegexBytecodeStreamOptimizer.h"
#include "RegexMatch.h"
#include "RegexOptions.h"
#include <AK/Concepts.h>
#include <AK/DisjointChunks.h>
#include <AK/Forward.h>
#include <AK/HashMap.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/OwnPtr.h>
#include <AK/Traits.h>
#include <AK/TypeCasts.h>
#include <AK/Types.h>
#include <AK/Vector.h>

View file

@ -8,7 +8,6 @@
#include <AK/Assertions.h>
#include <AK/Debug.h>
#include <AK/Format.h>
#include <stdio.h>
namespace regex {

View file

@ -13,9 +13,6 @@
#include <AK/Forward.h>
#include <AK/GenericLexer.h>
#include <AK/HashMap.h>
#include <AK/Types.h>
#include <AK/Utf32View.h>
#include <AK/Vector.h>
#include <ctype.h>

View file

@ -16,7 +16,6 @@
#include <AK/StringBuilder.h>
#include <AK/StringUtils.h>
#include <AK/TemporaryChange.h>
#include <AK/Utf16View.h>
#include <LibUnicode/CharacterTypes.h>
namespace regex {

View file

@ -12,7 +12,6 @@
#include "RegexOptions.h"
#include <AK/Forward.h>
#include <AK/StringBuilder.h>
#include <AK/Types.h>
#include <AK/Vector.h>
#include <LibUnicode/Forward.h>

View file

@ -7,6 +7,7 @@
#include <AK/Debug.h>
#include <AK/Endian.h>
#include <AK/MemoryStream.h>
#include <AK/Random.h>
#include <LibCore/EventLoop.h>
#include <LibCore/Timer.h>
#include <LibTLS/TLSv12.h>

View file

@ -9,8 +9,7 @@
#include <AK/Function.h>
#include <AK/HashMap.h>
#include <AK/HashTable.h>
#include <AK/OwnPtr.h>
#include <AK/Result.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/StackInfo.h>
#include <AK/UFixedBigInt.h>
#include <LibWasm/Types.h>

View file

@ -5,7 +5,6 @@
*/
#include <AK/HashTable.h>
#include <AK/Result.h>
#include <AK/SourceLocation.h>
#include <AK/TemporaryChange.h>
#include <AK/Try.h>

View file

@ -9,7 +9,6 @@
#include <AK/Endian.h>
#include <AK/LEB128.h>
#include <AK/MemoryStream.h>
#include <AK/ScopeGuard.h>
#include <AK/ScopeLogger.h>
#include <AK/UFixedBigInt.h>
#include <LibWasm/Types.h>

View file

@ -8,13 +8,10 @@
#include <AK/Debug.h>
#include <AK/FlyString.h>
#include <AK/Random.h>
#include <AK/SourceLocation.h>
#include <AK/Span.h>
#include <AK/Tuple.h>
#include <LibCore/File.h>
#include <LibWasm/AbstractMachine/Interpreter.h>
#include <LibWasm/Printer/Printer.h>
#include <LibWasm/AbstractMachine/Configuration.h>
#include <LibWasm/Wasi.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <time.h>

View file

@ -102,8 +102,13 @@ Optional<StyleProperty> PropertyOwningCSSStyleDeclaration::property(PropertyID p
}
// https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-setproperty
WebIDL::ExceptionOr<void> PropertyOwningCSSStyleDeclaration::set_property(PropertyID property_id, StringView value, StringView priority)
WebIDL::ExceptionOr<void> PropertyOwningCSSStyleDeclaration::set_property(StringView property_name, StringView value, StringView priority)
{
auto maybe_property_id = property_id_from_string(property_name);
if (!maybe_property_id.has_value())
return {};
auto property_id = maybe_property_id.value();
// 1. If the computed flag is set, then throw a NoModificationAllowedError exception.
// NOTE: This is handled by the virtual override in ResolvedCSSStyleDeclaration.
@ -114,7 +119,7 @@ WebIDL::ExceptionOr<void> PropertyOwningCSSStyleDeclaration::set_property(Proper
// 3. If value is the empty string, invoke removeProperty() with property as argument and return.
if (value.is_empty()) {
MUST(remove_property(property_id));
MUST(remove_property(property_name));
return {};
}
@ -146,10 +151,22 @@ WebIDL::ExceptionOr<void> PropertyOwningCSSStyleDeclaration::set_property(Proper
}
// 9. Otherwise,
else {
// let updated be the result of set the CSS declaration property with value component value list,
// with the important flag set if priority is not the empty string, and unset otherwise,
// and with the list of declarations being the declarations.
updated = set_a_css_declaration(property_id, *component_value_list, !priority.is_empty() ? Important::Yes : Important::No);
if (property_id == PropertyID::Custom) {
auto custom_name = FlyString::from_utf8_without_validation(property_name.bytes());
StyleProperty style_property {
.important = !priority.is_empty() ? Important::Yes : Important::No,
.property_id = property_id,
.value = component_value_list.release_nonnull(),
.custom_name = custom_name,
};
m_custom_properties.set(custom_name, style_property);
updated = true;
} else {
// let updated be the result of set the CSS declaration property with value component value list,
// with the important flag set if priority is not the empty string, and unset otherwise,
// and with the list of declarations being the declarations.
updated = set_a_css_declaration(property_id, *component_value_list, !priority.is_empty() ? Important::Yes : Important::No);
}
}
// 10. If updated is true, update style attribute for the CSS declaration block.
@ -160,8 +177,12 @@ WebIDL::ExceptionOr<void> PropertyOwningCSSStyleDeclaration::set_property(Proper
}
// https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-removeproperty
WebIDL::ExceptionOr<String> PropertyOwningCSSStyleDeclaration::remove_property(PropertyID property_id)
WebIDL::ExceptionOr<String> PropertyOwningCSSStyleDeclaration::remove_property(StringView property_name)
{
auto property_id = property_id_from_string(property_name);
if (!property_id.has_value())
return String {};
// 1. If the computed flag is set, then throw a NoModificationAllowedError exception.
// NOTE: This is handled by the virtual override in ResolvedCSSStyleDeclaration.
@ -169,8 +190,7 @@ WebIDL::ExceptionOr<String> PropertyOwningCSSStyleDeclaration::remove_property(P
// NOTE: We've already converted it to a PropertyID enum value.
// 3. Let value be the return value of invoking getPropertyValue() with property as argument.
// FIXME: The trip through string_from_property_id() here is silly.
auto value = get_property_value(string_from_property_id(property_id));
auto value = get_property_value(property_name);
// 4. Let removed be false.
bool removed = false;
@ -180,7 +200,12 @@ WebIDL::ExceptionOr<String> PropertyOwningCSSStyleDeclaration::remove_property(P
// 2. Remove that CSS declaration and let removed be true.
// 6. Otherwise, if property is a case-sensitive match for a property name of a CSS declaration in the declarations, remove that CSS declaration and let removed be true.
removed = m_properties.remove_first_matching([&](auto& entry) { return entry.property_id == property_id; });
if (property_id == PropertyID::Custom) {
auto custom_name = FlyString::from_utf8_without_validation(property_name.bytes());
removed = m_custom_properties.remove(custom_name);
} else {
removed = m_properties.remove_first_matching([&](auto& entry) { return entry.property_id == property_id; });
}
// 7. If removed is true, Update style attribute for the CSS declaration block.
if (removed)
@ -241,6 +266,14 @@ String CSSStyleDeclaration::get_property_value(StringView property_name) const
if (!property_id.has_value())
return {};
if (property_id.value() == PropertyID::Custom) {
auto maybe_custom_property = custom_property(FlyString::from_utf8_without_validation(property_name.bytes()));
if (maybe_custom_property.has_value()) {
return maybe_custom_property.value().value->to_string();
}
return {};
}
// 2. If property is a shorthand property, then follow these substeps:
if (property_is_shorthand(property_id.value())) {
// 1. Let list be a new empty array.
@ -285,26 +318,26 @@ StringView CSSStyleDeclaration::get_property_priority(StringView property_name)
auto property_id = property_id_from_string(property_name);
if (!property_id.has_value())
return {};
if (property_id.value() == PropertyID::Custom) {
auto maybe_custom_property = custom_property(FlyString::from_utf8_without_validation(property_name.bytes()));
if (!maybe_custom_property.has_value())
return {};
return maybe_custom_property.value().important == Important::Yes ? "important"sv : ""sv;
}
auto maybe_property = property(property_id.value());
if (!maybe_property.has_value())
return {};
return maybe_property->important == Important::Yes ? "important"sv : ""sv;
}
WebIDL::ExceptionOr<void> CSSStyleDeclaration::set_property(StringView property_name, StringView css_text, StringView priority)
WebIDL::ExceptionOr<void> CSSStyleDeclaration::set_property(PropertyID property_id, StringView css_text, StringView priority)
{
auto property_id = property_id_from_string(property_name);
if (!property_id.has_value())
return {};
return set_property(property_id.value(), css_text, priority);
return set_property(string_from_property_id(property_id), css_text, priority);
}
WebIDL::ExceptionOr<String> CSSStyleDeclaration::remove_property(StringView property_name)
WebIDL::ExceptionOr<String> CSSStyleDeclaration::remove_property(PropertyID property_name)
{
auto property_id = property_id_from_string(property_name);
if (!property_id.has_value())
return String {};
return remove_property(property_id.value());
return remove_property(string_from_property_id(property_name));
}
// https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-csstext

View file

@ -29,12 +29,13 @@ public:
virtual String item(size_t index) const = 0;
virtual Optional<StyleProperty> property(PropertyID) const = 0;
virtual Optional<StyleProperty> custom_property(FlyString const& custom_property_name) const = 0;
virtual WebIDL::ExceptionOr<void> set_property(PropertyID, StringView css_text, StringView priority = ""sv) = 0;
virtual WebIDL::ExceptionOr<String> remove_property(PropertyID) = 0;
virtual WebIDL::ExceptionOr<void> set_property(PropertyID, StringView css_text, StringView priority = ""sv);
virtual WebIDL::ExceptionOr<String> remove_property(PropertyID);
virtual WebIDL::ExceptionOr<void> set_property(StringView property_name, StringView css_text, StringView priority);
virtual WebIDL::ExceptionOr<String> remove_property(StringView property_name);
virtual WebIDL::ExceptionOr<void> set_property(StringView property_name, StringView css_text, StringView priority) = 0;
virtual WebIDL::ExceptionOr<String> remove_property(StringView property_name) = 0;
String get_property_value(StringView property) const;
StringView get_property_priority(StringView property) const;
@ -75,13 +76,13 @@ public:
virtual String item(size_t index) const override;
virtual Optional<StyleProperty> property(PropertyID) const override;
virtual Optional<StyleProperty> custom_property(FlyString const& custom_property_name) const override { return m_custom_properties.get(custom_property_name); }
virtual WebIDL::ExceptionOr<void> set_property(PropertyID, StringView css_text, StringView priority) override;
virtual WebIDL::ExceptionOr<String> remove_property(PropertyID) override;
virtual WebIDL::ExceptionOr<void> set_property(StringView property_name, StringView css_text, StringView priority) override;
virtual WebIDL::ExceptionOr<String> remove_property(StringView property_name) override;
Vector<StyleProperty> const& properties() const { return m_properties; }
HashMap<FlyString, StyleProperty> const& custom_properties() const { return m_custom_properties; }
Optional<StyleProperty> custom_property(FlyString const& custom_property_name) const { return m_custom_properties.get(custom_property_name); }
size_t custom_property_count() const { return m_custom_properties.size(); }
virtual String serialized() const final override;

View file

@ -601,6 +601,12 @@ Optional<StyleProperty> ResolvedCSSStyleDeclaration::property(PropertyID propert
};
}
Optional<StyleProperty> ResolvedCSSStyleDeclaration::custom_property(FlyString const&) const
{
dbgln("FIXME: ResolvedCSSStyleDeclaration::custom_property is not implemented");
return {};
}
static WebIDL::ExceptionOr<void> cannot_modify_computed_property_error(JS::Realm& realm)
{
return WebIDL::NoModificationAllowedError::create(realm, "Cannot modify properties in result of getComputedStyle()"_string);

View file

@ -24,6 +24,7 @@ public:
virtual String item(size_t index) const override;
virtual Optional<StyleProperty> property(PropertyID) const override;
virtual Optional<StyleProperty> custom_property(FlyString const& custom_property_name) const override;
virtual WebIDL::ExceptionOr<void> set_property(PropertyID, StringView css_text, StringView priority) override;
virtual WebIDL::ExceptionOr<void> set_property(StringView property_name, StringView css_text, StringView priority) override;
virtual WebIDL::ExceptionOr<String> remove_property(PropertyID) override;

View file

@ -45,7 +45,7 @@ ValueComparingNonnullRefPtr<CSSColorValue> CSSColorValue::create_from_color(Colo
return make_rgb_color(color);
}
Optional<float> CSSColorValue::resolve_hue(CSSStyleValue const& style_value)
Optional<double> CSSColorValue::resolve_hue(CSSStyleValue const& style_value)
{
// <number> | <angle> | none
auto normalized = [](double number) {
@ -67,11 +67,11 @@ Optional<float> CSSColorValue::resolve_hue(CSSStyleValue const& style_value)
return {};
}
Optional<float> CSSColorValue::resolve_with_reference_value(CSSStyleValue const& style_value, float one_hundred_percent_value)
Optional<double> CSSColorValue::resolve_with_reference_value(CSSStyleValue const& style_value, float one_hundred_percent_value)
{
// <percentage> | <number> | none
auto normalize_percentage = [one_hundred_percent_value](Percentage const& percentage) {
return static_cast<float>(percentage.as_fraction()) * one_hundred_percent_value;
return percentage.as_fraction() * one_hundred_percent_value;
};
if (style_value.is_percentage())
@ -94,7 +94,7 @@ Optional<float> CSSColorValue::resolve_with_reference_value(CSSStyleValue const&
return {};
}
Optional<float> CSSColorValue::resolve_alpha(CSSStyleValue const& style_value)
Optional<double> CSSColorValue::resolve_alpha(CSSStyleValue const& style_value)
{
// <number> | <percentage> | none
auto normalized = [](double number) {

View file

@ -48,9 +48,9 @@ protected:
{
}
static Optional<float> resolve_hue(CSSStyleValue const&);
static Optional<float> resolve_with_reference_value(CSSStyleValue const&, float one_hundred_percent_value);
static Optional<float> resolve_alpha(CSSStyleValue const&);
static Optional<double> resolve_hue(CSSStyleValue const&);
static Optional<double> resolve_with_reference_value(CSSStyleValue const&, float one_hundred_percent_value);
static Optional<double> resolve_alpha(CSSStyleValue const&);
private:
ColorType m_color_type;

View file

@ -25,8 +25,8 @@ Color CSSHWB::to_color(Optional<Layout::NodeWithStyle const&>) const
return Color(gray, gray, gray, to_byte(alpha_val));
}
float value = 1 - b_val;
float saturation = 1 - (w_val / value);
auto value = 1 - b_val;
auto saturation = 1 - (w_val / value);
return Color::from_hsv(h_val, saturation, value).with_opacity(alpha_val);
}

View file

@ -2526,6 +2526,106 @@ WebIDL::ExceptionOr<JS::Value> ECDSA::verify(AlgorithmParams const& params, GC::
return JS::Value(result);
}
// https://w3c.github.io/webcrypto/#ecdh-operations
WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> ECDH::generate_key(AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
{
// 1. If usages contains an entry which is not "deriveKey" or "deriveBits" then throw a SyntaxError.
for (auto const& usage : key_usages) {
if (usage != Bindings::KeyUsage::Derivekey && usage != Bindings::KeyUsage::Derivebits) {
return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
}
}
auto const& normalized_algorithm = static_cast<EcKeyGenParams const&>(params);
// 2. If the namedCurve member of normalizedAlgorithm is "P-256", "P-384" or "P-521":
// Generate an Elliptic Curve key pair, as defined in [RFC6090]
// with domain parameters for the curve identified by the namedCurve member of normalizedAlgorithm.
Variant<Empty, ::Crypto::Curves::SECP256r1, ::Crypto::Curves::SECP384r1> curve;
if (normalized_algorithm.named_curve.is_one_of("P-256"sv, "P-384"sv, "P-521"sv)) {
if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-256"sv))
curve = ::Crypto::Curves::SECP256r1 {};
if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-384"sv))
curve = ::Crypto::Curves::SECP384r1 {};
// FIXME: Support P-521
if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-521"sv))
return WebIDL::NotSupportedError::create(m_realm, "'P-521' is not supported yet"_string);
} else {
// If the namedCurve member of normalizedAlgorithm is a value specified in an applicable specification
// that specifies the use of that value with ECDH:
// Perform the ECDH generation steps specified in that specification,
// passing in normalizedAlgorithm and resulting in an elliptic curve key pair.
// Otherwise: throw a NotSupportedError
return WebIDL::NotSupportedError::create(m_realm, "Only 'P-256', 'P-384' and 'P-521' is supported"_string);
}
// 3. If performing the operation results in an error, then throw a OperationError.
auto maybe_private_key_data = curve.visit(
[](Empty const&) -> ErrorOr<ByteBuffer> { return Error::from_string_literal("noop error"); },
[](auto instance) { return instance.generate_private_key(); });
if (maybe_private_key_data.is_error())
return WebIDL::OperationError::create(m_realm, "Failed to create valid crypto instance"_string);
auto private_key_data = maybe_private_key_data.release_value();
auto maybe_public_key_data = curve.visit(
[](Empty const&) -> ErrorOr<ByteBuffer> { return Error::from_string_literal("noop error"); },
[&](auto instance) { return instance.generate_public_key(private_key_data); });
if (maybe_public_key_data.is_error())
return WebIDL::OperationError::create(m_realm, "Failed to create valid crypto instance"_string);
auto public_key_data = maybe_public_key_data.release_value();
// 4. Let algorithm be a new EcKeyAlgorithm object.
auto algorithm = EcKeyAlgorithm::create(m_realm);
// 5. Set the name attribute of algorithm to "ECDH".
algorithm->set_name("ECDH"_string);
// 6. Set the namedCurve attribute of algorithm to equal the namedCurve member of normalizedAlgorithm.
algorithm->set_named_curve(normalized_algorithm.named_curve);
// 7. Let publicKey be a new CryptoKey representing the public key of the generated key pair.
auto public_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key_data });
// 8. Set the [[type]] internal slot of publicKey to "public"
public_key->set_type(Bindings::KeyType::Public);
// 9. Set the [[algorithm]] internal slot of publicKey to algorithm.
public_key->set_algorithm(algorithm);
// 10. Set the [[extractable]] internal slot of publicKey to true.
public_key->set_extractable(true);
// 11. Set the [[usages]] internal slot of publicKey to be the empty list.
public_key->set_usages({});
// 12. Let privateKey be a new CryptoKey representing the private key of the generated key pair.
auto private_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key_data });
// 13. Set the [[type]] internal slot of privateKey to "private"
private_key->set_type(Bindings::KeyType::Private);
// 14. Set the [[algorithm]] internal slot of privateKey to algorithm.
private_key->set_algorithm(algorithm);
// 15. Set the [[extractable]] internal slot of privateKey to extractable.
private_key->set_extractable(extractable);
// 16. Set the [[usages]] internal slot of privateKey to be the usage intersection of usages and [ "deriveKey", "deriveBits" ].
private_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Derivekey, Bindings::KeyUsage::Derivebits } }));
// 17. Let result be a new CryptoKeyPair dictionary.
// 18. Set the publicKey attribute of result to be publicKey.
// 19. Set the privateKey attribute of result to be privateKey.
// 20. Return the result of converting result to an ECMAScript Object, as defined by [WebIDL].
return Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>> { CryptoKeyPair::create(m_realm, public_key, private_key) };
}
// https://wicg.github.io/webcrypto-secure-curves/#ed25519-operations
WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> ED25519::generate_key([[maybe_unused]] AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
{

View file

@ -493,6 +493,22 @@ private:
}
};
class ECDH : public AlgorithmMethods {
public:
virtual WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> generate_key(AlgorithmParams const&, bool, Vector<Bindings::KeyUsage> const&) override;
// TODO: virtual WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> derive_bits(AlgorithmParams const&, GC::Ref<CryptoKey>, Optional<u32>) override;
// TODO: virtual WebIDL::ExceptionOr<GC::Ref<CryptoKey>> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector<Bindings::KeyUsage> const&) override;
// TODO: virtual WebIDL::ExceptionOr<GC::Ref<JS::Object>> export_key(Bindings::KeyFormat, GC::Ref<CryptoKey>) override;
static NonnullOwnPtr<AlgorithmMethods> create(JS::Realm& realm) { return adopt_own(*new ECDH(realm)); }
private:
explicit ECDH(JS::Realm& realm)
: AlgorithmMethods(realm)
{
}
};
class ED25519 : public AlgorithmMethods {
public:
virtual WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> sign(AlgorithmParams const&, GC::Ref<CryptoKey>, ByteBuffer const&) override;

View file

@ -801,10 +801,10 @@ SupportedAlgorithmsMap supported_algorithms()
// FIXME: define_an_algorithm<ECDSA>("exportKey"_string, "ECDSA"_string);
// https://w3c.github.io/webcrypto/#ecdh-registration
// FIXME: define_an_algorithm<ECDH, EcKeyGenParams>("generateKey"_string, "ECDH"_string);
// FIXME: define_an_algorithm<ECDH, EcdhKeyDerivePrams>("deriveBits"_string, "ECDH"_string);
// FIXME: define_an_algorithm<ECDH, EcKeyImportParams>("importKey"_string, "ECDH"_string);
// FIXME: define_an_algorithm<ECDH>("exportKey"_string, "ECDH"_string);
define_an_algorithm<ECDH, EcKeyGenParams>("generateKey"_string, "ECDH"_string);
// https://w3c.github.io/webcrypto/#aes-ctr-registration
define_an_algorithm<AesCtr, AesCtrParams>("encrypt"_string, "AES-CTR"_string);

View file

@ -36,11 +36,14 @@
#include <LibWeb/HTML/CustomElements/CustomElementReactionNames.h>
#include <LibWeb/HTML/HTMLAnchorElement.h>
#include <LibWeb/HTML/HTMLDocument.h>
#include <LibWeb/HTML/HTMLFieldSetElement.h>
#include <LibWeb/HTML/HTMLImageElement.h>
#include <LibWeb/HTML/HTMLInputElement.h>
#include <LibWeb/HTML/HTMLLegendElement.h>
#include <LibWeb/HTML/HTMLSelectElement.h>
#include <LibWeb/HTML/HTMLSlotElement.h>
#include <LibWeb/HTML/HTMLStyleElement.h>
#include <LibWeb/HTML/HTMLTableElement.h>
#include <LibWeb/HTML/Navigable.h>
#include <LibWeb/HTML/NavigableContainer.h>
#include <LibWeb/HTML/Parser/HTMLParser.h>
@ -2280,6 +2283,15 @@ ErrorOr<String> Node::name_or_description(NameOrDescription target, Document con
for (u32 i = 0; i < labels->length(); i++) {
auto nodes = labels->item(i)->children_as_vector();
for (auto const& node : nodes) {
// AD-HOC: https://wpt.fyi/results/accname/name/comp_host_language_label.html has “encapsulation”
// tests, from which can be induced a requirement that when computing the accessible name for a
// <label>-ed form control (“embedded control”), then any content (text content or attribute values)
// from the control itself that would otherwise be included in the accessible-name computation for
// it ancestor <label> must instead be skipped and not included. The HTML-AAM spec seems to maybe
// be trying to achieve that result by expressing specific steps for each particular type of form
// control. But what all that reduces/optimizes/simplifies down to is just, “skip over self”.
if (node == this)
continue;
if (node->is_element()) {
auto const& element = static_cast<DOM::Element const&>(*node);
auto role = element.role_or_default();
@ -2360,6 +2372,38 @@ ErrorOr<String> Node::name_or_description(NameOrDescription target, Document con
// HTMLLabelElement is already handled (by the code for step C. “Embedded Control” above) in conformance
// with the spec requirements — and if not, then add handling for it here.
}
// https://w3c.github.io/html-aam/#table-element-accessible-name-computation
// if the table element has a child that is a caption element, then use the subtree of the first such element
if (is<HTML::HTMLTableElement>(*element))
if (auto& table = (const_cast<HTML::HTMLTableElement&>(static_cast<HTML::HTMLTableElement const&>(*element))); table.caption())
return table.caption()->text_content().value();
// https://w3c.github.io/html-aam/#table-element-accessible-name-computation
// if the fieldset element has a child that is a legend element, then use the subtree of the first such element
if (is<HTML::HTMLFieldSetElement>(*element)) {
Optional<String> legend;
auto& fieldset = (const_cast<HTML::HTMLFieldSetElement&>(static_cast<HTML::HTMLFieldSetElement const&>(*element)));
fieldset.for_each_child_of_type<HTML::HTMLLegendElement>([&](HTML::HTMLLegendElement const& element) mutable {
legend = element.text_content().value();
return IterationDecision::Break;
});
if (legend.has_value())
return legend.value();
}
if (is<HTML::HTMLInputElement>(*element)) {
auto& input = (const_cast<HTML::HTMLInputElement&>(static_cast<HTML::HTMLInputElement const&>(*element)));
// https://w3c.github.io/html-aam/#input-type-image-accessible-name-computation
// Otherwise use the value attribute.
if (input.type_state() == HTML::HTMLInputElement::TypeAttributeState::Button
|| input.type_state() == HTML::HTMLInputElement::TypeAttributeState::SubmitButton
|| input.type_state() == HTML::HTMLInputElement::TypeAttributeState::ResetButton)
if (auto value = input.get_attribute(HTML::AttributeNames::value); value.has_value())
return value.value();
// https://w3c.github.io/html-aam/#input-type-image-accessible-name-computation
// Otherwise use alt attribute if present and its value is not the empty string.
if (input.type_state() == HTML::HTMLInputElement::TypeAttributeState::ImageButton)
if (auto alt = element->get_attribute(HTML::AttributeNames::alt); alt.has_value())
return alt.release_value();
}
// F. Otherwise, if the current node's role allows name from content, or if the current node is referenced by aria-labelledby, aria-describedby, or is a native host language text alternative element (e.g. label in HTML), or is a descendant of a native host language text alternative element:
if ((role.has_value() && ARIA::allows_name_from_content(role.value())) || is_referenced || is_descendant == IsDescendant::Yes) {

View file

@ -177,8 +177,6 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS
if (!m_navigable->active_document()->is_fully_active())
return EventResult::Dropped;
auto position = viewport_position;
m_navigable->active_document()->update_layout();
if (!paint_root())
@ -190,20 +188,20 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS
auto handled_event = EventResult::Dropped;
GC::Ptr<Painting::Paintable> paintable;
if (auto result = target_for_mouse_position(position); result.has_value())
if (auto result = target_for_mouse_position(viewport_position); result.has_value())
paintable = result->paintable;
if (paintable) {
auto* containing_block = paintable->containing_block();
while (containing_block) {
auto handled_scroll_event = containing_block->handle_mousewheel({}, position, buttons, modifiers, wheel_delta_x, wheel_delta_y);
auto handled_scroll_event = containing_block->handle_mousewheel({}, viewport_position, buttons, modifiers, wheel_delta_x, wheel_delta_y);
if (handled_scroll_event)
return EventResult::Handled;
containing_block = containing_block->containing_block();
}
if (paintable->handle_mousewheel({}, position, buttons, modifiers, wheel_delta_x, wheel_delta_y))
if (paintable->handle_mousewheel({}, viewport_position, buttons, modifiers, wheel_delta_x, wheel_delta_y))
return EventResult::Handled;
auto node = dom_node_for_event_dispatch(*paintable);
@ -212,7 +210,7 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS
// FIXME: Support wheel events in nested browsing contexts.
if (is<HTML::HTMLIFrameElement>(*node)) {
auto& iframe = static_cast<HTML::HTMLIFrameElement&>(*node);
auto position_in_iframe = position.translated(compute_mouse_event_offset({}, paintable->layout_node()));
auto position_in_iframe = viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node()));
iframe.content_navigable()->event_handler().handle_mousewheel(position_in_iframe, screen_position, button, buttons, modifiers, wheel_delta_x, wheel_delta_y);
return EventResult::Dropped;
}
@ -222,10 +220,9 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS
if (!parent_element_for_event_dispatch(*paintable, node, layout_node))
return EventResult::Dropped;
auto offset = compute_mouse_event_offset(position, *layout_node);
auto client_offset = compute_mouse_event_client_offset(position);
auto page_offset = compute_mouse_event_page_offset(client_offset);
if (node->dispatch_event(UIEvents::WheelEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::wheel, screen_position, page_offset, client_offset, offset, wheel_delta_x, wheel_delta_y, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors())) {
auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, *layout_node);
if (node->dispatch_event(UIEvents::WheelEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::wheel, screen_position, page_offset, viewport_position, offset, wheel_delta_x, wheel_delta_y, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors())) {
m_navigable->active_window()->scroll_by(wheel_delta_x, wheel_delta_y);
}
@ -246,26 +243,24 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix
if (!m_navigable->active_document()->is_fully_active())
return EventResult::Dropped;
auto position = viewport_position;
m_navigable->active_document()->update_layout();
if (!paint_root())
return EventResult::Dropped;
GC::Ptr<Painting::Paintable> paintable;
if (auto result = target_for_mouse_position(position); result.has_value())
if (auto result = target_for_mouse_position(viewport_position); result.has_value())
paintable = result->paintable;
if (paintable && paintable->wants_mouse_events()) {
if (paintable->handle_mouseup({}, position, button, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
if (paintable->handle_mouseup({}, viewport_position, button, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
return EventResult::Cancelled;
// Things may have changed as a consequence of Layout::Node::handle_mouseup(). Hit test again.
if (!paint_root())
return EventResult::Handled;
if (auto result = paint_root()->hit_test(position, Painting::HitTestType::Exact); result.has_value())
if (auto result = paint_root()->hit_test(viewport_position, Painting::HitTestType::Exact); result.has_value())
paintable = result->paintable;
}
@ -277,7 +272,7 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix
if (node) {
if (is<HTML::HTMLIFrameElement>(*node)) {
if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable())
return content_navigable->event_handler().handle_mouseup(position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return content_navigable->event_handler().handle_mouseup(viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return EventResult::Dropped;
}
@ -290,22 +285,21 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix
goto after_node_use;
}
auto offset = compute_mouse_event_offset(position, *layout_node);
auto client_offset = compute_mouse_event_client_offset(position);
auto page_offset = compute_mouse_event_page_offset(client_offset);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mouseup, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, *layout_node);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mouseup, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
handled_event = EventResult::Handled;
bool run_activation_behavior = false;
if (node.ptr() == m_mousedown_target) {
if (button == UIEvents::MouseButton::Primary) {
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::click, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::click, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
} else if (button == UIEvents::MouseButton::Middle) {
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::auxclick, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::auxclick, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
} else if (button == UIEvents::MouseButton::Secondary) {
// Allow the user to bypass custom context menus by holding shift, like Firefox.
if ((modifiers & UIEvents::Mod_Shift) == 0)
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::contextmenu, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::contextmenu, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
else
run_activation_behavior = true;
}
@ -378,8 +372,6 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
if (!m_navigable->active_document()->is_fully_active())
return EventResult::Dropped;
auto position = viewport_position;
m_navigable->active_document()->update_layout();
if (!paint_root())
@ -390,7 +382,7 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
{
GC::Ptr<Painting::Paintable> paintable;
if (auto result = target_for_mouse_position(position); result.has_value())
if (auto result = target_for_mouse_position(viewport_position); result.has_value())
paintable = result->paintable;
else
return EventResult::Dropped;
@ -403,7 +395,7 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
document->set_hovered_node(node);
if (paintable->wants_mouse_events()) {
if (paintable->handle_mousedown({}, position, button, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
if (paintable->handle_mousedown({}, viewport_position, button, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
return EventResult::Cancelled;
}
@ -412,7 +404,7 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
if (is<HTML::HTMLIFrameElement>(*node)) {
if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable())
return content_navigable->event_handler().handle_mousedown(position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return content_navigable->event_handler().handle_mousedown(viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return EventResult::Dropped;
}
@ -426,10 +418,9 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
return EventResult::Dropped;
m_mousedown_target = node.ptr();
auto offset = compute_mouse_event_offset(position, *layout_node);
auto client_offset = compute_mouse_event_client_offset(position);
auto page_offset = compute_mouse_event_page_offset(client_offset);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousedown, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, *layout_node);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousedown, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
}
// NOTE: Dispatching an event may have disturbed the world.
@ -437,7 +428,7 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
return EventResult::Accepted;
if (button == UIEvents::MouseButton::Primary) {
if (auto result = paint_root()->hit_test(position, Painting::HitTestType::TextCursor); result.has_value()) {
if (auto result = paint_root()->hit_test(viewport_position, Painting::HitTestType::TextCursor); result.has_value()) {
auto paintable = result->paintable;
auto dom_node = paintable->dom_node();
if (dom_node) {
@ -494,8 +485,6 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
if (!m_navigable->active_document()->is_fully_active())
return EventResult::Dropped;
auto position = viewport_position;
m_navigable->active_document()->update_layout();
if (!paint_root())
@ -510,7 +499,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
GC::Ptr<Painting::Paintable> paintable;
Optional<int> start_index;
if (auto result = target_for_mouse_position(position); result.has_value()) {
if (auto result = target_for_mouse_position(viewport_position); result.has_value()) {
paintable = result->paintable;
start_index = result->index_in_node;
}
@ -519,7 +508,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
if (paintable) {
if (paintable->wants_mouse_events()) {
document.set_hovered_node(paintable->dom_node());
if (paintable->handle_mousemove({}, position, buttons, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
if (paintable->handle_mousemove({}, viewport_position, buttons, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
return EventResult::Cancelled;
// FIXME: It feels a bit aggressive to always update the cursor like this.
@ -530,7 +519,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
if (node && is<HTML::HTMLIFrameElement>(*node)) {
if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable())
return content_navigable->event_handler().handle_mousemove(position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, buttons, modifiers);
return content_navigable->event_handler().handle_mousemove(viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, buttons, modifiers);
return EventResult::Dropped;
}
@ -563,14 +552,13 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
hovered_node_cursor = cursor_css_to_gfx(cursor);
}
auto offset = compute_mouse_event_offset(position, *layout_node);
auto client_offset = compute_mouse_event_client_offset(position);
auto page_offset = compute_mouse_event_page_offset(client_offset);
auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, *layout_node);
auto movement = compute_mouse_event_movement(screen_position);
m_mousemove_previous_screen_position = screen_position;
bool continue_ = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousemove, screen_position, page_offset, client_offset, offset, movement, UIEvents::MouseButton::Primary, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
bool continue_ = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousemove, screen_position, page_offset, viewport_position, offset, movement, UIEvents::MouseButton::Primary, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
if (!continue_)
return EventResult::Cancelled;
@ -580,7 +568,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
}
if (m_in_mouse_selection) {
auto hit = paint_root()->hit_test(position, Painting::HitTestType::TextCursor);
auto hit = paint_root()->hit_test(viewport_position, Painting::HitTestType::TextCursor);
if (m_mouse_selection_target) {
if (hit.has_value()) {
m_mouse_selection_target->set_selection_focus(*hit->paintable->dom_node(), hit->index_in_node);
@ -635,16 +623,13 @@ EventResult EventHandler::handle_doubleclick(CSSPixelPoint viewport_position, CS
auto& document = *m_navigable->active_document();
auto scroll_offset = document.navigable()->viewport_scroll_offset();
auto position = viewport_position.translated(scroll_offset);
document.update_layout();
if (!paint_root())
return EventResult::Dropped;
GC::Ptr<Painting::Paintable> paintable;
if (auto result = target_for_mouse_position(position); result.has_value())
if (auto result = target_for_mouse_position(viewport_position); result.has_value())
paintable = result->paintable;
else
return EventResult::Dropped;
@ -665,7 +650,7 @@ EventResult EventHandler::handle_doubleclick(CSSPixelPoint viewport_position, CS
if (is<HTML::HTMLIFrameElement>(*node)) {
if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable())
return content_navigable->event_handler().handle_doubleclick(position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return content_navigable->event_handler().handle_doubleclick(viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return EventResult::Dropped;
}
@ -675,17 +660,16 @@ EventResult EventHandler::handle_doubleclick(CSSPixelPoint viewport_position, CS
if (!parent_element_for_event_dispatch(*paintable, node, layout_node))
return EventResult::Dropped;
auto offset = compute_mouse_event_offset(position, *layout_node);
auto client_offset = compute_mouse_event_client_offset(position);
auto page_offset = compute_mouse_event_page_offset(client_offset);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::dblclick, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, *layout_node);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::dblclick, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
// NOTE: Dispatching an event may have disturbed the world.
if (!paint_root() || paint_root() != node->document().paintable_box())
return EventResult::Accepted;
if (button == UIEvents::MouseButton::Primary) {
if (auto result = paint_root()->hit_test(position, Painting::HitTestType::TextCursor); result.has_value()) {
if (auto result = paint_root()->hit_test(viewport_position, Painting::HitTestType::TextCursor); result.has_value()) {
if (!result->paintable->dom_node())
return EventResult::Accepted;
if (!is<Painting::TextPaintable>(*result->paintable))
@ -738,19 +722,18 @@ EventResult EventHandler::handle_drag_and_drop_event(DragEvent::Type type, CSSPi
return EventResult::Dropped;
}
auto offset = compute_mouse_event_offset(viewport_position, paintable->layout_node());
auto client_offset = compute_mouse_event_client_offset(viewport_position);
auto page_offset = compute_mouse_event_page_offset(client_offset);
auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, paintable->layout_node());
switch (type) {
case DragEvent::Type::DragStart:
return m_drag_and_drop_event_handler->handle_drag_start(document.realm(), screen_position, page_offset, client_offset, offset, button, buttons, modifiers, move(files));
return m_drag_and_drop_event_handler->handle_drag_start(document.realm(), screen_position, page_offset, viewport_position, offset, button, buttons, modifiers, move(files));
case DragEvent::Type::DragMove:
return m_drag_and_drop_event_handler->handle_drag_move(document.realm(), document, *node, screen_position, page_offset, client_offset, offset, button, buttons, modifiers);
return m_drag_and_drop_event_handler->handle_drag_move(document.realm(), document, *node, screen_position, page_offset, viewport_position, offset, button, buttons, modifiers);
case DragEvent::Type::DragEnd:
return m_drag_and_drop_event_handler->handle_drag_leave(document.realm(), screen_position, page_offset, client_offset, offset, button, buttons, modifiers);
return m_drag_and_drop_event_handler->handle_drag_leave(document.realm(), screen_position, page_offset, viewport_position, offset, button, buttons, modifiers);
case DragEvent::Type::Drop:
return m_drag_and_drop_event_handler->handle_drop(document.realm(), screen_position, page_offset, client_offset, offset, button, buttons, modifiers);
return m_drag_and_drop_event_handler->handle_drop(document.realm(), screen_position, page_offset, viewport_position, offset, button, buttons, modifiers);
}
VERIFY_NOT_REACHED();
@ -1113,15 +1096,6 @@ void EventHandler::set_mouse_event_tracking_paintable(Painting::Paintable* paint
m_mouse_event_tracking_paintable = paintable;
}
CSSPixelPoint EventHandler::compute_mouse_event_client_offset(CSSPixelPoint event_page_position) const
{
// https://w3c.github.io/csswg-drafts/cssom-view/#dom-mouseevent-clientx
// The clientX attribute must return the x-coordinate of the position where the event occurred relative to the origin of the viewport.
auto scroll_offset = m_navigable->active_document()->navigable()->viewport_scroll_offset();
return event_page_position.translated(-scroll_offset);
}
CSSPixelPoint EventHandler::compute_mouse_event_page_offset(CSSPixelPoint event_client_offset) const
{
// https://w3c.github.io/csswg-drafts/cssom-view/#dom-mouseevent-pagex

View file

@ -6,6 +6,7 @@
#pragma once
#include <LibCore/Timer.h>
#include <LibMedia/Audio/PlaybackStream.h>
#include <LibWeb/Platform/AudioCodecPlugin.h>

View file

@ -7,11 +7,8 @@
#pragma once
#include <AK/Vector.h>
#include <LibCore/EventReceiver.h>
#include <LibHTTP/HeaderMap.h>
#include <LibTLS/TLSv12.h>
#include <LibURL/URL.h>
#include <LibWebSocket/Message.h>
namespace WebSocket {

View file

@ -8,6 +8,7 @@
#include <LibCore/EventLoop.h>
#include <LibCore/Socket.h>
#include <LibTLS/TLSv12.h>
#include <LibWebSocket/Impl/WebSocketImplSerenity.h>
namespace WebSocket {

View file

@ -10,7 +10,6 @@
#include <LibCrypto/Hash/HashManager.h>
#include <LibWebSocket/Impl/WebSocketImplSerenity.h>
#include <LibWebSocket/WebSocket.h>
#include <unistd.h>
namespace WebSocket {

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Format.h>
#include <LibCrypto/ASN1/PEM.h>
#include <stddef.h>
#include <stdint.h>

View file

@ -402,6 +402,7 @@ ErrorOr<void> generate_implementation_file(JsonObject& properties, Core::File& f
#include <LibWeb/CSS/Enums.h>
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/CSS/PropertyID.h>
#include <LibWeb/CSS/PropertyName.h>
#include <LibWeb/CSS/CSSStyleValue.h>
#include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
#include <LibWeb/CSS/StyleValues/TimeStyleValue.h>
@ -436,6 +437,9 @@ Optional<PropertyID> property_id_from_camel_case_string(StringView string)
Optional<PropertyID> property_id_from_string(StringView string)
{
if (is_a_custom_property_name_string(string))
return PropertyID::Custom;
if (Infra::is_ascii_case_insensitive_match(string, "all"sv))
return PropertyID::All;
)~~~");

View file

@ -12,6 +12,7 @@
#include <LibCore/Proxy.h>
#include <LibCore/Socket.h>
#include <LibRequests/NetworkErrorEnum.h>
#include <LibTLS/TLSv12.h>
#include <LibTextCodec/Decoder.h>
#include <LibWebSocket/ConnectionInfo.h>
#include <LibWebSocket/Message.h>

View file

@ -21,3 +21,10 @@ TEST_CASE(all_green)
EXPECT_EQ(Color(Color::NamedColor::Green), Color::from_xyz50(0.385152, 0.716887, 0.097081));
EXPECT_EQ(Color(Color::NamedColor::Green), Color::from_xyz65(0.357584, 0.715169, 0.119195));
}
TEST_CASE(hsv)
{
EXPECT_EQ(Color(51, 179, 51), Color::from_hsv(120, 0.714285714, .7));
EXPECT_EQ(Color(51, 179, 51, 128), Color::from_hsv(120, 0.714285714, .7).with_opacity(0.5));
EXPECT_EQ(Color(87, 128, 77), Color::from_hsv(108, 0.4, .5));
}

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Color 4: CSS Color 4: hwb</title>
<style>
.test { background-color: rgb(20% 70% 20%); width: 12em; height: 12em; } /* hwb(120 20% 30%) converted to sRGB */
</style>
<body>
<p>Test passes if you see a single square, and not two rectangles of different colors.</p>
<div class="test"></div>
</body>

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Color 4: hwb</title>
<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
<link rel="help" href="https://drafts.csswg.org/css-color-4/#the-hwb-notation">
<link rel="match" href="../../../../expected/wpt-import/css/css-color/hwb-004-ref.html">
<meta name="assert" content="hwb with no alpha">
<style>
.test { background-color: red; width: 12em; height: 6em; margin-top: 0; }
.ref { background-color: rgb(20% 70% 20%); width: 12em; height: 6em; margin-bottom: 0; } /* hwb(120 20% 30%) converted to sRGB */
.test { background-color: hwb(120 20% 30%); }
</style>
<body>
<p>Test passes if you see a single square, and not two rectangles of different colors.</p>
<div class="ref"></div>
<div class="test"></div>
</body>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1,10 @@
x: 50
y: 50
screenX: 50
screenY: 50
clientX: 50
clientY: 50
pageX: 50
pageY: 60
offsetX: 42
offsetY: 52

View file

@ -0,0 +1,4 @@
style.getPropertyValue(--redcolor)=red
style.getPropertyPriority(--redcolor)=
rgb(255, 0, 0)
rgba(0, 0, 0, 0)

View file

@ -0,0 +1,487 @@
Summary
Harness status: OK
Rerun
Found 476 tests
410 Pass
66 Fail
Details
Result Test Name MessagePass Bad algorithm: generateKey(AES, false, [decrypt])
Pass Bad algorithm: generateKey(AES, true, [decrypt])
Pass Bad algorithm: generateKey(AES, RED, [decrypt])
Pass Bad algorithm: generateKey(AES, 7, [decrypt])
Pass Bad algorithm: generateKey(AES, false, [sign, decrypt])
Pass Bad algorithm: generateKey(AES, true, [sign, decrypt])
Pass Bad algorithm: generateKey(AES, RED, [sign, decrypt])
Pass Bad algorithm: generateKey(AES, 7, [sign, decrypt])
Pass Bad algorithm: generateKey(AES, false, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey(AES, true, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey(AES, RED, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey(AES, 7, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey(AES, false, [deriveBits, decrypt])
Pass Bad algorithm: generateKey(AES, true, [deriveBits, decrypt])
Pass Bad algorithm: generateKey(AES, RED, [deriveBits, decrypt])
Pass Bad algorithm: generateKey(AES, 7, [deriveBits, decrypt])
Pass Bad algorithm: generateKey(AES, false, [sign])
Pass Bad algorithm: generateKey(AES, true, [sign])
Pass Bad algorithm: generateKey(AES, RED, [sign])
Pass Bad algorithm: generateKey(AES, 7, [sign])
Pass Bad algorithm: generateKey(AES, false, [deriveBits, sign])
Pass Bad algorithm: generateKey(AES, true, [deriveBits, sign])
Pass Bad algorithm: generateKey(AES, RED, [deriveBits, sign])
Pass Bad algorithm: generateKey(AES, 7, [deriveBits, sign])
Pass Bad algorithm: generateKey(AES, false, [deriveBits])
Pass Bad algorithm: generateKey(AES, true, [deriveBits])
Pass Bad algorithm: generateKey(AES, RED, [deriveBits])
Pass Bad algorithm: generateKey(AES, 7, [deriveBits])
Pass Bad algorithm: generateKey(AES, false, [])
Pass Bad algorithm: generateKey(AES, true, [])
Pass Bad algorithm: generateKey(AES, RED, [])
Pass Bad algorithm: generateKey(AES, 7, [])
Pass Bad algorithm: generateKey(AES, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey(AES, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey(AES, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey(AES, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({name: AES}, false, [decrypt])
Pass Bad algorithm: generateKey({name: AES}, true, [decrypt])
Pass Bad algorithm: generateKey({name: AES}, RED, [decrypt])
Pass Bad algorithm: generateKey({name: AES}, 7, [decrypt])
Pass Bad algorithm: generateKey({name: AES}, false, [sign, decrypt])
Pass Bad algorithm: generateKey({name: AES}, true, [sign, decrypt])
Pass Bad algorithm: generateKey({name: AES}, RED, [sign, decrypt])
Pass Bad algorithm: generateKey({name: AES}, 7, [sign, decrypt])
Pass Bad algorithm: generateKey({name: AES}, false, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({name: AES}, true, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({name: AES}, RED, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({name: AES}, 7, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({name: AES}, false, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({name: AES}, true, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({name: AES}, RED, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({name: AES}, 7, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({name: AES}, false, [sign])
Pass Bad algorithm: generateKey({name: AES}, true, [sign])
Pass Bad algorithm: generateKey({name: AES}, RED, [sign])
Pass Bad algorithm: generateKey({name: AES}, 7, [sign])
Pass Bad algorithm: generateKey({name: AES}, false, [deriveBits, sign])
Pass Bad algorithm: generateKey({name: AES}, true, [deriveBits, sign])
Pass Bad algorithm: generateKey({name: AES}, RED, [deriveBits, sign])
Pass Bad algorithm: generateKey({name: AES}, 7, [deriveBits, sign])
Pass Bad algorithm: generateKey({name: AES}, false, [deriveBits])
Pass Bad algorithm: generateKey({name: AES}, true, [deriveBits])
Pass Bad algorithm: generateKey({name: AES}, RED, [deriveBits])
Pass Bad algorithm: generateKey({name: AES}, 7, [deriveBits])
Pass Bad algorithm: generateKey({name: AES}, false, [])
Pass Bad algorithm: generateKey({name: AES}, true, [])
Pass Bad algorithm: generateKey({name: AES}, RED, [])
Pass Bad algorithm: generateKey({name: AES}, 7, [])
Pass Bad algorithm: generateKey({name: AES}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({name: AES}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({name: AES}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({name: AES}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES}, false, [decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, true, [decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, RED, [decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, 7, [decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, false, [sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, true, [sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, RED, [sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, 7, [sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES}, false, [sign])
Pass Bad algorithm: generateKey({length: 128, name: AES}, true, [sign])
Pass Bad algorithm: generateKey({length: 128, name: AES}, RED, [sign])
Pass Bad algorithm: generateKey({length: 128, name: AES}, 7, [sign])
Pass Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, sign])
Pass Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, sign])
Pass Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, sign])
Pass Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, sign])
Pass Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES}, false, [])
Pass Bad algorithm: generateKey({length: 128, name: AES}, true, [])
Pass Bad algorithm: generateKey({length: 128, name: AES}, RED, [])
Pass Bad algorithm: generateKey({length: 128, name: AES}, 7, [])
Pass Bad algorithm: generateKey({length: 128, name: AES}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, sign])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [sign, decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [sign, decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [sign, decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [sign, decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, sign, decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, sign, decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, sign, decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, sign, decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, decrypt])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [sign])
Pass Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [sign])
Pass Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [sign])
Pass Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [sign])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, sign])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, sign])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, sign])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, sign])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits])
Pass Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [])
Pass Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [])
Pass Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [])
Pass Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Fail Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [sign, decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [sign, decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [sign, decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [sign, decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, sign, decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, decrypt])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [sign])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [sign])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [sign])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [sign])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, sign])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, sign])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, sign])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, sign])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Fail Empty algorithm: generateKey({}, false, [decrypt])
Fail Empty algorithm: generateKey({}, true, [decrypt])
Fail Empty algorithm: generateKey({}, RED, [decrypt])
Fail Empty algorithm: generateKey({}, 7, [decrypt])
Fail Empty algorithm: generateKey({}, false, [sign, decrypt])
Fail Empty algorithm: generateKey({}, true, [sign, decrypt])
Fail Empty algorithm: generateKey({}, RED, [sign, decrypt])
Fail Empty algorithm: generateKey({}, 7, [sign, decrypt])
Fail Empty algorithm: generateKey({}, false, [deriveBits, sign, decrypt])
Fail Empty algorithm: generateKey({}, true, [deriveBits, sign, decrypt])
Fail Empty algorithm: generateKey({}, RED, [deriveBits, sign, decrypt])
Fail Empty algorithm: generateKey({}, 7, [deriveBits, sign, decrypt])
Fail Empty algorithm: generateKey({}, false, [deriveBits, decrypt])
Fail Empty algorithm: generateKey({}, true, [deriveBits, decrypt])
Fail Empty algorithm: generateKey({}, RED, [deriveBits, decrypt])
Fail Empty algorithm: generateKey({}, 7, [deriveBits, decrypt])
Fail Empty algorithm: generateKey({}, false, [sign])
Fail Empty algorithm: generateKey({}, true, [sign])
Fail Empty algorithm: generateKey({}, RED, [sign])
Fail Empty algorithm: generateKey({}, 7, [sign])
Fail Empty algorithm: generateKey({}, false, [deriveBits, sign])
Fail Empty algorithm: generateKey({}, true, [deriveBits, sign])
Fail Empty algorithm: generateKey({}, RED, [deriveBits, sign])
Fail Empty algorithm: generateKey({}, 7, [deriveBits, sign])
Fail Empty algorithm: generateKey({}, false, [deriveBits])
Fail Empty algorithm: generateKey({}, true, [deriveBits])
Fail Empty algorithm: generateKey({}, RED, [deriveBits])
Fail Empty algorithm: generateKey({}, 7, [deriveBits])
Fail Empty algorithm: generateKey({}, false, [])
Fail Empty algorithm: generateKey({}, true, [])
Fail Empty algorithm: generateKey({}, RED, [])
Fail Empty algorithm: generateKey({}, 7, [])
Fail Empty algorithm: generateKey({}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Fail Empty algorithm: generateKey({}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Fail Empty algorithm: generateKey({}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Fail Empty algorithm: generateKey({}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [unwrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, unwrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, unwrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, unwrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [unwrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, unwrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, unwrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, unwrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, encrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, decrypt])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, sign])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, verify])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, wrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [unwrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, unwrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, unwrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, unwrapKey])
Pass Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveKey])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveKey])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveBits, deriveKey])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveBits, deriveKey])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveBits])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveBits])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveKey])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveKey])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveBits, deriveKey])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveBits, deriveKey])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveBits])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveBits])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Pass Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Pass Empty usages: generateKey({name: ECDH, namedCurve: P-256}, false, [])
Pass Empty usages: generateKey({name: ECDH, namedCurve: P-256}, true, [])
Pass Empty usages: generateKey({name: ECDH, namedCurve: P-384}, false, [])
Pass Empty usages: generateKey({name: ECDH, namedCurve: P-384}, true, [])
Fail Empty usages: generateKey({name: ECDH, namedCurve: P-521}, false, [])
Fail Empty usages: generateKey({name: ECDH, namedCurve: P-521}, true, [])

View file

@ -0,0 +1,82 @@
Summary
Harness status: OK
Rerun
Found 72 tests
72 Fail
Details
Result Test Name MessageFail Success: generateKey({name: ECDH, namedCurve: P-256}, false, [deriveKey])
Fail Success: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey])
Fail Success: generateKey({name: ECDH, namedCurve: P-256}, false, [deriveBits, deriveKey])
Fail Success: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey])
Fail Success: generateKey({name: ECDH, namedCurve: P-256}, false, [deriveBits])
Fail Success: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits])
Fail Success: generateKey({name: ECDH, namedCurve: P-256}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: ECDH, namedCurve: P-384}, false, [deriveKey])
Fail Success: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey])
Fail Success: generateKey({name: ECDH, namedCurve: P-384}, false, [deriveBits, deriveKey])
Fail Success: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey])
Fail Success: generateKey({name: ECDH, namedCurve: P-384}, false, [deriveBits])
Fail Success: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits])
Fail Success: generateKey({name: ECDH, namedCurve: P-384}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveKey])
Fail Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey])
Fail Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveBits, deriveKey])
Fail Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey])
Fail Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveBits])
Fail Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits])
Fail Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: ecdh, namedCurve: P-256}, false, [deriveKey])
Fail Success: generateKey({name: ecdh, namedCurve: P-256}, true, [deriveKey])
Fail Success: generateKey({name: ecdh, namedCurve: P-256}, false, [deriveBits, deriveKey])
Fail Success: generateKey({name: ecdh, namedCurve: P-256}, true, [deriveBits, deriveKey])
Fail Success: generateKey({name: ecdh, namedCurve: P-256}, false, [deriveBits])
Fail Success: generateKey({name: ecdh, namedCurve: P-256}, true, [deriveBits])
Fail Success: generateKey({name: ecdh, namedCurve: P-256}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: ecdh, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: ecdh, namedCurve: P-384}, false, [deriveKey])
Fail Success: generateKey({name: ecdh, namedCurve: P-384}, true, [deriveKey])
Fail Success: generateKey({name: ecdh, namedCurve: P-384}, false, [deriveBits, deriveKey])
Fail Success: generateKey({name: ecdh, namedCurve: P-384}, true, [deriveBits, deriveKey])
Fail Success: generateKey({name: ecdh, namedCurve: P-384}, false, [deriveBits])
Fail Success: generateKey({name: ecdh, namedCurve: P-384}, true, [deriveBits])
Fail Success: generateKey({name: ecdh, namedCurve: P-384}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: ecdh, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveKey])
Fail Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveKey])
Fail Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveBits, deriveKey])
Fail Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveBits, deriveKey])
Fail Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveBits])
Fail Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveBits])
Fail Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: Ecdh, namedCurve: P-256}, false, [deriveKey])
Fail Success: generateKey({name: Ecdh, namedCurve: P-256}, true, [deriveKey])
Fail Success: generateKey({name: Ecdh, namedCurve: P-256}, false, [deriveBits, deriveKey])
Fail Success: generateKey({name: Ecdh, namedCurve: P-256}, true, [deriveBits, deriveKey])
Fail Success: generateKey({name: Ecdh, namedCurve: P-256}, false, [deriveBits])
Fail Success: generateKey({name: Ecdh, namedCurve: P-256}, true, [deriveBits])
Fail Success: generateKey({name: Ecdh, namedCurve: P-256}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: Ecdh, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: Ecdh, namedCurve: P-384}, false, [deriveKey])
Fail Success: generateKey({name: Ecdh, namedCurve: P-384}, true, [deriveKey])
Fail Success: generateKey({name: Ecdh, namedCurve: P-384}, false, [deriveBits, deriveKey])
Fail Success: generateKey({name: Ecdh, namedCurve: P-384}, true, [deriveBits, deriveKey])
Fail Success: generateKey({name: Ecdh, namedCurve: P-384}, false, [deriveBits])
Fail Success: generateKey({name: Ecdh, namedCurve: P-384}, true, [deriveBits])
Fail Success: generateKey({name: Ecdh, namedCurve: P-384}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: Ecdh, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveKey])
Fail Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveKey])
Fail Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveBits, deriveKey])
Fail Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveBits, deriveKey])
Fail Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveBits])
Fail Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveBits])
Fail Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])
Fail Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])

View file

@ -0,0 +1,88 @@
Summary
Harness status: OK
Rerun
Found 78 tests
78 Pass
Details
Result Test Name MessagePass html: input[type=button]
Pass html: input[type=image]
Pass html: input[type=reset]
Pass html: input[type=submit]
Pass html: label[for] input[type=checkbox]
Pass html: label[for] input[type=checkbox][value='test']
Pass html: label[for] input[type=checkbox][checked]
Pass html: label[for] input[type=checkbox][checked][value='test']
Pass html: label[for] input[type=color]
Pass html: label[for] input[type=color][value='#999999']
Pass html: label[for] input[type=date]
Pass html: label[for] input[type=date][value='2025-01-01']
Pass html: label[for] input[type=datetime-local]
Pass html: label[for] input[type=datetime-local][value='2025-01-01T00:01']
Pass html: label[for] input[type=email]
Pass html: label[for] input[type=email][value='test@test.com']
Pass html: label[for] input[type=month]
Pass html: label[for] input[type=month][value='2025-01']
Pass html: label[for] input[type=number]
Pass html: label[for] input[type=number][value=2025]
Pass html: label[for] input[type=password]
Pass html: label[for] input[type=password][value='test']
Pass html: label[for] input[type=radio]
Pass html: label[for] input[type=radio][value='test']
Pass html: label[for] input[type=range]
Pass html: label[for] input[type=range][min=0][max=10][value=5]
Pass html: label[for] input[type=search]
Pass html: label[for] input[type=search][value='test']
Pass html: label[for] input[type=tel]
Pass html: label[for] input[type=tel][value='123-45-678']
Pass html: label[for] input[type=text]
Pass html: label[for] input[type=text][value='test']
Pass html: label[for] input[type=time]
Pass html: label[for] input[type=time][value='00:01']
Pass html: label[for] input[type=url]
Pass html: label[for] input[type=url][value='https://www.w3.org']
Pass html: label[for] input[type=week]
Pass html: label[for] input[type=week][value='2025-W01']
Pass html: label input[type=checkbox] encapsulation
Pass html: label input[type=checkbox][value='test'] encapsulation
Pass html: label input[type=checkbox][checked] encapsulation
Pass html: label input[type=checkbox][value='test'][checked] encapsulation
Pass html: label input[type=color] encapsulation
Pass html: label input[type=color][value='#999999'] encapsulation
Pass html: label input[type=date] encapsulation
Pass html: label input[type=date][value='2025-01-01'] encapsulation
Pass html: label input[type=datetime-local] encapsulation
Pass html: label input[type=datetime-local][value='2025-01-01T00:01'] encapsulation
Pass html: label input[type=email] encapsulation
Pass html: label input[type=email][value='test@test.com'] encapsulation
Pass html: label input[type=month] encapsulation
Pass html: label input[type=month][value='2025-01'] encapsulation
Pass html: label input[type=number] encapsulation
Pass html: label input[type=number][value=1] encapsulation
Pass html: label input[type=password] encapsulation
Pass html: label input[type=password][value='test'] encapsulation
Pass html: label input[type=radio] encapsulation
Pass html: label input[type=radio][value='test'] encapsulation
Pass html: label input[type=range] encapsulation
Pass html: label input[type=range][value='5'][min='0'][max='10'] encapsulation
Pass html: label input[type=search] encapsulation
Pass html: label input[type=search][value='test'] encapsulation
Pass html: label input[type=tel] encapsulation
Pass html: label input[type=tel][value='123-45-678'] encapsulation
Pass html: label[for] input[type=text] encapsulation
Pass html: label[for] input[type=text][value='test'] encapsulation
Pass html: label input[type=time] encapsulation
Pass html: label input[type=time][value='00:01'] encapsulation
Pass html: label input[type=url] encapsulation
Pass html: label input[type=url][value='https://www.w3.org'] encapsulation
Pass html: label input[type=week] encapsulation
Pass html: label input[type=week][value='2025-W01'] encapsulation
Pass html: select for/id
Pass html: select encapsulation
Pass html: img[alt] (non-empty)
Pass html: picture > img[alt] (non-empty)
Pass html: fieldset > legend
Pass html: table > caption

View file

@ -0,0 +1,32 @@
<!DOCTYPE html>
<style>
div {
width: 100px;
height: 100px;
background-color: gray;
}
body {
height: 200vh;
}
</style>
<div onClick="
println(`x: ${event.x}`);
println(`y: ${event.y}`);
println(`screenX: ${event.screenX}`);
println(`screenY: ${event.screenY}`);
println(`clientX: ${event.clientX}`);
println(`clientY: ${event.clientY}`);
println(`pageX: ${event.pageX}`);
println(`pageY: ${event.pageY}`);
println(`offsetX: ${event.offsetX}`);
println(`offsetY: ${event.offsetY}`);
"></div>
<script src="../include.js"></script>
<script>
test(() => {
window.scrollBy(0, 10)
internals.click(50, 50);
});
</script>

View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<script src="../include.js"></script>
<body></body>
<script>
test(() => {
const div = document.createElement('div');
div.style.setProperty("--redcolor", "red");
println(`style.getPropertyValue(--redcolor)=${div.style.getPropertyValue("--redcolor")}`);
println(`style.getPropertyPriority(--redcolor)=${div.style.getPropertyPriority("--redcolor")}`);
const nested = document.createElement('div');
nested.style["backgroundColor"] = "var(--redcolor)";
nested.style["width"] = "100px";
nested.style["height"] = "100px";
div.appendChild(nested);
document.body.appendChild(div);
println(getComputedStyle(nested).backgroundColor);
div.style.removeProperty("--redcolor");
println(getComputedStyle(nested).backgroundColor);
});
</script>

View file

@ -0,0 +1,228 @@
function run_test(algorithmNames) {
var subtle = crypto.subtle; // Change to test prefixed implementations
setup({explicit_timeout: true});
// These tests check that generateKey throws an error, and that
// the error is of the right type, for a wide set of incorrect parameters.
//
// Error testing occurs by setting the parameter that should trigger the
// error to an invalid value, then combining that with all valid
// parameters that should be checked earlier by generateKey, and all
// valid and invalid parameters that should be checked later by
// generateKey.
//
// There are a lot of combinations of possible parameters for both
// success and failure modes, resulting in a very large number of tests
// performed.
// Setup: define the correct behaviors that should be sought, and create
// helper functions that generate all possible test parameters for
// different situations.
var allTestVectors = [ // Parameters that should work for generateKey
{name: "AES-CTR", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "AES-CBC", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "AES-GCM", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "AES-KW", resultType: CryptoKey, usages: ["wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "HMAC", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []},
{name: "RSASSA-PKCS1-v1_5", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "RSA-PSS", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "RSA-OAEP", resultType: "CryptoKeyPair", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: ["decrypt", "unwrapKey"]},
{name: "ECDSA", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "ECDH", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
{name: "Ed25519", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "Ed448", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "X25519", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
{name: "X448", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
];
var testVectors = [];
if (algorithmNames && !Array.isArray(algorithmNames)) {
algorithmNames = [algorithmNames];
};
allTestVectors.forEach(function(vector) {
if (!algorithmNames || algorithmNames.includes(vector.name)) {
testVectors.push(vector);
}
});
function parameterString(algorithm, extractable, usages) {
if (typeof algorithm !== "object" && typeof algorithm !== "string") {
alert(algorithm);
}
var result = "(" +
objectToString(algorithm) + ", " +
objectToString(extractable) + ", " +
objectToString(usages) +
")";
return result;
}
// Test that a given combination of parameters results in an error,
// AND that it is the correct kind of error.
//
// Expected error is either a number, tested against the error code,
// or a string, tested against the error name.
function testError(algorithm, extractable, usages, expectedError, testTag) {
promise_test(function(test) {
return crypto.subtle.generateKey(algorithm, extractable, usages)
.then(function(result) {
assert_unreached("Operation succeeded, but should not have");
}, function(err) {
if (typeof expectedError === "number") {
assert_equals(err.code, expectedError, testTag + " not supported");
} else {
assert_equals(err.name, expectedError, testTag + " not supported");
}
});
}, testTag + ": generateKey" + parameterString(algorithm, extractable, usages));
}
// Given an algorithm name, create several invalid parameters.
function badAlgorithmPropertySpecifiersFor(algorithmName) {
var results = [];
if (algorithmName.toUpperCase().substring(0, 3) === "AES") {
// Specifier properties are name and length
[64, 127, 129, 255, 257, 512].forEach(function(length) {
results.push({name: algorithmName, length: length});
});
} else if (algorithmName.toUpperCase().substring(0, 3) === "RSA") {
[new Uint8Array([1]), new Uint8Array([1,0,0])].forEach(function(publicExponent) {
results.push({name: algorithmName, hash: "SHA-256", modulusLength: 1024, publicExponent: publicExponent});
});
} else if (algorithmName.toUpperCase().substring(0, 2) === "EC") {
["P-512", "Curve25519"].forEach(function(curveName) {
results.push({name: algorithmName, namedCurve: curveName});
});
}
return results;
}
// Don't create an exhaustive list of all invalid usages,
// because there would usually be nearly 2**8 of them,
// way too many to test. Instead, create every singleton
// of an illegal usage, and "poison" every valid usage
// with an illegal one.
function invalidUsages(validUsages, mandatoryUsages) {
var results = [];
var illegalUsages = [];
["encrypt", "decrypt", "sign", "verify", "wrapKey", "unwrapKey", "deriveKey", "deriveBits"].forEach(function(usage) {
if (!validUsages.includes(usage)) {
illegalUsages.push(usage);
}
});
var goodUsageCombinations = allValidUsages(validUsages, false, mandatoryUsages);
illegalUsages.forEach(function(illegalUsage) {
results.push([illegalUsage]);
goodUsageCombinations.forEach(function(usageCombination) {
results.push(usageCombination.concat([illegalUsage]));
});
});
return results;
}
// Now test for properly handling errors
// - Unsupported algorithm
// - Bad usages for algorithm
// - Bad key lengths
// Algorithm normalization should fail with "Not supported"
var badAlgorithmNames = [
"AES",
{name: "AES"},
{name: "AES", length: 128},
{name: "AES-CMAC", length: 128}, // Removed after CR
{name: "AES-CFB", length: 128}, // Removed after CR
{name: "HMAC", hash: "MD5"},
{name: "RSA", hash: "SHA-256", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])},
{name: "RSA-PSS", hash: "SHA", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])},
{name: "EC", namedCurve: "P521"}
];
// Algorithm normalization failures should be found first
// - all other parameters can be good or bad, should fail
// due to NotSupportedError.
badAlgorithmNames.forEach(function(algorithm) {
allValidUsages(["decrypt", "sign", "deriveBits"], true, []) // Small search space, shouldn't matter because should fail before used
.forEach(function(usages) {
[false, true, "RED", 7].forEach(function(extractable){
testError(algorithm, extractable, usages, "NotSupportedError", "Bad algorithm");
});
});
});
// Empty algorithm should fail with TypeError
allValidUsages(["decrypt", "sign", "deriveBits"], true, []) // Small search space, shouldn't matter because should fail before used
.forEach(function(usages) {
[false, true, "RED", 7].forEach(function(extractable){
testError({}, extractable, usages, "TypeError", "Empty algorithm");
});
});
// Algorithms normalize okay, but usages bad (though not empty).
// It shouldn't matter what other extractable is. Should fail
// due to SyntaxError
testVectors.forEach(function(vector) {
var name = vector.name;
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
invalidUsages(vector.usages, vector.mandatoryUsages).forEach(function(usages) {
[true].forEach(function(extractable) {
testError(algorithm, extractable, usages, "SyntaxError", "Bad usages");
});
});
});
});
// Other algorithm properties should be checked next, so try good
// algorithm names and usages, but bad algorithm properties next.
// - Special case: normally bad usage [] isn't checked until after properties,
// so it's included in this test case. It should NOT cause an error.
testVectors.forEach(function(vector) {
var name = vector.name;
badAlgorithmPropertySpecifiersFor(name).forEach(function(algorithm) {
allValidUsages(vector.usages, true, vector.mandatoryUsages)
.forEach(function(usages) {
[false, true].forEach(function(extractable) {
if (name.substring(0,2) === "EC") {
testError(algorithm, extractable, usages, "NotSupportedError", "Bad algorithm property");
} else {
testError(algorithm, extractable, usages, "OperationError", "Bad algorithm property");
}
});
});
});
});
// The last thing that should be checked is empty usages (disallowed for secret and private keys).
testVectors.forEach(function(vector) {
var name = vector.name;
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
var usages = [];
[false, true].forEach(function(extractable) {
testError(algorithm, extractable, usages, "SyntaxError", "Empty usages");
});
});
});
}

View file

@ -0,0 +1,17 @@
<!doctype html>
<meta charset=utf-8>
<title>WebCryptoAPI: generateKey() for Failures</title>
<meta name="timeout" content="long">
<script>
self.GLOBAL = {
isWindow: function() { return true; },
isWorker: function() { return false; },
isShadowRealm: function() { return false; },
};
</script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../util/helpers.js"></script>
<script src="failures.js"></script>
<div id=log></div>
<script src="../../WebCryptoAPI/generateKey/failures_ECDH.https.any.js"></script>

View file

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["ECDH"]);

View file

@ -0,0 +1,115 @@
function run_test(algorithmNames, slowTest) {
var subtle = crypto.subtle; // Change to test prefixed implementations
setup({explicit_timeout: true});
// These tests check that generateKey successfully creates keys
// when provided any of a wide set of correct parameters
// and that they can be exported afterwards.
//
// There are a lot of combinations of possible parameters,
// resulting in a very large number of tests
// performed.
// Setup: define the correct behaviors that should be sought, and create
// helper functions that generate all possible test parameters for
// different situations.
var allTestVectors = [ // Parameters that should work for generateKey
{name: "AES-CTR", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "AES-CBC", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "AES-GCM", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "AES-KW", resultType: CryptoKey, usages: ["wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "HMAC", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []},
{name: "RSASSA-PKCS1-v1_5", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "RSA-PSS", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "RSA-OAEP", resultType: "CryptoKeyPair", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: ["decrypt", "unwrapKey"]},
{name: "ECDSA", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "ECDH", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
{name: "Ed25519", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "Ed448", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "X25519", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
{name: "X448", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
];
var testVectors = [];
if (algorithmNames && !Array.isArray(algorithmNames)) {
algorithmNames = [algorithmNames];
};
allTestVectors.forEach(function(vector) {
if (!algorithmNames || algorithmNames.includes(vector.name)) {
testVectors.push(vector);
}
});
function parameterString(algorithm, extractable, usages) {
var result = "(" +
objectToString(algorithm) + ", " +
objectToString(extractable) + ", " +
objectToString(usages) +
")";
return result;
}
// Test that a given combination of parameters is successful
function testSuccess(algorithm, extractable, usages, resultType, testTag) {
// algorithm, extractable, and usages are the generateKey parameters
// resultType is the expected result, either the CryptoKey object or "CryptoKeyPair"
// testTag is a string to prepend to the test name.
promise_test(function(test) {
return subtle.generateKey(algorithm, extractable, usages)
.then(function(result) {
if (resultType === "CryptoKeyPair") {
assert_goodCryptoKey(result.privateKey, algorithm, extractable, usages, "private");
assert_goodCryptoKey(result.publicKey, algorithm, true, usages, "public");
} else {
assert_goodCryptoKey(result, algorithm, extractable, usages, "secret");
}
return result;
}, function(err) {
assert_unreached("generateKey threw an unexpected error: " + err.toString());
})
.then(async function (result) {
if (resultType === "CryptoKeyPair") {
await Promise.all([
subtle.exportKey('jwk', result.publicKey),
subtle.exportKey('spki', result.publicKey),
result.publicKey.algorithm.name.startsWith('RSA') ? undefined : subtle.exportKey('raw', result.publicKey),
...(extractable ? [
subtle.exportKey('jwk', result.privateKey),
subtle.exportKey('pkcs8', result.privateKey),
] : [])
]);
} else {
if (extractable) {
await Promise.all([
subtle.exportKey('raw', result),
subtle.exportKey('jwk', result),
]);
}
}
}, function(err) {
assert_unreached("exportKey threw an unexpected error: " + err.toString());
})
}, testTag + ": generateKey" + parameterString(algorithm, extractable, usages));
}
// Test all valid sets of parameters for successful
// key generation.
testVectors.forEach(function(vector) {
allNameVariants(vector.name, slowTest).forEach(function(name) {
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
allValidUsages(vector.usages, false, vector.mandatoryUsages).forEach(function(usages) {
[false, true].forEach(function(extractable) {
subsetTest(testSuccess, algorithm, extractable, usages, vector.resultType, "Success");
});
});
});
});
});
}

View file

@ -0,0 +1,18 @@
<!doctype html>
<meta charset=utf-8>
<title>WebCryptoAPI: generateKey() Successful Calls</title>
<meta name="timeout" content="long">
<script>
self.GLOBAL = {
isWindow: function() { return true; },
isWorker: function() { return false; },
isShadowRealm: function() { return false; },
};
</script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../util/helpers.js"></script>
<script src="../../common/subset-tests.js"></script>
<script src="successes.js"></script>
<div id=log></div>
<script src="../../WebCryptoAPI/generateKey/successes_ECDH.https.any.js"></script>

View file

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["ECDH"]);

View file

@ -0,0 +1,299 @@
//
// helpers.js
//
// Helper functions used by several WebCryptoAPI tests
//
var registeredAlgorithmNames = [
"RSASSA-PKCS1-v1_5",
"RSA-PSS",
"RSA-OAEP",
"ECDSA",
"ECDH",
"AES-CTR",
"AES-CBC",
"AES-GCM",
"AES-KW",
"HMAC",
"SHA-1",
"SHA-256",
"SHA-384",
"SHA-512",
"HKDF",
"PBKDF2",
"Ed25519",
"Ed448",
"X25519",
"X448"
];
// Treats an array as a set, and generates an array of all non-empty
// subsets (which are themselves arrays).
//
// The order of members of the "subsets" is not guaranteed.
function allNonemptySubsetsOf(arr) {
var results = [];
var firstElement;
var remainingElements;
for(var i=0; i<arr.length; i++) {
firstElement = arr[i];
remainingElements = arr.slice(i+1);
results.push([firstElement]);
if (remainingElements.length > 0) {
allNonemptySubsetsOf(remainingElements).forEach(function(combination) {
combination.push(firstElement);
results.push(combination);
});
}
}
return results;
}
// Create a string representation of keyGeneration parameters for
// test names and labels.
function objectToString(obj) {
var keyValuePairs = [];
if (Array.isArray(obj)) {
return "[" + obj.map(function(elem){return objectToString(elem);}).join(", ") + "]";
} else if (typeof obj === "object") {
Object.keys(obj).sort().forEach(function(keyName) {
keyValuePairs.push(keyName + ": " + objectToString(obj[keyName]));
});
return "{" + keyValuePairs.join(", ") + "}";
} else if (typeof obj === "undefined") {
return "undefined";
} else {
return obj.toString();
}
var keyValuePairs = [];
Object.keys(obj).sort().forEach(function(keyName) {
var value = obj[keyName];
if (typeof value === "object") {
value = objectToString(value);
} else if (typeof value === "array") {
value = "[" + value.map(function(elem){return objectToString(elem);}).join(", ") + "]";
} else {
value = value.toString();
}
keyValuePairs.push(keyName + ": " + value);
});
return "{" + keyValuePairs.join(", ") + "}";
}
// Is key a CryptoKey object with correct algorithm, extractable, and usages?
// Is it a secret, private, or public kind of key?
function assert_goodCryptoKey(key, algorithm, extractable, usages, kind) {
var correctUsages = [];
var registeredAlgorithmName;
registeredAlgorithmNames.forEach(function(name) {
if (name.toUpperCase() === algorithm.name.toUpperCase()) {
registeredAlgorithmName = name;
}
});
assert_equals(key.constructor, CryptoKey, "Is a CryptoKey");
assert_equals(key.type, kind, "Is a " + kind + " key");
assert_equals(key.extractable, extractable, "Extractability is correct");
assert_equals(key.algorithm.name, registeredAlgorithmName, "Correct algorithm name");
if (key.algorithm.name.toUpperCase() === "HMAC" && algorithm.length === undefined) {
switch (key.algorithm.hash.name.toUpperCase()) {
case 'SHA-1':
case 'SHA-256':
assert_equals(key.algorithm.length, 512, "Correct length");
break;
case 'SHA-384':
case 'SHA-512':
assert_equals(key.algorithm.length, 1024, "Correct length");
break;
default:
assert_unreached("Unrecognized hash");
}
} else {
assert_equals(key.algorithm.length, algorithm.length, "Correct length");
}
if (["HMAC", "RSASSA-PKCS1-v1_5", "RSA-PSS"].includes(registeredAlgorithmName)) {
assert_equals(key.algorithm.hash.name.toUpperCase(), algorithm.hash.toUpperCase(), "Correct hash function");
}
if (/^(?:Ed|X)(?:25519|448)$/.test(key.algorithm.name)) {
assert_false('namedCurve' in key.algorithm, "Does not have a namedCurve property");
}
// usages is expected to be provided for a key pair, but we are checking
// only a single key. The publicKey and privateKey portions of a key pair
// recognize only some of the usages appropriate for a key pair.
if (key.type === "public") {
["encrypt", "verify", "wrapKey"].forEach(function(usage) {
if (usages.includes(usage)) {
correctUsages.push(usage);
}
});
} else if (key.type === "private") {
["decrypt", "sign", "unwrapKey", "deriveKey", "deriveBits"].forEach(function(usage) {
if (usages.includes(usage)) {
correctUsages.push(usage);
}
});
} else {
correctUsages = usages;
}
assert_equals((typeof key.usages), "object", key.type + " key.usages is an object");
assert_not_equals(key.usages, null, key.type + " key.usages isn't null");
// The usages parameter could have repeats, but the usages
// property of the result should not.
var usageCount = 0;
key.usages.forEach(function(usage) {
usageCount += 1;
assert_in_array(usage, correctUsages, "Has " + usage + " usage");
});
assert_equals(key.usages.length, usageCount, "usages property is correct");
assert_equals(key[Symbol.toStringTag], 'CryptoKey', "has the expected Symbol.toStringTag");
}
// The algorithm parameter is an object with a name and other
// properties. Given the name, generate all valid parameters.
function allAlgorithmSpecifiersFor(algorithmName) {
var results = [];
// RSA key generation is slow. Test a minimal set of parameters
var hashes = ["SHA-1", "SHA-256"];
// EC key generation is a lot faster. Check all curves in the spec
var curves = ["P-256", "P-384", "P-521"];
if (algorithmName.toUpperCase().substring(0, 3) === "AES") {
// Specifier properties are name and length
[128, 192, 256].forEach(function(length) {
results.push({name: algorithmName, length: length});
});
} else if (algorithmName.toUpperCase() === "HMAC") {
[
{hash: "SHA-1", length: 160},
{hash: "SHA-256", length: 256},
{hash: "SHA-384", length: 384},
{hash: "SHA-512", length: 512},
{hash: "SHA-1"},
{hash: "SHA-256"},
{hash: "SHA-384"},
{hash: "SHA-512"},
].forEach(function(hashAlgorithm) {
results.push({name: algorithmName, ...hashAlgorithm});
});
} else if (algorithmName.toUpperCase().substring(0, 3) === "RSA") {
hashes.forEach(function(hashName) {
results.push({name: algorithmName, hash: hashName, modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])});
});
} else if (algorithmName.toUpperCase().substring(0, 2) === "EC") {
curves.forEach(function(curveName) {
results.push({name: algorithmName, namedCurve: curveName});
});
} else if (algorithmName.toUpperCase().substring(0, 1) === "X" || algorithmName.toUpperCase().substring(0, 2) === "ED") {
results.push({ name: algorithmName });
}
return results;
}
// Create every possible valid usages parameter, given legal
// usages. Note that an empty usages parameter is not always valid.
//
// There is an optional parameter - mandatoryUsages. If provided,
// it should be an array containing those usages of which one must be
// included.
function allValidUsages(validUsages, emptyIsValid, mandatoryUsages) {
if (typeof mandatoryUsages === "undefined") {
mandatoryUsages = [];
}
var okaySubsets = [];
allNonemptySubsetsOf(validUsages).forEach(function(subset) {
if (mandatoryUsages.length === 0) {
okaySubsets.push(subset);
} else {
for (var i=0; i<mandatoryUsages.length; i++) {
if (subset.includes(mandatoryUsages[i])) {
okaySubsets.push(subset);
return;
}
}
}
});
if (emptyIsValid && validUsages.length !== 0) {
okaySubsets.push([]);
}
okaySubsets.push(validUsages.concat(mandatoryUsages).concat(validUsages)); // Repeated values are allowed
return okaySubsets;
}
function unique(names) {
return [...new Set(names)];
}
// Algorithm name specifiers are case-insensitive. Generate several
// case variations of a given name.
function allNameVariants(name, slowTest) {
var upCaseName = name.toUpperCase();
var lowCaseName = name.toLowerCase();
var mixedCaseName = upCaseName.substring(0, 1) + lowCaseName.substring(1);
// for slow tests effectively cut the amount of work in third by only
// returning one variation
if (slowTest) return [mixedCaseName];
return unique([upCaseName, lowCaseName, mixedCaseName]);
}
// Builds a hex string representation for an array-like input.
// "bytes" can be an Array of bytes, an ArrayBuffer, or any TypedArray.
// The output looks like this:
// ab034c99
function bytesToHexString(bytes)
{
if (!bytes)
return null;
bytes = new Uint8Array(bytes);
var hexBytes = [];
for (var i = 0; i < bytes.length; ++i) {
var byteString = bytes[i].toString(16);
if (byteString.length < 2)
byteString = "0" + byteString;
hexBytes.push(byteString);
}
return hexBytes.join("");
}
function hexStringToUint8Array(hexString)
{
if (hexString.length % 2 != 0)
throw "Invalid hexString";
var arrayBuffer = new Uint8Array(hexString.length / 2);
for (var i = 0; i < hexString.length; i += 2) {
var byteValue = parseInt(hexString.substr(i, 2), 16);
if (byteValue == NaN)
throw "Invalid hexString";
arrayBuffer[i/2] = byteValue;
}
return arrayBuffer;
}

View file

@ -0,0 +1,166 @@
<!DOCTYPE html>
<html>
<head>
<title>Name Comp: Host Language Label</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../../resources/testdriver.js"></script>
<script src="../../resources/testdriver-vendor.js"></script>
<script src="../../resources/testdriver-actions.js"></script>
<script src="../../wai-aria/scripts/aria-utils.js"></script>
</head>
<body>
<h1>AccName: Host Language Label Tests</h1>
<p>Tests the <a href="https://w3c.github.io/accname/#comp_host_language_label">#comp_host_language_label</a> portions of the AccName <em>Name Computation</em> algorithm.</p>
<h2>HTML input with value, alt, etc.</h2>
<input class="ex" data-expectedlabel="button label" data-testname="html: input[type=button]" type="button" value="button label"/>
<input alt="image input label" class="ex" data-expectedlabel="image input label" data-testname="html: input[type=image]" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" type="image"/>
<input class="ex" data-expectedlabel="reset label" data-testname="html: input[type=reset]" type="reset" value="reset label"/>
<input class="ex" data-expectedlabel="submit label" data-testname="html: input[type=submit]" type="submit" value="submit label"/>
<h2>HTML input label/for</h2>
<!-- above: input[type=button] -->
<label for="cb">checkbox label</label><input class="ex" data-expectedlabel="checkbox label" data-testname="html: label[for] input[type=checkbox]" id="cb" type="checkbox"/><br/>
<label for="cbv">checkbox label with non-empty value</label><input class="ex" data-expectedlabel="checkbox label with non-empty value" data-testname="html: label[for] input[type=checkbox][value='test']" id="cbv" type="checkbox" value="test"/><br/>
<label for="cbc">checkbox label checked</label><input checked="" class="ex" data-expectedlabel="checkbox label checked" data-testname="html: label[for] input[type=checkbox][checked]" id="cbc" type="checkbox"/><br/>
<label for="cbcv">checkbox label checked with non-empty value</label><input checked="" class="ex" data-expectedlabel="checkbox label checked with non-empty value" data-testname="html: label[for] input[type=checkbox][checked][value='test']" id="cbcv" type="checkbox" value="test"/><br/>
<label for="co">color label</label><input class="ex" data-expectedlabel="color label" data-testname="html: label[for] input[type=color]" id="co" type="color"/><br/>
<label for="cov">color label with non-empty value</label><input class="ex" data-expectedlabel="color label with non-empty value" data-testname="html: label[for] input[type=color][value='#999999']" id="cov" type="color" value="#999999"/><br/>
<label for="da">date label</label><input class="ex" data-expectedlabel="date label" data-testname="html: label[for] input[type=date]" id="da" type="date"/><br/>
<label for="dav">date label with non-empty value</label><input class="ex" data-expectedlabel="date label with non-empty value" data-testname="html: label[for] input[type=date][value='2025-01-01']" id="dav" type="date" value="2025-01-01"/><br/>
<label for="dtl">datetime-local label</label><input class="ex" data-expectedlabel="datetime-local label" data-testname="html: label[for] input[type=datetime-local]" id="dtl" type="date"/><br/>
<label for="dtlv">datetime-local label with non-empty value</label><input class="ex" data-expectedlabel="datetime-local label with non-empty value" data-testname="html: label[for] input[type=datetime-local][value='2025-01-01T00:01']" id="dtlv" type="date" value="2025-01-01T00:01"/><br/>
<label for="em">email label</label><input class="ex" data-expectedlabel="email label" data-testname="html: label[for] input[type=email]" id="em" type="email"/><br/>
<label for="emv">email label with non-empty value</label><input class="ex" data-expectedlabel="email label with non-empty value" data-testname="html: label[for] input[type=email][value='test@test.com']" id="emv" type="email" value="test@test.com"/><br/>
<!-- todo: results for input[type=file] currently differ in all engines -->
<!--
<label for="fi">file label</label><input id="fi" type="file" data-expectedlabel="file label" data-testname="html: label[for] input[type=file]" class="ex"><br>
-->
<!-- skipped: input[type=hidden] for/id n/a -->
<!-- above: input[type=image] -->
<label for="mo">month label</label><input class="ex" data-expectedlabel="month label" data-testname="html: label[for] input[type=month]" id="mo" type="month"/><br/>
<label for="mov">month label with non-empty value</label><input class="ex" data-expectedlabel="month label with non-empty value" data-testname="html: label[for] input[type=month][value='2025-01']" id="mov" type="month" value="2025-01"/><br/>
<label for="n">number label</label><input class="ex" data-expectedlabel="number label" data-testname="html: label[for] input[type=number]" id="n" type="number"/><br/>
<label for="nv">number label with non-empty value</label><input class="ex" data-expectedlabel="number label with non-empty value" data-testname="html: label[for] input[type=number][value=2025]" id="nv" type="number" value="2025"/><br/>
<label for="pw">password label</label><input class="ex" data-expectedlabel="password label" data-testname="html: label[for] input[type=password]" id="pw" type="password"/><br/>
<label for="pwv">password label with non-empty value</label><input class="ex" data-expectedlabel="password label with non-empty value" data-testname="html: label[for] input[type=password][value='test']" id="pwv" type="password" value="test"/><br/>
<label for="ra">radio label</label><input class="ex" data-expectedlabel="radio label" data-testname="html: label[for] input[type=radio]" id="ra" type="radio"/><br/>
<label for="rav">radio label with non-empty value</label><input class="ex" data-expectedlabel="radio label with non-empty value" data-testname="html: label[for] input[type=radio][value='test']" id="rav" type="radio" value="test"/><br/>
<label for="rng">range label</label><input class="ex" data-expectedlabel="range label" data-testname="html: label[for] input[type=range]" id="rng" type="range"/><br/>
<label for="rngv">range label with non-empty value</label><input class="ex" data-expectedlabel="range label with non-empty value" data-testname="html: label[for] input[type=range][min=0][max=10][value=5]" id="rngv" max="10" min="0" type="range" value="5"/><br/>
<!-- input[type=reset] above -->
<label for="search">search label</label><input class="ex" data-expectedlabel="search label" data-testname="html: label[for] input[type=search]" id="search" type="search"/><br/>
<label for="searchv">search label with non-empty value</label><input class="ex" data-expectedlabel="search label with non-empty value" data-testname="html: label[for] input[type=search][value='test']" id="searchv" type="search" value="test"/><br/>
<!-- input[type=submit] above -->
<label for="tel">tel label</label><input class="ex" data-expectedlabel="tel label" data-testname="html: label[for] input[type=tel]" id="tel" type="tel"/><br/>
<label for="telv">tel label with non-empty value</label><input class="ex" data-expectedlabel="tel label with non-empty value" data-testname="html: label[for] input[type=tel][value='123-45-678']" id="telv" type="tel" value="123-45-678"/><br/>
<label for="t">textfield label</label><input class="ex" data-expectedlabel="textfield label" data-testname="html: label[for] input[type=text]" id="t" type="text"/><br/>
<label for="tv">textfield label with non-empty value</label><input class="ex" data-expectedlabel="textfield label with non-empty value" data-testname="html: label[for] input[type=text][value='test']" id="tv" type="text" value="test"/><br/>
<label for="time">time label</label><input class="ex" data-expectedlabel="time label" data-testname="html: label[for] input[type=time]" id="time" type="time"/><br/>
<label for="timev">time label with non-empty value</label><input class="ex" data-expectedlabel="time label with non-empty value" data-testname="html: label[for] input[type=time][value='00:01']" id="timev" type="time" value="00:01"/><br/>
<label for="url">url label</label><input class="ex" data-expectedlabel="url label" data-testname="html: label[for] input[type=url]" id="url" type="url"/><br/>
<label for="urlv">url label with non-empty value</label><input class="ex" data-expectedlabel="url label with non-empty value" data-testname="html: label[for] input[type=url][value='https://www.w3.org']" id="urlv" type="url" value="https://www.w3.org"/><br/>
<label for="week">week label</label><input class="ex" data-expectedlabel="week label" data-testname="html: label[for] input[type=week]" id="week" type="week"/><br/>
<label for="weekv">week label with non-empty value</label><input class="ex" data-expectedlabel="week label with non-empty value" data-testname="html: label[for] input[type=week][value='2025-W01']" id="weekv" type="week" value="2025-W01"/><br/>
<h2>HTML input label encapsulation</h2>
<!-- above: input[type=button] -->
<label><input class="ex" data-expectedlabel="checkbox label" data-testname="html: label input[type=checkbox] encapsulation" type="checkbox"/>checkbox label</label><br/>
<label><input class="ex" data-expectedlabel="checkbox label with non-empty value" data-testname="html: label input[type=checkbox][value='test'] encapsulation" type="checkbox" value="test"/>checkbox label with non-empty value</label><br/>
<label><input checked="" class="ex" data-expectedlabel="checkbox label checked" data-testname="html: label input[type=checkbox][checked] encapsulation" type="checkbox"/>checkbox label checked</label><br/>
<label><input checked="" class="ex" data-expectedlabel="checkbox label checked with non-empty value" data-testname="html: label input[type=checkbox][value='test'][checked] encapsulation" type="checkbox" value="test"/>checkbox label checked with non-empty value</label><br/>
<label><input class="ex" data-expectedlabel="color label" data-testname="html: label input[type=color] encapsulation" type="color"/>color label</label><br/>
<label><input class="ex" data-expectedlabel="color label with non-empty value" data-testname="html: label input[type=color][value='#999999'] encapsulation" type="color" value="#999999"/>color label with non-empty value</label><br/>
<label><input class="ex" data-expectedlabel="date label" data-testname="html: label input[type=date] encapsulation" type="date"/>date label</label><br/>
<label><input class="ex" data-expectedlabel="date label with non-empty value" data-testname="html: label input[type=date][value='2025-01-01'] encapsulation" type="date" value="2025-01-01"/>date label with non-empty value</label><br/>
<label><input class="ex" data-expectedlabel="datetime-local label" data-testname="html: label input[type=datetime-local] encapsulation" type="datetime-local"/>datetime-local label</label><br/>
<label><input class="ex" data-expectedlabel="datetime-local label with non-empty value" data-testname="html: label input[type=datetime-local][value='2025-01-01T00:01'] encapsulation" type="datetime-local" value="2025-01-01T00:01"/>datetime-local label with non-empty value</label><br/>
<label><input class="ex" data-expectedlabel="email label" data-testname="html: label input[type=email] encapsulation" type="email"/>email label</label><br/>
<label><input class="ex" data-expectedlabel="email label with non-empty value" data-testname="html: label input[type=email][value='test@test.com'] encapsulation" type="email" value="test@test.com"/>email label with non-empty value</label><br/>
<!-- todo: results for input[type=file] currently differ in all engines -->
<!--
<label><input type="file" data-expectedlabel="file label" data-testname="html: label input[type=file] encapsulation" class="ex">file label</label><br>
-->
<!-- skipped: input[type=hidden] n/a -->
<!-- above: input[type=image] -->
<label><input class="ex" data-expectedlabel="month label" data-testname="html: label input[type=month] encapsulation" type="month"/>month label</label><br/>
<label><input class="ex" data-expectedlabel="month label with non-empty value" data-testname="html: label input[type=month][value='2025-01'] encapsulation" type="month" value="2025-01"/>month label with non-empty value</label><br/>
<label><input class="ex" data-expectedlabel="number label" data-testname="html: label input[type=number] encapsulation" type="number"/>number label</label><br/>
<label><input class="ex" data-expectedlabel="number label with non-empty value" data-testname="html: label input[type=number][value=1] encapsulation" type="number" value="1"/>number label with non-empty value</label><br/>
<label><input class="ex" data-expectedlabel="password label" data-testname="html: label input[type=password] encapsulation" type="password"/>password label</label><br/>
<label><input class="ex" data-expectedlabel="password label with non-empty value" data-testname="html: label input[type=password][value='test'] encapsulation" type="password" value="test"/>password label with non-empty value</label><br/>
<label><input class="ex" data-expectedlabel="radio label" data-testname="html: label input[type=radio] encapsulation" type="radio"/>radio label</label><br/>
<label><input class="ex" data-expectedlabel="radio label with non-empty value" data-testname="html: label input[type=radio][value='test'] encapsulation" type="radio" value="test"/>radio label with non-empty value</label><br/>
<label><input class="ex" data-expectedlabel="range label" data-testname="html: label input[type=range] encapsulation" type="range"/>range label</label><br/>
<label><input class="ex" data-expectedlabel="range label with non-empty value" data-testname="html: label input[type=range][value='5'][min='0'][max='10'] encapsulation" max="10" min="0" type="range" value="5"/>range label with non-empty value</label><br/>
<!-- above: input[type=reset] -->
<label><input class="ex" data-expectedlabel="search label" data-testname="html: label input[type=search] encapsulation" type="search"/>search label</label><br/>
<label><input class="ex" data-expectedlabel="search label with non-empty value" data-testname="html: label input[type=search][value='test'] encapsulation" type="search" value="test"/>search label with non-empty value</label><br/>
<!-- above: input[type=submit] -->
<label><input class="ex" data-expectedlabel="tel label" data-testname="html: label input[type=tel] encapsulation" type="tel"/>tel label</label><br/>
<label><input class="ex" data-expectedlabel="tel label with non-empty value" data-testname="html: label input[type=tel][value='123-45-678'] encapsulation" type="tel" value="123-45-678"/>tel label with non-empty value</label><br/>
<label><input class="ex" data-expectedlabel="textfield label" data-testname="html: label[for] input[type=text] encapsulation" type="text"/>textfield label</label><br/>
<label><input class="ex" data-expectedlabel="textfield label with non-empty value" data-testname="html: label[for] input[type=text][value='test'] encapsulation" type="text" value="test"/>textfield label with non-empty value</label><br/>
<label><input class="ex" data-expectedlabel="time label" data-testname="html: label input[type=time] encapsulation" type="time"/>time label</label><br/>
<label><input class="ex" data-expectedlabel="time label with non-empty value" data-testname="html: label input[type=time][value='00:01'] encapsulation" type="time" value="00:01"/>time label with non-empty value</label><br/>
<label><input class="ex" data-expectedlabel="url label" data-testname="html: label input[type=url] encapsulation" type="url"/>url label</label><br/>
<label><input class="ex" data-expectedlabel="url label with non-empty value" data-testname="html: label input[type=url][value='https://www.w3.org'] encapsulation" type="url" value="https://www.w3.org"/>url label with non-empty value</label><br/>
<label><input class="ex" data-expectedlabel="week label" data-testname="html: label input[type=week] encapsulation" type="week"/>week label</label><br/>
<label><input class="ex" data-expectedlabel="week label with non-empty value" data-testname="html: label input[type=week][value='2025-W01'] encapsulation" type="week" value="2025-W01"/>week label with non-empty value</label><br/>
<!-- skipped: skip textarea for v1 since all engines fail in different ways. need to verify label/textarea is expected. -->
<!--
<h2>HTML textarea</h2>
<label for="ta">textarea label</label><textarea data-expectedlabel="textarea label" data-testname="html: label[for] textarea" class="ex"></textarea><br>
<label for="ta">textarea label<textarea data-expectedlabel="textarea label" data-testname="html: textarea encapsulation" class="ex"></textarea></label><br>
-->
<h2>HTML select</h2>
<!-- todo: select for/id -->
<label for="select">select label</label>
<select class="ex" data-expectedlabel="select label" data-testname="html: select for/id" id="select">
<option>foo</option>
</select>
<br/>
<!-- select encapsulation -->
<label>
select label
<select class="ex" data-expectedlabel="select label" data-testname="html: select encapsulation">
<option>foo</option>
</select>
</label><br/>
<!-- todo: select labeled by selected option. All engines currently fail in different ways. Not sure which is correct. -->
<!--
<select data-expectedlabel="select label" data-testname="html: select w/selected option" class="ex">
<option>foo</option>
<option selected>select label</option>
<option>bar</option>
</select>
<br>
-->
<h2>HTML img/picture</h2>
<!-- skipped: img:not([alt]) -->
<!-- skipped: img[alt=""] -->
<img alt="image label" class="ex" data-expectedlabel="image label" data-testname="html: img[alt] (non-empty)" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="/>
<picture>
<source srcset="#"/>
<img alt="picture label" class="ex" data-expectedlabel="picture label" data-testname="html: picture &gt; img[alt] (non-empty)" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="/>
</picture>
<!-- elsewhere: image map area alt -> ./fragile/area-alt.html -->
<h2>HTML fieldset/legend</h2>
<fieldset class="ex" data-expectedlabel="fieldset legend label" data-testname="html: fieldset &gt; legend">
<legend>fieldset legend label</legend>
<input type="text"/><br/>
</fieldset>
<h2>HTML table/caption</h2>
<table class="ex" data-expectedlabel="table caption label" data-testname="html: table &gt; caption">
<caption>table caption label</caption>
<tr><th>a</th><th>b</th><th>c</th></tr>
<tr><th>1</th><td>2</td><td>3</td></tr>
</table>
<!-- SVG: -> /svg-aam/name/ -->
<!-- todo: Ruby? -->
<!-- todo: MathML? -->
<!-- todo: does HTML input[placeholder="foo"] count as a host language labeling mechanism? -->
<script>
AriaUtils.verifyLabelsBySelector(".ex");
</script>
</body>
</html>

View file

@ -0,0 +1,60 @@
(function() {
var subTestStart = 0;
var subTestEnd = Infinity;
var match;
if (location.search) {
match = /(?:^\?|&)(\d+)-(\d+|last)(?:&|$)/.exec(location.search);
if (match) {
subTestStart = parseInt(match[1], 10);
if (match[2] !== "last") {
subTestEnd = parseInt(match[2], 10);
}
}
// Below is utility code to generate <meta> for copy/paste into tests.
// Sample usage:
// test.html?split=1000
match = /(?:^\?|&)split=(\d+)(?:&|$)/.exec(location.search);
if (match) {
var testsPerVariant = parseInt(match[1], 10);
add_completion_callback(tests => {
var total = tests.length;
var template = '<meta name="variant" content="?%s-%s">';
var metas = [];
for (var i = 1; i < total - testsPerVariant; i = i + testsPerVariant) {
metas.push(template.replace("%s", i).replace("%s", i + testsPerVariant - 1));
}
metas.push(template.replace("%s", i).replace("%s", "last"));
var pre = document.createElement('pre');
pre.textContent = metas.join('\n');
document.body.insertBefore(pre, document.body.firstChild);
document.getSelection().selectAllChildren(pre);
});
}
}
/**
* Check if `currentSubTest` is in the subset specified in the URL.
* @param {number} currentSubTest
* @returns {boolean}
*/
function shouldRunSubTest(currentSubTest) {
return currentSubTest >= subTestStart && currentSubTest <= subTestEnd;
}
var currentSubTest = 0;
/**
* Only test a subset of tests with, e.g., `?1-10` in the URL.
* Can be used together with `<meta name="variant" content="...">`
* Sample usage:
* for (const test of tests) {
* subsetTest(async_test, test.fn, test.name);
* }
*/
function subsetTest(testFunc, ...args) {
currentSubTest++;
if (shouldRunSubTest(currentSubTest)) {
return testFunc(...args);
}
return null;
}
self.shouldRunSubTest = shouldRunSubTest;
self.subsetTest = subsetTest;
})();