Skip to content
Permalink
Browse files
Add WebIDL special operation support: serializer
https://bugs.webkit.org/show_bug.cgi?id=156293

Patch by Alejandro G. Castro <alex@igalia.com> on 2016-09-28
Reviewed by Youenn Fablet.

Source/WebCore:

Added support for the serializer special operation for WebIDLs,
current implementation adds support for:
  - just the keyword: serializer; It will return all the
    attributes of in an object.
  - map of entries with the attributes: serializer = {attribute1,
    attribute2, ...}

It creates a toJSON method that returns the serialized value
converted into an ECMAScript value. For more information check the
definition of the operation:

http://heycam.github.io/webidl/#idl-serializers

We have created a new function in the API of the objects
that are marked as serializer.

Used the support to add new API for RTCIceCandidate and
RTCSessionDescription.

Updated the tests expectations of the bindings.

Tests: bindings/scripts/test/TestNode.idl
       bindings/scripts/test/TestObj.idl
       fast/mediastream/RTCIceCandidate.html
       fast/mediastream/RTCSessionDescription.html

* Modules/mediastream/RTCIceCandidate.idl: Added the serializer
operation.
* Modules/mediastream/RTCSessionDescription.idl: Added the
serializer operation.
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateImplementation): Added the calls to the serializer
code generator.
(GenerateSerializerFunction): Added, generates the toJSON function
adding all the serializable->attributes value to an object as
defined in the spec.
* bindings/scripts/IDLParser.pm: Modified the serializer parser
that was unused to support the WebIDL spec parts. Added a new
domSerializable type to store the list of attributes in the
possible map.
(parseSerializer): Modified the function to follow the
semicolon rule in the spec, now the serializer line must have a
semicolon like any other line.
(parseSerializerRest): The function now has to get the attributes
list from the pattern parsing function and add them to the
domSerializable item.
(parseSerializationPattern): Now this function returns the list of
attributes in the serializable map or list if we have one.
(parseSerializationAttributes): Added, this function replaces the
Map and List functions, the currently supported parts are similar
for both situations.
(applyMemberList): Added the serializable item to the interface
variable and populate the serializable in case there is not a
defined map.
(parseSerializationPatternMap): Replaced with
parseSerializationAttributes.
(parseSerializationPatternList): Ditto.
* bindings/scripts/test/JS/JSTestNode.cpp: Modified the expected result.
(WebCore::jsTestNodePrototypeFunctionToJSON):
* bindings/scripts/test/JS/JSTestObj.cpp: Modified the expected result.
(WebCore::jsTestObjPrototypeFunctionToJSON):
* bindings/scripts/test/TestNode.idl: Added the serializer test.
* bindings/scripts/test/TestObj.idl: Added serializer map test.

LayoutTests:

Verify the new API of the objects and check what happens when user
modifies the values and types of the attributes, or adds a null value.

* fast/mediastream/RTCIceCandidate-expected.txt:
* fast/mediastream/RTCIceCandidate.html:
* fast/mediastream/RTCSessionDescription-expected.txt:
* fast/mediastream/RTCSessionDescription.html:

Canonical link: https://commits.webkit.org/180612@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@206514 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
alexgcastro authored and webkit-commit-queue committed Sep 28, 2016
1 parent 042b94d commit 0e26018d9f4785e6508ae963a1ede6927e3152a8
Show file tree
Hide file tree
Showing 14 changed files with 294 additions and 40 deletions.
@@ -1,3 +1,18 @@
2016-09-28 Alejandro G. Castro <alex@igalia.com>

Add WebIDL special operation support: serializer
https://bugs.webkit.org/show_bug.cgi?id=156293

Reviewed by Youenn Fablet.

Verify the new API of the objects and check what happens when user
modifies the values and types of the attributes, or adds a null value.

* fast/mediastream/RTCIceCandidate-expected.txt:
* fast/mediastream/RTCIceCandidate.html:
* fast/mediastream/RTCSessionDescription-expected.txt:
* fast/mediastream/RTCSessionDescription.html:

2016-09-28 Khaled Hosny <khaledhosny@eglug.org>

