webengine/wmlengine/src/css/src/CSSPatternMatcher.cpp
author andysimpson
Tue, 21 Jul 2009 00:40:18 +0100
changeset 7 a4c17f4cd12c
parent 0 dd21522fd290
child 26 cb62a4f66ebe
permissions -rw-r--r--
create tag for PDK_2.0.d

/*
* Copyright (c) 2003 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:  Matches CSS Pattern
*
*/



// INCLUDE FILES
#include <e32def.h>  // First to avoid NULL redefine warning (no #ifndef NULL).

#include "CSSPatternMatcher.h"
#include "nw_dom_document.h"
#include "nw_evt_activateevent.h"
#include "nw_evt_focusevent.h"
#include <nwx_assert.h>
#include "nwx_string.h"

#include "nw_hed_contenthandler.h"
#include "nw_hed_documentroot.h"
#include "nw_hed_historyvisitor.h"
#include "nw_xhtml_xhtml_1_0_tokens.h"
#include "BrsrStatusCodes.h"
#include "MemoryManager.h"

// EXTERNAL DATA STRUCTURES

// EXTERNAL FUNCTION PROTOTYPES  

// CONSTANTS

// MACROS

// LOCAL CONSTANTS AND MACROS

// MODULE DATA STRUCTURES

// LOCAL FUNCTION PROTOTYPES

// FORWARD DECLARATIONS

// ============================= LOCAL FUNCTIONS ===============================


// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CCSSPatternMatcher::GetNextSimpleSelectorL
// This function gets the data associated with a simple selector (iterator method)
// -----------------------------------------------------------------------------
//
TBrowserStatusCode
CCSSPatternMatcher::GetNextSimpleSelectorL(TCSSParser* aParser,
                                          NW_Byte* aSelector,
                                          TSimpleSelectorData& aData)
{
  TCSSSimpleSelector simpleSelector;
  NW_Uint32 index;

  NW_ASSERT(aParser != NULL);
  NW_ASSERT(aSelector != NULL);

  if (aData.simpleSelectorNum == 0)
  {
    return KBrsrIterateDone;
  }
  index = 0;
  aParser->SetPosition(aSelector);
  while (aParser->SimpleSelectorListIterate(&simpleSelector) == KBrsrIterateMore)
  {
    index++;
    if (index == aData.simpleSelectorNum)
      break;    
  }
  aData.elementToken = 0;
  aData.simpleSelectorNum--;
  /*nameSpace = simpleSelector.nameSpace; - deal later */
  aData.conditionListHandle = simpleSelector.conditionListHandle;
  if (simpleSelector.elementName.iLength != 0)
  {
    NW_Ucs2* ucs2Str = simpleSelector.elementName.GetUnicodeL(aParser->GetEncoding());
    aData.elementToken = (NW_Uint16)NW_WBXML_Dictionary_getTagToken(iDictionary,(NW_String_UCS2Buff_t *)ucs2Str, NW_FALSE);

    NW_Mem_Free(ucs2Str);
  }
  return KBrsrIterateMore;
}


// -----------------------------------------------------------------------------
// CCSSPatternMatcher::GetElementURLL
// This function gets the url associated with the element node
// -----------------------------------------------------------------------------
//
NW_Text_t*
CCSSPatternMatcher::GetElementURLL(NW_DOM_ElementNode_t* aElementNode)
{
  NW_String_t attrVal;
  NW_Text_t *retUrl = NULL;
 
  NW_ASSERT(aElementNode != NULL);

  /* Dom Helper always returns attribute as ucs2 */
  TBrowserStatusCode status = NW_HED_DomHelper_GetHTMLAttributeValue (iDomHelper, aElementNode, NW_XHTML_AttributeToken_href, &attrVal);  
 
  if (status == KBrsrSuccess)
  {
    /* Attribute storage is handed off to url text */
    NW_Text_t *url = NW_Text_New (HTTP_iso_10646_ucs_2, (NW_Ucs2*)attrVal.storage, 
                       NW_Str_Strlen((NW_Ucs2*)attrVal.storage), NW_TRUE);

    if (!url)
    {
      User::Leave(KErrNoMemory);
    }

    /* resolve the URL object */
    status = NW_HED_ContentHandler_ResolveURL (iOwner, url, &retUrl);
    if (status != KBrsrSuccess)
    {
      NW_Object_Delete(url);
      return NULL;
    }
    return retUrl;
  }
  return NULL;
}


