Changeset 10867 in webkit


Ignore:
Timestamp:
Oct 17, 2005 8:15:31 PM (18 years ago)
Author:
mjs
Message:

JavaScriptCore:

Reviewed by Geoff. Code changes by Darin.

  • some micro-optimizations to FastMalloc to reduce math and branches.
  • kxmlcore/FastMalloc.cpp: (KXMLCore::TCMalloc_Central_FreeList::Populate): (KXMLCore::fastMallocRegisterThread): (KXMLCore::TCMalloc_ThreadCache::GetCache): (KXMLCore::TCMalloc_ThreadCache::GetCacheIfPresent):

WebCore:

Reviewed by Geoff.

Speed up the tokenizer by keeping more state on the stack instead of in the object,
to avoid load-store traffic. About a .5% speedup.

  • khtml/html/htmltokenizer.cpp: (khtml::HTMLTokenizer::HTMLTokenizer): (khtml::HTMLTokenizer::reset): (khtml::HTMLTokenizer::begin): (khtml::HTMLTokenizer::setForceSynchronous): (khtml::HTMLTokenizer::processListing): (khtml::HTMLTokenizer::parseSpecial): (khtml::HTMLTokenizer::scriptHandler): (khtml::HTMLTokenizer::scriptExecution): (khtml::HTMLTokenizer::parseComment): (khtml::HTMLTokenizer::parseServer): (khtml::HTMLTokenizer::parseProcessingInstruction): (khtml::HTMLTokenizer::parseText): (khtml::HTMLTokenizer::parseEntity): (khtml::HTMLTokenizer::parseTag): (khtml::HTMLTokenizer::continueProcessing): (khtml::HTMLTokenizer::write): (khtml::HTMLTokenizer::allDataProcessed): (khtml::HTMLTokenizer::end): (khtml::HTMLTokenizer::finish): (khtml::HTMLTokenizer::notifyFinished): (khtml::HTMLTokenizer::isWaitingForScripts):
  • khtml/html/htmltokenizer.h: (khtml::HTMLTokenizer::): (khtml::HTMLTokenizer::State::State): (khtml::HTMLTokenizer::State::tagState): (khtml::HTMLTokenizer::State::setTagState): (khtml::HTMLTokenizer::State::entityState): (khtml::HTMLTokenizer::State::setEntityState): (khtml::HTMLTokenizer::State::inScript): (khtml::HTMLTokenizer::State::setInScript): (khtml::HTMLTokenizer::State::inStyle): (khtml::HTMLTokenizer::State::setInStyle): (khtml::HTMLTokenizer::State::inSelect): (khtml::HTMLTokenizer::State::setInSelect): (khtml::HTMLTokenizer::State::inXmp): (khtml::HTMLTokenizer::State::setInXmp): (khtml::HTMLTokenizer::State::inTitle): (khtml::HTMLTokenizer::State::setInTitle): (khtml::HTMLTokenizer::State::inPlainText): (khtml::HTMLTokenizer::State::setInPlainText): (khtml::HTMLTokenizer::State::inProcessingInstruction): (khtml::HTMLTokenizer::State::setInProcessingInstruction): (khtml::HTMLTokenizer::State::inComment): (khtml::HTMLTokenizer::State::setInComment): (khtml::HTMLTokenizer::State::inTextArea): (khtml::HTMLTokenizer::State::setInTextArea): (khtml::HTMLTokenizer::State::escaped): (khtml::HTMLTokenizer::State::setEscaped): (khtml::HTMLTokenizer::State::inServer): (khtml::HTMLTokenizer::State::setInServer): (khtml::HTMLTokenizer::State::skipLF): (khtml::HTMLTokenizer::State::setSkipLF): (khtml::HTMLTokenizer::State::startTag): (khtml::HTMLTokenizer::State::setStartTag): (khtml::HTMLTokenizer::State::discardLF): (khtml::HTMLTokenizer::State::setDiscardLF): (khtml::HTMLTokenizer::State::allowYield): (khtml::HTMLTokenizer::State::setAllowYield): (khtml::HTMLTokenizer::State::loadingExtScript): (khtml::HTMLTokenizer::State::setLoadingExtScript): (khtml::HTMLTokenizer::State::forceSynchronous): (khtml::HTMLTokenizer::State::setForceSynchronous): (khtml::HTMLTokenizer::State::inAnySpecial): (khtml::HTMLTokenizer::State::hasTagState): (khtml::HTMLTokenizer::State::hasEntityState): (khtml::HTMLTokenizer::State::): (khtml::HTMLTokenizer::State::setBit): (khtml::HTMLTokenizer::State::testBit):
  • khtml/rendering/bidi.cpp: (khtml::RenderBlock::checkLinesForTextOverflow):
  • khtml/rendering/render_block.cpp: (khtml::RenderBlock::updateFirstLetter):
  • khtml/rendering/render_flow.cpp: (RenderFlow::caretRect):
  • khtml/rendering/render_line.cpp: (khtml::EllipsisBox::paint):
  • khtml/rendering/render_object.cpp: (RenderObject::firstLineStyle):
  • khtml/rendering/render_object.h: (khtml::RenderObject::style):
Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r10857 r10867  
     12005-10-17  Maciej Stachowiak  <mjs@apple.com>
     2
     3        Reviewed by Geoff. Code changes by Darin.
     4
     5        - some micro-optimizations to FastMalloc to reduce math and branches.
     6
     7        * kxmlcore/FastMalloc.cpp:
     8        (KXMLCore::TCMalloc_Central_FreeList::Populate):
     9        (KXMLCore::fastMallocRegisterThread):
     10        (KXMLCore::TCMalloc_ThreadCache::GetCache):
     11        (KXMLCore::TCMalloc_ThreadCache::GetCacheIfPresent):
     12
    1132005-10-15  Maciej Stachowiak  <mjs@apple.com>
    214
  • trunk/JavaScriptCore/kxmlcore/FastMalloc.cpp

    r10703 r10867  
    12351235  const size_t size = ByteSizeForClass(size_class_);
    12361236  int num = 0;
    1237   while (ptr + size <= limit) {
     1237  char* nptr;
     1238  while ((nptr = ptr + size) <= limit) {
    12381239    *tail = ptr;
    12391240    tail = reinterpret_cast<void**>(ptr);
    1240     ptr += size;
     1241    ptr = nptr;
    12411242    num++;
    12421243  }
     
    13941395        // And other threads can't get it wrong because they must have gone through
    13951396        // this function before allocating so they've synchronized.
     1397        // Also, mainThreadCache is only set when isMultiThreaded is false,
     1398        // to save a branchin some cases.
    13961399        SpinLockHolder lock(&multiThreadedLock);
    13971400        isMultiThreaded = true;
    1398     }
    1399 }
    1400 
    1401 inline TCMalloc_ThreadCache* TCMalloc_ThreadCache::GetCache() {
     1401        mainThreadCache = 0;
     1402    }
     1403}
     1404
     1405ALWAYS_INLINE TCMalloc_ThreadCache* TCMalloc_ThreadCache::GetCache() {
    14021406  void* ptr = NULL;
    14031407  if (!tsd_inited) {
    14041408    InitModule();
    14051409  } else {
    1406       if (!isMultiThreaded)
     1410      if (mainThreadCache)
    14071411          ptr = mainThreadCache;
    14081412      else
     
    14171421// already cleaned up the cache for this thread.
    14181422inline TCMalloc_ThreadCache* TCMalloc_ThreadCache::GetCacheIfPresent() {
    1419   if (!isMultiThreaded)
     1423  if (mainThreadCache)
    14201424      return mainThreadCache;
    14211425  if (!tsd_inited) return NULL;
  • trunk/WebCore/ChangeLog-2005-12-19

    r10866 r10867  
     12005-10-17  Maciej Stachowiak  <mjs@apple.com>
     2
     3        Reviewed by Geoff.
     4
     5        Speed up the tokenizer by keeping more state on the stack instead of in the object,
     6        to avoid load-store traffic. About a .5% speedup.
     7
     8        * khtml/html/htmltokenizer.cpp:
     9        (khtml::HTMLTokenizer::HTMLTokenizer):
     10        (khtml::HTMLTokenizer::reset):
     11        (khtml::HTMLTokenizer::begin):
     12        (khtml::HTMLTokenizer::setForceSynchronous):
     13        (khtml::HTMLTokenizer::processListing):
     14        (khtml::HTMLTokenizer::parseSpecial):
     15        (khtml::HTMLTokenizer::scriptHandler):
     16        (khtml::HTMLTokenizer::scriptExecution):
     17        (khtml::HTMLTokenizer::parseComment):
     18        (khtml::HTMLTokenizer::parseServer):
     19        (khtml::HTMLTokenizer::parseProcessingInstruction):
     20        (khtml::HTMLTokenizer::parseText):
     21        (khtml::HTMLTokenizer::parseEntity):
     22        (khtml::HTMLTokenizer::parseTag):
     23        (khtml::HTMLTokenizer::continueProcessing):
     24        (khtml::HTMLTokenizer::write):
     25        (khtml::HTMLTokenizer::allDataProcessed):
     26        (khtml::HTMLTokenizer::end):
     27        (khtml::HTMLTokenizer::finish):
     28        (khtml::HTMLTokenizer::notifyFinished):
     29        (khtml::HTMLTokenizer::isWaitingForScripts):
     30        * khtml/html/htmltokenizer.h:
     31        (khtml::HTMLTokenizer::):
     32        (khtml::HTMLTokenizer::State::State):
     33        (khtml::HTMLTokenizer::State::tagState):
     34        (khtml::HTMLTokenizer::State::setTagState):
     35        (khtml::HTMLTokenizer::State::entityState):
     36        (khtml::HTMLTokenizer::State::setEntityState):
     37        (khtml::HTMLTokenizer::State::inScript):
     38        (khtml::HTMLTokenizer::State::setInScript):
     39        (khtml::HTMLTokenizer::State::inStyle):
     40        (khtml::HTMLTokenizer::State::setInStyle):
     41        (khtml::HTMLTokenizer::State::inSelect):
     42        (khtml::HTMLTokenizer::State::setInSelect):
     43        (khtml::HTMLTokenizer::State::inXmp):
     44        (khtml::HTMLTokenizer::State::setInXmp):
     45        (khtml::HTMLTokenizer::State::inTitle):
     46        (khtml::HTMLTokenizer::State::setInTitle):
     47        (khtml::HTMLTokenizer::State::inPlainText):
     48        (khtml::HTMLTokenizer::State::setInPlainText):
     49        (khtml::HTMLTokenizer::State::inProcessingInstruction):
     50        (khtml::HTMLTokenizer::State::setInProcessingInstruction):
     51        (khtml::HTMLTokenizer::State::inComment):
     52        (khtml::HTMLTokenizer::State::setInComment):
     53        (khtml::HTMLTokenizer::State::inTextArea):
     54        (khtml::HTMLTokenizer::State::setInTextArea):
     55        (khtml::HTMLTokenizer::State::escaped):
     56        (khtml::HTMLTokenizer::State::setEscaped):
     57        (khtml::HTMLTokenizer::State::inServer):
     58        (khtml::HTMLTokenizer::State::setInServer):
     59        (khtml::HTMLTokenizer::State::skipLF):
     60        (khtml::HTMLTokenizer::State::setSkipLF):
     61        (khtml::HTMLTokenizer::State::startTag):
     62        (khtml::HTMLTokenizer::State::setStartTag):
     63        (khtml::HTMLTokenizer::State::discardLF):
     64        (khtml::HTMLTokenizer::State::setDiscardLF):
     65        (khtml::HTMLTokenizer::State::allowYield):
     66        (khtml::HTMLTokenizer::State::setAllowYield):
     67        (khtml::HTMLTokenizer::State::loadingExtScript):
     68        (khtml::HTMLTokenizer::State::setLoadingExtScript):
     69        (khtml::HTMLTokenizer::State::forceSynchronous):
     70        (khtml::HTMLTokenizer::State::setForceSynchronous):
     71        (khtml::HTMLTokenizer::State::inAnySpecial):
     72        (khtml::HTMLTokenizer::State::hasTagState):
     73        (khtml::HTMLTokenizer::State::hasEntityState):
     74        (khtml::HTMLTokenizer::State::):
     75        (khtml::HTMLTokenizer::State::setBit):
     76        (khtml::HTMLTokenizer::State::testBit):
     77        * khtml/rendering/bidi.cpp:
     78        (khtml::RenderBlock::checkLinesForTextOverflow):
     79        * khtml/rendering/render_block.cpp:
     80        (khtml::RenderBlock::updateFirstLetter):
     81        * khtml/rendering/render_flow.cpp:
     82        (RenderFlow::caretRect):
     83        * khtml/rendering/render_line.cpp:
     84        (khtml::EllipsisBox::paint):
     85        * khtml/rendering/render_object.cpp:
     86        (RenderObject::firstLineStyle):
     87        * khtml/rendering/render_object.h:
     88        (khtml::RenderObject::style):
     89
    1902005-10-17  Maciej Stachowiak  <mjs@apple.com>
    291
  • trunk/WebCore/khtml/html/htmltokenizer.cpp

    r10854 r10867  
    173173    parser = new HTMLParser(_view, _doc, includesComments);
    174174    m_executingScript = 0;
    175     loadingExtScript = false;
    176175    onHold = false;
    177176    timerId = 0;
     
    192191    parser = new HTMLParser(i, _doc, includesComments);
    193192    m_executingScript = 0;
    194     loadingExtScript = false;
    195193    onHold = false;
    196194    timerId = 0;
     
    212210    }
    213211   
    214     if ( buffer )
     212    if (buffer)
    215213        KHTML_DELETE_QCHAR_VEC(buffer);
    216214    buffer = dest = 0;
    217215    size = 0;
    218216
    219     if ( scriptCode )
     217    if (scriptCode)
    220218        KHTML_DELETE_QCHAR_VEC(scriptCode);
    221219    scriptCode = 0;
     
    227225    }
    228226    timerId = 0;
    229     allowYield = false;
    230     forceSynchronous = false;
     227    m_state.setAllowYield(false);
     228    m_state.setForceSynchronous(false);
    231229
    232230    currToken.reset();
     
    236234{
    237235    m_executingScript = 0;
    238     loadingExtScript = false;
     236    m_state.setLoadingExtScript(false);
    239237    onHold = false;
    240238    reset();
     
    242240    buffer = KHTML_ALLOC_QCHAR_VEC( 255 );
    243241    dest = buffer;
    244     tag = NoTag;
    245     discard = NoneDiscard;
    246     plaintext = false;
    247     xmp = false;
    248     processingInstruction = false;
    249     script = false;
    250     escaped = false;
    251     style = false;
    252     skipLF = false;
    253     select = false;
    254     comment = false;
    255     server = false;
    256     textarea = false;
    257     title = false;
    258     startTag = false;
    259242    tquote = NoQuote;
    260243    searchCount = 0;
    261     Entity = NoEntity;
    262     loadingExtScript = false;
     244    m_state.setEntityState(NoEntity);
    263245    scriptSrc = QString::null;
    264246    pendingSrc.clear();
     
    270252    scriptStartLineno = 0;
    271253    tagStartLineno = 0;
    272     forceSynchronous = false;
     254    m_state.setForceSynchronous(false);
    273255}
    274256
    275257void HTMLTokenizer::setForceSynchronous(bool force)
    276258{
    277     forceSynchronous = force;
    278 }
    279 
    280 void HTMLTokenizer::processListing(TokenizerString list)
     259    m_state.setForceSynchronous(force);
     260}
     261
     262HTMLTokenizer::State HTMLTokenizer::processListing(TokenizerString list, State state)
    281263{
    282264    // This function adds the listing 'list' as
     
    285267        checkBuffer();
    286268
    287         if (skipLF && *list != '\n')
    288             skipLF = false;
    289 
    290         if (skipLF) {
    291             skipLF = false;
     269        if (state.skipLF() && *list != '\n')
     270            state.setSkipLF(false);
     271
     272        if (state.skipLF()) {
     273            state.setSkipLF(false);
    292274            ++list;
    293275        } else if (*list == '\n' || *list == '\r') {
    294             if (discard == LFDiscard)
     276            if (state.discardLF())
    295277                // Ignore this LF
    296                 discard = NoneDiscard; // We have discarded 1 LF
     278                state.setDiscardLF(false); // We have discarded 1 LF
    297279            else
    298280                *dest++ = '\n';
     
    300282            /* Check for MS-DOS CRLF sequence */
    301283            if (*list == '\r')
    302                 skipLF = true;
     284                state.setSkipLF(true);
    303285
    304286            ++list;
    305287        } else {
    306             discard = NoneDiscard;
     288            state.setDiscardLF(false);
    307289            *dest++ = *list;
    308290            ++list;
    309291        }
    310292    }
    311 }
    312 
    313 void HTMLTokenizer::parseSpecial(TokenizerString &src)
    314 {
    315     assert( textarea || title || !Entity );
    316     assert( !tag );
    317     assert( xmp+textarea+title+style+script == 1 );
    318     if (script)
    319         scriptStartLineno = lineno+src.lineCount();
    320 
    321     if ( comment ) parseComment( src );
     293
     294    return state;
     295}
     296
     297HTMLTokenizer::State HTMLTokenizer::parseSpecial(TokenizerString &src, State state)
     298{
     299    assert(state.inTextArea() || state.inTitle() || !state.hasEntityState());
     300    assert(!state.hasTagState());
     301    assert(state.inXmp() + state.inTextArea() + state.inTitle() + state.inStyle() + state.inScript() == 1 );
     302    if (state.inScript())
     303        scriptStartLineno = lineno + src.lineCount();
     304
     305    if (state.inComment())
     306        state = parseComment(src, state);
    322307
    323308    while ( !src.isEmpty() ) {
    324309        checkScriptBuffer();
    325310        unsigned char ch = src->latin1();
    326         if ( !scriptCodeResync && !brokenComments && !textarea && !xmp && !title && ch == '-' && scriptCodeSize >= 3 && !src.escaped() && scriptCode[scriptCodeSize-3] == '<' && scriptCode[scriptCodeSize-2] == '!' && scriptCode[scriptCodeSize-1] == '-' ) {
    327             comment = true;
    328             parseComment( src );
     311        if (!scriptCodeResync && !brokenComments && !state.inTextArea() && !state.inXmp() && !state.inTitle() && ch == '-' && scriptCodeSize >= 3 && !src.escaped() && scriptCode[scriptCodeSize-3] == '<' && scriptCode[scriptCodeSize-2] == '!' && scriptCode[scriptCodeSize-1] == '-') {
     312            state.setInComment(true);
     313            state = parseComment(src, state);
    329314            continue;
    330315        }
     
    334319            scriptCodeResync = 0;
    335320            scriptCode[ scriptCodeSize ] = scriptCode[ scriptCodeSize + 1 ] = 0;
    336             if ( script )
    337                 scriptHandler();
     321            if (state.inScript())
     322                state = scriptHandler(state);
    338323            else {
    339                 processListing(TokenizerString(scriptCode, scriptCodeSize));
     324                state = processListing(TokenizerString(scriptCode, scriptCodeSize), state);
    340325                processToken();
    341                 if ( style )         { currToken.tagName = styleTag.localName(); currToken.beginTag = false; }
    342                 else if ( textarea ) { currToken.tagName = textareaTag.localName(); currToken.beginTag = false; }
    343                 else if ( title ) { currToken.tagName = titleTag.localName(); currToken.beginTag = false; }
    344                 else if ( xmp )  { currToken.tagName = xmpTag.localName(); currToken.beginTag = false; }
     326                if (state.inStyle()) {
     327                    currToken.tagName = styleTag.localName();
     328                    currToken.beginTag = false;
     329                } else if (state.inTextArea()) {
     330                    currToken.tagName = textareaTag.localName();
     331                    currToken.beginTag = false;
     332                } else if (state.inTitle()) {
     333                    currToken.tagName = titleTag.localName();
     334                    currToken.beginTag = false;
     335                } else if (state.inXmp()) {
     336                    currToken.tagName = xmpTag.localName();
     337                    currToken.beginTag = false;
     338                }
    345339                processToken();
    346                 style = script = style = textarea = title = xmp = false;
     340                state.setInStyle(false);
     341                state.setInScript(false);
     342                state.setInTextArea(false);
     343                state.setInTitle(false);
     344                state.setInXmp(false);
    347345                tquote = NoQuote;
    348346                scriptCodeSize = scriptCodeResync = 0;
    349347            }
    350             return;
     348            return state;
    351349        }
    352350        // possible end of tagname, lets check.
    353         if ( !scriptCodeResync && !escaped && !src.escaped() && ( ch == '>' || ch == '/' || ch <= ' ' ) && ch &&
     351        if ( !scriptCodeResync && !state.escaped() && !src.escaped() && ( ch == '>' || ch == '/' || ch <= ' ' ) && ch &&
    354352             scriptCodeSize >= searchStopperLen &&
    355353             tagMatch( searchStopper, scriptCode+scriptCodeSize-searchStopperLen, searchStopperLen )) {
     
    358356            continue;
    359357        }
    360         if ( scriptCodeResync && !escaped ) {
     358        if ( scriptCodeResync && !state.escaped() ) {
    361359            if(ch == '\"')
    362360                tquote = (tquote == NoQuote) ? DoubleQuote : ((tquote == SingleQuote) ? SingleQuote : NoQuote);
     
    366364                tquote = NoQuote;
    367365        }
    368         escaped = ( !escaped && ch == '\\' );
    369         if (!scriptCodeResync && (textarea||title) && !src.escaped() && ch == '&') {
     366        state.setEscaped(!state.escaped() && ch == '\\');
     367        if (!scriptCodeResync && (state.inTextArea() || state.inTitle()) && !src.escaped() && ch == '&') {
    370368            QChar *scriptCodeDest = scriptCode+scriptCodeSize;
    371369            ++src;
    372             parseEntity(src,scriptCodeDest,true);
     370            state = parseEntity(src, scriptCodeDest, state, m_cBufferPos, true, false);
    373371            scriptCodeSize = scriptCodeDest-scriptCode;
    374372        }
     
    379377        }
    380378    }
    381 }
    382 
    383 void HTMLTokenizer::scriptHandler()
     379
     380    return state;
     381}
     382
     383HTMLTokenizer::State HTMLTokenizer::scriptHandler(State state)
    384384{
    385385    // We are inside a <script>
     
    413413        doScriptExec = true;
    414414    }
    415     processListing(TokenizerString(scriptCode, scriptCodeSize));
     415    state = processListing(TokenizerString(scriptCode, scriptCodeSize), state);
    416416    QString exScript( buffer, dest-buffer );
    417417    processToken();
     
    435435            setSrc(TokenizerString());
    436436            scriptCodeSize = scriptCodeResync = 0;
     437
     438            // the ref() call below may call notifyFinished if the script is already in cache,
     439            // and that mucks with the state directly, so we must write it back to the object.
     440            m_state = state;
    437441            cs->ref(this);
     442            state = m_state;
    438443            // will be 0 if script was already loaded and ref() executed it
    439444            if (!pendingScripts.isEmpty())
    440                 loadingExtScript = true;
     445                state.setLoadingExtScript(true);
    441446        }
    442447        else if (view && doScriptExec && javascript ) {
     
    449454            //QTime dt;
    450455            //dt.start();
    451             scriptExecution( exScript, QString::null, scriptStartLineno );
     456            state = scriptExecution(exScript, state, QString::null, scriptStartLineno);
    452457            //kdDebug( 6036 ) << "script execution time:" << dt.elapsed() << endl;
    453458        }
    454459    }
    455460
    456     script = false;
     461    state.setInScript(false);
    457462    scriptCodeSize = scriptCodeResync = 0;
    458463
    459     if ( !m_executingScript && !loadingExtScript ) {
     464    if (!m_executingScript && !state.loadingExtScript()) {
    460465        // kdDebug( 6036 ) << "adding pending Output to parsed string" << endl;
    461466        src.append(pendingSrc);
     
    469474        // because we want to prepend to pendingSrc rather than appending
    470475        // if there's no previous prependingSrc
    471         if (loadingExtScript) {
     476        if (state.loadingExtScript()) {
    472477            if (currentPrependingSrc) {
    473478                currentPrependingSrc->append(prependingSrc);
     
    476481            }
    477482        } else {
     483            m_state = state;
    478484            write(prependingSrc, false);
     485            state = m_state;
    479486        }
    480487    }
    481488
    482489    currentPrependingSrc = savedPrependingSrc;
    483 }
    484 
    485 void HTMLTokenizer::scriptExecution( const QString& str, QString scriptURL,
    486                                      int baseLine)
     490
     491    return state;
     492}
     493
     494HTMLTokenizer::State HTMLTokenizer::scriptExecution(const QString& str, State state,
     495                                                    QString scriptURL, int baseLine)
    487496{
    488497#if APPLE_CHANGES
    489498    if (!view || !view->part())
    490         return;
    491 #endif
    492     bool oldscript = script;
     499        return state;
     500#endif
     501    bool oldscript = state.inScript();
    493502    m_executingScript++;
    494     script = false;
     503    state.setInScript(false);
    495504    QString url;   
    496505    if (scriptURL.isNull())
     
    508517#endif
    509518
     519    m_state = state;
    510520    view->part()->executeScript(url,baseLine,0,str);
    511 
    512     allowYield = true;
     521    state = m_state;
     522
     523    state.setAllowYield(true);
    513524
    514525#ifdef INSTRUMENT_LAYOUT_SCHEDULING
     
    518529   
    519530    m_executingScript--;
    520     script = oldscript;
    521 
    522     if ( !m_executingScript && !loadingExtScript ) {
     531    state.setInScript(oldscript);
     532
     533    if (!m_executingScript && !state.loadingExtScript()) {
    523534        // kdDebug( 6036 ) << "adding pending Output to parsed string" << endl;
    524535        src.append(pendingSrc);
     
    532543        // because we want to prepend to pendingSrc rather than appending
    533544        // if there's no previous prependingSrc
    534         if (loadingExtScript) {
     545        if (state.loadingExtScript()) {
    535546            if (currentPrependingSrc) {
    536547                currentPrependingSrc->append(prependingSrc);
     
    539550            }
    540551        } else {
     552            m_state = state;
    541553            write(prependingSrc, false);
     554            state = m_state;
    542555        }
    543556    }
    544557
    545558    currentPrependingSrc = savedPrependingSrc;
    546 }
    547 
    548 void HTMLTokenizer::parseComment(TokenizerString &src)
     559
     560    return state;
     561}
     562
     563HTMLTokenizer::State HTMLTokenizer::parseComment(TokenizerString &src, State state)
    549564{
    550565    // FIXME: Why does this code even run for comments inside <script> and <style>? This seems bogus.
    551     bool strict = !parser->doc()->inCompatMode() && !script && !style;
     566    bool strict = !parser->doc()->inCompatMode() && !state.inScript() && !state.inStyle();
    552567    int delimiterCount = 0;
    553568    bool canClose = false;
     
    573588
    574589        if ((!strict || canClose) && src->unicode() == '>') {
    575             bool handleBrokenComments = brokenComments && !(script || style);
     590            bool handleBrokenComments = brokenComments && !(state.inScript() || state.inStyle());
    576591            int endCharsCount = 1; // start off with one for the '>' character
    577592            if (!strict) {
     
    589604            if (canClose || handleBrokenComments || endCharsCount > 1) {
    590605                ++src;
    591                 if (!( script || xmp || textarea || style)) {
     606                if (!(state.inScript() || state.inXmp() || state.inTextArea() || state.inStyle())) {
    592607                    if (includesCommentsInDOM) {
    593608                        checkScriptBuffer();
     
    596611                        currToken.tagName = commentAtom;
    597612                        currToken.beginTag = true;
    598                         processListing(TokenizerString(scriptCode, scriptCodeSize - endCharsCount));
     613                        state = processListing(TokenizerString(scriptCode, scriptCodeSize - endCharsCount), state);
    599614                        processToken();
    600615                        currToken.tagName = commentAtom;
     
    604619                    scriptCodeSize = 0;
    605620                }
    606                 comment = false;
    607                 return; // Finished parsing comment
     621                state.setInComment(false);
     622                return state; // Finished parsing comment
    608623            }
    609624        }
    610625        ++src;
    611626    }
    612 }
    613 
    614 void HTMLTokenizer::parseServer(TokenizerString &src)
     627
     628    return state;
     629}
     630
     631HTMLTokenizer::State HTMLTokenizer::parseServer(TokenizerString& src, State state)
    615632{
    616633    checkScriptBuffer(src.length());
    617     while ( !src.isEmpty() ) {
    618         scriptCode[ scriptCodeSize++ ] = *src;
     634    while (!src.isEmpty()) {
     635        scriptCode[scriptCodeSize++] = *src;
    619636        if (src->unicode() == '>' &&
    620637            scriptCodeSize > 1 && scriptCode[scriptCodeSize-2] == '%') {
    621638            ++src;
    622             server = false;
     639            state.setInServer(false);
    623640            scriptCodeSize = 0;
    624             return; // Finished parsing server include
     641            return state; // Finished parsing server include
    625642        }
    626643        ++src;
    627644    }
    628 }
    629 
    630 void HTMLTokenizer::parseProcessingInstruction(TokenizerString &src)
     645    return state;
     646}
     647
     648HTMLTokenizer::State HTMLTokenizer::parseProcessingInstruction(TokenizerString &src, State state)
    631649{
    632650    char oldchar = 0;
     
    646664        {
    647665            // We got a '?>' sequence
    648             processingInstruction = false;
     666            state.setInProcessingInstruction(false);
    649667            ++src;
    650             discard = LFDiscard;
    651             return; // Finished parsing comment!
     668            state.setDiscardLF(true);
     669            return state; // Finished parsing comment!
    652670        }
    653671        ++src;
    654672        oldchar = chbegin;
    655673    }
    656 }
    657 
    658 void HTMLTokenizer::parseText(TokenizerString &src)
    659 {
    660     while ( !src.isEmpty() )
     674   
     675    return state;
     676}
     677
     678HTMLTokenizer::State HTMLTokenizer::parseText(TokenizerString &src, State state)
     679{
     680    while (!src.isEmpty())
    661681    {
    662682        // do we need to enlarge the buffer?
     
    666686        unsigned char chbegin = src->latin1();
    667687
    668         if (skipLF && ( chbegin != '\n' ))
     688        if (state.skipLF() && (chbegin != '\n' ))
     689            state.setSkipLF(false);
     690
     691        if (state.skipLF())
    669692        {
    670             skipLF = false;
    671         }
    672 
    673         if (skipLF)
    674         {
    675             skipLF = false;
     693            state.setSkipLF(false);
    676694            ++src;
    677         }
    678         else if (( chbegin == '\n' ) || ( chbegin == '\r' ))
     695        } else if ((chbegin == '\n') || (chbegin == '\r'))
    679696        {
    680697            if (chbegin == '\r')
    681                 skipLF = true;
     698                state.setSkipLF(true);
    682699
    683700            *dest++ = '\n';
     
    691708        }
    692709    }
    693 }
    694 
    695 
    696 void HTMLTokenizer::parseEntity(TokenizerString &src, QChar *&dest, bool start)
    697 {
    698     if( start )
     710
     711    return state;
     712}
     713
     714
     715HTMLTokenizer::State HTMLTokenizer::parseEntity(TokenizerString &src, QChar *&dest, State state, unsigned &cBufferPos, bool start, bool parsingTag)
     716{
     717    if (start)
    699718    {
    700719        cBufferPos = 0;
    701         Entity = SearchEntity;
     720        state.setEntityState(SearchEntity);
    702721        EntityUnicodeValue = 0;
    703722    }
    704723
    705     while( !src.isEmpty() )
     724    while(!src.isEmpty())
    706725    {
    707726        ushort cc = src->unicode();
    708         switch(Entity) {
     727        switch(state.entityState()) {
    709728        case NoEntity:
    710             assert(Entity != NoEntity);
    711             return;
     729            assert(state.entityState() != NoEntity);
     730            return state;
    712731       
    713732        case SearchEntity:
     
    715734                cBuffer[cBufferPos++] = cc;
    716735                ++src;
    717                 Entity = NumericSearch;
     736                state.setEntityState(NumericSearch);
    718737            }
    719738            else
    720                 Entity = EntityName;
     739                state.setEntityState(EntityName);
    721740
    722741            break;
     
    726745                cBuffer[cBufferPos++] = cc;
    727746                ++src;
    728                 Entity = Hexadecimal;
     747                state.setEntityState(Hexadecimal);
    729748            }
    730749            else if(cc >= '0' && cc <= '9')
    731                 Entity = Decimal;
     750                state.setEntityState(Decimal);
    732751            else
    733                 Entity = SearchSemicolon;
     752                state.setEntityState(SearchSemicolon);
    734753
    735754            break;
     
    743762
    744763                if(csrc.row() || !((cc >= '0' && cc <= '9') || (cc >= 'a' && cc <= 'f'))) {
    745                     Entity = SearchSemicolon;
     764                    state.setEntityState(SearchSemicolon);
    746765                    break;
    747766                }
     
    750769                ++src;
    751770            }
    752             if(cBufferPos == 10)  Entity = SearchSemicolon;
     771            if (cBufferPos == 10) 
     772                state.setEntityState(SearchSemicolon);
    753773            break;
    754774        }
     
    760780
    761781                if(src->row() || !(cc >= '0' && cc <= '9')) {
    762                     Entity = SearchSemicolon;
     782                    state.setEntityState(SearchSemicolon);
    763783                    break;
    764784                }
     
    768788                ++src;
    769789            }
    770             if(cBufferPos == 9)  Entity = SearchSemicolon;
     790            if (cBufferPos == 9) 
     791                state.setEntityState(SearchSemicolon);
    771792            break;
    772793        }
     
    780801                if(csrc.row() || !((cc >= 'a' && cc <= 'z') ||
    781802                                   (cc >= '0' && cc <= '9') || (cc >= 'A' && cc <= 'Z'))) {
    782                     Entity = SearchSemicolon;
     803                    state.setEntityState(SearchSemicolon);
    783804                    break;
    784805                }
     
    787808                ++src;
    788809            }
    789             if(cBufferPos == 9) Entity = SearchSemicolon;
    790             if(Entity == SearchSemicolon) {
     810            if (cBufferPos == 9)
     811                state.setEntityState(SearchSemicolon);
     812            if (state.entityState() == SearchSemicolon) {
    791813                if(cBufferPos > 1) {
    792814                    const entity *e = findEntity(cBuffer, cBufferPos);
     
    795817
    796818                    // be IE compatible
    797                     if(tag && EntityUnicodeValue > 255 && *src != ';')
     819                    if(parsingTag && EntityUnicodeValue > 255 && *src != ';')
    798820                        EntityUnicodeValue = 0;
    799821                }
     
    839861            }
    840862
    841             Entity = NoEntity;
    842             return;
    843         }
    844     }
    845 }
    846 
    847 void HTMLTokenizer::parseTag(TokenizerString &src)
    848 {
    849     assert(!Entity );
    850 
    851     while ( !src.isEmpty() )
     863            state.setEntityState(NoEntity);
     864            return state;
     865        }
     866    }
     867
     868    return state;
     869}
     870
     871HTMLTokenizer::State HTMLTokenizer::parseTag(TokenizerString &src, State state)
     872{
     873    assert(!state.hasEntityState());
     874
     875    unsigned cBufferPos = m_cBufferPos;
     876
     877    while (!src.isEmpty())
    852878    {
    853879        checkBuffer();
     
    859885               QConstString((QChar*)src.operator->(), l).qstring().latin1(), tquote);
    860886#endif
    861         switch(tag) {
     887        switch(state.tagState()) {
    862888        case NoTag:
    863889        {
    864             return;
     890            m_cBufferPos = cBufferPos;
     891            return state;
    865892        }
    866893        case TagName:
     
    882909                        ++src;
    883910                        dest = buffer; // ignore the previous part of this tag
    884                         comment = true;
    885                         tag = NoTag;
     911                        state.setInComment(true);
     912                        state.setTagState(NoTag);
    886913
    887914                        // Fix bug 34302 at kde.bugs.org.  Go ahead and treat
     
    889916                        // can handle this case.  Only do this in quirks mode. -dwh
    890917                        if (!src.isEmpty() && *src == '>' && parser->doc()->inCompatMode()) {
    891                           comment = false;
     918                          state.setInComment(false);
    892919                          ++src;
    893920                          if (!src.isEmpty())
     
    895922                        }
    896923                        else
    897                           parseComment(src);
    898 
    899                         return; // Finished parsing tag!
     924                          state = parseComment(src, state);
     925
     926                        m_cBufferPos = cBufferPos;
     927                        return state; // Finished parsing tag!
    900928                    }
    901929                    // cuts of high part, is okay
     
    953981                }
    954982                dest = buffer;
    955                 tag = SearchAttribute;
     983                state.setTagState(SearchAttribute);
    956984                cBufferPos = 0;
    957985            }
     
    970998                if (curchar > ' ' && curchar != '\'' && curchar != '"') {
    971999                    if (curchar == '<' || curchar == '>')
    972                         tag = SearchEnd;
     1000                        state.setTagState(SearchEnd);
    9731001                    else
    974                         tag = AttributeName;
     1002                        state.setTagState(AttributeName);
    9751003
    9761004                    cBufferPos = 0;
     
    9971025                    dest = buffer;
    9981026                    *dest++ = 0;
    999                     tag = SearchEqual;
     1027                    state.setTagState(SearchEqual);
    10001028                    // This is a deliberate quirk to match Mozilla and Opera.  We have to do this
    10011029                    // since sites that use the "standards-compliant" path sometimes send
     
    10201048                dest = buffer;
    10211049                *dest++ = 0;
    1022                 tag = SearchEqual;
     1050                state.setTagState(SearchEqual);
    10231051            }
    10241052            break;
     
    10391067                        kdDebug(6036) << "found equal" << endl;
    10401068#endif
    1041                         tag = SearchValue;
     1069                        state.setTagState(SearchValue);
    10421070                        ++src;
    10431071                    }
     
    10451073                        currToken.addAttribute(parser->docPtr()->document(), attrName, emptyAtom);
    10461074                        dest = buffer;
    1047                         tag = SearchAttribute;
     1075                        state.setTagState(SearchAttribute);
    10481076                    }
    10491077                    break;
     
    10621090                    if(( curchar == '\'' || curchar == '\"' )) {
    10631091                        tquote = curchar == '\"' ? DoubleQuote : SingleQuote;
    1064                         tag = QuotedValue;
     1092                        state.setTagState(QuotedValue);
    10651093                        ++src;
    10661094                    } else
    1067                         tag = Value;
     1095                        state.setTagState(Value);
    10681096
    10691097                    break;
     
    10961124                    attrName = v; // Just make the name/value match. (FIXME: Is this some WinIE quirk?)
    10971125                    currToken.addAttribute(parser->docPtr()->document(), attrName, v);
    1098                     tag = SearchAttribute;
     1126                    state.setTagState(SearchAttribute);
    10991127                    dest = buffer;
    11001128                    tquote = NoQuote;
     
    11071135                    {
    11081136                        ++src;
    1109                         parseEntity(src, dest, true);
     1137                        state = parseEntity(src, dest, state, cBufferPos, true, true);
    11101138                        break;
    11111139                    }
     
    11221150
    11231151                        dest = buffer;
    1124                         tag = SearchAttribute;
     1152                        state.setTagState(SearchAttribute);
    11251153                        tquote = NoQuote;
    11261154                        ++src;
     
    11491177                    {
    11501178                        ++src;
    1151                         parseEntity(src, dest, true);
     1179                        state = parseEntity(src, dest, state, cBufferPos, true, true);
    11521180                        break;
    11531181                    }
     
    11591187                        currToken.addAttribute(parser->docPtr()->document(), attrName, v);
    11601188                        dest = buffer;
    1161                         tag = SearchAttribute;
     1189                        state.setTagState(SearchAttribute);
    11621190                        break;
    11631191                    }
     
    11881216
    11891217            searchCount = 0; // Stop looking for '<!--' sequence
    1190             tag = NoTag;
     1218            state.setTagState(NoTag);
    11911219            tquote = NoQuote;
    11921220
     
    11941222                ++src;
    11951223
    1196             if (currToken.tagName == nullAtom) //stop if tag is unknown
    1197                 return;
     1224            if (currToken.tagName == nullAtom) { //stop if tag is unknown
     1225                m_cBufferPos = cBufferPos;
     1226                return state;
     1227            }
    11981228
    11991229            AtomicString tagName = currToken.tagName;
     
    12821312
    12831313            if (tagName == preTag) {
    1284                 discard = LFDiscard; // Discard the first LF after we open a pre.
     1314                state.setDiscardLF(true); // Discard the first LF after we open a pre.
    12851315            } else if (tagName == scriptTag) {
    12861316                if (beginTag) {
    12871317                    searchStopper = scriptEnd;
    12881318                    searchStopperLen = 8;
    1289                     script = true;
    1290                     parseSpecial(src);
     1319                    state.setInScript(true);
     1320                    state = parseSpecial(src, state);
    12911321                } else if (isSelfClosingScript) { // Handle <script src="foo"/>
    1292                     script = true;
    1293                     scriptHandler();
     1322                    state.setInScript(true);
     1323                    state = scriptHandler(state);
    12941324                }
    12951325            } else if (tagName == styleTag) {
     
    12971327                    searchStopper = styleEnd;
    12981328                    searchStopperLen = 7;
    1299                     style = true;
    1300                     parseSpecial(src);
     1329                    state.setInStyle(true);
     1330                    state = parseSpecial(src, state);
    13011331                }
    13021332            } else if (tagName == textareaTag) {
     
    13041334                    searchStopper = textareaEnd;
    13051335                    searchStopperLen = 10;
    1306                     textarea = true;
    1307                     parseSpecial(src);
     1336                    state.setInTextArea(true);
     1337                    state = parseSpecial(src, state);
    13081338                }
    13091339            } else if (tagName == titleTag) {
     
    13111341                    searchStopper = titleEnd;
    13121342                    searchStopperLen = 7;
    1313                     title = true;
    1314                     parseSpecial(src);
     1343                    state.setInTitle(true);
     1344                    state = parseSpecial(src, state);
    13151345                }
    13161346            } else if (tagName == xmpTag) {
     
    13181348                    searchStopper = xmpEnd;
    13191349                    searchStopperLen = 5;
    1320                     xmp = true;
    1321                     parseSpecial(src);
     1350                    state.setInXmp(true);
     1351                    state = parseSpecial(src, state);
    13221352                }
    13231353            } else if (tagName == selectTag)
    1324                 select = beginTag;
     1354                state.setInSelect(beginTag);
    13251355            else if (tagName == plaintextTag)
    1326                 plaintext = beginTag;
    1327             return; // Finished parsing tag!
     1356                state.setInPlainText(beginTag);
     1357            m_cBufferPos = cBufferPos;
     1358            return state; // Finished parsing tag!
    13281359        }
    13291360        } // end switch
    13301361    }
    1331     return;
    1332 }
    1333 
    1334 void HTMLTokenizer::write(const TokenizerString &str, bool appendData)
    1335 {
    1336 #ifdef TOKEN_DEBUG
    1337     kdDebug( 6036 ) << this << " Tokenizer::write(\"" << str.toString() << "\"," << appendData << ")" << endl;
    1338 #endif
    1339 
    1340     if (!buffer)
    1341         return;
    1342    
    1343     if (loadStopped)
    1344         return;
    1345 
    1346     if ( ( m_executingScript && appendData ) || !pendingScripts.isEmpty() ) {
    1347         // don't parse; we will do this later
    1348         if (currentPrependingSrc) {
    1349             currentPrependingSrc->append(str);
    1350         } else {
    1351             pendingSrc.append(str);
    1352         }
    1353         return;
    1354     }
    1355 
    1356     if ( onHold ) {
    1357         src.append(str);
    1358         return;
    1359     }
    1360    
    1361     if (!src.isEmpty())
    1362         src.append(str);
    1363     else
    1364         setSrc(str);
    1365 
    1366     // Once a timer is set, it has control of when the tokenizer continues.
    1367     if (timerId)
    1368         return;
    1369 
    1370     bool wasInWrite = inWrite;
    1371     inWrite = true;
    1372    
    1373 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
    1374     if (!parser->doc()->ownerElement())
    1375         printf("Beginning write at time %d\n", parser->doc()->elapsedTime());
    1376 #endif
    1377    
    1378 //     if (Entity)
    1379 //         parseEntity(src, dest);
    1380 
    1381     int processedCount = 0;
    1382     QTime startTime;
    1383     startTime.start();
    1384     KWQUIEventTime eventTime;
    1385 
    1386     KHTMLPart* part = parser->doc()->part();
    1387     while (!src.isEmpty() && (!part || !part->isScheduledLocationChangePending())) {
    1388         if (!continueProcessing(processedCount, startTime, eventTime))
    1389             break;
    1390 
    1391         // do we need to enlarge the buffer?
    1392         checkBuffer();
    1393 
    1394         ushort cc = src->unicode();
    1395 
    1396         if (skipLF && (cc != '\n'))
    1397             skipLF = false;
    1398 
    1399         if (skipLF) {
    1400             skipLF = false;
    1401             ++src;
    1402         }
    1403         else if ( Entity )
    1404             parseEntity( src, dest );
    1405         else if ( plaintext )
    1406             parseText( src );
    1407         else if (script)
    1408             parseSpecial(src);
    1409         else if (style)
    1410             parseSpecial(src);
    1411         else if (xmp)
    1412             parseSpecial(src);
    1413         else if (textarea)
    1414             parseSpecial(src);
    1415         else if (title)
    1416             parseSpecial(src);
    1417         else if (comment)
    1418             parseComment(src);
    1419         else if (server)
    1420             parseServer(src);
    1421         else if (processingInstruction)
    1422             parseProcessingInstruction(src);
    1423         else if (tag)
    1424             parseTag(src);
    1425         else if ( startTag )
    1426         {
    1427             startTag = false;
    1428 
    1429             switch(cc) {
    1430             case '/':
    1431                 break;
    1432             case '!':
    1433             {
    1434                 // <!-- comment -->
    1435                 searchCount = 1; // Look for '<!--' sequence to start comment
    1436 
    1437                 break;
    1438             }
    1439             case '?':
    1440             {
    1441                 // xml processing instruction
    1442                 processingInstruction = true;
    1443                 tquote = NoQuote;
    1444                 parseProcessingInstruction(src);
    1445                 continue;
    1446 
    1447                 break;
    1448             }
    1449             case '%':
    1450                 if (!brokenServer) {
    1451                     // <% server stuff, handle as comment %>
    1452                     server = true;
    1453                     tquote = NoQuote;
    1454                     parseServer(src);
    1455                     continue;
    1456                 }
    1457                 // else fall through
    1458             default:
    1459             {
    1460                 if( ((cc >= 'a') && (cc <= 'z')) || ((cc >= 'A') && (cc <= 'Z')))
    1461                 {
    1462                     // Start of a Start-Tag
    1463                 }
    1464                 else
    1465                 {
    1466                     // Invalid tag
    1467                     // Add as is
    1468                     *dest = '<';
    1469                     dest++;
    1470                     continue;
    1471                 }
    1472             }
    1473             }; // end case
    1474 
    1475             processToken();
    1476 
    1477             cBufferPos = 0;
    1478             tag = TagName;
    1479             parseTag(src);
    1480         }
    1481         else if ( cc == '&' && !src.escaped())
    1482         {
    1483             ++src;
    1484             parseEntity(src, dest, true);
    1485         }
    1486         else if ( cc == '<' && !src.escaped())
    1487         {
    1488             tagStartLineno = lineno+src.lineCount();
    1489             ++src;
    1490             startTag = true;
    1491         }
    1492         else if (cc == '\n' || cc == '\r') {
    1493             if (discard == LFDiscard)
    1494                 // Ignore this LF
    1495                 discard = NoneDiscard; // We have discarded 1 LF
    1496             else
    1497                 // Process this LF
    1498                 *dest++ = '\n';
    1499            
    1500             /* Check for MS-DOS CRLF sequence */
    1501             if (cc == '\r')
    1502                 skipLF = true;
    1503             ++src;
    1504         } else {
    1505             discard = NoneDiscard;
    1506 #if QT_VERSION < 300
    1507             unsigned char row = src->row();
    1508             if ( row > 0x05 && row < 0x10 || row > 0xfd )
    1509                     currToken.complexText = true;
    1510 #endif
    1511             *dest = *src;
    1512             fixUpChar(*dest);
    1513             ++dest;
    1514             ++src;
    1515         }
    1516     }
    1517    
    1518 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
    1519     if (!parser->doc()->ownerElement())
    1520         printf("Ending write at time %d\n", parser->doc()->elapsedTime());
    1521 #endif
    1522    
    1523     inWrite = wasInWrite;
    1524 
    1525     if (noMoreData && !inWrite && !loadingExtScript && !m_executingScript && !timerId)
    1526         end(); // this actually causes us to be deleted
    1527 }
    1528 
    1529 void HTMLTokenizer::stopped()
    1530 {
    1531     if (timerId) {
    1532         killTimer(timerId);
    1533         timerId = 0;
    1534     }
    1535 }
    1536 
    1537 bool HTMLTokenizer::processingData() const
    1538 {
    1539     return timerId != 0;
    1540 }
    1541 
    1542 bool HTMLTokenizer::continueProcessing(int& processedCount, const QTime& startTime, const KWQUIEventTime& eventTime)
     1362    m_cBufferPos = cBufferPos;
     1363    return state;
     1364}
     1365
     1366inline bool HTMLTokenizer::continueProcessing(int& processedCount, const QTime& startTime, const KWQUIEventTime& eventTime, State &state)
    15431367{
    15441368    // We don't want to be checking elapsed time with every character, so we only check after we've
    15451369    // processed a certain number of characters.
    1546     bool allowedYield = allowYield;
    1547     allowYield = false;
    1548     if (!loadingExtScript && !forceSynchronous && !m_executingScript && (processedCount > TOKENIZER_CHUNK_SIZE || allowedYield)) {
     1370    bool allowedYield = state.allowYield();
     1371    state.setAllowYield(false);
     1372    if (!state.loadingExtScript() && !state.forceSynchronous() && !m_executingScript && (processedCount > TOKENIZER_CHUNK_SIZE || allowedYield)) {
    15491373        processedCount = 0;
    15501374        if (startTime.elapsed() > TOKENIZER_TIME_DELAY) {
     
    15711395}
    15721396
     1397void HTMLTokenizer::write(const TokenizerString &str, bool appendData)
     1398{
     1399#ifdef TOKEN_DEBUG
     1400    kdDebug( 6036 ) << this << " Tokenizer::write(\"" << str.toString() << "\"," << appendData << ")" << endl;
     1401#endif
     1402
     1403    if (!buffer)
     1404        return;
     1405   
     1406    if (loadStopped)
     1407        return;
     1408
     1409    if ( ( m_executingScript && appendData ) || !pendingScripts.isEmpty() ) {
     1410        // don't parse; we will do this later
     1411        if (currentPrependingSrc) {
     1412            currentPrependingSrc->append(str);
     1413        } else {
     1414            pendingSrc.append(str);
     1415        }
     1416        return;
     1417    }
     1418
     1419    if (onHold) {
     1420        src.append(str);
     1421        return;
     1422    }
     1423   
     1424    if (!src.isEmpty())
     1425        src.append(str);
     1426    else
     1427        setSrc(str);
     1428
     1429    // Once a timer is set, it has control of when the tokenizer continues.
     1430    if (timerId)
     1431        return;
     1432
     1433    bool wasInWrite = inWrite;
     1434    inWrite = true;
     1435   
     1436#ifdef INSTRUMENT_LAYOUT_SCHEDULING
     1437    if (!parser->doc()->ownerElement())
     1438        printf("Beginning write at time %d\n", parser->doc()->elapsedTime());
     1439#endif
     1440   
     1441    int processedCount = 0;
     1442    QTime startTime;
     1443    startTime.start();
     1444    KWQUIEventTime eventTime;
     1445
     1446    KHTMLPart* part = parser->doc()->part();
     1447
     1448    State state = m_state;
     1449
     1450    while (!src.isEmpty() && (!part || !part->isScheduledLocationChangePending())) {
     1451        if (!continueProcessing(processedCount, startTime, eventTime, state))
     1452            break;
     1453
     1454        // do we need to enlarge the buffer?
     1455        checkBuffer();
     1456
     1457        ushort cc = src->unicode();
     1458
     1459        bool wasSkipLF = state.skipLF();
     1460        if (wasSkipLF)
     1461            state.setSkipLF(false);
     1462
     1463        if (wasSkipLF && (cc == '\n'))
     1464            ++src;
     1465        else if (state.needsSpecialWriteHandling()) {
     1466            // it's important to keep needsSpecialWriteHandling with the flags this block tests
     1467            if (state.hasEntityState())
     1468                state = parseEntity(src, dest, state, m_cBufferPos, false, state.hasTagState());
     1469            else if (state.inPlainText())
     1470                state = parseText(src, state);
     1471            else if (state.inAnySpecial())
     1472                state = parseSpecial(src, state);
     1473            else if (state.inComment())
     1474                state = parseComment(src, state);
     1475            else if (state.inServer())
     1476                state = parseServer(src, state);
     1477            else if (state.inProcessingInstruction())
     1478                state = parseProcessingInstruction(src, state);
     1479            else if (state.hasTagState())
     1480                state = parseTag(src, state);
     1481            else if (state.startTag()) {
     1482                state.setStartTag(false);
     1483               
     1484                switch(cc) {
     1485                case '/':
     1486                    break;
     1487                case '!': {
     1488                    // <!-- comment -->
     1489                    searchCount = 1; // Look for '<!--' sequence to start comment
     1490                   
     1491                    break;
     1492                }
     1493                case '?': {
     1494                    // xml processing instruction
     1495                    state.setInProcessingInstruction(true);
     1496                    tquote = NoQuote;
     1497                    state = parseProcessingInstruction(src, state);
     1498                    continue;
     1499
     1500                    break;
     1501                }
     1502                case '%':
     1503                    if (!brokenServer) {
     1504                        // <% server stuff, handle as comment %>
     1505                        state.setInServer(true);
     1506                        tquote = NoQuote;
     1507                        state = parseServer(src, state);
     1508                        continue;
     1509                    }
     1510                    // else fall through
     1511                default: {
     1512                    if( ((cc >= 'a') && (cc <= 'z')) || ((cc >= 'A') && (cc <= 'Z'))) {
     1513                        // Start of a Start-Tag
     1514                    } else {
     1515                        // Invalid tag
     1516                        // Add as is
     1517                        *dest = '<';
     1518                        dest++;
     1519                        continue;
     1520                    }
     1521                }
     1522                }; // end case
     1523
     1524                processToken();
     1525
     1526                m_cBufferPos = 0;
     1527                state.setTagState(TagName);
     1528                state = parseTag(src, state);
     1529            }
     1530        } else if (cc == '&' && !src.escaped()) {
     1531            ++src;
     1532            state = parseEntity(src, dest, state, m_cBufferPos, true, state.hasTagState());
     1533        } else if (cc == '<' && !src.escaped()) {
     1534            tagStartLineno = lineno+src.lineCount();
     1535            ++src;
     1536            state.setStartTag(true);
     1537        } else if (cc == '\n' || cc == '\r') {
     1538            if (state.discardLF())
     1539                // Ignore this LF
     1540                state.setDiscardLF(false); // We have discarded 1 LF
     1541            else
     1542                // Process this LF
     1543                *dest++ = '\n';
     1544           
     1545            /* Check for MS-DOS CRLF sequence */
     1546            if (cc == '\r')
     1547                state.setSkipLF(true);
     1548            ++src;
     1549        } else {
     1550            state.setDiscardLF(false);
     1551#if QT_VERSION < 300
     1552            unsigned char row = src->row();
     1553            if ( row > 0x05 && row < 0x10 || row > 0xfd )
     1554                    currToken.complexText = true;
     1555#endif
     1556            *dest = *src;
     1557            fixUpChar(*dest);
     1558            ++dest;
     1559            ++src;
     1560        }
     1561    }
     1562   
     1563#ifdef INSTRUMENT_LAYOUT_SCHEDULING
     1564    if (!parser->doc()->ownerElement())
     1565        printf("Ending write at time %d\n", parser->doc()->elapsedTime());
     1566#endif
     1567   
     1568    inWrite = wasInWrite;
     1569
     1570    m_state = state;
     1571
     1572    if (noMoreData && !inWrite && !state.loadingExtScript() && !m_executingScript && !timerId)
     1573        end(); // this actually causes us to be deleted
     1574}
     1575
     1576void HTMLTokenizer::stopped()
     1577{
     1578    if (timerId) {
     1579        killTimer(timerId);
     1580        timerId = 0;
     1581    }
     1582}
     1583
     1584bool HTMLTokenizer::processingData() const
     1585{
     1586    return timerId != 0;
     1587}
     1588
    15731589void HTMLTokenizer::timerEvent(QTimerEvent* e)
    15741590{
     
    16031619void HTMLTokenizer::allDataProcessed()
    16041620{
    1605     if (noMoreData && !inWrite && !loadingExtScript && !m_executingScript && !onHold && !timerId) {
     1621    if (noMoreData && !inWrite && !m_state.loadingExtScript() && !m_executingScript && !onHold && !timerId) {
    16061622        QGuardedPtr<KHTMLView> savedView = view;
    16071623        end();
     
    16311647
    16321648    // parseTag is using the buffer for different matters
    1633     if ( !tag )
     1649    if (!m_state.hasTagState())
    16341650        processToken();
    16351651
     
    16501666{
    16511667    // do this as long as we don't find matching comment ends
    1652     while((comment || server) && scriptCode && scriptCodeSize)
    1653     {
     1668    while((m_state.inComment() || m_state.inServer()) && scriptCode && scriptCodeSize) {
    16541669        // we've found an unmatched comment start
    1655         if (comment)
     1670        if (m_state.inComment())
    16561671            brokenComments = true;
    16571672        else
    16581673            brokenServer = true;
    16591674        checkScriptBuffer();
    1660         scriptCode[ scriptCodeSize ] = 0;
    1661         scriptCode[ scriptCodeSize + 1 ] = 0;
     1675        scriptCode[scriptCodeSize] = 0;
     1676        scriptCode[scriptCodeSize + 1] = 0;
    16621677        int pos;
    16631678        QString food;
    1664         if (script || style) {
     1679        if (m_state.inScript() || m_state.inStyle())
    16651680            food.setUnicode(scriptCode, scriptCodeSize);
    1666         }
    1667         else if (server) {
     1681        else if (m_state.inServer()) {
    16681682            food = "<";
    16691683            food += QString(scriptCode, scriptCodeSize);
    1670         }
    1671         else {
     1684        } else {
    16721685            pos = QConstString(scriptCode, scriptCodeSize).string().find('>');
    16731686            food.setUnicode(scriptCode+pos+1, scriptCodeSize-pos-1); // deep copy
     
    16761689        scriptCode = 0;
    16771690        scriptCodeSize = scriptCodeMaxSize = scriptCodeResync = 0;
    1678         comment = server = false;
    1679         if ( !food.isEmpty() )
     1691        m_state.setInComment(false);
     1692        m_state.setInServer(false);
     1693        if (!food.isEmpty())
    16801694            write(food, true);
    16811695    }
     
    16831697    // an external script to load, we can't finish parsing until that is done
    16841698    noMoreData = true;
    1685     if (!inWrite && !loadingExtScript && !m_executingScript && !onHold && !timerId)
     1699    if (!inWrite && !m_state.loadingExtScript() && !m_executingScript && !onHold && !timerId)
    16861700        end(); // this actually causes us to be deleted
    16871701}
     
    18051819#endif
    18061820
    1807         scriptExecution( scriptSource.qstring(), cachedScriptUrl );
     1821        m_state = scriptExecution(scriptSource.qstring(), m_state, cachedScriptUrl);
    18081822
    18091823        // The state of pendingScripts.isEmpty() can change inside the scriptExecution()
     
    18111825        finished = pendingScripts.isEmpty();
    18121826        if (finished) {
    1813             loadingExtScript = false;
     1827            m_state.setLoadingExtScript(false);
    18141828#ifdef INSTRUMENT_LAYOUT_SCHEDULING
    18151829            if (!parser->doc()->ownerElement())
     
    18181832        }
    18191833
    1820         // 'script' is true when we are called synchronously from
     1834        // 'inScript' is true when we are called synchronously from
    18211835        // parseScript(). In that case parseScript() will take care
    18221836        // of 'scriptOutput'.
    1823         if ( !script ) {
     1837        if (!m_state.inScript()) {
    18241838            TokenizerString rest = pendingSrc;
    18251839            pendingSrc.clear();
     
    18331847bool HTMLTokenizer::isWaitingForScripts() const
    18341848{
    1835     return loadingExtScript;
     1849    return m_state.loadingExtScript();
    18361850}
    18371851
  • trunk/WebCore/khtml/html/htmltokenizer.h

    r10843 r10867  
    129129
    130130protected:
     131    class State;
     132
     133    // Where we are in parsing a tag
    131134    void begin();
    132135    void end();
     
    134137    void reset();
    135138    void processToken();
    136     void processListing(TokenizerString list);
    137 
    138     void parseComment(TokenizerString &str);
    139     void parseServer(TokenizerString &str);
    140     void parseText(TokenizerString &str);
    141     void parseListing(TokenizerString &str);
    142     void parseSpecial(TokenizerString &str);
    143     void parseTag(TokenizerString &str);
    144     void parseEntity(TokenizerString &str, QChar *&dest, bool start = false);
    145     void parseProcessingInstruction(TokenizerString &str);
    146     void scriptHandler();
    147     void scriptExecution(const QString& script, QString scriptURL = QString(),
    148                          int baseLine = 0);
     139
     140    State processListing(TokenizerString, State);
     141    State parseComment(TokenizerString&, State);
     142    State parseServer(TokenizerString&, State);
     143    State parseText(TokenizerString&, State);
     144    State parseSpecial(TokenizerString&, State);
     145    State parseTag(TokenizerString&, State);
     146    State parseEntity(TokenizerString &, QChar*& dest, State, unsigned& _cBufferPos, bool start, bool parsingTag);
     147    State parseProcessingInstruction(TokenizerString&, State);
     148    State scriptHandler(State);
     149    State scriptExecution(const QString& script, State state, QString scriptURL = QString(), int baseLine = 0);
    149150    void setSrc(const TokenizerString &source);
    150151
     
    165166    void enlargeScriptBuffer(int len);
    166167
    167     bool continueProcessing(int& processedCount, const QTime& startTime, const KWQUIEventTime& eventTime);
     168    bool continueProcessing(int& processedCount, const QTime& startTime, const KWQUIEventTime& eventTime, State &state);
    168169    void timerEvent(QTimerEvent*);
    169170    void allDataProcessed();
     
    193194    } tquote;
    194195
    195     // Discard line breaks immediately after <pre> tags
    196     enum
    197     {
    198         NoneDiscard = 0,
    199         LFDiscard
    200     } discard;
    201 
    202     // Discard the LF part of CRLF sequence
    203     bool skipLF;
    204 
    205     // Flag to say that we have the '<' but not the character following it.
    206     bool startTag;
    207 
    208     // Flag to say, we are just parsing a tag, meaning, we are in the middle
    209     // of <tag...
    210     enum {
     196    // Are we in a &... character entity description?
     197    enum EntityState {
     198        NoEntity = 0,
     199        SearchEntity = 1,
     200        NumericSearch = 2,
     201        Hexadecimal = 3,
     202        Decimal = 4,
     203        EntityName = 5,
     204        SearchSemicolon = 6
     205    };
     206    unsigned EntityUnicodeValue;
     207
     208    enum TagState {
    211209        NoTag = 0,
    212         TagName,
    213         SearchAttribute,
    214         AttributeName,
    215         SearchEqual,
    216         SearchValue,
    217         QuotedValue,
    218         Value,
    219         SearchEnd
    220     } tag;
    221 
    222     // Are we in a &... character entity description?
    223     enum {
    224         NoEntity = 0,
    225         SearchEntity,
    226         NumericSearch,
    227         Hexadecimal,
    228         Decimal,
    229         EntityName,
    230         SearchSemicolon
    231     } Entity;
    232     unsigned EntityUnicodeValue;
    233 
    234     // are we in a <script> ... </script block
    235     bool script;
    236 
    237     // Are we in a <style> ... </style> block
    238     bool style;
    239 
    240     // Are we in a <select> ... </select> block
    241     bool select;
    242 
    243     // Are we in a <xmp> ... </xmp> block
    244     bool xmp;
    245 
    246     // Are we in a <title> ... </title> block
    247     bool title;
    248 
    249     // Are we in plain textmode ?
    250     bool plaintext;
    251 
    252     // XML processing instructions. Ignored at the moment
    253     bool processingInstruction;
    254 
    255     // Area we in a <!-- comment --> block
    256     bool comment;
    257 
    258     // Are we in a <textarea> ... </textarea> block
    259     bool textarea;
    260 
    261     // was the previous character escaped ?
    262     bool escaped;
    263 
    264     // are we in a server includes statement?
    265     bool server;
     210        TagName = 1,
     211        SearchAttribute = 2,
     212        AttributeName = 3,
     213        SearchEqual = 4,
     214        SearchValue = 5,
     215        QuotedValue = 6,
     216        Value = 7,
     217        SearchEnd = 8
     218    };
     219
     220    class State {
     221    public:
     222        State() : m_bits(0) {}
     223
     224        TagState tagState() const { return static_cast<TagState>(m_bits & TagMask); }
     225        void setTagState(TagState t) { m_bits = (m_bits & ~TagMask) | t; }
     226        EntityState entityState() const { return static_cast<EntityState>((m_bits & EntityMask) >> EntityShift); }
     227        void setEntityState(EntityState e) { m_bits = (m_bits & ~EntityMask) | (e << EntityShift); }
     228
     229        bool inScript() const { return testBit(InScript); }
     230        void setInScript(bool v) { setBit(InScript, v); }
     231        bool inStyle() const { return testBit(InStyle); }
     232        void setInStyle(bool v) { setBit(InStyle, v); }
     233        bool inSelect() const { return testBit(InSelect); }
     234        void setInSelect(bool v) { setBit(InSelect, v); }
     235        bool inXmp() const { return testBit(InXmp); }
     236        void setInXmp(bool v) { setBit(InXmp, v); }
     237        bool inTitle() const { return testBit(InTitle); }
     238        void setInTitle(bool v) { setBit(InTitle, v); }
     239        bool inPlainText() const { return testBit(InPlainText); }
     240        void setInPlainText(bool v) { setBit(InPlainText, v); }
     241        bool inProcessingInstruction() const { return testBit(InProcessingInstruction); }
     242        void setInProcessingInstruction(bool v) { return setBit(InProcessingInstruction, v); }
     243        bool inComment() const { return testBit(InComment); }
     244        void setInComment(bool v) { setBit(InComment, v); }
     245        bool inTextArea() const { return testBit(InTextArea); }
     246        void setInTextArea(bool v) { setBit(InTextArea, v); }
     247        bool escaped() const { return testBit(Escaped); }
     248        void setEscaped(bool v) { setBit(Escaped, v); }
     249        bool inServer() const { return testBit(InServer); }
     250        void setInServer(bool v) { setBit(InServer, v); }
     251        bool skipLF() const { return testBit(SkipLF); }
     252        void setSkipLF(bool v) { setBit(SkipLF, v); }
     253        bool startTag() const { return testBit(StartTag); }
     254        void setStartTag(bool v) { setBit(StartTag, v); }
     255        bool discardLF() const { return testBit(DiscardLF); }
     256        void setDiscardLF(bool v) { setBit(DiscardLF, v); }
     257        bool allowYield() const { return testBit(AllowYield); }
     258        void setAllowYield(bool v) { setBit(AllowYield, v); }
     259        bool loadingExtScript() const { return testBit(LoadingExtScript); }
     260        void setLoadingExtScript(bool v) { setBit(LoadingExtScript, v); }
     261        bool forceSynchronous() const { return testBit(ForceSynchronous); }
     262        void setForceSynchronous(bool v) { setBit(ForceSynchronous, v); }
     263
     264        bool inAnySpecial() const { return m_bits & (InScript | InStyle | InXmp | InTextArea | InTitle); }
     265        bool hasTagState() const { return m_bits & TagMask; }
     266        bool hasEntityState() const { return m_bits & EntityMask; }
     267
     268        bool needsSpecialWriteHandling() const { return m_bits & (InScript | InStyle | InXmp | InTextArea | InTitle | TagMask | EntityMask | InPlainText | InComment | InServer | InProcessingInstruction | StartTag); }
     269
     270    private:
     271        static const int EntityShift = 4;
     272        enum StateBits {
     273            TagMask = (1 << 4) - 1,
     274            EntityMask = (1 << 7) - (1 << 4),
     275            InScript = 1 << 7,
     276            InStyle = 1 << 8,
     277            InSelect = 1 << 9,
     278            InXmp = 1 << 10,
     279            InTitle = 1 << 11,
     280            InPlainText = 1 << 12,
     281            InProcessingInstruction = 1 << 13,
     282            InComment = 1 << 14,
     283            InTextArea = 1 << 15,
     284            Escaped = 1 << 16,
     285            InServer = 1 << 17,
     286            SkipLF = 1 << 18,
     287            StartTag = 1 << 19,
     288            DiscardLF = 1 << 20, // FIXME: should clarify difference between skip and discard
     289            AllowYield = 1 << 21,
     290            LoadingExtScript = 1 << 22,
     291            ForceSynchronous = 1 << 23,
     292        };
     293   
     294        void setBit(StateBits bit, bool value)
     295        {
     296            if (value)
     297                m_bits |= bit;
     298            else
     299                m_bits &= ~bit;
     300        }
     301        bool testBit(StateBits bit) const { return m_bits & bit; }
     302
     303        unsigned m_bits;
     304    };
     305
     306    State m_state;
    266307
    267308    bool brokenServer;
     
    289330    // the stopper len
    290331    int searchStopperLen;
    291     // true if we are waiting for an external script (<SCRIPT SRC=...) to load, i.e.
    292     // we don't do any parsing while this is true
    293     bool loadingExtScript;
    294332    // if no more data is coming, just parse what we have (including ext scripts that
    295333    // may be still downloading) and finish
     
    324362    // The timer for continued processing.
    325363    int timerId;
    326     bool allowYield;
    327     bool forceSynchronous;  // disables yielding
    328364
    329365    bool includesCommentsInDOM;
     
    334370#define CBUFLEN 1024
    335371    char cBuffer[CBUFLEN+2];
    336     unsigned int cBufferPos;
     372    unsigned int m_cBufferPos;
    337373
    338374    TokenizerString src;
  • trunk/WebCore/khtml/rendering/bidi.cpp

    r10845 r10867  
    25242524    QChar ellipsis = 0x2026; // FIXME: CSS3 says this is configurable, also need to use 0x002E (FULL STOP) if 0x2026 not renderable
    25252525    static AtomicString ellipsisStr(ellipsis);
    2526     const Font& firstLineFont = style(true)->htmlFont();
     2526    const Font& firstLineFont = firstLineStyle()->htmlFont();
    25272527    const Font& font = style()->htmlFont();
    25282528    int firstLineEllipsisWidth = firstLineFont.width(&ellipsis, 1, 0, 0);
  • trunk/WebCore/khtml/rendering/render_block.cpp

    r10774 r10867  
    33173317    if (currChild->style()->styleType() == RenderStyle::FIRST_LETTER) {
    33183318        RenderStyle* pseudo = firstLetterBlock->getPseudoStyle(RenderStyle::FIRST_LETTER,
    3319                                                                     firstLetterContainer->style(true));
     3319                                                               firstLetterContainer->firstLineStyle());
    33203320        currChild->setStyle(pseudo);
    33213321        for (RenderObject* genChild = currChild->firstChild(); genChild; genChild = genChild->nextSibling()) {
     
    33343334        // Create our pseudo style now that we have our firstLetterContainer determined.
    33353335        RenderStyle* pseudoStyle = firstLetterBlock->getPseudoStyle(RenderStyle::FIRST_LETTER,
    3336                                                                     firstLetterContainer->style(true));
     3336                                                                    firstLetterContainer->firstLineStyle());
    33373337       
    33383338        // Force inline display (except for floating first-letters)
  • trunk/WebCore/khtml/rendering/render_flow.cpp

    r10866 r10867  
    601601    // the caret size of an empty :first-line'd block is wrong, but I think we
    602602    // can live with that.
    603     RenderStyle *currentStyle = style(true);
     603    RenderStyle *currentStyle = firstLineStyle();
    604604    //height = currentStyle->fontMetrics().height();
    605605    height = lineHeight(true);
  • trunk/WebCore/khtml/rendering/render_line.cpp

    r10755 r10867  
    10681068{
    10691069    QPainter* p = i.p;
    1070     RenderStyle* _style = m_firstLine ? m_object->style(true) : m_object->style();
     1070    RenderStyle* _style = m_firstLine ? m_object->firstLineStyle() : m_object->style();
    10711071    if (_style->font() != p->font())
    10721072        p->setFont(_style->font());
  • trunk/WebCore/khtml/rendering/render_object.cpp

    r10755 r10867  
    22962296}
    22972297
    2298 RenderStyle* RenderObject::style(bool firstLine) const {
    2299     RenderStyle *s = m_style;
    2300     if (firstLine) {
    2301         const RenderObject* obj = isText() ? parent() : this;
    2302         if (obj->isBlockFlow()) {
    2303             RenderBlock* firstLineBlock = obj->firstLineBlock();
    2304             if (firstLineBlock)
    2305                 s = firstLineBlock->getPseudoStyle(RenderStyle::FIRST_LINE, style());
    2306         }
    2307         else if (!obj->isAnonymous() && obj->isInlineFlow()) {
    2308             RenderStyle* parentStyle = obj->parent()->style(true);
    2309             if (parentStyle != obj->parent()->style()) {
    2310                 // A first-line style is in effect. We need to cache a first-line style
    2311                 // for ourselves.
    2312                 style()->setHasPseudoStyle(RenderStyle::FIRST_LINE_INHERITED);
    2313                 s = obj->getPseudoStyle(RenderStyle::FIRST_LINE_INHERITED, parentStyle);
    2314             }
     2298RenderStyle* RenderObject::firstLineStyle() const
     2299{
     2300    RenderStyle *s = m_style;
     2301    const RenderObject* obj = isText() ? parent() : this;
     2302    if (obj->isBlockFlow()) {
     2303        RenderBlock* firstLineBlock = obj->firstLineBlock();
     2304        if (firstLineBlock)
     2305            s = firstLineBlock->getPseudoStyle(RenderStyle::FIRST_LINE, style());
     2306    } else if (!obj->isAnonymous() && obj->isInlineFlow()) {
     2307        RenderStyle* parentStyle = obj->parent()->firstLineStyle();
     2308        if (parentStyle != obj->parent()->style()) {
     2309            // A first-line style is in effect. We need to cache a first-line style
     2310            // for ourselves.
     2311            style()->setHasPseudoStyle(RenderStyle::FIRST_LINE_INHERITED);
     2312            s = obj->getPseudoStyle(RenderStyle::FIRST_LINE_INHERITED, parentStyle);
    23152313        }
    23162314    }
  • trunk/WebCore/khtml/rendering/render_object.h

    r10755 r10867  
    677677
    678678    RenderStyle* style() const { return m_style; }
    679     RenderStyle* style( bool firstLine ) const;
     679    RenderStyle* firstLineStyle() const;
     680    RenderStyle* style(bool firstLine) const { return firstLine ? firstLineStyle() : style(); }
     681
    680682
    681683    void getTextDecorationColors(int decorations, QColor& underline, QColor& overline,
Note: See TracChangeset for help on using the changeset viewer.