1 # Copyright (C) 2008 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
2 # Copyright (C) 2008 Martin Soto <soto@freedesktop.org>
3 # Copyright (C) 2008 Alp Toker <alp@atoker.com>
4 # Copyright (C) 2009 Adam Dingle <adam@yorba.org>
5 # Copyright (C) 2009 Jim Nelson <jim@yorba.org>
6 # Copyright (C) 2009, 2010 Igalia S.L.
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Library General Public
10 # License as published by the Free Software Foundation; either
11 # version 2 of the License, or (at your option) any later version.
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # Library General Public License for more details.
18 # You should have received a copy of the GNU Library General Public License
19 # along with this library; see the file COPYING.LIB. If not, write to
20 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 # Boston, MA 02111-1307, USA.
23 package CodeGeneratorGObject;
26 my %implIncludes = ();
29 my $defineTypeMacro = "G_DEFINE_TYPE";
30 my $defineTypeInterfaceImplementation = ")";
31 my @txtEventListeners = ();
32 my @txtInstallEventListeners = ();
33 my @txtInstallSignals = ();
34 my @txtInstallProps = ();
45 $codeGenerator = shift;
49 bless($reference, $object);
55 my $licenceTemplate = << "EOF";
57 This file is part of the WebKit open source project.
58 This file has been generated by generate-bindings.pl. DO NOT MODIFY!
60 This library is free software; you can redistribute it and/or
61 modify it under the terms of the GNU Library General Public
62 License as published by the Free Software Foundation; either
63 version 2 of the License, or (at your option) any later version.
65 This library is distributed in the hope that it will be useful,
66 but WITHOUT ANY WARRANTY; without even the implied warranty of
67 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
68 Library General Public License for more details.
70 You should have received a copy of the GNU Library General Public License
71 along with this library; see the file COPYING.LIB. If not, write to
72 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
73 Boston, MA 02110-1301, USA.
80 sub GetParentClassName {
83 return "WebKitDOMObject" if @{$dataNode->parents} eq 0;
84 return "WebKitDOM" . $codeGenerator->StripModule($dataNode->parents(0));
87 # From String::CamelCase 0.01
91 join('', map{ ucfirst $_ } split(/(?<=[A-Za-z])_(?=[A-Za-z])|\b/, $s));
97 $s =~ s{([^a-zA-Z]?)([A-Z]*)([A-Z])([a-z]?)}{
99 my ($p0,$p1,$p2,$p3) = ($1,lc$2,lc$3,$4);
100 my $t = $p0 || $fc ? $p0 : '_';
101 $t .= $p3 ? $p1 ? "${p1}_$p2$p3" : "$p2$p3" : "$p1$p2";
107 sub FixUpDecamelizedName {
108 my $classname = shift;
110 # FIXME: try to merge this somehow with the fixes in ClassNameToGobjectType
111 $classname =~ s/x_path/xpath/;
112 $classname =~ s/web_kit/webkit/;
113 $classname =~ s/htmli_frame/html_iframe/;
118 sub ClassNameToGObjectType {
119 my $className = shift;
120 my $CLASS_NAME = uc(decamelize($className));
121 # Fixup: with our prefix being 'WebKitDOM' decamelize can't get
122 # WebKitDOMCSS and similar names right, so we have to fix it
124 $CLASS_NAME =~ s/DOMCSS/DOM_CSS/;
125 $CLASS_NAME =~ s/DOMHTML/DOM_HTML/;
126 $CLASS_NAME =~ s/DOMDOM/DOM_DOM/;
127 $CLASS_NAME =~ s/DOMCDATA/DOM_CDATA/;
128 $CLASS_NAME =~ s/DOMX_PATH/DOM_XPATH/;
129 $CLASS_NAME =~ s/DOM_WEB_KIT/DOM_WEBKIT/;
130 $CLASS_NAME =~ s/DOMUI/DOM_UI/;
131 $CLASS_NAME =~ s/HTMLI_FRAME/HTML_IFRAME/;
135 sub GetParentGObjType {
136 my $dataNode = shift;
138 return "WEBKIT_TYPE_DOM_OBJECT" if @{$dataNode->parents} eq 0;
139 return "WEBKIT_TYPE_DOM_" . ClassNameToGObjectType($codeGenerator->StripModule($dataNode->parents(0)));
143 my $name = $codeGenerator->StripModule(shift);
145 return "WebKitDOM$name";
149 my ($interfaceName, $name, $parameter) = @_;
151 return "WebCore::${interfaceName}* $name = WebKit::core($parameter);";
155 my $attribute = shift;
157 if ($attribute->signature->extendedAttributes->{"CustomGetter"} ||
158 $attribute->signature->extendedAttributes->{"CustomSetter"} ||
159 $attribute->signature->extendedAttributes->{"Replaceable"}) {
163 my $propType = $attribute->signature->type;
164 if ($propType =~ /Constructor$/) {
168 # This is for DOMWindow.idl location attribute
169 if ($attribute->signature->name eq "location") {
173 # This is for HTMLInput.idl valueAsDate
174 if ($attribute->signature->name eq "valueAsDate") {
178 # This is for DOMWindow.idl Crypto attribute
179 if ($attribute->signature->type eq "Crypto") {
187 my $function = shift;
188 my $decamelize = shift;
191 my $functionName = "webkit_dom_" . $decamelize . "_" . $prefix . decamelize($function->signature->name);
192 my $isCustomFunction = $function->signature->extendedAttributes->{"Custom"} ||
193 $function->signature->extendedAttributes->{"CustomArgumentHandling"};
195 if ($isCustomFunction &&
196 $functionName ne "webkit_dom_node_replace_child" &&
197 $functionName ne "webkit_dom_node_insert_before" &&
198 $functionName ne "webkit_dom_node_remove_child" &&
199 $functionName ne "webkit_dom_node_append_child" &&
200 $functionName ne "webkit_dom_html_collection_item" &&
201 $functionName ne "webkit_dom_html_collection_named_item") {
205 if ($function->signature->name eq "getSVGDocument") {
209 if ($function->signature->name eq "getCSSCanvasContext") {
213 # Skip functions that have ["Callback"] parameters, because this
214 # code generator doesn't know how to auto-generate callbacks.
215 # Skip functions that have "MediaQueryListListener" parameters, because this
216 # code generator doesn't know how to auto-generate MediaQueryListListener.
217 foreach my $param (@{$function->parameters}) {
218 if ($param->extendedAttributes->{"Callback"} ||
219 $param->type eq "MediaQueryListListener") {
227 # Name type used in the g_value_{set,get}_* functions
228 sub GetGValueTypeName {
231 my %types = ("DOMString", "string",
232 "DOMTimeStamp", "uint",
235 "boolean", "boolean",
238 "long long", "int64",
243 "unsigned int", "uint",
244 "unsigned long long", "uint64",
245 "unsigned long", "ulong",
246 "unsigned short", "ushort");
248 return $types{$type} ? $types{$type} : "object";
251 # Name type used in C declarations
252 sub GetGlibTypeName {
254 my $name = GetClassName($type);
256 my %types = ("DOMString", "gchar*",
257 "DOMTimeStamp", "guint32",
258 "CompareHow", "gushort",
261 "boolean", "gboolean",
264 "long long", "gint64",
269 "unsigned int", "guint",
270 "unsigned long", "gulong",
271 "unsigned long long", "guint64",
272 "unsigned short", "gushort",
275 return $types{$type} ? $types{$type} : "$name*";
278 sub IsGDOMClassType {
281 return 0 if $codeGenerator->IsNonPointerType($type) || $codeGenerator->IsStringType($type);
285 sub GetReadableProperties {
286 my $properties = shift;
290 foreach my $property (@{$properties}) {
291 if (!SkipAttribute($property)) {
292 push(@result, $property);
299 sub GetWriteableProperties {
300 my $properties = shift;
303 foreach my $property (@{$properties}) {
304 my $writeable = $property->type !~ /^readonly/;
305 my $gtype = GetGValueTypeName($property->signature->type);
306 my $hasGtypeSignature = ($gtype eq "boolean" || $gtype eq "float" || $gtype eq "double" ||
307 $gtype eq "uint64" || $gtype eq "ulong" || $gtype eq "long" ||
308 $gtype eq "uint" || $gtype eq "ushort" || $gtype eq "uchar" ||
309 $gtype eq "char" || $gtype eq "string");
310 if ($writeable && $hasGtypeSignature) {
311 push(@result, $property);
318 sub GenerateConditionalString
321 my $conditional = $node->extendedAttributes->{"Conditional"};
323 if ($conditional =~ /&/) {
324 return "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
325 } elsif ($conditional =~ /\|/) {
326 return "ENABLE(" . join(") || ENABLE(", split(/\|/, $conditional)) . ")";
328 return "ENABLE(" . $conditional . ")";
335 sub GenerateProperty {
336 my $attribute = shift;
337 my $interfaceName = shift;
338 my @writeableProperties = @{shift @_};
340 my $conditionalString = GenerateConditionalString($attribute->signature);
341 my $camelPropName = $attribute->signature->name;
342 my $setPropNameFunction = $codeGenerator->WK_ucfirst($camelPropName);
343 my $getPropNameFunction = $codeGenerator->WK_lcfirst($camelPropName);
345 my $propName = decamelize($camelPropName);
346 my $propNameCaps = uc($propName);
347 $propName =~ s/_/-/g;
348 my ${propEnum} = "PROP_${propNameCaps}";
349 push(@cBodyPriv, "#if ${conditionalString}\n") if $conditionalString;
350 push(@cBodyPriv, " ${propEnum},\n");
351 push(@cBodyPriv, "#endif /* ${conditionalString} */\n") if $conditionalString;
353 my $propType = $attribute->signature->type;
354 my ${propGType} = decamelize($propType);
355 my ${ucPropGType} = uc($propGType);
357 my $gtype = GetGValueTypeName($propType);
358 my $gparamflag = "WEBKIT_PARAM_READABLE";
359 my $writeable = $attribute->type !~ /^readonly/;
360 my $const = "read-only ";
361 my $custom = $attribute->signature->extendedAttributes->{"Custom"};
362 if ($writeable && $custom) {
363 $const = "read-only (due to custom functions needed in webkitdom)";
366 if ($writeable && !$custom) {
367 $gparamflag = "WEBKIT_PARAM_READWRITE";
368 $const = "read-write ";
371 my $type = GetGlibTypeName($propType);
372 $nick = decamelize("${interfaceName}_${propName}");
373 $long = "${const} ${type} ${interfaceName}.${propName}";
375 my $convertFunction = "";
376 if ($gtype eq "string") {
377 $convertFunction = "WTF::String::fromUTF8";
380 my $getterExpressionPrefix = $codeGenerator->GetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute);
381 my $setterExpressionPrefix = $codeGenerator->SetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute);
383 my $getterContentHead = "coreSelf->$getterExpressionPrefix";
384 my $setterContentHead = "coreSelf->$setterExpressionPrefix${convertFunction}(g_value_get_$gtype(value))";
386 if (grep {$_ eq $attribute} @writeableProperties) {
387 push(@txtSetProps, "#if ${conditionalString}\n") if $conditionalString;
388 push(@txtSetProps, " case ${propEnum}:\n {\n");
389 push(@txtSetProps, " WebCore::ExceptionCode ec = 0;\n") if @{$attribute->setterExceptions};
390 push(@txtSetProps, " ${setterContentHead}");
391 push(@txtSetProps, ", ec") if @{$attribute->setterExceptions};
392 push(@txtSetProps, ");\n");
393 push(@txtSetProps, " break;\n }\n");
394 push(@txtSetProps, "#endif /* ${conditionalString} */\n") if $conditionalString;
397 push(@txtGetProps, "#if ${conditionalString}\n") if $conditionalString;
398 push(@txtGetProps, " case ${propEnum}:\n {\n");
401 if (@{$attribute->getterExceptions}) {
403 push(@txtGetProps, " WebCore::ExceptionCode ec = 0;\n");
406 my $postConvertFunction = "";
408 if ($gtype eq "string") {
409 push(@txtGetProps, " g_value_take_string(value, convertToUTF8String(${getterContentHead}${exception})));\n");
411 } elsif ($gtype eq "object") {
412 $txtGetProp = << "EOF";
413 RefPtr<WebCore::${propType}> ptr = coreSelf->${getPropNameFunction}(${exception});
414 g_value_set_object(value, WebKit::kit(ptr.get()));
416 push(@txtGetProps, $txtGetProp);
420 # FIXME: get rid of this glitch?
422 if ($gtype eq "ushort") {
427 push(@txtGetProps, " g_value_set_$_gtype(value, ${convertFunction}coreSelf->${getterExpressionPrefix}${exception})${postConvertFunction});\n");
430 push(@txtGetProps, " break;\n }\n");
431 push(@txtGetProps, "#endif /* ${conditionalString} */\n") if $conditionalString;
433 my %param_spec_options = ("int", "G_MININT, /* min */\nG_MAXINT, /* max */\n0, /* default */",
434 "boolean", "FALSE, /* default */",
435 "float", "-G_MAXFLOAT, /* min */\nG_MAXFLOAT, /* max */\n0.0, /* default */",
436 "double", "-G_MAXDOUBLE, /* min */\nG_MAXDOUBLE, /* max */\n0.0, /* default */",
437 "uint64", "0, /* min */\nG_MAXUINT64, /* min */\n0, /* default */",
438 "long", "G_MINLONG, /* min */\nG_MAXLONG, /* max */\n0, /* default */",
439 "int64", "G_MININT64, /* min */\nG_MAXINT64, /* max */\n0, /* default */",
440 "ulong", "0, /* min */\nG_MAXULONG, /* max */\n0, /* default */",
441 "uint", "0, /* min */\nG_MAXUINT, /* max */\n0, /* default */",
442 "ushort", "0, /* min */\nG_MAXUINT16, /* max */\n0, /* default */",
443 "uchar", "G_MININT8, /* min */\nG_MAXINT8, /* max */\n0, /* default */",
444 "char", "0, /* min */\nG_MAXUINT8, /* max */\n0, /* default */",
445 "string", "\"\", /* default */",
446 "object", "WEBKIT_TYPE_DOM_${ucPropGType}, /* gobject type */");
448 my $txtInstallProp = << "EOF";
449 g_object_class_install_property(gobjectClass,
451 g_param_spec_${_gtype}("${propName}", /* name */
452 "$nick", /* short description */
453 "$long", /* longer - could do with some extra doc stuff here */
454 $param_spec_options{$gtype}
457 push(@txtInstallProps, "#if ${conditionalString}\n") if $conditionalString;
458 push(@txtInstallProps, $txtInstallProp);
459 push(@txtInstallProps, "#endif /* ${conditionalString} */\n") if $conditionalString;
462 sub GenerateProperties {
463 my ($object, $interfaceName, $dataNode) = @_;
465 my $clsCaps = substr(ClassNameToGObjectType($className), 12);
466 my $lowerCaseIfaceName = "webkit_dom_" . (FixUpDecamelizedName(decamelize($interfaceName)));
469 my $implContent = "";
472 $implContent = << "EOF";
476 push(@cBodyPriv, $implContent);
478 my @readableProperties = GetReadableProperties($dataNode->attributes);
480 my $privFunction = GetCoreObject($interfaceName, "coreSelf", "self");
482 my $txtGetProp = << "EOF";
483 static void ${lowerCaseIfaceName}_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec)
485 WebCore::JSMainThreadNullState state;
487 push(@txtGetProps, $txtGetProp);
488 if (scalar @readableProperties > 0) {
489 $txtGetProp = << "EOF";
490 ${className}* self = WEBKIT_DOM_${clsCaps}(object);
493 push(@txtGetProps, $txtGetProp);
496 $txtGetProp = << "EOF";
499 push(@txtGetProps, $txtGetProp);
501 my @writeableProperties = GetWriteableProperties(\@readableProperties);
503 my $txtSetProps = << "EOF";
504 static void ${lowerCaseIfaceName}_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec)
506 WebCore::JSMainThreadNullState state;
508 push(@txtSetProps, $txtSetProps);
510 if (scalar @writeableProperties > 0) {
511 $txtSetProps = << "EOF";
512 ${className}* self = WEBKIT_DOM_${clsCaps}(object);
515 push(@txtSetProps, $txtSetProps);
518 $txtSetProps = << "EOF";
521 push(@txtSetProps, $txtSetProps);
523 foreach my $attribute (@readableProperties) {
524 if ($attribute->signature->type ne "EventListener" &&
525 $attribute->signature->type ne "MediaQueryListListener") {
526 GenerateProperty($attribute, $interfaceName, \@writeableProperties);
530 push(@cBodyPriv, "};\n\n");
532 $txtGetProp = << "EOF";
534 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
539 push(@txtGetProps, $txtGetProp);
541 $txtSetProps = << "EOF";
543 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
548 push(@txtSetProps, $txtSetProps);
550 # Do not insert extra spaces when interpolating array variables
553 $implContent = << "EOF";
555 static void ${lowerCaseIfaceName}_finalize(GObject* object)
557 WebKitDOMObject* dom_object = WEBKIT_DOM_OBJECT(object);
559 if (dom_object->coreObject) {
560 WebCore::${interfaceName}* coreObject = static_cast<WebCore::${interfaceName} *>(dom_object->coreObject);
562 WebKit::DOMObjectCache::forget(coreObject);
565 dom_object->coreObject = NULL;
568 G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->finalize(object);
575 static void ${lowerCaseIfaceName}_constructed(GObject* object)
578 push(@cBodyPriv, $implContent);
580 $implContent = << "EOF";
581 @txtInstallEventListeners
582 if (G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->constructed)
583 G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->constructed(object);
586 static void ${lowerCaseIfaceName}_class_init(${className}Class* requestClass)
588 GObjectClass *gobjectClass = G_OBJECT_CLASS(requestClass);
589 gobjectClass->finalize = ${lowerCaseIfaceName}_finalize;
590 gobjectClass->set_property = ${lowerCaseIfaceName}_set_property;
591 gobjectClass->get_property = ${lowerCaseIfaceName}_get_property;
592 gobjectClass->constructed = ${lowerCaseIfaceName}_constructed;
598 static void ${lowerCaseIfaceName}_init(${className}* request)
603 push(@cBodyPriv, $implContent);
607 my ($object, $interfaceName, $parentClassName) = @_;
609 my $implContent = "";
611 # Add the default header template
612 @hPrefix = split("\r", $licenceTemplate);
613 push(@hPrefix, "\n");
616 my $guard = $className . "_h";
618 @hPrefixGuard = << "EOF";
624 $implContent = << "EOF";
628 push(@hBodyPre, $implContent);
630 my $decamelize = FixUpDecamelizedName(decamelize($interfaceName));
631 my $clsCaps = uc($decamelize);
632 my $lowerCaseIfaceName = "webkit_dom_" . ($decamelize);
634 $implContent = << "EOF";
635 #define WEBKIT_TYPE_DOM_${clsCaps} (${lowerCaseIfaceName}_get_type())
636 #define WEBKIT_DOM_${clsCaps}(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_DOM_${clsCaps}, ${className}))
637 #define WEBKIT_DOM_${clsCaps}_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_DOM_${clsCaps}, ${className}Class)
638 #define WEBKIT_DOM_IS_${clsCaps}(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_DOM_${clsCaps}))
639 #define WEBKIT_DOM_IS_${clsCaps}_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_DOM_${clsCaps}))
640 #define WEBKIT_DOM_${clsCaps}_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_DOM_${clsCaps}, ${className}Class))
642 struct _${className} {
643 ${parentClassName} parent_instance;
646 struct _${className}Class {
647 ${parentClassName}Class parent_class;
651 ${lowerCaseIfaceName}_get_type (void);
655 push(@hBody, $implContent);
658 sub getIncludeHeader {
660 my $name = GetClassName($type);
662 return "" if $type eq "int";
663 return "" if $type eq "long";
664 return "" if $type eq "long long";
665 return "" if $type eq "short";
666 return "" if $type eq "char";
667 return "" if $type eq "float";
668 return "" if $type eq "double";
669 return "" if $type eq "unsigned";
670 return "" if $type eq "unsigned int";
671 return "" if $type eq "unsigned long";
672 return "" if $type eq "unsigned long long";
673 return "" if $type eq "unsigned short";
674 return "" if $type eq "DOMTimeStamp";
675 return "" if $type eq "EventListener";
676 return "" if $type eq "MediaQueryListListener";
677 return "" if $type eq "unsigned char";
678 return "" if $type eq "DOMString";
679 return "" if $type eq "float";
680 return "" if $type eq "boolean";
681 return "" if $type eq "void";
682 return "" if $type eq "CompareHow";
687 sub addIncludeInBody {
690 if ($type eq "DOMObject") {
694 my $header = getIncludeHeader($type);
699 if (IsGDOMClassType($type)) {
700 $implIncludes{"webkit/$header"} = 1;
702 $implIncludes{$header} = 1
706 sub GenerateFunction {
707 my ($object, $interfaceName, $function, $prefix) = @_;
709 my $decamelize = FixUpDecamelizedName(decamelize($interfaceName));
711 if ($object eq "MediaQueryListListener") {
715 if (SkipFunction($function, $decamelize, $prefix)) {
719 my $functionSigName = $function->signature->name;
720 my $functionSigType = $prefix eq "set_" ? "void" : $function->signature->type;
721 my $functionName = "webkit_dom_" . $decamelize . "_" . $prefix . decamelize($functionSigName);
722 my $returnType = GetGlibTypeName($functionSigType);
723 my $returnValueIsGDOMType = IsGDOMClassType($functionSigType);
724 my $conditionalString = GenerateConditionalString($function->signature);
726 my $functionSig = "${className}* self";
728 my $callImplParams = "";
730 # skip some custom functions for now
731 my $isCustomFunction = $function->signature->extendedAttributes->{"Custom"} ||
732 $function->signature->extendedAttributes->{"CustomArgumentHandling"};
734 foreach my $param (@{$function->parameters}) {
735 my $paramIDLType = $param->type;
736 if ($paramIDLType eq "EventListener" || $paramIDLType eq "MediaQueryListListener") {
737 # EventListeners are handled elsewhere.
740 addIncludeInBody($paramIDLType);
741 my $paramType = GetGlibTypeName($paramIDLType);
742 my $const = $paramType eq "gchar*" ? "const " : "";
743 my $paramName = decamelize($param->name);
745 $functionSig .= ", ${const}$paramType $paramName";
747 my $paramIsGDOMType = IsGDOMClassType($paramIDLType);
748 if ($paramIsGDOMType) {
749 if ($paramIDLType ne "DOMObject") {
750 $implIncludes{"webkit/WebKitDOM${paramIDLType}Private.h"} = 1;
753 if ($paramIsGDOMType || ($paramIDLType eq "DOMString") || ($paramIDLType eq "CompareHow")) {
754 $paramName = "converted_" . $paramName;
756 if ($callImplParams) {
757 $callImplParams .= ", $paramName";
759 $callImplParams = "$paramName";
763 # Not quite sure what to do with this yet, but we need to take into
764 # account the difference in parameters between the IDL file and the
765 # actual implementation.
766 if ($function->signature->extendedAttributes->{"NeedsUserGestureCheck"}) {
767 $functionSig .= ", gboolean isUserGesture";
768 $callImplParams .= ", " if $callImplParams;
769 $callImplParams .= "false";
772 if ($returnType ne "void" && $returnValueIsGDOMType && $functionSigType ne "DOMObject") {
773 if ($functionSigType ne "EventTarget") {
774 $implIncludes{"webkit/WebKitDOM${functionSigType}Private.h"} = 1;
775 $implIncludes{"webkit/WebKitDOM${functionSigType}.h"} = 1;
777 $implIncludes{"WebKitDOM${functionSigType}.h"} = 1;
780 $implIncludes{"${functionSigType}.h"} = 1;
783 if(@{$function->raisesExceptions}) {
784 $functionSig .= ", GError **error";
787 # Insert introspection annotations
788 push(@hBody, "/**\n");
789 push(@hBody, " * ${functionName}:\n");
790 push(@hBody, " * \@self: A #${className}\n");
792 foreach my $param (@{$function->parameters}) {
793 my $paramType = GetGlibTypeName($param->type);
794 # $paramType can have a trailing * in some cases
795 $paramType =~ s/\*$//;
796 my $paramName = decamelize($param->name);
797 push(@hBody, " * \@${paramName}: A #${paramType}\n");
799 if(@{$function->raisesExceptions}) {
800 push(@hBody, " * \@error: #GError\n");
802 push(@hBody, " *\n");
803 if (IsGDOMClassType($function->signature->type)) {
804 push(@hBody, " * Returns: (transfer none):\n");
806 push(@hBody, " * Returns:\n");
808 push(@hBody, " *\n");
809 push(@hBody, "**/\n");
811 push(@hBody, "WEBKIT_API $returnType\n$functionName($functionSig);\n");
814 push(@cBody, "$returnType\n$functionName($functionSig)\n{\n");
815 push(@cBody, "#if ${conditionalString}\n") if $conditionalString;
817 if ($returnType ne "void") {
818 # TODO: return proper default result
819 push(@cBody, " g_return_val_if_fail(self, 0);\n");
821 push(@cBody, " g_return_if_fail(self);\n");
824 push(@cBody, " WebCore::JSMainThreadNullState state;\n");
826 # The WebKit::core implementations check for NULL already; no need to
828 push(@cBody, " WebCore::${interfaceName} * item = WebKit::core(self);\n");
830 foreach my $param (@{$function->parameters}) {
831 my $paramName = decamelize($param->name);
832 my $paramIDLType = $param->type;
833 my $paramTypeIsPrimitive = $codeGenerator->IsPrimitiveType($paramIDLType);
834 my $paramIsGDOMType = IsGDOMClassType($paramIDLType);
835 if (!$paramTypeIsPrimitive) {
836 if ($returnType ne "void") {
837 # TODO: return proper default result
838 # FIXME: Temporary hack for generating a proper implementation
839 # of the webkit_dom_document_evaluate function (Bug-ID: 42115)
840 if (!(($functionName eq "webkit_dom_document_evaluate") && ($paramIDLType eq "XPathResult"))) {
841 push(@cBody, " g_return_val_if_fail($paramName, 0);\n");
844 push(@cBody, " g_return_if_fail($paramName);\n");
849 $returnParamName = "";
850 foreach my $param (@{$function->parameters}) {
851 my $paramIDLType = $param->type;
852 my $paramName = decamelize($param->name);
854 my $paramIsGDOMType = IsGDOMClassType($paramIDLType);
855 if ($paramIDLType eq "DOMString") {
856 push(@cBody, " WTF::String converted_${paramName} = WTF::String::fromUTF8($paramName);\n");
857 } elsif ($paramIDLType eq "CompareHow") {
858 push(@cBody, " WebCore::Range::CompareHow converted_${paramName} = static_cast<WebCore::Range::CompareHow>($paramName);\n");
859 } elsif ($paramIsGDOMType) {
860 push(@cBody, " WebCore::${paramIDLType} * converted_${paramName} = NULL;\n");
861 push(@cBody, " if (${paramName} != NULL) {\n");
862 push(@cBody, " converted_${paramName} = WebKit::core($paramName);\n");
864 if ($returnType ne "void") {
865 # TODO: return proper default result
866 push(@cBody, " g_return_val_if_fail(converted_${paramName}, 0);\n");
868 push(@cBody, " g_return_if_fail(converted_${paramName});\n");
871 push(@cBody, " }\n");
873 $returnParamName = "converted_".$paramName if $param->extendedAttributes->{"Return"};
880 # We need to special-case these Node methods because their C++
881 # signature is different from what we'd expect given their IDL
882 # description; see Node.h.
883 my $functionHasCustomReturn = $functionName eq "webkit_dom_node_append_child" ||
884 $functionName eq "webkit_dom_node_insert_before" ||
885 $functionName eq "webkit_dom_node_replace_child" ||
886 $functionName eq "webkit_dom_node_remove_child";
888 if ($returnType ne "void" && !$functionHasCustomReturn) {
889 if ($returnValueIsGDOMType) {
890 $assign = "PassRefPtr<WebCore::${functionSigType}> g_res = ";
891 $assignPre = "WTF::getPtr(";
894 $assign = "${returnType} res = ";
898 if (@{$function->raisesExceptions}) {
899 push(@cBody, " WebCore::ExceptionCode ec = 0;\n");
900 if (${callImplParams} ne "") {
901 $exceptions = ", ec";
907 if ($functionHasCustomReturn) {
908 my $customNodeAppendChild = << "EOF";
909 bool ok = item->${functionSigName}(${callImplParams}${exceptions});
912 ${returnType} res = WebKit::kit($returnParamName);
916 push(@cBody, $customNodeAppendChild);
918 if(@{$function->raisesExceptions}) {
919 my $exceptionHandling = << "EOF";
921 WebCore::ExceptionCodeDescription ecdesc;
922 WebCore::getExceptionCodeDescription(ec, ecdesc);
923 g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), ecdesc.code, ecdesc.name);
925 push(@cBody, $exceptionHandling);
927 push(@cBody, "return NULL;");
928 push(@cBody, "}\n\n");
930 } elsif ($functionSigType eq "DOMString") {
931 my $getterContentHead;
933 my $getterExpressionPrefix = $codeGenerator->GetterExpressionPrefix(\%implIncludes, $interfaceName, $function);
934 $getterContentHead = "${assign}convertToUTF8String(item->$getterExpressionPrefix${exceptions}));\n";
936 $getterContentHead = "${assign}convertToUTF8String(item->${functionSigName}(${callImplParams}${exceptions}));\n";
938 push(@cBody, " ${getterContentHead}");
941 if ($prefix eq "get_") {
942 my $getterExpressionPrefix = $codeGenerator->GetterExpressionPrefix(\%implIncludes, $interfaceName, $function);
943 $contentHead = "${assign}${assignPre}item->$getterExpressionPrefix${callImplParams}${exceptions}${assignPost});\n";
944 } elsif ($prefix eq "set_") {
945 my $setterExpressionPrefix = $codeGenerator->SetterExpressionPrefix(\%implIncludes, $interfaceName, $function);
946 $contentHead = "${assign}${assignPre}item->$setterExpressionPrefix${callImplParams}${exceptions}${assignPost});\n";
948 $contentHead = "${assign}${assignPre}item->${functionSigName}(${callImplParams}${exceptions}${assignPost});\n";
950 push(@cBody, " ${contentHead}");
952 if(@{$function->raisesExceptions}) {
953 my $exceptionHandling = << "EOF";
955 WebCore::ExceptionCodeDescription ecdesc;
956 WebCore::getExceptionCodeDescription(ec, ecdesc);
957 g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), ecdesc.code, ecdesc.name);
960 push(@cBody, $exceptionHandling);
964 if ($returnType ne "void" && !$functionHasCustomReturn) {
965 if ($functionSigType ne "DOMObject") {
966 if ($returnValueIsGDOMType) {
967 push(@cBody, " ${returnType} res = WebKit::kit(g_res.get());\n");
970 if ($functionSigType eq "DOMObject") {
971 push(@cBody, " return NULL; /* TODO: return canvas object */\n");
973 push(@cBody, " return res;\n");
977 if ($conditionalString) {
978 if ($returnType ne "void") {
979 push(@cBody, "#else\n");
980 if ($codeGenerator->IsNonPointerType($functionSigType)) {
981 push(@cBody, " return static_cast<${returnType}>(0);\n");
983 push(@cBody, " return NULL;\n");
986 push(@cBody, "#endif /* ${conditionalString} */\n") if $conditionalString;
989 push(@cBody, "}\n\n");
992 sub ClassHasFunction {
993 my ($class, $name) = @_;
995 foreach my $function (@{$class->functions}) {
996 if ($function->signature->name eq $name) {
1004 sub GenerateFunctions {
1005 my ($object, $interfaceName, $dataNode) = @_;
1007 foreach my $function (@{$dataNode->functions}) {
1008 $object->GenerateFunction($interfaceName, $function, "");
1012 foreach my $attribute (@{$dataNode->attributes}) {
1013 if (SkipAttribute($attribute) ||
1014 $attribute->signature->type eq "EventListener" ||
1015 $attribute->signature->type eq "MediaQueryListListener") {
1019 if ($attribute->signature->name eq "type"
1020 # This will conflict with the get_type() function we define to return a GType
1021 # according to GObject conventions. Skip this for now.
1022 || $attribute->signature->name eq "URL" # TODO: handle this
1027 my $attrNameUpper = $codeGenerator->WK_ucfirst($attribute->signature->name);
1028 my $getname = "get${attrNameUpper}";
1029 my $setname = "set${attrNameUpper}";
1030 if (ClassHasFunction($dataNode, $getname) || ClassHasFunction($dataNode, $setname)) {
1031 # Very occasionally an IDL file defines getter/setter functions for one of its
1032 # attributes; in this case we don't need to autogenerate the getter/setter.
1036 # Generate an attribute getter. For an attribute "foo", this is a function named
1037 # "get_foo" which calls a DOM class method named foo().
1038 my $function = new domFunction();
1039 $function->signature($attribute->signature);
1040 $function->raisesExceptions($attribute->getterExceptions);
1041 $object->GenerateFunction($interfaceName, $function, "get_");
1043 if ($attribute->type =~ /^readonly/) {
1047 # Generate an attribute setter. For an attribute, "foo", this is a function named
1048 # "set_foo" which calls a DOM class method named setFoo().
1049 $function = new domFunction();
1051 $function->signature(new domSignature());
1052 $function->signature->name($attribute->signature->name);
1053 $function->signature->type($attribute->signature->type);
1054 $function->signature->extendedAttributes($attribute->signature->extendedAttributes);
1056 my $param = new domSignature();
1057 $param->name("value");
1058 $param->type($attribute->signature->type);
1059 my %attributes = ();
1060 $param->extendedAttributes(attributes);
1061 my $arrayRef = $function->parameters;
1062 push(@$arrayRef, $param);
1064 $function->raisesExceptions($attribute->setterExceptions);
1066 $object->GenerateFunction($interfaceName, $function, "set_");
1071 my ($object, $interfaceName, $parentClassName, $parentGObjType, $dataNode) = @_;
1073 if ($dataNode->extendedAttributes->{"EventTarget"}) {
1074 $object->GenerateEventTargetIface($dataNode);
1077 my $implContent = "";
1079 my $clsCaps = uc(FixUpDecamelizedName(decamelize($interfaceName)));
1080 my $lowerCaseIfaceName = "webkit_dom_" . FixUpDecamelizedName(decamelize($interfaceName));
1082 $implContent = << "EOF";
1083 ${defineTypeMacro}(${className}, ${lowerCaseIfaceName}, ${parentGObjType}${defineTypeInterfaceImplementation}
1087 WebCore::${interfaceName}* core(${className}* request)
1089 g_return_val_if_fail(request, 0);
1091 WebCore::${interfaceName}* coreObject = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(request)->coreObject);
1092 g_return_val_if_fail(coreObject, 0);
1097 } // namespace WebKit
1100 push(@cBodyPriv, $implContent);
1101 $object->GenerateProperties($interfaceName, $dataNode);
1102 $object->GenerateFunctions($interfaceName, $dataNode);
1104 my $wrapMethod = << "EOF";
1106 ${className}* wrap${interfaceName}(WebCore::${interfaceName}* coreObject)
1108 g_return_val_if_fail(coreObject, 0);
1110 /* We call ref() rather than using a C++ smart pointer because we can't store a C++ object
1111 * in a C-allocated GObject structure. See the finalize() code for the
1116 return WEBKIT_DOM_${clsCaps}(g_object_new(WEBKIT_TYPE_DOM_${clsCaps},
1117 "core-object", coreObject, NULL));
1119 } // namespace WebKit
1121 push(@cBodyPriv, $wrapMethod);
1124 sub GenerateEndHeader {
1128 my $guard = $className . "_h";
1130 push(@hBody, "G_END_DECLS\n\n");
1131 push(@hPrefixGuardEnd, "#endif /* $guard */\n");
1134 sub GeneratePrivateHeader {
1136 my $dataNode = shift;
1138 my $interfaceName = $dataNode->name;
1139 my $filename = "$outputDir/" . $className . "Private.h";
1140 my $guard = uc(decamelize($className)) . "_PRIVATE_H";
1141 my $parentClassName = GetParentClassName($dataNode);
1142 my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
1143 my $hasRealParent = @{$dataNode->parents} > 0;
1144 my $hasParent = $hasLegacyParent || $hasRealParent;
1146 open(PRIVHEADER, ">$filename") or die "Couldn't open file $filename for writing";
1148 print PRIVHEADER split("\r", $licenceTemplate);
1149 print PRIVHEADER "\n";
1151 my $text = << "EOF";
1155 #include <glib-object.h>
1156 #include <webkit/${parentClassName}.h>
1157 #include "${interfaceName}.h"
1160 print PRIVHEADER $text;
1162 print PRIVHEADER map { "#include \"$_\"\n" } sort keys(%hdrPropIncludes);
1163 print PRIVHEADER "\n" if keys(%hdrPropIncludes);
1168 wrap${interfaceName}(WebCore::${interfaceName} *coreObject);
1170 WebCore::${interfaceName} *
1171 core(${className} *request);
1175 print PRIVHEADER $text;
1177 if ($className ne "WebKitDOMNode") {
1180 kit(WebCore::${interfaceName}* node);
1183 print PRIVHEADER $text;
1187 } // namespace WebKit
1189 #endif /* ${guard} */
1191 print PRIVHEADER $text;
1196 sub UsesManualKitImplementation {
1199 return 1 if $type eq "Node" or $type eq "Element" or $type eq "Event";
1203 sub GenerateEventTargetIface {
1205 my $dataNode = shift;
1207 my $interfaceName = $dataNode->name;
1208 my $decamelize = FixUpDecamelizedName(decamelize($interfaceName));
1210 $implIncludes{"GObjectEventListener.h"} = 1;
1211 $implIncludes{"WebKitDOMEventTarget.h"} = 1;
1212 $implIncludes{"WebKitDOMEventPrivate.h"} = 1;
1214 my $impl = << "EOF";
1215 static void webkit_dom_${decamelize}_dispatch_event(WebKitDOMEventTarget* target, WebKitDOMEvent* event, GError** error)
1217 WebCore::Event* coreEvent = WebKit::core(event);
1218 WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);
1220 WebCore::ExceptionCode ec = 0;
1221 coreTarget->dispatchEvent(coreEvent, ec);
1223 WebCore::ExceptionCodeDescription description;
1224 WebCore::getExceptionCodeDescription(ec, description);
1225 g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), description.code, description.name);
1229 static gboolean webkit_dom_${decamelize}_add_event_listener(WebKitDOMEventTarget* target, const char* eventName, GCallback handler, gboolean bubble, gpointer userData)
1231 WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);
1232 return WebCore::GObjectEventListener::addEventListener(G_OBJECT(target), coreTarget, eventName, handler, bubble, userData);
1235 static gboolean webkit_dom_${decamelize}_remove_event_listener(WebKitDOMEventTarget* target, const char* eventName, GCallback handler, gboolean bubble)
1237 WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);
1238 return WebCore::GObjectEventListener::removeEventListener(G_OBJECT(target), coreTarget, eventName, handler, bubble);
1241 static void webkit_dom_event_target_init(WebKitDOMEventTargetIface* iface)
1243 iface->dispatch_event = webkit_dom_${decamelize}_dispatch_event;
1244 iface->add_event_listener = webkit_dom_${decamelize}_add_event_listener;
1245 iface->remove_event_listener = webkit_dom_${decamelize}_remove_event_listener;
1250 push(@cBody, $impl);
1252 $defineTypeMacro = "G_DEFINE_TYPE_WITH_CODE";
1253 $defineTypeInterfaceImplementation = ", G_IMPLEMENT_INTERFACE(WEBKIT_TYPE_DOM_EVENT_TARGET, webkit_dom_event_target_init))";
1257 my ($object, $dataNode) = @_;
1259 my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
1260 my $hasRealParent = @{$dataNode->parents} > 0;
1261 my $hasParent = $hasLegacyParent || $hasRealParent;
1262 my $parentClassName = GetParentClassName($dataNode);
1263 my $parentGObjType = GetParentGObjType($dataNode);
1264 my $interfaceName = $dataNode->name;
1266 # Add the guard if the 'Conditional' extended attribute exists
1267 my $conditionalString = GenerateConditionalString($dataNode);
1268 push(@conditionGuardStart, "#if ${conditionalString}\n\n") if $conditionalString;
1269 push(@conditionGuardEnd, "#endif /* ${conditionalString} */\n") if $conditionalString;
1271 # Add the default impl header template
1272 @cPrefix = split("\r", $licenceTemplate);
1273 push(@cPrefix, "\n");
1275 $implIncludes{"webkitdefines.h"} = 1;
1276 $implIncludes{"webkitglobalsprivate.h"} = 1;
1277 $implIncludes{"webkitmarshal.h"} = 1;
1278 $implIncludes{"DOMObjectCache.h"} = 1;
1279 $implIncludes{"WebKitDOMBinding.h"} = 1;
1280 $implIncludes{"gobject/ConvertToUTF8String.h"} = 1;
1281 $implIncludes{"webkit/$className.h"} = 1;
1282 $implIncludes{"webkit/${className}Private.h"} = 1;
1283 $implIncludes{"${interfaceName}.h"} = 1;
1284 $implIncludes{"JSMainThreadExecState.h"} = 1;
1285 $implIncludes{"ExceptionCode.h"} = 1;
1287 $hdrIncludes{"webkit/${parentClassName}.h"} = 1;
1289 if (!UsesManualKitImplementation($interfaceName)) {
1290 my $converter = << "EOF";
1293 ${className}* kit(WebCore::$interfaceName* obj)
1295 g_return_val_if_fail(obj, 0);
1297 if (gpointer ret = DOMObjectCache::get(obj))
1298 return static_cast<${className}*>(ret);
1300 return static_cast<${className}*>(DOMObjectCache::put(obj, WebKit::wrap${interfaceName}(obj)));
1303 } // namespace WebKit //
1306 push(@cBody, $converter);
1309 $object->GenerateHeader($interfaceName, $parentClassName);
1310 $object->GenerateCFile($interfaceName, $parentClassName, $parentGObjType, $dataNode);
1311 $object->GenerateEndHeader();
1312 $object->GeneratePrivateHeader($dataNode);
1318 my ($object, $name) = @_;
1320 # Write public header.
1321 my $hdrFName = "$outputDir/" . $name . ".h";
1322 open(HEADER, ">$hdrFName") or die "Couldn't open file $hdrFName";
1324 print HEADER @hPrefix;
1325 print HEADER @hPrefixGuard;
1326 print HEADER "#include \"webkit/webkitdomdefines.h\"\n";
1327 print HEADER "#include <glib-object.h>\n";
1328 print HEADER "#include <webkit/webkitdefines.h>\n";
1329 print HEADER map { "#include \"$_\"\n" } sort keys(%hdrIncludes);
1330 print HEADER "\n" if keys(%hdrIncludes);
1332 print HEADER @hBodyPre;
1333 print HEADER @hBody;
1334 print HEADER @hPrefixGuardEnd;
1338 # Write the implementation sources
1339 my $implFileName = "$outputDir/" . $name . ".cpp";
1340 open(IMPL, ">$implFileName") or die "Couldn't open file $implFileName";
1342 print IMPL @cPrefix;
1343 print IMPL "#include <glib-object.h>\n";
1344 print IMPL "#include \"config.h\"\n\n";
1345 print IMPL @conditionGuardStart;
1346 print IMPL "#include <wtf/GetPtr.h>\n";
1347 print IMPL "#include <wtf/RefPtr.h>\n";
1348 print IMPL map { "#include \"$_\"\n" } sort keys(%implIncludes);
1349 print IMPL "\n" if keys(%implIncludes);
1353 print IMPL @cBodyPriv;
1354 print IMPL @conditionGuardEnd;
1368 sub GenerateInterface {
1369 my ($object, $dataNode, $defines) = @_;
1370 my $name = $dataNode->name;
1372 # Set up some global variables
1373 $className = GetClassName($dataNode->name);
1374 $object->Generate($dataNode);
1377 my $fname = "WebKitDOM_" . $name;
1379 $object->WriteData($fname);