Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(585)

Side by Side Diff: third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp

Issue 2397033002: Reflow comments in //third_party/WebKit/Source/core/editing/iterators (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All r ights reserved. 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All
3 * rights reserved.
3 * Copyright (C) 2005 Alexey Proskuryakov. 4 * Copyright (C) 2005 Alexey Proskuryakov.
4 * 5 *
5 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
7 * are met: 8 * are met:
8 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 m_textBox(nullptr), 157 m_textBox(nullptr),
157 m_remainingTextBox(nullptr), 158 m_remainingTextBox(nullptr),
158 m_firstLetterText(nullptr), 159 m_firstLetterText(nullptr),
159 m_lastTextNode(nullptr), 160 m_lastTextNode(nullptr),
160 m_lastTextNodeEndedWithCollapsedSpace(false), 161 m_lastTextNodeEndedWithCollapsedSpace(false),
161 m_sortedTextBoxesPosition(0), 162 m_sortedTextBoxesPosition(0),
162 m_behavior(adjustBehaviorFlags<Strategy>(behavior)), 163 m_behavior(adjustBehaviorFlags<Strategy>(behavior)),
163 m_handledFirstLetter(false), 164 m_handledFirstLetter(false),
164 m_shouldStop(false), 165 m_shouldStop(false),
165 m_handleShadowRoot(false), 166 m_handleShadowRoot(false),
166 // The call to emitsOriginalText() must occur after m_behavior is initiali zed. 167 // The call to emitsOriginalText() must occur after m_behavior is
168 // initialized.
167 m_textState(emitsOriginalText()) { 169 m_textState(emitsOriginalText()) {
168 DCHECK(start.isNotNull()); 170 DCHECK(start.isNotNull());
169 DCHECK(end.isNotNull()); 171 DCHECK(end.isNotNull());
170 172
171 // TODO(dglazkov): TextIterator should not be created for documents that don't have a frame, 173 // TODO(dglazkov): TextIterator should not be created for documents that don't
172 // but it currently still happens in some cases. See http://crbug.com/591877 f or details. 174 // have a frame, but it currently still happens in some cases. See
175 // http://crbug.com/591877 for details.
173 DCHECK(!start.document()->view() || !start.document()->view()->needsLayout()); 176 DCHECK(!start.document()->view() || !start.document()->view()->needsLayout());
174 DCHECK(!start.document()->needsLayoutTreeUpdate()); 177 DCHECK(!start.document()->needsLayoutTreeUpdate());
175 178
176 if (start.compareTo(end) > 0) { 179 if (start.compareTo(end) > 0) {
177 initialize(end.computeContainerNode(), end.computeOffsetInContainerNode(), 180 initialize(end.computeContainerNode(), end.computeOffsetInContainerNode(),
178 start.computeContainerNode(), 181 start.computeContainerNode(),
179 start.computeOffsetInContainerNode()); 182 start.computeOffsetInContainerNode());
180 return; 183 return;
181 } 184 }
182 initialize(start.computeContainerNode(), start.computeOffsetInContainerNode(), 185 initialize(start.computeContainerNode(), start.computeOffsetInContainerNode(),
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 return; 261 return;
259 262
260 if (m_node) 263 if (m_node)
261 DCHECK(!m_node->document().needsLayoutTreeUpdate()) << m_node; 264 DCHECK(!m_node->document().needsLayoutTreeUpdate()) << m_node;
262 265
263 m_textState.resetRunInformation(); 266 m_textState.resetRunInformation();
264 267
265 // handle remembered node that needed a newline after the text node's newline 268 // handle remembered node that needed a newline after the text node's newline
266 if (m_needsAnotherNewline) { 269 if (m_needsAnotherNewline) {
267 // Emit the extra newline, and position it *inside* m_node, after m_node's 270 // Emit the extra newline, and position it *inside* m_node, after m_node's
268 // contents, in case it's a block, in the same way that we position the firs t 271 // contents, in case it's a block, in the same way that we position the
269 // newline. The range for the emitted newline should start where the line 272 // first newline. The range for the emitted newline should start where the
270 // break begins. 273 // line break begins.
271 // FIXME: It would be cleaner if we emitted two newlines during the last 274 // FIXME: It would be cleaner if we emitted two newlines during the last
272 // iteration, instead of using m_needsAnotherNewline. 275 // iteration, instead of using m_needsAnotherNewline.
273 Node* lastChild = Strategy::lastChild(*m_node); 276 Node* lastChild = Strategy::lastChild(*m_node);
274 Node* baseNode = lastChild ? lastChild : m_node.get(); 277 Node* baseNode = lastChild ? lastChild : m_node.get();
275 spliceBuffer('\n', Strategy::parent(*baseNode), baseNode, 1, 1); 278 spliceBuffer('\n', Strategy::parent(*baseNode), baseNode, 1, 1);
276 m_needsAnotherNewline = false; 279 m_needsAnotherNewline = false;
277 return; 280 return;
278 } 281 }
279 282
280 if (!m_textBox && m_remainingTextBox) { 283 if (!m_textBox && m_remainingTextBox) {
(...skipping 20 matching lines...) Expand all
301 // precedes the element 304 // precedes the element
302 if (m_node == m_endContainer && !m_endOffset) { 305 if (m_node == m_endContainer && !m_endOffset) {
303 representNodeOffsetZero(); 306 representNodeOffsetZero();
304 m_node = nullptr; 307 m_node = nullptr;
305 return; 308 return;
306 } 309 }
307 310
308 LayoutObject* layoutObject = m_node->layoutObject(); 311 LayoutObject* layoutObject = m_node->layoutObject();
309 if (!layoutObject) { 312 if (!layoutObject) {
310 if (m_node->isShadowRoot()) { 313 if (m_node->isShadowRoot()) {
311 // A shadow root doesn't have a layoutObject, but we want to visit child ren anyway. 314 // A shadow root doesn't have a layoutObject, but we want to visit
315 // children anyway.
312 m_iterationProgress = m_iterationProgress < HandledNode 316 m_iterationProgress = m_iterationProgress < HandledNode
313 ? HandledNode 317 ? HandledNode
314 : m_iterationProgress; 318 : m_iterationProgress;
315 m_handleShadowRoot = true; 319 m_handleShadowRoot = true;
316 } else { 320 } else {
317 m_iterationProgress = HandledChildren; 321 m_iterationProgress = HandledChildren;
318 } 322 }
319 } else { 323 } else {
320 // Enter author shadow roots, from youngest, if any and if necessary. 324 // Enter author shadow roots, from youngest, if any and if necessary.
321 if (m_iterationProgress < HandledOpenShadowRoots) { 325 if (m_iterationProgress < HandledOpenShadowRoots) {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 // 385 //
382 // 1. Iterate over child nodes, if we haven't done yet. 386 // 1. Iterate over child nodes, if we haven't done yet.
383 // To support |TextIteratorEmitsImageAltText|, we don't traversal child 387 // To support |TextIteratorEmitsImageAltText|, we don't traversal child
384 // nodes, in flat tree. 388 // nodes, in flat tree.
385 Node* next = 389 Node* next =
386 m_iterationProgress < HandledChildren && !isHTMLImageElement(*m_node) 390 m_iterationProgress < HandledChildren && !isHTMLImageElement(*m_node)
387 ? Strategy::firstChild(*m_node) 391 ? Strategy::firstChild(*m_node)
388 : nullptr; 392 : nullptr;
389 m_offset = 0; 393 m_offset = 0;
390 if (!next) { 394 if (!next) {
391 // 2. If we've already iterated children or they are not available, go to the next sibling node. 395 // 2. If we've already iterated children or they are not available, go to
396 // the next sibling node.
392 next = Strategy::nextSibling(*m_node); 397 next = Strategy::nextSibling(*m_node);
393 if (!next) { 398 if (!next) {
394 // 3. If we are at the last child, go up the node tree until we find a n ext sibling. 399 // 3. If we are at the last child, go up the node tree until we find a
400 // next sibling.
395 ContainerNode* parentNode = Strategy::parent(*m_node); 401 ContainerNode* parentNode = Strategy::parent(*m_node);
396 while (!next && parentNode) { 402 while (!next && parentNode) {
397 if (m_node == m_endNode || 403 if (m_node == m_endNode ||
398 Strategy::isDescendantOf(*m_endContainer, *parentNode)) 404 Strategy::isDescendantOf(*m_endContainer, *parentNode))
399 return; 405 return;
400 bool haveLayoutObject = m_node->layoutObject(); 406 bool haveLayoutObject = m_node->layoutObject();
401 m_node = parentNode; 407 m_node = parentNode;
402 m_fullyClippedStack.pop(); 408 m_fullyClippedStack.pop();
403 parentNode = Strategy::parent(*m_node); 409 parentNode = Strategy::parent(*m_node);
404 if (haveLayoutObject) 410 if (haveLayoutObject)
405 exitNode(); 411 exitNode();
406 if (m_textState.positionNode()) { 412 if (m_textState.positionNode()) {
407 m_iterationProgress = HandledChildren; 413 m_iterationProgress = HandledChildren;
408 return; 414 return;
409 } 415 }
410 next = Strategy::nextSibling(*m_node); 416 next = Strategy::nextSibling(*m_node);
411 } 417 }
412 418
413 if (!next && !parentNode && m_shadowDepth > 0) { 419 if (!next && !parentNode && m_shadowDepth > 0) {
414 // 4. Reached the top of a shadow root. If it's created by author, the n try to visit the next 420 // 4. Reached the top of a shadow root. If it's created by author,
421 // then try to visit the next
415 // sibling shadow root, if any. 422 // sibling shadow root, if any.
416 if (!m_node->isShadowRoot()) { 423 if (!m_node->isShadowRoot()) {
417 NOTREACHED(); 424 NOTREACHED();
418 m_shouldStop = true; 425 m_shouldStop = true;
419 return; 426 return;
420 } 427 }
421 ShadowRoot* shadowRoot = toShadowRoot(m_node); 428 ShadowRoot* shadowRoot = toShadowRoot(m_node);
422 if (shadowRoot->type() == ShadowRootType::V0 || 429 if (shadowRoot->type() == ShadowRootType::V0 ||
423 shadowRoot->type() == ShadowRootType::Open) { 430 shadowRoot->type() == ShadowRootType::Open) {
424 ShadowRoot* nextShadowRoot = shadowRoot->olderShadowRoot(); 431 ShadowRoot* nextShadowRoot = shadowRoot->olderShadowRoot();
425 if (nextShadowRoot && 432 if (nextShadowRoot &&
426 nextShadowRoot->type() == ShadowRootType::V0) { 433 nextShadowRoot->type() == ShadowRootType::V0) {
427 m_fullyClippedStack.pop(); 434 m_fullyClippedStack.pop();
428 m_node = nextShadowRoot; 435 m_node = nextShadowRoot;
429 m_iterationProgress = HandledNone; 436 m_iterationProgress = HandledNone;
430 // m_shadowDepth is unchanged since we exit from a shadow root and enter another. 437 // m_shadowDepth is unchanged since we exit from a shadow root and
438 // enter another.
431 m_fullyClippedStack.pushFullyClippedState(m_node); 439 m_fullyClippedStack.pushFullyClippedState(m_node);
432 } else { 440 } else {
433 // We are the last shadow root; exit from here and go back to wher e we were. 441 // We are the last shadow root; exit from here and go back to
442 // where we were.
434 m_node = &shadowRoot->host(); 443 m_node = &shadowRoot->host();
435 m_iterationProgress = HandledOpenShadowRoots; 444 m_iterationProgress = HandledOpenShadowRoots;
436 --m_shadowDepth; 445 --m_shadowDepth;
437 m_fullyClippedStack.pop(); 446 m_fullyClippedStack.pop();
438 } 447 }
439 } else { 448 } else {
440 // If we are in a closed or user-agent shadow root, then go back to the host. 449 // If we are in a closed or user-agent shadow root, then go back to
441 // TODO(kochi): Make sure we treat closed shadow as user agent shado w here. 450 // the host.
451 // TODO(kochi): Make sure we treat closed shadow as user agent
452 // shadow here.
442 DCHECK(shadowRoot->type() == ShadowRootType::Closed || 453 DCHECK(shadowRoot->type() == ShadowRootType::Closed ||
443 shadowRoot->type() == ShadowRootType::UserAgent); 454 shadowRoot->type() == ShadowRootType::UserAgent);
444 m_node = &shadowRoot->host(); 455 m_node = &shadowRoot->host();
445 m_iterationProgress = HandledUserAgentShadowRoot; 456 m_iterationProgress = HandledUserAgentShadowRoot;
446 --m_shadowDepth; 457 --m_shadowDepth;
447 m_fullyClippedStack.pop(); 458 m_fullyClippedStack.pop();
448 } 459 }
449 m_handledFirstLetter = false; 460 m_handledFirstLetter = false;
450 m_firstLetterText = nullptr; 461 m_firstLetterText = nullptr;
451 continue; 462 continue;
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 size_t subrunEnd) { 599 size_t subrunEnd) {
589 if (nextTextBox || !m_textBox->root().nextRootBox() || 600 if (nextTextBox || !m_textBox->root().nextRootBox() ||
590 m_textBox->root().lastChild() != m_textBox) 601 m_textBox->root().lastChild() != m_textBox)
591 return subrunEnd; 602 return subrunEnd;
592 603
593 const String& text = toLayoutText(m_node->layoutObject())->text(); 604 const String& text = toLayoutText(m_node->layoutObject())->text();
594 if (text.endsWith(' ') == 0 || subrunEnd != text.length() - 1 || 605 if (text.endsWith(' ') == 0 || subrunEnd != text.length() - 1 ||
595 text[subrunEnd - 1] == ' ') 606 text[subrunEnd - 1] == ' ')
596 return subrunEnd; 607 return subrunEnd;
597 608
598 // If there is the leading space in the next line, we don't need to restore th e trailing space. 609 // If there is the leading space in the next line, we don't need to restore
610 // the trailing space.
599 // Example: <div style="width: 2em;"><b><i>foo </i></b> bar</div> 611 // Example: <div style="width: 2em;"><b><i>foo </i></b> bar</div>
600 InlineBox* firstBoxOfNextLine = m_textBox->root().nextRootBox()->firstChild(); 612 InlineBox* firstBoxOfNextLine = m_textBox->root().nextRootBox()->firstChild();
601 if (!firstBoxOfNextLine) 613 if (!firstBoxOfNextLine)
602 return subrunEnd + 1; 614 return subrunEnd + 1;
603 Node* firstNodeOfNextLine = firstBoxOfNextLine->getLineLayoutItem().node(); 615 Node* firstNodeOfNextLine = firstBoxOfNextLine->getLineLayoutItem().node();
604 if (!firstNodeOfNextLine || firstNodeOfNextLine->nodeValue()[0] != ' ') 616 if (!firstNodeOfNextLine || firstNodeOfNextLine->nodeValue()[0] != ' ')
605 return subrunEnd + 1; 617 return subrunEnd + 1;
606 618
607 return subrunEnd; 619 return subrunEnd;
608 } 620 }
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 !(nextTextBox->getLineLayoutItem().isEqual(layoutObject))) { 703 !(nextTextBox->getLineLayoutItem().isEqual(layoutObject))) {
692 m_textBox = 0; 704 m_textBox = 0;
693 return; 705 return;
694 } 706 }
695 DCHECK(!nextTextBox || 707 DCHECK(!nextTextBox ||
696 nextTextBox->getLineLayoutItem().isEqual(layoutObject)); 708 nextTextBox->getLineLayoutItem().isEqual(layoutObject));
697 709
698 if (runStart < runEnd) { 710 if (runStart < runEnd) {
699 // Handle either a single newline character (which becomes a space), 711 // Handle either a single newline character (which becomes a space),
700 // or a run of characters that does not include a newline. 712 // or a run of characters that does not include a newline.
701 // This effectively translates newlines to spaces without copying the te xt. 713 // This effectively translates newlines to spaces without copying the
714 // text.
702 if (str[runStart] == '\n') { 715 if (str[runStart] == '\n') {
703 // We need to preserve new lines in case of PRE_LINE. 716 // We need to preserve new lines in case of PRE_LINE.
704 // See bug crbug.com/317365. 717 // See bug crbug.com/317365.
705 if (layoutObject->style()->whiteSpace() == PRE_LINE) 718 if (layoutObject->style()->whiteSpace() == PRE_LINE)
706 spliceBuffer('\n', m_node, 0, runStart, runStart); 719 spliceBuffer('\n', m_node, 0, runStart, runStart);
707 else 720 else
708 spliceBuffer(spaceCharacter, m_node, 0, runStart, runStart + 1); 721 spliceBuffer(spaceCharacter, m_node, 0, runStart, runStart + 1);
709 m_offset = runStart + 1; 722 m_offset = runStart + 1;
710 } else { 723 } else {
711 size_t subrunEnd = str.find('\n', runStart); 724 size_t subrunEnd = str.find('\n', runStart);
712 if (subrunEnd == kNotFound || subrunEnd > runEnd) { 725 if (subrunEnd == kNotFound || subrunEnd > runEnd) {
713 subrunEnd = runEnd; 726 subrunEnd = runEnd;
714 runStart = restoreCollapsedLeadingSpace(runStart); 727 runStart = restoreCollapsedLeadingSpace(runStart);
715 subrunEnd = restoreCollapsedTrailingSpace(nextTextBox, subrunEnd); 728 subrunEnd = restoreCollapsedTrailingSpace(nextTextBox, subrunEnd);
716 } 729 }
717 730
718 m_offset = subrunEnd; 731 m_offset = subrunEnd;
719 emitText(m_node, layoutObject, runStart, subrunEnd); 732 emitText(m_node, layoutObject, runStart, subrunEnd);
720 } 733 }
721 734
722 // If we are doing a subrun that doesn't go to the end of the text box, 735 // If we are doing a subrun that doesn't go to the end of the text box,
723 // come back again to finish handling this text box; don't advance to th e next one. 736 // come back again to finish handling this text box; don't advance to
737 // the next one.
724 if (static_cast<unsigned>(m_textState.positionEndOffset()) < textBoxEnd) 738 if (static_cast<unsigned>(m_textState.positionEndOffset()) < textBoxEnd)
725 return; 739 return;
726 740
727 // Advance and return 741 // Advance and return
728 unsigned nextRunStart = 742 unsigned nextRunStart =
729 nextTextBox ? nextTextBox->start() : str.length(); 743 nextTextBox ? nextTextBox->start() : str.length();
730 if (nextRunStart > runEnd) 744 if (nextRunStart > runEnd)
731 m_lastTextNodeEndedWithCollapsedSpace = 745 m_lastTextNodeEndedWithCollapsedSpace =
732 true; // collapsed space between runs or at the end 746 true; // collapsed space between runs or at the end
733 747
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
958 int bottomMargin = toLayoutBox(r)->collapsedMarginAfter().toInt(); 972 int bottomMargin = toLayoutBox(r)->collapsedMarginAfter().toInt();
959 int fontSize = style->getFontDescription().computedPixelSize(); 973 int fontSize = style->getFontDescription().computedPixelSize();
960 if (bottomMargin * 2 >= fontSize) 974 if (bottomMargin * 2 >= fontSize)
961 return true; 975 return true;
962 } 976 }
963 } 977 }
964 978
965 return false; 979 return false;
966 } 980 }
967 981
968 // Whether or not we should emit a character as we enter m_node (if it's a conta iner) or as we hit it (if it's atomic). 982 // Whether or not we should emit a character as we enter m_node (if it's a
983 // container) or as we hit it (if it's atomic).
969 template <typename Strategy> 984 template <typename Strategy>
970 bool TextIteratorAlgorithm<Strategy>::shouldRepresentNodeOffsetZero() { 985 bool TextIteratorAlgorithm<Strategy>::shouldRepresentNodeOffsetZero() {
971 if (emitsCharactersBetweenAllVisiblePositions() && 986 if (emitsCharactersBetweenAllVisiblePositions() &&
972 isDisplayInsideTable(m_node)) 987 isDisplayInsideTable(m_node))
973 return true; 988 return true;
974 989
975 // Leave element positioned flush with start of a paragraph 990 // Leave element positioned flush with start of a paragraph
976 // (e.g. do not insert tab before a table cell at the start of a paragraph) 991 // (e.g. do not insert tab before a table cell at the start of a paragraph)
977 if (m_textState.lastCharacter() == '\n') 992 if (m_textState.lastCharacter() == '\n')
978 return false; 993 return false;
979 994
980 // Otherwise, show the position if we have emitted any characters 995 // Otherwise, show the position if we have emitted any characters
981 if (m_textState.hasEmitted()) 996 if (m_textState.hasEmitted())
982 return true; 997 return true;
983 998
984 // We've not emitted anything yet. Generally, there is no need for any positio ning then. 999 // We've not emitted anything yet. Generally, there is no need for any
985 // The only exception is when the element is visually not in the same line as 1000 // positioning then. The only exception is when the element is visually not in
986 // the start of the range (e.g. the range starts at the end of the previous pa ragraph). 1001 // the same line as the start of the range (e.g. the range starts at the end
987 // NOTE: Creating VisiblePositions and comparing them is relatively expensive, so we 1002 // of the previous paragraph).
988 // make quicker checks to possibly avoid that. Another check that we could mak e is 1003 // NOTE: Creating VisiblePositions and comparing them is relatively expensive,
989 // is whether the inline vs block flow changed since the previous visible elem ent. 1004 // so we make quicker checks to possibly avoid that. Another check that we
990 // I think we're already in a special enough case that that won't be needed, t ho. 1005 // could make is is whether the inline vs block flow changed since the
1006 // previous visible element. I think we're already in a special enough case
1007 // that that won't be needed, tho.
991 1008
992 // No character needed if this is the first node in the range. 1009 // No character needed if this is the first node in the range.
993 if (m_node == m_startContainer) 1010 if (m_node == m_startContainer)
994 return false; 1011 return false;
995 1012
996 // If we are outside the start container's subtree, assume we need to emit. 1013 // If we are outside the start container's subtree, assume we need to emit.
997 // FIXME: m_startContainer could be an inline block 1014 // FIXME: m_startContainer could be an inline block
998 if (!Strategy::isDescendantOf(*m_node, *m_startContainer)) 1015 if (!Strategy::isDescendantOf(*m_node, *m_startContainer))
999 return true; 1016 return true;
1000 1017
1001 // If we started as m_startContainer offset 0 and the current node is a descen dant of 1018 // If we started as m_startContainer offset 0 and the current node is a
1002 // the start container, we already had enough context to correctly decide whet her to 1019 // descendant of the start container, we already had enough context to
1003 // emit after a preceding block. We chose not to emit (m_hasEmitted is false), 1020 // correctly decide whether to emit after a preceding block. We chose not to
1004 // so don't second guess that now. 1021 // emit (m_hasEmitted is false), so don't second guess that now.
1005 // NOTE: Is this really correct when m_node is not a leftmost descendant? Prob ably 1022 // NOTE: Is this really correct when m_node is not a leftmost descendant?
1006 // immaterial since we likely would have already emitted something by now. 1023 // Probably immaterial since we likely would have already emitted something by
1024 // now.
1007 if (!m_startOffset) 1025 if (!m_startOffset)
1008 return false; 1026 return false;
1009 1027
1010 // If this node is unrendered or invisible the VisiblePosition checks below wo n't have much meaning. 1028 // If this node is unrendered or invisible the VisiblePosition checks below
1011 // Additionally, if the range we are iterating over contains huge sections of unrendered content, 1029 // won't have much meaning.
1012 // we would create VisiblePositions on every call to this function without thi s check. 1030 // Additionally, if the range we are iterating over contains huge sections of
1031 // unrendered content, we would create VisiblePositions on every call to this
1032 // function without this check.
1013 if (!m_node->layoutObject() || 1033 if (!m_node->layoutObject() ||
1014 m_node->layoutObject()->style()->visibility() != EVisibility::Visible || 1034 m_node->layoutObject()->style()->visibility() != EVisibility::Visible ||
1015 (m_node->layoutObject()->isLayoutBlockFlow() && 1035 (m_node->layoutObject()->isLayoutBlockFlow() &&
1016 !toLayoutBlock(m_node->layoutObject())->size().height() && 1036 !toLayoutBlock(m_node->layoutObject())->size().height() &&
1017 !isHTMLBodyElement(*m_node))) 1037 !isHTMLBodyElement(*m_node)))
1018 return false; 1038 return false;
1019 1039
1020 // The startPos.isNotNull() check is needed because the start could be before the body, 1040 // The startPos.isNotNull() check is needed because the start could be before
1021 // and in that case we'll get null. We don't want to put in newlines at the st art in that case. 1041 // the body, and in that case we'll get null. We don't want to put in newlines
1022 // The currPos.isNotNull() check is needed because positions in non-HTML conte nt 1042 // at the start in that case.
1023 // (like SVG) do not have visible positions, and we don't want to emit for the m either. 1043 // The currPos.isNotNull() check is needed because positions in non-HTML
1044 // content (like SVG) do not have visible positions, and we don't want to emit
1045 // for them either.
1024 VisiblePosition startPos = 1046 VisiblePosition startPos =
1025 createVisiblePosition(Position(m_startContainer, m_startOffset)); 1047 createVisiblePosition(Position(m_startContainer, m_startOffset));
1026 VisiblePosition currPos = VisiblePosition::beforeNode(m_node); 1048 VisiblePosition currPos = VisiblePosition::beforeNode(m_node);
1027 return startPos.isNotNull() && currPos.isNotNull() && 1049 return startPos.isNotNull() && currPos.isNotNull() &&
1028 !inSameLine(startPos, currPos); 1050 !inSameLine(startPos, currPos);
1029 } 1051 }
1030 1052
1031 template <typename Strategy> 1053 template <typename Strategy>
1032 bool TextIteratorAlgorithm<Strategy>::shouldEmitSpaceBeforeAndAfterNode( 1054 bool TextIteratorAlgorithm<Strategy>::shouldEmitSpaceBeforeAndAfterNode(
1033 Node* node) { 1055 Node* node) {
1034 return isDisplayInsideTable(node) && 1056 return isDisplayInsideTable(node) &&
1035 (node->layoutObject()->isInline() || 1057 (node->layoutObject()->isInline() ||
1036 emitsCharactersBetweenAllVisiblePositions()); 1058 emitsCharactersBetweenAllVisiblePositions());
1037 } 1059 }
1038 1060
1039 template <typename Strategy> 1061 template <typename Strategy>
1040 void TextIteratorAlgorithm<Strategy>::representNodeOffsetZero() { 1062 void TextIteratorAlgorithm<Strategy>::representNodeOffsetZero() {
1041 // Emit a character to show the positioning of m_node. 1063 // Emit a character to show the positioning of m_node.
1042 1064
1043 // When we haven't been emitting any characters, shouldRepresentNodeOffsetZero () can 1065 // When we haven't been emitting any characters,
1044 // create VisiblePositions, which is expensive. So, we perform the inexpensive checks 1066 // shouldRepresentNodeOffsetZero() can create VisiblePositions, which is
1045 // on m_node to see if it necessitates emitting a character first and will ear ly return 1067 // expensive. So, we perform the inexpensive checks on m_node to see if it
1046 // before encountering shouldRepresentNodeOffsetZero()s worse case behavior. 1068 // necessitates emitting a character first and will early return before
1069 // encountering shouldRepresentNodeOffsetZero()s worse case behavior.
1047 if (shouldEmitTabBeforeNode(m_node)) { 1070 if (shouldEmitTabBeforeNode(m_node)) {
1048 if (shouldRepresentNodeOffsetZero()) 1071 if (shouldRepresentNodeOffsetZero())
1049 spliceBuffer('\t', Strategy::parent(*m_node), m_node, 0, 0); 1072 spliceBuffer('\t', Strategy::parent(*m_node), m_node, 0, 0);
1050 } else if (shouldEmitNewlineBeforeNode(*m_node)) { 1073 } else if (shouldEmitNewlineBeforeNode(*m_node)) {
1051 if (shouldRepresentNodeOffsetZero()) 1074 if (shouldRepresentNodeOffsetZero())
1052 spliceBuffer('\n', Strategy::parent(*m_node), m_node, 0, 0); 1075 spliceBuffer('\n', Strategy::parent(*m_node), m_node, 0, 0);
1053 } else if (shouldEmitSpaceBeforeAndAfterNode(m_node)) { 1076 } else if (shouldEmitSpaceBeforeAndAfterNode(m_node)) {
1054 if (shouldRepresentNodeOffsetZero()) 1077 if (shouldRepresentNodeOffsetZero())
1055 spliceBuffer(spaceCharacter, Strategy::parent(*m_node), m_node, 0, 0); 1078 spliceBuffer(spaceCharacter, Strategy::parent(*m_node), m_node, 0, 0);
1056 } 1079 }
1057 } 1080 }
1058 1081
1059 template <typename Strategy> 1082 template <typename Strategy>
1060 bool TextIteratorAlgorithm<Strategy>::handleNonTextNode() { 1083 bool TextIteratorAlgorithm<Strategy>::handleNonTextNode() {
1061 if (shouldEmitNewlineForNode(m_node, emitsOriginalText())) 1084 if (shouldEmitNewlineForNode(m_node, emitsOriginalText()))
1062 spliceBuffer('\n', Strategy::parent(*m_node), m_node, 0, 1); 1085 spliceBuffer('\n', Strategy::parent(*m_node), m_node, 0, 1);
1063 else if (emitsCharactersBetweenAllVisiblePositions() && 1086 else if (emitsCharactersBetweenAllVisiblePositions() &&
1064 m_node->layoutObject() && m_node->layoutObject()->isHR()) 1087 m_node->layoutObject() && m_node->layoutObject()->isHR())
1065 spliceBuffer(spaceCharacter, Strategy::parent(*m_node), m_node, 0, 1); 1088 spliceBuffer(spaceCharacter, Strategy::parent(*m_node), m_node, 0, 1);
1066 else 1089 else
1067 representNodeOffsetZero(); 1090 representNodeOffsetZero();
1068 1091
1069 return true; 1092 return true;
1070 } 1093 }
1071 1094
1072 template <typename Strategy> 1095 template <typename Strategy>
1073 void TextIteratorAlgorithm<Strategy>::exitNode() { 1096 void TextIteratorAlgorithm<Strategy>::exitNode() {
1074 // prevent emitting a newline when exiting a collapsed block at beginning of t he range 1097 // prevent emitting a newline when exiting a collapsed block at beginning of
1075 // FIXME: !m_hasEmitted does not necessarily mean there was a collapsed block. .. it could 1098 // the range
1076 // have been an hr (e.g.). Also, a collapsed block could have height (e.g. a t able) and 1099 // FIXME: !m_hasEmitted does not necessarily mean there was a collapsed
1077 // therefore look like a blank line. 1100 // block... it could have been an hr (e.g.). Also, a collapsed block could
1101 // have height (e.g. a table) and therefore look like a blank line.
1078 if (!m_textState.hasEmitted()) 1102 if (!m_textState.hasEmitted())
1079 return; 1103 return;
1080 1104
1081 // Emit with a position *inside* m_node, after m_node's contents, in 1105 // Emit with a position *inside* m_node, after m_node's contents, in
1082 // case it is a block, because the run should start where the 1106 // case it is a block, because the run should start where the
1083 // emitted character is positioned visually. 1107 // emitted character is positioned visually.
1084 Node* lastChild = Strategy::lastChild(*m_node); 1108 Node* lastChild = Strategy::lastChild(*m_node);
1085 Node* baseNode = lastChild ? lastChild : m_node.get(); 1109 Node* baseNode = lastChild ? lastChild : m_node.get();
1086 // FIXME: This shouldn't require the m_lastTextNode to be true, but we can't c hange that without making 1110 // FIXME: This shouldn't require the m_lastTextNode to be true, but we can't
1087 // the logic in _web_attributedStringFromRange match. We'll get that for free when we switch to use 1111 // change that without making the logic in _web_attributedStringFromRange
1088 // TextIterator in _web_attributedStringFromRange. 1112 // match. We'll get that for free when we switch to use TextIterator in
1089 // See <rdar://problem/5428427> for an example of how this mismatch will cause problems. 1113 // _web_attributedStringFromRange. See <rdar://problem/5428427> for an example
1114 // of how this mismatch will cause problems.
1090 if (m_lastTextNode && shouldEmitNewlineAfterNode(*m_node)) { 1115 if (m_lastTextNode && shouldEmitNewlineAfterNode(*m_node)) {
1091 // use extra newline to represent margin bottom, as needed 1116 // use extra newline to represent margin bottom, as needed
1092 bool addNewline = shouldEmitExtraNewlineForNode(m_node); 1117 bool addNewline = shouldEmitExtraNewlineForNode(m_node);
1093 1118
1094 // FIXME: We need to emit a '\n' as we leave an empty block(s) that 1119 // FIXME: We need to emit a '\n' as we leave an empty block(s) that
1095 // contain a VisiblePosition when doing selection preservation. 1120 // contain a VisiblePosition when doing selection preservation.
1096 if (m_textState.lastCharacter() != '\n') { 1121 if (m_textState.lastCharacter() != '\n') {
1097 // insert a newline with a position following this block's contents. 1122 // insert a newline with a position following this block's contents.
1098 spliceBuffer(newlineCharacter, Strategy::parent(*baseNode), baseNode, 1, 1123 spliceBuffer(newlineCharacter, Strategy::parent(*baseNode), baseNode, 1,
1099 1); 1124 1);
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
1293 1318
1294 DocumentLifecycle::DisallowTransitionScope disallowTransition( 1319 DocumentLifecycle::DisallowTransitionScope disallowTransition(
1295 range.startPosition().document()->lifecycle()); 1320 range.startPosition().document()->lifecycle());
1296 1321
1297 TextIteratorAlgorithm<Strategy> it(range.startPosition(), range.endPosition(), 1322 TextIteratorAlgorithm<Strategy> it(range.startPosition(), range.endPosition(),
1298 behavior); 1323 behavior);
1299 1324
1300 if (it.atEnd()) 1325 if (it.atEnd())
1301 return emptyString(); 1326 return emptyString();
1302 1327
1303 // The initial buffer size can be critical for performance: https://bugs.webki t.org/show_bug.cgi?id=81192 1328 // The initial buffer size can be critical for performance:
1329 // https://bugs.webkit.org/show_bug.cgi?id=81192
1304 static const unsigned initialCapacity = 1 << 15; 1330 static const unsigned initialCapacity = 1 << 15;
1305 1331
1306 StringBuilder builder; 1332 StringBuilder builder;
1307 builder.reserveCapacity(initialCapacity); 1333 builder.reserveCapacity(initialCapacity);
1308 1334
1309 for (; !it.atEnd(); it.advance()) 1335 for (; !it.atEnd(); it.advance())
1310 it.text().appendTextToStringBuilder(builder); 1336 it.text().appendTextToStringBuilder(builder);
1311 1337
1312 if (builder.isEmpty()) 1338 if (builder.isEmpty())
1313 return emptyString(); 1339 return emptyString();
1314 1340
1315 return builder.toString(); 1341 return builder.toString();
1316 } 1342 }
1317 1343
1318 String plainText(const EphemeralRange& range, 1344 String plainText(const EphemeralRange& range,
1319 TextIteratorBehaviorFlags behavior) { 1345 TextIteratorBehaviorFlags behavior) {
1320 return createPlainText<EditingStrategy>(range, behavior); 1346 return createPlainText<EditingStrategy>(range, behavior);
1321 } 1347 }
1322 1348
1323 String plainText(const EphemeralRangeInFlatTree& range, 1349 String plainText(const EphemeralRangeInFlatTree& range,
1324 TextIteratorBehaviorFlags behavior) { 1350 TextIteratorBehaviorFlags behavior) {
1325 return createPlainText<EditingInFlatTreeStrategy>(range, behavior); 1351 return createPlainText<EditingInFlatTreeStrategy>(range, behavior);
1326 } 1352 }
1327 1353
1328 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; 1354 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>;
1329 template class CORE_TEMPLATE_EXPORT 1355 template class CORE_TEMPLATE_EXPORT
1330 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; 1356 TextIteratorAlgorithm<EditingInFlatTreeStrategy>;
1331 1357
1332 } // namespace blink 1358 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698