Use new woff2 API
@@ -7,6 +7,21 @@ PASS candidate = new RTCIceCandidate(initializer); did not throw exception.
PASS candidate.candidate is "foo"
PASS candidate.sdpMid is "bar"
PASS candidate.sdpMLineIndex is 6
PASS RTCIceCandidate.prototype.toJSON is defined.
PASS Object.getOwnPropertyDescriptor(RTCIceCandidate.prototype, "toJSON").enumerable is true
PASS Object.getOwnPropertyDescriptor(RTCIceCandidate.prototype, "toJSON").writable is true
PASS Object.getOwnPropertyDescriptor(RTCIceCandidate.prototype, "toJSON").configurable is true
PASS RTCIceCandidate.prototype.toJSON.length is 0
PASS RTCIceCandidate.prototype.toJSON.name is "toJSON"
PASS Object.getOwnPropertyDescriptor(jsonMap, "candidate").enumerable is true
PASS Object.getOwnPropertyDescriptor(jsonMap, "candidate").writable is true
PASS Object.getOwnPropertyDescriptor(jsonMap, "candidate").configurable is true
PASS childCandidate.toJSON(); threw exception TypeError: Can only call RTCIceCandidate.toJSON on instances of RTCIceCandidate.
PASS JSON.stringify(candidate.toJSON()) is "{\"candidate\":\"foo\",\"sdpMid\":\"bar\",\"sdpMLineIndex\":6}"
PASS JSON.stringify(candidate.toJSON()) is "{\"candidate\":\"foo\",\"sdpMid\":\"bar\",\"sdpMLineIndex\":6}"
PASS JSON.stringify(candidate.toJSON()) is "{\"candidate\":\"foo\",\"sdpMid\":\"bar\",\"sdpMLineIndex\":6}"
PASS JSON.stringify(candidate.toJSON()) is "{\"candidate\":\"foo\",\"sdpMid\":\"bar\",\"sdpMLineIndex\":6}"
PASS JSON.stringify(candidate.toJSON()) is "{\"candidate\":\"foo\",\"sdpMid\":\"bar\",\"sdpMLineIndex\":6}"

Attributes are readonly
candidate.candidate = "foo-updated"
@@ -13,6 +13,33 @@
shouldBe('candidate.candidate', '"foo"');
shouldBe('candidate.sdpMid', '"bar"');
shouldBe('candidate.sdpMLineIndex', '6');
shouldBeDefined('RTCIceCandidate.prototype.toJSON');
shouldBeTrue('Object.getOwnPropertyDescriptor(RTCIceCandidate.prototype, "toJSON").enumerable');
shouldBeTrue('Object.getOwnPropertyDescriptor(RTCIceCandidate.prototype, "toJSON").writable');
shouldBeTrue('Object.getOwnPropertyDescriptor(RTCIceCandidate.prototype, "toJSON").configurable');
shouldBe('RTCIceCandidate.prototype.toJSON.length', '0');
shouldBe('RTCIceCandidate.prototype.toJSON.name', '"toJSON"');

var jsonMap = candidate.toJSON();
shouldBeTrue('Object.getOwnPropertyDescriptor(jsonMap, "candidate").enumerable');
shouldBeTrue('Object.getOwnPropertyDescriptor(jsonMap, "candidate").writable');
shouldBeTrue('Object.getOwnPropertyDescriptor(jsonMap, "candidate").configurable');

var childRTCIceCandidate = function() {};
childRTCIceCandidate.prototype = Object.create(RTCIceCandidate.prototype);
var childCandidate = new childRTCIceCandidate();
shouldThrow('childCandidate.toJSON();');

shouldBeEqualToString('JSON.stringify(candidate.toJSON())', '{"candidate":"foo","sdpMid":"bar","sdpMLineIndex":6}');
candidate.newAttribute = "new value";
shouldBeEqualToString('JSON.stringify(candidate.toJSON())', '{"candidate":"foo","sdpMid":"bar","sdpMLineIndex":6}');
candidate.sdpMLineIndex = "not a number";
shouldBeEqualToString('JSON.stringify(candidate.toJSON())', '{"candidate":"foo","sdpMid":"bar","sdpMLineIndex":6}');
candidate.sdpMid = 7;
shouldBeEqualToString('JSON.stringify(candidate.toJSON())', '{"candidate":"foo","sdpMid":"bar","sdpMLineIndex":6}');
candidate.sdpMid = null;
shouldBeEqualToString('JSON.stringify(candidate.toJSON())', '{"candidate":"foo","sdpMid":"bar","sdpMLineIndex":6}');

