Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(190)

Side by Side Diff: sky/engine/core/html/parser/HTMLDocumentParser.cpp

Issue 1215103007: Remove remaining HTML elements (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "sky/engine/core/html/parser/HTMLDocumentParser.h"
27
28 #include "base/bind.h"
29 #include "gen/sky/core/HTMLNames.h"
30 #include "sky/engine/core/css/MediaValuesCached.h"
31 #include "sky/engine/core/dom/Element.h"
32 #include "sky/engine/core/frame/LocalFrame.h"
33 #include "sky/engine/core/html/HTMLScriptElement.h"
34 #include "sky/engine/core/html/parser/AtomicHTMLToken.h"
35 #include "sky/engine/core/html/parser/BackgroundHTMLParser.h"
36 #include "sky/engine/core/html/parser/HTMLParserScheduler.h"
37 #include "sky/engine/core/html/parser/HTMLParserThread.h"
38 #include "sky/engine/core/html/parser/HTMLTreeBuilder.h"
39 #include "sky/engine/platform/SharedBuffer.h"
40 #include "sky/engine/platform/TraceEvent.h"
41
42 namespace blink {
43
44 HTMLDocumentParser::HTMLDocumentParser(Document& document, bool reportErrors)
45 : DocumentParser(&document)
46 , m_treeBuilder(HTMLTreeBuilder::create(this, &document, reportErrors))
47 , m_parserScheduler(HTMLParserScheduler::create(this))
48 , m_weakFactory(this)
49 , m_isFragment(false)
50 , m_endWasDelayed(false)
51 , m_haveBackgroundParser(false)
52 , m_pumpSessionNestingLevel(0)
53 {
54 }
55
56 HTMLDocumentParser::~HTMLDocumentParser()
57 {
58 ASSERT(!m_parserScheduler);
59 ASSERT(!m_pumpSessionNestingLevel);
60 ASSERT(!m_haveBackgroundParser);
61 // FIXME: We should be able to ASSERT(m_pendingChunks.isEmpty()),
62 // but there are cases where that's not true currently. For example,
63 // we we're told to stop parsing before we've consumed all the input.
64 }
65
66 void HTMLDocumentParser::parse(mojo::ScopedDataPipeConsumerHandle source,
67 const base::Closure& completionCallback)
68 {
69 ASSERT(!isStopped());
70 ASSERT(!m_haveBackgroundParser);
71 m_haveBackgroundParser = true;
72
73 m_completionCallback = completionCallback;
74
75 OwnPtr<BackgroundHTMLParser::Configuration> config = adoptPtr(new Background HTMLParser::Configuration);
76 config->source = source.Pass();
77 config->parser = m_weakFactory.GetWeakPtr();
78
79 m_backgroundParser = BackgroundHTMLParser::create(config.release());
80 HTMLParserThread::taskRunner()->PostTask(FROM_HERE,
81 base::Bind(&BackgroundHTMLParser::start, m_backgroundParser));
82 }
83
84 void HTMLDocumentParser::detach()
85 {
86 if (m_haveBackgroundParser)
87 stopBackgroundParser();
88 DocumentParser::detach();
89 m_treeBuilder->detach();
90 // FIXME: It seems wrong that we would have a preload scanner here.
91 // Yet during fast/dom/HTMLScriptElement/script-load-events.html we do.
92 m_parserScheduler.clear(); // Deleting the scheduler will clear any timers.
93 }
94
95 void HTMLDocumentParser::stopParsing()
96 {
97 DocumentParser::stopParsing();
98 m_parserScheduler.clear(); // Deleting the scheduler will clear any timers.
99 if (m_haveBackgroundParser)
100 stopBackgroundParser();
101 }
102
103 // This kicks off "Once the user agent stops parsing" as described by:
104 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#the- end
105 void HTMLDocumentParser::prepareToStopParsing()
106 {
107 // FIXME: It may not be correct to disable this for the background parser.
108 // That means hasInsertionPoint() may not be correct in some cases.
109 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser);
110
111 // pumpTokenizer can cause this parser to be detached from the Document,
112 // but we need to ensure it isn't deleted yet.
113 RefPtr<HTMLDocumentParser> protect(this);
114
115 if (isStopped())
116 return;
117
118 DocumentParser::prepareToStopParsing();
119
120 // We will not have a scriptRunner when parsing a DocumentFragment.
121 if (!m_isFragment)
122 document()->setReadyState(Document::Interactive);
123
124 // Setting the ready state above can fire mutation event and detach us
125 // from underneath. In that case, just bail out.
126 if (isDetached())
127 return;
128
129 ASSERT(isStopping());
130 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser);
131 end();
132 }
133
134 bool HTMLDocumentParser::isParsingFragment() const
135 {
136 return m_treeBuilder->isParsingFragment();
137 }
138
139 bool HTMLDocumentParser::isScheduledForResume() const
140 {
141 return m_parserScheduler && m_parserScheduler->isScheduledForResume();
142 }
143
144 // Used by HTMLParserScheduler
145 void HTMLDocumentParser::resumeParsingAfterYield()
146 {
147 // pumpTokenizer can cause this parser to be detached from the Document,
148 // but we need to ensure it isn't deleted yet.
149 RefPtr<HTMLDocumentParser> protect(this);
150
151 ASSERT(m_haveBackgroundParser);
152 pumpPendingChunks();
153 }
154
155 void HTMLDocumentParser::runScriptsForPausedTreeBuilder()
156 {
157 if (m_isFragment)
158 return;
159 TextPosition scriptStartPosition = TextPosition::belowRangePosition();
160 RefPtr<Element> scriptToProcess = m_treeBuilder->takeScriptToProcess(scriptS tartPosition);
161
162 // Sending the script to dart may find additional 'import' declarations
163 // which need to load before the script can execute. HTMLScriptRunner
164 // always calls scriptExecutionCompleted regardless of success/failure.
165 m_scriptRunner = HTMLScriptRunner::createForScript(
166 toHTMLScriptElement(scriptToProcess.get()), scriptStartPosition, this);
167 m_scriptRunner->start();
168 }
169
170 void HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<Pa rsedChunk> chunk)
171 {
172 TRACE_EVENT0("blink", "HTMLDocumentParser::didReceiveParsedChunkFromBackgrou ndParser");
173 // Sky should not need nested parsers.
174 ASSERT(document()->activeParserCount() == 0);
175
176 if (isWaitingForScripts() || !m_pendingChunks.isEmpty() ||
177 document()->activeParserCount() > 0) {
178 m_pendingChunks.append(chunk);
179 return;
180 }
181
182 // processParsedChunkFromBackgroundParser can cause this parser to be detach ed from the Document,
183 // but we need to ensure it isn't deleted yet.
184 RefPtr<HTMLDocumentParser> protect(this);
185
186 ASSERT(m_pendingChunks.isEmpty());
187 m_pendingChunks.append(chunk);
188 pumpPendingChunks();
189 }
190
191 void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Parse dChunk> popChunk)
192 {
193 // TODO(eseidel): Include the token count in the trace event.
194 TRACE_EVENT0("blink", "HTMLDocumentParser::processParsedChunkFromBackgroundP arser");
195
196 ASSERT_WITH_SECURITY_IMPLICATION(!document()->activeParserCount());
197 ASSERT(!isParsingFragment());
198 ASSERT(!isWaitingForScripts());
199 ASSERT(!isStopped());
200
201 // ASSERT that this object is both attached to the Document and protected.
202 ASSERT(refCount() >= 2);
203
204 ActiveParserSession session(contextForParsingSession());
205
206 OwnPtr<ParsedChunk> chunk(popChunk);
207 OwnPtr<CompactHTMLTokenStream> tokens = chunk->tokens.release();
208
209 Vector<CompactHTMLToken>::const_iterator it;
210 for (it = tokens->begin(); it != tokens->end(); ++it) {
211 // A chunk can issue import loads causing us to be isWaitingForScripts
212 // but we don't stop processing in that case.
213 ASSERT(!m_treeBuilder->hasParserBlockingScript());
214 ASSERT(!m_scriptRunner);
215
216 m_textPosition = it->textPosition();
217
218 constructTreeFromCompactHTMLToken(*it);
219
220 if (isStopped())
221 break;
222
223 if (m_treeBuilder->hasParserBlockingScript()) {
224 ++it; // Make it == end() during non-stopped termination.
225 ASSERT(it == tokens->end()); // The </script> is assumed to be the
226 // last token of this bunch.
227 runScriptsForPausedTreeBuilder();
228 break;
229 }
230
231 if (it->type() == HTMLToken::EndOfFile) {
232 ++it; // Make it == end() during non-stopped termination.
233 ASSERT(it == tokens->end()); // The EOF is assumed to be the
234 // last token of this bunch.
235 ASSERT(m_pendingChunks.isEmpty()); // There should never be any chun ks after the EOF.
236 prepareToStopParsing();
237 break;
238 }
239 }
240
241 // Either we aborted due to stopping or we processed all tokens.
242 ASSERT(isStopped() || it == tokens->end());
243
244 // Make sure any pending text nodes are emitted before returning.
245 if (!isStopped())
246 m_treeBuilder->flush();
247 }
248
249 void HTMLDocumentParser::pumpPendingChunks()
250 {
251 // FIXME: Share this constant with the parser scheduler.
252 const double parserTimeLimit = 0.500;
253
254 // ASSERT that this object is both attached to the Document and protected.
255 ASSERT(refCount() >= 2);
256 ASSERT(!isWaitingForScripts());
257 ASSERT(!isStopped());
258
259 double startTime = currentTime();
260
261 while (!m_pendingChunks.isEmpty()) {
262 processParsedChunkFromBackgroundParser(m_pendingChunks.takeFirst());
263
264 // Always check isStopped first as m_document may be null.
265 if (isStopped() || isWaitingForScripts())
266 break;
267
268 if (currentTime() - startTime > parserTimeLimit && !m_pendingChunks.isEm pty()) {
269 m_parserScheduler->scheduleForResume();
270 break;
271 }
272 }
273 }
274
275 Document* HTMLDocumentParser::contextForParsingSession()
276 {
277 // The parsing session should interact with the document only when parsing
278 // non-fragments. Otherwise, we might delay the load event mistakenly.
279 if (isParsingFragment())
280 return 0;
281 return document();
282 }
283
284 void HTMLDocumentParser::constructTreeFromHTMLToken(HTMLToken& rawToken)
285 {
286 AtomicHTMLToken token(rawToken);
287
288 // We clear the rawToken in case constructTreeFromAtomicToken
289 // synchronously re-enters the parser. We don't clear the token immedately
290 // for Character tokens because the AtomicHTMLToken avoids copying the
291 // characters by keeping a pointer to the underlying buffer in the
292 // HTMLToken. Fortunately, Character tokens can't cause us to re-enter
293 // the parser.
294 //
295 // FIXME: Stop clearing the rawToken once we start running the parser off
296 // the main thread or once we stop allowing synchronous JavaScript
297 // execution from parseAttribute.
298 if (rawToken.type() != HTMLToken::Character)
299 rawToken.clear();
300
301 m_treeBuilder->constructTree(&token);
302
303 if (!rawToken.isUninitialized()) {
304 ASSERT(rawToken.type() == HTMLToken::Character);
305 rawToken.clear();
306 }
307 }
308
309 void HTMLDocumentParser::constructTreeFromCompactHTMLToken(const CompactHTMLToke n& compactToken)
310 {
311 AtomicHTMLToken token(compactToken);
312 m_treeBuilder->constructTree(&token);
313 }
314
315 bool HTMLDocumentParser::hasInsertionPoint()
316 {
317 return false;
318 }
319
320 void HTMLDocumentParser::stopBackgroundParser()
321 {
322 ASSERT(m_haveBackgroundParser);
323 m_haveBackgroundParser = false;
324
325 HTMLParserThread::taskRunner()->PostTask(FROM_HERE,
326 base::Bind(&BackgroundHTMLParser::stop, m_backgroundParser));
327 m_weakFactory.InvalidateWeakPtrs();
328 }
329
330 void HTMLDocumentParser::end()
331 {
332 ASSERT(!isDetached());
333 ASSERT(!isScheduledForResume());
334
335 if (m_haveBackgroundParser)
336 stopBackgroundParser();
337
338 // Notice that we copy the compleition callback into a local variable
339 // because we might be deleted after we call ffinish() below.
340 base::Closure completionCallback = m_completionCallback;
341
342 // Informs the the rest of WebCore that parsing is really finished (and dele tes this).
343 m_treeBuilder->finished();
344
345 completionCallback.Run();
346 }
347
348 void HTMLDocumentParser::attemptToEnd()
349 {
350 if (shouldDelayEnd()) {
351 m_endWasDelayed = true;
352 return;
353 }
354 prepareToStopParsing();
355 }
356
357 void HTMLDocumentParser::endIfDelayed()
358 {
359 // If we've already been detached, don't bother ending.
360 if (isDetached())
361 return;
362
363 if (!m_endWasDelayed || shouldDelayEnd())
364 return;
365
366 m_endWasDelayed = false;
367 prepareToStopParsing();
368 }
369
370 bool HTMLDocumentParser::isExecutingScript() const
371 {
372 // TODO(eseidel): Callers may need updates now that scripts can be async.
373 return m_scriptRunner && m_scriptRunner->isExecutingScript();
374 }
375
376 OrdinalNumber HTMLDocumentParser::lineNumber() const
377 {
378 ASSERT(m_haveBackgroundParser);
379 return m_textPosition.m_line;
380 }
381
382 TextPosition HTMLDocumentParser::textPosition() const
383 {
384 ASSERT(m_haveBackgroundParser);
385 return m_textPosition;
386 }
387
388 bool HTMLDocumentParser::isWaitingForScripts() const
389 {
390 return m_treeBuilder->hasParserBlockingScript() || m_scriptRunner ||
391 !document()->haveImportsLoaded();
392 }
393
394 void HTMLDocumentParser::resumeAfterWaitingForImports()
395 {
396 if (isWaitingForScripts())
397 return;
398 if (m_pendingChunks.isEmpty())
399 return;
400 ASSERT(m_haveBackgroundParser);
401 RefPtr<HTMLDocumentParser> protect(this);
402 pumpPendingChunks();
403 }
404
405 // HTMLScriptRunner has finished executing a script.
406 // Just call resumeAfterWaitingForImports since it happens to do what we need.
407 void HTMLDocumentParser::scriptExecutionCompleted() {
408 ASSERT(m_scriptRunner);
409 m_scriptRunner.clear();
410 // To avoid re-entering the parser for synchronous scripts, we use a postTask.
411 base::MessageLoop::current()->PostTask(
412 FROM_HERE, base::Bind(&HTMLDocumentParser::resumeAfterWaitingForImports,
413 m_weakFactory.GetWeakPtr()));
414 }
415 }
OLDNEW
« no previous file with comments | « sky/engine/core/html/parser/HTMLDocumentParser.h ('k') | sky/engine/core/html/parser/HTMLElementStack.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698