summaryrefslogtreecommitdiffstats
path: root/ksvg/ecma/ksvg_lookup.h
blob: 11c414623567d246a942f85da3b4f701076ed374 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
/*
    Copyright (C) 2002-2003 KSVG Team
	This file is part of the KDE project

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#ifndef KSVG_LOOKUP_H
#define KSVG_LOOKUP_H

#include <kjs/object.h>
#include <kjs/lookup.h>
#include <kjs/interpreter.h> // for ExecState

#include "ksvg_bridge.h"
#include "ksvg_scriptinterpreter.h"

#define KSVG_GET_COMMON \
public: \
    \
    /* The standard hasProperty call, auto-generated. Looks in hashtable, forwards to parents. */ \
    bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
    \
    /* get() method, called by KSVGBridge::get */ \
    KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::ObjectImp* bridge) const; \
    \
    /* Called by lookupGet(). Auto-generated. Forwards to the parent which has the given property. */ \
    KJS::Value getInParents(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::ObjectImp* bridge) const; \
    \
    KJS::Object prototype(KJS::ExecState *exec) const;\
    \
    static const KJS::ClassInfo s_classInfo; \
    \
    static const struct KJS::HashTable s_hashTable; \
	\
	int m_attrFlags;

// For classes with properties to read, and a hashtable.
#define KSVG_GET \
    KSVG_GET_COMMON \
    KJS::Value cache(KJS::ExecState *exec) const;

// Same thing, for base classes (kalyptus helps finding them)
// The difference is that cache() is virtual
#define KSVG_BASECLASS_GET \
    KSVG_GET_COMMON \
    virtual KJS::Value cache(KJS::ExecState *exec) const;

// For classes without properties, but with a parent class to forward to
#define KSVG_FORWARDGET \
public: \
    \
    bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
    \
    /* will have the code for getInParents */ \
    KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::ObjectImp* bridge) const; \
    \
    KJS::Object prototype(KJS::ExecState *exec) const;\
    \
    static const KJS::ClassInfo s_classInfo; \
    \
    KJS::Value cache(KJS::ExecState *exec) const;

// For read-write classes only, i.e. those which support put()
#define KSVG_PUT \
    \
    /* put() method, called by KSVGBridge::put */ \
    bool put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr); \
	\
    /* Called by lookupPut. Auto-generated. Looks in hashtable, forwards to parents. */ \
    bool putInParents(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr);

// For classes which inherit a read-write class, but have no readwrite property themselves
#define KSVG_FORWARDPUT \
    \
    /* put() method, called by KSVGBridge::put */ \
    bool put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr);

// For classes which need to be accessable with getElementById -> elements
#define KSVG_NO_TAG_BRIDGE \
public: \
	KJS::ObjectImp *bridge(KJS::ExecState *) const { return 0; }

#define KSVG_BRIDGE \
public: \
	KJS::ObjectImp *bridge(KJS::ExecState *) const; \
	virtual DOM::DOMString tagName() const { return s_tagName; } \
	static const DOM::DOMString s_tagName;

// Fast setting of default values, if the token is known
// Note: this is actually misnamed it should be KSVG_SET_DEFAULT_ATTRIBUTE
#define KSVG_SET_ALT_ATTRIBUTE(Token, Name) putValueProperty(ownerDoc()->ecmaEngine()->globalExec(), Token, String(Name), Internal);

// Check if attribute has not been parsed, if the token is known
#define KSVG_TOKEN_NOT_PARSED_ELEMENT(Token, Element) (~Element->m_attrFlags & (1 << Token))
#define KSVG_TOKEN_NOT_PARSED(Token) KSVG_TOKEN_NOT_PARSED_ELEMENT(Token, this)

// Checks if the interpreter is in attribute "getting" mode
#define KSVG_CHECK_ATTRIBUTE bool attributeMode = static_cast<KSVGScriptInterpreter *>(exec->interpreter())->attributeGetMode();

// Sets the class specific flags to a ZERO value
#define KSVG_EMPTY_FLAGS m_attrFlags = 0;

