| 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 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 if (it.isBreak(proposedBreakIndex - currentPosition)) | 133 if (it.isBreak(proposedBreakIndex - currentPosition)) |
| 134 return proposedBreakIndex; | 134 return proposedBreakIndex; |
| 135 | 135 |
| 136 int adjustedBreakIndexInSubstring = it.preceding(proposedBreakIndex - curren
tPosition); | 136 int adjustedBreakIndexInSubstring = it.preceding(proposedBreakIndex - curren
tPosition); |
| 137 if (adjustedBreakIndexInSubstring > 0) | 137 if (adjustedBreakIndexInSubstring > 0) |
| 138 return currentPosition + adjustedBreakIndexInSubstring; | 138 return currentPosition + adjustedBreakIndexInSubstring; |
| 139 // We failed to find a breakable point, let the caller figure out what to do
. | 139 // We failed to find a breakable point, let the caller figure out what to do
. |
| 140 return 0; | 140 return 0; |
| 141 } | 141 } |
| 142 | 142 |
| 143 static String atomizeIfAllWhitespace(const String& string, WhitespaceMode whites
paceMode) | |
| 144 { | |
| 145 // Strings composed entirely of whitespace are likely to be repeated. | |
| 146 // Turn them into AtomicString so we share a single string for each. | |
| 147 if (whitespaceMode == AllWhitespace || (whitespaceMode == WhitespaceUnknown
&& isAllWhitespace(string))) | |
| 148 return AtomicString(string).string(); | |
| 149 return string; | |
| 150 } | |
| 151 | |
| 152 void HTMLConstructionSite::flushPendingText() | 143 void HTMLConstructionSite::flushPendingText() |
| 153 { | 144 { |
| 154 if (m_pendingText.isEmpty()) | 145 if (m_pendingText.isEmpty()) |
| 155 return; | 146 return; |
| 156 | 147 |
| 157 PendingText pendingText; | 148 PendingText pendingText; |
| 158 // Hold onto the current pending text on the stack so that queueTask doesn't
recurse infinitely. | 149 // Hold onto the current pending text on the stack so that queueTask doesn't
recurse infinitely. |
| 159 m_pendingText.swap(pendingText); | 150 m_pendingText.swap(pendingText); |
| 160 ASSERT(m_pendingText.isEmpty()); | 151 ASSERT(m_pendingText.isEmpty()); |
| 161 | 152 |
| 162 // Splitting text nodes into smaller chunks contradicts HTML5 spec, but is n
ecessary | 153 // Splitting text nodes into smaller chunks contradicts HTML5 spec, but is n
ecessary |
| 163 // for performance, see: https://bugs.webkit.org/show_bug.cgi?id=55898 | 154 // for performance, see: https://bugs.webkit.org/show_bug.cgi?id=55898 |
| 164 unsigned lengthLimit = textLengthLimitForContainer(*pendingText.parent); | 155 unsigned lengthLimit = textLengthLimitForContainer(*pendingText.parent); |
| 165 | 156 |
| 166 unsigned currentPosition = 0; | 157 unsigned currentPosition = 0; |
| 167 const StringBuilder& string = pendingText.stringBuilder; | 158 const StringBuilder& string = pendingText.stringBuilder; |
| 168 while (currentPosition < string.length()) { | 159 while (currentPosition < string.length()) { |
| 169 unsigned proposedBreakIndex = std::min(currentPosition + lengthLimit, st
ring.length()); | 160 unsigned proposedBreakIndex = std::min(currentPosition + lengthLimit, st
ring.length()); |
| 170 unsigned breakIndex = findBreakIndexBetween(string, currentPosition, pro
posedBreakIndex); | 161 unsigned breakIndex = findBreakIndexBetween(string, currentPosition, pro
posedBreakIndex); |
| 171 ASSERT(breakIndex <= string.length()); | 162 ASSERT(breakIndex <= string.length()); |
| 172 String substring = string.substring(currentPosition, breakIndex - curren
tPosition); | 163 String substring = string.substring(currentPosition, breakIndex - curren
tPosition); |
| 173 substring = atomizeIfAllWhitespace(substring, pendingText.whitespaceMode
); | 164 |
| 165 ASSERT(breakIndex > currentPosition); |
| 166 ASSERT(breakIndex - currentPosition == substring.length()); |
| 167 currentPosition = breakIndex; |
| 168 |
| 169 if (isAllWhitespace(substring)) { |
| 170 // Ignore whitespace nodes not inside inside a <t>. If we're splitti
ng |
| 171 // a text node this isn't really a whitespace node and we can't igno
re |
| 172 // it either. |
| 173 if (!m_openElements.preserveWhiteSpace() && string.length() == subst
ring.length()) |
| 174 continue; |
| 175 |
| 176 // Strings composed entirely of whitespace are likely to be repeated
. |
| 177 // Turn them into AtomicString so we share a single string for each. |
| 178 substring = AtomicString(substring).string(); |
| 179 } |
| 174 | 180 |
| 175 HTMLConstructionSiteTask task(HTMLConstructionSiteTask::InsertText); | 181 HTMLConstructionSiteTask task(HTMLConstructionSiteTask::InsertText); |
| 176 task.parent = pendingText.parent; | 182 task.parent = pendingText.parent; |
| 177 task.child = Text::create(task.parent->document(), substring); | 183 task.child = Text::create(task.parent->document(), substring); |
| 178 queueTask(task); | 184 queueTask(task); |
| 179 | |
| 180 ASSERT(breakIndex > currentPosition); | |
| 181 ASSERT(breakIndex - currentPosition == substring.length()); | |
| 182 ASSERT(toText(task.child.get())->length() == substring.length()); | 185 ASSERT(toText(task.child.get())->length() == substring.length()); |
| 183 currentPosition = breakIndex; | |
| 184 } | 186 } |
| 185 } | 187 } |
| 186 | 188 |
| 187 void HTMLConstructionSite::queueTask(const HTMLConstructionSiteTask& task) | 189 void HTMLConstructionSite::queueTask(const HTMLConstructionSiteTask& task) |
| 188 { | 190 { |
| 189 flushPendingText(); | 191 flushPendingText(); |
| 190 ASSERT(m_pendingText.isEmpty()); | 192 ASSERT(m_pendingText.isEmpty()); |
| 191 m_taskQueue.append(task); | 193 m_taskQueue.append(task); |
| 192 } | 194 } |
| 193 | 195 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 } | 292 } |
| 291 | 293 |
| 292 void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token) | 294 void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token) |
| 293 { | 295 { |
| 294 RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(ownerDocumentF
orCurrentNode()); | 296 RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(ownerDocumentF
orCurrentNode()); |
| 295 setAttributes(element.get(), token); | 297 setAttributes(element.get(), token); |
| 296 attachLater(currentNode(), element); | 298 attachLater(currentNode(), element); |
| 297 m_openElements.push(element.release()); | 299 m_openElements.push(element.release()); |
| 298 } | 300 } |
| 299 | 301 |
| 300 void HTMLConstructionSite::insertTextNode(const String& string, WhitespaceMode w
hitespaceMode) | 302 void HTMLConstructionSite::insertTextNode(const String& string) |
| 301 { | 303 { |
| 302 HTMLConstructionSiteTask dummyTask(HTMLConstructionSiteTask::Insert); | 304 HTMLConstructionSiteTask dummyTask(HTMLConstructionSiteTask::Insert); |
| 303 dummyTask.parent = currentNode(); | 305 dummyTask.parent = currentNode(); |
| 304 | 306 |
| 305 // FIXME: This probably doesn't need to be done both here and in insert(Task
). | 307 // FIXME: This probably doesn't need to be done both here and in insert(Task
). |
| 306 if (isHTMLTemplateElement(*dummyTask.parent)) | 308 if (isHTMLTemplateElement(*dummyTask.parent)) |
| 307 dummyTask.parent = toHTMLTemplateElement(dummyTask.parent.get())->conten
t(); | 309 dummyTask.parent = toHTMLTemplateElement(dummyTask.parent.get())->conten
t(); |
| 308 | 310 |
| 309 // Unclear when parent != case occurs. Somehow we insert text into two separ
ate | 311 // Unclear when parent != case occurs. Somehow we insert text into two separ
ate |
| 310 // nodes while processing the same Token. When it happens we have to flush t
he | 312 // nodes while processing the same Token. When it happens we have to flush t
he |
| 311 // pending text into the task queue before making more. | 313 // pending text into the task queue before making more. |
| 312 if (!m_pendingText.isEmpty() && (m_pendingText.parent != dummyTask.parent)) | 314 if (!m_pendingText.isEmpty() && (m_pendingText.parent != dummyTask.parent)) |
| 313 flushPendingText(); | 315 flushPendingText(); |
| 314 m_pendingText.append(dummyTask.parent, string, whitespaceMode); | 316 m_pendingText.append(dummyTask.parent, string); |
| 315 } | 317 } |
| 316 | 318 |
| 317 PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken* token,
const AtomicString& namespaceURI) | 319 PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken* token,
const AtomicString& namespaceURI) |
| 318 { | 320 { |
| 319 QualifiedName tagName(token->name()); | 321 QualifiedName tagName(token->name()); |
| 320 RefPtr<Element> element = ownerDocumentForCurrentNode().createElement(tagNam
e, true); | 322 RefPtr<Element> element = ownerDocumentForCurrentNode().createElement(tagNam
e, true); |
| 321 setAttributes(element.get(), token); | 323 setAttributes(element.get(), token); |
| 322 return element.release(); | 324 return element.release(); |
| 323 } | 325 } |
| 324 | 326 |
| 325 inline Document& HTMLConstructionSite::ownerDocumentForCurrentNode() | 327 inline Document& HTMLConstructionSite::ownerDocumentForCurrentNode() |
| 326 { | 328 { |
| 327 if (isHTMLTemplateElement(*currentNode())) | 329 if (isHTMLTemplateElement(*currentNode())) |
| 328 return toHTMLTemplateElement(currentElement())->content()->document(); | 330 return toHTMLTemplateElement(currentElement())->content()->document(); |
| 329 return currentNode()->document(); | 331 return currentNode()->document(); |
| 330 } | 332 } |
| 331 | 333 |
| 332 PassRefPtr<HTMLElement> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken*
token) | 334 PassRefPtr<HTMLElement> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken*
token) |
| 333 { | 335 { |
| 334 Document& document = ownerDocumentForCurrentNode(); | 336 Document& document = ownerDocumentForCurrentNode(); |
| 335 RefPtr<HTMLElement> element = HTMLElementFactory::createHTMLElement(token->n
ame(), document, true); | 337 RefPtr<HTMLElement> element = HTMLElementFactory::createHTMLElement(token->n
ame(), document, true); |
| 336 setAttributes(element.get(), token); | 338 setAttributes(element.get(), token); |
| 337 return element.release(); | 339 return element.release(); |
| 338 } | 340 } |
| 339 | 341 |
| 340 } | 342 } |
| OLD | NEW |