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