webengine/osswebengine/WebKit/s60/webview/WebTextFormatMask.cpp
changeset 0 dd21522fd290
child 8 7c90e6132015
--- /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; i<text.length(); ++i) {
+        if( !m_currentMask || !m_currentMask->check(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<MaskStatic*>(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<HTMLInputElement*>(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
+