// -----------------------------------------------------------------------------
// CCSSPatternMatcher::UrlInCache
// This function checks if url is in cache
// -----------------------------------------------------------------------------
//
TBool
CCSSPatternMatcher::UrlInCache(NW_DOM_ElementNode_t* aElementNode)
{
  NW_Text_t *url;
  TBool inCache = EFalse;

  NW_ASSERT(aElementNode != NULL);

  url = GetElementURLL(aElementNode);
  if (url)
  {
    NW_Bool freeNeeded;
    NW_Ucs2* ucs2AttrVal1 = NULL;

    ucs2AttrVal1 = NW_Text_GetUCS2Buffer(url, 
                                         NW_Text_Flags_Aligned | NW_Text_Flags_NullTerminated,
                                         NULL, 
                                         &freeNeeded);
    if (ucs2AttrVal1 != NULL) 
    {
//R->ul      inCache = UrlLoader_IsUrlInCache(ucs2AttrVal1);
    }
  
    if (freeNeeded)
    {
      NW_Mem_Free(ucs2AttrVal1);
    }
    NW_Object_Delete(url);
  }
    
  return inCache;          
}


/* Match a list words (separated by space) against a pattern */
static
NW_Bool
NW_CSS_PatternMatcher_MatchWords(NW_Ucs2 * words, NW_Ucs2* pattern)
{
  const NW_Ucs2 *pStart = NULL;
  const NW_Ucs2 *pSpace = NULL;
  
  NW_ASSERT(words != NULL);
  NW_ASSERT(pattern != NULL);

  NW_Bool retVal = NW_TRUE;
  pStart = words;
 
  pSpace = NW_Str_Strchr(pStart, WAE_ASCII_SPACE);

  if (pSpace != NULL) {
    NW_Ucs2 *pParttern = NW_Str_Substr(pStart, 0, pSpace - pStart);
    if (!NW_Str_Stricmp(pattern, pParttern))
    {
      retVal = NW_TRUE;
    }
    else
    {
      retVal = NW_CSS_PatternMatcher_MatchWords((NW_Ucs2*)pSpace + 1, pattern);
    }
    NW_Mem_Free (pParttern);
    return retVal;
  }
  else {
    if (!NW_Str_Stricmp(pattern, words))
      return NW_TRUE;
  }
  return NW_FALSE;
}

