1 /*
2 * Copyright (C) 2010 Google, Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "core/html/parser/HTMLParserScheduler.h"
28
29 #include "core/dom/Document.h"
30 #include "core/html/parser/HTMLDocumentParser.h"
31 #include "core/frame/FrameView.h"
32
33 namespace blink {
34
35 // parserChunkSize is used to define how many tokens the parser will
36 // process before checking against parserTimeLimit and possibly yielding.
37 // This is a performance optimization to prevent checking after every token.
38 const int HTMLParserScheduler::parserChunkSize = 4096;
39
40 // parserTimeLimit is the seconds the parser will run in one write() call
41 // before yielding. Inline <script> execution can cause it to exceed the limit.
42 const double HTMLParserScheduler::parserTimeLimit = 0.2;
43
ActiveParserSession(Document * document)44 ActiveParserSession::ActiveParserSession(Document* document)
45 : m_document(document)
46 {
47 if (!m_document)
48 return;
49 m_document->incrementActiveParserCount();
50 }
51
~ActiveParserSession()52 ActiveParserSession::~ActiveParserSession()
53 {
54 if (!m_document)
55 return;
56 m_document->decrementActiveParserCount();
57 }
58
PumpSession(unsigned & nestingLevel,Document * document)59 PumpSession::PumpSession(unsigned& nestingLevel, Document* document)
60 : NestingLevelIncrementer(nestingLevel)
61 , ActiveParserSession(document)
62 // Setting processedTokens to INT_MAX causes us to check for yields
63 // after any token during any parse where yielding is allowed.
64 // At that time we'll initialize startTime.
65 , processedTokens(INT_MAX)
66 , startTime(0)
67 , needsYield(false)
68 , didSeeScript(false)
69 {
70 }
71
~PumpSession()72 PumpSession::~PumpSession()
73 {
74 }
75
HTMLParserScheduler(HTMLDocumentParser * parser)76 HTMLParserScheduler::HTMLParserScheduler(HTMLDocumentParser* parser)
77 : m_parser(parser)
78 , m_continueNextChunkTimer(this, &HTMLParserScheduler::continueNextChunkTimerFired)
79 , m_isSuspendedWithActiveTimer(false)
80 {
81 }
82
~HTMLParserScheduler()83 HTMLParserScheduler::~HTMLParserScheduler()
84 {
85 m_continueNextChunkTimer.stop();
86 }
87
continueNextChunkTimerFired(Timer<HTMLParserScheduler> * timer)88 void HTMLParserScheduler::continueNextChunkTimerFired(Timer<HTMLParserScheduler>* timer)
89 {
90 ASSERT_UNUSED(timer, timer == &m_continueNextChunkTimer);
91 m_parser->resumeParsingAfterYield();
92 }
93
scheduleForResume()94 void HTMLParserScheduler::scheduleForResume()
95 {
96 m_continueNextChunkTimer.startOneShot(0, FROM_HERE);
97 }
98
suspend()99 void HTMLParserScheduler::suspend()
100 {
101 ASSERT(!m_isSuspendedWithActiveTimer);
102 if (!m_continueNextChunkTimer.isActive())
103 return;
104 m_isSuspendedWithActiveTimer = true;
105 m_continueNextChunkTimer.stop();
106 }
107
resume()108 void HTMLParserScheduler::resume()
109 {
110 ASSERT(!m_continueNextChunkTimer.isActive());
111 if (!m_isSuspendedWithActiveTimer)
112 return;
113 m_isSuspendedWithActiveTimer = false;
114 m_continueNextChunkTimer.startOneShot(0, FROM_HERE);
115 }
116
117 }
118