diff options
126 files changed, 2708 insertions, 610 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..75df82a --- /dev/null +++ b/.clang-format @@ -0,0 +1,120 @@ +--- +Language: Cpp +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterClass: true + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Linux +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: false +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^(<.*/)' + Priority: 3 + - Regex: '^(<(nsutils)/)' + Priority: 2 + - Regex: '"utils/' + Priority: 4 + - Regex: '"netsurf/' + Priority: 5 + - Regex: '.*' + Priority: 6 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 8 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 100 +PenaltyBreakBeforeFirstCallParameter: 50 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 19 +PointerAlignment: Right +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 8 +UseTab: Always +... + diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..17f2958 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,89 @@ +name: "Linux Build" + +on: [push] + +jobs: + linux: + name: '${{ matrix.os }}: ${{ matrix.compiler.vendor }}' + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-22.04 + - ubuntu-20.04 + compiler: + # The NetSurf build system can't find LLVM AR (it looks for it + # in /usr/lib instead of /usr/bin: + # `make: /usr/lib/llvm-ar: No such file or directory`). + # So we need to make it explicit for llvm. + - { vendor: gnu, CC: gcc, AR: ar } + - { vendor: llvm, CC: clang, AR: llvm-ar } + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 1 + + - name: apt-get install packages + run: sudo apt-get update -qq && + sudo apt-get install --no-install-recommends -y + bison + build-essential + check + clang + flex + git + gperf + llvm + pkg-config + libxml-perl + libxml-sax-perl + libxml-sax-base-perl + libxml-sax-expat-perl + libxml-parser-perl + libxml-libxml-perl + libxml-xpath-perl + libswitch-perl + + - name: Get env.sh + run: | + mkdir projects + wget -O projects/env.sh https://git.netsurf-browser.org/netsurf.git/plain/docs/env.sh + + - name: Build and install project deps + env: + CC: ${{ matrix.compiler.CC }} + AR: ${{ matrix.compiler.AR }} + TARGET: ${{ github.event.repository.name }} + run: | + export TARGET_WORKSPACE="$(pwd)/projects" + source projects/env.sh + ns-clone -d -s + ns-make-libs install + + - name: Build Library + env: + CC: ${{ matrix.compiler.CC }} + AR: ${{ matrix.compiler.AR }} + TARGET: ${{ github.event.repository.name }} + run: | + export TARGET_WORKSPACE="$(pwd)/projects" + source projects/env.sh + make -j"$(nproc)" + + - name: Unit Tests + # Planet saving measure: + # The tests take ages to convert from XML and we don't gain much by + # running them on every combination in the matrix. + # Another option might be to have the transformed C tests checked in. + if: ${{ matrix.compiler.vendor == 'gnu' && matrix.os == 'ubuntu-22.04' }} + env: + CC: ${{ matrix.compiler.CC }} + AR: ${{ matrix.compiler.AR }} + TARGET: ${{ github.event.repository.name }} + run: | + export TARGET_WORKSPACE="$(pwd)/projects" + source projects/env.sh + make test diff --git a/.github/workflows/static-analysis.yaml b/.github/workflows/static-analysis.yaml new file mode 100644 index 0000000..ec5171f --- /dev/null +++ b/.github/workflows/static-analysis.yaml @@ -0,0 +1,61 @@ +name: "Static Analysis" + +on: [push] + +jobs: + codeql: + name: codeql + runs-on: ubuntu-22.04 + + strategy: + fail-fast: false + matrix: + language: ['cpp'] + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + fetch-depth: 1 + + - name: apt-get install packages + run: sudo apt-get update -qq && + sudo apt-get install --no-install-recommends -y + bison + build-essential + check + clang + flex + git + gperf + llvm + pkg-config + + - name: Get env.sh + run: | + mkdir projects + wget -O projects/env.sh https://git.netsurf-browser.org/netsurf.git/plain/docs/env.sh + + - name: Build and install project deps + env: + TARGET: ${{ github.event.repository.name }} + run: | + export TARGET_WORKSPACE="$(pwd)/projects" + source projects/env.sh + ns-clone -d -s + ns-make-libs install + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + + - name: Build Library + run: | + export TARGET_WORKSPACE="$(pwd)/projects" + source projects/env.sh + make -j"$(nproc)" + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 @@ -2,11 +2,11 @@ # # Makefile for libdom # -# Copyright 2009-2015 John-Mark Bell <jmb@netsurf-browser.org> +# Copyright 2009-2020 John-Mark Bell <jmb@netsurf-browser.org> # Component settings COMPONENT := dom -COMPONENT_VERSION := 0.3.1 +COMPONENT_VERSION := 0.4.2 # Default to a static library COMPONENT_TYPE ?= lib-static @@ -56,7 +56,7 @@ include $(NSBUILD)/Makefile.top # Extra installation rules Is := include/dom I := /$(INCLUDEDIR)/dom -INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/dom.h;$(Is)/functypes.h;$(Is)/inttypes.h +INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/dom.h;$(Is)/functypes.h;$(Is)/inttypes.h;$(Is)/walk.h Is := include/dom/core I := /$(INCLUDEDIR)/dom/core @@ -69,7 +69,7 @@ INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/entity_ref.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/element.h;$(Is)/exceptions.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/implementation.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/namednodemap.h;$(Is)/node.h -INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/nodelist.h;$(Is)/string.h +INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/nodelist.h;$(Is)/tokenlist.h;$(Is)/string.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/pi.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/text.h;$(Is)/typeinfo.h @@ -99,6 +99,7 @@ INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_body_element.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_meta_element.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_form_element.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_button_element.h +INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_canvas_element.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_input_element.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_select_element.h INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_text_area_element.h @@ -148,6 +149,8 @@ INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):$(Is)/html_isindex_element.h INSTALL_ITEMS := $(INSTALL_ITEMS) /$(LIBDIR)/pkgconfig:lib$(COMPONENT).pc.in INSTALL_ITEMS := $(INSTALL_ITEMS) /$(LIBDIR):$(OUTPUT) +REQUIRED_PKGS := $(REQUIRED_PKGS) libwapcaplet + ifeq ($(WITH_LIBXML_BINDING),yes) REQUIRED_PKGS := $(REQUIRED_PKGS) libxml-2.0 endif @@ -156,3 +159,6 @@ ifeq ($(WITH_HUBBUB_BINDING),yes) REQUIRED_PKGS := $(REQUIRED_PKGS) libhubbub endif +ifeq ($(WITH_EXPAT_BINDING),yes) + REQUIRED_LIBS := $(REQUIRED_LIBS) expat +endif diff --git a/Makefile.config b/Makefile.config index 04971d5..0aba3ff 100644 --- a/Makefile.config +++ b/Makefile.config @@ -3,6 +3,9 @@ # Build the libxml2 binding? # yes | no WITH_LIBXML_BINDING := no + +# Build the expat binding? +# yes | no WITH_EXPAT_BINDING := yes # Build the hubbub binding? @@ -21,6 +21,7 @@ libdom requires the following tools: - A C99 capable C compiler - GNU make or compatible - Perl (for the testcases) + `sudo apt-get install libxml-xpath-perl` LibDOM also requires the following libraries to be installed: diff --git a/bindings/hubbub/parser.c b/bindings/hubbub/parser.c index 9dfe738..a84a951 100644 --- a/bindings/hubbub/parser.c +++ b/bindings/hubbub/parser.c @@ -39,7 +39,7 @@ struct dom_hubbub_parser { hubbub_tree_handler tree_handler; /**< Hubbub parser tree handler */ - struct dom_document *doc; /**< DOM Document we're building */ + struct dom_document *doc; /**< DOM Document we're building within */ dom_hubbub_encoding_source encoding_source; /**< The document's encoding source */ @@ -219,13 +219,51 @@ static hubbub_error create_element(void *parser, const hubbub_tag *tag, } } - if (element != NULL && tag->n_attributes > 0) { + /* By now, we MUST have constructed an element */ + assert(element != NULL); + + if (tag->n_attributes > 0) { herr = add_attributes(parser, element, tag->attributes, tag->n_attributes); if (herr != HUBBUB_OK) goto clean1; } + /* Now do some special per-element-type handling */ + dom_html_element_type tag_type; + err = dom_html_element_get_tag_type(element, &tag_type); + if (err != DOM_NO_ERR) { + dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx, + "Can't get tag type out of element"); + goto clean1; + } + + switch (tag_type) { + case DOM_HTML_ELEMENT_TYPE_SCRIPT: { + /* Kickstart of https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model */ + dom_html_script_element *script = (dom_html_script_element *)element; + dom_html_script_element_flags flags; + err = dom_html_script_element_get_flags(script, &flags); + if (err != DOM_NO_ERR) { + dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx, + "Can't get flags out of script element"); + goto clean1; + } + flags |= DOM_HTML_SCRIPT_ELEMENT_FLAG_PARSER_INSERTED; + err = dom_html_script_element_set_flags(script, flags); + if (err != DOM_NO_ERR) { + dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx, + "Can't set flags into script element"); + goto clean1; + } + break; + } + default: + /* Nothing */ + break; + } + + *result = element; clean1: @@ -604,7 +642,7 @@ static hubbub_error set_quirks_mode(void *parser, hubbub_quirks_mode mode) static hubbub_error change_encoding(void *parser, const char *charset) { dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser; - uint32_t source; + hubbub_charset_source source; const char *name; /* If we have an encoding here, it means we are *certain* */ @@ -827,6 +865,119 @@ dom_hubbub_parser_create(dom_hubbub_parser_params *params, } +/** + * Create a Hubbub parser instance + * + * \param params The binding creation parameters + * \param parser Pointer to location to recive instance. + * \param document Pointer to location to receive document. + * \return Error code + */ +dom_hubbub_error +dom_hubbub_fragment_parser_create(dom_hubbub_parser_params *params, + dom_document *document, + dom_hubbub_parser **parser, + dom_document_fragment **fragment) +{ + dom_hubbub_parser *binding; + hubbub_parser_optparams optparams; + hubbub_error error; + dom_exception err; + + if (document == NULL) { + return DOM_HUBBUB_BADPARM; + } + + /* check result parameters */ + if (fragment == NULL) { + return DOM_HUBBUB_BADPARM; + } + + if (parser == NULL) { + return DOM_HUBBUB_BADPARM; + } + + /* setup binding parser context */ + binding = malloc(sizeof(dom_hubbub_parser)); + if (binding == NULL) { + return DOM_HUBBUB_NOMEM; + } + + binding->parser = NULL; + binding->doc = (struct dom_document *)dom_node_ref(document); + binding->encoding = params->enc; + + if (params->enc != NULL) { + binding->encoding_source = DOM_HUBBUB_ENCODING_SOURCE_HEADER; + } else { + binding->encoding_source = DOM_HUBBUB_ENCODING_SOURCE_DETECTED; + } + + binding->complete = false; + + if (params->msg == NULL) { + binding->msg = dom_hubbub_parser_default_msg; + } else { + binding->msg = params->msg; + } + binding->mctx = params->ctx; + + /* ensure script function is valid or use the default */ + if (params->script == NULL) { + binding->script = dom_hubbub_parser_default_script; + } else { + binding->script = params->script; + } + + /* create hubbub parser */ + error = hubbub_parser_create(binding->encoding, + params->fix_enc, + &binding->parser); + if (error != HUBBUB_OK) { + dom_node_unref(binding->doc); + free(binding); + return (DOM_HUBBUB_HUBBUB_ERR | error); + } + + /* create DOM document fragment */ + err = dom_document_create_document_fragment(binding->doc, + fragment); + if (err != DOM_NO_ERR) { + hubbub_parser_destroy(binding->parser); + dom_node_unref(binding->doc); + free(binding); + return DOM_HUBBUB_DOM; + } + + binding->tree_handler = tree_handler; + binding->tree_handler.ctx = (void *)binding; + + /* set tree handler on parser */ + optparams.tree_handler = &binding->tree_handler; + hubbub_parser_setopt(binding->parser, + HUBBUB_PARSER_TREE_HANDLER, + &optparams); + + /* set document node*/ + optparams.document_node = dom_node_ref((struct dom_node *)*fragment); + hubbub_parser_setopt(binding->parser, + HUBBUB_PARSER_DOCUMENT_NODE, + &optparams); + + /* set scripting state */ + optparams.enable_scripting = params->enable_script; + hubbub_parser_setopt(binding->parser, + HUBBUB_PARSER_ENABLE_SCRIPTING, + &optparams); + + /* set return parameters */ + *parser = binding; + /* fragment is already set up */ + + return DOM_HUBBUB_OK; +} + + dom_hubbub_error dom_hubbub_parser_insert_chunk(dom_hubbub_parser *parser, const uint8_t *data, diff --git a/bindings/hubbub/parser.h b/bindings/hubbub/parser.h index 54ad0c8..5a95a91 100644 --- a/bindings/hubbub/parser.h +++ b/bindings/hubbub/parser.h @@ -70,6 +70,12 @@ dom_hubbub_error dom_hubbub_parser_create(dom_hubbub_parser_params *params, dom_hubbub_parser **parser, dom_document **document); +/* Create a Hubbub parser instance for a document fragment */ +dom_hubbub_error dom_hubbub_fragment_parser_create(dom_hubbub_parser_params *params, + dom_document *document, + dom_hubbub_parser **parser, + dom_document_fragment **fragment); + /* Destroy a Hubbub parser instance */ void dom_hubbub_parser_destroy(dom_hubbub_parser *parser); diff --git a/bindings/xml/libxml_xmlparser.c b/bindings/xml/libxml_xmlparser.c index 02b8a34..cd7f8ad 100644 --- a/bindings/xml/libxml_xmlparser.c +++ b/bindings/xml/libxml_xmlparser.c @@ -6,6 +6,7 @@ */ #include <stdbool.h> +#include <stdlib.h> #include <string.h> #include <assert.h> @@ -36,21 +37,21 @@ static void xml_parser_end_element_ns(void *ctx, const xmlChar *localname, static dom_exception xml_parser_link_nodes(dom_xml_parser *parser, struct dom_node *dom, xmlNodePtr xml); -static void xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, - xmlNodePtr child); -static void xml_parser_add_element_node(dom_xml_parser *parser, +static dom_exception xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_text_node(dom_xml_parser *parser, +static dom_exception xml_parser_add_element_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_cdata_section(dom_xml_parser *parser, +static dom_exception xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_entity_reference(dom_xml_parser *parser, +static dom_exception xml_parser_add_cdata_section(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_entity(dom_xml_parser *parser, +static dom_exception xml_parser_add_entity_reference(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child); +static dom_exception xml_parser_add_entity(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_comment(dom_xml_parser *parser, +static dom_exception xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_document_type(dom_xml_parser *parser, +static dom_exception xml_parser_add_document_type(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); static void xml_parser_internal_subset(void *ctx, const xmlChar *name, @@ -96,6 +97,8 @@ struct dom_xml_parser { dom_msg msg; /**< Informational message function */ void *mctx; /**< Pointer to client data */ + + dom_exception err; /**< Last DOM error, if any */ }; /** @@ -133,7 +136,7 @@ static xmlSAXHandler sax_handler = { ._private = NULL, .startElementNs = xml_parser_start_element_ns, .endElementNs = xml_parser_end_element_ns, - .serror = NULL + .serror = NULL, }; static void *dom_xml_alloc(void *ptr, size_t len, void *pw) @@ -231,6 +234,8 @@ dom_xml_parser *dom_xml_parser_create(const char *enc, const char *int_enc, parser->msg = msg; parser->mctx = mctx; + parser->err = DOM_NO_ERR; + return parser; } @@ -271,6 +276,10 @@ dom_xml_error dom_xml_parser_parse_chunk(dom_xml_parser *parser, return DOM_XML_EXTERNAL_ERR | err; } + if (parser->err != DOM_NO_ERR) { + return DOM_XML_DOM_ERR | parser->err; + } + return DOM_XML_OK; } @@ -293,6 +302,10 @@ dom_xml_error dom_xml_parser_completed(dom_xml_parser *parser) return DOM_XML_EXTERNAL_ERR | err; } + if (parser->err != DOM_NO_ERR) { + return DOM_XML_DOM_ERR | parser->err; + } + return DOM_XML_OK; } @@ -304,15 +317,27 @@ dom_xml_error dom_xml_parser_completed(dom_xml_parser *parser) void xml_parser_start_document(void *ctx) { dom_xml_parser *parser = (dom_xml_parser *) ctx; - dom_exception err; +#if LIBXML_VERSION >= 21200 + const xmlError *xmlerr; +#else + xmlErrorPtr xmlerr; +#endif + + if (parser->err != DOM_NO_ERR) + return; /* Invoke libxml2's default behaviour */ xmlSAX2StartDocument(parser->xml_ctx); + xmlerr = xmlCtxtGetLastError(parser->xml_ctx); + if (xmlerr != NULL && xmlerr->level >= XML_ERR_ERROR) { + return; + } /* Link nodes together */ - err = xml_parser_link_nodes(parser, (struct dom_node *) parser->doc, + parser->err = xml_parser_link_nodes(parser, + (struct dom_node *) parser->doc, (xmlNodePtr) parser->xml_ctx->myDoc); - if (err != DOM_NO_ERR) { + if (parser->err != DOM_NO_ERR) { parser->msg(DOM_MSG_WARNING, parser->mctx, "Not able to link document nodes"); } @@ -328,10 +353,21 @@ void xml_parser_end_document(void *ctx) dom_xml_parser *parser = (dom_xml_parser *) ctx; xmlNodePtr node; xmlNodePtr n; - dom_exception err; +#if LIBXML_VERSION >= 21200 + const xmlError *xmlerr; +#else + xmlErrorPtr xmlerr; +#endif + + if (parser->err != DOM_NO_ERR) + return; /* Invoke libxml2's default behaviour */ xmlSAX2EndDocument(parser->xml_ctx); + xmlerr = xmlCtxtGetLastError(parser->xml_ctx); + if (xmlerr != NULL && xmlerr->level >= XML_ERR_ERROR) { + return; + } /* If there is no document, we can't do anything */ if (parser->doc == NULL) { @@ -344,9 +380,13 @@ void xml_parser_end_document(void *ctx) * children which occur after the last Element node in the list */ /* Get XML node */ - err = dom_node_get_user_data((struct dom_node *) parser->doc, + parser->err = dom_node_get_user_data((struct dom_node *) parser->doc, parser->udkey, (void **) (void *) &node); - if (err != DOM_NO_ERR) { + + /* The return value from dom_node_get_user_data() is always + * DOM_NO_ERR, but the returned "node" will be NULL if no user + * data is found. */ + if (parser->err != DOM_NO_ERR || node == NULL) { parser->msg(DOM_MSG_WARNING, parser->mctx, "Failed finding XML node"); return; @@ -368,8 +408,10 @@ void xml_parser_end_document(void *ctx) /* Now, mirror nodes in the DOM */ for (; n != NULL; n = n->next) { - xml_parser_add_node(parser, + parser->err = xml_parser_add_node(parser, (struct dom_node *) node->_private, n); + if (parser->err != DOM_NO_ERR) + return; } } @@ -397,11 +439,23 @@ void xml_parser_start_element_ns(void *ctx, const xmlChar *localname, { dom_xml_parser *parser = (dom_xml_parser *) ctx; xmlNodePtr parent = parser->xml_ctx->node; +#if LIBXML_VERSION >= 21200 + const xmlError *xmlerr; +#else + xmlErrorPtr xmlerr; +#endif + + if (parser->err != DOM_NO_ERR) + return; /* Invoke libxml2's default behaviour */ xmlSAX2StartElementNs(parser->xml_ctx, localname, prefix, URI, nb_namespaces, namespaces, nb_attributes, nb_defaulted, attributes); + xmlerr = xmlCtxtGetLastError(parser->xml_ctx); + if (xmlerr != NULL && xmlerr->level >= XML_ERR_ERROR) { + return; + } /* If there is no document, we can't do anything */ if (parser->doc == NULL) { @@ -440,16 +494,18 @@ void xml_parser_start_element_ns(void *ctx, const xmlChar *localname, /* Now, mirror nodes in the DOM */ for (; n != parser->xml_ctx->node; n = n->next) { - xml_parser_add_node(parser, + parser->err = xml_parser_add_node(parser, (struct dom_node *) parent->_private, n); + if (parser->err != DOM_NO_ERR) + return; } } /* Mirror the created node and its attributes in the DOM */ - xml_parser_add_node(parser, (struct dom_node *) parent->_private, + parser->err = xml_parser_add_node(parser, + (struct dom_node *) parent->_private, parser->xml_ctx->node); - } /** @@ -466,9 +522,21 @@ void xml_parser_end_element_ns(void *ctx, const xmlChar *localname, dom_xml_parser *parser = (dom_xml_parser *) ctx; xmlNodePtr node = parser->xml_ctx->node; xmlNodePtr n; +#if LIBXML_VERSION >= 21200 + const xmlError *xmlerr; +#else + xmlErrorPtr xmlerr; +#endif + + if (parser->err != DOM_NO_ERR) + return; /* Invoke libxml2's default behaviour */ xmlSAX2EndElementNs(parser->xml_ctx, localname, prefix, URI); + xmlerr = xmlCtxtGetLastError(parser->xml_ctx); + if (xmlerr != NULL && xmlerr->level >= XML_ERR_ERROR) { + return; + } /* If there is no document, we can't do anything */ if (parser->doc == NULL) { @@ -503,8 +571,10 @@ void xml_parser_end_element_ns(void *ctx, const xmlChar *localname, /* Now, mirror nodes in the DOM */ for (; n != NULL; n = n->next) { - xml_parser_add_node(parser, + parser->err = xml_parser_add_node(parser, (struct dom_node *) node->_private, n); + if (parser->err != DOM_NO_ERR) + return; } } @@ -543,9 +613,10 @@ dom_exception xml_parser_link_nodes(dom_xml_parser *parser, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, - xmlNodePtr child) +dom_exception xml_parser_add_node(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) { static const char *node_types[] = { "THIS_IS_NOT_A_NODE", @@ -574,31 +645,26 @@ void xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, switch (child->type) { case XML_ELEMENT_NODE: - xml_parser_add_element_node(parser, parent, child); - break; + return xml_parser_add_element_node(parser, parent, child); case XML_TEXT_NODE: - xml_parser_add_text_node(parser, parent, child); - break; + return xml_parser_add_text_node(parser, parent, child); case XML_CDATA_SECTION_NODE: - xml_parser_add_cdata_section(parser, parent, child); - break; + return xml_parser_add_cdata_section(parser, parent, child); case XML_ENTITY_REF_NODE: - xml_parser_add_entity_reference(parser, parent, child); - break; + return xml_parser_add_entity_reference(parser, parent, child); case XML_COMMENT_NODE: - xml_parser_add_comment(parser, parent, child); - break; + return xml_parser_add_comment(parser, parent, child); case XML_DTD_NODE: - xml_parser_add_document_type(parser, parent, child); - break; - case XML_ENTITY_DECL: - xml_parser_add_entity(parser, parent, child); - break; + return xml_parser_add_document_type(parser, parent, child); + case XML_ENTITY_DECL: + return xml_parser_add_entity(parser, parent, child); default: parser->msg(DOM_MSG_NOTICE, parser->mctx, "Unsupported node type: %s", node_types[child->type]); } + + return DOM_NO_ERR; } /** @@ -607,8 +673,9 @@ void xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_element_node(dom_xml_parser *parser, +dom_exception xml_parser_add_element_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child) { struct dom_element *el, *ins_el = NULL; @@ -626,7 +693,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for tag name"); - return; + return err; } /* Create element node */ @@ -637,7 +704,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed creating element '%s'", child->name); - return; + return err; } /* No longer need tag name */ @@ -660,7 +727,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for namespace"); - return; + return err; } /* QName is "prefix:localname", @@ -680,7 +747,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, dom_string_unref(namespace); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for qname"); - return; + return err; } /* Create element node */ @@ -692,7 +759,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed creating element '%s'", qnamebuf); - return; + return err; } /* No longer need namespace / qname */ @@ -752,7 +819,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for namespace"); - return; + goto cleanup; } /* QName is "prefix:localname", @@ -772,7 +839,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, dom_string_unref(namespace); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for qname"); - return; + goto cleanup; } /* Create attribute */ @@ -784,7 +851,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed creating attribute \ '%s'", qnamebuf); - return; + goto cleanup; } /* No longer need namespace / qname */ @@ -794,8 +861,12 @@ void xml_parser_add_element_node(dom_xml_parser *parser, /* Clone subtree (attribute value) */ for (c = a->children; c != NULL; c = c->next) { - xml_parser_add_node(parser, + err = xml_parser_add_node(parser, (struct dom_node *) attr, c); + if (err != DOM_NO_ERR) { + dom_node_unref((struct dom_node *) attr); + goto cleanup; + } } /* Link nodes together */ @@ -861,14 +932,14 @@ void xml_parser_add_element_node(dom_xml_parser *parser, /* No longer interested in element node */ dom_node_unref((struct dom_node *) el); - return; + return DOM_NO_ERR; cleanup: /* No longer want node (any attributes attached to it * will be cleaned up with it) */ dom_node_unref((struct dom_node *) el); - return; + return err; } /** @@ -877,9 +948,10 @@ cleanup: * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, - xmlNodePtr child) +dom_exception xml_parser_add_text_node(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) { struct dom_text *text, *ins_text = NULL; dom_string *data; @@ -891,7 +963,7 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for text node contents "); - return; + return err; } /* Create text node */ @@ -900,7 +972,7 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, dom_string_unref(data); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for text node"); - return; + return err; } /* No longer need data */ @@ -913,7 +985,7 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, dom_node_unref((struct dom_node *) text); parser->msg(DOM_MSG_ERROR, parser->mctx, "Failed attaching text node"); - return; + return err; } /* We're not interested in the inserted text node */ @@ -925,11 +997,13 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) text); - return; + return err; } /* No longer interested in text node */ dom_node_unref((struct dom_node *) text); + + return DOM_NO_ERR; } /** @@ -938,8 +1012,9 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_cdata_section(dom_xml_parser *parser, +dom_exception xml_parser_add_cdata_section(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child) { struct dom_cdata_section *cdata, *ins_cdata = NULL; @@ -952,7 +1027,7 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for cdata section contents"); - return; + return err; } /* Create cdata section */ @@ -961,7 +1036,7 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, dom_string_unref(data); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for cdata section"); - return; + return err; } /* No longer need data */ @@ -974,7 +1049,7 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, dom_node_unref((struct dom_node *) cdata); parser->msg(DOM_MSG_ERROR, parser->mctx, "Failed attaching cdata section"); - return; + return err; } /* We're not interested in the inserted cdata section */ @@ -986,11 +1061,13 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) cdata); - return; + return err; } /* No longer interested in cdata section */ dom_node_unref((struct dom_node *) cdata); + + return DOM_NO_ERR; } /** @@ -999,8 +1076,9 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_entity_reference(dom_xml_parser *parser, +dom_exception xml_parser_add_entity_reference(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child) { struct dom_entity_reference *entity, *ins_entity = NULL; @@ -1014,7 +1092,7 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for entity reference name"); - return; + return err; } /* Create text node */ @@ -1024,7 +1102,7 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, dom_string_unref(name); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for entity reference"); - return; + return err; } /* No longer need name */ @@ -1032,7 +1110,10 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, /* Mirror subtree (reference value) */ for (c = child->children; c != NULL; c = c->next) { - xml_parser_add_node(parser, (struct dom_node *) entity, c); + err = xml_parser_add_node(parser, + (struct dom_node *) entity, c); + if (err != DOM_NO_ERR) + return err; } /* Append entity reference to parent */ @@ -1042,7 +1123,7 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, dom_node_unref((struct dom_node *) entity); parser->msg(DOM_MSG_ERROR, parser->mctx, "Failed attaching entity reference"); - return; + return err; } /* We're not interested in the inserted entity reference */ @@ -1054,19 +1135,33 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) entity); - return; + return err; } /* No longer interested in entity reference */ dom_node_unref((struct dom_node *) entity); + + return DOM_NO_ERR; } -static void xml_parser_add_entity(dom_xml_parser *parser, - struct dom_node *parent, xmlNodePtr child) +/** + * Add an entity to the DOM + * + * \param parser The parser context + * \param parent The parent DOM node + * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise + */ +dom_exception xml_parser_add_entity(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) { - UNUSED(parser); - UNUSED(parent); - UNUSED(child); + UNUSED(parser); + UNUSED(parent); + UNUSED(child); + + /** \todo implement */ + + return DOM_NO_ERR; } /** @@ -1075,9 +1170,10 @@ static void xml_parser_add_entity(dom_xml_parser *parser, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, - xmlNodePtr child) +dom_exception xml_parser_add_comment(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) { struct dom_comment *comment, *ins_comment = NULL; dom_string *data; @@ -1089,7 +1185,7 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for comment data"); - return; + return err; } /* Create comment */ @@ -1098,7 +1194,7 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, dom_string_unref(data); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for comment node"); - return; + return err; } /* No longer need data */ @@ -1111,7 +1207,7 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, dom_node_unref((struct dom_node *) comment); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed attaching comment node"); - return; + return err; } /* We're not interested in the inserted comment */ @@ -1123,11 +1219,13 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) comment); - return; + return err; } /* No longer interested in comment */ dom_node_unref((struct dom_node *) comment); + + return DOM_NO_ERR; } /** @@ -1136,8 +1234,9 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_document_type(dom_xml_parser *parser, +dom_exception xml_parser_add_document_type(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child) { xmlDtdPtr dtd = (xmlDtdPtr) child; @@ -1163,7 +1262,7 @@ void xml_parser_add_document_type(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed to create document type"); - return; + return err; } /* Add doctype to document */ @@ -1173,7 +1272,7 @@ void xml_parser_add_document_type(dom_xml_parser *parser, dom_node_unref((struct dom_node *) doctype); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed attaching doctype"); - return; + return err; } /* Not interested in inserted node */ @@ -1185,11 +1284,13 @@ void xml_parser_add_document_type(dom_xml_parser *parser, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) doctype); - return; + return err; } /* No longer interested in doctype */ dom_node_unref((struct dom_node *) doctype); + + return DOM_NO_ERR; } /* ------------------------------------------------------------------------*/ diff --git a/bindings/xml/xmlerror.h b/bindings/xml/xmlerror.h index 51f2c8b..a6cb905 100644 --- a/bindings/xml/xmlerror.h +++ b/bindings/xml/xmlerror.h @@ -13,7 +13,9 @@ typedef enum { DOM_XML_NOMEM = 1, - DOM_XML_EXTERNAL_ERR = (1<<16), + DOM_XML_EXTERNAL_ERR = (1<<16), + + DOM_XML_DOM_ERR = (1<<24), } dom_xml_error; #endif diff --git a/examples/dom-structure-dump.c b/examples/dom-structure-dump.c index 4ce7670..189292d 100644 --- a/examples/dom-structure-dump.c +++ b/examples/dom-structure-dump.c @@ -44,6 +44,7 @@ #include <string.h> #include <dom/dom.h> +#include <dom/walk.h> #include <dom/bindings/hubbub/parser.h> @@ -181,6 +182,12 @@ bool dump_dom_element_attribute(dom_node *node, char *attribute) return true; } +static inline void dump_indent(int depth) +{ + for (int i = 0; i < depth; i++) { + printf(" "); + } +} /** * Print a line in a DOM structure dump for an element @@ -189,25 +196,13 @@ bool dump_dom_element_attribute(dom_node *node, char *attribute) * \param depth The node's depth * \return true on success, or false on error */ -bool dump_dom_element(dom_node *node, int depth) +bool dump_dom_element(dom_node *node, int depth, bool close) { dom_exception exc; dom_string *node_name = NULL; - dom_node_type type; - int i; const char *string; size_t length; - /* Only interested in element nodes */ - exc = dom_node_get_node_type(node, &type); - if (exc != DOM_NO_ERR) { - printf("Exception raised for node_get_node_type\n"); - return false; - } else if (type != DOM_ELEMENT_NODE) { - /* Nothing to print */ - return true; - } - /* Get element name */ exc = dom_node_get_node_name(node, &node_name); if (exc != DOM_NO_ERR) { @@ -215,48 +210,84 @@ bool dump_dom_element(dom_node *node, int depth) return false; } else if (node_name == NULL) { printf("Broken: root_name == NULL\n"); - return false; + return false; } /* Print ASCII tree structure for current node */ - if (depth > 0) { - for (i = 0; i < depth; i++) { - printf("| "); - } - printf("+-"); - } + dump_indent(depth); /* Get string data and print element name */ string = dom_string_data(node_name); length = dom_string_byte_length(node_name); - printf("[%.*s]", (int)length, string); - - if (length == 5 && strncmp(string, "title", 5) == 0) { - /* Title tag, gather the title */ - dom_string *str; - exc = dom_node_get_text_content(node, &str); - if (exc == DOM_NO_ERR && str != NULL) { - printf(" $%.*s$", (int)dom_string_byte_length(str), - dom_string_data(str)); - dom_string_unref(str); - } - } - /* Finished with the node_name dom_string */ + /* TODO: Some elements don't have close tags; only print close tags for + * those that do. */ + printf("<%s%.*s", close ? "/" : "", (int)length, string); + dom_string_unref(node_name); - /* Print the element's id & class, if it has them */ - if (dump_dom_element_attribute(node, "id") == false || - dump_dom_element_attribute(node, "class") == false) { - /* Error occured */ - printf("\n"); - return false; + if (!close) { + if (length == 5 && strncmp(string, "title", 5) == 0) { + /* Title tag, gather the title */ + dom_string *s; + exc = dom_node_get_text_content(node, &s); + if (exc == DOM_NO_ERR && s != NULL) { + printf(" $%.*s$", + (int)dom_string_byte_length(s), + dom_string_data(s)); + dom_string_unref(s); + } + } + + /* Print the element's id & class, if it has them */ + if (dump_dom_element_attribute(node, "id") == false || + dump_dom_element_attribute(node, "class") == false) { + /* Error occured */ + printf(">\n"); + return false; + } } - printf("\n"); + printf(">\n"); return true; } +/** + * Structure dump callback for DOM walker. + */ +enum dom_walk_cmd dump_dom_structure__cb( + enum dom_walk_stage stage, + dom_node_type type, + dom_node *node, + void *pw) +{ + int *depth = pw; + + switch (type) { + case DOM_ELEMENT_NODE: + switch (stage) { + case DOM_WALK_STAGE_ENTER: + (*depth)++; + if (!dump_dom_element(node, *depth, false)) { + return DOM_WALK_CMD_ABORT; + } + break; + + case DOM_WALK_STAGE_LEAVE: + if (!dump_dom_element(node, *depth, true)) { + return DOM_WALK_CMD_ABORT; + } + (*depth)--; + break; + } + break; + + default: + break; + } + + return DOM_WALK_CMD_CONTINUE; +} /** * Walk though a DOM (sub)tree, in depth first order, printing DOM structure. @@ -267,51 +298,34 @@ bool dump_dom_element(dom_node *node, int depth) bool dump_dom_structure(dom_node *node, int depth) { dom_exception exc; - dom_node *child; - /* Print this node's entry */ - if (dump_dom_element(node, depth) == false) { - /* There was an error; return */ + if (!dump_dom_element(node, depth, false)) { return false; } - /* Get the node's first child */ - exc = dom_node_get_first_child(node, &child); + exc = libdom_treewalk(DOM_WALK_ENABLE_ALL, + dump_dom_structure__cb, + node, &depth); if (exc != DOM_NO_ERR) { - printf("Exception raised for node_get_first_child\n"); return false; - } else if (child != NULL) { - /* node has children; decend to children's depth */ - depth++; - - /* Loop though all node's children */ - do { - dom_node *next_child; - - /* Visit node's descendents */ - if (dump_dom_structure(child, depth) == false) { - /* There was an error; return */ - dom_node_unref(child); - return false; - } - - /* Go to next sibling */ - exc = dom_node_get_next_sibling(child, &next_child); - if (exc != DOM_NO_ERR) { - printf("Exception raised for " - "node_get_next_sibling\n"); - dom_node_unref(child); - return false; - } + } - dom_node_unref(child); - child = next_child; - } while (child != NULL); /* No more children */ + if (!dump_dom_element(node, depth, true)) { + return false; } return true; } +/* LWC leak callback */ +void sd__fini_lwc_callback(lwc_string *str, void *pw) +{ + (void)(pw); + + fprintf(stderr, "Leaked string: %.*s\n", + (int)lwc_string_length(str), + lwc_string_data(str)); +} /** * Main entry point from OS. @@ -354,6 +368,8 @@ int main(int argc, char **argv) /* Finished with the dom_document */ dom_node_unref(doc); + dom_namespace_finalise(); + lwc_iterate_strings(sd__fini_lwc_callback, NULL); return EXIT_SUCCESS; } diff --git a/examples/makefile b/examples/example.mk index 47cc7ae..8e1da17 100644 --- a/examples/makefile +++ b/examples/example.mk @@ -1,3 +1,9 @@ +# From the top level: +# +# make -C examples -f example.mk clean +# make -C examples -f example.mk +# ./examples/dom-structure-dump examples/files/test.html + CC := gcc LD := gcc diff --git a/gdb/libdom.py b/gdb/libdom.py index 65286e3..09b1577 100644 --- a/gdb/libdom.py +++ b/gdb/libdom.py @@ -49,9 +49,9 @@ def dom_node_pending_offset(): return gdb.parse_and_eval("(int)&((struct dom_node_internal *)0)->pending_list") def dom_print_node(node, prefix = ""): - print("%s%s @ %s [%s]%s" % (prefix, dom_node_type(node), + print(("%s%s @ %s [%s]%s" % (prefix, dom_node_type(node), node.address, dom_node_refcnt(node), - dom_node_name(node))) + dom_node_name(node)))) def dom_walk_tree(node, prefix = ""): dom_print_node(node, prefix) @@ -61,12 +61,12 @@ def dom_walk_tree(node, prefix = ""): current = current['next'].dereference() def dom_document_show(doc): - print "Node Tree:" + print("Node Tree:") node = dom_node_at(doc.address) dom_walk_tree(node, " ") pending = doc['pending_nodes'] if pending['next'] != pending.address: - print "Pending Node trees:" + print("Pending Node trees:") current_list_entry = pending['next'] while current_list_entry is not None: voidp = current_list_entry.cast(dom_get_type_ptr("void")) diff --git a/include/dom/core/node.h b/include/dom/core/node.h index ba273af..90026a1 100644 --- a/include/dom/core/node.h +++ b/include/dom/core/node.h @@ -77,7 +77,7 @@ typedef struct dom_node_internal dom_node_internal; * DOM node type */ typedef struct dom_node { - void *vtable; + const void *vtable; uint32_t refcnt; } dom_node; @@ -169,8 +169,8 @@ typedef struct dom_node_vtable { dom_exception (*dom_node_set_user_data)(dom_node_internal *node, dom_string *key, void *data, dom_user_data_handler handler, void **result); - dom_exception (*dom_node_get_user_data)(dom_node_internal *node, - dom_string *key, void **result); + dom_exception (*dom_node_get_user_data)(const dom_node_internal *node, + const dom_string *key, void **result); } dom_node_vtable; /* The ref/unref methods define */ @@ -202,6 +202,16 @@ static inline void dom_node_unref(dom_node *node) } #define dom_node_unref(n) dom_node_unref((dom_node *) (n)) +/* Contains is non-virtual since it doesn't need to be */ + +dom_exception _dom_node_contains(struct dom_node_internal *node, + struct dom_node_internal *other, + bool *contains); +#define dom_node_contains(n, o, c) \ + _dom_node_contains((dom_node_internal *)(n), (dom_node_internal *)(o), (c)) + +/* All the rest are virtual */ + static inline dom_exception dom_node_get_node_name(struct dom_node *node, dom_string **result) { @@ -557,8 +567,8 @@ static inline dom_exception dom_node_set_user_data(struct dom_node *node, (dom_node *) (n), (k), (void *) (d), \ (dom_user_data_handler) h, (void **) (r)) -static inline dom_exception dom_node_get_user_data(struct dom_node *node, - dom_string *key, void **result) +static inline dom_exception dom_node_get_user_data(const struct dom_node *node, + const dom_string *key, void **result) { return ((dom_node_vtable *) node->vtable)->dom_node_get_user_data( (dom_node_internal *) node, key, result); diff --git a/include/dom/core/string.h b/include/dom/core/string.h index f2a6122..4c2da97 100644 --- a/include/dom/core/string.h +++ b/include/dom/core/string.h @@ -18,7 +18,7 @@ typedef struct dom_string dom_string; struct dom_string { uint32_t refcnt; -} _ALIGNED; +}; /* Claim a reference on a DOM string */ diff --git a/include/dom/core/tokenlist.h b/include/dom/core/tokenlist.h new file mode 100644 index 0000000..718d3a5 --- /dev/null +++ b/include/dom/core/tokenlist.h @@ -0,0 +1,43 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2022 Daniel Silverstone <dsilvers@netsurf-browser.org> + */ + +#ifndef dom_core_tokenlist_h_ +#define dom_core_tokenlist_h_ + +#include <dom/core/exceptions.h> + +struct dom_element; +struct dom_string; + +typedef struct dom_tokenlist dom_tokenlist; + +void dom_tokenlist_ref(struct dom_tokenlist *list); +void dom_tokenlist_unref(struct dom_tokenlist *list); + +dom_exception dom_tokenlist_create(struct dom_element *ele, struct dom_string *attr, dom_tokenlist **list); + +dom_exception dom_tokenlist_get_length(struct dom_tokenlist *list, + uint32_t *length); +dom_exception _dom_tokenlist_item(struct dom_tokenlist *list, + uint32_t index, struct dom_string **value); + +#define dom_tokenlist_item(l, i, n) _dom_tokenlist_item((dom_tokenlist *) (l), \ + (uint32_t) (i), (struct dom_string **) (n)) + +dom_exception dom_tokenlist_get_value(struct dom_tokenlist *list, + struct dom_string **value); + +dom_exception dom_tokenlist_set_value(struct dom_tokenlist *list, + struct dom_string *value); + +dom_exception dom_tokenlist_contains(struct dom_tokenlist *list, struct dom_string *value, bool *contains); + +dom_exception dom_tokenlist_add(struct dom_tokenlist *list, struct dom_string *value); + +dom_exception dom_tokenlist_remove(struct dom_tokenlist *list, struct dom_string *value); + +#endif diff --git a/include/dom/dom.h b/include/dom/dom.h index 0740fe9..00bf3d9 100644 --- a/include/dom/dom.h +++ b/include/dom/dom.h @@ -32,6 +32,7 @@ #include <dom/core/doc_fragment.h> #include <dom/core/entity_ref.h> #include <dom/core/nodelist.h> +#include <dom/core/tokenlist.h> #include <dom/core/string.h> #include <dom/core/text.h> #include <dom/core/pi.h> @@ -51,6 +52,7 @@ #include <dom/html/html_form_element.h> #include <dom/html/html_input_element.h> #include <dom/html/html_button_element.h> +#include <dom/html/html_canvas_element.h> #include <dom/html/html_text_area_element.h> #include <dom/html/html_opt_group_element.h> #include <dom/html/html_option_element.h> @@ -111,6 +113,12 @@ typedef enum dom_namespace { DOM_NAMESPACE_COUNT = 7 } dom_namespace; +/* Note, these are not valid until at least one function related to DOM + * namespaces has been called such as the creation of a Document. + */ extern dom_string *dom_namespaces[DOM_NAMESPACE_COUNT]; +/* Optional client-callable namespace cleanup function */ +extern dom_exception dom_namespace_finalise(void); + #endif diff --git a/include/dom/events/keyboard_event.h b/include/dom/events/keyboard_event.h index 132049e..e3b7d50 100644 --- a/include/dom/events/keyboard_event.h +++ b/include/dom/events/keyboard_event.h @@ -23,16 +23,26 @@ typedef enum { DOM_KEY_LOCATION_NUMPAD = 3 } dom_key_location; -dom_exception _dom_keyboard_event_get_key_identifier(dom_keyboard_event *evt, - dom_string **ident); -#define dom_keyboard_event_get_key_identifier(e, i) \ - _dom_keyboard_event_get_key_identifier( \ +dom_exception _dom_keyboard_event_create(dom_keyboard_event **evt); +#define dom_keyboard_event_create(n) \ + _dom_keyboard_event_create((dom_keyboard_event **) (n)) + +dom_exception _dom_keyboard_event_get_key(dom_keyboard_event *evt, + dom_string **key); +#define dom_keyboard_event_get_key(e, i) \ + _dom_keyboard_event_get_key( \ (dom_keyboard_event *) (e), (dom_string **) (i)) -dom_exception _dom_keyboard_event_get_key_location(dom_keyboard_event *evt, - dom_key_location *loc); -#define dom_keyboard_event_get_key_location(e, l) \ - _dom_keyboard_event_get_key_location( \ +dom_exception _dom_keyboard_event_get_code(dom_keyboard_event *evt, + dom_string **code); +#define dom_keyboard_event_get_code(e, i) \ + _dom_keyboard_event_get_code( \ + (dom_keyboard_event *) (e), (dom_string **) (i)) + +dom_exception _dom_keyboard_event_get_location(dom_keyboard_event *evt, + dom_key_location *location); +#define dom_keyboard_event_get_location(e, l) \ + _dom_keyboard_event_get_location( \ (dom_keyboard_event *) (e), (dom_key_location *) (l)) dom_exception _dom_keyboard_event_get_ctrl_key(dom_keyboard_event *evt, @@ -65,25 +75,32 @@ dom_exception _dom_keyboard_event_get_modifier_state(dom_keyboard_event *evt, dom_exception _dom_keyboard_event_init(dom_keyboard_event *evt, dom_string *type, bool bubble, bool cancelable, - struct dom_abstract_view *view, dom_string *key_ident, - dom_key_location key_loc, dom_string *modifier_list); -#define dom_keyboard_event_init(e, t, b, c, v, ki, kl, m) \ + struct dom_abstract_view *view, dom_string *key, + dom_string *code, dom_key_location location, + bool ctrl_key, bool shift_key, bool alt_key, bool meta_key, + bool repeat, bool is_composing); +#define dom_keyboard_event_init(e, t, b, c, v, kk, kc, kl, ck, sk, ak, mk, r, ic) \ _dom_keyboard_event_init((dom_keyboard_event *) (e), \ (dom_string *) (t), (bool) (b), (bool) (c), \ - (struct dom_abstract_view *) (v), (dom_string *) (ki), \ - (dom_key_location) (kl), (dom_string *) (m)) + (struct dom_abstract_view *) (v), (dom_string *) (kk), \ + (dom_string *) (kc), (dom_key_location) (kl), \ + (bool) (ck), (bool) (sk), (bool) (ak), (bool) (mk), \ + (bool) (r), (bool) (ic)) dom_exception _dom_keyboard_event_init_ns(dom_keyboard_event *evt, dom_string *namespace, dom_string *type, bool bubble, bool cancelable, struct dom_abstract_view *view, - dom_string *key_ident, dom_key_location key_loc, - dom_string *modifier_list); + dom_string *key, dom_string *code, dom_key_location location, + bool ctrl_key, bool shift_key, bool alt_key, bool meta_key, + bool repeat, bool is_composing); #define dom_keyboard_event_init_ns(e, n, t, b, c, v, ki, kl, m) \ _dom_keyboard_event_init_ns((dom_keyboard_event *) (e), \ (dom_string *) (n), (dom_string *) (t), \ - (bool) (b), (bool) (c), (struct dom_abstract_view *) (v), \ - (dom_string *) (ki), (dom_key_location) (kl), \ - (dom_string *) (m)) + (bool) (b), (bool) (c), \ + (struct dom_abstract_view *) (v), (dom_string *) (kk), \ + (dom_string *) (kc), (dom_key_location) (kl), \ + (bool) (ck), (bool) (sk), (bool) (ak), (bool) (mk), \ + (bool) (r), (bool) (ic)) #endif diff --git a/include/dom/html/html_canvas_element.h b/include/dom/html/html_canvas_element.h new file mode 100644 index 0000000..29c7668 --- /dev/null +++ b/include/dom/html/html_canvas_element.h @@ -0,0 +1,31 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2020 Vincent Sanders <vince@netsurf-browser.org> + */ + +#ifndef dom_html_canvas_element_h_ +#define dom_html_canvas_element_h_ + +#include <dom/inttypes.h> +#include <dom/core/exceptions.h> + +#include <dom/html/html_document.h> + +typedef struct dom_html_canvas_element dom_html_canvas_element; + +dom_exception dom_html_canvas_element_get_width( + dom_html_canvas_element *object, dom_ulong *width); + +dom_exception dom_html_canvas_element_set_width( + dom_html_canvas_element *object, dom_ulong width); + +dom_exception dom_html_canvas_element_get_height( + dom_html_canvas_element *object, dom_ulong *height); + +dom_exception dom_html_canvas_element_set_height( + dom_html_canvas_element *object, dom_ulong height); + + +#endif diff --git a/include/dom/html/html_elements.h b/include/dom/html/html_elements.h index 5b54bbe..6e954c5 100644 --- a/include/dom/html/html_elements.h +++ b/include/dom/html/html_elements.h @@ -12,6 +12,7 @@ DOM_HTML_ELEMENT_STRINGS_ENTRY(_UNKNOWN) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(A) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(ABBR) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(ACRONYM) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(ADDRESS) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(APPLET) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(AREA) \ @@ -23,6 +24,8 @@ DOM_HTML_ELEMENT_STRINGS_ENTRY(BASEFONT) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(BDI) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(BDO) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(BGSOUND) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(BIG) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(BLOCKQUOTE) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(BODY) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(BR) \ @@ -81,11 +84,14 @@ DOM_HTML_ELEMENT_STRINGS_ENTRY(MAIN) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(MAP) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(MARK) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(MARQUEE) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(MENU) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(MENUITEM) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(META) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(METER) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(NAV) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(NOBR) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(NOFRAMES) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(NOSCRIPT) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(OBJECT) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(OL) \ @@ -108,7 +114,9 @@ DOM_HTML_ELEMENT_STRINGS_ENTRY(SELECT) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(SMALL) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(SOURCE) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(SPACER) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(SPAN) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(STRIKE) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(STRONG) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(STYLE) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(SUB) \ @@ -126,6 +134,7 @@ DOM_HTML_ELEMENT_STRINGS_ENTRY(TITLE) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(TR) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(TRACK) \ + DOM_HTML_ELEMENT_STRINGS_ENTRY(TT) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(U) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(UL) \ DOM_HTML_ELEMENT_STRINGS_ENTRY(VAR) \ diff --git a/include/dom/html/html_script_element.h b/include/dom/html/html_script_element.h index 855bf9d..880ca1c 100644 --- a/include/dom/html/html_script_element.h +++ b/include/dom/html/html_script_element.h @@ -4,7 +4,9 @@ * http://www.opensource.org/licenses/mit-license.php * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com> * Copyright 2014 Rupinder Singh Khokhar <rsk1coder99@gmail.com> + * Copyright 2019 Daniel Silverstone <dsilvers@digital-scurf.org> */ + #ifndef dom_html_script_element_h_ #define dom_html_script_element_h_ @@ -14,6 +16,20 @@ typedef struct dom_html_script_element dom_html_script_element; +typedef enum { + DOM_HTML_SCRIPT_ELEMENT_FLAG_ALREADY_STARTED = 1 << 0, + DOM_HTML_SCRIPT_ELEMENT_FLAG_PARSER_INSERTED = 1 << 1, + DOM_HTML_SCRIPT_ELEMENT_FLAG_NON_BLOCKING = 1 << 2, + DOM_HTML_SCRIPT_ELEMENT_FLAG_READY_TO_BE_PARSER_EXECUTED = 1 << 3, + DOM_HTML_SCRIPT_ELEMENT_FLAG_FROM_EXTERNAL = 1 << 4, +} dom_html_script_element_flags; + +dom_exception dom_html_script_element_get_flags( + dom_html_script_element *ele, dom_html_script_element_flags *flags); + +dom_exception dom_html_script_element_set_flags( + dom_html_script_element *ele, dom_html_script_element_flags flags); + dom_exception dom_html_script_element_get_defer( dom_html_script_element *ele, bool *defer); diff --git a/include/dom/html/html_table_element.h b/include/dom/html/html_table_element.h index 6fcd7ed..205d719 100644 --- a/include/dom/html/html_table_element.h +++ b/include/dom/html/html_table_element.h @@ -120,7 +120,7 @@ dom_exception dom_html_table_element_delete_t_foot( dom_exception dom_html_table_element_insert_row( dom_html_table_element *element, - int32_t index, dom_html_element **row); + int32_t index, dom_html_element **row_out); dom_exception dom_html_table_element_delete_row( dom_html_table_element *element, diff --git a/include/dom/inttypes.h b/include/dom/inttypes.h index 3571cef..366e56e 100644 --- a/include/dom/inttypes.h +++ b/include/dom/inttypes.h @@ -8,7 +8,7 @@ #ifndef dom_inttypes_h_ #define dom_inttypes_h_ -#include <inttypes.h> +#include <stdint.h> /** * The IDL spec(2nd ed) 3.10.5 defines a short type with 16bit range diff --git a/include/dom/walk.h b/include/dom/walk.h new file mode 100644 index 0000000..5de3546 --- /dev/null +++ b/include/dom/walk.h @@ -0,0 +1,65 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2021 Michael Drake <tlsa@netsurf-browser.org> + */ + +/** \file + * This is an API for walking a loaded DOM. + */ + +#ifndef dom_walk_h_ +#define dom_walk_h_ + +enum dom_walk_stage { + DOM_WALK_STAGE_ENTER, + DOM_WALK_STAGE_LEAVE, +}; + +enum dom_walk_enable { + DOM_WALK_ENABLE_ENTER = (1 << DOM_WALK_STAGE_ENTER), + DOM_WALK_ENABLE_LEAVE = (1 << DOM_WALK_STAGE_LEAVE), + DOM_WALK_ENABLE_ALL = DOM_WALK_ENABLE_ENTER | DOM_WALK_ENABLE_LEAVE, +}; + +enum dom_walk_cmd { + DOM_WALK_CMD_CONTINUE, /**< Continue the tree walk. */ + DOM_WALK_CMD_ABORT, /**< Early termination of the tree walk. */ + DOM_WALK_CMD_SKIP, /**< Skip children (only for \ref DOM_WALK_ENABLE_ENTER). */ +}; + +/** + * DOM walking callback. + * + * Client callback for DOM walk. + * + * \param[in] stage Whether the \ref node is being entered or left. + * \param[in] node The node being walked. Client must take ref itself. + * \param[in] type The node type. + * \param[in] pw Client private data. + * \return Tree walking client command. + */ +typedef enum dom_walk_cmd (*dom_walk_cb)( + enum dom_walk_stage stage, + dom_node_type type, + dom_node *node, + void *pw); + + +/** + * Walk a DOM subtree. + * + * \param[in] mask Mask of stages to enable callback for. + * \param[in] cb The client callback function. + * \param[in] root Node to start walk from. + * \param[in] pw The client's private data. + * \return false for early termination of walk, true otherwise. + */ +dom_exception libdom_treewalk( + enum dom_walk_enable mask, + dom_walk_cb cb, + dom_node *root, + void *pw); + +#endif diff --git a/libdom.pc.in b/libdom.pc.in index 406ed9e..86a97bb 100644 --- a/libdom.pc.in +++ b/libdom.pc.in @@ -7,5 +7,5 @@ Name: libdom Description: W3C DOM implementation Version: VERSION REQUIRED -Libs: -L${libdir} -ldom -lexpat +Libs: -L${libdir} -ldom LIBRARIES Cflags: -I${includedir} diff --git a/src/core/Makefile b/src/core/Makefile index 41fd51f..5d9c969 100644 --- a/src/core/Makefile +++ b/src/core/Makefile @@ -6,6 +6,6 @@ DIR_SOURCES := \ text.c typeinfo.c comment.c \ namednodemap.c nodelist.c \ cdatasection.c document_type.c entity_ref.c pi.c \ - doc_fragment.c document.c + doc_fragment.c document.c tokenlist.c include $(NSBUILD)/Makefile.subdir diff --git a/src/core/attr.c b/src/core/attr.c index e18e2a7..8fcaac3 100644 --- a/src/core/attr.c +++ b/src/core/attr.c @@ -49,7 +49,7 @@ struct dom_attr { }; /* The vtable for dom_attr node */ -static struct dom_attr_vtable attr_vtable = { +static const struct dom_attr_vtable attr_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE, @@ -60,7 +60,7 @@ static struct dom_attr_vtable attr_vtable = { }; /* The protected vtable for dom_attr */ -static struct dom_node_protect_vtable attr_protect_vtable = { +static const struct dom_node_protect_vtable attr_protect_vtable = { DOM_ATTR_PROTECT_VTABLE }; diff --git a/src/core/cdatasection.c b/src/core/cdatasection.c index c6812e3..efba237 100644 --- a/src/core/cdatasection.c +++ b/src/core/cdatasection.c @@ -20,7 +20,7 @@ struct dom_cdata_section { dom_text base; /**< Base node */ }; -static struct dom_node_protect_vtable cdata_section_protect_vtable = { +static const struct dom_node_protect_vtable cdata_section_protect_vtable = { DOM_CDATA_SECTION_PROTECT_VTABLE }; diff --git a/src/core/characterdata.c b/src/core/characterdata.c index ea665b3..e6f5dbe 100644 --- a/src/core/characterdata.c +++ b/src/core/characterdata.c @@ -21,7 +21,7 @@ /* The virtual functions for dom_characterdata, we make this vtable * public to each child class */ -struct dom_characterdata_vtable characterdata_vtable = { +const struct dom_characterdata_vtable characterdata_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE diff --git a/src/core/characterdata.h b/src/core/characterdata.h index 0b0889c..c8f4db3 100644 --- a/src/core/characterdata.h +++ b/src/core/characterdata.h @@ -116,7 +116,7 @@ dom_exception _dom_characterdata_copy(dom_node_internal *old, _dom_characterdata_destroy, \ _dom_characterdata_copy -extern struct dom_characterdata_vtable characterdata_vtable; +extern const struct dom_characterdata_vtable characterdata_vtable; dom_exception _dom_characterdata_copy_internal(dom_characterdata *old, dom_characterdata *new); diff --git a/src/core/comment.c b/src/core/comment.c index 0697826..b36a1be 100644 --- a/src/core/comment.c +++ b/src/core/comment.c @@ -21,7 +21,7 @@ struct dom_comment { dom_characterdata base; /**< Base node */ }; -static struct dom_node_protect_vtable comment_protect_vtable = { +static const struct dom_node_protect_vtable comment_protect_vtable = { DOM_COMMENT_PROTECT_VTABLE }; diff --git a/src/core/doc_fragment.c b/src/core/doc_fragment.c index 96cc707..9e10a1a 100644 --- a/src/core/doc_fragment.c +++ b/src/core/doc_fragment.c @@ -22,14 +22,14 @@ struct dom_document_fragment { dom_node_internal base; /**< Base node */ }; -static struct dom_node_vtable df_vtable = { +static const struct dom_node_vtable df_vtable = { { DOM_NODE_EVENT_TARGET_VTABLE }, DOM_NODE_VTABLE }; -static struct dom_node_protect_vtable df_protect_vtable = { +static const struct dom_node_protect_vtable df_protect_vtable = { DOM_DF_PROTECT_VTABLE }; diff --git a/src/core/document.c b/src/core/document.c index 7c0bcdc..40d4cd9 100644 --- a/src/core/document.c +++ b/src/core/document.c @@ -42,7 +42,7 @@ struct dom_doc_nl { }; /* The virtual functions of this dom_document */ -static struct dom_document_vtable document_vtable = { +static const struct dom_document_vtable document_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE @@ -52,7 +52,7 @@ static struct dom_document_vtable document_vtable = { DOM_DOCUMENT_VTABLE }; -static struct dom_node_protect_vtable document_protect_vtable = { +static const struct dom_node_protect_vtable document_protect_vtable = { DOM_DOCUMENT_PROTECT_VTABLE }; diff --git a/src/core/document_type.c b/src/core/document_type.c index d7b1b99..a0fafdd 100644 --- a/src/core/document_type.c +++ b/src/core/document_type.c @@ -27,7 +27,7 @@ struct dom_document_type { dom_string *system_id; /**< Doctype system ID */ }; -static struct dom_document_type_vtable document_type_vtable = { +static const struct dom_document_type_vtable document_type_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE @@ -37,7 +37,7 @@ static struct dom_document_type_vtable document_type_vtable = { DOM_DOCUMENT_TYPE_VTABLE }; -static struct dom_node_protect_vtable dt_protect_vtable = { +static const struct dom_node_protect_vtable dt_protect_vtable = { DOM_DT_PROTECT_VTABLE }; diff --git a/src/core/element.c b/src/core/element.c index 1dae60a..05dc8c6 100644 --- a/src/core/element.c +++ b/src/core/element.c @@ -32,7 +32,7 @@ #include "utils/list.h" #include "events/mutation_event.h" -struct dom_element_vtable _dom_element_vtable = { +const struct dom_element_vtable _dom_element_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE @@ -42,7 +42,7 @@ struct dom_element_vtable _dom_element_vtable = { DOM_ELEMENT_VTABLE }; -static struct dom_element_protected_vtable element_protect_vtable = { +static const struct dom_element_protected_vtable element_protect_vtable = { { DOM_NODE_PROTECT_VTABLE_ELEMENT }, @@ -1232,9 +1232,11 @@ dom_exception _dom_element_has_class(struct dom_element *element, /** * Get a named ancestor node * + * The caller is responsible for unreffing the returned node. + * * \param element Element to consider * \param name Node name to look for - * \param ancestor Pointer to location to receive node pointer + * \param ancestor Pointer to location to receive node. * \return DOM_NO_ERR. */ dom_exception dom_element_named_ancestor_node(dom_element *element, @@ -1251,7 +1253,7 @@ dom_exception dom_element_named_ancestor_node(dom_element *element, assert(node->name != NULL); if (dom_string_caseless_lwc_isequal(node->name, name)) { - *ancestor = (dom_element *)node; + *ancestor = (dom_element *)dom_node_ref(node); break; } } @@ -1262,6 +1264,8 @@ dom_exception dom_element_named_ancestor_node(dom_element *element, /** * Get a named parent node * + * The caller is responsible for unreffing the returned node. + * * \param element Element to consider * \param name Node name to look for * \param parent Pointer to location to receive node pointer @@ -1281,7 +1285,7 @@ dom_exception dom_element_named_parent_node(dom_element *element, assert(node->name != NULL); if (dom_string_caseless_lwc_isequal(node->name, name)) { - *parent = (dom_element *)node; + *parent = (dom_element *)dom_node_ref(node); } break; } @@ -1292,6 +1296,8 @@ dom_exception dom_element_named_parent_node(dom_element *element, /** * Get a named parent node * + * The caller is responsible for unreffing the returned node. + * * \param element Element to consider * \param name Node name to look for * \param parent Pointer to location to receive node pointer @@ -1308,7 +1314,7 @@ dom_exception dom_element_parent_node(dom_element *element, if (node->type != DOM_ELEMENT_NODE) continue; - *parent = (dom_element *)node; + *parent = (dom_element *)dom_node_ref(node); break; } @@ -1414,7 +1420,12 @@ dom_exception _dom_element_is_default_namespace(dom_node_internal *node, return DOM_NO_ERR; } - return dom_node_is_default_namespace(node->parent, namespace, result); + if (node->parent != NULL) { + return dom_node_is_default_namespace(node->parent, namespace, result); + } else { + *result = false; + } + return DOM_NO_ERR; } /** @@ -1661,13 +1672,13 @@ dom_exception _dom_element_set_attr(struct dom_element *element, if (err != DOM_NO_ERR) return err; - success = true; - err = _dom_dispatch_subtree_modified_event(doc, - (dom_event_target *) e, &success); + err = dom_attr_set_value(match->attr, value); if (err != DOM_NO_ERR) return err; - err = dom_attr_set_value(match->attr, value); + success = true; + err = _dom_dispatch_subtree_modified_event(doc, + (dom_event_target *) e, &success); if (err != DOM_NO_ERR) return err; } else { diff --git a/src/core/element.h b/src/core/element.h index c89ddc0..fb946b7 100644 --- a/src/core/element.h +++ b/src/core/element.h @@ -238,6 +238,6 @@ dom_exception _dom_element_copy_internal(dom_element *old, dom_exception _dom_element_get_id(struct dom_element *ele, dom_string **id); -extern struct dom_element_vtable _dom_element_vtable; +extern const struct dom_element_vtable _dom_element_vtable; #endif diff --git a/src/core/entity_ref.c b/src/core/entity_ref.c index aa32111..bc6fbab 100644 --- a/src/core/entity_ref.c +++ b/src/core/entity_ref.c @@ -20,14 +20,14 @@ struct dom_entity_reference { dom_node_internal base; /**< Base node */ }; -static struct dom_node_vtable er_vtable = { +static const struct dom_node_vtable er_vtable = { { DOM_NODE_EVENT_TARGET_VTABLE }, DOM_NODE_VTABLE }; -static struct dom_node_protect_vtable er_protect_vtable = { +static const struct dom_node_protect_vtable er_protect_vtable = { DOM_ER_PROTECT_VTABLE }; diff --git a/src/core/node.c b/src/core/node.c index 17f93dd..1218742 100644 --- a/src/core/node.c +++ b/src/core/node.c @@ -55,14 +55,14 @@ static inline dom_exception _dom_node_detach_range(dom_node_internal *first, static inline void _dom_node_replace(dom_node_internal *old, dom_node_internal *replacement); -static struct dom_node_vtable node_vtable = { +static const struct dom_node_vtable node_vtable = { { DOM_NODE_EVENT_TARGET_VTABLE }, DOM_NODE_VTABLE }; -static struct dom_node_protect_vtable node_protect_vtable = { +static const struct dom_node_protect_vtable node_protect_vtable = { DOM_NODE_PROTECT_VTABLE }; @@ -296,6 +296,36 @@ void _dom_node_finalise(dom_node_internal *node) /* ---------------------------------------------------------------------*/ +/* The public non-virtual function of this interface Node */ + +dom_exception _dom_node_contains(struct dom_node_internal *node, + struct dom_node_internal *other, + bool *contains) +{ + assert(node != NULL); + assert(other != NULL); + assert(contains != NULL); + + if (node->owner != other->owner) { + *contains = false; + return DOM_NO_ERR; + } + + while (other != NULL) { + if (other == node) { + *contains = true; + return DOM_NO_ERR; + } + other = other->parent; + } + + *contains = false; + return DOM_NO_ERR; +} + + +/* ---------------------------------------------------------------------*/ + /* The public virtual function of this interface Node */ /** @@ -1472,6 +1502,8 @@ dom_exception _dom_node_set_text_content(dom_node_internal *node, err = dom_node_remove_child(node, p, (void *) &r); if (err != DOM_NO_ERR) return err; + /* The returned node was reffed, so unref it */ + dom_node_unref(r); } doc = node->owner; @@ -1480,12 +1512,15 @@ dom_exception _dom_node_set_text_content(dom_node_internal *node, err = dom_document_create_text_node(doc, content, &text); if (err != DOM_NO_ERR) return err; - + err = dom_node_append_child(node, text, (void *) &r); - if (err != DOM_NO_ERR) - return err; - return DOM_NO_ERR; + /* The node is held alive as a child here, so unref it */ + dom_node_unref(text); + /* And unref it a second time because append_child reffed it too */ + dom_node_unref(r); + + return err; } /** @@ -1792,8 +1827,8 @@ dom_exception _dom_node_set_user_data(dom_node_internal *node, * \param result Pointer to location to receive result * \return DOM_NO_ERR. */ -dom_exception _dom_node_get_user_data(dom_node_internal *node, - dom_string *key, void **result) +dom_exception _dom_node_get_user_data(const dom_node_internal *node, + const dom_string *key, void **result) { struct dom_user_data *ud = NULL; @@ -2137,7 +2172,9 @@ dom_exception _dom_node_detach_range(dom_node_internal *first, * * This is not implemented in terms of attach/detach in case * we want to perform any special replacement-related behaviour - * at a later date. + * at a later date. If the replacement is essentially empty (either NULL + * or an empty document fragment node) then this essentially just removes + * the old node from its parent. It is up to the caller to deal with that. */ void _dom_node_replace(dom_node_internal *old, dom_node_internal *replacement) @@ -2155,6 +2192,19 @@ void _dom_node_replace(dom_node_internal *old, last = replacement; } + if (first == NULL) { + /* All we're doing is removing old */ + if (old->previous == NULL) { + old->parent->first_child = old->next; + } + if (old->next == NULL) { + old->parent->last_child = old->previous; + } + old->previous = old->next = old->parent = NULL; + return; + } + + /* We're replacing old with first-to-last */ first->previous = old->previous; last->next = old->next; @@ -2168,7 +2218,7 @@ void _dom_node_replace(dom_node_internal *old, else old->parent->last_child = last; - for (n = first; n != last->next; n = n->next) { + for (n = first; n != NULL && n != last->next; n = n->next) { n->parent = old->parent; } diff --git a/src/core/node.h b/src/core/node.h index 87f3cb3..36cdd7d 100644 --- a/src/core/node.h +++ b/src/core/node.h @@ -53,7 +53,7 @@ typedef struct dom_node_protect_vtable { */ struct dom_node_internal { struct dom_node base; /**< The vtable base */ - void *vtable; /**< The protected vtable */ + const void *vtable; /**< The protected vtable */ dom_string *name; /**< Node name (this is the local part * of a QName in the cases where a @@ -182,8 +182,8 @@ dom_exception _dom_node_get_feature(dom_node_internal *node, dom_exception _dom_node_set_user_data(dom_node_internal *node, dom_string *key, void *data, dom_user_data_handler handler, void **result); -dom_exception _dom_node_get_user_data(dom_node_internal *node, - dom_string *key, void **result); +dom_exception _dom_node_get_user_data(const dom_node_internal *node, + const dom_string *key, void **result); #define DOM_NODE_EVENT_TARGET_VTABLE \ _dom_node_add_event_listener, \ diff --git a/src/core/nodelist.c b/src/core/nodelist.c index e2a1435..c549255 100644 --- a/src/core/nodelist.c +++ b/src/core/nodelist.c @@ -298,6 +298,9 @@ dom_exception dom_nodelist_get_length(dom_nodelist *list, uint32_t *length) * * The returned node will have had its reference count increased. The client * should unref the node once it has finished with it. + * + * NOTE: If \ref node contains a node pointer already, it will *NOT* be + * unreffed. Managing the lifetime of that is up to the caller. */ dom_exception _dom_nodelist_item(dom_nodelist *list, uint32_t index, dom_node **node) diff --git a/src/core/pi.c b/src/core/pi.c index d12f109..3e69841 100644 --- a/src/core/pi.c +++ b/src/core/pi.c @@ -20,14 +20,14 @@ struct dom_processing_instruction { dom_node_internal base; /**< Base node */ }; -static struct dom_node_vtable pi_vtable = { +static const struct dom_node_vtable pi_vtable = { { DOM_NODE_EVENT_TARGET_VTABLE }, DOM_NODE_VTABLE }; -static struct dom_node_protect_vtable pi_protect_vtable = { +static const struct dom_node_protect_vtable pi_protect_vtable = { DOM_PI_PROTECT_VTABLE }; /** diff --git a/src/core/string.c b/src/core/string.c index 1f0fdd5..f140a3a 100644 --- a/src/core/string.c +++ b/src/core/string.c @@ -56,7 +56,7 @@ static const dom_string_internal empty_string = { void dom_string_destroy(dom_string *str) { - dom_string_internal *istr = (dom_string_internal *)str; + dom_string_internal *istr = (void *) str; if (str != NULL) { assert(istr->base.refcnt == 0); switch (istr->type) { @@ -175,7 +175,7 @@ dom_exception dom_string_create_interned(const uint8_t *ptr, size_t len, dom_exception dom_string_intern(dom_string *str, struct lwc_string_s **lwcstr) { - dom_string_internal *istr = (dom_string_internal *) str; + dom_string_internal *istr = (void *) str; /* If this string is already interned, do nothing */ if (istr->type != DOM_STRING_INTERNED) { lwc_string *ret; @@ -209,8 +209,8 @@ dom_exception dom_string_intern(dom_string *str, bool dom_string_isequal(const dom_string *s1, const dom_string *s2) { size_t len; - const dom_string_internal *is1 = (dom_string_internal *) s1; - const dom_string_internal *is2 = (dom_string_internal *) s2; + const dom_string_internal *is1 = (void *) s1; + const dom_string_internal *is2 = (void *) s2; if (s1 == NULL) is1 = &empty_string; @@ -258,8 +258,8 @@ bool dom_string_caseless_isequal(const dom_string *s1, const dom_string *s2) const uint8_t *d1 = NULL; const uint8_t *d2 = NULL; size_t len; - const dom_string_internal *is1 = (dom_string_internal *) s1; - const dom_string_internal *is2 = (dom_string_internal *) s2; + const dom_string_internal *is1 = (void *) s1; + const dom_string_internal *is2 = (void *) s2; if (s1 == NULL) is1 = &empty_string; @@ -311,7 +311,7 @@ bool dom_string_caseless_isequal(const dom_string *s1, const dom_string *s2) bool dom_string_lwc_isequal(const dom_string *s1, lwc_string *s2) { size_t len; - dom_string_internal *is1 = (dom_string_internal *) s1; + dom_string_internal *is1 = (void *) s1; if (s1 == NULL || s2 == NULL) return false; @@ -348,7 +348,7 @@ bool dom_string_caseless_lwc_isequal(const dom_string *s1, lwc_string *s2) size_t len; const uint8_t *d1 = NULL; const uint8_t *d2 = NULL; - dom_string_internal *is1 = (dom_string_internal *) s1; + dom_string_internal *is1 = (void *) s1; if (s1 == NULL || s2 == NULL) return false; @@ -897,7 +897,7 @@ dom_exception _dom_exception_from_lwc_error(lwc_error err) */ const char *dom_string_data(const dom_string *str) { - dom_string_internal *istr = (dom_string_internal *) str; + dom_string_internal *istr = (void *) str; if (istr->type == DOM_STRING_CDATA) { return (const char *) istr->data.cdata.ptr; } else { @@ -911,7 +911,7 @@ const char *dom_string_data(const dom_string *str) */ size_t dom_string_byte_length(const dom_string *str) { - dom_string_internal *istr = (dom_string_internal *) str; + dom_string_internal *istr = (void *) str; if (istr->type == DOM_STRING_CDATA) { return istr->data.cdata.len; } else { @@ -954,7 +954,7 @@ dom_string_toupper(dom_string *source, bool ascii_only, dom_string **upper) index++; } - if (((dom_string_internal*)source)->type == DOM_STRING_CDATA) { + if (((dom_string_internal *) ((void *) source))->type == DOM_STRING_CDATA) { exc = dom_string_create(copy_s, nbytes, upper); } else { exc = dom_string_create_interned(copy_s, nbytes, upper); @@ -978,7 +978,7 @@ dom_string_toupper(dom_string *source, bool ascii_only, dom_string **upper) dom_exception dom_string_tolower(dom_string *source, bool ascii_only, dom_string **lower) { - dom_string_internal *isource = (dom_string_internal *)source; + dom_string_internal *isource = (void *) source; dom_exception exc = DOM_NO_ERR; if (ascii_only == false) @@ -1106,7 +1106,7 @@ dom_exception dom_string_whitespace_op(dom_string *s, len = temp_pos - temp; /* Make new string */ - if (((dom_string_internal *) s)->type == DOM_STRING_CDATA) { + if (((dom_string_internal *) ((void *) s))->type == DOM_STRING_CDATA) { exc = dom_string_create(temp, len, ret); } else { exc = dom_string_create_interned(temp, len, ret); diff --git a/src/core/text.c b/src/core/text.c index 3b726fd..f63fabe 100644 --- a/src/core/text.c +++ b/src/core/text.c @@ -20,7 +20,7 @@ #include "utils/utils.h" /* The virtual table for dom_text */ -struct dom_text_vtable text_vtable = { +const struct dom_text_vtable text_vtable = { { { { @@ -33,7 +33,7 @@ struct dom_text_vtable text_vtable = { DOM_TEXT_VTABLE }; -static struct dom_node_protect_vtable text_protect_vtable = { +static const struct dom_node_protect_vtable text_protect_vtable = { DOM_TEXT_PROTECT_VTABLE }; @@ -381,21 +381,32 @@ dom_exception walk_logic_adjacent_text_in_order( assert(node->last_child == NULL); if (opt == COLLECT) { err = dom_characterdata_get_data(node, &data); - if (err == DOM_NO_ERR) + if (err != DOM_NO_ERR) return err; tmp = *ret; if (order == LEFT) { - err = dom_string_concat(data, tmp, ret); - if (err == DOM_NO_ERR) - return err; + if (tmp != NULL) { + err = dom_string_concat(data, tmp, ret); + if (err != DOM_NO_ERR) + return err; + } else { + dom_string_ref(data); + *ret = data; + } } else if (order == RIGHT) { - err = dom_string_concat(tmp, data, ret); - if (err == DOM_NO_ERR) - return err; + if (tmp != NULL) { + err = dom_string_concat(tmp, data, ret); + if (err != DOM_NO_ERR) + return err; + } else { + dom_string_ref(data); + *ret = data; + } } - dom_string_unref(tmp); + if (tmp != NULL) + dom_string_unref(tmp); dom_string_unref(data); *cont = true; diff --git a/src/core/text.h b/src/core/text.h index 26424ce..3f5739b 100644 --- a/src/core/text.h +++ b/src/core/text.h @@ -66,7 +66,7 @@ dom_exception _dom_text_copy(dom_node_internal *old, dom_node_internal **copy); __dom_text_destroy, \ _dom_text_copy -extern struct dom_text_vtable text_vtable; +extern const struct dom_text_vtable text_vtable; dom_exception _dom_text_copy_internal(dom_text *old, dom_text *new); #define dom_text_copy_internal(o, n) \ diff --git a/src/core/tokenlist.c b/src/core/tokenlist.c new file mode 100644 index 0000000..cc93a8c --- /dev/null +++ b/src/core/tokenlist.c @@ -0,0 +1,547 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2022 Daniel Silverstone <dsilvers@digital-scurf.org> + */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <dom/core/element.h> +#include <dom/core/nodelist.h> +#include <dom/core/tokenlist.h> +#include <dom/core/string.h> +#include <dom/events/event.h> +#include <dom/events/event_target.h> +#include <dom/events/event_listener.h> +#include <dom/events/mutation_event.h> + +#include "core/element.h" +#include "core/document.h" + +#include "utils/utils.h" + +#define DOM_TOKENLIST_GROW_INCREMENT 4 + +struct dom_tokenlist { + uint32_t refcnt; + dom_element *ele; + dom_string *attr; + dom_event_listener *listener; + dom_string *last_set; + bool needs_parse; + /* Parsed content, for optimal access */ + dom_string **entries; + uint32_t len; + uint32_t alloc; +}; + +/* Handle a DOMAttrModified event which might be to do with our attribute */ + +static void _dom_tokenlist_handle_attrmodified(dom_event *evt, void *pw) +{ + dom_mutation_event *mutevt = (dom_mutation_event *)evt; + dom_tokenlist *list = (dom_tokenlist *)pw; + dom_exception exc; + dom_string *value; + + { + dom_event_target *target; + exc = dom_event_get_target(evt, &target); + if (exc != DOM_NO_ERR) + return; + dom_node_unref(target); + if (target != (dom_event_target *)list->ele) + return; + } + + { + dom_string *attr; + exc = dom_mutation_event_get_attr_name(mutevt, &attr); + if (exc != DOM_NO_ERR) + return; + if (!dom_string_isequal(attr, list->attr)) { + dom_string_unref(attr); + return; + } + dom_string_unref(attr); + } + + /* At this point we know that this is a mutation of our attribute on our + * node */ + + exc = dom_mutation_event_get_new_value(mutevt, &value); + if (exc != DOM_NO_ERR) + return; + + if (list->last_set != NULL && + dom_string_isequal(list->last_set, value)) { + /* We've just seen the mutation event for one of our own set + * operations */ + dom_string_unref(value); + return; + } + + /* Mark that we need to re-parse the tokenlist on the next request */ + list->needs_parse = true; + + dom_string_unref(value); +} + +static dom_exception _dom_tokenlist_make_room(dom_tokenlist *list) +{ + if (list->len == list->alloc) { + uint32_t new_alloc = list->alloc + DOM_TOKENLIST_GROW_INCREMENT; + dom_string **new_entries = realloc( + list->entries, new_alloc * sizeof(dom_string *)); + if (new_entries == NULL) + return DOM_NO_MEM_ERR; + list->alloc = new_alloc; + list->entries = new_entries; + } + + return DOM_NO_ERR; +} + +static dom_exception _dom_tokenlist_reparse(dom_tokenlist *list) +{ + dom_exception exc; + dom_string *value; + const char *pos; + uint32_t remaining, check; + uint32_t n_entries = 0; + dom_string *temp; + bool found; + + if (!list->needs_parse) + return DOM_NO_ERR; + + /* Clean down the current entries */ + while (list->len-- > 0) + dom_string_unref(list->entries[list->len]); + list->len = 0; + + /* Get the "new" attribute value */ + exc = dom_element_get_attribute(list->ele, list->attr, &value); + if (exc != DOM_NO_ERR) + return exc; + + /* If there is no value, we're an empty list and we're done */ + if (value == NULL) { + list->needs_parse = false; + return DOM_NO_ERR; + } + + /* OK, there's something here to do, so let's do it... */ + + /* Count number of entries */ + for (pos = dom_string_data(value), remaining = dom_string_length(value); + remaining > 0;) { + if (*pos != ' ') { + while (*pos != ' ' && remaining > 0) { + remaining--; + pos++; + } + n_entries++; + } else { + while (*pos == ' ' && remaining > 0) { + remaining--; + pos++; + } + } + } + + /* If there are no entries (all whitespace) just bail here */ + if (n_entries == 0) { + list->needs_parse = false; + dom_string_unref(value); + return DOM_NO_ERR; + } + + /* If we need more room, reallocate the buffer */ + if (list->alloc < n_entries) { + dom_string **new_alloc = realloc( + list->entries, n_entries * sizeof(dom_string *)); + if (new_alloc == NULL) { + dom_string_unref(value); + return DOM_NO_MEM_ERR; + } + list->entries = new_alloc; + list->alloc = n_entries; + } + + /* And now parse those entries into the buffer */ + for (pos = dom_string_data(value), + remaining = dom_string_length(value), + n_entries = 0; + remaining > 0;) { + if (*pos != ' ') { + const char *s = pos; + while (*pos != ' ' && remaining > 0) { + pos++; + remaining--; + } + exc = dom_string_create_interned((const uint8_t *)s, + pos - s, + &temp); + if (exc != DOM_NO_ERR) { + dom_string_unref(value); + return exc; + } + found = false; + for (check = 0; check < list->len; check++) { + if (dom_string_isequal(temp, + list->entries[check])) { + found = true; + break; + } + } + if (found == true) { + dom_string_unref(temp); + } else { + list->entries[list->len] = temp; + list->len++; + } + } else { + while (*pos == ' ' && remaining > 0) { + pos++; + remaining--; + } + } + } + + dom_string_unref(value); + list->needs_parse = false; + + return DOM_NO_ERR; +} + +static dom_exception _dom_tokenlist_reify(dom_tokenlist *list) +{ + dom_exception exc; + uint32_t nchars = 0, n; + char *buffer, *next; + dom_string *output; + + if (list->len == 0) { + if (list->last_set != NULL) { + dom_string_unref(list->last_set); + } + list->last_set = dom_string_ref( + list->ele->base.owner->_memo_empty); + return dom_element_set_attribute(list->ele, + list->attr, + list->last_set); + } + + for (n = 0; n < list->len; ++n) + nchars += dom_string_length(list->entries[n]); + + buffer = calloc(1, nchars + list->len); + if (buffer == NULL) + return DOM_NO_MEM_ERR; + + for (next = buffer, n = 0; n < list->len; ++n) { + uint32_t slen = dom_string_length(list->entries[n]); + memcpy(next, dom_string_data(list->entries[n]), slen); + next[slen] = ' '; + next += slen + 1; + } + + exc = dom_string_create_interned((const uint8_t *)buffer, + nchars + list->len - 1, + &output); + free(buffer); + if (exc != DOM_NO_ERR) + return exc; + + if (list->last_set != NULL) { + dom_string_unref(list->last_set); + } + list->last_set = output; + + return dom_element_set_attribute(list->ele, list->attr, list->last_set); +} + +/**********************************************************************************/ + +/** + * Create a tokenlist + * + * \param ele The element which owns the tokenlist attribute + * \param attr The name of the attribute we are treating as a tokenlist + * \param list The tokenlist output which is set on success + * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion + * + * The returned list will already be referenced, so the client need not + * do so explicitly. The client must unref the list once finished with it. + * + * This list will take its own references to ::ele and ::attr + */ +dom_exception +dom_tokenlist_create(dom_element *ele, dom_string *attr, dom_tokenlist **list) +{ + dom_tokenlist *l; + dom_exception exc; + + l = calloc(1, sizeof(dom_tokenlist)); + if (l == NULL) + return DOM_NO_MEM_ERR; + + l->refcnt = 1; + l->ele = (dom_element *)dom_node_ref(ele); + l->attr = dom_string_ref(attr); + l->needs_parse = true; + + exc = dom_event_listener_create(_dom_tokenlist_handle_attrmodified, + l, + &l->listener); + if (exc != DOM_NO_ERR) + goto fail; + + exc = dom_event_target_add_event_listener( + ele, + ele->base.owner->_memo_domattrmodified, + l->listener, + false); + + if (exc != DOM_NO_ERR) + goto fail; + + *list = l; + + return DOM_NO_ERR; + +fail: + if (l->listener != NULL) + dom_event_listener_unref(l->listener); + dom_node_unref(l->ele); + dom_string_unref(l->attr); + free(l); + return exc; +} + +/** + * Claim a ref on a tokenlist + * + * \param list The tokenlist to claim a ref on + */ +void dom_tokenlist_ref(dom_tokenlist *list) +{ + assert(list != NULL); + list->refcnt++; +} + +/** + * Release a ref on a tokenlist + * + * \param list The list to release the reference of + * + * If you release the last ref, this cleans up the tokenlist + */ +void dom_tokenlist_unref(dom_tokenlist *list) +{ + assert(list != NULL); + + if (--list->refcnt > 0) + return; + + if (list->alloc > 0) { + while (list->len-- > 0) + dom_string_unref(list->entries[list->len]); + free(list->entries); + } + + dom_event_target_remove_event_listener( + list->ele, + list->ele->base.owner->_memo_domattrmodified, + list->listener, + false); + + dom_event_listener_unref(list->listener); + + if (list->last_set != NULL) + dom_string_unref(list->last_set); + + dom_string_unref(list->attr); + dom_node_unref(list->ele); + + free(list); +} + +/** + * Get the length of the tokenlist + * + * \param list The list to get the length of + * \param length Length of the list outputs here + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception dom_tokenlist_get_length(dom_tokenlist *list, uint32_t *length) +{ + dom_exception exc; + assert(list != NULL); + + exc = _dom_tokenlist_reparse(list); + if (exc != DOM_NO_ERR) + return exc; + + *length = list->len; + + return DOM_NO_ERR; +} + +/** + * Get a particular item from the tokenlist + * + * \param list The list to retrieve the item from + * \param index The index of the item to retrieve + * \param value The value of the item returns here + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception +_dom_tokenlist_item(dom_tokenlist *list, uint32_t index, dom_string **value) +{ + dom_exception exc; + assert(list != NULL); + + exc = _dom_tokenlist_reparse(list); + if (exc != DOM_NO_ERR) + return exc; + + if (index >= list->len) { + *value = NULL; + return DOM_NO_ERR; + } + + *value = dom_string_ref(list->entries[index]); + return DOM_NO_ERR; +} + +/** + * Retrieve the value of the tokenlist as a string + * + * \param list The list to retrieve the value of + * \param value The value of the list returns here + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception dom_tokenlist_get_value(dom_tokenlist *list, dom_string **value) +{ + assert(list != NULL); + + return dom_element_get_attribute(list->ele, list->attr, value); +} + +/** + * Set the value of the tokenlist as a string + * + * \param list The list to set the value of + * \param value The value to set + * \return DOM_NO_ERR on success, otherwise the failure code + * + */ +dom_exception dom_tokenlist_set_value(dom_tokenlist *list, dom_string *value) +{ + assert(list != NULL); + + return dom_element_set_attribute(list->ele, list->attr, value); +} + +/** + * Check if the given value is in the tokenlist + * + * \param list The list to scan for the given value + * \param value The value to look for in the token list + * \param contains This will be set based on whether or not the value is present + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception +dom_tokenlist_contains(dom_tokenlist *list, dom_string *value, bool *contains) +{ + dom_exception exc; + uint32_t n; + + assert(list != NULL); + + exc = _dom_tokenlist_reparse(list); + if (exc != DOM_NO_ERR) + return exc; + + *contains = false; + + for (n = 0; n < list->len; n++) { + if (dom_string_isequal(value, list->entries[n])) { + *contains = true; + break; + } + } + + return DOM_NO_ERR; +} + +/** + * Add the given value to the tokenlist + * + * \param list The list to add to + * \param value The value to add + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception dom_tokenlist_add(dom_tokenlist *list, dom_string *value) +{ + dom_exception exc; + bool present = false; + + assert(list != NULL); + + exc = dom_tokenlist_contains(list, value, &present); + if (exc != DOM_NO_ERR) + return exc; + + if (present == true) + return DOM_NO_ERR; + + exc = _dom_tokenlist_make_room(list); + if (exc != DOM_NO_ERR) + return exc; + + list->entries[list->len++] = dom_string_ref(value); + + exc = _dom_tokenlist_reify(list); + + return exc; +} + +/** + * Remove the given value from the tokenlist + * + * \param list The list to remove from + * \param value The value to remove + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception dom_tokenlist_remove(dom_tokenlist *list, dom_string *value) +{ + dom_exception exc; + uint32_t n, m; + + assert(list != NULL); + + exc = _dom_tokenlist_reparse(list); + if (exc != DOM_NO_ERR) + return false; + + for (n = 0; n < list->len; ++n) { + if (dom_string_isequal(value, list->entries[n])) { + dom_string_unref(list->entries[n]); + for (m = n + 1; m < list->len; ++m) { + list->entries[m - 1] = list->entries[m]; + } + list->len--; + break; + } + } + + exc = _dom_tokenlist_reify(list); + + return exc; +} diff --git a/src/core/tokenlist.h b/src/core/tokenlist.h new file mode 100644 index 0000000..325d726 --- /dev/null +++ b/src/core/tokenlist.h @@ -0,0 +1,18 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org> + */ + +#ifndef dom_internal_core_tokenlist_h_ +#define dom_internal_core_tokenlist_h_ + +#include <stdbool.h> + +#include <dom/core/tokenlist.h> + +struct dom_element; +struct dom_string; + +#endif diff --git a/src/events/dispatch.c b/src/events/dispatch.c index 0e0048d..a8b8ad7 100644 --- a/src/events/dispatch.c +++ b/src/events/dispatch.c @@ -56,7 +56,7 @@ dom_exception __dom_dispatch_node_change_event(dom_document *doc, goto cleanup; cleanup: - _dom_mutation_event_destroy(evt); + dom_event_unref(evt); return err; } @@ -101,7 +101,7 @@ dom_exception __dom_dispatch_node_change_document_event(dom_document *doc, goto cleanup; cleanup: - _dom_mutation_event_destroy(evt); + dom_event_unref(evt); return err; } @@ -145,7 +145,7 @@ dom_exception __dom_dispatch_attr_modified_event(dom_document *doc, err = dom_event_target_dispatch_event(et, evt, success); cleanup: - _dom_mutation_event_destroy(evt); + dom_event_unref(evt); return err; } @@ -188,7 +188,7 @@ dom_exception __dom_dispatch_characterdata_modified_event( err = dom_event_target_dispatch_event(et, evt, success); cleanup: - _dom_mutation_event_destroy(evt); + dom_event_unref(evt); return err; } @@ -224,7 +224,7 @@ dom_exception __dom_dispatch_subtree_modified_event(dom_document *doc, err = dom_event_target_dispatch_event(et, evt, success); cleanup: - _dom_mutation_event_destroy(evt); + dom_event_unref(evt); return err; } @@ -263,7 +263,7 @@ dom_exception _dom_dispatch_generic_event(dom_document *doc, err = dom_event_target_dispatch_event(et, evt, success); cleanup: - _dom_event_destroy(evt); + dom_event_unref(evt); return err; } diff --git a/src/events/event.c b/src/events/event.c index 028c2e1..26b245e 100644 --- a/src/events/event.c +++ b/src/events/event.c @@ -18,7 +18,7 @@ static void _virtual_dom_event_destroy(dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_event_destroy }; @@ -57,7 +57,7 @@ dom_exception _dom_event_initialise(dom_event *evt) evt->refcnt = 1; evt->in_dispatch = false; evt->is_initialised = false; - evt->is_trusted = false; + evt->is_trusted = true; return DOM_NO_ERR; } diff --git a/src/events/event.h b/src/events/event.h index 857f20a..7cada7b 100644 --- a/src/events/event.h +++ b/src/events/event.h @@ -45,7 +45,7 @@ struct dom_event { uint32_t refcnt; /**< The reference count of this object */ - struct dom_event_private_vtable *vtable; + const struct dom_event_private_vtable *vtable; /**< The private virtual function table of Event */ bool in_dispatch; /**< Whether this event is in dispatch */ bool is_initialised; /**< Whether this event is initialised */ diff --git a/src/events/event_target.c b/src/events/event_target.c index ef2dc83..4592fee 100644 --- a/src/events/event_target.c +++ b/src/events/event_target.c @@ -99,6 +99,9 @@ dom_exception _dom_event_target_add_event_listener( /** * Remove an EventListener from the EventTarget * + * (LibDOM extension: If type is NULL, remove all listener registrations + * regardless of type and cature) + * * \param et The EventTarget object * \param type The event type this listener is registered for * \param listener The listener object @@ -114,9 +117,15 @@ dom_exception _dom_event_target_remove_event_listener( struct listener_entry *le = eti->listeners; do { - if (dom_string_isequal(le->type, type) && - le->listener == listener && - le->capture == capture) { + bool matches; + if (type == NULL) { + matches = (le->listener == listener); + } else { + matches = dom_string_isequal(le->type, type) && + (le->listener == listener) && + (le->capture == capture); + } + if (matches) { if (le->list.next == &le->list) { eti->listeners = NULL; } else { diff --git a/src/events/keyboard_event.c b/src/events/keyboard_event.c index fb29c18..d1fa1ca 100644 --- a/src/events/keyboard_event.c +++ b/src/events/keyboard_event.c @@ -15,14 +15,14 @@ static void _virtual_dom_keyboard_event_destroy(struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_keyboard_event_destroy }; /* Constructor */ dom_exception _dom_keyboard_event_create(struct dom_keyboard_event **evt) { - *evt = malloc(sizeof(dom_keyboard_event)); + *evt = calloc(1, sizeof(dom_keyboard_event)); if (*evt == NULL) return DOM_NO_MEM_ERR; @@ -42,8 +42,16 @@ void _dom_keyboard_event_destroy(struct dom_keyboard_event *evt) /* Initialise function */ dom_exception _dom_keyboard_event_initialise(struct dom_keyboard_event *evt) { - evt->key_ident = NULL; - evt->modifier_state = 0; + dom_exception err; + dom_string *empty_string; + + err = dom_string_create((const uint8_t *)"", 0, &empty_string); + if (err != DOM_NO_ERR) { + return err; + } + + evt->key = empty_string; + evt->code = dom_string_ref(empty_string); return _dom_ui_event_initialise(&evt->base); } @@ -51,6 +59,11 @@ dom_exception _dom_keyboard_event_initialise(struct dom_keyboard_event *evt) /* Finalise function */ void _dom_keyboard_event_finalise(struct dom_keyboard_event *evt) { + if (evt->key != NULL) + dom_string_unref(evt->key); + if (evt->code != NULL) + dom_string_unref(evt->code); + _dom_ui_event_finalise(&evt->base); } @@ -64,17 +77,31 @@ void _virtual_dom_keyboard_event_destroy(struct dom_event *evt) /* The public API */ /** - * Get the key identifier + * Get the key * * \param evt The Event object - * \param ident The returned key identifier + * \param key The returned key + * \return DOM_NO_ERR. + */ +dom_exception _dom_keyboard_event_get_key(dom_keyboard_event *evt, + dom_string **key) +{ + *key = dom_string_ref(evt->key); + + return DOM_NO_ERR; +} + +/** + * Get the code + * + * \param evt The Event object + * \param code The returned code * \return DOM_NO_ERR. */ -dom_exception _dom_keyboard_event_get_key_identifier(dom_keyboard_event *evt, - dom_string **ident) +dom_exception _dom_keyboard_event_get_code(dom_keyboard_event *evt, + dom_string **code) { - *ident = evt->key_ident; - dom_string_ref(*ident); + *code = dom_string_ref(evt->code); return DOM_NO_ERR; } @@ -83,13 +110,13 @@ dom_exception _dom_keyboard_event_get_key_identifier(dom_keyboard_event *evt, * Get the key location * * \param evt The Event object - * \param loc The returned key location + * \param location The returned key location * \return DOM_NO_ERR. */ -dom_exception _dom_keyboard_event_get_key_location(dom_keyboard_event *evt, - dom_key_location *loc) +dom_exception _dom_keyboard_event_get_location(dom_keyboard_event *evt, + dom_key_location *location) { - *loc = evt->key_loc; + *location = evt->location; return DOM_NO_ERR; } @@ -123,7 +150,7 @@ dom_exception _dom_keyboard_event_get_shift_key(dom_keyboard_event *evt, return DOM_NO_ERR; } - + /** * Get the alt key state * @@ -207,70 +234,147 @@ dom_exception _dom_keyboard_event_get_modifier_state(dom_keyboard_event *evt, } /** - * Initialise the keyboard event + * Helper to initialise the keyboard event * - * \param evt The Event object - * \param type The event's type - * \param bubble Whether this is a bubbling event - * \param cancelable Whether this is a cancelable event - * \param view The AbstractView associated with this event - * \param key_indent The key identifier of pressed key - * \param key_loc The key location of the preesed key - * \param modifier_list A string of modifier key identifiers, separated with - * space - * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + * \param evt The Event object + * \param view The AbstractView associated with this event + * \param key The key identifier of pressed key + * \param code The code identifier of pressed key + * \param location The key location of the preesed key + * \param ctrl_key Whether the ctrl_key is pressed + * \param shift_key Whether the shift_key is pressed + * \param alt_key Whether the alt_key is pressed + * \param meta_key Whether the ctrl_key is pressed + * \param repeat Whether this is a repeat press from a held key + * \param is_composing Whether the input is being composed */ -dom_exception _dom_keyboard_event_init(dom_keyboard_event *evt, - dom_string *type, bool bubble, bool cancelable, - struct dom_abstract_view *view, dom_string *key_ident, - dom_key_location key_loc, dom_string *modifier_list) +static void _dom_keyboard_event_init_helper( + dom_keyboard_event *evt, + dom_string *key, + dom_string *code, + dom_key_location location, + bool ctrl_key, + bool shift_key, + bool alt_key, + bool meta_key, + bool repeat, + bool is_composing) { - dom_exception err; + if (key != NULL) { + dom_string_unref(evt->key); + evt->key = dom_string_ref(key); + } + if (code != NULL) { + dom_string_unref(evt->code); + evt->code = dom_string_ref(code); + } - evt->key_ident = key_ident; - dom_string_ref(evt->key_ident); - evt->key_loc = key_loc; + evt->location = location; - err = _dom_parse_modifier_list(modifier_list, &evt->modifier_state); - if (err != DOM_NO_ERR) - return err; + if (ctrl_key) { + evt->modifier_state |= DOM_MOD_CTRL; + } + if (shift_key) { + evt->modifier_state |= DOM_MOD_CTRL; + } + if (alt_key) { + evt->modifier_state |= DOM_MOD_SHIFT; + } + if (meta_key) { + evt->modifier_state |= DOM_MOD_META; + } - return _dom_ui_event_init(&evt->base, type, bubble, cancelable, - view, 0); + evt->repeat = repeat; + evt->is_composing = is_composing; } + + /** * Initialise the keyboard event with namespace * - * \param evt The Event object - * \param namespace The namespace of this event - * \param type The event's type - * \param bubble Whether this is a bubbling event - * \param cancelable Whether this is a cancelable event - * \param view The AbstractView associated with this event - * \param key_indent The key identifier of pressed key - * \param key_loc The key location of the preesed key - * \param modifier_list A string of modifier key identifiers, separated with - * space + * \param evt The Event object + * \param type The event's type + * \param bubble Whether this is a bubbling event + * \param cancelable Whether this is a cancelable event + * \param view The AbstractView associated with this event + * \param key The key identifier of pressed key + * \param code The code identifier of pressed key + * \param location The key location of the preesed key + * \param ctrl_key Whether the ctrl_key is pressed + * \param shift_key Whether the shift_key is pressed + * \param alt_key Whether the alt_key is pressed + * \param meta_key Whether the ctrl_key is pressed + * \param repeat Whether this is a repeat press from a held key + * \param is_composing Whether the input is being composed * \return DOM_NO_ERR on success, appropriate dom_exception on failure. */ -dom_exception _dom_keyboard_event_init_ns(dom_keyboard_event *evt, - dom_string *namespace, dom_string *type, - bool bubble, bool cancelable, struct dom_abstract_view *view, - dom_string *key_ident, dom_key_location key_loc, - dom_string *modifier_list) +dom_exception _dom_keyboard_event_init( + dom_keyboard_event *evt, + dom_string *type, + bool bubble, + bool cancelable, + struct dom_abstract_view *view, + dom_string *key, + dom_string *code, + dom_key_location location, + bool ctrl_key, + bool shift_key, + bool alt_key, + bool meta_key, + bool repeat, + bool is_composing) { - dom_exception err; + _dom_keyboard_event_init_helper(evt, key, code, location, + ctrl_key, shift_key, alt_key, meta_key, + repeat, is_composing); - evt->key_ident = key_ident; - dom_string_ref(evt->key_ident); - evt->key_loc = key_loc; + return _dom_ui_event_init(&evt->base, type, bubble, cancelable, + view, 0); +} - err = _dom_parse_modifier_list(modifier_list, &evt->modifier_state); - if (err != DOM_NO_ERR) - return err; +/** + * Initialise the keyboard event with namespace + * + * \param evt The Event object + * \param namespace The namespace of this event + * \param type The event's type + * \param bubble Whether this is a bubbling event + * \param cancelable Whether this is a cancelable event + * \param view The AbstractView associated with this event + * \param key The key identifier of pressed key + * \param code The code identifier of pressed key + * \param location The key location of the preesed key + * \param ctrl_key Whether the ctrl_key is pressed + * \param shift_key Whether the shift_key is pressed + * \param alt_key Whether the alt_key is pressed + * \param meta_key Whether the ctrl_key is pressed + * \param repeat Whether this is a repeat press from a held key + * \param is_composing Whether the input is being composed + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_keyboard_event_init_ns( + dom_keyboard_event *evt, + dom_string *namespace, + dom_string *type, + bool bubble, + bool cancelable, + struct dom_abstract_view *view, + dom_string *key, + dom_string *code, + dom_key_location location, + bool ctrl_key, + bool shift_key, + bool alt_key, + bool meta_key, + bool repeat, + bool is_composing) +{ + _dom_keyboard_event_init_helper(evt, key, code, location, + ctrl_key, shift_key, alt_key, meta_key, + repeat, is_composing); - return _dom_ui_event_init_ns(&evt->base, namespace, type, bubble, + return _dom_ui_event_init_ns(&evt->base, namespace, type, bubble, cancelable, view, 0); } diff --git a/src/events/keyboard_event.h b/src/events/keyboard_event.h index d640bbb..81b702f 100644 --- a/src/events/keyboard_event.h +++ b/src/events/keyboard_event.h @@ -18,21 +18,15 @@ struct dom_keyboard_event { struct dom_ui_event base; /**< The base class */ - dom_string *key_ident; /**< The identifier of the key in this - * event, please refer: - * http://www.w3.org/TR/DOM-Level-3-Events/keyset.html#KeySet-Set - * for detail - */ - - dom_key_location key_loc; /**< Indicate the location of the key on - * the keyboard - */ + dom_string *key; + dom_string *code; + dom_key_location location; uint32_t modifier_state; /**< The modifier keys state */ -}; -/* Constructor */ -dom_exception _dom_keyboard_event_create(struct dom_keyboard_event **evt); + bool repeat; + bool is_composing; +}; /* Destructor */ void _dom_keyboard_event_destroy(struct dom_keyboard_event *evt); diff --git a/src/events/mouse_event.c b/src/events/mouse_event.c index b3b2154..ac1d142 100644 --- a/src/events/mouse_event.c +++ b/src/events/mouse_event.c @@ -15,7 +15,7 @@ static void _virtual_dom_mouse_event_destroy(struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_mouse_event_destroy }; diff --git a/src/events/mouse_multi_wheel_event.c b/src/events/mouse_multi_wheel_event.c index bcbe8d5..a42085a 100644 --- a/src/events/mouse_multi_wheel_event.c +++ b/src/events/mouse_multi_wheel_event.c @@ -16,7 +16,7 @@ static void _virtual_dom_mouse_multi_wheel_event_destroy( struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_mouse_multi_wheel_event_destroy }; diff --git a/src/events/mouse_wheel_event.c b/src/events/mouse_wheel_event.c index d59eab1..5d6bdd6 100644 --- a/src/events/mouse_wheel_event.c +++ b/src/events/mouse_wheel_event.c @@ -15,7 +15,7 @@ static void _virtual_dom_mouse_wheel_event_destroy(struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_mouse_wheel_event_destroy }; diff --git a/src/events/mutation_event.c b/src/events/mutation_event.c index df92c5f..2c5ffdc 100644 --- a/src/events/mutation_event.c +++ b/src/events/mutation_event.c @@ -11,7 +11,7 @@ static void _virtual_dom_mutation_event_destroy(struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_mutation_event_destroy }; diff --git a/src/events/mutation_name_event.c b/src/events/mutation_name_event.c index e0ba82e..13a51b5 100644 --- a/src/events/mutation_name_event.c +++ b/src/events/mutation_name_event.c @@ -14,7 +14,7 @@ static void _virtual_dom_mutation_name_event_destroy(struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_mutation_name_event_destroy }; diff --git a/src/events/text_event.c b/src/events/text_event.c index 3437716..d0d2706 100644 --- a/src/events/text_event.c +++ b/src/events/text_event.c @@ -12,7 +12,7 @@ static void _virtual_dom_text_event_destroy(struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_text_event_destroy }; diff --git a/src/events/ui_event.c b/src/events/ui_event.c index 4fac3b6..672f999 100644 --- a/src/events/ui_event.c +++ b/src/events/ui_event.c @@ -11,14 +11,14 @@ static void _virtual_dom_ui_event_destroy(struct dom_event *evt); -static struct dom_event_private_vtable _event_vtable = { +static const struct dom_event_private_vtable _event_vtable = { _virtual_dom_ui_event_destroy }; /* Constructor */ dom_exception _dom_ui_event_create(struct dom_ui_event **evt) { - *evt = malloc(sizeof(dom_ui_event)); + *evt = calloc(1, sizeof(dom_ui_event)); if (*evt == NULL) return DOM_NO_MEM_ERR; @@ -38,7 +38,6 @@ void _dom_ui_event_destroy(struct dom_ui_event *evt) /* Initialise function */ dom_exception _dom_ui_event_initialise(struct dom_ui_event *evt) { - evt->view = NULL; return _dom_event_initialise(&evt->base); } diff --git a/src/html/Makefile b/src/html/Makefile index c98ce9a..db765ad 100644 --- a/src/html/Makefile +++ b/src/html/Makefile @@ -1,24 +1,62 @@ # Sources DIR_SOURCES := \ - html_document.c html_collection.c html_options_collection.c \ - html_element.c html_html_element.c html_head_element.c \ - html_link_element.c html_title_element.c html_meta_element.c \ - html_base_element.c html_style_element.c \ - html_body_element.c html_form_element.c html_select_element.c \ - html_button_element.c html_input_element.c html_text_area_element.c \ - html_opt_group_element.c html_option_element.c html_hr_element.c \ - html_dlist_element.c html_directory_element.c html_menu_element.c \ - html_fieldset_element.c html_legend_element.c html_div_element.c \ - html_paragraph_element.c html_heading_element.c html_quote_element.c \ - html_pre_element.c html_br_element.c html_label_element.c \ - html_ulist_element.c html_olist_element.c html_li_element.c \ - html_font_element.c html_mod_element.c html_anchor_element.c \ - html_basefont_element.c html_image_element.c html_object_element.c \ - html_param_element.c html_applet_element.c html_area_element.c \ - html_map_element.c html_script_element.c html_tablecaption_element.c \ - html_tablecell_element.c html_tablecol_element.c html_tablesection_element.c \ - html_table_element.c html_tablerow_element.c html_frameset_element.c \ - html_frame_element.c html_iframe_element.c html_isindex_element.c \ + html_applet_element.c \ + html_area_element.c \ + html_anchor_element.c \ + html_basefont_element.c \ + html_base_element.c \ + html_body_element.c \ + html_button_element.c \ + html_canvas_element.c \ + html_collection.c \ + html_document.c \ + html_element.c \ + html_dlist_element.c \ + html_directory_element.c \ + html_options_collection.c \ + html_html_element.c \ + html_head_element.c \ + html_link_element.c \ + html_title_element.c \ + html_meta_element.c \ + html_style_element.c \ + html_form_element.c \ + html_select_element.c \ + html_input_element.c \ + html_text_area_element.c \ + html_opt_group_element.c \ + html_option_element.c \ + html_hr_element.c \ + html_menu_element.c \ + html_fieldset_element.c \ + html_legend_element.c \ + html_div_element.c \ + html_paragraph_element.c \ + html_heading_element.c \ + html_quote_element.c \ + html_pre_element.c \ + html_br_element.c \ + html_label_element.c \ + html_ulist_element.c \ + html_olist_element.c \ + html_li_element.c \ + html_font_element.c \ + html_mod_element.c \ + html_image_element.c \ + html_object_element.c \ + html_param_element.c \ + html_map_element.c \ + html_script_element.c \ + html_tablecaption_element.c \ + html_tablecell_element.c \ + html_tablecol_element.c \ + html_tablesection_element.c \ + html_table_element.c \ + html_tablerow_element.c \ + html_frameset_element.c \ + html_frame_element.c \ + html_iframe_element.c \ + html_isindex_element.c \ UNINMPLEMENTED_SOURCES := \ diff --git a/src/html/html_anchor_element.c b/src/html/html_anchor_element.c index 8d64c2b..88fd2ac 100644 --- a/src/html/html_anchor_element.c +++ b/src/html/html_anchor_element.c @@ -18,7 +18,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_ANCHOR_ELEMENT }, diff --git a/src/html/html_applet_element.c b/src/html/html_applet_element.c index 93ea1b5..f7f1afc 100644 --- a/src/html/html_applet_element.c +++ b/src/html/html_applet_element.c @@ -18,7 +18,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_APPLET_ELEMENT }, diff --git a/src/html/html_area_element.c b/src/html/html_area_element.c index 828b073..3da59d7 100644 --- a/src/html/html_area_element.c +++ b/src/html/html_area_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_AREA_ELEMENT }, diff --git a/src/html/html_base_element.c b/src/html/html_base_element.c index 0034f7c..f322f5b 100644 --- a/src/html/html_base_element.c +++ b/src/html/html_base_element.c @@ -13,7 +13,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_BASE_ELEMENT }, diff --git a/src/html/html_basefont_element.c b/src/html/html_basefont_element.c index ac1183d..b68ae03 100644 --- a/src/html/html_basefont_element.c +++ b/src/html/html_basefont_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_BASE_FONT_ELEMENT }, diff --git a/src/html/html_body_element.c b/src/html/html_body_element.c index 0fc4b13..4f52152 100644 --- a/src/html/html_body_element.c +++ b/src/html/html_body_element.c @@ -15,7 +15,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_BODY_ELEMENT }, diff --git a/src/html/html_br_element.c b/src/html/html_br_element.c index 74e3ea8..71778f6 100644 --- a/src/html/html_br_element.c +++ b/src/html/html_br_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_BR_ELEMENT }, diff --git a/src/html/html_button_element.c b/src/html/html_button_element.c index 04a17dd..52a3607 100644 --- a/src/html/html_button_element.c +++ b/src/html/html_button_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_BUTTON_ELEMENT }, diff --git a/src/html/html_canvas_element.c b/src/html/html_canvas_element.c new file mode 100644 index 0000000..71d4a53 --- /dev/null +++ b/src/html/html_canvas_element.c @@ -0,0 +1,214 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2020 Vincent Sanders <vince@netsurf-browser.org> + */ + +#include <assert.h> +#include <stdlib.h> + +#include <dom/html/html_canvas_element.h> + +#include "html/html_document.h" +#include "html/html_canvas_element.h" + +#include "core/node.h" +#include "core/attr.h" +#include "utils/utils.h" + +static const struct dom_element_protected_vtable _protect_vtable = { + { + DOM_NODE_PROTECT_VTABLE_HTML_CANVAS_ELEMENT + }, + DOM_HTML_CANVAS_ELEMENT_PROTECT_VTABLE +}; + +/** + * Create a dom_html_canvas_element object + * + * \param params The html element creation parameters + * \param ele The returned element object + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_html_canvas_element_create( + struct dom_html_element_create_params *params, + struct dom_html_canvas_element **ele) +{ + struct dom_node_internal *node; + + *ele = malloc(sizeof(dom_html_canvas_element)); + if (*ele == NULL) + return DOM_NO_MEM_ERR; + + /* Set up vtables */ + node = (struct dom_node_internal *) *ele; + node->base.vtable = &_dom_html_element_vtable; + node->vtable = &_protect_vtable; + + return _dom_html_canvas_element_initialise(params, *ele); +} + +/** + * Initialise a dom_html_canvas_element object + * + * \param params The html element creation parameters + * \param ele The dom_html_canvas_element object + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_html_canvas_element_initialise( + struct dom_html_element_create_params *params, + struct dom_html_canvas_element *ele) +{ + return _dom_html_element_initialise(params, &ele->base); +} + +/** + * Finalise a dom_html_canvas_element object + * + * \param ele The dom_html_canvas_element object + */ +void _dom_html_canvas_element_finalise(struct dom_html_canvas_element *ele) +{ + _dom_html_element_finalise(&ele->base); +} + +/** + * Destroy a dom_html_canvas_element object + * + * \param ele The dom_html_canvas_element object + */ +void _dom_html_canvas_element_destroy(struct dom_html_canvas_element *ele) +{ + _dom_html_canvas_element_finalise(ele); + free(ele); +} + +/*------------------------------------------------------------------------*/ +/* The protected virtual functions */ + +/* The virtual function used to parse attribute value, see src/core/element.c + * for detail */ +dom_exception _dom_html_canvas_element_parse_attribute(dom_element *ele, + dom_string *name, dom_string *value, + dom_string **parsed) +{ + UNUSED(ele); + UNUSED(name); + + dom_string_ref(value); + *parsed = value; + + return DOM_NO_ERR; +} + +/* The virtual destroy function, see src/core/node.c for detail */ +void _dom_virtual_html_canvas_element_destroy(dom_node_internal *node) +{ + _dom_html_canvas_element_destroy((struct dom_html_canvas_element *) node); +} + +/* The virtual copy function, see src/core/node.c for detail */ +dom_exception _dom_html_canvas_element_copy( + dom_node_internal *old, dom_node_internal **copy) +{ + dom_html_canvas_element *new_node; + dom_exception err; + + new_node = malloc(sizeof(dom_html_canvas_element)); + if (new_node == NULL) + return DOM_NO_MEM_ERR; + + err = dom_html_canvas_element_copy_internal(old, new_node); + if (err != DOM_NO_ERR) { + free(new_node); + return err; + } + + *copy = (dom_node_internal *) new_node; + + return DOM_NO_ERR; +} + +dom_exception _dom_html_canvas_element_copy_internal( + dom_html_canvas_element *old, + dom_html_canvas_element *new) +{ + dom_exception err; + + err = dom_html_element_copy_internal(old, new); + if (err != DOM_NO_ERR) { + return err; + } + + return DOM_NO_ERR; +} + +/*-----------------------------------------------------------------------*/ +/* API functions */ + + +dom_exception +dom_html_canvas_element_get_width(dom_html_canvas_element *canvas, + dom_ulong *width) +{ + dom_exception exc; + + exc = dom_html_element_get_dom_ulong_property(&canvas->base, + "width", + SLEN("width"), + width); + + if (exc != DOM_NO_ERR) + return exc; + + if (*width == (dom_ulong)-1) { + /* width not set on the canvas, default is 300px */ + *width = 300; + } + + return DOM_NO_ERR; +} + +dom_exception +dom_html_canvas_element_set_width(dom_html_canvas_element *canvas, + dom_ulong width) +{ + return dom_html_element_set_dom_ulong_property(&canvas->base, + "width", + SLEN("width"), + width); +} + +dom_exception +dom_html_canvas_element_get_height(dom_html_canvas_element *canvas, + dom_ulong *height) +{ + dom_exception exc; + + exc = dom_html_element_get_dom_ulong_property(&canvas->base, + "height", + SLEN("height"), + height); + + if (exc != DOM_NO_ERR) + return exc; + + if (*height == (dom_ulong)-1) { + /* height not set on the canvas, default is 150px */ + *height = 150; + } + + return DOM_NO_ERR; +} + +dom_exception +dom_html_canvas_element_set_height(dom_html_canvas_element *canvas, + dom_ulong height) +{ + return dom_html_element_set_dom_ulong_property(&canvas->base, + "height", + SLEN("height"), + height); +} + diff --git a/src/html/html_canvas_element.h b/src/html/html_canvas_element.h new file mode 100644 index 0000000..4cf3042 --- /dev/null +++ b/src/html/html_canvas_element.h @@ -0,0 +1,62 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2020 Vincent Sanders <vince@netsurf-browser.org> + */ + +#ifndef dom_internal_html_canvas_element_h_ +#define dom_internal_html_canvas_element_h_ + +#include <dom/html/html_canvas_element.h> + +#include "html/html_element.h" + +struct dom_html_canvas_element { + struct dom_html_element base; + /**< The base class */ +}; + +/* Create a dom_html_canvas_element object */ +dom_exception _dom_html_canvas_element_create( + struct dom_html_element_create_params *params, + struct dom_html_canvas_element **ele); + +/* Initialise a dom_html_canvas_element object */ +dom_exception _dom_html_canvas_element_initialise( + struct dom_html_element_create_params *params, + struct dom_html_canvas_element *ele); + +/* Finalise a dom_html_canvas_element object */ +void _dom_html_canvas_element_finalise(struct dom_html_canvas_element *ele); + +/* Destroy a dom_html_canvas_element object */ +void _dom_html_canvas_element_destroy(struct dom_html_canvas_element *ele); + +/* The protected virtual functions */ +dom_exception _dom_html_canvas_element_parse_attribute(dom_element *ele, + dom_string *name, dom_string *value, + dom_string **parsed); + +void _dom_virtual_html_canvas_element_destroy(dom_node_internal *node); +dom_exception _dom_html_canvas_element_copy(dom_node_internal *old, + dom_node_internal **copy); + +#define DOM_HTML_CANVAS_ELEMENT_PROTECT_VTABLE \ + _dom_html_canvas_element_parse_attribute + +#define DOM_NODE_PROTECT_VTABLE_HTML_CANVAS_ELEMENT \ + _dom_virtual_html_canvas_element_destroy, \ + _dom_html_canvas_element_copy + +/* Helper functions*/ +dom_exception _dom_html_canvas_element_copy_internal( + dom_html_canvas_element *old, + dom_html_canvas_element *new); +#define dom_html_canvas_element_copy_internal(o, n) \ + _dom_html_canvas_element_copy_internal( \ + (dom_html_canvas_element *) (o), \ + (dom_html_canvas_element *) (n)) + + +#endif diff --git a/src/html/html_collection.c b/src/html/html_collection.c index cba2b2d..7bb55b6 100644 --- a/src/html/html_collection.c +++ b/src/html/html_collection.c @@ -215,7 +215,8 @@ dom_exception dom_html_collection_named_item(dom_html_collection *col, struct dom_node_internal *n = col->root; dom_html_document *doc = (dom_html_document *)dom_node_get_owner(n); dom_exception err; - while (n != NULL) { + + while (n != NULL) { if (n->type == DOM_ELEMENT_NODE && col->ic(n, col->ctx) == true) { dom_string *id = NULL; @@ -227,16 +228,15 @@ dom_exception dom_html_collection_named_item(dom_html_collection *col, return err; } - if (id != NULL && dom_string_isequal(name, id)) { - *node = (struct dom_node *) n; - dom_node_ref(n); - dom_string_unref(id); - - return DOM_NO_ERR; - } + if (id != NULL) { + if (dom_string_isequal(name, id)) { + *node = dom_node_ref(n); + dom_string_unref(id); - if (id != NULL) + return DOM_NO_ERR; + } dom_string_unref(id); + } /* Check for Name attr if id not matched/found */ err = _dom_element_get_attribute((dom_element *)n, @@ -244,14 +244,16 @@ dom_exception dom_html_collection_named_item(dom_html_collection *col, if(err != DOM_NO_ERR) { return err; } - if (id_name != NULL && dom_string_isequal(name, id_name)) { - *node = (struct dom_node *) n; - dom_node_ref(n); - dom_string_unref(id_name); - return DOM_NO_ERR; - } + if (id_name != NULL) { + if (dom_string_isequal(name, id_name)) { + *node = dom_node_ref(n); + dom_string_unref(id_name); + return DOM_NO_ERR; + } + dom_string_unref(id_name); + } } /* Depth first iterating */ diff --git a/src/html/html_directory_element.c b/src/html/html_directory_element.c index 585af1c..19db7cd 100644 --- a/src/html/html_directory_element.c +++ b/src/html/html_directory_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_DIRECTORY_ELEMENT }, diff --git a/src/html/html_div_element.c b/src/html/html_div_element.c index b061246..c39af74 100644 --- a/src/html/html_div_element.c +++ b/src/html/html_div_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_DIV_ELEMENT }, diff --git a/src/html/html_dlist_element.c b/src/html/html_dlist_element.c index ab9d4c3..fb0ad56 100644 --- a/src/html/html_dlist_element.c +++ b/src/html/html_dlist_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_DL_ELEMENT }, diff --git a/src/html/html_document.c b/src/html/html_document.c index 2f219d0..cf3c25d 100644 --- a/src/html/html_document.c +++ b/src/html/html_document.c @@ -17,6 +17,7 @@ #include "html/html_head_element.h" #include "html/html_body_element.h" #include "html/html_base_element.h" +#include "html/html_canvas_element.h" #include "html/html_div_element.h" #include "html/html_link_element.h" #include "html/html_title_element.h" @@ -71,7 +72,7 @@ #include "utils/namespace.h" #include "utils/utils.h" -static struct dom_html_document_vtable html_document_vtable = { +static const struct dom_html_document_vtable html_document_vtable = { { { { @@ -84,7 +85,7 @@ static struct dom_html_document_vtable html_document_vtable = { DOM_HTML_DOCUMENT_VTABLE }; -static struct dom_node_protect_vtable html_document_protect_vtable = { +static const struct dom_node_protect_vtable html_document_protect_vtable = { DOM_HTML_DOCUMENT_PROTECT_VTABLE }; @@ -318,6 +319,8 @@ static inline dom_html_element_type _dom_html_document_get_element_type( RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_RP) else RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_RT) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_TT) break; case 3: RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_DIV) @@ -353,6 +356,8 @@ static inline dom_html_element_type _dom_html_document_get_element_type( RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_BDO) else RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_WBR) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_BIG) break; case 4: RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_META) @@ -394,6 +399,8 @@ static inline dom_html_element_type _dom_html_document_get_element_type( RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_BASE) else RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_TIME) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_NOBR) break; case 5: RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_INPUT) @@ -468,6 +475,10 @@ static inline dom_html_element_type _dom_html_document_get_element_type( RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_SOURCE) else RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_STRONG) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_SPACER) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_STRIKE) break; case 7: RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_CAPTION) @@ -485,6 +496,12 @@ static inline dom_html_element_type _dom_html_document_get_element_type( RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_SECTION) else RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_SUMMARY) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_ACRONYM) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_BGSOUND) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_MARQUEE) break; case 8: RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_TEXTAREA) @@ -508,6 +525,8 @@ static inline dom_html_element_type _dom_html_document_get_element_type( RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_PROGRESS) else RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_TEMPLATE) + else + RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_NOFRAMES) break; case 10: RETURN_IF_MATCH(upper, DOM_HTML_ELEMENT_TYPE_BLOCKQUOTE) @@ -535,6 +554,10 @@ _dom_html_document_create_element_internal( dom_exception exc; struct dom_html_element_create_params params; + /* If the input tag name is empty, this is an 'invalid character' error */ + if (dom_string_length(in_tag_name) == 0) + return DOM_INVALID_CHARACTER_ERR; + exc = dom_string_toupper(in_tag_name, true, ¶ms.name); if (exc != DOM_NO_ERR) return exc; @@ -771,6 +794,10 @@ _dom_html_document_create_element_internal( exc = _dom_html_isindex_element_create(¶ms, (dom_html_isindex_element **) result); break; + case DOM_HTML_ELEMENT_TYPE_CANVAS: + exc = _dom_html_canvas_element_create(¶ms, + (dom_html_canvas_element **) result); + break; case DOM_HTML_ELEMENT_TYPE_DATA: case DOM_HTML_ELEMENT_TYPE_SPAN: case DOM_HTML_ELEMENT_TYPE_TIME: @@ -779,7 +806,6 @@ _dom_html_document_create_element_internal( case DOM_HTML_ELEMENT_TYPE_METER: case DOM_HTML_ELEMENT_TYPE_TRACK: case DOM_HTML_ELEMENT_TYPE_VIDEO: - case DOM_HTML_ELEMENT_TYPE_CANVAS: case DOM_HTML_ELEMENT_TYPE_DIALOG: case DOM_HTML_ELEMENT_TYPE_KEYGEN: case DOM_HTML_ELEMENT_TYPE_OUTPUT: @@ -801,8 +827,10 @@ _dom_html_document_create_element_internal( case DOM_HTML_ELEMENT_TYPE_EM: case DOM_HTML_ELEMENT_TYPE_RP: case DOM_HTML_ELEMENT_TYPE_RT: + case DOM_HTML_ELEMENT_TYPE_TT: case DOM_HTML_ELEMENT_TYPE_BDI: case DOM_HTML_ELEMENT_TYPE_BDO: + case DOM_HTML_ELEMENT_TYPE_BIG: case DOM_HTML_ELEMENT_TYPE_DFN: case DOM_HTML_ELEMENT_TYPE_KBD: case DOM_HTML_ELEMENT_TYPE_NAV: @@ -815,6 +843,7 @@ _dom_html_document_create_element_internal( case DOM_HTML_ELEMENT_TYPE_CODE: case DOM_HTML_ELEMENT_TYPE_MAIN: case DOM_HTML_ELEMENT_TYPE_MARK: + case DOM_HTML_ELEMENT_TYPE_NOBR: case DOM_HTML_ELEMENT_TYPE_RUBY: case DOM_HTML_ELEMENT_TYPE_SAMP: case DOM_HTML_ELEMENT_TYPE_ASIDE: @@ -825,10 +854,16 @@ _dom_html_document_create_element_internal( case DOM_HTML_ELEMENT_TYPE_HEADER: case DOM_HTML_ELEMENT_TYPE_HGROUP: case DOM_HTML_ELEMENT_TYPE_STRONG: + case DOM_HTML_ELEMENT_TYPE_SPACER: + case DOM_HTML_ELEMENT_TYPE_STRIKE: + case DOM_HTML_ELEMENT_TYPE_ACRONYM: case DOM_HTML_ELEMENT_TYPE_ADDRESS: case DOM_HTML_ELEMENT_TYPE_ARTICLE: + case DOM_HTML_ELEMENT_TYPE_BGSOUND: + case DOM_HTML_ELEMENT_TYPE_MARQUEE: case DOM_HTML_ELEMENT_TYPE_SECTION: case DOM_HTML_ELEMENT_TYPE_SUMMARY: + case DOM_HTML_ELEMENT_TYPE_NOFRAMES: case DOM_HTML_ELEMENT_TYPE_NOSCRIPT: case DOM_HTML_ELEMENT_TYPE_FIGCAPTION: /* These have no specialisation: use HTMLElement */ @@ -1119,6 +1154,7 @@ dom_exception _dom_html_document_get_body(dom_html_document *doc, } if (len == 0) { + dom_nodelist_unref(nodes); exc = dom_document_get_elements_by_tag_name(doc, doc->elements[DOM_HTML_ELEMENT_TYPE_FRAMESET], &nodes); @@ -1143,7 +1179,6 @@ dom_exception _dom_html_document_get_body(dom_html_document *doc, } *body = (dom_html_element *)node; - dom_node_unref(node); } return exc; @@ -1183,8 +1218,10 @@ dom_exception _dom_html_document_get_images(dom_html_document *doc, if (err != DOM_NO_ERR) return err; - return _dom_html_collection_create(doc, (dom_node_internal *) root, + err = _dom_html_collection_create(doc, (dom_node_internal *) root, images_callback, doc, col); + dom_node_unref(root); + return err; } bool applet_callback(struct dom_node_internal * node, void *ctx) @@ -1232,8 +1269,10 @@ dom_exception _dom_html_document_get_applets(dom_html_document *doc, if (err != DOM_NO_ERR) return err; - return _dom_html_collection_create(doc, (dom_node_internal *) root, + err = _dom_html_collection_create(doc, (dom_node_internal *) root, applets_callback, doc, col); + dom_node_unref(root); + return err; } /** @@ -1275,8 +1314,10 @@ dom_exception _dom_html_document_get_links(dom_html_document *doc, if (err != DOM_NO_ERR) return err; - return _dom_html_collection_create(doc, (dom_node_internal *) root, + err = _dom_html_collection_create(doc, (dom_node_internal *) root, links_callback, doc, col); + dom_node_unref(root); + return err; } static bool __dom_html_document_node_is_form(dom_node_internal *node, @@ -1351,8 +1392,10 @@ dom_exception _dom_html_document_get_anchors(dom_html_document *doc, if (err != DOM_NO_ERR) return err; - return _dom_html_collection_create(doc, (dom_node_internal *) root, + err = _dom_html_collection_create(doc, (dom_node_internal *) root, anchors_callback, doc, col); + dom_node_unref(root); + return err; } dom_exception _dom_html_document_get_cookie(dom_html_document *doc, diff --git a/src/html/html_element.c b/src/html/html_element.c index 65a75ca..c110455 100644 --- a/src/html/html_element.c +++ b/src/html/html_element.c @@ -18,7 +18,7 @@ #include "core/document.h" #include "utils/utils.h" -struct dom_html_element_vtable _dom_html_element_vtable = { +const struct dom_html_element_vtable _dom_html_element_vtable = { { { { @@ -31,7 +31,7 @@ struct dom_html_element_vtable _dom_html_element_vtable = { DOM_HTML_ELEMENT_VTABLE }; -static struct dom_element_protected_vtable _dom_html_element_protect_vtable = { +static const struct dom_element_protected_vtable _dom_html_element_protect_vtable = { { DOM_HTML_ELEMENT_PROTECT_VTABLE }, @@ -477,7 +477,7 @@ dom_exception dom_html_element_get_int32_t_property(dom_html_element *ele, char *s3 = _strndup(dom_string_data(s2), dom_string_byte_length(s2)); if (s3 != NULL) { - *value = strtoul(s3, NULL, 0); + *value = strtol(s3, NULL, 0); free(s3); } else { err = DOM_NO_MEM_ERR; @@ -518,7 +518,7 @@ dom_exception dom_html_element_set_int32_t_property(dom_html_element *ele, if (err != DOM_NO_ERR) goto fail; - if (snprintf(numbuffer, 32, "%u", value) == 32) + if (snprintf(numbuffer, 32, "%"PRIu32, value) == 32) numbuffer[31] = '\0'; err = dom_string_create((const uint8_t *) numbuffer, @@ -526,7 +526,7 @@ dom_exception dom_html_element_set_int32_t_property(dom_html_element *ele, if (err != DOM_NO_ERR) goto cleanup; - err = dom_element_set_attribute(ele, svalue, str); + err = dom_element_set_attribute(ele, str, svalue); dom_string_unref(svalue); cleanup: @@ -607,7 +607,7 @@ dom_exception dom_html_element_set_dom_ulong_property(dom_html_element *ele, if (err != DOM_NO_ERR) goto fail; - if (snprintf(numbuffer, 32, "%u", value) == 32) + if (snprintf(numbuffer, 32, "%"PRIu32, value) == 32) numbuffer[31] = '\0'; err = dom_string_create((const uint8_t *) numbuffer, @@ -615,7 +615,7 @@ dom_exception dom_html_element_set_dom_ulong_property(dom_html_element *ele, if (err != DOM_NO_ERR) goto cleanup; - err = dom_element_set_attribute(ele, svalue, str); + err = dom_element_set_attribute(ele, str, svalue); dom_string_unref(svalue); cleanup: diff --git a/src/html/html_element.h b/src/html/html_element.h index 0290569..87e1bbb 100644 --- a/src/html/html_element.h +++ b/src/html/html_element.h @@ -162,7 +162,7 @@ dom_exception _dom_html_element_copy_internal(dom_html_element *old, #define dom_html_element_copy_internal(o, n) _dom_html_element_copy_internal( \ (dom_html_element *) (o), (dom_html_element *) (n)) -extern struct dom_html_element_vtable _dom_html_element_vtable; +extern const struct dom_html_element_vtable _dom_html_element_vtable; #endif diff --git a/src/html/html_fieldset_element.c b/src/html/html_fieldset_element.c index c869822..2ab8dd0 100644 --- a/src/html/html_fieldset_element.c +++ b/src/html/html_fieldset_element.c @@ -17,7 +17,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_FIELDSET_ELEMENT }, @@ -170,7 +170,7 @@ dom_exception dom_html_field_set_element_get_form( } if (form_tmp != NULL) { - *form = (dom_html_form_element *) form_tmp; + *form = (dom_html_form_element *) dom_node_ref(form_tmp); return DOM_NO_ERR; } diff --git a/src/html/html_font_element.c b/src/html/html_font_element.c index ecedfb0..38f8869 100644 --- a/src/html/html_font_element.c +++ b/src/html/html_font_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_FONT_ELEMENT }, diff --git a/src/html/html_form_element.c b/src/html/html_form_element.c index 1dd1992..5ba8365 100644 --- a/src/html/html_form_element.c +++ b/src/html/html_form_element.c @@ -22,7 +22,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_FORM_ELEMENT }, diff --git a/src/html/html_frame_element.c b/src/html/html_frame_element.c index fe6859c..321cff9 100644 --- a/src/html/html_frame_element.c +++ b/src/html/html_frame_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_FRAME_ELEMENT }, diff --git a/src/html/html_frameset_element.c b/src/html/html_frameset_element.c index be44d5d..84a52b0 100644 --- a/src/html/html_frameset_element.c +++ b/src/html/html_frameset_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_FRAME_SET_ELEMENT }, diff --git a/src/html/html_head_element.c b/src/html/html_head_element.c index ff02b1f..20f6aa8 100644 --- a/src/html/html_head_element.c +++ b/src/html/html_head_element.c @@ -13,7 +13,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_HEAD_ELEMENT }, diff --git a/src/html/html_heading_element.c b/src/html/html_heading_element.c index 8ab2c5a..21e36c6 100644 --- a/src/html/html_heading_element.c +++ b/src/html/html_heading_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_HEADING_ELEMENT }, diff --git a/src/html/html_hr_element.c b/src/html/html_hr_element.c index e6086f5..8ca9743 100644 --- a/src/html/html_hr_element.c +++ b/src/html/html_hr_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_HR_ELEMENT }, diff --git a/src/html/html_html_element.c b/src/html/html_html_element.c index 9cdcd5e..24f35e4 100644 --- a/src/html/html_html_element.c +++ b/src/html/html_html_element.c @@ -13,7 +13,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_HTML_ELEMENT }, diff --git a/src/html/html_iframe_element.c b/src/html/html_iframe_element.c index 4d7272b..96397d0 100644 --- a/src/html/html_iframe_element.c +++ b/src/html/html_iframe_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_IFRAME_ELEMENT }, diff --git a/src/html/html_image_element.c b/src/html/html_image_element.c index 3cdd15f..e5b9c7b 100644 --- a/src/html/html_image_element.c +++ b/src/html/html_image_element.c @@ -18,7 +18,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_IMAGE_ELEMENT }, diff --git a/src/html/html_input_element.c b/src/html/html_input_element.c index 079b55e..025ef5d 100644 --- a/src/html/html_input_element.c +++ b/src/html/html_input_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_INPUT_ELEMENT }, diff --git a/src/html/html_isindex_element.c b/src/html/html_isindex_element.c index 40cb99c..e793fae 100644 --- a/src/html/html_isindex_element.c +++ b/src/html/html_isindex_element.c @@ -16,7 +16,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_ISINDEX_ELEMENT }, diff --git a/src/html/html_label_element.c b/src/html/html_label_element.c index 3864cc4..c62adca 100644 --- a/src/html/html_label_element.c +++ b/src/html/html_label_element.c @@ -15,7 +15,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_LABEL_ELEMENT }, @@ -167,7 +167,7 @@ dom_exception dom_html_label_element_get_form( } if (form_tmp != NULL) { - *form = (dom_html_form_element *) form_tmp; + *form = (dom_html_form_element *) dom_node_ref(form_tmp); return DOM_NO_ERR; } diff --git a/src/html/html_legend_element.c b/src/html/html_legend_element.c index efb712b..f4200c8 100644 --- a/src/html/html_legend_element.c +++ b/src/html/html_legend_element.c @@ -19,7 +19,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_LEGEND_ELEMENT }, diff --git a/src/html/html_li_element.c b/src/html/html_li_element.c index 84becf9..6856046 100644 --- a/src/html/html_li_element.c +++ b/src/html/html_li_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_LI_ELEMENT }, diff --git a/src/html/html_link_element.c b/src/html/html_link_element.c index 87fe980..4916883 100644 --- a/src/html/html_link_element.c +++ b/src/html/html_link_element.c @@ -15,7 +15,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_LINK_ELEMENT }, diff --git a/src/html/html_map_element.c b/src/html/html_map_element.c index 3b10222..865d9b6 100644 --- a/src/html/html_map_element.c +++ b/src/html/html_map_element.c @@ -19,7 +19,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_MAP_ELEMENT }, diff --git a/src/html/html_menu_element.c b/src/html/html_menu_element.c index 09eadb6..882f1f2 100644 --- a/src/html/html_menu_element.c +++ b/src/html/html_menu_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_MENU_ELEMENT }, diff --git a/src/html/html_meta_element.c b/src/html/html_meta_element.c index 4098daf..39fd9e1 100644 --- a/src/html/html_meta_element.c +++ b/src/html/html_meta_element.c @@ -13,7 +13,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_META_ELEMENT }, diff --git a/src/html/html_mod_element.c b/src/html/html_mod_element.c index 20cb042..4f3331c 100644 --- a/src/html/html_mod_element.c +++ b/src/html/html_mod_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_MOD_ELEMENT }, diff --git a/src/html/html_object_element.c b/src/html/html_object_element.c index e926aef..1359ede 100644 --- a/src/html/html_object_element.c +++ b/src/html/html_object_element.c @@ -20,7 +20,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_OBJECT_ELEMENT }, @@ -274,7 +274,7 @@ dom_exception dom_html_object_element_get_form( } if (form_tmp != NULL) { - *form = (dom_html_form_element *) form_tmp; + *form = (dom_html_form_element *) dom_node_ref(form_tmp); return DOM_NO_ERR; } diff --git a/src/html/html_olist_element.c b/src/html/html_olist_element.c index c89d11f..415b656 100644 --- a/src/html/html_olist_element.c +++ b/src/html/html_olist_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_OLIST_ELEMENT }, diff --git a/src/html/html_opt_group_element.c b/src/html/html_opt_group_element.c index 6af0a29..a50e3de 100644 --- a/src/html/html_opt_group_element.c +++ b/src/html/html_opt_group_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_OPT_GROUP_ELEMENT }, diff --git a/src/html/html_paragraph_element.c b/src/html/html_paragraph_element.c index 2b2f420..3c8f384 100644 --- a/src/html/html_paragraph_element.c +++ b/src/html/html_paragraph_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_P_ELEMENT }, diff --git a/src/html/html_param_element.c b/src/html/html_param_element.c index c75e1ce..2c991ac 100644 --- a/src/html/html_param_element.c +++ b/src/html/html_param_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_PARAM_ELEMENT }, diff --git a/src/html/html_pre_element.c b/src/html/html_pre_element.c index 64c8c3d..7582fde 100644 --- a/src/html/html_pre_element.c +++ b/src/html/html_pre_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_PRE_ELEMENT }, diff --git a/src/html/html_quote_element.c b/src/html/html_quote_element.c index cf3e0c5..f1bc06f 100644 --- a/src/html/html_quote_element.c +++ b/src/html/html_quote_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_QUOTE_ELEMENT }, diff --git a/src/html/html_script_element.c b/src/html/html_script_element.c index d20d727..9acbf29 100644 --- a/src/html/html_script_element.c +++ b/src/html/html_script_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_SCRIPT_ELEMENT }, @@ -60,6 +60,8 @@ dom_exception _dom_html_script_element_initialise( struct dom_html_element_create_params *params, struct dom_html_script_element *ele) { + ele->flags = DOM_HTML_SCRIPT_ELEMENT_FLAG_NON_BLOCKING; + return _dom_html_element_initialise(params, &ele->base); } @@ -273,3 +275,40 @@ dom_exception dom_html_script_element_set_text( { return _dom_node_set_text_content((dom_node_internal *)ele, text); } + +/** + * Read the internal node flags + * + * \param ele The dom_html_script_element object + * \param flags Where to fill out the flags + * \return DOM_NO_ERR on success + */ +dom_exception dom_html_script_element_get_flags( + dom_html_script_element *ele, + dom_html_script_element_flags *flags) +{ + assert(flags != NULL); + assert(ele != NULL); + + *flags = ele->flags; + + return DOM_NO_ERR; +} + +/** + * Set the internal node flags + * + * \param ele The dom_html_script_element object + * \param flags The flags to retain + * \return DOM_NO_ERR on success + */ +dom_exception dom_html_script_element_set_flags( + dom_html_script_element *ele, + dom_html_script_element_flags flags) +{ + assert(ele != NULL); + + ele->flags = flags; + + return DOM_NO_ERR; +} diff --git a/src/html/html_script_element.h b/src/html/html_script_element.h index 9b1d704..1b34f6a 100644 --- a/src/html/html_script_element.h +++ b/src/html/html_script_element.h @@ -16,6 +16,7 @@ struct dom_html_script_element { struct dom_html_element base; /**< The base class */ + dom_html_script_element_flags flags; }; /* Create a dom_html_script_element object */ diff --git a/src/html/html_select_element.c b/src/html/html_select_element.c index ff549b2..8ba78f1 100644 --- a/src/html/html_select_element.c +++ b/src/html/html_select_element.c @@ -17,7 +17,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_SELECT_ELEMENT }, @@ -213,6 +213,9 @@ dom_exception dom_html_select_element_get_selected_index( dom_html_options_collection *col; err = _dom_html_select_element_make_collection(ele, &col); + if (err != DOM_NO_ERR) { + return err; + } err = dom_html_options_collection_get_length(col, &len); if (err != DOM_NO_ERR) { @@ -266,6 +269,9 @@ dom_exception dom_html_select_element_set_selected_index( dom_html_options_collection *col; err = _dom_html_select_element_make_collection(ele, &col); + if (err != DOM_NO_ERR) { + return err; + } err = dom_html_options_collection_item(col, index, &option); diff --git a/src/html/html_style_element.c b/src/html/html_style_element.c index ae845be..4e4974f 100644 --- a/src/html/html_style_element.c +++ b/src/html/html_style_element.c @@ -13,7 +13,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_STYLE_ELEMENT }, diff --git a/src/html/html_table_element.c b/src/html/html_table_element.c index 7e8a508..010a6cd 100644 --- a/src/html/html_table_element.c +++ b/src/html/html_table_element.c @@ -21,7 +21,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TABLE_ELEMENT }, @@ -726,6 +726,7 @@ static dom_exception dom_html_table_element_create_t_body( dom_html_collection_unref(t_bodies); return exp; } + /** * Insert a new Row into the table * @@ -736,7 +737,7 @@ static dom_exception dom_html_table_element_create_t_body( dom_exception dom_html_table_element_insert_row( dom_html_table_element *element, int32_t index, - dom_html_element **row) + dom_html_element **row_out) { dom_exception exp; dom_html_collection* rows; @@ -744,31 +745,13 @@ dom_exception dom_html_table_element_insert_row( dom_html_document *doc = (dom_html_document *) ((dom_node_internal *) element)->owner; - struct dom_html_element_create_params params = { - .type = DOM_HTML_ELEMENT_TYPE_TR, - .doc = doc, - .name = doc->elements[DOM_HTML_ELEMENT_TYPE_TR], - .namespace = ((dom_node_internal *)element)->namespace, - .prefix = ((dom_node_internal *)element)->prefix - }; - - exp = dom_html_table_element_get_rows(element, - &rows); + exp = dom_html_table_element_get_rows(element, &rows); if(exp != DOM_NO_ERR) { - dom_html_collection_unref(rows); return exp; } - exp = dom_html_collection_get_length(rows, - &len); - if(exp != DOM_NO_ERR) { - dom_html_collection_unref(rows); - return exp; - } - exp = _dom_html_table_row_element_create(¶ms, - (dom_html_table_row_element **)row); + exp = dom_html_collection_get_length(rows, &len); + dom_html_collection_unref(rows); if(exp != DOM_NO_ERR) { - dom_node_unref(*row); - dom_html_collection_unref(rows); return exp; } @@ -776,25 +759,40 @@ dom_exception dom_html_table_element_insert_row( exp = DOM_INDEX_SIZE_ERR; } else if(len == 0) { dom_html_table_section_element *new_body; + dom_html_table_row_element *row; dom_node *new_row; - exp = dom_html_table_element_create_t_body(element, - &new_body); + + struct dom_html_element_create_params params = { + .type = DOM_HTML_ELEMENT_TYPE_TR, + .doc = doc, + .name = doc->elements[DOM_HTML_ELEMENT_TYPE_TR], + .namespace = ((dom_node_internal *)element)->namespace, + .prefix = ((dom_node_internal *)element)->prefix + }; + + exp = _dom_html_table_row_element_create(¶ms, &row); if(exp != DOM_NO_ERR) { - dom_html_collection_unref(rows); - dom_node_unref(new_body); return exp; } - exp = dom_node_append_child(new_body, *row, + exp = dom_html_table_element_create_t_body(element, &new_body); + if(exp != DOM_NO_ERR) { + dom_node_unref(row); + return exp; + } + + exp = dom_node_append_child(new_body, (dom_html_element *) row, &new_row); + dom_node_unref(new_body); + dom_node_unref(row); if(exp == DOM_NO_ERR) { - dom_node_unref(*row); - *row = (dom_html_element *)new_row; + *row_out = (dom_html_element *)new_row; } } else { uint32_t window_len = 0, section_len; dom_html_table_section_element *t_head; dom_html_table_section_element *t_foot; + dom_html_element *row; dom_node_internal *n; if(index ==-1) { @@ -802,83 +800,106 @@ dom_exception dom_html_table_element_insert_row( } exp = dom_html_table_element_get_t_head(element, &t_head); - if (exp != DOM_NO_ERR) + if (exp != DOM_NO_ERR) { return exp; - - dom_html_collection_unref(rows); + } exp = dom_html_table_section_element_get_rows(t_head, &rows); if(exp != DOM_NO_ERR) { - dom_html_collection_unref(rows); + dom_node_unref(t_head); return exp; } - dom_html_collection_get_length(rows, §ion_len); + exp = dom_html_collection_get_length(rows, §ion_len); + dom_html_collection_unref(rows); if(exp != DOM_NO_ERR) { - dom_html_collection_unref(rows); + dom_node_unref(t_head); return exp; } if(window_len + section_len > (uint32_t)index || window_len + section_len == len) { - dom_html_collection_unref(rows); - return dom_html_table_section_element_insert_row(t_head, - index-window_len, row); + exp = dom_html_table_section_element_insert_row(t_head, + index-window_len, &row); + dom_node_unref(t_head); + if (exp == DOM_NO_ERR) { + *row_out = row; + } + return exp; } + dom_node_unref(t_head); window_len += section_len; n = (dom_node_internal *)element; - dom_html_collection_unref(rows); - for (n = n->first_child; n != NULL; n = n->next) { if((n->type == DOM_ELEMENT_NODE) && dom_string_caseless_isequal( doc->elements[DOM_HTML_ELEMENT_TYPE_TBODY], n->name)) { - exp = dom_html_table_section_element_get_rows((dom_html_table_section_element *)n, &rows); + exp = dom_html_table_section_element_get_rows( + (dom_html_table_section_element *)n, + &rows); + if (exp != DOM_NO_ERR) { + return exp; + } exp = dom_html_collection_get_length(rows, §ion_len); dom_html_collection_unref(rows); + if (exp != DOM_NO_ERR) { + return exp; + } if(window_len + section_len > (uint32_t)index || window_len + section_len == len) { - return dom_html_table_section_element_insert_row( + exp = dom_html_table_section_element_insert_row( (dom_html_table_section_element *)n, - index-window_len, row); + index-window_len, &row); + if (exp == DOM_NO_ERR) { + *row_out = row; + } + return exp; } window_len += section_len; } } exp = dom_html_table_element_get_t_foot(element, &t_foot); - if(exp != DOM_NO_ERR) + if(exp != DOM_NO_ERR) { return exp; + } exp = dom_html_table_section_element_get_rows(t_foot, &rows); if(exp != DOM_NO_ERR) { - dom_html_collection_unref(rows); + dom_node_unref(t_foot); return exp; } exp = dom_html_collection_get_length(rows, §ion_len); - dom_html_collection_unref(rows); - - if(exp != DOM_NO_ERR) + if(exp != DOM_NO_ERR) { + dom_node_unref(t_foot); return exp; + } if(window_len + section_len > (uint32_t)index || window_len +section_len == len) { - return dom_html_table_section_element_insert_row(t_foot, - index-window_len, row); + exp = dom_html_table_section_element_insert_row(t_foot, + index-window_len, &row); + dom_node_unref(t_foot); + if (exp == DOM_NO_ERR) { + *row_out = row; + } + return exp; } + dom_node_unref(t_foot); exp = DOM_INDEX_SIZE_ERR; } - dom_html_collection_unref(rows); + return exp; } + /** * Delete the table Head, if one exists * @@ -895,22 +916,17 @@ dom_exception dom_html_table_element_delete_row( dom_html_document *doc = (dom_html_document *) ((dom_node_internal *) element)->owner; - exp = dom_html_table_element_get_rows(element, - &rows); + exp = dom_html_table_element_get_rows(element, &rows); if(exp != DOM_NO_ERR) { - dom_html_collection_unref(rows); return exp; } - exp = dom_html_collection_get_length(rows, - &len); - + exp = dom_html_collection_get_length(rows, &len); + dom_html_collection_unref(rows); if(exp != DOM_NO_ERR) { - dom_html_collection_unref(rows); return exp; } if(index >= (int32_t)len || index < -1 || len ==0) { - dom_html_collection_unref(rows); return DOM_INDEX_SIZE_ERR; } else { uint32_t window_len = 0, section_len; @@ -922,28 +938,31 @@ dom_exception dom_html_table_element_delete_row( index = (int32_t)len-1; } - dom_html_collection_unref(rows); - exp = dom_html_table_element_get_t_head(element, &t_head); if(exp != DOM_NO_ERR) return exp; exp = dom_html_table_section_element_get_rows(t_head, &rows); if (exp != DOM_NO_ERR) { - dom_html_collection_unref(rows); + dom_node_unref(t_head); return DOM_NO_ERR; } exp = dom_html_collection_get_length(rows, §ion_len); - dom_html_collection_unref(rows); - if(exp != DOM_NO_ERR) + if(exp != DOM_NO_ERR) { + dom_node_unref(t_head); return exp; + } if(window_len + section_len > (uint32_t)index) { - return dom_html_table_section_element_delete_row(t_head, + exp = dom_html_table_section_element_delete_row(t_head, index-window_len); + dom_node_unref(t_head); + return exp; } + dom_node_unref(t_head); + window_len += section_len; n = (dom_node_internal *)element; @@ -952,10 +971,10 @@ dom_exception dom_html_table_element_delete_row( dom_string_caseless_isequal( doc->elements[DOM_HTML_ELEMENT_TYPE_TBODY], n->name)) { - exp = dom_html_table_section_element_get_rows - ((dom_html_table_section_element *)n, &rows); + exp = dom_html_table_section_element_get_rows( + (dom_html_table_section_element *)n, + &rows); if(exp != DOM_NO_ERR) { - dom_html_collection_unref(rows); return exp; } @@ -973,19 +992,26 @@ dom_exception dom_html_table_element_delete_row( } } exp = dom_html_table_element_get_t_foot(element, &t_foot); + if(exp != DOM_NO_ERR) + return exp; + exp = dom_html_table_section_element_get_rows(t_foot, &rows); if(exp != DOM_NO_ERR) { - dom_html_collection_unref(rows); + dom_node_unref(t_foot); return exp; } exp = dom_html_collection_get_length(rows, §ion_len); dom_html_collection_unref(rows); - if (exp != DOM_NO_ERR) + if (exp != DOM_NO_ERR) { + dom_node_unref(t_foot); return exp; + } if(window_len + section_len > (uint32_t)index) { - return dom_html_table_section_element_delete_row(t_foot, + exp = dom_html_table_section_element_delete_row(t_foot, index-window_len); + dom_node_unref(t_foot); + return exp; } return DOM_INDEX_SIZE_ERR; } diff --git a/src/html/html_tablecaption_element.c b/src/html/html_tablecaption_element.c index cae229c..0e55e3a 100644 --- a/src/html/html_tablecaption_element.c +++ b/src/html/html_tablecaption_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TABLE_CAPTION_ELEMENT }, diff --git a/src/html/html_tablecell_element.c b/src/html/html_tablecell_element.c index 7a1f968..2fc31c8 100644 --- a/src/html/html_tablecell_element.c +++ b/src/html/html_tablecell_element.c @@ -18,7 +18,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TABLE_CELL_ELEMENT }, diff --git a/src/html/html_tablecol_element.c b/src/html/html_tablecol_element.c index 74169be..56bcd64 100644 --- a/src/html/html_tablecol_element.c +++ b/src/html/html_tablecol_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TABLE_COL_ELEMENT }, diff --git a/src/html/html_tablerow_element.c b/src/html/html_tablerow_element.c index b722d0d..1a6069b 100644 --- a/src/html/html_tablerow_element.c +++ b/src/html/html_tablerow_element.c @@ -20,7 +20,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TABLE_ROW_ELEMENT }, @@ -244,18 +244,17 @@ dom_exception dom_html_table_row_element_get_row_index( return exp; } - exp = dom_html_table_section_element_get_rows(t_head, - &rows); - if (exp != DOM_NO_ERR) { + if (t_head != NULL) { + exp = dom_html_table_section_element_get_rows(t_head, &rows); dom_node_unref(t_head); - return exp; - } - - dom_html_collection_get_length(rows, - &len); - dom_html_collection_unref(rows); + if (exp != DOM_NO_ERR) { + return exp; + } - count += len; + dom_html_collection_get_length(rows, &len); + dom_html_collection_unref(rows); + count += len; + } for (n = n->first_child;n != parent && n != NULL; n = n->next) { @@ -356,7 +355,7 @@ dom_exception dom_html_table_row_element_insert_cell( int32_t index, dom_html_element **cell) { dom_html_document *doc = (dom_html_document *) ((dom_node_internal *) element)->owner; - dom_node *node; /*< The node at the (index)th position*/ + dom_html_element *new_cell; dom_html_collection *cells; /*< The collection of cells in input table_row_element*/ uint32_t len; /*< The size of the cell collection */ @@ -370,42 +369,45 @@ dom_exception dom_html_table_row_element_insert_cell( .prefix = ((dom_node_internal *)element)->prefix }; - exp = _dom_html_element_create(¶ms, cell); + exp = _dom_html_element_create(¶ms, &new_cell); if (exp != DOM_NO_ERR) return exp; exp = dom_html_table_row_element_get_cells(element, &cells); if (exp != DOM_NO_ERR) { - dom_node_unref(*cell); + dom_node_unref(new_cell); return exp; } exp = dom_html_collection_get_length(cells, &len); if (exp != DOM_NO_ERR) { - dom_node_unref(*cell); + dom_node_unref(new_cell); + dom_html_collection_unref(cells); return exp; } if (index < -1 || index > (int32_t)len) { /* Check for index validity */ + dom_node_unref(new_cell); dom_html_collection_unref (cells); return DOM_INDEX_SIZE_ERR; } else if (index == -1 || index == (int32_t)len) { - dom_node *new_cell; dom_html_collection_unref(cells); - return dom_node_append_child(element, - *cell, - &new_cell); + exp = dom_node_append_child(element, new_cell, cell); + dom_node_unref(new_cell); + } else { - dom_node *new_cell; - dom_html_collection_item(cells, - index, &node); + dom_node *node; + dom_html_collection_item(cells, index, &node); dom_html_collection_unref(cells); - return dom_node_insert_before(element, - *cell, node, &new_cell); + exp = dom_node_insert_before(element, new_cell, node, cell); + dom_node_unref(new_cell); + dom_node_unref(node); } + + return exp; } /** diff --git a/src/html/html_tablesection_element.c b/src/html/html_tablesection_element.c index 1ffe102..dee5ae5 100644 --- a/src/html/html_tablesection_element.c +++ b/src/html/html_tablesection_element.c @@ -21,7 +21,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TABLE_SECTION_ELEMENT }, @@ -229,14 +229,13 @@ dom_exception dom_html_table_section_element_get_rows( */ dom_exception dom_html_table_section_element_insert_row( dom_html_table_section_element *element, - int32_t index, dom_html_element **new_row) { + int32_t index, dom_html_element **new_row) +{ dom_html_document *doc = (dom_html_document *) ((dom_node_internal *) element)->owner; - - dom_node *node; /*< The node at the (index)th position*/ - dom_html_collection *rows; /*< The collection of rows in input table_section_element*/ uint32_t len; /*< The size of the row collection */ dom_exception exp; /*< Variable for getting the exceptions*/ + dom_node *new_node; struct dom_html_element_create_params params = { .type = DOM_HTML_ELEMENT_TYPE_TR, @@ -247,48 +246,45 @@ dom_exception dom_html_table_section_element_insert_row( }; exp = _dom_html_table_row_element_create(¶ms, - (dom_html_table_row_element **)new_row); + (dom_html_table_row_element **)(void *) &new_node); if(exp != DOM_NO_ERR) return exp; exp = dom_html_table_section_element_get_rows(element, &rows); if(exp != DOM_NO_ERR) { - dom_node_unref(new_row); - new_row = NULL; + dom_node_unref(new_node); return exp; } exp = dom_html_collection_get_length(rows, &len); - - - if(exp != DOM_NO_ERR) { - dom_node_unref(new_row); - new_row = NULL; + if (exp != DOM_NO_ERR) { + dom_node_unref(new_node); dom_html_collection_unref(rows); return exp; } - if(index < -1 || index > (int32_t)len) { + if (index < -1 || index > (int32_t)len) { /* Check for index validity */ dom_html_collection_unref(rows); + dom_node_unref(new_node); return DOM_INDEX_SIZE_ERR; - } else if(index == -1 || index == (int32_t)len) { - dom_node *new_node; + + } else if (index == -1 || index == (int32_t)len) { dom_html_collection_unref(rows); - return dom_node_append_child(element, - *new_row, - &new_node); + exp = dom_node_append_child(element, new_node, new_row); } else { - dom_node *new_node; - - dom_html_collection_item(rows, - index, &node); + dom_node *node; + dom_html_collection_item(rows, index, &node); dom_html_collection_unref(rows); - return dom_node_insert_before(element, - *new_row, node, - &new_node); + exp = dom_node_insert_before(element, + new_node, node, new_row); + dom_node_unref(node); } + + dom_node_unref(new_node); + + return exp; } /** diff --git a/src/html/html_text_area_element.c b/src/html/html_text_area_element.c index 6117e83..db351bc 100644 --- a/src/html/html_text_area_element.c +++ b/src/html/html_text_area_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TEXT_AREA_ELEMENT }, @@ -273,7 +273,7 @@ dom_exception dom_html_text_area_element_set_value( if (ele->value != NULL) dom_string_ref(ele->value); - return DOM_NO_ERR; + return dom_node_set_text_content((dom_node *)ele, ele->value); } /*------------------------------------------------------------------------*/ diff --git a/src/html/html_title_element.c b/src/html/html_title_element.c index 39e898a..f727dfa 100644 --- a/src/html/html_title_element.c +++ b/src/html/html_title_element.c @@ -17,7 +17,7 @@ #include "core/node.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_TITLE_ELEMENT }, @@ -157,15 +157,7 @@ dom_exception _dom_html_title_element_copy_internal( dom_exception dom_html_title_element_get_text(dom_html_title_element *ele, dom_string **text) { - dom_node_internal *node = (dom_node_internal *) ele; - dom_node_internal *n = node->first_child; - - /* There should be only one child of title element */ - assert(node->first_child == node->last_child); - /* And it should be a text node */ - assert(n->type == DOM_TEXT_NODE); - - return dom_characterdata_get_data(n, text); + return dom_node_get_text_content(ele, text); } /** @@ -178,14 +170,6 @@ dom_exception dom_html_title_element_get_text(dom_html_title_element *ele, dom_exception dom_html_title_element_set_text(dom_html_title_element *ele, dom_string *text) { - dom_node_internal *node = (dom_node_internal *) ele; - dom_node_internal *n = node->first_child; - - /* There should be only one child of title element */ - assert(node->first_child == node->last_child); - /* And it should be a text node */ - assert(n->type == DOM_TEXT_NODE); - - return dom_characterdata_set_data(n, text); + return dom_node_set_text_content(ele, text); } diff --git a/src/html/html_ulist_element.c b/src/html/html_ulist_element.c index f2b87fb..48cb0c2 100644 --- a/src/html/html_ulist_element.c +++ b/src/html/html_ulist_element.c @@ -17,7 +17,7 @@ #include "core/attr.h" #include "utils/utils.h" -static struct dom_element_protected_vtable _protect_vtable = { +static const struct dom_element_protected_vtable _protect_vtable = { { DOM_NODE_PROTECT_VTABLE_HTML_U_LIST_ELEMENT }, diff --git a/src/utils/Makefile b/src/utils/Makefile index 4bb586f..f891b6e 100644 --- a/src/utils/Makefile +++ b/src/utils/Makefile @@ -1,4 +1,4 @@ # Sources -DIR_SOURCES := namespace.c hashtable.c character_valid.c validate.c +DIR_SOURCES := namespace.c hashtable.c character_valid.c validate.c walk.c include $(NSBUILD)/Makefile.subdir diff --git a/src/utils/namespace.c b/src/utils/namespace.c index c18e24b..e2d249f 100644 --- a/src/utils/namespace.c +++ b/src/utils/namespace.c @@ -77,13 +77,12 @@ static dom_exception _dom_namespace_initialise(void) return DOM_NO_ERR; } -#ifdef FINALISE_NAMESPACE /** * Finalise the namespace component * * \return DOM_NO_ERR on success. */ -dom_exception _dom_namespace_finalise(void) +dom_exception dom_namespace_finalise(void) { int i; @@ -106,7 +105,6 @@ dom_exception _dom_namespace_finalise(void) return DOM_NO_ERR; } -#endif /** * Ensure a QName is valid diff --git a/src/utils/walk.c b/src/utils/walk.c new file mode 100644 index 0000000..f103908 --- /dev/null +++ b/src/utils/walk.c @@ -0,0 +1,130 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2021 Michael Drake <tlsa@netsurf-browser.org> + */ + +/** \file + * This is an API for walking a loaded DOM. + */ + +#include <dom/dom.h> +#include <dom/walk.h> + +/** + * Wrapper for calling client callback. + * + * \param[in] mask Mask of stages to enable callback for. + * \param[in] stage Whether the \ref node is being entered or left. + * \param[in] node The node being walked. + * \param[in] cb The client callback function. + * \param[in] pw The client's private data. + * \param[out] cmd_out Walk instruction from client. + * \return false for early termination of walk, true otherwise. + */ +static inline dom_exception dom_walk__cb( + enum dom_walk_enable mask, + enum dom_walk_stage stage, + dom_node *node, + dom_walk_cb cb, + void *pw, + enum dom_walk_cmd *cmd_out) +{ + if ((1 << stage) & mask) { + dom_node_type type; + dom_exception exc; + + exc = dom_node_get_node_type(node, &type); + if (exc != DOM_NO_ERR) { + return exc; + } + + *cmd_out = cb(stage, type, node, pw); + } + + return DOM_NO_ERR; +} + +/* exported interface documented in include/dom/walk.h */ +dom_exception libdom_treewalk( + enum dom_walk_enable mask, + dom_walk_cb cb, + dom_node *root, + void *pw) +{ + dom_node *node; + dom_exception exc; + enum dom_walk_cmd cmd = DOM_WALK_CMD_CONTINUE; + + node = dom_node_ref(root); + + while (cmd != DOM_WALK_CMD_ABORT) { + dom_node *next = NULL; + + if (cmd != DOM_WALK_CMD_SKIP) { + exc = dom_node_get_first_child(node, &next); + if (exc != DOM_NO_ERR) { + dom_node_unref(node); + break; + } + } + + if (next != NULL) { + dom_node_unref(node); + node = next; + } else { + /* No children; siblings & ancestor's siblings */ + while (node != root) { + exc = dom_walk__cb(mask, DOM_WALK_STAGE_LEAVE, + node, cb, pw, &cmd); + if (exc != DOM_NO_ERR || + cmd == DOM_WALK_CMD_ABORT) { + dom_node_unref(node); + return exc; + } + + exc = dom_node_get_next_sibling(node, &next); + if (exc != DOM_NO_ERR) { + dom_node_unref(node); + node = NULL; + break; + } + + if (next != NULL) { + /* Found next sibling. */ + break; + } + + exc = dom_node_get_parent_node(node, &next); + if (exc != DOM_NO_ERR) { + dom_node_unref(node); + return exc; + } + + dom_node_unref(node); + node = next; + } + + if (node == root) { + break; + } + + dom_node_unref(node); + node = next; + } + + assert(node != NULL); + assert(node != root); + + exc = dom_walk__cb(mask, DOM_WALK_STAGE_ENTER, node, + cb, pw, &cmd); + if (exc != DOM_NO_ERR) { + return exc; + } + } + + dom_node_unref(node); + + return DOM_NO_ERR; +} diff --git a/test/DOMTSHandler.pm b/test/DOMTSHandler.pm index 09b657e..7c68cd4 100644 --- a/test/DOMTSHandler.pm +++ b/test/DOMTSHandler.pm @@ -85,8 +85,9 @@ our %unref_prefix = ( DOMString => "dom_string", NamedNodeMap => "dom_namednodemap", NodeList => "dom_nodelist", - HTMLCollection => "dom_html_collection", - HTMLDocument => "dom_html_document", + HTMLCollection => "dom_html_collection", + HTMLOptionsCollection => "dom_html_options_collection", + HTMLDocument => "dom_html_document", ); our %special_method = ( @@ -179,6 +180,7 @@ sub new { # The list for UNREF unref => [], string_unref => [], + block_unrefs => ["!!!"], # The indent of current statement indent => "", # The variables for List/Collection @@ -1250,7 +1252,9 @@ sub generate_control_statement { } case "for-each" { - # Detect what is the collection type, if it is "string", we + # Push a block onto the cleanups + push(@{$self->{"block_unrefs"}}, "b"); + # Detect what is the collection type, if it is "string", we # should also do some conversion work my $coll = $ats->{"collection"}; # The default member type is dom_node @@ -1306,6 +1310,8 @@ sub generate_control_statement { print "unsigned int iterator$iterator_index = 0;"; print "foreach_initialise_domnodelist($coll, \&iterator$iterator_index);\n"; print "while(get_next_domnodelist($coll, \&iterator$iterator_index, \&$member)) {\n"; + $self->addto_cleanup($member); + push(@{$self->{'block_unrefs'}}, $member); } if ($self->{"var"}->{$coll} eq "NamedNodeMap") { @@ -1313,6 +1319,8 @@ sub generate_control_statement { print "unsigned int iterator$iterator_index = 0;"; print "foreach_initialise_domnamednodemap($coll, \&iterator$iterator_index);\n"; print "while(get_next_domnamednodemap($coll, \&iterator$iterator_index, \&$member)) {\n"; + $self->addto_cleanup($member); + push(@{$self->{'block_unrefs'}}, $member); } if ($self->{"var"}->{$coll} eq "HTMLCollection") { @@ -1320,6 +1328,8 @@ sub generate_control_statement { print "unsigned int iterator$iterator_index = 0;"; print "foreach_initialise_domhtmlcollection($coll, \&iterator$iterator_index);\n"; print "while(get_next_domhtmlcollection($coll, \&iterator$iterator_index, \&$member)) {\n"; + $self->addto_cleanup($member); + push(@{$self->{'block_unrefs'}}, $member); } } } @@ -1338,12 +1348,20 @@ sub complete_control_statement { case [qw(if while for-each)] { # Firstly, we should cleanup the dom_string in this block $self->cleanup_block_domstring(); - + $self->pop_block_unrefs() if ($name eq 'for-each'); print "}\n"; } } } +sub pop_block_unrefs { + my ($self) = @_; + while ((my $var = pop(@{$self->{'block_unrefs'}})) ne 'b') { + die "OMG!" if ($var eq '!!!'); + print("if ($var != NULL) {\n dom_node_unref($var);\n $var = NULL;\n}\n"); + } +} + ############################################################################### # @@ -1560,6 +1578,12 @@ sub end_half_assertion { ### Enclose an unsed function ############################################################################################## +sub cleanup_lists { + my ($self, $indent) = @_; + foreach my $list (keys %{$self->{list_map}}) { + print "${indent}if ($list != NULL)\n${indent}\tlist_destroy($list);\n" if ($list ne ''); + } +} sub cleanup_domvar { my ($self, $indent) = @_; @@ -1579,6 +1603,7 @@ sub cleanup { my $self = shift; print "\n\n"; + $self->cleanup_lists("\t"); $self->cleanup_domstring("\t"); $self->cleanup_domvar("\t"); print "\n\tprintf(\"PASS\");\n"; @@ -1595,7 +1620,7 @@ sub addto_cleanup { if (exists $unref_prefix{$type}) { $prefix = $unref_prefix{$type}; } - push(@{$self->{unref}}, $prefix."_unref(".$var.");\n"); + push(@{$self->{unref}}, "if (".$var." != NULL) { ".$prefix."_unref(".$var."); ".$var." = NULL; }\n"); } } diff --git a/test/testutils/foreach.c b/test/testutils/foreach.c index 05d7f2a..533958f 100644 --- a/test/testutils/foreach.c +++ b/test/testutils/foreach.c @@ -44,6 +44,7 @@ bool _get_next_domnodelist(dom_nodelist *list, unsigned int *iterator, dom_node { dom_exception err; uint32_t len; + dom_node *old = *ret; err = dom_nodelist_get_length(list, &len); if (err != DOM_NO_ERR) @@ -56,6 +57,12 @@ bool _get_next_domnodelist(dom_nodelist *list, unsigned int *iterator, dom_node if (err != DOM_NO_ERR) return false; + /* NOTE: If we change the API of dom_nodelist_item to release the ref + * then we should remove this + */ + if (old != NULL) + dom_node_unref(old); + (*iterator)++; return true; } @@ -86,6 +93,7 @@ bool _get_next_domnamednodemap(dom_namednodemap *map, unsigned int *iterator, do { dom_exception err; uint32_t len; + dom_node *old = *ret; err = dom_namednodemap_get_length(map, &len); if (err != DOM_NO_ERR) @@ -97,7 +105,10 @@ bool _get_next_domnamednodemap(dom_namednodemap *map, unsigned int *iterator, do err = dom_namednodemap_item(map, (*iterator), ret); if (err != DOM_NO_ERR) return false; - + + if (old != NULL) + dom_node_unref(old); + (*iterator)++; return true; diff --git a/test/testutils/list.c b/test/testutils/list.c index 09a8cfc..fa43c61 100644 --- a/test/testutils/list.c +++ b/test/testutils/list.c @@ -100,6 +100,10 @@ bool list_remove(struct list* list, void* data) } else { prevElt->next = nextElt; } + if (list->type == DOM_STRING) + dom_string_unref((dom_string *) elt->data); + if (list->type == NODE) + dom_node_unref(elt->data); free(elt); list->size--; found = true; @@ -164,7 +168,7 @@ bool list_contains_all(struct list* superList, struct list* subList, subElt = subElt->next; } - free(superListClone); + list_destroy(superListClone); return found; } diff --git a/test/testutils/load.c b/test/testutils/load.c index eba4cb0..ea68fcf 100644 --- a/test/testutils/load.c +++ b/test/testutils/load.c @@ -101,7 +101,7 @@ dom_document *load_html(const char *file, bool willBeModified) int handle; int readed; dom_hubbub_error error; - dom_document *ret; + dom_document *ret = NULL; uint8_t buffer[1024]; dom_hubbub_parser_params params; @@ -118,6 +118,8 @@ dom_document *load_html(const char *file, bool willBeModified) error = dom_hubbub_parser_create(¶ms, &parser, &ret); if (error != DOM_HUBBUB_OK) { fprintf(stderr, "Can't create Hubbub Parser\n"); + if (ret != NULL) + dom_node_unref(ret); return NULL; } @@ -125,6 +127,8 @@ dom_document *load_html(const char *file, bool willBeModified) if (handle == -1) { dom_hubbub_parser_destroy(parser); /* fprintf(stderr, "Can't open test input file: %s\n", file); */ + if (ret != NULL) + dom_node_unref(ret); return NULL; } @@ -133,6 +137,8 @@ dom_document *load_html(const char *file, bool willBeModified) if (error != DOM_HUBBUB_OK) { dom_hubbub_parser_destroy(parser); fprintf(stderr, "Parsing errors occur\n"); + if (ret != NULL) + dom_node_unref(ret); return NULL; } @@ -142,6 +148,8 @@ dom_document *load_html(const char *file, bool willBeModified) if (error != DOM_HUBBUB_OK) { dom_hubbub_parser_destroy(parser); fprintf(stderr, "Parsing errors occur\n"); + if (ret != NULL) + dom_node_unref(ret); return NULL; } } @@ -150,6 +158,8 @@ dom_document *load_html(const char *file, bool willBeModified) if (error != DOM_HUBBUB_OK) { dom_hubbub_parser_destroy(parser); fprintf(stderr, "Parsing error when construct DOM\n"); + if (ret != NULL) + dom_node_unref(ret); return NULL; } diff --git a/test/testutils/utils.c b/test/testutils/utils.c index c876613..379b0ad 100644 --- a/test/testutils/utils.c +++ b/test/testutils/utils.c @@ -27,7 +27,7 @@ void mymsg(uint32_t severity, void *ctx, const char *msg, ...) va_start(l, msg); - fprintf(stderr, "%d: ", severity); + fprintf(stderr, "%"PRIu32": ", severity); vfprintf(stderr, msg, l); fprintf(stderr, "\n"); } |