// -----------------------------------------------------------------------------
// CCSSPatternMatcher::MatchConditionL
// This function matches condition list
// -----------------------------------------------------------------------------
//
TBool 
CCSSPatternMatcher::MatchConditionLazyL(NW_DOM_ElementNode_t* aElementNode, 
                                    NW_Byte* aConditionListHandle,
                                    TCSSParser* aParser,
                                    const NW_Evt_Event_t* aEvent,
                                    CCSSNodeData* aNodeData)
{
  TBrowserStatusCode status;
  NW_Uint8 conditionType;
  TCSSReaderUnit value1;
  TCSSReaderUnit value2;
  NW_String_t str;
  NW_String_t attrVal;
  NW_Uint16 attributeToken;
  NW_Ucs2* ucs2AttrVal1 = NULL;
  NW_Ucs2* ucs2AttrVal2 = NULL;
  NW_Ucs2* ucs2AttrName = NULL;
  TBool equals = NW_FALSE;

  NW_ASSERT(aElementNode != NULL);
  NW_ASSERT(aConditionListHandle != NULL);
  NW_ASSERT(aParser != NULL);

  aParser->SetPosition(aConditionListHandle);
  while (aParser->ConditionListIterate(&conditionType, &value1, &value2) == KBrsrIterateMore)
  {
    attributeToken = 0;
    equals = EFalse;

    switch(conditionType)
      {
      case CLASS_CONDITION:
      { 
        if ((aNodeData == NULL) || aNodeData->classVal == NULL)
        { 
          /* Get the attribute from the dom. Dom helper always converts attribute to ucs2 */
          status = NW_HED_DomHelper_GetHTMLAttributeValue (iDomHelper,
                                                       aElementNode, 
                                                       NW_XHTML_AttributeToken_class, 
                                                       &attrVal);             
          if (status != KBrsrSuccess)
          {
            return EFalse;
          }
      
          ucs2AttrVal1 = (NW_Ucs2 *)attrVal.storage; 
          if (aNodeData)
          {
            aNodeData->classVal = ucs2AttrVal1;
          }
        }
        else 
        {
          ucs2AttrVal1 = aNodeData->classVal;
        }
        ucs2AttrVal2 = value1.GetUnicodeL(aParser->GetEncoding());

        if (NULL != NW_CSS_PatternMatcher_MatchWords(ucs2AttrVal1, ucs2AttrVal2))
        {
          equals = ETrue;
        }

        NW_Mem_Free(ucs2AttrVal2);
        break;
      }
        
      case ID_CONDITION:

        if ((aNodeData == NULL) || aNodeData->idVal == NULL)
        {
          /* Get the attribute from the dom. Dom helper always converts attribute to ucs2 */
          status = NW_HED_DomHelper_GetHTMLAttributeValue (iDomHelper,
                                                           aElementNode, 
                                                           NW_XHTML_AttributeToken_id, 
                                                           &attrVal);             
          if (status != KBrsrSuccess){
            return EFalse;
          }
      
          ucs2AttrVal1 = (NW_Ucs2 *)attrVal.storage; 
          if (aNodeData)
          {
            aNodeData->idVal = ucs2AttrVal1;
          }
        }
        else 
        {
          ucs2AttrVal1 = aNodeData->idVal;
        }
        ucs2AttrVal2 = value1.GetUnicodeL(aParser->GetEncoding());

        /* Compare the strings */
        if ( (NW_Str_Strlen(ucs2AttrVal1) == NW_Str_Strlen(ucs2AttrVal2)) &&
             (!NW_Mem_memcmp(ucs2AttrVal1, ucs2AttrVal2, NW_Str_Strlen(ucs2AttrVal1)*2)) )
        {
          equals = ETrue;
        }

        NW_Mem_Free(ucs2AttrVal2);
        break;
        
      case ATTRIBUTE_CONDITION:
        ucs2AttrName = value1.GetUnicodeL(aParser->GetEncoding());
        if (ucs2AttrName == NULL) 
        {
          return NW_FALSE;
        }
        str.storage = (NW_Byte*)ucs2AttrName;
        str.length = NW_Str_Strlen(ucs2AttrName);
        attributeToken = (NW_Uint16)NW_WBXML_Dictionary_getAttributeToken(iDictionary, &str, HTTP_iso_10646_ucs_2, NW_FALSE);

        /* Get the attribute from the dom. Dom helper always converts attribute to ucs2 */
        status = NW_HED_DomHelper_GetHTMLAttributeValue (iDomHelper,
                                                     aElementNode, 
                                                     attributeToken, 
                                                     &attrVal);             
        if (status != KBrsrSuccess)
        {
          NW_Str_Delete(ucs2AttrName);
          NW_String_deleteStorage(&attrVal);
          return EFalse;
        }
      
        ucs2AttrVal1 = (NW_Ucs2 *)attrVal.storage;
        CleanupStack::PushL(ucs2AttrName);
        ucs2AttrVal2 = value2.GetUnicodeL(aParser->GetEncoding());
        CleanupStack::Pop(ucs2AttrName);

        /* Compare the strings */
        if ( (NW_Str_Strlen(ucs2AttrVal1) == NW_Str_Strlen(ucs2AttrVal2)) &&
             !NW_Str_Stricmp(ucs2AttrVal1, ucs2AttrVal2) )
        {
          equals = ETrue;
        }

        NW_String_deleteStorage(&attrVal);
        NW_Mem_Free(ucs2AttrVal2);
        NW_Mem_Free(ucs2AttrName);
        break;
        
      case ACTIVE_PSEUDO_CLASS:
        if (!NW_Object_IsInstanceOf(aEvent, &NW_Evt_ActivateEvent_Class)){
          return NW_FALSE;
        }
        return EFalse;
        
      case FOCUS_PSEUDO_CLASS:
        if (NW_Object_IsInstanceOf(aEvent, &NW_Evt_FocusEvent_Class)){
          if (NW_Evt_FocusEvent_GetHasFocus(aEvent)){
            return ETrue;
          }
          return EFalse;
        }
        return EFalse;
        
      case LINK_PSEUDO_CLASS:
        {
          TBool isVisited = NW_FALSE;
          NW_Text_t* elementUrl = NULL; 

          if (aNodeData)
          {
            if (aNodeData->elementUrl == NULL)
              aNodeData->elementUrl = GetElementURLL(aElementNode);  
            elementUrl = aNodeData->elementUrl;
          }
          else
            elementUrl = GetElementURLL(aElementNode); 
          
          if (elementUrl == NULL)
            return EFalse;

          if (aNodeData)
          {
            if (aNodeData->isVisited)
            return NW_FALSE;
            if (aNodeData->isLink)
              return ETrue;
          }
          
          /* 
            Check if url has been visited - if yes return FALSE else return TRUE 
            "Visited" means that the link is either in the cache or in the history list
          */
          /* In the cache? */  
          isVisited = UrlInCache(aElementNode);
          if (aNodeData)
          {
            aNodeData->isVisited = isVisited;
            aNodeData->isCached = aNodeData->isVisited;         
            if (!aNodeData->isVisited)
              aNodeData->isLink = ETrue;
            return aNodeData->isLink;
          }
          if (isVisited)
            return EFalse;
          else
            return ETrue;
        }

      case VISITED_PSEUDO_CLASS:
        {
          TBool isVisited = NW_FALSE;
          
          if (aNodeData)
          {
            if (aNodeData->isLink)
              return EFalse;
            if (aNodeData->isVisited)
              return ETrue;
          }

          isVisited = UrlInCache(aElementNode);
          if (aNodeData)
          {
            aNodeData->isVisited = isVisited;
            aNodeData->isCached = aNodeData->isVisited;         
            if (!aNodeData->isVisited)
              aNodeData->isLink = ETrue;
            return aNodeData->isVisited;
          }
          return isVisited;
        }

      case CACHED_PSEUDO_CLASS:
        {
          return UrlInCache(aElementNode);
        }

      default:
        return NW_FALSE;
    } 

    if (!equals) {
      break;
      }
    }

  return equals;
}

