Chromium Code Reviews| 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 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 112 ASSERT(task.operation == HTMLConstructionSiteTask::Insert); | 112 ASSERT(task.operation == HTMLConstructionSiteTask::Insert); |
| 113 | 113 |
| 114 insert(task); | 114 insert(task); |
| 115 | 115 |
| 116 task.child->beginParsingChildren(); | 116 task.child->beginParsingChildren(); |
| 117 | 117 |
| 118 if (task.selfClosing) | 118 if (task.selfClosing) |
| 119 task.child->finishParsingChildren(); | 119 task.child->finishParsingChildren(); |
| 120 } | 120 } |
| 121 | 121 |
| 122 static inline void executeInsertTextTask(HTMLConstructionSiteTask& task) | |
| 123 { | |
| 124 ASSERT(task.operation == HTMLConstructionSiteTask::InsertText); | |
| 125 ASSERT(task.child->isTextNode()); | |
| 126 | |
| 127 // Merge text nodes into previous ones if possible: | |
| 128 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construc tion.html#insert-a-character | |
| 129 Text* newText = toText(task.child.get()); | |
| 130 Node* previousChild = task.nextChild ? task.nextChild->previousSibling() : t ask.parent->lastChild(); | |
| 131 if (previousChild && previousChild->isTextNode()) { | |
| 132 Text* previousText = toText(previousChild); | |
| 133 unsigned lengthLimit = textLengthLimitForContainer(task.parent.get()); | |
| 134 if (previousText->length() + newText->length() < lengthLimit) { | |
| 135 previousText->parserAppendData(newText->data()); | |
| 136 return; | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 insert(task); | |
| 141 } | |
| 142 | |
| 122 static inline void executeReparentTask(HTMLConstructionSiteTask& task) | 143 static inline void executeReparentTask(HTMLConstructionSiteTask& task) |
| 123 { | 144 { |
| 124 ASSERT(task.operation == HTMLConstructionSiteTask::Reparent); | 145 ASSERT(task.operation == HTMLConstructionSiteTask::Reparent); |
| 125 | 146 |
| 126 if (ContainerNode* parent = task.child->parentNode()) | 147 if (ContainerNode* parent = task.child->parentNode()) |
| 127 parent->parserRemoveChild(task.child.get()); | 148 parent->parserRemoveChild(task.child.get()); |
| 128 | 149 |
| 129 task.parent->parserAppendChild(task.child); | 150 task.parent->parserAppendChild(task.child); |
| 130 } | 151 } |
| 131 | 152 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 142 | 163 |
| 143 task.parent->parserTakeAllChildrenFrom(task.oldParent()); | 164 task.parent->parserTakeAllChildrenFrom(task.oldParent()); |
| 144 } | 165 } |
| 145 | 166 |
| 146 void HTMLConstructionSite::executeTask(HTMLConstructionSiteTask& task) | 167 void HTMLConstructionSite::executeTask(HTMLConstructionSiteTask& task) |
| 147 { | 168 { |
| 148 ASSERT(m_taskQueue.isEmpty()); | 169 ASSERT(m_taskQueue.isEmpty()); |
| 149 if (task.operation == HTMLConstructionSiteTask::Insert) | 170 if (task.operation == HTMLConstructionSiteTask::Insert) |
| 150 return executeInsertTask(task); | 171 return executeInsertTask(task); |
| 151 | 172 |
| 173 if (task.operation == HTMLConstructionSiteTask::InsertText) | |
| 174 return executeInsertTextTask(task); | |
| 175 | |
| 152 // All the cases below this point are only used by the adoption agency. | 176 // All the cases below this point are only used by the adoption agency. |
| 153 | 177 |
| 154 if (task.operation == HTMLConstructionSiteTask::InsertAlreadyParsedChild) | 178 if (task.operation == HTMLConstructionSiteTask::InsertAlreadyParsedChild) |
| 155 return executeInsertAlreadyParsedChildTask(task); | 179 return executeInsertAlreadyParsedChildTask(task); |
| 156 | 180 |
| 157 if (task.operation == HTMLConstructionSiteTask::Reparent) | 181 if (task.operation == HTMLConstructionSiteTask::Reparent) |
| 158 return executeReparentTask(task); | 182 return executeReparentTask(task); |
| 159 | 183 |
| 160 if (task.operation == HTMLConstructionSiteTask::TakeAllChildren) | 184 if (task.operation == HTMLConstructionSiteTask::TakeAllChildren) |
| 161 return executeTakeAllChildrenTask(task); | 185 return executeTakeAllChildrenTask(task); |
| 162 | 186 |
| 163 ASSERT_NOT_REACHED(); | 187 ASSERT_NOT_REACHED(); |
| 164 } | 188 } |
| 165 | 189 |
| 166 // This is only needed for TextDocuments where we might have text nodes | 190 // This is only needed for TextDocuments where we might have text nodes |
| 167 // approaching the default length limit (~64k) and we don't want to | 191 // approaching the default length limit (~64k) and we don't want to |
| 168 // break a text node in the middle of a combining character. | 192 // break a text node in the middle of a combining character. |
| 169 static unsigned findBreakIndexBetween(const String& string, unsigned currentPosi tion, unsigned proposedBreakIndex) | 193 static unsigned findBreakIndexBetween(const StringBuilder& string, unsigned curr entPosition, unsigned proposedBreakIndex) |
| 170 { | 194 { |
| 171 ASSERT(currentPosition < proposedBreakIndex); | 195 ASSERT(currentPosition < proposedBreakIndex); |
| 172 ASSERT(proposedBreakIndex <= string.length()); | 196 ASSERT(proposedBreakIndex <= string.length()); |
| 173 // The end of the string is always a valid break. | 197 // The end of the string is always a valid break. |
| 174 if (proposedBreakIndex == string.length()) | 198 if (proposedBreakIndex == string.length()) |
| 175 return proposedBreakIndex; | 199 return proposedBreakIndex; |
| 176 | 200 |
| 177 // Latin-1 does not have breakable boundaries. If we ever moved to a differn et 8-bit encoding this could be wrong. | 201 // Latin-1 does not have breakable boundaries. If we ever moved to a differn et 8-bit encoding this could be wrong. |
| 178 if (string.is8Bit()) | 202 if (string.is8Bit()) |
| 179 return proposedBreakIndex; | 203 return proposedBreakIndex; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 195 | 219 |
| 196 static String atomizeIfAllWhitespace(const String& string, WhitespaceMode whites paceMode) | 220 static String atomizeIfAllWhitespace(const String& string, WhitespaceMode whites paceMode) |
| 197 { | 221 { |
| 198 // Strings composed entirely of whitespace are likely to be repeated. | 222 // Strings composed entirely of whitespace are likely to be repeated. |
| 199 // Turn them into AtomicString so we share a single string for each. | 223 // Turn them into AtomicString so we share a single string for each. |
| 200 if (whitespaceMode == AllWhitespace || (whitespaceMode == WhitespaceUnknown && isAllWhitespace(string))) | 224 if (whitespaceMode == AllWhitespace || (whitespaceMode == WhitespaceUnknown && isAllWhitespace(string))) |
| 201 return AtomicString(string).string(); | 225 return AtomicString(string).string(); |
| 202 return string; | 226 return string; |
| 203 } | 227 } |
| 204 | 228 |
| 229 void HTMLConstructionSite::flushPendingText() | |
| 230 { | |
| 231 if (m_pendingText.isEmpty()) | |
| 232 return; | |
| 233 | |
| 234 PendingText pendingText; | |
| 235 // Hold onto the current pending text on the stack so that queueTask doesn't recurse infinitely. | |
| 236 m_pendingText.swap(pendingText); | |
| 237 ASSERT(m_pendingText.isEmpty()); | |
| 238 | |
| 239 // Splitting text nodes into smaller chunks contradicts HTML5 spec, but is n ecessary | |
| 240 // for performance, see: https://bugs.webkit.org/show_bug.cgi?id=55898 | |
| 241 unsigned lengthLimit = textLengthLimitForContainer(pendingText.parent.get()) ; | |
| 242 | |
| 243 unsigned currentPosition = 0; | |
| 244 const StringBuilder& string = pendingText.stringBuilder; | |
| 245 while (currentPosition < string.length()) { | |
| 246 unsigned proposedBreakIndex = std::min(currentPosition + lengthLimit, st ring.length()); | |
| 247 unsigned breakIndex = findBreakIndexBetween(string, currentPosition, pro posedBreakIndex); | |
| 248 ASSERT(breakIndex <= string.length()); | |
| 249 String substring = string.substring(currentPosition, breakIndex - curren tPosition); | |
| 250 substring = atomizeIfAllWhitespace(substring, pendingText.whitespaceMode ); | |
| 251 | |
| 252 HTMLConstructionSiteTask task(HTMLConstructionSiteTask::InsertText); | |
| 253 task.parent = pendingText.parent; | |
| 254 task.nextChild = pendingText.nextChild; | |
| 255 task.child = Text::create(task.parent->document(), substring); | |
| 256 queueTask(task); | |
| 257 | |
| 258 ASSERT(breakIndex > currentPosition); | |
| 259 ASSERT(breakIndex - currentPosition == substring.length()); | |
| 260 ASSERT(toText(task.child.get())->length() == substring.length()); | |
| 261 currentPosition = breakIndex; | |
| 262 } | |
| 263 } | |
| 264 | |
| 205 void HTMLConstructionSite::queueTask(const HTMLConstructionSiteTask& task) | 265 void HTMLConstructionSite::queueTask(const HTMLConstructionSiteTask& task) |
| 206 { | 266 { |
| 267 flushPendingText(); | |
| 268 ASSERT(m_pendingText.isEmpty()); | |
| 207 m_taskQueue.append(task); | 269 m_taskQueue.append(task); |
| 208 } | 270 } |
| 209 | 271 |
| 210 void HTMLConstructionSite::attachLater(ContainerNode* parent, PassRefPtr<Node> p rpChild, bool selfClosing) | 272 void HTMLConstructionSite::attachLater(ContainerNode* parent, PassRefPtr<Node> p rpChild, bool selfClosing) |
| 211 { | 273 { |
| 212 ASSERT(scriptingContentIsAllowed(m_parserContentPolicy) || !prpChild.get()-> isElementNode() || !toScriptLoaderIfPossible(toElement(prpChild.get()))); | 274 ASSERT(scriptingContentIsAllowed(m_parserContentPolicy) || !prpChild.get()-> isElementNode() || !toScriptLoaderIfPossible(toElement(prpChild.get()))); |
| 213 ASSERT(pluginContentIsAllowed(m_parserContentPolicy) || !prpChild->isPluginE lement()); | 275 ASSERT(pluginContentIsAllowed(m_parserContentPolicy) || !prpChild->isPluginE lement()); |
| 214 | 276 |
| 215 HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert); | 277 HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert); |
| 216 task.parent = parent; | 278 task.parent = parent; |
| 217 task.child = prpChild; | 279 task.child = prpChild; |
| 218 task.selfClosing = selfClosing; | 280 task.selfClosing = selfClosing; |
| 219 | 281 |
| 220 if (shouldFosterParent()) { | 282 if (shouldFosterParent()) { |
| 221 fosterParent(task.child); | 283 fosterParent(task.child); |
| 222 return; | 284 return; |
| 223 } | 285 } |
| 224 | 286 |
| 225 // Add as a sibling of the parent if we have reached the maximum depth allow ed. | 287 // Add as a sibling of the parent if we have reached the maximum depth allow ed. |
| 226 if (m_openElements.stackDepth() > maximumHTMLParserDOMTreeDepth && task.pare nt->parentNode()) | 288 if (m_openElements.stackDepth() > maximumHTMLParserDOMTreeDepth && task.pare nt->parentNode()) |
| 227 task.parent = task.parent->parentNode(); | 289 task.parent = task.parent->parentNode(); |
| 228 | 290 |
| 229 ASSERT(task.parent); | 291 ASSERT(task.parent); |
| 230 queueTask(task); | 292 queueTask(task); |
| 231 } | 293 } |
| 232 | 294 |
| 233 void HTMLConstructionSite::executeQueuedTasks() | 295 void HTMLConstructionSite::executeQueuedTasks() |
| 234 { | 296 { |
| 297 // This has no affect on pendingText, and we may have pendingText | |
| 298 // remaining after executing all other queued tasks. | |
| 235 const size_t size = m_taskQueue.size(); | 299 const size_t size = m_taskQueue.size(); |
| 236 if (!size) | 300 if (!size) |
| 237 return; | 301 return; |
| 238 | 302 |
| 239 // Copy the task queue into a local variable in case executeTask | 303 // Copy the task queue into a local variable in case executeTask |
| 240 // re-enters the parser. | 304 // re-enters the parser. |
| 241 TaskQueue queue; | 305 TaskQueue queue; |
| 242 queue.swap(m_taskQueue); | 306 queue.swap(m_taskQueue); |
| 243 | 307 |
| 244 for (size_t i = 0; i < size; ++i) | 308 for (size_t i = 0; i < size; ++i) |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 267 , m_inQuirksMode(fragment->document().inQuirksMode()) | 331 , m_inQuirksMode(fragment->document().inQuirksMode()) |
| 268 { | 332 { |
| 269 ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument()); | 333 ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument()); |
| 270 } | 334 } |
| 271 | 335 |
| 272 HTMLConstructionSite::~HTMLConstructionSite() | 336 HTMLConstructionSite::~HTMLConstructionSite() |
| 273 { | 337 { |
| 274 // Depending on why we're being destroyed it might be OK | 338 // Depending on why we're being destroyed it might be OK |
| 275 // to forget queued tasks, but currently we don't expect to. | 339 // to forget queued tasks, but currently we don't expect to. |
| 276 ASSERT(m_taskQueue.isEmpty()); | 340 ASSERT(m_taskQueue.isEmpty()); |
| 341 // Currently we assume that text will never be the last token in the | |
| 342 // document and that we'll always queue some additional task text to cause i t to flush. | |
|
esprehn
2013/10/11 00:02:56
text task?
"task text" is weird.
abarth-chromium
2013/10/11 18:54:04
"task text" -> task
| |
| 343 ASSERT(m_pendingText.isEmpty()); | |
| 277 } | 344 } |
| 278 | 345 |
| 279 void HTMLConstructionSite::detach() | 346 void HTMLConstructionSite::detach() |
| 280 { | 347 { |
| 348 // FIXME: We'd like to ASSERT here that we're canceling and not just discard ing | |
| 349 // text that really should have made it into the DOM earlier, but there | |
| 350 // doesn't seem to be a nice way to do that. | |
| 351 PendingText discardedText; | |
| 352 m_pendingText.swap(discardedText); | |
|
esprehn
2013/10/11 00:02:56
Adding a discard() method would be prettier.
abarth-chromium
2013/10/11 18:54:04
Agreed. It can use swap internally if that's help
| |
| 353 | |
| 281 m_document = 0; | 354 m_document = 0; |
| 282 m_attachmentRoot = 0; | 355 m_attachmentRoot = 0; |
| 283 } | 356 } |
| 284 | 357 |
| 285 void HTMLConstructionSite::setForm(HTMLFormElement* form) | 358 void HTMLConstructionSite::setForm(HTMLFormElement* form) |
| 286 { | 359 { |
| 287 // This method should only be needed for HTMLTreeBuilder in the fragment cas e. | 360 // This method should only be needed for HTMLTreeBuilder in the fragment cas e. |
| 288 ASSERT(!m_form); | 361 ASSERT(!m_form); |
| 289 m_form = form; | 362 m_form = form; |
| 290 } | 363 } |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 437 || (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Fr ameset//", false)) | 510 || (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Fr ameset//", false)) |
| 438 || (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Tr ansitional//", false))) { | 511 || (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Tr ansitional//", false))) { |
| 439 setCompatibilityMode(Document::LimitedQuirksMode); | 512 setCompatibilityMode(Document::LimitedQuirksMode); |
| 440 return; | 513 return; |
| 441 } | 514 } |
| 442 | 515 |
| 443 // Otherwise we are No Quirks Mode. | 516 // Otherwise we are No Quirks Mode. |
| 444 setCompatibilityMode(Document::NoQuirksMode); | 517 setCompatibilityMode(Document::NoQuirksMode); |
| 445 } | 518 } |
| 446 | 519 |
| 520 void HTMLConstructionSite::flush() | |
| 521 { | |
| 522 flushPendingText(); | |
| 523 executeQueuedTasks(); | |
| 524 } | |
| 525 | |
| 447 void HTMLConstructionSite::processEndOfFile() | 526 void HTMLConstructionSite::processEndOfFile() |
| 448 { | 527 { |
| 449 ASSERT(currentNode()); | 528 ASSERT(currentNode()); |
| 529 flush(); | |
| 450 openElements()->popAll(); | 530 openElements()->popAll(); |
| 451 } | 531 } |
| 452 | 532 |
| 453 void HTMLConstructionSite::finishedParsing() | 533 void HTMLConstructionSite::finishedParsing() |
| 454 { | 534 { |
| 535 // We shouldn't have any queued tasks but we might have pending text which w e need to promote to tasks and execute. | |
| 455 ASSERT(m_taskQueue.isEmpty()); | 536 ASSERT(m_taskQueue.isEmpty()); |
| 537 flush(); | |
| 456 m_document->finishedParsing(); | 538 m_document->finishedParsing(); |
| 457 } | 539 } |
| 458 | 540 |
| 459 void HTMLConstructionSite::insertDoctype(AtomicHTMLToken* token) | 541 void HTMLConstructionSite::insertDoctype(AtomicHTMLToken* token) |
| 460 { | 542 { |
| 461 ASSERT(token->type() == HTMLToken::DOCTYPE); | 543 ASSERT(token->type() == HTMLToken::DOCTYPE); |
| 462 | 544 |
| 463 const String& publicId = StringImpl::create8BitIfPossible(token->publicIdent ifier()); | 545 const String& publicId = StringImpl::create8BitIfPossible(token->publicIdent ifier()); |
| 464 const String& systemId = StringImpl::create8BitIfPossible(token->systemIdent ifier()); | 546 const String& systemId = StringImpl::create8BitIfPossible(token->systemIdent ifier()); |
| 465 RefPtr<DocumentType> doctype = DocumentType::create(m_document, token->name( ), publicId, systemId); | 547 RefPtr<DocumentType> doctype = DocumentType::create(m_document, token->name( ), publicId, systemId); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 579 | 661 |
| 580 RefPtr<Element> element = createElement(token, namespaceURI); | 662 RefPtr<Element> element = createElement(token, namespaceURI); |
| 581 if (scriptingContentIsAllowed(m_parserContentPolicy) || !toScriptLoaderIfPos sible(element.get())) | 663 if (scriptingContentIsAllowed(m_parserContentPolicy) || !toScriptLoaderIfPos sible(element.get())) |
| 582 attachLater(currentNode(), element, token->selfClosing()); | 664 attachLater(currentNode(), element, token->selfClosing()); |
| 583 if (!token->selfClosing()) | 665 if (!token->selfClosing()) |
| 584 m_openElements.push(HTMLStackItem::create(element.release(), token, name spaceURI)); | 666 m_openElements.push(HTMLStackItem::create(element.release(), token, name spaceURI)); |
| 585 } | 667 } |
| 586 | 668 |
| 587 void HTMLConstructionSite::insertTextNode(const String& string, WhitespaceMode w hitespaceMode) | 669 void HTMLConstructionSite::insertTextNode(const String& string, WhitespaceMode w hitespaceMode) |
| 588 { | 670 { |
| 589 HTMLConstructionSiteTask protoTask(HTMLConstructionSiteTask::Insert); | 671 HTMLConstructionSiteTask dummyTask(HTMLConstructionSiteTask::Insert); |
| 590 protoTask.parent = currentNode(); | 672 dummyTask.parent = currentNode(); |
| 591 | 673 |
| 592 if (shouldFosterParent()) | 674 if (shouldFosterParent()) |
| 593 findFosterSite(protoTask); | 675 findFosterSite(dummyTask); |
| 594 | 676 |
| 595 // FIXME: This probably doesn't need to be done both here and in insert(Task ). | 677 // FIXME: This probably doesn't need to be done both here and in insert(Task ). |
| 596 if (protoTask.parent->hasTagName(templateTag)) | 678 if (dummyTask.parent->hasTagName(templateTag)) |
| 597 protoTask.parent = toHTMLTemplateElement(protoTask.parent.get())->conten t(); | 679 dummyTask.parent = toHTMLTemplateElement(dummyTask.parent.get())->conten t(); |
| 598 | 680 |
| 599 // Splitting text nodes into smaller chunks contradicts HTML5 spec, but is n ecessary | 681 // Unclear when parent != case occurs. Somehow we insert text into two separ ate nodes while processing the same Token. |
| 600 // for performance, see: https://bugs.webkit.org/show_bug.cgi?id=55898 | 682 // The nextChild != dummy.nextChild case occurs whenever foster parenting ha ppened and we hit a new text node "<table>a</table>b" |
| 601 unsigned lengthLimit = textLengthLimitForContainer(protoTask.parent.get()); | 683 // In either case we have to flush the pending text into the task queue befo re making more. |
| 602 unsigned currentPosition = 0; | 684 if (!m_pendingText.isEmpty() && (m_pendingText.parent != dummyTask.parent || m_pendingText.nextChild != dummyTask.nextChild)) |
| 603 | 685 flushPendingText(); |
| 604 // Merge text nodes into previous ones if possible: | 686 m_pendingText.append(dummyTask.parent, dummyTask.nextChild, string, whitespa ceMode); |
| 605 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construc tion.html#insert-a-character | |
| 606 Node* previousChild = protoTask.nextChild ? protoTask.nextChild->previousSib ling() : protoTask.parent->lastChild(); | |
| 607 if (previousChild && previousChild->isTextNode()) { | |
| 608 Text* previousText = toText(previousChild); | |
| 609 unsigned appendLengthLimit = lengthLimit - previousText->length(); | |
| 610 | |
| 611 unsigned proposedBreakIndex = std::min(currentPosition + appendLengthLim it, string.length()); | |
| 612 unsigned breakIndex = findBreakIndexBetween(string, currentPosition, pro posedBreakIndex); | |
| 613 ASSERT(breakIndex <= string.length()); | |
| 614 // If we didn't find a breable piece to append, forget it. | |
| 615 if (breakIndex) { | |
| 616 String substring = string.substring(currentPosition, breakIndex - cu rrentPosition); | |
| 617 substring = atomizeIfAllWhitespace(substring, whitespaceMode); | |
| 618 previousText->parserAppendData(substring); | |
| 619 currentPosition += substring.length(); | |
| 620 } | |
| 621 } | |
| 622 | |
| 623 while (currentPosition < string.length()) { | |
| 624 unsigned proposedBreakIndex = std::min(currentPosition + lengthLimit, st ring.length()); | |
| 625 unsigned breakIndex = findBreakIndexBetween(string, currentPosition, pro posedBreakIndex); | |
| 626 // We failed to find a breakable boudary between the minimum and the pro posed, just give up and break at the proposed index. | |
| 627 // We could go searching after the proposed index, but current callers a re attempting to break after 65k chars! | |
| 628 // 65k of unbreakable characters isn't worth trying to handle "correctly ". | |
| 629 if (!breakIndex) | |
| 630 breakIndex = proposedBreakIndex; | |
| 631 ASSERT(breakIndex <= string.length()); | |
| 632 String substring = string.substring(currentPosition, breakIndex - curren tPosition); | |
| 633 substring = atomizeIfAllWhitespace(substring, whitespaceMode); | |
| 634 | |
| 635 HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert); | |
| 636 task.parent = protoTask.parent; | |
| 637 task.nextChild = protoTask.nextChild; | |
| 638 task.child = Text::create(task.parent->document(), substring); | |
| 639 queueTask(task); | |
| 640 | |
| 641 ASSERT(breakIndex > currentPosition); | |
| 642 ASSERT(breakIndex - currentPosition == substring.length()); | |
| 643 ASSERT(toText(task.child.get())->length() == substring.length()); | |
| 644 currentPosition = breakIndex; | |
| 645 } | |
| 646 } | 687 } |
| 647 | 688 |
| 648 void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord* newParent, HTMLElementStack::ElementRecord* child) | 689 void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord* newParent, HTMLElementStack::ElementRecord* child) |
| 649 { | 690 { |
| 650 HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent); | 691 HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent); |
| 651 task.parent = newParent->node(); | 692 task.parent = newParent->node(); |
| 652 task.child = child->node(); | 693 task.child = child->node(); |
| 653 queueTask(task); | 694 queueTask(task); |
| 654 } | 695 } |
| 655 | 696 |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 818 void HTMLConstructionSite::fosterParent(PassRefPtr<Node> node) | 859 void HTMLConstructionSite::fosterParent(PassRefPtr<Node> node) |
| 819 { | 860 { |
| 820 HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert); | 861 HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert); |
| 821 findFosterSite(task); | 862 findFosterSite(task); |
| 822 task.child = node; | 863 task.child = node; |
| 823 ASSERT(task.parent); | 864 ASSERT(task.parent); |
| 824 queueTask(task); | 865 queueTask(task); |
| 825 } | 866 } |
| 826 | 867 |
| 827 } | 868 } |
| OLD | NEW |