debug("");

debug("Attributes are readonly");
@@ -6,6 +6,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
PASS sessionDescription = new RTCSessionDescription(initializer); did not throw exception.
PASS sessionDescription.type is "offer"
PASS sessionDescription.sdp is "foobar"
PASS JSON.stringify(sessionDescription.toJSON()) is "{\"type\":\"offer\",\"sdp\":\"foobar\"}"
*** Attributes are read-only.
PASS sessionDescription.type = 'answer' did not throw exception.
PASS sessionDescription.type is 'offer'
@@ -14,6 +14,7 @@
shouldNotThrow("sessionDescription = new RTCSessionDescription(initializer);");
shouldBe('sessionDescription.type', '"offer"');
shouldBe('sessionDescription.sdp', '"foobar"');
shouldBeEqualToString('JSON.stringify(sessionDescription.toJSON())', '{"type":"offer","sdp":"foobar"}');

debug("*** Attributes are read-only.");
shouldNotThrow("sessionDescription.type = 'answer'");
@@ -1,3 +1,74 @@
2016-09-28 Alejandro G. Castro <alex@igalia.com>

Add WebIDL special operation support: serializer
https://bugs.webkit.org/show_bug.cgi?id=156293

Reviewed by Youenn Fablet.

Added support for the serializer special operation for WebIDLs,
current implementation adds support for:
- just the keyword: serializer; It will return all the
attributes of in an object.
- map of entries with the attributes: serializer = {attribute1,
attribute2, ...}

It creates a toJSON method that returns the serialized value
converted into an ECMAScript value. For more information check the
definition of the operation:

http://heycam.github.io/webidl/#idl-serializers

We have created a new function in the API of the objects
that are marked as serializer.

Used the support to add new API for RTCIceCandidate and
RTCSessionDescription.

Updated the tests expectations of the bindings.

Tests: bindings/scripts/test/TestNode.idl
bindings/scripts/test/TestObj.idl
fast/mediastream/RTCIceCandidate.html
fast/mediastream/RTCSessionDescription.html

* Modules/mediastream/RTCIceCandidate.idl: Added the serializer
operation.
* Modules/mediastream/RTCSessionDescription.idl: Added the
serializer operation.
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateImplementation): Added the calls to the serializer
code generator.
(GenerateSerializerFunction): Added, generates the toJSON function
adding all the serializable->attributes value to an object as
defined in the spec.
* bindings/scripts/IDLParser.pm: Modified the serializer parser
that was unused to support the WebIDL spec parts. Added a new
domSerializable type to store the list of attributes in the
possible map.
(parseSerializer): Modified the function to follow the
semicolon rule in the spec, now the serializer line must have a
semicolon like any other line.
(parseSerializerRest): The function now has to get the attributes
list from the pattern parsing function and add them to the
domSerializable item.
(parseSerializationPattern): Now this function returns the list of
attributes in the serializable map or list if we have one.
(parseSerializationAttributes): Added, this function replaces the
Map and List functions, the currently supported parts are similar
for both situations.
(applyMemberList): Added the serializable item to the interface
variable and populate the serializable in case there is not a
defined map.
(parseSerializationPatternMap): Replaced with
parseSerializationAttributes.
(parseSerializationPatternList): Ditto.
* bindings/scripts/test/JS/JSTestNode.cpp: Modified the expected result.
(WebCore::jsTestNodePrototypeFunctionToJSON):
* bindings/scripts/test/JS/JSTestObj.cpp: Modified the expected result.
(WebCore::jsTestObjPrototypeFunctionToJSON):
* bindings/scripts/test/TestNode.idl: Added the serializer test.
* bindings/scripts/test/TestObj.idl: Added serializer map test.

2016-09-28 Michael Catanzaro <mcatanzaro@igalia.com>

[GTK] Simplify platformForUAString
@@ -39,5 +39,7 @@
readonly attribute DOMString candidate;
readonly attribute DOMString? sdpMid;
readonly attribute unsigned short? sdpMLineIndex;