// -----------------------------------------------------------------------------
// InitSimpleSelectorData
// Initializes SimpleSelectorData
// -----------------------------------------------------------------------------
//
TBrowserStatusCode
CCSSPatternMatcher::InitSimpleSelectorData(TCSSParser* aParser, NW_Byte* aSelector, TSimpleSelectorData& aData)
{
  TCSSSimpleSelector simpleSelector;
  TBrowserStatusCode status;

  NW_ASSERT(aParser != NULL);
  NW_ASSERT(aSelector != NULL);

  aData.simpleSelectorNum = 0;
  aData.conditionListHandle = NULL;
  aData.elementToken = 0;
  aData.nameSpace.Init(NULL, 0, 0);

  aParser->SetPosition(aSelector);
  while ((status = aParser->SimpleSelectorListIterate(&simpleSelector))
          == KBrsrIterateMore)
  {
    aData.simpleSelectorNum++;
  }
  if (status != KBrsrIterateDone){
    return KBrsrFailure;
  }
  return KBrsrSuccess;
}



// -----------------------------------------------------------------------------
// CCSSPatternMatcher::MatchPatternL
// This function matches pattern
// -----------------------------------------------------------------------------
//
TBool 
CCSSPatternMatcher::MatchPatternLazyL(NW_DOM_ElementNode_t* aElementNode,
                                  TCSSParser* aParser,
                                  NW_Byte* aSelector,
                                  const NW_Evt_Event_t* aEvent,
                                  CCSSNodeData* aNodeData)
{
  TBrowserStatusCode status;
  TSimpleSelectorData data;

  NW_ASSERT(aElementNode != NULL);
  NW_ASSERT(aParser != NULL);
  NW_ASSERT(aSelector != NULL);

  status = InitSimpleSelectorData(aParser, aSelector, data);
  if (status!= KBrsrSuccess){
    return EFalse;
  }

  status = GetNextSimpleSelectorL(aParser, aSelector, data);
  if (data.conditionListHandle != NULL)
  {
    TBool matched = MatchConditionLazyL(aElementNode, data.conditionListHandle, aParser, aEvent, aNodeData);
    if (!matched)
    {
      return EFalse;
    }
  }
  while ((status = GetNextSimpleSelectorL(aParser, aSelector, data)) == KBrsrIterateMore)
  {
    NW_Uint16 elementToken;
    
    if (data.elementToken != 0)
    { /* match ancestor */
      do
      {
        aElementNode = NW_DOM_Node_getParentNode(aElementNode);
        if (aElementNode == NULL)
        {
          return EFalse;
        }
        elementToken = NW_DOM_ElementNode_getTagToken(aElementNode);
      }while (data.elementToken != elementToken);
    }
    /* empty data == wildcard selector. Go up a generation before starting the
      ancestor match */
    else
    {
      aElementNode = NW_DOM_Node_getParentNode(aElementNode);
      if (aElementNode == NULL)
      {
        return EFalse;
      }
    }

    if (data.conditionListHandle != NULL)
    {      
      TBool matched = MatchConditionLazyL(aElementNode, data.conditionListHandle, aParser, aEvent, NULL);
      if (!matched)
      {
        return EFalse;
      }
    }
  }
  if (status != KBrsrIterateDone){
    return EFalse;
  }
  return ETrue;
}


