webengine/device/src/DeviceLiwIterable.cpp
changeset 0 dd21522fd290
child 10 a359256acfc6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/device/src/DeviceLiwIterable.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,347 @@
+/*
+* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Implementation of LIW Iterable wrapper
+*
+*/
+
+
+// INCLUDE FILES
+#include <config.h>
+#include <lookup.h>
+#include <LiwServiceHandler.h>
+#include "DeviceLiwIterable.h"
+#include "DeviceLiwBinding.h"
+
+const TInt KMaxKeySize = 128;
+
+using namespace KJS;
+
+const ClassInfo DeviceLiwIterable::info = { "DeviceLiwIterable", 0, 0, 0 };
+const TInt INIT_JSOBJ_ARRAY_SIZE = 10;   // initial jsobject array
+// ============================= LOCAL FUNCTIONS ===============================
+/*
+@begin DeviceLiwIterableTable 1
+    getNext DeviceLiwIterable::getNext DontDelete|Function 0
+    reset   DeviceLiwIterable::reset   DontDelete|Function 0
+    close   DeviceLiwIterable::close   DontDelete|Function 0
+@end
+*/
+
+/*
+ * The DeviceLiwIterable is a plain wrapper around the underlying LIW iterable variant
+ * object. It acts as a pass through for the iterable methods to JS. This
+ * is needed for efficiently processing returned iterables (instead of copying the
+ * contents into a JS array). Of course much of the benefit depends on how well iterables
+ * are implemented in the underlying LIW framework.
+ */
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+
+// ----------------------------------------------------------------------------
+// DeviceLiwIterable::DeviceLiwIterable
+//
+// ----------------------------------------------------------------------------
+//
+DeviceLiwIterable::DeviceLiwIterable(
+    ExecState* exec,
+    CDeviceLiwBinding* binding,
+    CLiwIterable* variant)
+    : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype() )
+    {
+        m_privateData = new DeviceLiwIterablePrivate(variant, binding);
+        if (!m_privateData || !m_privateData->m_jsobjArray )
+            m_valid = false;
+        else 
+            {
+            m_valid = true;
+            KJS::Collector::protect(this);            
+            }            
+    }
+
+// ----------------------------------------------------------------------------
+// DeviceLiwIterable::~DeviceLiwIterable
+//
+// ----------------------------------------------------------------------------
+//
+DeviceLiwIterable::~DeviceLiwIterable()
+    {
+        // only can be called by garbage collection after the 
+        // DeviceLiwIterable::Close() was called
+    }
+
+// ----------------------------------------------------------------------------
+// DeviceLiwIterable::Close()
+//
+// ----------------------------------------------------------------------------
+//
+void DeviceLiwIterable::Close(ExecState* exec, bool unmark)
+    {
+    // avoid double close    
+    if(!m_valid) 
+        {   
+        if(unmark) 
+            {
+            // unprotect this to allow the garbage collection to release this jsobject
+            KJS::Collector::unprotect(this);
+            }
+        return;
+        }
+    
+    // need exec to close other jsobject
+    m_privateData->m_exec = exec;
+    delete m_privateData;
+    m_privateData = NULL;
+    m_valid = false;
+    
+    if(unmark) 
+        {
+        // unprotect this to allow the garbage collection to release this jsobject
+        KJS::Collector::unprotect(this);
+        }
+    }     
+
+// ----------------------------------------------------------------------------
+// DeviceLiwIterable::toString
+// Returns string representation of the object
+//
+// ----------------------------------------------------------------------------
+UString DeviceLiwIterable::toString(ExecState* /*exec*/) const
+    {
+    return "[object DeviceLiwIterable]";
+    }
+
+// ----------------------------------------------------------------------------
+// Device::getOwnPropertySlot
+//
+// ----------------------------------------------------------------------------
+
+bool DeviceLiwIterable::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+    {
+    // When the DeviceLiwIterable is valid, the check order is
+    //      DeviceLiwIterable table => own property => prototype property
+    // When the DeviceLiwIterable is invalid (after close), the check order is
+    //      close function in table => prototype property
+
+    // 1. when it is valid
+    if(m_valid) 
+        {
+        // 1.1 check DeviceLiwIterable table    
+        const HashEntry* entry = Lookup::findEntry(&DeviceLiwIterableTable, propertyName);
+        if (entry)
+            {
+            slot.setStaticEntry(this, entry, staticValueGetter<DeviceLiwIterable>);
+            return true;
+            }
+
+        // 1.2 check own property
+        if(JSObject::getOwnPropertySlot(exec, propertyName, slot))
+            return true;
+        
+        // 1.3 check prototypes
+        JSObject *proto = static_cast<JSObject *>(this->prototype());
+        while (!proto->isNull() && proto->isObject())
+            {
+            if (proto->getOwnPropertySlot(exec, propertyName, slot))
+                return true;
+
+            proto = static_cast<JSObject *>(proto->prototype());
+            }
+        }
+    // 2. when it is invalid
+    else
+        {
+        // 2.1 check close() function
+        if (propertyName == "close")
+            {
+            const HashEntry* entry = Lookup::findEntry(&DeviceLiwIterableTable, propertyName);
+            if (entry)
+                {
+                slot.setStaticEntry(this, entry, staticValueGetter<DeviceLiwIterable>);
+                return true;
+                }      
+            }
+
+        // 2.2 check prototypes
+        JSObject *proto = static_cast<JSObject *>(this->prototype());
+        while (!proto->isNull() && proto->isObject())
+            {
+            if (proto->getOwnPropertySlot(exec, propertyName, slot))
+                return true;
+
+            proto = static_cast<JSObject *>(proto->prototype());
+            }
+        }
+
+    return false;
+    }
+
+// ----------------------------------------------------------------------------
+// JSVersion::getValueProperty
+//
+// ----------------------------------------------------------------------------
+JSValue* DeviceLiwIterable::getValueProperty(ExecState *exec, int token) const
+    {
+    DeviceLiwIterableFunc *lf;
+    switch (token)
+            {
+            // Unfortunately, the only operations that LIW Iterables support are next() and reset(). e.g. there
+            // are no hasNext() or count() operations typical for iterators.
+            case getNext:
+            case reset:
+            case close:
+                {
+                lf = new DeviceLiwIterableFunc(exec, token);
+                break;
+                }
+
+            default:
+                return throwError(exec, GeneralError);
+            }
+            return lf;
+    }
+    
+// ---------------------------------------------------------------------------
+// DeviceLiwIterablePrivate constructor
+//
+// ---------------------------------------------------------------------------
+DeviceLiwIterablePrivate::DeviceLiwIterablePrivate(const CLiwIterable* liwIterable, CDeviceLiwBinding* liwBinding)
+    {
+    TRAP_IGNORE(
+            m_liwBinding = liwBinding;
+            m_jsobjArray = new RPointerArray<JSObject>( INIT_JSOBJ_ARRAY_SIZE );
+            m_exec = NULL;    
+            m_iterable = (CLiwIterable*) liwIterable;
+            if ( m_iterable )
+                m_iterable->IncRef();
+            )
+    }
+    
+// ---------------------------------------------------------------------------
+// DeviceLiwMapPrivate::Close
+//
+// ---------------------------------------------------------------------------
+void DeviceLiwIterablePrivate::Close()
+    {
+    // close the jsobject
+    if ( m_jsobjArray && m_exec )
+        {
+        // close all the DeviceLiwMap objects and DeviceLiwIterable objects
+        for (int i = 0; i < m_jsobjArray->Count(); i++)
+            {
+            JSObject * jsobj = (*m_jsobjArray)[i];
+            if (jsobj->inherits( &DeviceLiwIterable::info ))
+                {
+                (static_cast<DeviceLiwIterable*>(jsobj))->Close(m_exec, true);
+                }
+            else if (jsobj->inherits( &DeviceLiwMap::info ))
+                {
+                (static_cast<DeviceLiwMap*>(jsobj))->Close(m_exec, true);
+                }
+            }
+        m_jsobjArray->Close();
+        delete m_jsobjArray;
+        m_jsobjArray = NULL;
+        m_exec = NULL;
+        }
+    
+    // release the map    
+    if ( m_iterable ) 
+        {
+        m_iterable->DecRef();
+        m_iterable = NULL;
+        }        
+    }
+    
+// ----------------------------------------------------------------------------
+// DeviceLiwIterablePrivate::DeviceLiwIterableFunc
+//
+// ----------------------------------------------------------------------------
+//
+DeviceLiwIterableFunc::DeviceLiwIterableFunc( ExecState* exec, int token )
+    : JSObject( exec->lexicalInterpreter()->builtinObjectPrototype() ),
+    m_func( token )
+    {
+    }
+
+// ----------------------------------------------------------------------------
+// DeviceLiwIterableFunc::~DeviceLiwIterableFunc
+//
+// ----------------------------------------------------------------------------
+//
+DeviceLiwIterableFunc::~DeviceLiwIterableFunc()
+    {
+    }
+
+// ----------------------------------------------------------------------------
+// DeviceLiwIterableFunc::implementsCall
+//
+// ----------------------------------------------------------------------------
+//
+bool DeviceLiwIterableFunc::implementsCall() const
+    {
+    return true;
+    }
+
+// ----------------------------------------------------------------------------
+// DeviceLiwIterableFunc::callAsFunction
+//
+// ----------------------------------------------------------------------------
+//
+JSValue* DeviceLiwIterableFunc::callAsFunction(ExecState* exec, JSObject *thisObj, const List& aArgs )
+    {
+        JSValue* rval = jsUndefined();
+        TBool found = EFalse;
+
+        if (!thisObj->inherits(&DeviceLiwIterable::info)) {
+                    return throwError(exec, GeneralError);
+        }
+
+        DeviceLiwIterable *it = static_cast<DeviceLiwIterable *>(thisObj);
+        
+        if ( !it->isValid() || !it->m_privateData->m_liwBinding || !it->m_privateData->m_iterable) {
+            return rval;
+        }
+
+        if ( m_func == DeviceLiwIterable::getNext ) {
+            TLiwVariant vv;
+            TRAP_IGNORE( found = it->m_privateData->m_iterable->NextL( vv ) );
+            if( found ) 
+                {
+                rval =  it->m_privateData->m_liwBinding->LiwVariant2JsVal( exec, vv );
+                if(rval->isObject()) 
+                    {
+                    JSObject* obj =  static_cast<JSObject*> (rval);
+                    if(obj->inherits( &KJS::DeviceLiwIterable::info ) || obj->inherits( &KJS::DeviceLiwMap::info ))
+                        {
+                        // insert into jsobject array
+                        it->m_privateData->m_jsobjArray->Append(obj);
+                        }
+                    }                
+                
+                vv.Reset();
+                }
+        }
+        else if ( m_func == DeviceLiwIterable::reset ){
+            it->m_privateData->m_iterable->Reset();
+        }
+        else if ( m_func == DeviceLiwIterable::close ){
+            it->Close(exec, false);
+        }
+        return rval;
+    }
+//END OF FILE
+
+
+