Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement custom element registry #17112

Merged
merged 3 commits into from Jun 5, 2017

Conversation

@cbrewster
Copy link
Member

cbrewster commented May 31, 2017

Implements https://html.spec.whatwg.org/multipage/#customelementregistry


  • ./mach build -d does not report any errors
  • ./mach test-tidy does not report any errors
  • These changes fix #16753 (github issue number if applicable).
  • There are tests for these changes OR
  • These changes do not require tests because _____

This change is Reviewable

@highfive
Copy link

highfive commented May 31, 2017

Heads up! This PR modifies the following files:

  • @fitzgen: components/script/dom/mod.rs, components/script/dom/customelementregistry.rs, components/script/dom/webidls/CustomElementRegistry.webidl, components/script/dom/window.rs, components/script/dom/webidls/Window.webidl
  • @KiChjang: components/script/dom/mod.rs, components/script/dom/customelementregistry.rs, components/script/dom/webidls/CustomElementRegistry.webidl, components/script/dom/window.rs, components/script/dom/webidls/Window.webidl
@highfive
Copy link

highfive commented May 31, 2017

warning Warning warning

  • These commits modify unsafe code. Please review it carefully!
@cbrewster
Copy link
Member Author

cbrewster commented May 31, 2017

r? @jdm

part of #9372

@highfive highfive assigned jdm and unassigned metajack May 31, 2017
}

// TODO: 7.2
// Check that the element interface for extends is not HTMLUnknownElement

This comment has been minimized.

@cbrewster

cbrewster May 31, 2017

Author Member

I'm not entirely sure the best way to go about this. AFAICT we only determine the element interface here: https://dxr.mozilla.org/servo/rev/779edd7c4aaf900f12fab378a378b0fc52d4c628/components/script/dom/create.rs#129-272.

This comment has been minimized.

@nox

nox Jun 2, 2017

Member

Yeah, you need a similar match expression for this step to be implemented.

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Indeed. I am trying to think of a way that we could reuse the match here so we don't need to maintain two matches, but I haven't thought of anything yet. How often is that match changed?

@cbrewster cbrewster force-pushed the cbrewster:custom_element_registry branch from d022726 to 96d3193 Jun 1, 2017
Copy link
Member

nox left a comment

First review pass.

