--- /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