| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserv
ed. | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights |
| 3 * reserved. |
| 3 * Copyright (C) 2008, 2009, 2010, 2011 Google Inc. All rights reserved. | 4 * Copyright (C) 2008, 2009, 2010, 2011 Google Inc. All rights reserved. |
| 4 * Copyright (C) 2011 Igalia S.L. | 5 * Copyright (C) 2011 Igalia S.L. |
| 5 * Copyright (C) 2011 Motorola Mobility. All rights reserved. | 6 * Copyright (C) 2011 Motorola Mobility. All rights reserved. |
| 6 * | 7 * |
| 7 * Redistribution and use in source and binary forms, with or without | 8 * Redistribution and use in source and binary forms, with or without |
| 8 * modification, are permitted provided that the following conditions | 9 * modification, are permitted provided that the following conditions |
| 9 * are met: | 10 * are met: |
| 10 * 1. Redistributions of source code must retain the above copyright | 11 * 1. Redistributions of source code must retain the above copyright |
| 11 * notice, this list of conditions and the following disclaimer. | 12 * notice, this list of conditions and the following disclaimer. |
| 12 * 2. Redistributions in binary form must reproduce the above copyright | 13 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 Node* constrainingAncestor) { | 171 Node* constrainingAncestor) { |
| 171 Node* firstNode = startPosition.nodeAsRangeFirstNode(); | 172 Node* firstNode = startPosition.nodeAsRangeFirstNode(); |
| 172 // For compatibility reason, we use container node of start and end | 173 // For compatibility reason, we use container node of start and end |
| 173 // positions rather than first node and last node in selection. | 174 // positions rather than first node and last node in selection. |
| 174 Node* commonAncestor = | 175 Node* commonAncestor = |
| 175 Strategy::commonAncestor(*startPosition.computeContainerNode(), | 176 Strategy::commonAncestor(*startPosition.computeContainerNode(), |
| 176 *endPosition.computeContainerNode()); | 177 *endPosition.computeContainerNode()); |
| 177 DCHECK(commonAncestor); | 178 DCHECK(commonAncestor); |
| 178 HTMLElement* specialCommonAncestor = nullptr; | 179 HTMLElement* specialCommonAncestor = nullptr; |
| 179 if (shouldAnnotate == AnnotateForInterchange) { | 180 if (shouldAnnotate == AnnotateForInterchange) { |
| 180 // Include ancestors that aren't completely inside the range but are require
d to retain | 181 // Include ancestors that aren't completely inside the range but are |
| 181 // the structure and appearance of the copied markup. | 182 // required to retain the structure and appearance of the copied markup. |
| 182 specialCommonAncestor = | 183 specialCommonAncestor = |
| 183 ancestorToRetainStructureAndAppearance(commonAncestor); | 184 ancestorToRetainStructureAndAppearance(commonAncestor); |
| 184 if (Node* parentListNode = enclosingNodeOfType( | 185 if (Node* parentListNode = enclosingNodeOfType( |
| 185 firstPositionInOrBeforeNode(firstNode), isListItem)) { | 186 firstPositionInOrBeforeNode(firstNode), isListItem)) { |
| 186 EphemeralRangeTemplate<Strategy> markupRange = | 187 EphemeralRangeTemplate<Strategy> markupRange = |
| 187 EphemeralRangeTemplate<Strategy>(startPosition, endPosition); | 188 EphemeralRangeTemplate<Strategy>(startPosition, endPosition); |
| 188 EphemeralRangeTemplate<Strategy> nodeRange = normalizeRange( | 189 EphemeralRangeTemplate<Strategy> nodeRange = normalizeRange( |
| 189 EphemeralRangeTemplate<Strategy>::rangeOfContents(*parentListNode)); | 190 EphemeralRangeTemplate<Strategy>::rangeOfContents(*parentListNode)); |
| 190 if (nodeRange == markupRange) { | 191 if (nodeRange == markupRange) { |
| 191 ContainerNode* ancestor = parentListNode->parentNode(); | 192 ContainerNode* ancestor = parentListNode->parentNode(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 208 if (checkAncestor->layoutObject()) { | 209 if (checkAncestor->layoutObject()) { |
| 209 HTMLElement* newSpecialCommonAncestor = | 210 HTMLElement* newSpecialCommonAncestor = |
| 210 toHTMLElement(highestEnclosingNodeOfType( | 211 toHTMLElement(highestEnclosingNodeOfType( |
| 211 Position::firstPositionInNode(checkAncestor), | 212 Position::firstPositionInNode(checkAncestor), |
| 212 &isPresentationalHTMLElement, CanCrossEditingBoundary, | 213 &isPresentationalHTMLElement, CanCrossEditingBoundary, |
| 213 constrainingAncestor)); | 214 constrainingAncestor)); |
| 214 if (newSpecialCommonAncestor) | 215 if (newSpecialCommonAncestor) |
| 215 specialCommonAncestor = newSpecialCommonAncestor; | 216 specialCommonAncestor = newSpecialCommonAncestor; |
| 216 } | 217 } |
| 217 | 218 |
| 218 // If a single tab is selected, commonAncestor will be a text node inside a ta
b span. | 219 // If a single tab is selected, commonAncestor will be a text node inside a |
| 219 // If two or more tabs are selected, commonAncestor will be the tab span. | 220 // tab span. If two or more tabs are selected, commonAncestor will be the tab |
| 220 // In either case, if there is a specialCommonAncestor already, it will necess
arily be above | 221 // span. In either case, if there is a specialCommonAncestor already, it will |
| 221 // any tab span that needs to be included. | 222 // necessarily be above any tab span that needs to be included. |
| 222 if (!specialCommonAncestor && isTabHTMLSpanElementTextNode(commonAncestor)) | 223 if (!specialCommonAncestor && isTabHTMLSpanElementTextNode(commonAncestor)) |
| 223 specialCommonAncestor = | 224 specialCommonAncestor = |
| 224 toHTMLSpanElement(Strategy::parent(*commonAncestor)); | 225 toHTMLSpanElement(Strategy::parent(*commonAncestor)); |
| 225 if (!specialCommonAncestor && isTabHTMLSpanElement(commonAncestor)) | 226 if (!specialCommonAncestor && isTabHTMLSpanElement(commonAncestor)) |
| 226 specialCommonAncestor = toHTMLSpanElement(commonAncestor); | 227 specialCommonAncestor = toHTMLSpanElement(commonAncestor); |
| 227 | 228 |
| 228 if (HTMLAnchorElement* enclosingAnchor = | 229 if (HTMLAnchorElement* enclosingAnchor = |
| 229 toHTMLAnchorElement(enclosingElementWithTag( | 230 toHTMLAnchorElement(enclosingElementWithTag( |
| 230 Position::firstPositionInNode(specialCommonAncestor | 231 Position::firstPositionInNode(specialCommonAncestor |
| 231 ? specialCommonAncestor | 232 ? specialCommonAncestor |
| 232 : commonAncestor), | 233 : commonAncestor), |
| 233 aTag))) | 234 aTag))) |
| 234 specialCommonAncestor = enclosingAnchor; | 235 specialCommonAncestor = enclosingAnchor; |
| 235 | 236 |
| 236 return specialCommonAncestor; | 237 return specialCommonAncestor; |
| 237 } | 238 } |
| 238 | 239 |
| 239 template <typename Strategy> | 240 template <typename Strategy> |
| 240 class CreateMarkupAlgorithm { | 241 class CreateMarkupAlgorithm { |
| 241 public: | 242 public: |
| 242 static String createMarkup( | 243 static String createMarkup( |
| 243 const PositionTemplate<Strategy>& startPosition, | 244 const PositionTemplate<Strategy>& startPosition, |
| 244 const PositionTemplate<Strategy>& endPosition, | 245 const PositionTemplate<Strategy>& endPosition, |
| 245 EAnnotateForInterchange shouldAnnotate = DoNotAnnotateForInterchange, | 246 EAnnotateForInterchange shouldAnnotate = DoNotAnnotateForInterchange, |
| 246 ConvertBlocksToInlines = ConvertBlocksToInlines::NotConvert, | 247 ConvertBlocksToInlines = ConvertBlocksToInlines::NotConvert, |
| 247 EAbsoluteURLs shouldResolveURLs = DoNotResolveURLs, | 248 EAbsoluteURLs shouldResolveURLs = DoNotResolveURLs, |
| 248 Node* constrainingAncestor = nullptr); | 249 Node* constrainingAncestor = nullptr); |
| 249 }; | 250 }; |
| 250 | 251 |
| 251 // FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForIntercha
nge? | 252 // FIXME: Shouldn't we omit style info when annotate == |
| 252 // FIXME: At least, annotation and style info should probably not be included in
range.markupString() | 253 // DoNotAnnotateForInterchange? |
| 254 // FIXME: At least, annotation and style info should probably not be included in |
| 255 // range.markupString() |
| 253 template <typename Strategy> | 256 template <typename Strategy> |
| 254 String CreateMarkupAlgorithm<Strategy>::createMarkup( | 257 String CreateMarkupAlgorithm<Strategy>::createMarkup( |
| 255 const PositionTemplate<Strategy>& startPosition, | 258 const PositionTemplate<Strategy>& startPosition, |
| 256 const PositionTemplate<Strategy>& endPosition, | 259 const PositionTemplate<Strategy>& endPosition, |
| 257 EAnnotateForInterchange shouldAnnotate, | 260 EAnnotateForInterchange shouldAnnotate, |
| 258 ConvertBlocksToInlines convertBlocksToInlines, | 261 ConvertBlocksToInlines convertBlocksToInlines, |
| 259 EAbsoluteURLs shouldResolveURLs, | 262 EAbsoluteURLs shouldResolveURLs, |
| 260 Node* constrainingAncestor) { | 263 Node* constrainingAncestor) { |
| 261 if (startPosition.isNull() || endPosition.isNull()) | 264 if (startPosition.isNull() || endPosition.isNull()) |
| 262 return emptyString(); | 265 return emptyString(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 return CreateMarkupAlgorithm<EditingInFlatTreeStrategy>::createMarkup( | 306 return CreateMarkupAlgorithm<EditingInFlatTreeStrategy>::createMarkup( |
| 304 startPosition, endPosition, shouldAnnotate, convertBlocksToInlines, | 307 startPosition, endPosition, shouldAnnotate, convertBlocksToInlines, |
| 305 shouldResolveURLs, constrainingAncestor); | 308 shouldResolveURLs, constrainingAncestor); |
| 306 } | 309 } |
| 307 | 310 |
| 308 DocumentFragment* createFragmentFromMarkup( | 311 DocumentFragment* createFragmentFromMarkup( |
| 309 Document& document, | 312 Document& document, |
| 310 const String& markup, | 313 const String& markup, |
| 311 const String& baseURL, | 314 const String& baseURL, |
| 312 ParserContentPolicy parserContentPolicy) { | 315 ParserContentPolicy parserContentPolicy) { |
| 313 // We use a fake body element here to trick the HTML parser to using the InBod
y insertion mode. | 316 // We use a fake body element here to trick the HTML parser to using the |
| 317 // InBody insertion mode. |
| 314 HTMLBodyElement* fakeBody = HTMLBodyElement::create(document); | 318 HTMLBodyElement* fakeBody = HTMLBodyElement::create(document); |
| 315 DocumentFragment* fragment = DocumentFragment::create(document); | 319 DocumentFragment* fragment = DocumentFragment::create(document); |
| 316 | 320 |
| 317 fragment->parseHTML(markup, fakeBody, parserContentPolicy); | 321 fragment->parseHTML(markup, fakeBody, parserContentPolicy); |
| 318 | 322 |
| 319 if (!baseURL.isEmpty() && baseURL != blankURL() && | 323 if (!baseURL.isEmpty() && baseURL != blankURL() && |
| 320 baseURL != document.baseURL()) | 324 baseURL != document.baseURL()) |
| 321 completeURLs(*fragment, baseURL); | 325 completeURLs(*fragment, baseURL); |
| 322 | 326 |
| 323 return fragment; | 327 return fragment; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 368 } | 372 } |
| 369 } | 373 } |
| 370 | 374 |
| 371 DocumentFragment* createFragmentFromMarkupWithContext( | 375 DocumentFragment* createFragmentFromMarkupWithContext( |
| 372 Document& document, | 376 Document& document, |
| 373 const String& markup, | 377 const String& markup, |
| 374 unsigned fragmentStart, | 378 unsigned fragmentStart, |
| 375 unsigned fragmentEnd, | 379 unsigned fragmentEnd, |
| 376 const String& baseURL, | 380 const String& baseURL, |
| 377 ParserContentPolicy parserContentPolicy) { | 381 ParserContentPolicy parserContentPolicy) { |
| 378 // FIXME: Need to handle the case where the markup already contains these mark
ers. | 382 // FIXME: Need to handle the case where the markup already contains these |
| 383 // markers. |
| 379 | 384 |
| 380 StringBuilder taggedMarkup; | 385 StringBuilder taggedMarkup; |
| 381 taggedMarkup.append(markup.left(fragmentStart)); | 386 taggedMarkup.append(markup.left(fragmentStart)); |
| 382 MarkupFormatter::appendComment(taggedMarkup, fragmentMarkerTag); | 387 MarkupFormatter::appendComment(taggedMarkup, fragmentMarkerTag); |
| 383 taggedMarkup.append( | 388 taggedMarkup.append( |
| 384 markup.substring(fragmentStart, fragmentEnd - fragmentStart)); | 389 markup.substring(fragmentStart, fragmentEnd - fragmentStart)); |
| 385 MarkupFormatter::appendComment(taggedMarkup, fragmentMarkerTag); | 390 MarkupFormatter::appendComment(taggedMarkup, fragmentMarkerTag); |
| 386 taggedMarkup.append(markup.substring(fragmentEnd)); | 391 taggedMarkup.append(markup.substring(fragmentEnd)); |
| 387 | 392 |
| 388 DocumentFragment* taggedFragment = createFragmentFromMarkup( | 393 DocumentFragment* taggedFragment = createFragmentFromMarkup( |
| (...skipping 14 matching lines...) Expand all Loading... |
| 403 | 408 |
| 404 Range* range = Range::create( | 409 Range* range = Range::create( |
| 405 *taggedDocument, | 410 *taggedDocument, |
| 406 Position::afterNode(nodeBeforeContext).parentAnchoredEquivalent(), | 411 Position::afterNode(nodeBeforeContext).parentAnchoredEquivalent(), |
| 407 Position::beforeNode(nodeAfterContext).parentAnchoredEquivalent()); | 412 Position::beforeNode(nodeAfterContext).parentAnchoredEquivalent()); |
| 408 | 413 |
| 409 Node* commonAncestor = range->commonAncestorContainer(); | 414 Node* commonAncestor = range->commonAncestorContainer(); |
| 410 HTMLElement* specialCommonAncestor = | 415 HTMLElement* specialCommonAncestor = |
| 411 ancestorToRetainStructureAndAppearanceWithNoLayoutObject(commonAncestor); | 416 ancestorToRetainStructureAndAppearanceWithNoLayoutObject(commonAncestor); |
| 412 | 417 |
| 413 // When there's a special common ancestor outside of the fragment, we must inc
lude it as well to | 418 // When there's a special common ancestor outside of the fragment, we must |
| 414 // preserve the structure and appearance of the fragment. For example, if the
fragment contains | 419 // include it as well to preserve the structure and appearance of the |
| 415 // TD, we need to include the enclosing TABLE tag as well. | 420 // fragment. For example, if the fragment contains TD, we need to include the |
| 421 // enclosing TABLE tag as well. |
| 416 DocumentFragment* fragment = DocumentFragment::create(document); | 422 DocumentFragment* fragment = DocumentFragment::create(document); |
| 417 if (specialCommonAncestor) | 423 if (specialCommonAncestor) |
| 418 fragment->appendChild(specialCommonAncestor); | 424 fragment->appendChild(specialCommonAncestor); |
| 419 else | 425 else |
| 420 fragment->parserTakeAllChildrenFrom(toContainerNode(*commonAncestor)); | 426 fragment->parserTakeAllChildrenFrom(toContainerNode(*commonAncestor)); |
| 421 | 427 |
| 422 trimFragment(fragment, nodeBeforeContext, nodeAfterContext); | 428 trimFragment(fragment, nodeBeforeContext, nodeAfterContext); |
| 423 | 429 |
| 424 return fragment; | 430 return fragment; |
| 425 } | 431 } |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 shouldPreserveNewline(context)) { | 535 shouldPreserveNewline(context)) { |
| 530 fragment->appendChild(document.createTextNode(string)); | 536 fragment->appendChild(document.createTextNode(string)); |
| 531 if (string.endsWith('\n')) { | 537 if (string.endsWith('\n')) { |
| 532 HTMLBRElement* element = HTMLBRElement::create(document); | 538 HTMLBRElement* element = HTMLBRElement::create(document); |
| 533 element->setAttribute(classAttr, AppleInterchangeNewline); | 539 element->setAttribute(classAttr, AppleInterchangeNewline); |
| 534 fragment->appendChild(element); | 540 fragment->appendChild(element); |
| 535 } | 541 } |
| 536 return fragment; | 542 return fragment; |
| 537 } | 543 } |
| 538 | 544 |
| 539 // A string with no newlines gets added inline, rather than being put into a p
aragraph. | 545 // A string with no newlines gets added inline, rather than being put into a |
| 546 // paragraph. |
| 540 if (string.find('\n') == kNotFound) { | 547 if (string.find('\n') == kNotFound) { |
| 541 fillContainerFromString(fragment, string); | 548 fillContainerFromString(fragment, string); |
| 542 return fragment; | 549 return fragment; |
| 543 } | 550 } |
| 544 | 551 |
| 545 // Break string into paragraphs. Extra line breaks turn into empty paragraphs. | 552 // Break string into paragraphs. Extra line breaks turn into empty paragraphs. |
| 546 Element* block = | 553 Element* block = |
| 547 enclosingBlock(context.startPosition().nodeAsRangeFirstNode()); | 554 enclosingBlock(context.startPosition().nodeAsRangeFirstNode()); |
| 548 bool useClonesOfEnclosingBlock = | 555 bool useClonesOfEnclosingBlock = |
| 549 block && !isHTMLBodyElement(*block) && !isHTMLHtmlElement(*block) && | 556 block && !isHTMLBodyElement(*block) && !isHTMLHtmlElement(*block) && |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 return fragment; | 608 return fragment; |
| 602 } | 609 } |
| 603 | 610 |
| 604 DocumentFragment* createFragmentForTransformToFragment( | 611 DocumentFragment* createFragmentForTransformToFragment( |
| 605 const String& sourceString, | 612 const String& sourceString, |
| 606 const String& sourceMIMEType, | 613 const String& sourceMIMEType, |
| 607 Document& outputDoc) { | 614 Document& outputDoc) { |
| 608 DocumentFragment* fragment = outputDoc.createDocumentFragment(); | 615 DocumentFragment* fragment = outputDoc.createDocumentFragment(); |
| 609 | 616 |
| 610 if (sourceMIMEType == "text/html") { | 617 if (sourceMIMEType == "text/html") { |
| 611 // As far as I can tell, there isn't a spec for how transformToFragment is s
upposed to work. | 618 // As far as I can tell, there isn't a spec for how transformToFragment is |
| 612 // Based on the documentation I can find, it looks like we want to start par
sing the fragment in the InBody insertion mode. | 619 // supposed to work. Based on the documentation I can find, it looks like we |
| 613 // Unfortunately, that's an implementation detail of the parser. | 620 // want to start parsing the fragment in the InBody insertion mode. |
| 614 // We achieve that effect here by passing in a fake body element as context
for the fragment. | 621 // Unfortunately, that's an implementation detail of the parser. We achieve |
| 622 // that effect here by passing in a fake body element as context for the |
| 623 // fragment. |
| 615 HTMLBodyElement* fakeBody = HTMLBodyElement::create(outputDoc); | 624 HTMLBodyElement* fakeBody = HTMLBodyElement::create(outputDoc); |
| 616 fragment->parseHTML(sourceString, fakeBody); | 625 fragment->parseHTML(sourceString, fakeBody); |
| 617 } else if (sourceMIMEType == "text/plain") { | 626 } else if (sourceMIMEType == "text/plain") { |
| 618 fragment->parserAppendChild(Text::create(outputDoc, sourceString)); | 627 fragment->parserAppendChild(Text::create(outputDoc, sourceString)); |
| 619 } else { | 628 } else { |
| 620 bool successfulParse = fragment->parseXML(sourceString, 0); | 629 bool successfulParse = fragment->parseXML(sourceString, 0); |
| 621 if (!successfulParse) | 630 if (!successfulParse) |
| 622 return nullptr; | 631 return nullptr; |
| 623 } | 632 } |
| 624 | 633 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 702 return; | 711 return; |
| 703 } | 712 } |
| 704 | 713 |
| 705 // FIXME: This is wrong if containerNode->firstChild() has more than one ref! | 714 // FIXME: This is wrong if containerNode->firstChild() has more than one ref! |
| 706 if (containerNode->hasOneTextChild() && fragment->hasOneTextChild()) { | 715 if (containerNode->hasOneTextChild() && fragment->hasOneTextChild()) { |
| 707 toText(containerNode->firstChild()) | 716 toText(containerNode->firstChild()) |
| 708 ->setData(toText(fragment->firstChild())->data()); | 717 ->setData(toText(fragment->firstChild())->data()); |
| 709 return; | 718 return; |
| 710 } | 719 } |
| 711 | 720 |
| 712 // FIXME: No need to replace the child it is a text node and its contents are
already == text. | 721 // FIXME: No need to replace the child it is a text node and its contents are |
| 722 // already == text. |
| 713 if (containerNode->hasOneChild()) { | 723 if (containerNode->hasOneChild()) { |
| 714 containerNode->replaceChild(fragment, containerNode->firstChild(), | 724 containerNode->replaceChild(fragment, containerNode->firstChild(), |
| 715 exceptionState); | 725 exceptionState); |
| 716 return; | 726 return; |
| 717 } | 727 } |
| 718 | 728 |
| 719 containerNode->removeChildren(); | 729 containerNode->removeChildren(); |
| 720 containerNode->appendChild(fragment, exceptionState); | 730 containerNode->appendChild(fragment, exceptionState); |
| 721 } | 731 } |
| 722 | 732 |
| 723 void replaceChildrenWithText(ContainerNode* container, | 733 void replaceChildrenWithText(ContainerNode* container, |
| 724 const String& text, | 734 const String& text, |
| 725 ExceptionState& exceptionState) { | 735 ExceptionState& exceptionState) { |
| 726 DCHECK(container); | 736 DCHECK(container); |
| 727 ContainerNode* containerNode(container); | 737 ContainerNode* containerNode(container); |
| 728 | 738 |
| 729 ChildListMutationScope mutation(*containerNode); | 739 ChildListMutationScope mutation(*containerNode); |
| 730 | 740 |
| 731 // FIXME: This is wrong if containerNode->firstChild() has more than one ref!
Example: | 741 // FIXME: This is wrong if containerNode->firstChild() has more than one ref! |
| 742 // Example: |
| 732 // <div>foo</div> | 743 // <div>foo</div> |
| 733 // <script> | 744 // <script> |
| 734 // var oldText = div.firstChild; | 745 // var oldText = div.firstChild; |
| 735 // console.log(oldText.data); // foo | 746 // console.log(oldText.data); // foo |
| 736 // div.innerText = "bar"; | 747 // div.innerText = "bar"; |
| 737 // console.log(oldText.data); // bar!?! | 748 // console.log(oldText.data); // bar!?! |
| 738 // </script> | 749 // </script> |
| 739 // I believe this is an intentional benchmark cheat from years ago. | 750 // I believe this is an intentional benchmark cheat from years ago. |
| 740 // We should re-visit if we actually want this still. | 751 // We should re-visit if we actually want this still. |
| 741 if (containerNode->hasOneTextChild()) { | 752 if (containerNode->hasOneTextChild()) { |
| 742 toText(containerNode->firstChild())->setData(text); | 753 toText(containerNode->firstChild())->setData(text); |
| 743 return; | 754 return; |
| 744 } | 755 } |
| 745 | 756 |
| 746 // NOTE: This method currently always creates a text node, even if that text n
ode will be empty. | 757 // NOTE: This method currently always creates a text node, even if that text |
| 758 // node will be empty. |
| 747 Text* textNode = Text::create(containerNode->document(), text); | 759 Text* textNode = Text::create(containerNode->document(), text); |
| 748 | 760 |
| 749 // FIXME: No need to replace the child it is a text node and its contents are
already == text. | 761 // FIXME: No need to replace the child it is a text node and its contents are |
| 762 // already == text. |
| 750 if (containerNode->hasOneChild()) { | 763 if (containerNode->hasOneChild()) { |
| 751 containerNode->replaceChild(textNode, containerNode->firstChild(), | 764 containerNode->replaceChild(textNode, containerNode->firstChild(), |
| 752 exceptionState); | 765 exceptionState); |
| 753 return; | 766 return; |
| 754 } | 767 } |
| 755 | 768 |
| 756 containerNode->removeChildren(); | 769 containerNode->removeChildren(); |
| 757 containerNode->appendChild(textNode, exceptionState); | 770 containerNode->appendChild(textNode, exceptionState); |
| 758 } | 771 } |
| 759 | 772 |
| 760 void mergeWithNextTextNode(Text* textNode, ExceptionState& exceptionState) { | 773 void mergeWithNextTextNode(Text* textNode, ExceptionState& exceptionState) { |
| 761 DCHECK(textNode); | 774 DCHECK(textNode); |
| 762 Node* next = textNode->nextSibling(); | 775 Node* next = textNode->nextSibling(); |
| 763 if (!next || !next->isTextNode()) | 776 if (!next || !next->isTextNode()) |
| 764 return; | 777 return; |
| 765 | 778 |
| 766 Text* textNext = toText(next); | 779 Text* textNext = toText(next); |
| 767 textNode->appendData(textNext->data()); | 780 textNode->appendData(textNext->data()); |
| 768 if (textNext->parentNode()) // Might have been removed by mutation event. | 781 if (textNext->parentNode()) // Might have been removed by mutation event. |
| 769 textNext->remove(exceptionState); | 782 textNext->remove(exceptionState); |
| 770 } | 783 } |
| 771 | 784 |
| 772 template class CORE_TEMPLATE_EXPORT CreateMarkupAlgorithm<EditingStrategy>; | 785 template class CORE_TEMPLATE_EXPORT CreateMarkupAlgorithm<EditingStrategy>; |
| 773 template class CORE_TEMPLATE_EXPORT | 786 template class CORE_TEMPLATE_EXPORT |
| 774 CreateMarkupAlgorithm<EditingInFlatTreeStrategy>; | 787 CreateMarkupAlgorithm<EditingInFlatTreeStrategy>; |
| 775 | 788 |
| 776 } // namespace blink | 789 } // namespace blink |
| OLD | NEW |