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 |