webengine/osswebengine/WebKit/s60/webview/WebTextFormatMask.cpp
changeset 0 dd21522fd290
child 8 7c90e6132015
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  
       
    15 *
       
    16 */
       
    17 
       
    18 #include "config.h"
       
    19 #include "../../bidi.h"
       
    20 
       
    21 #include "WebTextFormatMask.h"
       
    22 
       
    23 #include "Frame.h"
       
    24 #include "Editor.h"
       
    25 #include "String.h"
       
    26 #include "HtmlNames.h"
       
    27 #include "HtmlInputElement.h"
       
    28 
       
    29 #include "Text.h"
       
    30 #include "CString.h"
       
    31 #include "DeprecatedCString.h"
       
    32 #include "SelectionController.h"
       
    33 
       
    34 using namespace WebCore;
       
    35 static const int kInfinite = -1;
       
    36 
       
    37 // help functions
       
    38 inline bool isPunctuation(TChar::TCategory category)       { return (category & 0xF0) == TChar::EPunctuationGroup; }
       
    39 inline bool isSymbol(TChar::TCategory category)            { return (category & 0xF0) == TChar::ESymbolGroup; }
       
    40 inline bool isLowerCase(TChar::TCategory category)         { return category == TChar::ELlCategory; }
       
    41 inline bool isUpperCase(TChar::TCategory category)         { return category == TChar::ELuCategory; }
       
    42 inline bool isDigit(TChar::TCategory category)             { return category == TChar::ENdCategory; }
       
    43 
       
    44 // NOTE: it seems more logical to put WebTextFormatMask as a member of 
       
    45 // RenderStyle.  This way we just need to parse the format mask string once
       
    46 // when parsing CSS.  However, for now we don't want to mess up with css code
       
    47 // in webcore, and anyway wap css is not used very often.
       
    48 
       
    49 WebTextFormatMask::WebTextFormatMask(const String& str, bool required) 
       
    50     : m_masks(0), m_currentMask(0), m_acceptAll(false), m_inputRequired(required)
       
    51 {
       
    52     buildMaskList(str);
       
    53     m_currentMask = m_masks;
       
    54 }
       
    55 
       
    56 WebTextFormatMask::~WebTextFormatMask()
       
    57 {
       
    58     clearMaskList();
       
    59 }
       
    60 
       
    61 void WebTextFormatMask::buildMaskList(const String& str)
       
    62 {
       
    63     // *M or *m
       
    64     if (str.isEmpty() || str=="*M" || str=="*m") {
       
    65         m_acceptAll = true;
       
    66         return;
       
    67     }
       
    68 
       
    69     // parse the string
       
    70     const UChar* p = String(str).charactersWithNullTermination();
       
    71     UChar ch;
       
    72     int mul = 1;
       
    73     bool result = true;
       
    74     while( ch = *p++ ) {
       
    75         switch(ch) {
       
    76             case 'a': result = createMask( ELeLoSymPuc, mul );      break;
       
    77             case 'A': result = createMask( ELeUpSymPuc, mul );      break;
       
    78             case 'n': result = createMask( ENumSymPuc, mul );       break;
       
    79             case 'N': result = createMask( ENumChar, mul );         break;
       
    80             case 'x': result = createMask( ELeLoNumSymPuc, mul );   break;
       
    81             case 'X': result = createMask( ELeUpNumSymPuc, mul );   break;
       
    82             case 'm': result = createMask( EAnyLow, mul );          break;
       
    83             case 'M': result = createMask( EAnyUpper, mul );        break;
       
    84             case '*': mul = kInfinite;                              break;
       
    85             case '\\':result = createStaticMask(p);                 break;
       
    86             default: {
       
    87                 // 'nf'
       
    88                 if( isdigit(ch) )
       
    89                     mul = parseMultitude(--p, result);
       
    90                 else 
       
    91                     result = false;
       
    92                 break;
       
    93            }
       
    94         }
       
    95 
       
    96         if(!result) {
       
    97             // something wrong with the format string, fallback to
       
    98             // accept all characters.
       
    99             clearMaskList();
       
   100             m_acceptAll = true;
       
   101             return;
       
   102         }
       
   103     }
       
   104     
       
   105 }
       
   106 
       
   107 void WebTextFormatMask::clearMaskList()
       
   108 {
       
   109     MaskBase* m = m_masks;
       
   110     MaskBase* p = m;
       
   111     while(p) {
       
   112         p = m->m_next;
       
   113         delete m;
       
   114         m = p;
       
   115     }
       
   116     m_masks = NULL;
       
   117 }
       
   118 
       
   119 bool WebTextFormatMask::createMask( TInputFormatMaskType type, int& multi )
       
   120 {
       
   121     MaskBase* m = NULL;
       
   122     if( multi == 1 )
       
   123         m = new MaskSingle( type );
       
   124     else
       
   125         m = new MaskComposite( type, multi );
       
   126     multi = 1;
       
   127     return appendMask(m);
       
   128 }
       
   129 
       
   130 int WebTextFormatMask::parseMultitude( const UChar*& p, bool& result )
       
   131 {
       
   132     // start from p, search all digits
       
   133     String dstr;
       
   134     while(isdigit(*p))
       
   135         dstr.append(*p++);    
       
   136     
       
   137     // there should be one valid character after digits
       
   138     if(*p == 0) {
       
   139         result = false;
       
   140         return 0;
       
   141     }
       
   142 
       
   143     // parse the digit string
       
   144     int multi = atoi( dstr.latin1().deprecatedCString().data() );
       
   145     if(multi>0)
       
   146         result = true;
       
   147     return multi;        
       
   148 }
       
   149 
       
   150 bool WebTextFormatMask::createStaticMask( const UChar*& p )
       
   151 {
       
   152     MaskBase* m = new MaskStatic( *p++ );
       
   153     return appendMask(m);
       
   154 }
       
   155 
       
   156 bool WebTextFormatMask::checkText( const String& text, ErrorBlock& eb )
       
   157 {
       
   158     // "-wap-input-required" takes precedence
       
   159     if(text.length() == 0) {
       
   160         return !m_inputRequired;
       
   161     }
       
   162 
       
   163     if(m_acceptAll) return true;
       
   164 
       
   165     m_currentMask = m_masks;
       
   166 
       
   167     // we have no masks left
       
   168     if( !m_currentMask && text.length()>0 ) {
       
   169         eb.set(0, text.length());
       
   170         return false;
       
   171     }
       
   172 
       
   173     for(int i=0; i<text.length(); ++i) {
       
   174         if( !m_currentMask || !m_currentMask->check(text[i]) ) {
       
   175             // search all illegal characters in this run
       
   176             if( m_currentMask ) {
       
   177                 if( eb.m_start == -1 )
       
   178                     eb.set( i, 1 );
       
   179                 else
       
   180                     eb.m_extent++;
       
   181             }
       
   182             else {
       
   183                 eb.m_extent += text.length() - i;
       
   184                 return false;
       
   185             }
       
   186         }
       
   187         else if( eb.m_start != -1 ) {
       
   188             // the previous check failed
       
   189             return false;
       
   190         }
       
   191 
       
   192         m_currentMask = m_currentMask->nextMask();
       
   193     }
       
   194 
       
   195     // did we use up all the masks?
       
   196     if(m_currentMask && m_currentMask->multitude() != kInfinite)
       
   197         return false;
       
   198 
       
   199     return (eb.m_start == -1);
       
   200 }
       
   201 
       
   202 int WebTextFormatMask::getMultitude()
       
   203 {
       
   204     int count = 0;
       
   205     MaskBase* m = m_masks;
       
   206     while (m) {
       
   207 
       
   208         if (m->multitude() == kInfinite){
       
   209             return kInfinite;    
       
   210         }        
       
   211         else {
       
   212             count += m->multitude();           
       
   213         }
       
   214         m = m->nextMask();                
       
   215     }
       
   216         
       
   217     return (count)?count:kInfinite;    
       
   218 }
       
   219 
       
   220 
       
   221 TInputFormatMaskType WebTextFormatMask::getInputFormatMaskType(Frame* frame, int aOffset)
       
   222 { 
       
   223 
       
   224     int i = 0;
       
   225     MaskBase* m = m_masks;
       
   226     while (m) {
       
   227         if (m->isComposite()){
       
   228             return m->getInputFormatMaskType();    
       
   229         }
       
   230         else if (i==aOffset) {
       
   231 
       
   232             TInputFormatMaskType ifmt = m->getInputFormatMaskType();
       
   233             if (ifmt == EStatic){
       
   234                 MaskStatic* ms = static_cast<MaskStatic*>(m);
       
   235                 if (ms) {                
       
   236                     //make sure not to re-write the static text if it already exists
       
   237                     if (frame->document() &&
       
   238                         frame->document()->focusedNode() &&
       
   239                         frame->document()->focusedNode()->hasTagName(HTMLNames::inputTag) ) {         
       
   240                     
       
   241                         HTMLInputElement* ie = static_cast<HTMLInputElement*>(frame->document()->focusedNode());                      
       
   242                         int len = ie->value().length();
       
   243 
       
   244                         if (len<=aOffset) {                            
       
   245                             UChar c = ms->getStatic();                            
       
   246                             frame->editor()->insertTextWithoutSendingTextEvent(String(&c,1), false);
       
   247                         }
       
   248                     }
       
   249                 }            
       
   250             }
       
   251             return ifmt;            
       
   252         }
       
   253         m = m->nextMask();
       
   254         ++i;                
       
   255     }
       
   256 
       
   257     return ENoFormat;
       
   258 }
       
   259   
       
   260 bool WebTextFormatMask::appendMask(MaskBase* m)
       
   261 {
       
   262     // build the mask chain
       
   263     if( !m_masks ) {
       
   264         m_masks = m;
       
   265     }
       
   266     else {
       
   267         MaskBase* msk = m_masks;
       
   268         while( msk->m_next )
       
   269             msk = msk->m_next;
       
   270 
       
   271         // composite mask only exists at the end of mask chain.
       
   272         if( msk->isComposite() ) {
       
   273             delete m;
       
   274             return false;
       
   275         }
       
   276        
       
   277         msk->m_next = m;
       
   278     }
       
   279 
       
   280     return true;
       
   281 }
       
   282 
       
   283 MaskComposite::MaskComposite(TInputFormatMaskType t, int mul) 
       
   284             : MaskSingle(t), m_offset(0), m_length(mul)
       
   285 {
       
   286 }
       
   287 
       
   288 MaskBase* MaskComposite::nextMask()
       
   289 {
       
   290     if( ++m_offset < m_length || m_length == kInfinite )
       
   291         return this;
       
   292     
       
   293     return NULL;
       
   294 }
       
   295 
       
   296 bool MaskSingle::check(UChar ch)
       
   297 {
       
   298 
       
   299     TChar::TCategory c = TChar(ch).GetCategory();
       
   300 
       
   301     switch(m_type) {
       
   302         case ELeLoSymPuc:       return isLowerCase(c) || isSymbol(c) || isPunctuation(c);
       
   303         case ELeUpSymPuc:       return isUpperCase(c) || isSymbol(c) || isPunctuation(c);
       
   304         case ENumSymPuc:        return isDigit(c) || isSymbol(c) || isPunctuation(c);
       
   305         case ENumChar:          return isDigit(c);
       
   306         case ELeLoNumSymPuc:    return isLowerCase(c) || isDigit(c) || isSymbol(c) || isPunctuation(c);
       
   307         case ELeUpNumSymPuc:    return isUpperCase(c) || isDigit(c) || isSymbol(c) || isPunctuation(c);
       
   308         case EAnyLow:
       
   309         case EAnyUpper: 
       
   310         default:
       
   311             return true;
       
   312     }
       
   313 
       
   314 }
       
   315 
       
   316 bool MaskStatic::check(UChar ch)
       
   317 {
       
   318     return m_char == ch;
       
   319 }
       
   320     
       
   321 // END OF FILE
       
   322