| 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 reserv
ed. |
| 3 * Copyright (C) 2008, 2009, 2010, 2011 Google Inc. All rights reserved. | 3 * Copyright (C) 2008, 2009, 2010, 2011 Google Inc. All rights reserved. |
| 4 * Copyright (C) 2011 Igalia S.L. | 4 * Copyright (C) 2011 Igalia S.L. |
| 5 * Copyright (C) 2011 Motorola Mobility. All rights reserved. | 5 * Copyright (C) 2011 Motorola Mobility. All rights reserved. |
| 6 * | 6 * |
| 7 * Redistribution and use in source and binary forms, with or without | 7 * Redistribution and use in source and binary forms, with or without |
| 8 * modification, are permitted provided that the following conditions | 8 * modification, are permitted provided that the following conditions |
| 9 * are met: | 9 * are met: |
| 10 * 1. Redistributions of source code must retain the above copyright | 10 * 1. Redistributions of source code must retain the above copyright |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 unsigned startOffset = 0; | 251 unsigned startOffset = 0; |
| 252 unsigned endOffset = textNode->length(); | 252 unsigned endOffset = textNode->length(); |
| 253 | 253 |
| 254 if (range && node == range->startContainer()) | 254 if (range && node == range->startContainer()) |
| 255 startOffset = range->startOffset(); | 255 startOffset = range->startOffset(); |
| 256 if (range && node == range->endContainer()) | 256 if (range && node == range->endContainer()) |
| 257 endOffset = range->endOffset(); | 257 endOffset = range->endOffset(); |
| 258 | 258 |
| 259 Position start = createLegacyEditingPosition(const_cast<Node*>(node), startO
ffset); | 259 Position start = createLegacyEditingPosition(const_cast<Node*>(node), startO
ffset); |
| 260 Position end = createLegacyEditingPosition(const_cast<Node*>(node), endOffse
t); | 260 Position end = createLegacyEditingPosition(const_cast<Node*>(node), endOffse
t); |
| 261 return plainText(Range::create(&node->document(), start, end).get()); | 261 return plainText(Range::create(node->document(), start, end).get()); |
| 262 } | 262 } |
| 263 | 263 |
| 264 String StyledMarkupAccumulator::stringValueForRange(const Node* node, const Rang
e* range) | 264 String StyledMarkupAccumulator::stringValueForRange(const Node* node, const Rang
e* range) |
| 265 { | 265 { |
| 266 if (!range) | 266 if (!range) |
| 267 return node->nodeValue(); | 267 return node->nodeValue(); |
| 268 | 268 |
| 269 String str = node->nodeValue(); | 269 String str = node->nodeValue(); |
| 270 if (node == range->endContainer()) | 270 if (node == range->endContainer()) |
| 271 str.truncate(range->endOffset()); | 271 str.truncate(range->endOffset()); |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 535 specialCommonAncestor = commonAncestor; | 535 specialCommonAncestor = commonAncestor; |
| 536 | 536 |
| 537 if (Node *enclosingAnchor = enclosingNodeWithTag(firstPositionInNode(special
CommonAncestor ? specialCommonAncestor : commonAncestor), aTag)) | 537 if (Node *enclosingAnchor = enclosingNodeWithTag(firstPositionInNode(special
CommonAncestor ? specialCommonAncestor : commonAncestor), aTag)) |
| 538 specialCommonAncestor = enclosingAnchor; | 538 specialCommonAncestor = enclosingAnchor; |
| 539 | 539 |
| 540 return specialCommonAncestor; | 540 return specialCommonAncestor; |
| 541 } | 541 } |
| 542 | 542 |
| 543 // FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForIntercha
nge? | 543 // FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForIntercha
nge? |
| 544 // FIXME: At least, annotation and style info should probably not be included in
range.markupString() | 544 // FIXME: At least, annotation and style info should probably not be included in
range.markupString() |
| 545 static String createMarkupInternal(Document* document, const Range* range, const
Range* updatedRange, Vector<Node*>* nodes, | 545 static String createMarkupInternal(Document& document, const Range* range, const
Range* updatedRange, Vector<Node*>* nodes, |
| 546 EAnnotateForInterchange shouldAnnotate, bool convertBlocksToInlines, EAbsolu
teURLs shouldResolveURLs, Node* constrainingAncestor) | 546 EAnnotateForInterchange shouldAnnotate, bool convertBlocksToInlines, EAbsolu
teURLs shouldResolveURLs, Node* constrainingAncestor) |
| 547 { | 547 { |
| 548 ASSERT(document); | |
| 549 ASSERT(range); | 548 ASSERT(range); |
| 550 ASSERT(updatedRange); | 549 ASSERT(updatedRange); |
| 551 DEFINE_STATIC_LOCAL(const String, interchangeNewlineString, ("<br class=\""
AppleInterchangeNewline "\">")); | 550 DEFINE_STATIC_LOCAL(const String, interchangeNewlineString, ("<br class=\""
AppleInterchangeNewline "\">")); |
| 552 | 551 |
| 553 bool collapsed = updatedRange->collapsed(ASSERT_NO_EXCEPTION); | 552 bool collapsed = updatedRange->collapsed(ASSERT_NO_EXCEPTION); |
| 554 if (collapsed) | 553 if (collapsed) |
| 555 return emptyString(); | 554 return emptyString(); |
| 556 Node* commonAncestor = updatedRange->commonAncestorContainer(ASSERT_NO_EXCEP
TION); | 555 Node* commonAncestor = updatedRange->commonAncestorContainer(ASSERT_NO_EXCEP
TION); |
| 557 if (!commonAncestor) | 556 if (!commonAncestor) |
| 558 return emptyString(); | 557 return emptyString(); |
| 559 | 558 |
| 560 document->updateLayoutIgnorePendingStylesheets(); | 559 document.updateLayoutIgnorePendingStylesheets(); |
| 561 | 560 |
| 562 Node* body = enclosingNodeWithTag(firstPositionInNode(commonAncestor), bodyT
ag); | 561 Node* body = enclosingNodeWithTag(firstPositionInNode(commonAncestor), bodyT
ag); |
| 563 Node* fullySelectedRoot = 0; | 562 Node* fullySelectedRoot = 0; |
| 564 // FIXME: Do this for all fully selected blocks, not just the body. | 563 // FIXME: Do this for all fully selected blocks, not just the body. |
| 565 if (body && areRangesEqual(VisibleSelection::selectionFromContentsOfNode(bod
y).toNormalizedRange().get(), range)) | 564 if (body && areRangesEqual(VisibleSelection::selectionFromContentsOfNode(bod
y).toNormalizedRange().get(), range)) |
| 566 fullySelectedRoot = body; | 565 fullySelectedRoot = body; |
| 567 Node* specialCommonAncestor = highestAncestorToWrapMarkup(updatedRange, shou
ldAnnotate, constrainingAncestor); | 566 Node* specialCommonAncestor = highestAncestorToWrapMarkup(updatedRange, shou
ldAnnotate, constrainingAncestor); |
| 568 StyledMarkupAccumulator accumulator(nodes, shouldResolveURLs, shouldAnnotate
, updatedRange, specialCommonAncestor); | 567 StyledMarkupAccumulator accumulator(nodes, shouldResolveURLs, shouldAnnotate
, updatedRange, specialCommonAncestor); |
| 569 Node* pastEnd = updatedRange->pastLastNode(); | 568 Node* pastEnd = updatedRange->pastLastNode(); |
| 570 | 569 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 597 fullySelectedRootStyle->style()->setProperty(CSSPropertyBack
groundImage, "url('" + toElement(fullySelectedRoot)->getAttribute(backgroundAttr
) + "')"); | 596 fullySelectedRootStyle->style()->setProperty(CSSPropertyBack
groundImage, "url('" + toElement(fullySelectedRoot)->getAttribute(backgroundAttr
) + "')"); |
| 598 | 597 |
| 599 if (fullySelectedRootStyle->style()) { | 598 if (fullySelectedRootStyle->style()) { |
| 600 // Reset the CSS properties to avoid an assertion error in a
ddStyleMarkup(). | 599 // Reset the CSS properties to avoid an assertion error in a
ddStyleMarkup(). |
| 601 // This assertion is caused at least when we select all text
of a <body> element whose | 600 // This assertion is caused at least when we select all text
of a <body> element whose |
| 602 // 'text-decoration' property is "inherit", and copy it. | 601 // 'text-decoration' property is "inherit", and copy it. |
| 603 if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->st
yle(), CSSPropertyTextDecoration)) | 602 if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->st
yle(), CSSPropertyTextDecoration)) |
| 604 fullySelectedRootStyle->style()->setProperty(CSSProperty
TextDecoration, CSSValueNone); | 603 fullySelectedRootStyle->style()->setProperty(CSSProperty
TextDecoration, CSSValueNone); |
| 605 if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->st
yle(), CSSPropertyWebkitTextDecorationsInEffect)) | 604 if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->st
yle(), CSSPropertyWebkitTextDecorationsInEffect)) |
| 606 fullySelectedRootStyle->style()->setProperty(CSSProperty
WebkitTextDecorationsInEffect, CSSValueNone); | 605 fullySelectedRootStyle->style()->setProperty(CSSProperty
WebkitTextDecorationsInEffect, CSSValueNone); |
| 607 accumulator.wrapWithStyleNode(fullySelectedRootStyle->style(
), document, true); | 606 accumulator.wrapWithStyleNode(fullySelectedRootStyle->style(
), &document, true); |
| 608 } | 607 } |
| 609 } else { | 608 } else { |
| 610 // Since this node and all the other ancestors are not in the se
lection we want to set RangeFullySelectsNode to DoesNotFullySelectNode | 609 // Since this node and all the other ancestors are not in the se
lection we want to set RangeFullySelectsNode to DoesNotFullySelectNode |
| 611 // so that styles that affect the exterior of the node are not i
ncluded. | 610 // so that styles that affect the exterior of the node are not i
ncluded. |
| 612 accumulator.wrapWithNode(ancestor, convertBlocksToInlines, Style
dMarkupAccumulator::DoesNotFullySelectNode); | 611 accumulator.wrapWithNode(ancestor, convertBlocksToInlines, Style
dMarkupAccumulator::DoesNotFullySelectNode); |
| 613 } | 612 } |
| 614 if (nodes) | 613 if (nodes) |
| 615 nodes->append(ancestor); | 614 nodes->append(ancestor); |
| 616 | 615 |
| 617 lastClosed = ancestor; | 616 lastClosed = ancestor; |
| 618 | 617 |
| 619 if (ancestor == specialCommonAncestor) | 618 if (ancestor == specialCommonAncestor) |
| 620 break; | 619 break; |
| 621 } | 620 } |
| 622 } | 621 } |
| 623 | 622 |
| 624 // FIXME: The interchange newline should be placed in the block that it's in
, not after all of the content, unconditionally. | 623 // FIXME: The interchange newline should be placed in the block that it's in
, not after all of the content, unconditionally. |
| 625 if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(
visibleEnd.previous())) | 624 if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(
visibleEnd.previous())) |
| 626 accumulator.appendString(interchangeNewlineString); | 625 accumulator.appendString(interchangeNewlineString); |
| 627 | 626 |
| 628 return accumulator.takeResults(); | 627 return accumulator.takeResults(); |
| 629 } | 628 } |
| 630 | 629 |
| 631 String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterc
hange shouldAnnotate, bool convertBlocksToInlines, EAbsoluteURLs shouldResolveUR
Ls, Node* constrainingAncestor) | 630 String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterc
hange shouldAnnotate, bool convertBlocksToInlines, EAbsoluteURLs shouldResolveUR
Ls, Node* constrainingAncestor) |
| 632 { | 631 { |
| 633 if (!range) | 632 if (!range) |
| 634 return emptyString(); | 633 return emptyString(); |
| 635 | 634 |
| 636 Document* document = range->ownerDocument(); | 635 Document& document = range->ownerDocument(); |
| 637 if (!document) | |
| 638 return emptyString(); | |
| 639 | |
| 640 const Range* updatedRange = range; | 636 const Range* updatedRange = range; |
| 641 | 637 |
| 642 return createMarkupInternal(document, range, updatedRange, nodes, shouldAnno
tate, convertBlocksToInlines, shouldResolveURLs, constrainingAncestor); | 638 return createMarkupInternal(document, range, updatedRange, nodes, shouldAnno
tate, convertBlocksToInlines, shouldResolveURLs, constrainingAncestor); |
| 643 } | 639 } |
| 644 | 640 |
| 645 PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document* document, const
String& markup, const String& baseURL, ParserContentPolicy parserContentPolicy) | 641 PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document* document, const
String& markup, const String& baseURL, ParserContentPolicy parserContentPolicy) |
| 646 { | 642 { |
| 647 ASSERT(document); | 643 ASSERT(document); |
| 648 // We use a fake body element here to trick the HTML parser to using the InB
ody insertion mode. | 644 // We use a fake body element here to trick the HTML parser to using the InB
ody insertion mode. |
| 649 RefPtr<HTMLBodyElement> fakeBody = HTMLBodyElement::create(*document); | 645 RefPtr<HTMLBodyElement> fakeBody = HTMLBodyElement::create(*document); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 711 RefPtr<DocumentFragment> taggedFragment = createFragmentFromMarkup(document,
taggedMarkup.toString(), baseURL, parserContentPolicy); | 707 RefPtr<DocumentFragment> taggedFragment = createFragmentFromMarkup(document,
taggedMarkup.toString(), baseURL, parserContentPolicy); |
| 712 RefPtr<Document> taggedDocument = Document::create(); | 708 RefPtr<Document> taggedDocument = Document::create(); |
| 713 taggedDocument->setContextFeatures(document->contextFeatures()); | 709 taggedDocument->setContextFeatures(document->contextFeatures()); |
| 714 taggedDocument->takeAllChildrenFrom(taggedFragment.get()); | 710 taggedDocument->takeAllChildrenFrom(taggedFragment.get()); |
| 715 | 711 |
| 716 RefPtr<Node> nodeBeforeContext; | 712 RefPtr<Node> nodeBeforeContext; |
| 717 RefPtr<Node> nodeAfterContext; | 713 RefPtr<Node> nodeAfterContext; |
| 718 if (!findNodesSurroundingContext(taggedDocument.get(), nodeBeforeContext, no
deAfterContext)) | 714 if (!findNodesSurroundingContext(taggedDocument.get(), nodeBeforeContext, no
deAfterContext)) |
| 719 return 0; | 715 return 0; |
| 720 | 716 |
| 721 RefPtr<Range> range = Range::create(taggedDocument.get(), | 717 RefPtr<Range> range = Range::create(*taggedDocument.get(), |
| 722 positionAfterNode(nodeBeforeContext.get()).parentAnchoredEquivalent(), | 718 positionAfterNode(nodeBeforeContext.get()).parentAnchoredEquivalent(), |
| 723 positionBeforeNode(nodeAfterContext.get()).parentAnchoredEquivalent()); | 719 positionBeforeNode(nodeAfterContext.get()).parentAnchoredEquivalent()); |
| 724 | 720 |
| 725 Node* commonAncestor = range->commonAncestorContainer(ASSERT_NO_EXCEPTION); | 721 Node* commonAncestor = range->commonAncestorContainer(ASSERT_NO_EXCEPTION); |
| 726 Node* specialCommonAncestor = ancestorToRetainStructureAndAppearanceWithNoRe
nderer(commonAncestor); | 722 Node* specialCommonAncestor = ancestorToRetainStructureAndAppearanceWithNoRe
nderer(commonAncestor); |
| 727 | 723 |
| 728 // When there's a special common ancestor outside of the fragment, we must i
nclude it as well to | 724 // When there's a special common ancestor outside of the fragment, we must i
nclude it as well to |
| 729 // preserve the structure and appearance of the fragment. For example, if th
e fragment contains | 725 // preserve the structure and appearance of the fragment. For example, if th
e fragment contains |
| 730 // TD, we need to include the enclosing TABLE tag as well. | 726 // TD, we need to include the enclosing TABLE tag as well. |
| 731 RefPtr<DocumentFragment> fragment = DocumentFragment::create(document); | 727 RefPtr<DocumentFragment> fragment = DocumentFragment::create(document); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 812 } | 808 } |
| 813 | 809 |
| 814 return false; | 810 return false; |
| 815 } | 811 } |
| 816 | 812 |
| 817 PassRefPtr<DocumentFragment> createFragmentFromText(Range* context, const String
& text) | 813 PassRefPtr<DocumentFragment> createFragmentFromText(Range* context, const String
& text) |
| 818 { | 814 { |
| 819 if (!context) | 815 if (!context) |
| 820 return 0; | 816 return 0; |
| 821 | 817 |
| 822 Document& document = *context->ownerDocument(); | 818 Document& document = context->ownerDocument(); |
| 823 RefPtr<DocumentFragment> fragment = document.createDocumentFragment(); | 819 RefPtr<DocumentFragment> fragment = document.createDocumentFragment(); |
| 824 | 820 |
| 825 if (text.isEmpty()) | 821 if (text.isEmpty()) |
| 826 return fragment.release(); | 822 return fragment.release(); |
| 827 | 823 |
| 828 String string = text; | 824 String string = text; |
| 829 string.replace("\r\n", "\n"); | 825 string.replace("\r\n", "\n"); |
| 830 string.replace('\r', '\n'); | 826 string.replace('\r', '\n'); |
| 831 | 827 |
| 832 if (shouldPreserveNewline(*context)) { | 828 if (shouldPreserveNewline(*context)) { |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1073 if (containerNode->hasOneChild()) { | 1069 if (containerNode->hasOneChild()) { |
| 1074 containerNode->replaceChild(textNode.release(), containerNode->firstChil
d(), es); | 1070 containerNode->replaceChild(textNode.release(), containerNode->firstChil
d(), es); |
| 1075 return; | 1071 return; |
| 1076 } | 1072 } |
| 1077 | 1073 |
| 1078 containerNode->removeChildren(); | 1074 containerNode->removeChildren(); |
| 1079 containerNode->appendChild(textNode.release(), es); | 1075 containerNode->appendChild(textNode.release(), es); |
| 1080 } | 1076 } |
| 1081 | 1077 |
| 1082 } | 1078 } |
| OLD | NEW |