webengine/wmlengine/src/css/src/CSSHandler.cpp
changeset 0 dd21522fd290
child 68 92a765b5b3e7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/wmlengine/src/css/src/CSSHandler.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,420 @@
+/*
+* 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:  Handler for appling styles
+*
+*/
+
+
+
+// INCLUDE FILES
+#include "CSSHandler.h"
+#include "nw_lmgr_simplepropertylist.h"
+#include "nw_hed_documentroot.h"
+#include "nw_hed_CompositeContentHandler.h"
+#include "nw_lmgr_statictablebox.h"
+#include "nw_fbox_inputbox.h"
+#include "HEDDocumentListener.h"
+#include "nw_lmgr_rootbox.h"
+#include "nw_basicforms_inputelementhandler.h"
+#include "nwx_logger.h"
+#include "BrsrStatusCodes.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 ===============================
+
+// -----------------------------------------------------------------------------
+// CCCSSHandler::CCCSSHandler
+// C++ default constructor can NOT contain any code, that might leave.
+// -----------------------------------------------------------------------------
+//
+CCSSHandler::CCSSHandler(NW_CSS_Processor_t* aProcessor) : 
+              CActive( CActive::EPriorityLow + 1 )
+  {
+  iProcessor = aProcessor;
+  }
+
+// -----------------------------------------------------------------------------
+// CCSSHandler::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CCSSHandler::ConstructL()
+  {
+  CActiveScheduler::Add(this);
+  }
+
+// -----------------------------------------------------------------------------
+// CCSSHandler::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CCSSHandler* CCSSHandler::NewL(NW_CSS_Processor_t* aProcessor)
+  {
+  CCSSHandler* self = new( ELeave ) CCSSHandler(aProcessor);
+  
+  CleanupStack::PushL( self );
+  self->ConstructL();
+  CleanupStack::Pop();
+
+  return self;
+  }
+
+    
+// Destructor
+CCSSHandler::~CCSSHandler()
+  {
+  Cancel();
+  }
+
+
+// -----------------------------------------------------------------------------
+// CCSSHandler::RunL
+// Applies styles to each box of the box tree
+// -----------------------------------------------------------------------------
+//
+void CCSSHandler::RunL()
+  {
+	// Each time RunL() gets called we need to
+	// 1. Apply styles to the next box
+	// 2. Find out if the styles have been applied 
+  //    to the entire box tree    
+	//
+	//	-	If it has completed, tell the owner to collapse
+  //    the box tree and update display
+	//
+	//	-	If it hasn't completed, simulate a request
+	//		completion, so that this RunL() will get
+	//		called again by the active scheduler.
+	//
+  TBool completed = EFalse;
+	TRAPD(ret, completed = ApplyBoxStylesL());
+  if (ret == KErrNone)
+    {
+	  if (!completed)
+	    {
+		  // Before simulating a request completion we need to
+		  // set this active object as active.
+		  SetActive();
+      // The following two lines simulate a request completion
+	    // as if it were generated by a server. This completion will
+	    // be processed by the active scheduler. If other events have
+	    // completed belonging to higher-priority active objects, those
+	    // will get processed first. Otherwise, our RunL() function
+	    // will get called, allowing us to apply styles to next box
+	    // User::RequestComplete() takes two parameters: the address 
+	    // of the status variable for the active object whose event
+	    // has completed (in this case, *this* active object), and
+	    // an error code to write to this address - KErrNone in this case.
+		  TRequestStatus* status = &iStatus;
+		  User::RequestComplete(status, KErrNone);
+	    }
+
+	  else
+	    {
+      // call the function to update display
+		  TInt ret1;
+		  TRAP(ret1, ApplyStylesCompleteL());
+      }
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CCCSSHandler::DoCancel
+// -----------------------------------------------------------------------------
+//
+void CCSSHandler::DoCancel()
+{
+}
+
+// -----------------------------------------------------------------------------
+// CCCSSHandler::ApplyStylesCompleteL
+// collapse the box tree, swaps property list and then formats and redraws 
+// the updated tree
+// -----------------------------------------------------------------------------
+//
+void CCSSHandler::ApplyStylesCompleteL()
+{ 
+  NW_LOG0(NW_LOG_LEVEL4, "[CCSSHandler:ApplyStylesCompleteL Begin]");
+  NW_HED_DocumentRoot_t* docRoot = 
+    (NW_HED_DocumentRoot_t*) NW_HED_DocumentNode_GetRootNode (iProcessor->owner);
+
+  NW_LMgr_RootBox_t* rootBox = NW_HED_DocumentRoot_GetRootBox(docRoot);
+
+  // collapse the box tree
+  TBrowserStatusCode status = rootBox->boxTreeListener->Collapse (NULL, NW_TRUE);
+  if (status == KBrsrOutOfMemory)
+  {
+    User::Leave(KErrNoMemory);
+  }
+  else if (status != KBrsrSuccess)
+  {
+    User::Leave(KErrAbort);
+  }
+  NW_LOG0(NW_LOG_LEVEL4, "[CCSSHandler:Collapse tree finished]");
+
+  // swap the property list 
+  SwapPropListL();
+  NW_LOG0(NW_LOG_LEVEL4, "[CCSSHandler:Swap prop list finished]");
+  
+  // format the box tree
+  status = rootBox->boxTreeListener->FormatBoxTree (NW_TRUE);
+  if (status == KBrsrOutOfMemory)
+  {
+    User::Leave(KErrNoMemory);
+  }
+  else if (status != KBrsrSuccess)
+  {
+    User::Leave(KErrAbort);
+  }
+  NW_LOG0(NW_LOG_LEVEL4, "[CCSSHandler:format tree finished]");
+
+  // draw
+  status = rootBox->boxTreeListener->RedrawDisplay (NW_FALSE);
+  if (status == KBrsrOutOfMemory)
+  {
+    User::Leave(KErrNoMemory);
+  }
+  else if (status != KBrsrSuccess)
+  {
+    User::Leave(KErrAbort);
+  }
+  NW_LOG0(NW_LOG_LEVEL4, "[CCSSHandler:ApplyStylesCompleteL finished]");
+}
+
+// -----------------------------------------------------------------------------
+// CCCSSHandler::ApplyStylesCompleteL
+// swaps the property list of the boxes
+// -----------------------------------------------------------------------------
+//
+void
+CCSSHandler::SwapPropListL()
+  {
+  NW_LMgr_Box_t* box = NULL;
+  NW_Bool skipChildren = NW_FALSE;
+  NW_HED_ContentHandler_t* contentHandler = (NW_HED_ContentHandler_t*)(iProcessor->owner);
+  NW_LMgr_PropertyValue_t displayVal;
+  
+  // Initialize the box visitor
+  NW_LMgr_BoxVisitor_Initialize(&iBoxVisitor, contentHandler->boxTree);
+  
+  box = NW_LMgr_BoxVisitor_NextBox(&iBoxVisitor,&skipChildren);
+  // swap the propery lists
+  // Look for the next box with Simple property list set 
+  while (box != NULL) 
+    {
+    
+    displayVal.token = NW_CSS_PropValue_display_inline; 
+    // we want to look at simple prop list since we don't want to look at split boxes
+    if (box->propList && NW_Object_IsClass(box->propList, &NW_LMgr_SimplePropertyList_Class))
+      {
+      NW_LMgr_SimplePropertyList_t* simplePropList = (NW_LMgr_SimplePropertyList_t*)box->propList;
+      if (simplePropList->backupPropList)
+        {
+        box->propList = simplePropList->backupPropList;
+        simplePropList->backupPropList = NULL;
+        NW_Object_Delete(simplePropList);
+        
+        // we need to do this so that context can again calculate the border info 
+        if (NW_Object_IsClass(box, &NW_LMgr_StaticTableBox_Class))
+          {
+          NW_LMgr_StaticTableBox_t* tableBox = (NW_LMgr_StaticTableBox_t*)box;
+          NW_Object_Delete(tableBox->ctx);
+          tableBox->ctx = NULL;
+          }
+        
+        if (NW_Object_IsInstanceOf(box, &NW_FBox_InputBox_Class))
+          {
+          TBrowserStatusCode status = NW_XHTML_inputElementHandler_HandleValidation(NW_FBox_InputBoxOf(box), 
+            NW_FBox_FormBoxOf(box)->formLiaison);
+          if (status == KBrsrOutOfMemory)
+            {
+            User::Leave(KErrNoMemory);
+            }
+          }
+        
+        NW_LMgr_Box_GetPropertyValue(box, NW_CSS_Prop_display, NW_CSS_ValueType_Token, &displayVal);
+        
+        if (displayVal.token != NW_CSS_PropValue_none) 
+          {
+          // Check display Val and replace box is necessary
+          TBrowserStatusCode status = NW_CSS_Processor_HandleDisplayVal(&box, &displayVal);
+          if (status == KBrsrOutOfMemory)
+            {
+            User::Leave(KErrNoMemory);
+            }
+          else if (status != KBrsrSuccess)
+            {
+            User::Leave(KErrAbort);
+            }
+          iBoxVisitor.currentBox = box;
+          }
+        }
+      }// end if
+    
+    // handle display none
+    if (displayVal.token == NW_CSS_PropValue_none) 
+      {
+      skipChildren = NW_TRUE;
+      }
+    // Algorithm was changed here. We do not remove boxes with NW_CSS_PropValue_none any more at this point.
+
+    box = NW_LMgr_BoxVisitor_NextBox(&iBoxVisitor,&skipChildren);
+  
+    
+    }// end while
+  }
+
+// -----------------------------------------------------------------------------
+// CCCSSHandler::ApplyBoxStylesL
+// Applies styles to each box and stores it as backup property list
+// -----------------------------------------------------------------------------
+//
+TBool CCSSHandler::ApplyBoxStylesL()
+{
+  NW_DOM_ElementNode_t* elementNode = NULL;
+  NW_LMgr_Box_t* box = NULL;
+  NW_LMgr_SimplePropertyList_t* oldPropList = NULL;
+  TBrowserStatusCode status = KBrsrSuccess;
+
+  // Look for the next box with DOM node set 
+  box = GetNextBox(&elementNode);
+
+  // we have element node and proplist
+  if (box != NULL)
+  {
+    oldPropList = (NW_LMgr_SimplePropertyList_t*)(box->propList);
+    // set propList as NULL to get new prop list
+    box->propList = NULL;
+
+    if (oldPropList->backupPropList)
+    {
+      NW_Object_Delete(oldPropList->backupPropList);
+      oldPropList->backupPropList = NULL;
+    }
+
+    // get new styles
+    status = iProcessor->applyCSSCallback((void *)(iProcessor->owner), elementNode, &box);
+    if (status == KBrsrOutOfMemory)
+    {
+      User::Leave(KErrNoMemory);
+    }
+
+    // box was deleted either because of error
+    if (box == NULL)
+    {
+      NW_Object_Delete(oldPropList);
+      User::Leave(KErrAbort);
+    }
+    
+    // save the box proplist as backup prop list
+    oldPropList->backupPropList = box->propList;
+    box->propList = (NW_LMgr_PropertyList_t*)oldPropList;
+  }
+  return (box == NULL);
+}
+
+// -----------------------------------------------------------------------------
+// CCCSSHandler::GetNextBox
+// Get next box with  DOM node - these are the boxes we need to apply styles again
+// -----------------------------------------------------------------------------
+//
+NW_LMgr_Box_t*
+CCSSHandler::GetNextBox(NW_DOM_ElementNode_t** node)
+{
+  NW_LMgr_Box_t* box = NULL;
+  NW_DOM_ElementNode_t* elementNode = NULL;
+
+  // Look for the next box with DOM node set 
+  while ((box = NW_LMgr_BoxVisitor_NextBox(&iBoxVisitor,0)) != NULL) 
+  {
+    NW_LMgr_PropertyValue_t value; 
+    NW_LMgr_PropertyList_t* propList = box->propList;
+
+    // we want to look at simple prop list since we don't want to loook at split boxes
+    if (propList && NW_Object_IsClass(propList, &NW_LMgr_SimplePropertyList_Class))
+    {
+      value.object = NULL;
+      (void)NW_LMgr_Box_GetPropertyValue(box, NW_CSS_Prop_elementId, NW_CSS_ValueType_Object, &value);
+      if (value.object == NULL)
+        continue;
+
+      elementNode = (NW_DOM_ElementNode_t*)value.object;  
+      if (elementNode)
+      {
+        break;
+      }
+    }
+  }
+  *node = elementNode;
+  return box;
+}
+
+// -----------------------------------------------------------------------------
+// CCCSSHandler::ApplyStylesL
+// This is called from the processor when a new stylesheet needs to be applied
+// -----------------------------------------------------------------------------
+//
+void CCSSHandler::ApplyStylesL()
+{
+  NW_LOG0(NW_LOG_LEVEL4, "[CCSSHandler:ApplyStylesL Begin]");
+  // cancel the active object
+  // we need to stop applying styles as a new CSS has arrived which will resolve to
+  // new CSS properties
+  Cancel();
+
+	// This function is called by client code (processor) to start the long
+	// running css apply styles.
+
+  // we want to apply styles to the box tree associated with the owner
+  NW_HED_ContentHandler_t* contentHandler = (NW_HED_ContentHandler_t*)(iProcessor->owner);
+
+  // Initialize the box visitor
+  NW_LMgr_BoxVisitor_Initialize(&iBoxVisitor, contentHandler->boxTree);
+
+  // Call SetActive() so that this active object gets notified of completed requests.
+  SetActive();
+
+  // The following two lines simulate a request completion
+	// as if it were generated by a server. This completion will
+	// be processed by the active scheduler. If other events have
+	// completed belonging to higher-priority active objects, those
+	// will get processed first. Otherwise, our RunL() function
+	// will get called, allowing us to apply styles to next box
+	// User::RequestComplete() takes two parameters: the address 
+	// of the status variable for the active object whose event
+	// has completed (in this case, *this* active object), and
+	// an error code to write to this address - KErrNone in this case.
+  TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+}
+
+//  End of File