// -----------------------------------------------------------------------------
// CCSSPatternMatcher::MatchPatternL
// This function matches pattern
// -----------------------------------------------------------------------------
//
TBool 
CCSSPatternMatcher::MatchPatternL(NW_DOM_ElementNode_t* aElementNode,
                                  CCSSSelector* aSelector,
                                  const NW_Evt_Event_t* aEvent,
                                  CCSSNodeData* aNodeData)
{
  NW_ASSERT(aElementNode != NULL);
  NW_ASSERT(aSelector != NULL);

  TInt size = aSelector->iSimpleSelectorList->Count();
  TInt index = size-1;
  CCSSSimpleSelector* simpleSelector = aSelector->iSimpleSelectorList->At(index);

  if (simpleSelector->iConditionList != NULL)
  {
    TBool matched = MatchConditionL(aElementNode, simpleSelector->iConditionList, 
                                    aEvent, aNodeData);
    if (!matched)
    {
      return EFalse;
    }
  }
  while (index > 0)
  {
    index--;
    simpleSelector = aSelector->iSimpleSelectorList->At(index);
    TUint16 elementToken = 0;
    
    if (simpleSelector->iElementToken != 0)
    { /* match ancestor */
      do
      {
        aElementNode = NW_DOM_Node_getParentNode(aElementNode);
        if (aElementNode == NULL)
        {
          return EFalse;
        }
        elementToken = NW_DOM_ElementNode_getTagToken(aElementNode);
      }while (simpleSelector->iElementToken != elementToken);
    }
    /* empty data == wildcard selector. Go up a generation before starting the
      ancestor match */
    else
    {
      aElementNode = NW_DOM_Node_getParentNode(aElementNode);
      if (aElementNode == NULL)
      {
        return EFalse;
      }
    }

    if (simpleSelector->iConditionList != NULL)
    {      
      TBool matched = MatchConditionL(aElementNode, simpleSelector->iConditionList,
                                      aEvent, NULL);
      if (!matched)
      {
        return EFalse;
      }
    }
  }
  if (index != 0){
    return EFalse;
  }
  return ETrue;
}

