-
Notifications
You must be signed in to change notification settings - Fork 32
vaev-webdriver: Intial implementation of webdriver2. #129
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
base: main
Are you sure you want to change the base?
Changes from all commits
d279f0e
ea4403d
483bfea
fca9a92
034d670
a451f1b
d0ae01a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -94,6 +94,7 @@ export Symbol qualifiedAttrNameCased(Str name) { | |
| if (eqCi(Str(#VALUE), name)) \ | ||
| return Symbol::from(Str(#VALUE)); | ||
| #include "defs/ns-svg-attr-names.inc" | ||
|
|
||
| #undef ATTR | ||
| return Symbol::from(name); | ||
| } | ||
|
|
@@ -103,6 +104,7 @@ export Symbol qualifiedTagNameCased(Str name) { | |
| if (eqCi(Str(#VALUE), name)) \ | ||
| return Symbol::from(Str(#VALUE)); | ||
| #include "defs/ns-svg-tag-names.inc" | ||
|
|
||
|
||
| #undef TAG | ||
| return Symbol::from(name); | ||
| } | ||
|
|
@@ -127,13 +129,18 @@ namespace Dom { | |
|
|
||
| void Dom::QualifiedName::repr(Io::Emit& e) const { | ||
| Str displayNamespace = ns.str(); | ||
| // NOTE: If current node is an element in the HTML namespace, the MathML namespace, | ||
| // or the SVG namespace, then let tagname be current node's local name. | ||
| // Otherwise, let tagname be current node's qualified name. | ||
| // SEE: 13.3.5.2 https://html.spec.whatwg.org/multipage/parsing.html#serialising-html-fragments | ||
| if (ns == Html::NAMESPACE) { | ||
| displayNamespace = "html"; | ||
| } else if (ns == Svg::NAMESPACE) { | ||
| displayNamespace = "svg"; | ||
| } else if (ns == MathMl::NAMESPACE) { | ||
| displayNamespace = "mathml"; | ||
| } | ||
|
|
||
|
||
| e("{}:{}", displayNamespace, name); | ||
| } | ||
|
|
||
|
|
||
sleepy-monax marked this conversation as resolved.
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,189 @@ | ||
| export module Vaev.Engine:dom.serialisation; | ||
|
|
||
| import Karm.Core; | ||
| import Karm.Gc; | ||
|
|
||
| import :dom.element; | ||
| import :dom.comment; | ||
| import :dom.document; | ||
| import :dom.documentType; | ||
|
|
||
| using namespace Karm; | ||
|
|
||
| namespace Vaev::Dom { | ||
|
|
||
| // MARK: Escaping -------------------------------------------------------------- | ||
| // https://html.spec.whatwg.org/multipage/parsing.html#escapingString | ||
|
|
||
| export void escapeString(Io::Emit& e, Io::SScan& s, bool attributeMode = false) { | ||
| while (not s.ended()) { | ||
sleepy-monax marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| auto r = s.next(); | ||
| // Replace any occurrence of the "&" character by the string "&". | ||
| if (r == '&') | ||
| e("&"); | ||
|
|
||
| // Replace any occurrences of the U+00A0 NO-BREAK SPACE character by the string " ". | ||
| else if (r == U'\xA0') | ||
| e(" "); | ||
|
|
||
| // Replace any occurrences of the "<" character by the string "<". | ||
| else if (r == '<') | ||
| e("<"); | ||
|
|
||
| // Replace any occurrences of the ">" character by the string ">". | ||
| else if (r == '>') | ||
| e(">"); | ||
|
|
||
| // If the algorithm was invoked in the attribute mode, then replace any occurrences of the """ character by the string """. | ||
| else if (attributeMode and r == '"') | ||
| e("""); | ||
|
|
||
| else | ||
| e(r); | ||
| } | ||
| } | ||
|
|
||
| export void escapeString(Io::Emit& e, Str str, bool attributeMode = false) { | ||
| Io::SScan s{str}; | ||
| escapeString(e, s, attributeMode); | ||
| } | ||
|
|
||
| // MARK: Serialize ------------------------------------------------------------- | ||
| // https://html.spec.whatwg.org/multipage/parsing.html#serialising-html-fragments | ||
|
|
||
| // https://html.spec.whatwg.org/multipage/parsing.html#serializes-as-void | ||
| bool _serializeAsVoid(Gc::Ref<Node> node) { | ||
| auto el = node->is<Element>(); | ||
| if (not el) | ||
| return false; | ||
|
|
||
| // For the purposes of the following algorithm, an element serializes as void | ||
| // if its element type is one of the void elements, or is basefont, bgsound, frame, keygen, or param. | ||
| return el->isVoidElement() or | ||
| el->qualifiedName == Html::BASEFONT_TAG or | ||
| el->qualifiedName == Html::BGSOUND_TAG or | ||
| el->qualifiedName == Html::FRAME_TAG or | ||
| el->qualifiedName == Html::KEYGEN_TAG or | ||
| el->qualifiedName == Html::PARAM_TAG; | ||
sleepy-monax marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // https://html.spec.whatwg.org/multipage/parsing.html#html-fragment-serialisation-algorithm | ||
| export void serializeHtmlFragment(Gc::Ref<Node> node, Io::Emit& e) { | ||
| // 1. If the node serializes as void, then return the empty string. | ||
| if (_serializeAsVoid(node)) | ||
| return; | ||
|
|
||
| // 3. If the node is a template element, then let the node instead be the template element's template contents (a DocumentFragment node). | ||
| // TODO: We don't support DocumentFragment | ||
|
|
||
| // 4. If current node is a shadow host, then: | ||
| // 1. Let shadow be current node's shadow root. | ||
| // 2. If serializableShadowRoots is true and shadow’s serializable is true, or shadowRoots contains shadow, then: | ||
| // 1. Append "<template shadowrootmode="". | ||
| // 2. If shadow’s mode is "open", append "open". Otherwise, append "closed". | ||
| // 3. Append """. | ||
| // 4. If shadow’s delegates focus is set, append " shadowrootdelegatesfocus=""". | ||
| // 5. If shadow’s serializable is set, append " shadowrootserializable=""". | ||
| // 6. If shadow’s clonable is set, append " shadowrootclonable=""". | ||
| // 7. If current node’s custom element registry is not shadow’s custom element registry, append " shadowrootcustomelementregistry=""". | ||
| // 8. Append ">". | ||
| // 9. Append the value of running the HTML fragment serialization algorithm with shadow, serializableShadowRoots, and shadowRoots. | ||
| // 10. Append "</template>". | ||
| // TODO: We don't have shadow dom support | ||
|
|
||
| // 5. For each child node of the node, in tree order: | ||
| // 1. Let current node be the child node being processed. | ||
| for (auto currentNode : node->iterChildren()) { | ||
sleepy-monax marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // 2. Append the appropriate string: | ||
| // If current node is an Element: | ||
| if (auto el = currentNode->is<Element>()) { | ||
| // - Determine tagname: if in HTML, MathML, or SVG namespace, tagname is local name; otherwise qualified name. | ||
| // - Append "<" followed by tagname. | ||
| e("<{}", el->qualifiedName); | ||
|
|
||
| // - If current node has an is value not present as an attribute, append ' is="<escaped is value>"'. | ||
| if (auto isValue = el->getAttribute(Html::IS_ATTR)) { | ||
| e(" is=\""); | ||
| escapeString(e, isValue.unwrap(), true); | ||
| e("\""); | ||
| } | ||
| // - For each attribute: | ||
| for (auto& [name, attr] : el->attributes.iterUnordered()) { | ||
| if (name == Html::IS_ATTR) | ||
| continue; | ||
| // Append space, attribute’s serialized name, "=", quote, escaped value, quote. | ||
| e(" {}=\"", name); | ||
| escapeString(e, attr->value, true); | ||
| e("\""); | ||
| } | ||
|
Comment on lines
+105
to
+118
|
||
| // - Append ">". | ||
| e(">"); | ||
|
|
||
| // - If current node serializes as void, continue. | ||
| if (_serializeAsVoid(currentNode)) | ||
| continue; | ||
|
|
||
| // - Append the value of running this algorithm on current node | ||
| serializeHtmlFragment(currentNode, e); | ||
|
|
||
| // then "</tagname>". | ||
| e("</{}>", el->qualifiedName); | ||
| } | ||
|
|
||
| // If current node is a Text node: | ||
| else if (auto text = currentNode->is<Text>()) { | ||
| auto parent = text->parentNode(); | ||
| // - If its parent is style, script, xmp, iframe, noembed, noframes, plaintext, or (if scripting enabled) noscript, | ||
| if (auto parentElement = parent->is<Element>(); | ||
| parentElement and | ||
| (parentElement->qualifiedName == Html::STYLE_TAG or | ||
| parentElement->qualifiedName == Html::SCRIPT_TAG or | ||
| parentElement->qualifiedName == Html::XMP_TAG or | ||
| parentElement->qualifiedName == Html::IFRAME_TAG or | ||
| parentElement->qualifiedName == Html::NOEMBED_TAG or | ||
| parentElement->qualifiedName == Html::NOFRAMES_TAG or | ||
| parentElement->qualifiedName == Html::PLAINTEXT_TAG or | ||
| parentElement->qualifiedName == Html::NOSCRIPT_TAG)) { | ||
| // append text literally. | ||
| e(text->data()); | ||
| } | ||
| // - Otherwise append escaped text. | ||
| else { | ||
| escapeString(e, text->data()); | ||
| } | ||
| } | ||
|
|
||
| // If current node is a Comment: | ||
| else if (auto comment = currentNode->is<Comment>()) { | ||
| // - Append "<!--" + data + "-->". | ||
| e("<!--{}-->", comment->data()); | ||
| } | ||
|
|
||
| // If current node is a ProcessingInstruction: | ||
| // - Append "<?" + target + " " + data + ">". | ||
| // TODO: We don't support ProcessingInstruction | ||
|
|
||
| // If current node is a DocumentType: | ||
| else if (auto doctype = currentNode->is<DocumentType>()) { | ||
| // - Append "<!DOCTYPE " + name + ">". | ||
| e("<!DOCTYPE {}>", doctype->name); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| export String serializeHtmlFragment(Gc::Ref<Node> node) { | ||
| // 1. If the node serializes as void, then return the empty string. | ||
| if (_serializeAsVoid(node)) | ||
| return ""s; | ||
|
|
||
| // 2. Let s be a string, and initialize it to the empty string. | ||
| Io::StringWriter sw; | ||
| Io::Emit e{sw}; | ||
|
|
||
| serializeHtmlFragment(node, e); | ||
|
|
||
| // 6. Return s. | ||
| return sw.take(); | ||
| } | ||
|
|
||
| } // namespace Vaev::Dom | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -58,10 +58,16 @@ export struct Window { | |||||||||||||
| } else { | ||||||||||||||
| co_return Error::invalidInput("unsupported intent"); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
sleepy-monax marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
| invalidateRender(); | ||||||||||||||
| co_return Ok(); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| [[clang::coro_wrapper]] | ||||||||||||||
| Async::Task<> refreshAsync() { | ||||||||||||||
| return loadLocationAsync(document()->url()); | ||||||||||||||
|
||||||||||||||
| return loadLocationAsync(document()->url()); | |
| auto doc = document(); | |
| if (!doc) { | |
| co_return Error::invalidState("No document to refresh"); | |
| } | |
| co_return co_await loadLocationAsync(doc->url()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty line added at beginning of scope. According to coding guidelines, empty lines at the beginning of scopes should be removed.