OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. | 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 void HTMLDocumentParser::prepareToStopParsing() | 212 void HTMLDocumentParser::prepareToStopParsing() |
213 { | 213 { |
214 // FIXME: It may not be correct to disable this for the background parser. | 214 // FIXME: It may not be correct to disable this for the background parser. |
215 // That means hasInsertionPoint() may not be correct in some cases. | 215 // That means hasInsertionPoint() may not be correct in some cases. |
216 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); | 216 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); |
217 | 217 |
218 // pumpTokenizer can cause this parser to be detached from the Document, | 218 // pumpTokenizer can cause this parser to be detached from the Document, |
219 // but we need to ensure it isn't deleted yet. | 219 // but we need to ensure it isn't deleted yet. |
220 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this); | 220 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this); |
221 | 221 |
222 // NOTE: This pump should only ever emit buffered character tokens, | 222 // NOTE: This pump should only ever emit buffered character tokens. |
223 // so ForceSynchronous vs. AllowYield should be meaningless. | |
224 if (m_tokenizer) { | 223 if (m_tokenizer) { |
225 ASSERT(!m_haveBackgroundParser); | 224 ASSERT(!m_haveBackgroundParser); |
226 pumpTokenizerIfPossible(ForceSynchronous); | 225 pumpTokenizerIfPossible(); |
227 } | 226 } |
228 | 227 |
229 if (isStopped()) | 228 if (isStopped()) |
230 return; | 229 return; |
231 | 230 |
232 DocumentParser::prepareToStopParsing(); | 231 DocumentParser::prepareToStopParsing(); |
233 | 232 |
234 // We will not have a scriptRunner when parsing a DocumentFragment. | 233 // We will not have a scriptRunner when parsing a DocumentFragment. |
235 if (m_scriptRunner) | 234 if (m_scriptRunner) |
236 document()->setReadyState(Document::Interactive); | 235 document()->setReadyState(Document::Interactive); |
237 | 236 |
238 // Setting the ready state above can fire mutation event and detach us | 237 // Setting the ready state above can fire mutation event and detach us |
239 // from underneath. In that case, just bail out. | 238 // from underneath. In that case, just bail out. |
240 if (isDetached()) | 239 if (isDetached()) |
241 return; | 240 return; |
242 | 241 |
243 attemptToRunDeferredScriptsAndEnd(); | 242 attemptToRunDeferredScriptsAndEnd(); |
244 } | 243 } |
245 | 244 |
246 bool HTMLDocumentParser::isParsingFragment() const | 245 bool HTMLDocumentParser::isParsingFragment() const |
247 { | 246 { |
248 return m_treeBuilder->isParsingFragment(); | 247 return m_treeBuilder->isParsingFragment(); |
249 } | 248 } |
250 | 249 |
251 bool HTMLDocumentParser::processingData() const | 250 bool HTMLDocumentParser::processingData() const |
252 { | 251 { |
253 return isScheduledForResume() || inPumpSession() || m_haveBackgroundParser; | 252 return isScheduledForResume() || inPumpSession() || m_haveBackgroundParser; |
254 } | 253 } |
255 | 254 |
256 void HTMLDocumentParser::pumpTokenizerIfPossible(SynchronousMode mode) | 255 void HTMLDocumentParser::pumpTokenizerIfPossible() |
257 { | 256 { |
258 ASSERT(mode == ForceSynchronous); | |
259 | |
260 if (isStopped()) | 257 if (isStopped()) |
261 return; | 258 return; |
262 if (isWaitingForScripts()) | 259 if (isWaitingForScripts()) |
263 return; | 260 return; |
264 | 261 |
265 // Once a resume is scheduled, HTMLParserScheduler controls when we next pum
p. | 262 // Once a resume is scheduled, HTMLParserScheduler controls when we next pum
p. |
266 if (isScheduledForResume()) { | 263 if (isScheduledForResume()) { |
267 return; | 264 return; |
268 } | 265 } |
269 | 266 |
270 pumpTokenizer(mode); | 267 pumpTokenizer(); |
271 } | 268 } |
272 | 269 |
273 bool HTMLDocumentParser::isScheduledForResume() const | 270 bool HTMLDocumentParser::isScheduledForResume() const |
274 { | 271 { |
275 return m_parserScheduler && m_parserScheduler->isScheduledForResume(); | 272 return m_parserScheduler && m_parserScheduler->isScheduledForResume(); |
276 } | 273 } |
277 | 274 |
278 // Used by HTMLParserScheduler | 275 // Used by HTMLParserScheduler |
279 void HTMLDocumentParser::resumeParsingAfterYield() | 276 void HTMLDocumentParser::resumeParsingAfterYield() |
280 { | 277 { |
(...skipping 10 matching lines...) Expand all Loading... |
291 { | 288 { |
292 ASSERT(scriptingContentIsAllowed(parserContentPolicy())); | 289 ASSERT(scriptingContentIsAllowed(parserContentPolicy())); |
293 | 290 |
294 TextPosition scriptStartPosition = TextPosition::belowRangePosition(); | 291 TextPosition scriptStartPosition = TextPosition::belowRangePosition(); |
295 RefPtrWillBeRawPtr<Element> scriptElement = m_treeBuilder->takeScriptToProce
ss(scriptStartPosition); | 292 RefPtrWillBeRawPtr<Element> scriptElement = m_treeBuilder->takeScriptToProce
ss(scriptStartPosition); |
296 // We will not have a scriptRunner when parsing a DocumentFragment. | 293 // We will not have a scriptRunner when parsing a DocumentFragment. |
297 if (m_scriptRunner) | 294 if (m_scriptRunner) |
298 m_scriptRunner->execute(scriptElement.release(), scriptStartPosition); | 295 m_scriptRunner->execute(scriptElement.release(), scriptStartPosition); |
299 } | 296 } |
300 | 297 |
301 bool HTMLDocumentParser::canTakeNextToken(SynchronousMode mode, PumpSession& ses
sion) | 298 bool HTMLDocumentParser::canTakeNextToken(PumpSession& session) |
302 { | 299 { |
303 if (isStopped()) | 300 if (isStopped()) |
304 return false; | 301 return false; |
305 | 302 |
306 ASSERT(!m_haveBackgroundParser || mode == ForceSynchronous); | |
307 | |
308 if (isWaitingForScripts()) { | 303 if (isWaitingForScripts()) { |
309 if (mode == AllowYield) | |
310 session.didSeeScript = true; | |
311 | |
312 // If we don't run the script, we cannot allow the next token to be take
n. | 304 // If we don't run the script, we cannot allow the next token to be take
n. |
313 if (session.needsYield) | 305 if (session.needsYield) |
314 return false; | 306 return false; |
315 | 307 |
316 // If we're paused waiting for a script, we try to execute scripts befor
e continuing. | 308 // If we're paused waiting for a script, we try to execute scripts befor
e continuing. |
317 runScriptsForPausedTreeBuilder(); | 309 runScriptsForPausedTreeBuilder(); |
318 if (isStopped()) | 310 if (isStopped()) |
319 return false; | 311 return false; |
320 if (isWaitingForScripts()) | 312 if (isWaitingForScripts()) |
321 return false; | 313 return false; |
322 } | 314 } |
323 | 315 |
324 // FIXME: It's wrong for the HTMLDocumentParser to reach back to the | 316 // FIXME: It's wrong for the HTMLDocumentParser to reach back to the |
325 // LocalFrame, but this approach is how the old parser handled | 317 // LocalFrame, but this approach is how the old parser handled |
326 // stopping when the page assigns window.location. What really | 318 // stopping when the page assigns window.location. What really |
327 // should happen is that assigning window.location causes the | 319 // should happen is that assigning window.location causes the |
328 // parser to stop parsing cleanly. The problem is we're not | 320 // parser to stop parsing cleanly. The problem is we're not |
329 // perpared to do that at every point where we run JavaScript. | 321 // perpared to do that at every point where we run JavaScript. |
330 if (!isParsingFragment() | 322 if (!isParsingFragment() |
331 && document()->frame() && document()->frame()->navigationScheduler().loc
ationChangePending()) | 323 && document()->frame() && document()->frame()->navigationScheduler().loc
ationChangePending()) |
332 return false; | 324 return false; |
333 | 325 |
334 if (mode == AllowYield) | |
335 m_parserScheduler->checkForYieldBeforeToken(session); | |
336 | |
337 return true; | 326 return true; |
338 } | 327 } |
339 | 328 |
340 void HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<Pa
rsedChunk> chunk) | 329 void HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<Pa
rsedChunk> chunk) |
341 { | 330 { |
342 TRACE_EVENT0("blink", "HTMLDocumentParser::didReceiveParsedChunkFromBackgrou
ndParser"); | 331 TRACE_EVENT0("blink", "HTMLDocumentParser::didReceiveParsedChunkFromBackgrou
ndParser"); |
343 | 332 |
344 // alert(), runModalDialog, and the JavaScript Debugger all run nested event
loops | 333 // alert(), runModalDialog, and the JavaScript Debugger all run nested event
loops |
345 // which can cause this method to be re-entered. We detect re-entry using | 334 // which can cause this method to be re-entered. We detect re-entry using |
346 // hasActiveParser(), save the chunk as a speculation, and return. | 335 // hasActiveParser(), save the chunk as a speculation, and return. |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
566 } | 555 } |
567 | 556 |
568 static PassRefPtr<MediaValues> createMediaValues(Document* document) | 557 static PassRefPtr<MediaValues> createMediaValues(Document* document) |
569 { | 558 { |
570 ASSERT(document); | 559 ASSERT(document); |
571 RefPtr<MediaValues> mediaValues = MediaValuesCached::create(*document); | 560 RefPtr<MediaValues> mediaValues = MediaValuesCached::create(*document); |
572 ASSERT(mediaValues->isSafeToSendToAnotherThread()); | 561 ASSERT(mediaValues->isSafeToSendToAnotherThread()); |
573 return mediaValues; | 562 return mediaValues; |
574 } | 563 } |
575 | 564 |
576 void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode) | 565 void HTMLDocumentParser::pumpTokenizer() |
577 { | 566 { |
578 ASSERT(!isStopped()); | 567 ASSERT(!isStopped()); |
579 ASSERT(!isScheduledForResume()); | 568 ASSERT(!isScheduledForResume()); |
580 #if !ENABLE(OILPAN) | 569 #if !ENABLE(OILPAN) |
581 // ASSERT that this object is both attached to the Document and protected. | 570 // ASSERT that this object is both attached to the Document and protected. |
582 ASSERT(refCount() >= 2); | 571 ASSERT(refCount() >= 2); |
583 #endif | 572 #endif |
584 ASSERT(m_tokenizer); | 573 ASSERT(m_tokenizer); |
585 ASSERT(m_token); | 574 ASSERT(m_token); |
586 ASSERT(mode == ForceSynchronous); | |
587 | 575 |
588 PumpSession session(m_pumpSessionNestingLevel, contextForParsingSession()); | 576 PumpSession session(m_pumpSessionNestingLevel, contextForParsingSession()); |
589 | 577 |
590 // We tell the InspectorInstrumentation about every pump, even if we | 578 // We tell the InspectorInstrumentation about every pump, even if we |
591 // end up pumping nothing. It can filter out empty pumps itself. | 579 // end up pumping nothing. It can filter out empty pumps itself. |
592 // FIXME: m_input.current().length() is only accurate if we | 580 // FIXME: m_input.current().length() is only accurate if we |
593 // end up parsing the whole buffer in this pump. We should pass how | 581 // end up parsing the whole buffer in this pump. We should pass how |
594 // much we parsed as part of didWriteHTML instead of willWriteHTML. | 582 // much we parsed as part of didWriteHTML instead of willWriteHTML. |
595 TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ParseHTM
L", "beginData", InspectorParseHtmlEvent::beginData(document(), m_input.current(
).currentLine().zeroBasedInt())); | 583 TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ParseHTM
L", "beginData", InspectorParseHtmlEvent::beginData(document(), m_input.current(
).currentLine().zeroBasedInt())); |
596 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "
CallStack", "stack", InspectorCallStackEvent::currentCallStack()); | 584 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "
CallStack", "stack", InspectorCallStackEvent::currentCallStack()); |
597 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeli
ne migrates to tracing. | 585 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeli
ne migrates to tracing. |
598 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willWriteH
TML(document(), m_input.current().currentLine().zeroBasedInt()); | 586 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willWriteH
TML(document(), m_input.current().currentLine().zeroBasedInt()); |
599 | 587 |
600 m_xssAuditor.init(document(), &m_xssAuditorDelegate); | 588 m_xssAuditor.init(document(), &m_xssAuditorDelegate); |
601 | 589 |
602 while (canTakeNextToken(mode, session) && !session.needsYield) { | 590 while (canTakeNextToken(session) && !session.needsYield) { |
603 if (!isParsingFragment()) | 591 if (!isParsingFragment()) |
604 m_sourceTracker.start(m_input.current(), m_tokenizer.get(), token())
; | 592 m_sourceTracker.start(m_input.current(), m_tokenizer.get(), token())
; |
605 | 593 |
606 if (!m_tokenizer->nextToken(m_input.current(), token())) | 594 if (!m_tokenizer->nextToken(m_input.current(), token())) |
607 break; | 595 break; |
608 | 596 |
609 if (!isParsingFragment()) { | 597 if (!isParsingFragment()) { |
610 m_sourceTracker.end(m_input.current(), m_tokenizer.get(), token()); | 598 m_sourceTracker.end(m_input.current(), m_tokenizer.get(), token()); |
611 | 599 |
612 // We do not XSS filter innerHTML, which means we (intentionally) fa
il | 600 // We do not XSS filter innerHTML, which means we (intentionally) fa
il |
(...skipping 10 matching lines...) Expand all Loading... |
623 // Ensure we haven't been totally deref'ed after pumping. Any caller of this | 611 // Ensure we haven't been totally deref'ed after pumping. Any caller of this |
624 // function should be holding a RefPtr to this to ensure we weren't deleted. | 612 // function should be holding a RefPtr to this to ensure we weren't deleted. |
625 ASSERT(refCount() >= 1); | 613 ASSERT(refCount() >= 1); |
626 #endif | 614 #endif |
627 | 615 |
628 if (isStopped()) | 616 if (isStopped()) |
629 return; | 617 return; |
630 | 618 |
631 // There should only be PendingText left since the tree-builder always flush
es | 619 // There should only be PendingText left since the tree-builder always flush
es |
632 // the task queue before returning. In case that ever changes, crash. | 620 // the task queue before returning. In case that ever changes, crash. |
633 if (mode == ForceSynchronous) | 621 m_treeBuilder->flush(FlushAlways); |
634 m_treeBuilder->flush(FlushAlways); | |
635 RELEASE_ASSERT(!isStopped()); | 622 RELEASE_ASSERT(!isStopped()); |
636 | 623 |
637 if (session.needsYield) | 624 if (session.needsYield) |
638 m_parserScheduler->scheduleForResume(); | 625 m_parserScheduler->scheduleForResume(); |
639 | 626 |
640 if (isWaitingForScripts()) { | 627 if (isWaitingForScripts()) { |
641 ASSERT(m_tokenizer->state() == HTMLTokenizer::DataState); | 628 ASSERT(m_tokenizer->state() == HTMLTokenizer::DataState); |
642 if (!m_preloadScanner) { | 629 if (!m_preloadScanner) { |
643 m_preloadScanner = adoptPtr(new HTMLPreloadScanner(m_options, docume
nt()->url(), createMediaValues(document()))); | 630 m_preloadScanner = adoptPtr(new HTMLPreloadScanner(m_options, docume
nt()->url(), createMediaValues(document()))); |
644 m_preloadScanner->appendToEnd(m_input.current()); | 631 m_preloadScanner->appendToEnd(m_input.current()); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
706 if (!m_tokenizer) { | 693 if (!m_tokenizer) { |
707 ASSERT(!inPumpSession()); | 694 ASSERT(!inPumpSession()); |
708 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); | 695 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); |
709 m_token = adoptPtr(new HTMLToken); | 696 m_token = adoptPtr(new HTMLToken); |
710 m_tokenizer = HTMLTokenizer::create(m_options); | 697 m_tokenizer = HTMLTokenizer::create(m_options); |
711 } | 698 } |
712 | 699 |
713 SegmentedString excludedLineNumberSource(source); | 700 SegmentedString excludedLineNumberSource(source); |
714 excludedLineNumberSource.setExcludeLineNumbers(); | 701 excludedLineNumberSource.setExcludeLineNumbers(); |
715 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); | 702 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); |
716 pumpTokenizerIfPossible(ForceSynchronous); | 703 pumpTokenizerIfPossible(); |
717 | 704 |
718 if (isWaitingForScripts()) { | 705 if (isWaitingForScripts()) { |
719 // Check the document.write() output with a separate preload scanner as | 706 // Check the document.write() output with a separate preload scanner as |
720 // the main scanner can't deal with insertions. | 707 // the main scanner can't deal with insertions. |
721 if (!m_insertionPreloadScanner) | 708 if (!m_insertionPreloadScanner) |
722 m_insertionPreloadScanner = adoptPtr(new HTMLPreloadScanner(m_option
s, document()->url(), createMediaValues(document()))); | 709 m_insertionPreloadScanner = adoptPtr(new HTMLPreloadScanner(m_option
s, document()->url(), createMediaValues(document()))); |
723 | 710 |
724 m_insertionPreloadScanner->appendToEnd(source); | 711 m_insertionPreloadScanner->appendToEnd(source); |
725 m_insertionPreloadScanner->scan(m_preloader.get(), document()->baseEleme
ntURL()); | 712 m_insertionPreloadScanner->scan(m_preloader.get(), document()->baseEleme
ntURL()); |
726 } | 713 } |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
802 // not worry. We'll consume this data in a less-nested write(). | 789 // not worry. We'll consume this data in a less-nested write(). |
803 return; | 790 return; |
804 } | 791 } |
805 | 792 |
806 // A couple pinToMainThread() callers require synchronous parsing, but can't | 793 // A couple pinToMainThread() callers require synchronous parsing, but can't |
807 // easily use the insert() method, so we hack append() for them to be synchr
onous. | 794 // easily use the insert() method, so we hack append() for them to be synchr
onous. |
808 // javascript: url handling is one such caller. | 795 // javascript: url handling is one such caller. |
809 // FIXME: This is gross, and we should separate the concept of synchronous p
arsing | 796 // FIXME: This is gross, and we should separate the concept of synchronous p
arsing |
810 // from insert() so that only document.write() uses insert. | 797 // from insert() so that only document.write() uses insert. |
811 ASSERT(m_isPinnedToMainThread); | 798 ASSERT(m_isPinnedToMainThread); |
812 pumpTokenizerIfPossible(ForceSynchronous); | 799 pumpTokenizerIfPossible(); |
813 | 800 |
814 endIfDelayed(); | 801 endIfDelayed(); |
815 } | 802 } |
816 | 803 |
817 void HTMLDocumentParser::end() | 804 void HTMLDocumentParser::end() |
818 { | 805 { |
819 ASSERT(!isDetached()); | 806 ASSERT(!isDetached()); |
820 ASSERT(!isScheduledForResume()); | 807 ASSERT(!isScheduledForResume()); |
821 | 808 |
822 if (m_haveBackgroundParser) | 809 if (m_haveBackgroundParser) |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
956 validateSpeculations(m_lastChunkBeforeScript.release()); | 943 validateSpeculations(m_lastChunkBeforeScript.release()); |
957 ASSERT(!m_lastChunkBeforeScript); | 944 ASSERT(!m_lastChunkBeforeScript); |
958 // processParsedChunkFromBackgroundParser can cause this parser to be de
tached from the Document, | 945 // processParsedChunkFromBackgroundParser can cause this parser to be de
tached from the Document, |
959 // but we need to ensure it isn't deleted yet. | 946 // but we need to ensure it isn't deleted yet. |
960 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this); | 947 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this); |
961 pumpPendingSpeculations(); | 948 pumpPendingSpeculations(); |
962 return; | 949 return; |
963 } | 950 } |
964 | 951 |
965 m_insertionPreloadScanner.clear(); | 952 m_insertionPreloadScanner.clear(); |
966 pumpTokenizerIfPossible(ForceSynchronous); | 953 pumpTokenizerIfPossible(); |
967 endIfDelayed(); | 954 endIfDelayed(); |
968 } | 955 } |
969 | 956 |
970 void HTMLDocumentParser::appendCurrentInputStreamToPreloadScannerAndScan() | 957 void HTMLDocumentParser::appendCurrentInputStreamToPreloadScannerAndScan() |
971 { | 958 { |
972 ASSERT(m_preloadScanner); | 959 ASSERT(m_preloadScanner); |
973 m_preloadScanner->appendToEnd(m_input.current()); | 960 m_preloadScanner->appendToEnd(m_input.current()); |
974 m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL()); | 961 m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL()); |
975 } | 962 } |
976 | 963 |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1067 void HTMLDocumentParser::setDecoder(PassOwnPtr<TextResourceDecoder> decoder) | 1054 void HTMLDocumentParser::setDecoder(PassOwnPtr<TextResourceDecoder> decoder) |
1068 { | 1055 { |
1069 ASSERT(decoder); | 1056 ASSERT(decoder); |
1070 DecodedDataDocumentParser::setDecoder(decoder); | 1057 DecodedDataDocumentParser::setDecoder(decoder); |
1071 | 1058 |
1072 if (m_haveBackgroundParser) | 1059 if (m_haveBackgroundParser) |
1073 HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::setDeco
der, m_backgroundParser, takeDecoder())); | 1060 HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::setDeco
der, m_backgroundParser, takeDecoder())); |
1074 } | 1061 } |
1075 | 1062 |
1076 } | 1063 } |
OLD | NEW |