// -----------------------------------------------------------------------------
// CCSSPatternMatcher::MatchConditionL
// This function matches condition list
// -----------------------------------------------------------------------------
//
TBool 
CCSSPatternMatcher::MatchConditionL(NW_DOM_ElementNode_t* aElementNode, 
                                    CCSSConditionList* aConditionList,
                                    const NW_Evt_Event_t* aEvent,
                                    CCSSNodeData* aNodeData)
{
  TBrowserStatusCode status;
  NW_String_t str;
  NW_String_t attrVal;
  NW_Uint16 attributeToken;
  NW_Ucs2* ucs2AttrVal1 = NULL;
  TBool equals = NW_FALSE;
  TInt index = 0;
  TInt numConditions;

  NW_ASSERT(aElementNode != NULL);
  NW_ASSERT(aConditionList != NULL);

  numConditions = aConditionList->Count();

  while (index < numConditions)
  {
    CCSSCondition* condition = aConditionList->At(index);

    index++;
    attributeToken = 0;
    equals = EFalse;

    switch(condition->iConditionType)
      {
      case CLASS_CONDITION:
      { 
        if ((aNodeData == NULL) || aNodeData->classVal == NULL)
        { 
          /* Get the attribute from the dom. Dom helper always converts attribute to ucs2 */
          status = NW_HED_DomHelper_GetHTMLAttributeValue (iDomHelper,
                                                       aElementNode, 
                                                       NW_XHTML_AttributeToken_class, 
                                                       &attrVal);             
          if (status != KBrsrSuccess)
          {
            return EFalse;
          }
      
          ucs2AttrVal1 = (NW_Ucs2 *)attrVal.storage; 
          if (aNodeData)
          {
            aNodeData->classVal = ucs2AttrVal1;
          }
        }
        else 
        {
          ucs2AttrVal1 = aNodeData->classVal;
        }

        if (NULL != NW_CSS_PatternMatcher_MatchWords(ucs2AttrVal1, condition->iValue1))
        {
          equals = ETrue;
        }

        // Free ucs2AttrVal1 if it wasn't adopted by aNodeData
        if ((aNodeData == NULL) || (ucs2AttrVal1 != aNodeData->classVal))
        {
          NW_Mem_Free(ucs2AttrVal1);
          ucs2AttrVal1 = NULL;
        }
        break;
      }
        
      case ID_CONDITION:

        if ((aNodeData == NULL) || aNodeData->idVal == NULL)
        {
          /* Get the attribute from the dom. Dom helper always converts attribute to ucs2 */
          status = NW_HED_DomHelper_GetHTMLAttributeValue (iDomHelper,
                                                           aElementNode, 
                                                           NW_XHTML_AttributeToken_id, 
                                                           &attrVal);             
          if (status != KBrsrSuccess){
            return EFalse;
          }
      
          ucs2AttrVal1 = (NW_Ucs2 *)attrVal.storage; 
          if (aNodeData)
          {
            aNodeData->idVal = ucs2AttrVal1;
          }
        }
        else 
        {
          ucs2AttrVal1 = aNodeData->idVal;
        }

        /* Compare the strings */
        if ( (NW_Str_Strlen(ucs2AttrVal1) == NW_Str_Strlen(condition->iValue1)) &&
             (!NW_Mem_memcmp(ucs2AttrVal1, condition->iValue1, NW_Str_Strlen(ucs2AttrVal1)*2)) )
        {
          equals = ETrue;
        }

        // Free ucs2AttrVal1 if it wasn't adopted by aNodeData
        if ((aNodeData == NULL) || (ucs2AttrVal1 != aNodeData->idVal))
        {
          NW_Mem_Free(ucs2AttrVal1);
          ucs2AttrVal1 = NULL;
        }
        break;
        
      case ATTRIBUTE_CONDITION:
        if (condition->iValue1 == NULL) {
          return EFalse;
        }
        str.storage = (NW_Byte*)condition->iValue1;
        str.length = NW_Str_Strlen(condition->iValue1);
        attributeToken = (NW_Uint16)NW_WBXML_Dictionary_getAttributeToken(iDictionary, &str, HTTP_iso_10646_ucs_2, NW_FALSE);

        /* Get the attribute from the dom. Dom helper always converts attribute to ucs2 */
        status = NW_HED_DomHelper_GetHTMLAttributeValue (iDomHelper,
                                                     aElementNode, 
                                                     attributeToken, 
                                                     &attrVal);             
        if (status != KBrsrSuccess)
        {
          NW_String_deleteStorage(&attrVal);
          return EFalse;
        }
      
        ucs2AttrVal1 = (NW_Ucs2 *)attrVal.storage; 
        /* Compare the strings */
        if ( (condition->iValue2) &&
             (NW_Str_Strlen(ucs2AttrVal1) == NW_Str_Strlen(condition->iValue2)) &&
              !NW_Str_Stricmp(ucs2AttrVal1, condition->iValue2) )
        {
          equals = ETrue;
        }

        NW_String_deleteStorage(&attrVal);
        break;
        
      case ACTIVE_PSEUDO_CLASS:
        return EFalse;
        
      case FOCUS_PSEUDO_CLASS:
        if (NW_Object_IsInstanceOf(aEvent, &NW_Evt_FocusEvent_Class)){
          if (NW_Evt_FocusEvent_GetHasFocus(NW_Evt_FocusEventOf(aEvent))){
            return ETrue;
          }
        }
        return EFalse;
        
      case LINK_PSEUDO_CLASS:
        {
          TBool isVisited = NW_FALSE;
          NW_Text_t* elementUrl = NULL; 

          if (aNodeData)
          {
            if (aNodeData->elementUrl == NULL)
              aNodeData->elementUrl = GetElementURLL(aElementNode);  
            elementUrl = aNodeData->elementUrl;
          }
          else
            elementUrl = GetElementURLL(aElementNode); 
          
          if (elementUrl == NULL)
            return EFalse;

          if (aNodeData)
          {
            if (aNodeData->isVisited)
            return NW_FALSE;
            if (aNodeData->isLink)
              return ETrue;
          }
          
          /* 
            Check if url has been visited - if yes return FALSE else return TRUE 
            "Visited" means that the link is either in the cache or in the history list
          */
          /* In the cache? */  
          isVisited = UrlInCache(aElementNode);
          if (aNodeData)
          {
            aNodeData->isVisited = isVisited;
            aNodeData->isCached = aNodeData->isVisited;         
            if (!aNodeData->isVisited)
              aNodeData->isLink = ETrue;
            return aNodeData->isLink;
          }
          if (isVisited)
            return EFalse;
          else
            return ETrue;
        }

      case VISITED_PSEUDO_CLASS:
        {
          TBool isVisited = NW_FALSE;
          
          if (aNodeData)
          {
            if (aNodeData->isLink)
              return EFalse;
            if (aNodeData->isVisited)
              return ETrue;
          }

          isVisited = UrlInCache(aElementNode);
          if (aNodeData)
          {
            aNodeData->isVisited = isVisited;
            aNodeData->isCached = aNodeData->isVisited;         
            if (!aNodeData->isVisited)
              aNodeData->isLink = ETrue;
            return aNodeData->isVisited;
          }
          return isVisited;
        }

      case CACHED_PSEUDO_CLASS:
        {
          return UrlInCache(aElementNode);
        }

      default:
        return NW_FALSE;
    } 

    if (!equals) {
      break;
      }
    }

  return equals;
}