// to be used in generatedata.cpp
// GET p1=exec, p2=propertyName, p3=bridge
// PUT p1=exec, p2=propertyName, p3=value, p4=attr
#define GET_METHOD_ARGS KJS::ExecState *p1, const KJS::Identifier &p2, const KJS::ObjectImp *p3
#define PUT_METHOD_ARGS KJS::ExecState *p1, const KJS::Identifier &p2, const KJS::Value &p3, int p4

namespace KSVG
{
	/**
	 * Helper method for property lookups
	 *
	 * This method does it all (looking in the hashtable, checking for function
	 * overrides, creating the function or retrieving from cache, calling
	 * getValueProperty in case of a non-function property, forwarding to parent[s] if
	 * unknown property).
	 *
	 * Template arguments:
	 * @param FuncImp the class which implements this object's functions
	 * @param ThisImp the class of "this". It must implement the getValueProperty(exec,token) method,
	 * for non-function properties, and the getInParents() method (auto-generated).
	 *
	 * Method arguments:
	 * @param exec execution state, as usual
	 * @param propertyName the property we're looking for
	 * @param table the static hashtable for this class
	 * @param thisObj "this"
	 */
	template<class FuncImp, class ThisImp>
	inline KJS::Value lookupGet(KJS::ExecState *exec,
								const KJS::Identifier &propertyName,
								const KJS::HashTable *table,
								const ThisImp *thisObj, // the 'impl' object
								const KJS::ObjectImp *bridge)
	{
		const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName);

		if(!entry) // not found, forward to parents
			return thisObj->getInParents(exec, propertyName, bridge);

		if(entry->attr & KJS::Function)
			return KJS::lookupOrCreateFunction<FuncImp>(exec, propertyName,
														const_cast<KJS::ObjectImp *>(bridge),
														entry->value, entry->params, entry->attr);

		return thisObj->getValueProperty(exec, entry->value);
    }

	/**
	 * Simplified version of lookupGet in case there are no functions, only "values".
	 * Using this instead of lookupGet removes the need for a FuncImp class.
	 */
	template <class ThisImp>
    inline KJS::Value lookupGetValue(KJS::ExecState *exec,
									 const KJS::Identifier &propertyName,
									 const KJS::HashTable *table,
									 const ThisImp *thisObj, // the 'impl' object
                                     const KJS::ObjectImp *bridge)
	{
		const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName);

		if(!entry) // not found, forward to parents
			return thisObj->getInParents(exec, propertyName, bridge);

		if(entry->attr & KJS::Function)
			kdError(26004) << "Function bit set! Shouldn't happen in lookupGetValue! propertyName was " << propertyName.qstring() << endl;

		return thisObj->getValueProperty(exec, entry->value);
	}

    /**
	 * This one is for "put".
	 * Lookup hash entry for property to be set, and set the value.
	 * The "this" class must implement putValueProperty.
	 * If it returns false, put() will return false, and KSVGRequest will set a dynamic property in ObjectImp
	 */
	template <class ThisImp>
	inline bool lookupPut(KJS::ExecState *exec,
						  const KJS::Identifier &propertyName,
						  const KJS::Value &value,
						  int attr,
						  const KJS::HashTable *table,
						  ThisImp *thisObj)
    {
		const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName);

		if(!entry) // not found, forward to parents
			return thisObj->putInParents(exec, propertyName, value, attr);
		else if(entry->attr & KJS::Function) // Function: put as override property
			return false;
		else if(entry->attr & KJS::ReadOnly && !(attr & KJS::Internal)) // readonly! Can't put!
		{
#ifdef KJS_VERBOSE
			kdWarning(26004) <<" Attempt to change value of readonly property '" << propertyName.qstring() << "'" << endl;
#endif
			return true; // "we did it" -> don't put override property
		}
		else
		{
			if(static_cast<KSVGScriptInterpreter *>(exec->interpreter())->attributeSetMode())
				thisObj->m_attrFlags |= (1 << entry->value);

			thisObj->putValueProperty(exec, entry->value, value, attr);
			return true;
		}
	}
}