serializer = {candidate, sdpMid, sdpMLineIndex};
};

@@ -38,6 +38,8 @@
] interface RTCSessionDescription {
[SetterRaisesException] readonly attribute RTCSdpType type;
readonly attribute DOMString sdp;

serializer = {type, sdp};
};

enum RTCSdpType {
@@ -664,6 +664,7 @@ sub PrototypeFunctionCount
}

$count += scalar @{$interface->iterable->functions} if $interface->iterable;
$count += scalar @{$interface->serializable->functions} if $interface->serializable;

return $count;
}
@@ -1680,6 +1681,7 @@ sub GeneratePropertiesHashTable

my @functions = @{$interface->functions};
push(@functions, @{$interface->iterable->functions}) if IsKeyValueIterableInterface($interface);
push(@functions, @{$interface->serializable->functions}) if $interface->serializable;
foreach my $function (@functions) {
next if ($function->signature->extendedAttributes->{"PrivateIdentifier"} and not $function->signature->extendedAttributes->{"PublicIdentifier"});
next if ($function->isStatic);
@@ -2322,6 +2324,7 @@ sub GenerateImplementation

my @functions = @{$interface->functions};
push(@functions, @{$interface->iterable->functions}) if IsKeyValueIterableInterface($interface);
push(@functions, @{$interface->serializable->functions}) if $interface->serializable;

my $numConstants = @{$interface->constants};
my $numFunctions = @functions;
@@ -3533,9 +3536,9 @@ END

}

if ($interface->iterable) {
GenerateImplementationIterableFunctions($interface);
}

GenerateImplementationIterableFunctions($interface) if $interface->iterable;
GenerateSerializerFunction($interface, $interfaceName, $className) if $interface->serializable;

if ($needsVisitChildren) {
push(@implContent, "void ${className}::visitChildren(JSCell* cell, SlotVisitor& visitor)\n");
@@ -3758,6 +3761,38 @@ END
push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
}

sub GenerateSerializerFunction
{
my ($interface, $interfaceName, $className) = @_;
my $serializerFunctionName = "toJSON";
my $serializerNativeFunctionName = $codeGenerator->WK_lcfirst($className) . "PrototypeFunction" . $codeGenerator->WK_ucfirst($serializerFunctionName);

AddToImplIncludes("ObjectConstructor.h");
push(@implContent, "EncodedJSValue JSC_HOST_CALL ${serializerNativeFunctionName}(ExecState* state)\n");
push(@implContent, "{\n");
push(@implContent, " ASSERT(state);\n");
push(@implContent, " auto thisValue = state->thisValue();\n");
push(@implContent, " auto castedThis = jsDynamicCast<JS$interfaceName*>(thisValue);\n");
push(@implContent, " VM& vm = state->vm();\n");
push(@implContent, " auto throwScope = DECLARE_THROW_SCOPE(vm);\n");
push(@implContent, " if (UNLIKELY(!castedThis)){\n");
push(@implContent, " return throwThisTypeError(*state, throwScope, \"$interfaceName\", \"$serializerFunctionName\");\n");
push(@implContent, " }\n");
push(@implContent, " ASSERT_GC_OBJECT_INHERITS(castedThis, ${className}::info());\n\n") unless $interfaceName eq "EventTarget";
push(@implContent, " auto* result = constructEmptyObject(state);\n");
foreach my $attribute (@{$interface->attributes}) {
my $name = $attribute->signature->name;
if (grep $_ eq $name, @{$interface->serializable->attributes}) {
my $getFunctionName = GetAttributeGetterName($interface, $className, $attribute);
push(@implContent, " auto ${name}Value = ${getFunctionName}(state, JSValue::encode(thisValue), Identifier());\n");
push(@implContent, " ASSERT(!throwScope.exception());\n");
push(@implContent, " result->putDirect(vm, Identifier::fromString(&vm, \"${name}\"), JSValue::decode(${name}Value));\n");
}
}
push(@implContent, " return JSValue::encode(result);\n");
push(@implContent, "}\n\n");
}

sub GenerateFunctionCastedThis
{
my ($interface, $className, $function, $shouldRejectPromise) = @_;

0 comments on commit 0e26018

Please sign in to comment.