rooted!(in(global_scope.get_cx()) let mut prototype = UndefinedValue());
unsafe {
// Step 10.1
let c_name = CString::new("prototype").unwrap();

This comment has been minimized.

@nox

nox Jun 2, 2017

Member

You don't need this here, just use b"prototype\0".

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

I think we have to use CString here. JS_GetProperty expects a *const i8 and b"prototype\0".as_ptr() gets a *const u8

This comment has been minimized.

@jdm

jdm Jun 2, 2017

Member

Other places use b"foo\0".as_ptr() as *const _.

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Ok, will change it to that

// https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define
// Steps 10.1, 10.2
#[allow(unsafe_code)]
fn check_prototype(&self, constructor: HandleObject) -> ErrorResult {

This comment has been minimized.

@nox

nox Jun 2, 2017

Member

Why make a separate method?

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Step 10.1 (The second 10.1, which unsets the element definition is running) By making it a function I can return early without worrying about not unsetting the flag.


// Step 10.2
if !prototype.is_object() {
return Err(Error::Type("constructor.protoype is not an object".to_owned()));

This comment has been minimized.

@nox

nox Jun 2, 2017

Member

Typo: prototype.

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Done.

}

impl CustomElementRegistryMethods for CustomElementRegistry {
#[allow(unsafe_code, unrooted_must_root)]

This comment has been minimized.

@nox

nox Jun 2, 2017

Member

Why is unrooted_must_root required?

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

We have to allow it in order to use Promises.


// Step 1
if unsafe { !IsConstructor(constructor.get()) } {
return Err(Error::Type("Second argument of CustomElementRegistry.defin is not a constructor".to_owned()));

This comment has been minimized.

@nox

nox Jun 2, 2017

Member

Typo: define.

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Done.


// https://html.spec.whatwg.org/multipage/#dom-customelementregistry-whendefined
#[allow(unrooted_must_root)]
fn WhenDefined(&self, name: DOMString) -> Fallible<Rc<Promise>> {

This comment has been minimized.

@nox

nox Jun 2, 2017

Member

This method isn't actually fallible.

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Done.

let mut map = self.when_defined.borrow_mut();

// Steps 4, 5
let promise = match map.get(&name).cloned() {

This comment has been minimized.

@nox

nox Jun 2, 2017

Member

Using Option::unwrap_or_else would be cleaner.

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Done.

}
} else {
return false;
}

This comment has been minimized.

@nox

nox Jun 2, 2017

Member
if !name.chars().next().map_or(false, |c| c >= 'a' && c >= 'z') {
    return false;
}

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Done.


// Check if this character is not a PCENChar
// https://html.spec.whatwg.org/multipage/#prod-pcenchar
if c != '-' && c != '.' && c != '_' && c != '\u{B7}' &&

This comment has been minimized.

@nox

nox Jun 2, 2017

Member

Please make a is_potential_custom_element_char function and use that here, all the reversed conditions don't help readability.

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Done.


for c in name.chars() {
if c == '-' {
has_dash = true;

This comment has been minimized.

@nox

nox Jun 2, 2017

Member

Nit: you can continue here.

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Done.

Copy link
Member Author

cbrewster left a comment

Thanks for the review @nox!

// https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define
// Steps 10.1, 10.2
#[allow(unsafe_code)]
fn check_prototype(&self, constructor: HandleObject) -> ErrorResult {

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Step 10.1 (The second 10.1, which unsets the element definition is running) By making it a function I can return early without worrying about not unsetting the flag.

rooted!(in(global_scope.get_cx()) let mut prototype = UndefinedValue());
unsafe {
// Step 10.1
let c_name = CString::new("prototype").unwrap();

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

I think we have to use CString here. JS_GetProperty expects a *const i8 and b"prototype\0".as_ptr() gets a *const u8


// Step 10.2
if !prototype.is_object() {
return Err(Error::Type("constructor.protoype is not an object".to_owned()));

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Done.

}

impl CustomElementRegistryMethods for CustomElementRegistry {
#[allow(unsafe_code, unrooted_must_root)]

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

We have to allow it in order to use Promises.


// Step 1
if unsafe { !IsConstructor(constructor.get()) } {
return Err(Error::Type("Second argument of CustomElementRegistry.defin is not a constructor".to_owned()));

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Done.


// Step 1
if !is_valid_custom_element_name(&name) {
return Err(Error::Syntax);

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Woops! misread spec. fixed.

let mut map = self.when_defined.borrow_mut();

// Steps 4, 5
let promise = match map.get(&name).cloned() {

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Done.

}
} else {
return false;
}

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Done.


for c in name.chars() {
if c == '-' {
has_dash = true;

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Done.


// Check if this character is not a PCENChar
// https://html.spec.whatwg.org/multipage/#prod-pcenchar
if c != '-' && c != '.' && c != '_' && c != '\u{B7}' &&

This comment has been minimized.

@cbrewster

cbrewster Jun 2, 2017

Author Member

Done.


[customElements.whenDefined must return an unresolved promise when the registry does not contain the entry with the given name]
expected: FAIL

[customElements.whenDefined must return a rejected promise when the given name is not a valid custom element name]

This comment has been minimized.

@jdm

jdm Jun 2, 2017

Member

I suspect this test passes now.

@cbrewster cbrewster force-pushed the cbrewster:custom_element_registry branch 2 times, most recently from 666f935 to e233823 Jun 2, 2017
Copy link
Member

jdm left a comment

This is a really readable implementation!

}

if !is_potential_custom_element_char(c)
{

This comment has been minimized.

@jdm

jdm Jun 2, 2017

Member

nit: { on the previous line.

This comment has been minimized.

@cbrewster

cbrewster Jun 3, 2017

Author Member

Done.


for c in chars {
if c == '-' {
has_dash = true;

This comment has been minimized.

@jdm

jdm Jun 2, 2017

Member

Should we return false if has_dash is already true?

This comment has been minimized.

@cbrewster

cbrewster Jun 3, 2017

Author Member

The name can have more than one dash, it just needs at a minimum one.

// https://html.spec.whatwg.org/multipage/#dom-customelementregistry-get
#[allow(unsafe_code)]
unsafe fn Get(&self, cx: *mut JSContext, name: DOMString) -> JSVal {
match self.definitions.borrow_mut().get(&name) {

This comment has been minimized.

@jdm

jdm Jun 2, 2017

Member

borrow(), right?

This comment has been minimized.

@cbrewster

cbrewster Jun 3, 2017

Author Member

Done.

}

// TODO: 7.2
// Check that the element interface for extends is not HTMLUnknownElement

This comment has been minimized.

@jdm

jdm Jun 2, 2017

Member

I don't see any way around it but duplicating the relevant data from create.rs, unfortunately.


[customElements.define unset the element definition is running flag before upgrading custom elements]
expected: FAIL

[customElements.define must not throw when defining another custom element in a different global object during Get(constructor, "prototype")]

This comment has been minimized.

@jdm

jdm Jun 2, 2017

Member

Can we look into why this test fails?

This comment has been minimized.

@cbrewster

cbrewster Jun 3, 2017

Author Member

The test relies on createElement creating a custom element which isn't implemented yet:

assert_true(iframe.contentDocument.createElement('another-custom-element') instanceof InnerCustomElement);
@cbrewster cbrewster force-pushed the cbrewster:custom_element_registry branch from e233823 to 5bcf748 Jun 3, 2017
// https://html.spec.whatwg.org/multipage/#dom-customelementregistry-get
#[allow(unsafe_code)]
unsafe fn Get(&self, cx: *mut JSContext, name: DOMString) -> JSVal {
match self.definitions.borrow_mut().get(&name) {

This comment has been minimized.

@cbrewster

cbrewster Jun 3, 2017

Author Member

Done.


for c in chars {
if c == '-' {
has_dash = true;

This comment has been minimized.

@cbrewster

cbrewster Jun 3, 2017

Author Member

The name can have more than one dash, it just needs at a minimum one.

}

if !is_potential_custom_element_char(c)
{

This comment has been minimized.

@cbrewster

cbrewster Jun 3, 2017

Author Member

Done.


[customElements.define unset the element definition is running flag before upgrading custom elements]
expected: FAIL

[customElements.define must not throw when defining another custom element in a different global object during Get(constructor, "prototype")]

This comment has been minimized.

@cbrewster

cbrewster Jun 3, 2017

Author Member

The test relies on createElement creating a custom element which isn't implemented yet:

assert_true(iframe.contentDocument.createElement('another-custom-element') instanceof InnerCustomElement);
@@ -1,5 +1,53 @@
[define.html]
type: testharness
[Custom Elements: Element definition]
[If constructor is arrow function, should throw a TypeError]

This comment has been minimized.

@cbrewster

cbrewster Jun 3, 2017

Author Member

I am not sure how I should check for this, is there anything other than IsConstructor that I need to do?

This comment has been minimized.

@jdm

jdm Jun 3, 2017

Member

I suspect it's a limitation of our old version of Spider monkey. It would be worth seeing if Gecko passes that test.

This comment has been minimized.

@cbrewster

cbrewster Jun 4, 2017

Author Member

Ahh probably, Gecko does pass.

@jdm
Copy link
Member

jdm commented Jun 5, 2017

@bors-servo
Copy link
Contributor

bors-servo commented Jun 5, 2017

📌 Commit 5bcf748 has been approved by jdm

@bors-servo
Copy link
Contributor

bors-servo commented Jun 5, 2017

Testing commit 5bcf748 with merge fccaefa...

bors-servo added a commit that referenced this pull request Jun 5, 2017
Implement custom element registry

<!-- Please describe your changes on the following line: -->
Implements https://html.spec.whatwg.org/multipage/#customelementregistry

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #16753 (github issue number if applicable).

<!-- Either: -->
- [X] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17112)
<!-- Reviewable:end -->
@bors-servo
Copy link
Contributor

bors-servo commented Jun 5, 2017

💔 Test failed - linux-rel-wpt

@jdm
Copy link
Member

jdm commented Jun 5, 2017

You should add a Preference annotation to the CustomElementRegistry interface as well.

cbrewster added 3 commits May 11, 2017
The test relies on DOM elements with ids beind added
as properties of the window. Servo does not do this, and
this is not a best practice.
@cbrewster cbrewster force-pushed the cbrewster:custom_element_registry branch from 5bcf748 to 87bf4ca Jun 5, 2017
@cbrewster
Copy link
Member Author

cbrewster commented Jun 5, 2017

@bors-servo r=jdm

@bors-servo
Copy link
Contributor

bors-servo commented Jun 5, 2017

📌 Commit 87bf4ca has been approved by jdm

@bors-servo
Copy link
Contributor

bors-servo commented Jun 5, 2017

Testing commit 87bf4ca with merge b584944...

bors-servo added a commit that referenced this pull request Jun 5, 2017
Implement custom element registry

<!-- Please describe your changes on the following line: -->
Implements https://html.spec.whatwg.org/multipage/#customelementregistry

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #16753 (github issue number if applicable).

<!-- Either: -->
- [X] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17112)
<!-- Reviewable:end -->
@bors-servo
Copy link
Contributor

bors-servo commented Jun 5, 2017

@bors-servo bors-servo merged commit 87bf4ca into servo:master Jun 5, 2017
3 checks passed
3 checks passed
continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
homu Test successful
Details
jdm added a commit to web-platform-tests/wpt that referenced this pull request Jun 19, 2017
The test relies on DOM elements with ids beind added
as properties of the window. Servo does not do this, and
this is not a best practice.

Upstreamed from servo/servo#17112 [ci skip]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

6 participants
You can’t perform that action at this time.