// Same as kjs' DEFINE_PROTOTYPE, but with a pointer to the hashtable too, and no ClassName here
// The ClassProto ctor(exec) must be public, so we can use KJS::cacheGlobalObject... (Niko)
#define KSVG_DEFINE_PROTOTYPE(ClassProto) \
  namespace KSVG { \
  class ClassProto : public KJS::ObjectImp { \
  public: \
    static KJS::Object self(KJS::ExecState *exec); \
    ClassProto( KJS::ExecState *exec ) \
      : KJS::ObjectImp( exec->interpreter()->builtinObjectPrototype() ) {} \
    virtual const KJS::ClassInfo *classInfo() const { return &info; } \
    static const KJS::ClassInfo info; \
    KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
    bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
    \
    static const struct KJS::HashTable s_hashTable; \
  }; \
  }

// same as IMPLEMENT_PROTOTYPE but in the KSVG namespace, and with ClassName here
// so that KSVG_DEFINE_PROTOTYPE can be put in a header file ('info' defined here)
#define KSVG_IMPLEMENT_PROTOTYPE(ClassName,ClassProto,ClassFunc) \
    KJS::Value KSVG::ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
    { \
      return lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &s_hashTable, this ); \
    } \
    bool KSVG::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
    { /*stupid but we need this to have a common macro for the declaration*/ \
      return KJS::ObjectImp::hasProperty(exec, propertyName); \
    } \
    KJS::Object KSVG::ClassProto::self(KJS::ExecState *exec) \
    { \
      return KJS::cacheGlobalObject<ClassProto>( exec, "[[" ClassName ".prototype]]" ); \
    } \
    const KJS::ClassInfo ClassProto::info = { ClassName, 0, &s_hashTable, 0 }; \

// same as KSVG_IMPLEMENT_PROTOTYPE but with a parent class to forward calls to
// Not used within KSVG up to now - each class does a self proto lookup in generateddata.cpp
#define KSVG_IMPLEMENT_PROTOTYPE_WITH_PARENT(ClassName,ClassProto,ClassFunc,ParentProto) \
    KJS::Value KSVG::ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
    { \
      KJS::Value val = lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &s_hashTable, this ); \
      if ( val.type() != UndefinedType ) return val; \
      /* Not found -> forward request to "parent" prototype */ \
      return ParentProto::self(exec).get( exec, propertyName ); \
    } \
    bool KSVG::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
    { \
      if (KJS::ObjectImp::hasProperty(exec, propertyName)) \
        return true; \
      return ParentProto::self(exec).hasProperty(exec, propertyName); \
    } \
    KJS::Object KSVG::ClassProto::self(KJS::ExecState *exec) \
    { \
      return KJS::cacheGlobalObject<ClassProto>( exec, "[[" ClassName ".prototype]]" ); \
    } \
    const KJS::ClassInfo ClassProto::info = { ClassName, 0, &s_hashTable, 0 }; \

#define KSVG_IMPLEMENT_PROTOFUNC(ClassFunc,Class) \
  namespace KSVG { \
  class ClassFunc : public KJS::ObjectImp { \
  public: \
    ClassFunc(KJS::ExecState *exec, int i, int len) \
       : KJS::ObjectImp( /*proto? */ ), id(i) { \
       KJS::Value protect(this); \
       put(exec,"length",KJS::Number(len),KJS::DontDelete|KJS::ReadOnly|KJS::DontEnum); \
    } \
    /** Used by call() to check the type of thisObj. Generated code */ \
    Class * cast(const KJS::ObjectImp* bridge) const; \
    \
    virtual bool implementsCall() const { return true; } \
    /** You need to implement that one */ \
    virtual KJS::Value call(KJS::ExecState *exec, KJS::Object &thisObj, const KJS::List &args); \
  private: \
    int id; \
  }; \
  }

// To be used when casting the type of an argument
#define KSVG_CHECK(ClassName, theObj) \
    ClassName* obj = cast(static_cast<KJS::ObjectImp*>(theObj.imp())); \
    if (!obj) { \
        kdDebug(26004) << k_funcinfo << " Wrong object type: expected " << ClassName::s_classInfo.className << " got " << thisObj.classInfo()->className << endl; \
        Object err = Error::create(exec,TypeError);   \
        exec->setException(err);                      \
        return err;                                   \
    }

// To be used in all call() implementations!
// Can't use if (!thisObj.inherits(&ClassName::s_classInfo) since we don't
// use the (single-parent) inheritance of ClassInfo...
#define KSVG_CHECK_THIS(ClassName) KSVG_CHECK(ClassName, thisObj)

#endif

// vim:ts=4:noet