diff -r 000000000000 -r dd21522fd290 webengine/osswebengine/WebKit/s60/webview/WebTextFormatMask.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webengine/osswebengine/WebKit/s60/webview/WebTextFormatMask.cpp Mon Mar 30 12:54:55 2009 +0300 @@ -0,0 +1,322 @@ +/* +* Copyright (c) 2006 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: +* +*/ + +#include "config.h" +#include "../../bidi.h" + +#include "WebTextFormatMask.h" + +#include "Frame.h" +#include "Editor.h" +#include "String.h" +#include "HtmlNames.h" +#include "HtmlInputElement.h" + +#include "Text.h" +#include "CString.h" +#include "DeprecatedCString.h" +#include "SelectionController.h" + +using namespace WebCore; +static const int kInfinite = -1; + +// help functions +inline bool isPunctuation(TChar::TCategory category) { return (category & 0xF0) == TChar::EPunctuationGroup; } +inline bool isSymbol(TChar::TCategory category) { return (category & 0xF0) == TChar::ESymbolGroup; } +inline bool isLowerCase(TChar::TCategory category) { return category == TChar::ELlCategory; } +inline bool isUpperCase(TChar::TCategory category) { return category == TChar::ELuCategory; } +inline bool isDigit(TChar::TCategory category) { return category == TChar::ENdCategory; } + +// NOTE: it seems more logical to put WebTextFormatMask as a member of +// RenderStyle. This way we just need to parse the format mask string once +// when parsing CSS. However, for now we don't want to mess up with css code +// in webcore, and anyway wap css is not used very often. + +WebTextFormatMask::WebTextFormatMask(const String& str, bool required) + : m_masks(0), m_currentMask(0), m_acceptAll(false), m_inputRequired(required) +{ + buildMaskList(str); + m_currentMask = m_masks; +} + +WebTextFormatMask::~WebTextFormatMask() +{ + clearMaskList(); +} + +void WebTextFormatMask::buildMaskList(const String& str) +{ + // *M or *m + if (str.isEmpty() || str=="*M" || str=="*m") { + m_acceptAll = true; + return; + } + + // parse the string + const UChar* p = String(str).charactersWithNullTermination(); + UChar ch; + int mul = 1; + bool result = true; + while( ch = *p++ ) { + switch(ch) { + case 'a': result = createMask( ELeLoSymPuc, mul ); break; + case 'A': result = createMask( ELeUpSymPuc, mul ); break; + case 'n': result = createMask( ENumSymPuc, mul ); break; + case 'N': result = createMask( ENumChar, mul ); break; + case 'x': result = createMask( ELeLoNumSymPuc, mul ); break; + case 'X': result = createMask( ELeUpNumSymPuc, mul ); break; + case 'm': result = createMask( EAnyLow, mul ); break; + case 'M': result = createMask( EAnyUpper, mul ); break; + case '*': mul = kInfinite; break; + case '\\':result = createStaticMask(p); break; + default: { + // 'nf' + if( isdigit(ch) ) + mul = parseMultitude(--p, result); + else + result = false; + break; + } + } + + if(!result) { + // something wrong with the format string, fallback to + // accept all characters. + clearMaskList(); + m_acceptAll = true; + return; + } + } + +} + +void WebTextFormatMask::clearMaskList() +{ + MaskBase* m = m_masks; + MaskBase* p = m; + while(p) { + p = m->m_next; + delete m; + m = p; + } + m_masks = NULL; +} + +bool WebTextFormatMask::createMask( TInputFormatMaskType type, int& multi ) +{ + MaskBase* m = NULL; + if( multi == 1 ) + m = new MaskSingle( type ); + else + m = new MaskComposite( type, multi ); + multi = 1; + return appendMask(m); +} + +int WebTextFormatMask::parseMultitude( const UChar*& p, bool& result ) +{ + // start from p, search all digits + String dstr; + while(isdigit(*p)) + dstr.append(*p++); + + // there should be one valid character after digits + if(*p == 0) { + result = false; + return 0; + } + + // parse the digit string + int multi = atoi( dstr.latin1().deprecatedCString().data() ); + if(multi>0) + result = true; + return multi; +} + +bool WebTextFormatMask::createStaticMask( const UChar*& p ) +{ + MaskBase* m = new MaskStatic( *p++ ); + return appendMask(m); +} + +bool WebTextFormatMask::checkText( const String& text, ErrorBlock& eb ) +{ + // "-wap-input-required" takes precedence + if(text.length() == 0) { + return !m_inputRequired; + } + + if(m_acceptAll) return true; + + m_currentMask = m_masks; + + // we have no masks left + if( !m_currentMask && text.length()>0 ) { + eb.set(0, text.length()); + return false; + } + + for(int i=0; icheck(text[i]) ) { + // search all illegal characters in this run + if( m_currentMask ) { + if( eb.m_start == -1 ) + eb.set( i, 1 ); + else + eb.m_extent++; + } + else { + eb.m_extent += text.length() - i; + return false; + } + } + else if( eb.m_start != -1 ) { + // the previous check failed + return false; + } + + m_currentMask = m_currentMask->nextMask(); + } + + // did we use up all the masks? + if(m_currentMask && m_currentMask->multitude() != kInfinite) + return false; + + return (eb.m_start == -1); +} + +int WebTextFormatMask::getMultitude() +{ + int count = 0; + MaskBase* m = m_masks; + while (m) { + + if (m->multitude() == kInfinite){ + return kInfinite; + } + else { + count += m->multitude(); + } + m = m->nextMask(); + } + + return (count)?count:kInfinite; +} + + +TInputFormatMaskType WebTextFormatMask::getInputFormatMaskType(Frame* frame, int aOffset) +{ + + int i = 0; + MaskBase* m = m_masks; + while (m) { + if (m->isComposite()){ + return m->getInputFormatMaskType(); + } + else if (i==aOffset) { + + TInputFormatMaskType ifmt = m->getInputFormatMaskType(); + if (ifmt == EStatic){ + MaskStatic* ms = static_cast(m); + if (ms) { + //make sure not to re-write the static text if it already exists + if (frame->document() && + frame->document()->focusedNode() && + frame->document()->focusedNode()->hasTagName(HTMLNames::inputTag) ) { + + HTMLInputElement* ie = static_cast(frame->document()->focusedNode()); + int len = ie->value().length(); + + if (len<=aOffset) { + UChar c = ms->getStatic(); + frame->editor()->insertTextWithoutSendingTextEvent(String(&c,1), false); + } + } + } + } + return ifmt; + } + m = m->nextMask(); + ++i; + } + + return ENoFormat; +} + +bool WebTextFormatMask::appendMask(MaskBase* m) +{ + // build the mask chain + if( !m_masks ) { + m_masks = m; + } + else { + MaskBase* msk = m_masks; + while( msk->m_next ) + msk = msk->m_next; + + // composite mask only exists at the end of mask chain. + if( msk->isComposite() ) { + delete m; + return false; + } + + msk->m_next = m; + } + + return true; +} + +MaskComposite::MaskComposite(TInputFormatMaskType t, int mul) + : MaskSingle(t), m_offset(0), m_length(mul) +{ +} + +MaskBase* MaskComposite::nextMask() +{ + if( ++m_offset < m_length || m_length == kInfinite ) + return this; + + return NULL; +} + +bool MaskSingle::check(UChar ch) +{ + + TChar::TCategory c = TChar(ch).GetCategory(); + + switch(m_type) { + case ELeLoSymPuc: return isLowerCase(c) || isSymbol(c) || isPunctuation(c); + case ELeUpSymPuc: return isUpperCase(c) || isSymbol(c) || isPunctuation(c); + case ENumSymPuc: return isDigit(c) || isSymbol(c) || isPunctuation(c); + case ENumChar: return isDigit(c); + case ELeLoNumSymPuc: return isLowerCase(c) || isDigit(c) || isSymbol(c) || isPunctuation(c); + case ELeUpNumSymPuc: return isUpperCase(c) || isDigit(c) || isSymbol(c) || isPunctuation(c); + case EAnyLow: + case EAnyUpper: + default: + return true; + } + +} + +bool MaskStatic::check(UChar ch) +{ + return m_char == ch; +} + +// END OF FILE +