OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. | 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. |
3 * Copyright (C) 2011 Apple Inc. All rights reserved. | 3 * Copyright (C) 2011 Apple Inc. All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 if (task.operation == HTMLConstructionSiteTask::Reparent) | 177 if (task.operation == HTMLConstructionSiteTask::Reparent) |
178 return executeReparentTask(task); | 178 return executeReparentTask(task); |
179 | 179 |
180 if (task.operation == HTMLConstructionSiteTask::TakeAllChildren) | 180 if (task.operation == HTMLConstructionSiteTask::TakeAllChildren) |
181 return executeTakeAllChildrenTask(task); | 181 return executeTakeAllChildrenTask(task); |
182 | 182 |
183 ASSERT_NOT_REACHED(); | 183 ASSERT_NOT_REACHED(); |
184 } | 184 } |
185 | 185 |
186 // This is only needed for TextDocuments where we might have text nodes | 186 // This is only needed for TextDocuments where we might have text nodes |
187 // approaching the default length limit (~64k) and we don't want to | 187 // approaching the default length limit (~64k) and we don't want to break a text |
188 // break a text node in the middle of a combining character. | 188 // node in the middle of a combining character. |
189 static unsigned findBreakIndexBetween(const StringBuilder& string, | 189 static unsigned findBreakIndexBetween(const StringBuilder& string, |
190 unsigned currentPosition, | 190 unsigned currentPosition, |
191 unsigned proposedBreakIndex) { | 191 unsigned proposedBreakIndex) { |
192 ASSERT(currentPosition < proposedBreakIndex); | 192 ASSERT(currentPosition < proposedBreakIndex); |
193 ASSERT(proposedBreakIndex <= string.length()); | 193 ASSERT(proposedBreakIndex <= string.length()); |
194 // The end of the string is always a valid break. | 194 // The end of the string is always a valid break. |
195 if (proposedBreakIndex == string.length()) | 195 if (proposedBreakIndex == string.length()) |
196 return proposedBreakIndex; | 196 return proposedBreakIndex; |
197 | 197 |
198 // Latin-1 does not have breakable boundaries. If we ever moved to a differnet
8-bit encoding this could be wrong. | 198 // Latin-1 does not have breakable boundaries. If we ever moved to a different |
| 199 // 8-bit encoding this could be wrong. |
199 if (string.is8Bit()) | 200 if (string.is8Bit()) |
200 return proposedBreakIndex; | 201 return proposedBreakIndex; |
201 | 202 |
202 const UChar* breakSearchCharacters = string.characters16() + currentPosition; | 203 const UChar* breakSearchCharacters = string.characters16() + currentPosition; |
203 // We need at least two characters look-ahead to account for UTF-16 surrogates
, but can't search off the end of the buffer! | 204 // We need at least two characters look-ahead to account for UTF-16 |
| 205 // surrogates, but can't search off the end of the buffer! |
204 unsigned breakSearchLength = | 206 unsigned breakSearchLength = |
205 std::min(proposedBreakIndex - currentPosition + 2, | 207 std::min(proposedBreakIndex - currentPosition + 2, |
206 string.length() - currentPosition); | 208 string.length() - currentPosition); |
207 NonSharedCharacterBreakIterator it(breakSearchCharacters, breakSearchLength); | 209 NonSharedCharacterBreakIterator it(breakSearchCharacters, breakSearchLength); |
208 | 210 |
209 if (it.isBreak(proposedBreakIndex - currentPosition)) | 211 if (it.isBreak(proposedBreakIndex - currentPosition)) |
210 return proposedBreakIndex; | 212 return proposedBreakIndex; |
211 | 213 |
212 int adjustedBreakIndexInSubstring = | 214 int adjustedBreakIndexInSubstring = |
213 it.preceding(proposedBreakIndex - currentPosition); | 215 it.preceding(proposedBreakIndex - currentPosition); |
214 if (adjustedBreakIndexInSubstring > 0) | 216 if (adjustedBreakIndexInSubstring > 0) |
215 return currentPosition + adjustedBreakIndexInSubstring; | 217 return currentPosition + adjustedBreakIndexInSubstring; |
216 // We failed to find a breakable point, let the caller figure out what to do. | 218 // We failed to find a breakable point, let the caller figure out what to do. |
217 return 0; | 219 return 0; |
218 } | 220 } |
219 | 221 |
220 static String atomizeIfAllWhitespace(const String& string, | 222 static String atomizeIfAllWhitespace(const String& string, |
221 WhitespaceMode whitespaceMode) { | 223 WhitespaceMode whitespaceMode) { |
222 // Strings composed entirely of whitespace are likely to be repeated. | 224 // Strings composed entirely of whitespace are likely to be repeated. Turn |
223 // Turn them into AtomicString so we share a single string for each. | 225 // them into AtomicString so we share a single string for each. |
224 if (whitespaceMode == AllWhitespace || | 226 if (whitespaceMode == AllWhitespace || |
225 (whitespaceMode == WhitespaceUnknown && isAllWhitespace(string))) | 227 (whitespaceMode == WhitespaceUnknown && isAllWhitespace(string))) |
226 return AtomicString(string).getString(); | 228 return AtomicString(string).getString(); |
227 return string; | 229 return string; |
228 } | 230 } |
229 | 231 |
230 void HTMLConstructionSite::flushPendingText(FlushMode mode) { | 232 void HTMLConstructionSite::flushPendingText(FlushMode mode) { |
231 if (m_pendingText.isEmpty()) | 233 if (m_pendingText.isEmpty()) |
232 return; | 234 return; |
233 | 235 |
234 if (mode == FlushIfAtTextLimit && | 236 if (mode == FlushIfAtTextLimit && |
235 !shouldUseLengthLimit(*m_pendingText.parent)) | 237 !shouldUseLengthLimit(*m_pendingText.parent)) |
236 return; | 238 return; |
237 | 239 |
238 PendingText pendingText; | 240 PendingText pendingText; |
239 // Hold onto the current pending text on the stack so that queueTask doesn't r
ecurse infinitely. | 241 // Hold onto the current pending text on the stack so that queueTask doesn't |
| 242 // recurse infinitely. |
240 m_pendingText.swap(pendingText); | 243 m_pendingText.swap(pendingText); |
241 ASSERT(m_pendingText.isEmpty()); | 244 ASSERT(m_pendingText.isEmpty()); |
242 | 245 |
243 // Splitting text nodes into smaller chunks contradicts HTML5 spec, but is nec
essary | 246 // Splitting text nodes into smaller chunks contradicts HTML5 spec, but is |
244 // for performance, see: https://bugs.webkit.org/show_bug.cgi?id=55898 | 247 // necessary for performance, see: |
| 248 // https://bugs.webkit.org/show_bug.cgi?id=55898 |
245 unsigned lengthLimit = textLengthLimitForContainer(*pendingText.parent); | 249 unsigned lengthLimit = textLengthLimitForContainer(*pendingText.parent); |
246 | 250 |
247 unsigned currentPosition = 0; | 251 unsigned currentPosition = 0; |
248 const StringBuilder& string = pendingText.stringBuilder; | 252 const StringBuilder& string = pendingText.stringBuilder; |
249 while (currentPosition < string.length()) { | 253 while (currentPosition < string.length()) { |
250 unsigned proposedBreakIndex = | 254 unsigned proposedBreakIndex = |
251 std::min(currentPosition + lengthLimit, string.length()); | 255 std::min(currentPosition + lengthLimit, string.length()); |
252 unsigned breakIndex = | 256 unsigned breakIndex = |
253 findBreakIndexBetween(string, currentPosition, proposedBreakIndex); | 257 findBreakIndexBetween(string, currentPosition, proposedBreakIndex); |
254 ASSERT(breakIndex <= string.length()); | 258 ASSERT(breakIndex <= string.length()); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert); | 291 HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert); |
288 task.parent = parent; | 292 task.parent = parent; |
289 task.child = child; | 293 task.child = child; |
290 task.selfClosing = selfClosing; | 294 task.selfClosing = selfClosing; |
291 | 295 |
292 if (shouldFosterParent()) { | 296 if (shouldFosterParent()) { |
293 fosterParent(task.child); | 297 fosterParent(task.child); |
294 return; | 298 return; |
295 } | 299 } |
296 | 300 |
297 // Add as a sibling of the parent if we have reached the maximum depth allowed
. | 301 // Add as a sibling of the parent if we have reached the maximum depth |
| 302 // allowed. |
298 if (m_openElements.stackDepth() > maximumHTMLParserDOMTreeDepth && | 303 if (m_openElements.stackDepth() > maximumHTMLParserDOMTreeDepth && |
299 task.parent->parentNode()) | 304 task.parent->parentNode()) |
300 task.parent = task.parent->parentNode(); | 305 task.parent = task.parent->parentNode(); |
301 | 306 |
302 ASSERT(task.parent); | 307 ASSERT(task.parent); |
303 queueTask(task); | 308 queueTask(task); |
304 } | 309 } |
305 | 310 |
306 void HTMLConstructionSite::executeQueuedTasks() { | 311 void HTMLConstructionSite::executeQueuedTasks() { |
307 // This has no affect on pendingText, and we may have pendingText | 312 // This has no affect on pendingText, and we may have pendingText remaining |
308 // remaining after executing all other queued tasks. | 313 // after executing all other queued tasks. |
309 const size_t size = m_taskQueue.size(); | 314 const size_t size = m_taskQueue.size(); |
310 if (!size) | 315 if (!size) |
311 return; | 316 return; |
312 | 317 |
313 // Copy the task queue into a local variable in case executeTask | 318 // Copy the task queue into a local variable in case executeTask re-enters the |
314 // re-enters the parser. | 319 // parser. |
315 TaskQueue queue; | 320 TaskQueue queue; |
316 queue.swap(m_taskQueue); | 321 queue.swap(m_taskQueue); |
317 | 322 |
318 for (size_t i = 0; i < size; ++i) | 323 for (size_t i = 0; i < size; ++i) |
319 executeTask(queue[i]); | 324 executeTask(queue[i]); |
320 | 325 |
321 // We might be detached now. | 326 // We might be detached now. |
322 } | 327 } |
323 | 328 |
324 HTMLConstructionSite::HTMLConstructionSite( | 329 HTMLConstructionSite::HTMLConstructionSite( |
(...skipping 19 matching lines...) Expand all Loading... |
344 DCHECK(!m_form); | 349 DCHECK(!m_form); |
345 | 350 |
346 m_attachmentRoot = fragment; | 351 m_attachmentRoot = fragment; |
347 m_isParsingFragment = true; | 352 m_isParsingFragment = true; |
348 | 353 |
349 if (!contextElement->document().isTemplateDocument()) | 354 if (!contextElement->document().isTemplateDocument()) |
350 m_form = Traversal<HTMLFormElement>::firstAncestorOrSelf(*contextElement); | 355 m_form = Traversal<HTMLFormElement>::firstAncestorOrSelf(*contextElement); |
351 } | 356 } |
352 | 357 |
353 HTMLConstructionSite::~HTMLConstructionSite() { | 358 HTMLConstructionSite::~HTMLConstructionSite() { |
354 // Depending on why we're being destroyed it might be OK | 359 // Depending on why we're being destroyed it might be OK to forget queued |
355 // to forget queued tasks, but currently we don't expect to. | 360 // tasks, but currently we don't expect to. |
356 ASSERT(m_taskQueue.isEmpty()); | 361 ASSERT(m_taskQueue.isEmpty()); |
357 // Currently we assume that text will never be the last token in the | 362 // Currently we assume that text will never be the last token in the document |
358 // document and that we'll always queue some additional task to cause it to fl
ush. | 363 // and that we'll always queue some additional task to cause it to flush. |
359 ASSERT(m_pendingText.isEmpty()); | 364 ASSERT(m_pendingText.isEmpty()); |
360 } | 365 } |
361 | 366 |
362 DEFINE_TRACE(HTMLConstructionSite) { | 367 DEFINE_TRACE(HTMLConstructionSite) { |
363 visitor->trace(m_document); | 368 visitor->trace(m_document); |
364 visitor->trace(m_attachmentRoot); | 369 visitor->trace(m_attachmentRoot); |
365 visitor->trace(m_head); | 370 visitor->trace(m_head); |
366 visitor->trace(m_form); | 371 visitor->trace(m_form); |
367 visitor->trace(m_openElements); | 372 visitor->trace(m_openElements); |
368 visitor->trace(m_activeFormattingElements); | 373 visitor->trace(m_activeFormattingElements); |
369 visitor->trace(m_taskQueue); | 374 visitor->trace(m_taskQueue); |
370 visitor->trace(m_pendingText); | 375 visitor->trace(m_pendingText); |
371 } | 376 } |
372 | 377 |
373 void HTMLConstructionSite::detach() { | 378 void HTMLConstructionSite::detach() { |
374 // FIXME: We'd like to ASSERT here that we're canceling and not just discardin
g | 379 // FIXME: We'd like to ASSERT here that we're canceling and not just |
375 // text that really should have made it into the DOM earlier, but there | 380 // discarding text that really should have made it into the DOM earlier, but |
376 // doesn't seem to be a nice way to do that. | 381 // there doesn't seem to be a nice way to do that. |
377 m_pendingText.discard(); | 382 m_pendingText.discard(); |
378 m_document = nullptr; | 383 m_document = nullptr; |
379 m_attachmentRoot = nullptr; | 384 m_attachmentRoot = nullptr; |
380 } | 385 } |
381 | 386 |
382 HTMLFormElement* HTMLConstructionSite::takeForm() { | 387 HTMLFormElement* HTMLConstructionSite::takeForm() { |
383 return m_form.release(); | 388 return m_form.release(); |
384 } | 389 } |
385 | 390 |
386 void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML( | 391 void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML( |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
434 Document::CompatibilityMode mode) { | 439 Document::CompatibilityMode mode) { |
435 m_inQuirksMode = (mode == Document::QuirksMode); | 440 m_inQuirksMode = (mode == Document::QuirksMode); |
436 m_document->setCompatibilityMode(mode); | 441 m_document->setCompatibilityMode(mode); |
437 } | 442 } |
438 | 443 |
439 void HTMLConstructionSite::setCompatibilityModeFromDoctype( | 444 void HTMLConstructionSite::setCompatibilityModeFromDoctype( |
440 const String& name, | 445 const String& name, |
441 const String& publicId, | 446 const String& publicId, |
442 const String& systemId) { | 447 const String& systemId) { |
443 // There are three possible compatibility modes: | 448 // There are three possible compatibility modes: |
444 // Quirks - quirks mode emulates WinIE and NS4. CSS parsing is also relaxed in
this mode, e.g., unit types can | 449 // Quirks - quirks mode emulates WinIE and NS4. CSS parsing is also relaxed in |
445 // be omitted from numbers. | 450 // this mode, e.g., unit types can be omitted from numbers. |
446 // Limited Quirks - This mode is identical to no-quirks mode except for its tr
eatment of line-height in the inline box model. | 451 // Limited Quirks - This mode is identical to no-quirks mode except for its |
447 // No Quirks - no quirks apply. Web pages will obey the specifications to the
letter. | 452 // treatment of line-height in the inline box model. |
| 453 // No Quirks - no quirks apply. Web pages will obey the specifications to the |
| 454 // letter. |
448 | 455 |
449 // Check for Quirks Mode. | 456 // Check for Quirks Mode. |
450 if (name != "html" || | 457 if (name != "html" || |
451 publicId.startsWith("+//Silmaril//dtd html Pro v0r11 19970101//", | 458 publicId.startsWith("+//Silmaril//dtd html Pro v0r11 19970101//", |
452 TextCaseInsensitive) || | 459 TextCaseInsensitive) || |
453 publicId.startsWith( | 460 publicId.startsWith( |
454 "-//AdvaSoft Ltd//DTD HTML 3.0 asWedit + extensions//", | 461 "-//AdvaSoft Ltd//DTD HTML 3.0 asWedit + extensions//", |
455 TextCaseInsensitive) || | 462 TextCaseInsensitive) || |
456 publicId.startsWith("-//AS//DTD HTML 3.0 asWedit + extensions//", | 463 publicId.startsWith("-//AS//DTD HTML 3.0 asWedit + extensions//", |
457 TextCaseInsensitive) || | 464 TextCaseInsensitive) || |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
586 setCompatibilityMode(Document::NoQuirksMode); | 593 setCompatibilityMode(Document::NoQuirksMode); |
587 } | 594 } |
588 | 595 |
589 void HTMLConstructionSite::processEndOfFile() { | 596 void HTMLConstructionSite::processEndOfFile() { |
590 ASSERT(currentNode()); | 597 ASSERT(currentNode()); |
591 flush(FlushAlways); | 598 flush(FlushAlways); |
592 openElements()->popAll(); | 599 openElements()->popAll(); |
593 } | 600 } |
594 | 601 |
595 void HTMLConstructionSite::finishedParsing() { | 602 void HTMLConstructionSite::finishedParsing() { |
596 // We shouldn't have any queued tasks but we might have pending text which we
need to promote to tasks and execute. | 603 // We shouldn't have any queued tasks but we might have pending text which we |
| 604 // need to promote to tasks and execute. |
597 ASSERT(m_taskQueue.isEmpty()); | 605 ASSERT(m_taskQueue.isEmpty()); |
598 flush(FlushAlways); | 606 flush(FlushAlways); |
599 m_document->finishedParsing(); | 607 m_document->finishedParsing(); |
600 } | 608 } |
601 | 609 |
602 void HTMLConstructionSite::insertDoctype(AtomicHTMLToken* token) { | 610 void HTMLConstructionSite::insertDoctype(AtomicHTMLToken* token) { |
603 ASSERT(token->type() == HTMLToken::DOCTYPE); | 611 ASSERT(token->type() == HTMLToken::DOCTYPE); |
604 | 612 |
605 const String& publicId = | 613 const String& publicId = |
606 StringImpl::create8BitIfPossible(token->publicIdentifier()); | 614 StringImpl::create8BitIfPossible(token->publicIdentifier()); |
607 const String& systemId = | 615 const String& systemId = |
608 StringImpl::create8BitIfPossible(token->systemIdentifier()); | 616 StringImpl::create8BitIfPossible(token->systemIdentifier()); |
609 DocumentType* doctype = | 617 DocumentType* doctype = |
610 DocumentType::create(m_document, token->name(), publicId, systemId); | 618 DocumentType::create(m_document, token->name(), publicId, systemId); |
611 attachLater(m_attachmentRoot, doctype); | 619 attachLater(m_attachmentRoot, doctype); |
612 | 620 |
613 // DOCTYPE nodes are only processed when parsing fragments w/o contextElements
, which | 621 // DOCTYPE nodes are only processed when parsing fragments w/o |
614 // never occurs. However, if we ever chose to support such, this code is subt
ly wrong, | 622 // contextElements, which never occurs. However, if we ever chose to support |
615 // because context-less fragments can determine their own quirks mode, and thu
s change | 623 // such, this code is subtly wrong, because context-less fragments can |
616 // parsing rules (like <p> inside <table>). For now we ASSERT that we never h
it this code | 624 // determine their own quirks mode, and thus change parsing rules (like <p> |
617 // in a fragment, as changing the owning document's compatibility mode would b
e wrong. | 625 // inside <table>). For now we ASSERT that we never hit this code in a |
| 626 // fragment, as changing the owning document's compatibility mode would be |
| 627 // wrong. |
618 ASSERT(!m_isParsingFragment); | 628 ASSERT(!m_isParsingFragment); |
619 if (m_isParsingFragment) | 629 if (m_isParsingFragment) |
620 return; | 630 return; |
621 | 631 |
622 if (token->forceQuirks()) | 632 if (token->forceQuirks()) |
623 setCompatibilityMode(Document::QuirksMode); | 633 setCompatibilityMode(Document::QuirksMode); |
624 else { | 634 else { |
625 setCompatibilityModeFromDoctype(token->name(), publicId, systemId); | 635 setCompatibilityModeFromDoctype(token->name(), publicId, systemId); |
626 } | 636 } |
627 } | 637 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
694 // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#th
e-stack-of-open-elements | 704 // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#th
e-stack-of-open-elements |
695 // Possible active formatting elements include: | 705 // Possible active formatting elements include: |
696 // a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u. | 706 // a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u. |
697 insertHTMLElement(token); | 707 insertHTMLElement(token); |
698 m_activeFormattingElements.append(currentElementRecord()->stackItem()); | 708 m_activeFormattingElements.append(currentElementRecord()->stackItem()); |
699 } | 709 } |
700 | 710 |
701 void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token) { | 711 void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token) { |
702 // http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.htm
l#already-started | 712 // http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.htm
l#already-started |
703 // http://html5.org/specs/dom-parsing.html#dom-range-createcontextualfragment | 713 // http://html5.org/specs/dom-parsing.html#dom-range-createcontextualfragment |
704 // For createContextualFragment, the specifications say to mark it parser-inse
rted and already-started and later unmark them. | 714 // For createContextualFragment, the specifications say to mark it |
705 // However, we short circuit that logic to avoid the subtree traversal to find
script elements since scripts can never see | 715 // parser-inserted and already-started and later unmark them. However, we |
706 // those flags or effects thereof. | 716 // short circuit that logic to avoid the subtree traversal to find script |
| 717 // elements since scripts can never see those flags or effects thereof. |
707 const bool parserInserted = | 718 const bool parserInserted = |
708 m_parserContentPolicy != AllowScriptingContentAndDoNotMarkAlreadyStarted; | 719 m_parserContentPolicy != AllowScriptingContentAndDoNotMarkAlreadyStarted; |
709 const bool alreadyStarted = m_isParsingFragment && parserInserted; | 720 const bool alreadyStarted = m_isParsingFragment && parserInserted; |
710 // TODO(csharrison): This logic only works if the tokenizer/parser was not | 721 // TODO(csharrison): This logic only works if the tokenizer/parser was not |
711 // blocked waiting for scripts when the element was inserted. This usually | 722 // blocked waiting for scripts when the element was inserted. This usually |
712 // fails for instance, on second document.write if a script writes twice in | 723 // fails for instance, on second document.write if a script writes twice in a |
713 // a row. To fix this, the parser might have to keep track of raw string | 724 // row. To fix this, the parser might have to keep track of raw string |
714 // position. | 725 // position. |
715 // TODO(csharrison): Refactor this so that the bools that are passed in are | 726 // TODO(csharrison): Refactor this so that the bools that are passed |
716 // packed in a bitfield from an enum class. | 727 // in are packed in a bitfield from an enum class. |
717 const bool createdDuringDocumentWrite = | 728 const bool createdDuringDocumentWrite = |
718 ownerDocumentForCurrentNode().isInDocumentWrite(); | 729 ownerDocumentForCurrentNode().isInDocumentWrite(); |
719 HTMLScriptElement* element = | 730 HTMLScriptElement* element = |
720 HTMLScriptElement::create(ownerDocumentForCurrentNode(), parserInserted, | 731 HTMLScriptElement::create(ownerDocumentForCurrentNode(), parserInserted, |
721 alreadyStarted, createdDuringDocumentWrite); | 732 alreadyStarted, createdDuringDocumentWrite); |
722 setAttributes(element, token, m_parserContentPolicy); | 733 setAttributes(element, token, m_parserContentPolicy); |
723 if (scriptingContentIsAllowed(m_parserContentPolicy)) | 734 if (scriptingContentIsAllowed(m_parserContentPolicy)) |
724 attachLater(currentNode(), element); | 735 attachLater(currentNode(), element); |
725 m_openElements.push(HTMLStackItem::create(element, token)); | 736 m_openElements.push(HTMLStackItem::create(element, token)); |
726 } | 737 } |
727 | 738 |
728 void HTMLConstructionSite::insertForeignElement( | 739 void HTMLConstructionSite::insertForeignElement( |
729 AtomicHTMLToken* token, | 740 AtomicHTMLToken* token, |
730 const AtomicString& namespaceURI) { | 741 const AtomicString& namespaceURI) { |
731 ASSERT(token->type() == HTMLToken::StartTag); | 742 ASSERT(token->type() == HTMLToken::StartTag); |
732 DVLOG(1) | 743 // parseError when xmlns or xmlns:xlink are wrong. |
733 << "Not implemented."; // parseError when xmlns or xmlns:xlink are wrong. | 744 DVLOG(1) << "Not implemented."; |
734 | 745 |
735 Element* element = createElement(token, namespaceURI); | 746 Element* element = createElement(token, namespaceURI); |
736 if (scriptingContentIsAllowed(m_parserContentPolicy) || | 747 if (scriptingContentIsAllowed(m_parserContentPolicy) || |
737 !toScriptLoaderIfPossible(element)) | 748 !toScriptLoaderIfPossible(element)) |
738 attachLater(currentNode(), element, token->selfClosing()); | 749 attachLater(currentNode(), element, token->selfClosing()); |
739 if (!token->selfClosing()) | 750 if (!token->selfClosing()) |
740 m_openElements.push(HTMLStackItem::create(element, token, namespaceURI)); | 751 m_openElements.push(HTMLStackItem::create(element, token, namespaceURI)); |
741 } | 752 } |
742 | 753 |
743 void HTMLConstructionSite::insertTextNode(const String& string, | 754 void HTMLConstructionSite::insertTextNode(const String& string, |
744 WhitespaceMode whitespaceMode) { | 755 WhitespaceMode whitespaceMode) { |
745 HTMLConstructionSiteTask dummyTask(HTMLConstructionSiteTask::Insert); | 756 HTMLConstructionSiteTask dummyTask(HTMLConstructionSiteTask::Insert); |
746 dummyTask.parent = currentNode(); | 757 dummyTask.parent = currentNode(); |
747 | 758 |
748 if (shouldFosterParent()) | 759 if (shouldFosterParent()) |
749 findFosterSite(dummyTask); | 760 findFosterSite(dummyTask); |
750 | 761 |
751 // FIXME: This probably doesn't need to be done both here and in insert(Task). | 762 // FIXME: This probably doesn't need to be done both here and in insert(Task). |
752 if (isHTMLTemplateElement(*dummyTask.parent)) | 763 if (isHTMLTemplateElement(*dummyTask.parent)) |
753 dummyTask.parent = toHTMLTemplateElement(dummyTask.parent.get())->content(); | 764 dummyTask.parent = toHTMLTemplateElement(dummyTask.parent.get())->content(); |
754 | 765 |
755 // Unclear when parent != case occurs. Somehow we insert text into two separat
e nodes while processing the same Token. | 766 // Unclear when parent != case occurs. Somehow we insert text into two |
756 // The nextChild != dummy.nextChild case occurs whenever foster parenting happ
ened and we hit a new text node "<table>a</table>b" | 767 // separate nodes while processing the same Token. The nextChild != |
757 // In either case we have to flush the pending text into the task queue before
making more. | 768 // dummy.nextChild case occurs whenever foster parenting happened and we hit a |
| 769 // new text node "<table>a</table>b" In either case we have to flush the |
| 770 // pending text into the task queue before making more. |
758 if (!m_pendingText.isEmpty() && | 771 if (!m_pendingText.isEmpty() && |
759 (m_pendingText.parent != dummyTask.parent || | 772 (m_pendingText.parent != dummyTask.parent || |
760 m_pendingText.nextChild != dummyTask.nextChild)) | 773 m_pendingText.nextChild != dummyTask.nextChild)) |
761 flushPendingText(FlushAlways); | 774 flushPendingText(FlushAlways); |
762 m_pendingText.append(dummyTask.parent, dummyTask.nextChild, string, | 775 m_pendingText.append(dummyTask.parent, dummyTask.nextChild, string, |
763 whitespaceMode); | 776 whitespaceMode); |
764 } | 777 } |
765 | 778 |
766 void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord* newParent, | 779 void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord* newParent, |
767 HTMLElementStack::ElementRecord* child) { | 780 HTMLElementStack::ElementRecord* child) { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
842 const Attribute* isAttribute = token->getAttributeItem(HTMLNames::isAttr); | 855 const Attribute* isAttribute = token->getAttributeItem(HTMLNames::isAttr); |
843 const AtomicString& name = isAttribute ? isAttribute->value() : localName; | 856 const AtomicString& name = isAttribute ? isAttribute->value() : localName; |
844 CustomElementDescriptor descriptor(name, localName); | 857 CustomElementDescriptor descriptor(name, localName); |
845 | 858 |
846 // 4.-6. | 859 // 4.-6. |
847 return registry->definitionFor(descriptor); | 860 return registry->definitionFor(descriptor); |
848 } | 861 } |
849 | 862 |
850 // "create an element for a token" | 863 // "create an element for a token" |
851 // https://html.spec.whatwg.org/#create-an-element-for-the-token | 864 // https://html.spec.whatwg.org/#create-an-element-for-the-token |
852 // TODO(dominicc): When form association is separate from creation, | 865 // TODO(dominicc): When form association is separate from creation, unify this |
853 // unify this with foreign element creation. Add a namespace parameter | 866 // with foreign element creation. Add a namespace parameter and check for HTML |
854 // and check for HTML namespace to lookupCustomElementDefinition. | 867 // namespace to lookupCustomElementDefinition. |
855 HTMLElement* HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token) { | 868 HTMLElement* HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token) { |
856 // "1. Let document be intended parent's node document." | 869 // "1. Let document be intended parent's node document." |
857 Document& document = ownerDocumentForCurrentNode(); | 870 Document& document = ownerDocumentForCurrentNode(); |
858 | 871 |
859 // Only associate the element with the current form if we're creating the new
element | 872 // Only associate the element with the current form if we're creating the new |
860 // in a document with a browsing context (rather than in <template> contents). | 873 // element in a document with a browsing context (rather than in <template> |
| 874 // contents). |
861 // TODO(dominicc): Change form to happen after element creation when | 875 // TODO(dominicc): Change form to happen after element creation when |
862 // implementing customized built-in elements. | 876 // implementing customized built-in elements. |
863 HTMLFormElement* form = document.frame() ? m_form.get() : nullptr; | 877 HTMLFormElement* form = document.frame() ? m_form.get() : nullptr; |
864 | 878 |
865 // "2. Let local name be the tag name of the token." | 879 // "2. Let local name be the tag name of the token." |
866 // "3. Let is be the value of the "is" attribute in the giev token ..." etc. | 880 // "3. Let is be the value of the "is" attribute in the giev token ..." etc. |
867 // "4. Let definition be the result of looking up a custom element ..." etc. | 881 // "4. Let definition be the result of looking up a custom element ..." etc. |
868 CustomElementDefinition* definition = | 882 CustomElementDefinition* definition = |
869 m_isParsingFragment ? nullptr | 883 m_isParsingFragment ? nullptr |
870 : lookUpCustomElementDefinition(document, token); | 884 : lookUpCustomElementDefinition(document, token); |
871 // "5. If definition is non-null and the parser was not originally created | 885 // "5. If definition is non-null and the parser was not originally created |
872 // for the HTML fragment parsing algorithm, then let will execute script | 886 // for the HTML fragment parsing algorithm, then let will execute script |
873 // be true." | 887 // be true." |
874 bool willExecuteScript = definition && !m_isParsingFragment; | 888 bool willExecuteScript = definition && !m_isParsingFragment; |
875 | 889 |
876 HTMLElement* element; | 890 HTMLElement* element; |
877 | 891 |
878 if (willExecuteScript) { | 892 if (willExecuteScript) { |
879 // "6.1 Increment the document's throw-on-dynamic-insertion counter." | 893 // "6.1 Increment the document's throw-on-dynamic-insertion counter." |
880 ThrowOnDynamicMarkupInsertionCountIncrementer | 894 ThrowOnDynamicMarkupInsertionCountIncrementer |
881 throwOnDynamicMarkupInsertions(&document); | 895 throwOnDynamicMarkupInsertions(&document); |
882 | 896 |
883 // "6.2 If the JavaScript execution context stack is empty, | 897 // "6.2 If the JavaScript execution context stack is empty, |
884 // then perform a microtask checkpoint." | 898 // then perform a microtask checkpoint." |
885 | 899 |
886 // TODO(dominicc): This is the way the Blink HTML parser | 900 // TODO(dominicc): This is the way the Blink HTML parser performs |
887 // performs checkpoints, but note the spec is different--it | 901 // checkpoints, but note the spec is different--it talks about the |
888 // talks about the JavaScript stack, not the script nesting | 902 // JavaScript stack, not the script nesting level. |
889 // level. | |
890 if (0u == m_reentryPermit->scriptNestingLevel()) | 903 if (0u == m_reentryPermit->scriptNestingLevel()) |
891 Microtask::performCheckpoint(V8PerIsolateData::mainThreadIsolate()); | 904 Microtask::performCheckpoint(V8PerIsolateData::mainThreadIsolate()); |
892 | 905 |
893 // "6.3 Push a new element queue onto the custom element | 906 // "6.3 Push a new element queue onto the custom element |
894 // reactions stack." | 907 // reactions stack." |
895 CEReactionsScope reactions; | 908 CEReactionsScope reactions; |
896 | 909 |
897 // 7. | 910 // 7. |
898 QualifiedName elementQName(nullAtom, token->name(), | 911 QualifiedName elementQName(nullAtom, token->name(), |
899 HTMLNames::xhtmlNamespaceURI); | 912 HTMLNames::xhtmlNamespaceURI); |
900 element = definition->createElementSync(document, elementQName); | 913 element = definition->createElementSync(document, elementQName); |
901 | 914 |
902 // "8. Append each attribute in the given token to element." | 915 // "8. Append each attribute in the given token to element." We don't use |
903 // We don't use setAttributes here because the custom element | 916 // setAttributes here because the custom element constructor may have |
904 // constructor may have manipulated attributes. | 917 // manipulated attributes. |
905 for (const auto& attribute : token->attributes()) | 918 for (const auto& attribute : token->attributes()) |
906 element->setAttribute(attribute.name(), attribute.value()); | 919 element->setAttribute(attribute.name(), attribute.value()); |
907 | 920 |
908 // "9. If will execute script is true, then ..." etc. The | 921 // "9. If will execute script is true, then ..." etc. The CEReactionsScope |
909 // CEReactionsScope and ThrowOnDynamicMarkupInsertionCountIncrementer | 922 // and ThrowOnDynamicMarkupInsertionCountIncrementer destructors implement |
910 // destructors implement steps 9.1-3. | 923 // steps 9.1-3. |
911 } else { | 924 } else { |
912 // FIXME: This can't use | 925 // FIXME: This can't use HTMLConstructionSite::createElement because we have |
913 // HTMLConstructionSite::createElement because we have to | 926 // to pass the current form element. We should rework form association to |
914 // pass the current form element. We should rework form | 927 // occur after construction to allow better code sharing here. |
915 // association to occur after construction to allow better | |
916 // code sharing here. | |
917 element = HTMLElementFactory::createHTMLElement( | 928 element = HTMLElementFactory::createHTMLElement( |
918 token->name(), document, form, getCreateElementFlags()); | 929 token->name(), document, form, getCreateElementFlags()); |
919 // Definition for the created element does not exist here and | 930 // Definition for the created element does not exist here and it cannot be |
920 // it cannot be custom or failed. | 931 // custom or failed. |
921 DCHECK_NE(element->getCustomElementState(), CustomElementState::Custom); | 932 DCHECK_NE(element->getCustomElementState(), CustomElementState::Custom); |
922 DCHECK_NE(element->getCustomElementState(), CustomElementState::Failed); | 933 DCHECK_NE(element->getCustomElementState(), CustomElementState::Failed); |
923 | 934 |
924 // "8. Append each attribute in the given token to element." | 935 // "8. Append each attribute in the given token to element." |
925 setAttributes(element, token, m_parserContentPolicy); | 936 setAttributes(element, token, m_parserContentPolicy); |
926 } | 937 } |
927 | 938 |
928 // TODO(dominicc): Implement steps 10-12 when customized built-in | 939 // TODO(dominicc): Implement steps 10-12 when customized built-in elements are |
929 // elements are implemented. | 940 // implemented. |
930 | 941 |
931 return element; | 942 return element; |
932 } | 943 } |
933 | 944 |
934 HTMLStackItem* HTMLConstructionSite::createElementFromSavedToken( | 945 HTMLStackItem* HTMLConstructionSite::createElementFromSavedToken( |
935 HTMLStackItem* item) { | 946 HTMLStackItem* item) { |
936 Element* element; | 947 Element* element; |
937 // NOTE: Moving from item -> token -> item copies the Attribute vector twice! | 948 // NOTE: Moving from item -> token -> item copies the Attribute vector twice! |
938 AtomicHTMLToken fakeToken(HTMLToken::StartTag, item->localName(), | 949 AtomicHTMLToken fakeToken(HTMLToken::StartTag, item->localName(), |
939 item->attributes()); | 950 item->attributes()); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
990 | 1001 |
991 void HTMLConstructionSite::generateImpliedEndTags() { | 1002 void HTMLConstructionSite::generateImpliedEndTags() { |
992 while (hasImpliedEndTag(currentStackItem())) | 1003 while (hasImpliedEndTag(currentStackItem())) |
993 m_openElements.pop(); | 1004 m_openElements.pop(); |
994 } | 1005 } |
995 | 1006 |
996 bool HTMLConstructionSite::inQuirksMode() { | 1007 bool HTMLConstructionSite::inQuirksMode() { |
997 return m_inQuirksMode; | 1008 return m_inQuirksMode; |
998 } | 1009 } |
999 | 1010 |
1000 // Adjusts |task| to match the "adjusted insertion location" determined by the f
oster parenting algorithm, | 1011 // Adjusts |task| to match the "adjusted insertion location" determined by the |
1001 // laid out as the substeps of step 2 of https://html.spec.whatwg.org/#appropria
te-place-for-inserting-a-node | 1012 // foster parenting algorithm, laid out as the substeps of step 2 of |
| 1013 // https://html.spec.whatwg.org/#appropriate-place-for-inserting-a-node |
1002 void HTMLConstructionSite::findFosterSite(HTMLConstructionSiteTask& task) { | 1014 void HTMLConstructionSite::findFosterSite(HTMLConstructionSiteTask& task) { |
1003 // 2.1 | 1015 // 2.1 |
1004 HTMLElementStack::ElementRecord* lastTemplate = | 1016 HTMLElementStack::ElementRecord* lastTemplate = |
1005 m_openElements.topmost(templateTag.localName()); | 1017 m_openElements.topmost(templateTag.localName()); |
1006 | 1018 |
1007 // 2.2 | 1019 // 2.2 |
1008 HTMLElementStack::ElementRecord* lastTable = | 1020 HTMLElementStack::ElementRecord* lastTable = |
1009 m_openElements.topmost(tableTag.localName()); | 1021 m_openElements.topmost(tableTag.localName()); |
1010 | 1022 |
1011 // 2.3 | 1023 // 2.3 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1045 ASSERT(task.parent); | 1057 ASSERT(task.parent); |
1046 queueTask(task); | 1058 queueTask(task); |
1047 } | 1059 } |
1048 | 1060 |
1049 DEFINE_TRACE(HTMLConstructionSite::PendingText) { | 1061 DEFINE_TRACE(HTMLConstructionSite::PendingText) { |
1050 visitor->trace(parent); | 1062 visitor->trace(parent); |
1051 visitor->trace(nextChild); | 1063 visitor->trace(nextChild); |
1052 } | 1064 } |
1053 | 1065 |
1054 } // namespace blink | 1066 } // namespace blink |
OLD | NEW |