| 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 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 : MarkupAccumulator(nodes, shouldResolveURLs, range) | 162 : MarkupAccumulator(nodes, shouldResolveURLs, range) |
| 163 , m_shouldAnnotate(shouldAnnotate) | 163 , m_shouldAnnotate(shouldAnnotate) |
| 164 , m_highestNodeToBeSerialized(highestNodeToBeSerialized) | 164 , m_highestNodeToBeSerialized(highestNodeToBeSerialized) |
| 165 { | 165 { |
| 166 } | 166 } |
| 167 | 167 |
| 168 void StyledMarkupAccumulator::wrapWithNode(Node* node, bool convertBlocksToInlin
es, RangeFullySelectsNode rangeFullySelectsNode) | 168 void StyledMarkupAccumulator::wrapWithNode(Node* node, bool convertBlocksToInlin
es, RangeFullySelectsNode rangeFullySelectsNode) |
| 169 { | 169 { |
| 170 StringBuilder markup; | 170 StringBuilder markup; |
| 171 if (node->isElementNode()) | 171 if (node->isElementNode()) |
| 172 appendElement(markup, adoptRawResult(toElement(node)), convertBlocksToIn
lines && isBlock(const_cast<Node*>(node)), rangeFullySelectsNode); | 172 appendElement(markup, adoptRawResult(toElement(node)), convertBlocksToIn
lines && isBlock(adoptRawResult(const_cast<Node*>(node))), rangeFullySelectsNode
); |
| 173 else | 173 else |
| 174 appendStartMarkup(markup, node, 0); | 174 appendStartMarkup(markup, node, 0); |
| 175 m_reversedPrecedingMarkup.append(markup.toString()); | 175 m_reversedPrecedingMarkup.append(markup.toString()); |
| 176 appendEndTag(node); | 176 appendEndTag(node); |
| 177 if (m_nodes) | 177 if (m_nodes) |
| 178 m_nodes->append(node); | 178 m_nodes->append(node); |
| 179 } | 179 } |
| 180 | 180 |
| 181 void StyledMarkupAccumulator::wrapWithStyleNode(const Handle<StylePropertySet>&
style, const Handle<Document>& document, bool isBlock) | 181 void StyledMarkupAccumulator::wrapWithStyleNode(const Handle<StylePropertySet>&
style, const Handle<Document>& document, bool isBlock) |
| 182 { | 182 { |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 360 // past pastEnd and become null here. This shouldn't be possible. | 360 // past pastEnd and become null here. This shouldn't be possible. |
| 361 // This null check will prevent crashes (but create too much markup) | 361 // This null check will prevent crashes (but create too much markup) |
| 362 // and the ASSERT will hopefully lead us to understanding the problem. | 362 // and the ASSERT will hopefully lead us to understanding the problem. |
| 363 ASSERT(n); | 363 ASSERT(n); |
| 364 if (!n) | 364 if (!n) |
| 365 break; | 365 break; |
| 366 | 366 |
| 367 next = NodeTraversal::next(n); | 367 next = NodeTraversal::next(n); |
| 368 bool openedTag = false; | 368 bool openedTag = false; |
| 369 | 369 |
| 370 if (isBlock(n.raw()) && canHaveChildrenForEditing(n.raw()) && next == pa
stEnd) | 370 if (isBlock(n) && canHaveChildrenForEditing(n) && next == pastEnd) |
| 371 // Don't write out empty block containers that aren't fully selected
. | 371 // Don't write out empty block containers that aren't fully selected
. |
| 372 continue; | 372 continue; |
| 373 | 373 |
| 374 if (!n->renderer() && !enclosingNodeWithTag(firstPositionInOrBeforeNode(
n.raw()), selectTag)) { | 374 if (!n->renderer() && !enclosingNodeWithTag(firstPositionInOrBeforeNode(
n), selectTag)) { |
| 375 next = NodeTraversal::nextSkippingChildren(n); | 375 next = NodeTraversal::nextSkippingChildren(n); |
| 376 // Don't skip over pastEnd. | 376 // Don't skip over pastEnd. |
| 377 if (pastEnd && pastEnd->isDescendantOf(n.raw())) | 377 if (pastEnd && pastEnd->isDescendantOf(n.raw())) |
| 378 next = adoptRawResult(pastEnd); | 378 next = adoptRawResult(pastEnd); |
| 379 } else { | 379 } else { |
| 380 // Add the node to the markup if we're not skipping the descendants | 380 // Add the node to the markup if we're not skipping the descendants |
| 381 if (shouldEmit) | 381 if (shouldEmit) |
| 382 appendStartTag(n.raw()); | 382 appendStartTag(n.raw()); |
| 383 | 383 |
| 384 // If node has no children, close the tag now. | 384 // If node has no children, close the tag now. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 421 wrapWithNode(parent.raw()); | 421 wrapWithNode(parent.raw()); |
| 422 lastClosed = parent; | 422 lastClosed = parent; |
| 423 } | 423 } |
| 424 } | 424 } |
| 425 } | 425 } |
| 426 } | 426 } |
| 427 | 427 |
| 428 return lastClosed.raw(); | 428 return lastClosed.raw(); |
| 429 } | 429 } |
| 430 | 430 |
| 431 static bool isHTMLBlockElement(const Node* node) | 431 static bool isHTMLBlockElement(const Handle<const Node>& node) |
| 432 { | 432 { |
| 433 return node->hasTagName(tdTag) | 433 return node->hasTagName(tdTag) |
| 434 || node->hasTagName(thTag) | 434 || node->hasTagName(thTag) |
| 435 || isNonTableCellHTMLBlockElement(node); | 435 || isNonTableCellHTMLBlockElement(node); |
| 436 } | 436 } |
| 437 | 437 |
| 438 static Node* ancestorToRetainStructureAndAppearanceForBlock(Node* commonAncestor
Block) | 438 static Result<Node> ancestorToRetainStructureAndAppearanceForBlock(const Handle<
Node>& commonAncestorBlock) |
| 439 { | 439 { |
| 440 if (!commonAncestorBlock) | 440 if (!commonAncestorBlock) |
| 441 return 0; | 441 return nullptr; |
| 442 | 442 |
| 443 if (commonAncestorBlock->hasTagName(tbodyTag) || commonAncestorBlock->hasTag
Name(trTag)) { | 443 if (commonAncestorBlock->hasTagName(tbodyTag) || commonAncestorBlock->hasTag
Name(trTag)) { |
| 444 Handle<ContainerNode> table = commonAncestorBlock->parentNode(); | 444 Handle<ContainerNode> table = commonAncestorBlock->parentNode(); |
| 445 while (table && !table->hasTagName(tableTag)) | 445 while (table && !table->hasTagName(tableTag)) { |
| 446 NoHandleScope scope; |
| 446 table = table->parentNode(); | 447 table = table->parentNode(); |
| 448 } |
| 447 | 449 |
| 448 return table.raw(); | 450 return table; |
| 449 } | 451 } |
| 450 | 452 |
| 451 if (isNonTableCellHTMLBlockElement(commonAncestorBlock)) | 453 if (isNonTableCellHTMLBlockElement(commonAncestorBlock)) |
| 452 return commonAncestorBlock; | 454 return commonAncestorBlock; |
| 453 | 455 |
| 454 return 0; | 456 return nullptr; |
| 455 } | 457 } |
| 456 | 458 |
| 457 static inline Node* ancestorToRetainStructureAndAppearance(Node* commonAncestor) | 459 static inline Result<Node> ancestorToRetainStructureAndAppearance(const Handle<N
ode>& commonAncestor) |
| 458 { | 460 { |
| 459 return ancestorToRetainStructureAndAppearanceForBlock(enclosingBlock(commonA
ncestor).handle().raw()); | 461 return ancestorToRetainStructureAndAppearanceForBlock(enclosingBlock(commonA
ncestor)); |
| 460 } | 462 } |
| 461 | 463 |
| 462 static inline Node* ancestorToRetainStructureAndAppearanceWithNoRenderer(Node* c
ommonAncestor) | 464 static inline Result<Node> ancestorToRetainStructureAndAppearanceWithNoRenderer(
const Handle<Node>& commonAncestor) |
| 463 { | 465 { |
| 464 Node* commonAncestorBlock = enclosingNodeOfType(firstPositionInOrBeforeNode(
commonAncestor), isHTMLBlockElement); | 466 Handle<Node> commonAncestorBlock = enclosingNodeOfType(firstPositionInOrBefo
reNode(commonAncestor), isHTMLBlockElement); |
| 465 return ancestorToRetainStructureAndAppearanceForBlock(commonAncestorBlock); | 467 return ancestorToRetainStructureAndAppearanceForBlock(commonAncestorBlock); |
| 466 } | 468 } |
| 467 | 469 |
| 468 static bool propertyMissingOrEqualToNone(const Handle<StylePropertySet>& style,
CSSPropertyID propertyID) | 470 static bool propertyMissingOrEqualToNone(const Handle<StylePropertySet>& style,
CSSPropertyID propertyID) |
| 469 { | 471 { |
| 470 if (!style) | 472 if (!style) |
| 471 return false; | 473 return false; |
| 472 Handle<CSSValue> value = style->getPropertyCSSValue(propertyID); | 474 Handle<CSSValue> value = style->getPropertyCSSValue(propertyID); |
| 473 if (!value) | 475 if (!value) |
| 474 return true; | 476 return true; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 492 return 0; | 494 return 0; |
| 493 | 495 |
| 494 // FIXME: Having to const_cast here is ugly, but it is quite a bit of work t
o untangle | 496 // FIXME: Having to const_cast here is ugly, but it is quite a bit of work t
o untangle |
| 495 // the non-const-ness of styleFromMatchedRulesForElement. | 497 // the non-const-ness of styleFromMatchedRulesForElement. |
| 496 Handle<HTMLElement> element = toHTMLElement(Handle<Node>::constCast(adoptRaw
Result(node))); | 498 Handle<HTMLElement> element = toHTMLElement(Handle<Node>::constCast(adoptRaw
Result(node))); |
| 497 RefPtr<EditingStyle> style = EditingStyle::createFromPropertySet(element->in
lineStyle()); | 499 RefPtr<EditingStyle> style = EditingStyle::createFromPropertySet(element->in
lineStyle()); |
| 498 style->mergeStyleFromRules(element); | 500 style->mergeStyleFromRules(element); |
| 499 return style.release(); | 501 return style.release(); |
| 500 } | 502 } |
| 501 | 503 |
| 502 static bool isElementPresentational(const Node* node) | 504 static bool isElementPresentational(const Handle<const Node>& node) |
| 503 { | 505 { |
| 504 return node->hasTagName(uTag) || node->hasTagName(sTag) || node->hasTagName(
strikeTag) | 506 return node->hasTagName(uTag) || node->hasTagName(sTag) || node->hasTagName(
strikeTag) |
| 505 || node->hasTagName(iTag) || node->hasTagName(emTag) || node->hasTagName
(bTag) || node->hasTagName(strongTag); | 507 || node->hasTagName(iTag) || node->hasTagName(emTag) || node->hasTagName
(bTag) || node->hasTagName(strongTag); |
| 506 } | 508 } |
| 507 | 509 |
| 508 static Node* highestAncestorToWrapMarkup(const Handle<const Range>& range, EAnno
tateForInterchange shouldAnnotate, Node* constrainingAncestor) | 510 static Node* highestAncestorToWrapMarkup(const Handle<const Range>& range, EAnno
tateForInterchange shouldAnnotate, Node* constrainingAncestor) |
| 509 { | 511 { |
| 510 Handle<Node> commonAncestor = range->commonAncestorContainer(IGNORE_EXCEPTIO
N); | 512 Handle<Node> commonAncestor = range->commonAncestorContainer(IGNORE_EXCEPTIO
N); |
| 511 ASSERT(commonAncestor); | 513 ASSERT(commonAncestor); |
| 512 Handle<Node> specialCommonAncestor; | 514 Handle<Node> specialCommonAncestor; |
| 513 if (shouldAnnotate == AnnotateForInterchange) { | 515 if (shouldAnnotate == AnnotateForInterchange) { |
| 514 // Include ancestors that aren't completely inside the range but are req
uired to retain | 516 // Include ancestors that aren't completely inside the range but are req
uired to retain |
| 515 // the structure and appearance of the copied markup. | 517 // the structure and appearance of the copied markup. |
| 516 specialCommonAncestor = adoptRawResult(ancestorToRetainStructureAndAppea
rance(commonAncestor.raw())); | 518 specialCommonAncestor = ancestorToRetainStructureAndAppearance(commonAnc
estor); |
| 517 | 519 |
| 518 if (Node* parentListNode = enclosingNodeOfType(firstPositionInOrBeforeNo
de(range->firstNode().handle().raw()), isListItem)) { | 520 if (Handle<Node> parentListNode = enclosingNodeOfType(firstPositionInOrB
eforeNode(range->firstNode()), isListItem)) { |
| 519 if (WebCore::areRangesEqual(VisibleSelection::selectionFromContentsO
fNode(parentListNode).toNormalizedRange(), range)) { | 521 if (WebCore::areRangesEqual(VisibleSelection::selectionFromContentsO
fNode(parentListNode.raw()).toNormalizedRange(), range)) { |
| 520 specialCommonAncestor = parentListNode->parentNode(); | 522 specialCommonAncestor = parentListNode->parentNode(); |
| 521 while (specialCommonAncestor && !isListElement(specialCommonAnce
stor.raw())) { | 523 while (specialCommonAncestor && !isListElement(specialCommonAnce
stor)) { |
| 522 NoHandleScope scope; | 524 NoHandleScope scope; |
| 523 specialCommonAncestor = specialCommonAncestor->parentNode(); | 525 specialCommonAncestor = specialCommonAncestor->parentNode(); |
| 524 } | 526 } |
| 525 } | 527 } |
| 526 } | 528 } |
| 527 | 529 |
| 528 // Retain the Mail quote level by including all ancestor mail block quot
es. | 530 // Retain the Mail quote level by including all ancestor mail block quot
es. |
| 529 if (Handle<Node> highestMailBlockquote = adoptRawResult(highestEnclosing
NodeOfType(firstPositionInOrBeforeNode(range->firstNode().handle().raw()), isMai
lBlockquote, CanCrossEditingBoundary))) | 531 if (Handle<Node> highestMailBlockquote = highestEnclosingNodeOfType(firs
tPositionInOrBeforeNode(range->firstNode()), isMailBlockquote, CanCrossEditingBo
undary)) |
| 530 specialCommonAncestor = highestMailBlockquote; | 532 specialCommonAncestor = highestMailBlockquote; |
| 531 } | 533 } |
| 532 | 534 |
| 533 Handle<Node> checkAncestor = specialCommonAncestor ? specialCommonAncestor :
commonAncestor; | 535 Handle<Node> checkAncestor = specialCommonAncestor ? specialCommonAncestor :
commonAncestor; |
| 534 if (checkAncestor->renderer()) { | 536 if (checkAncestor->renderer()) { |
| 535 Handle<Node> newSpecialCommonAncestor = adoptRawResult(highestEnclosingN
odeOfType(firstPositionInNode(checkAncestor), &isElementPresentational, CanCross
EditingBoundary, constrainingAncestor)); | 537 Handle<Node> newSpecialCommonAncestor = highestEnclosingNodeOfType(first
PositionInNode(checkAncestor), &isElementPresentational, CanCrossEditingBoundary
, adoptRawResult(constrainingAncestor)); |
| 536 if (newSpecialCommonAncestor) | 538 if (newSpecialCommonAncestor) |
| 537 specialCommonAncestor = newSpecialCommonAncestor; | 539 specialCommonAncestor = newSpecialCommonAncestor; |
| 538 } | 540 } |
| 539 | 541 |
| 540 // If a single tab is selected, commonAncestor will be a text node inside a
tab span. | 542 // If a single tab is selected, commonAncestor will be a text node inside a
tab span. |
| 541 // If two or more tabs are selected, commonAncestor will be the tab span. | 543 // If two or more tabs are selected, commonAncestor will be the tab span. |
| 542 // In either case, if there is a specialCommonAncestor already, it will nece
ssarily be above | 544 // In either case, if there is a specialCommonAncestor already, it will nece
ssarily be above |
| 543 // any tab span that needs to be included. | 545 // any tab span that needs to be included. |
| 544 if (!specialCommonAncestor && isTabSpanTextNode(commonAncestor.raw())) | 546 if (!specialCommonAncestor && isTabSpanTextNode(commonAncestor)) |
| 545 specialCommonAncestor = commonAncestor->parentNode(); | 547 specialCommonAncestor = commonAncestor->parentNode(); |
| 546 if (!specialCommonAncestor && isTabSpanNode(commonAncestor.raw())) | 548 if (!specialCommonAncestor && isTabSpanNode(commonAncestor)) |
| 547 specialCommonAncestor = commonAncestor; | 549 specialCommonAncestor = commonAncestor; |
| 548 | 550 |
| 549 if (Handle<Node> enclosingAnchor = adoptRawResult(enclosingNodeWithTag(first
PositionInNode(specialCommonAncestor ? specialCommonAncestor : commonAncestor),
aTag))) | 551 if (Handle<Node> enclosingAnchor = enclosingNodeWithTag(firstPositionInNode(
specialCommonAncestor ? specialCommonAncestor : commonAncestor), aTag)) |
| 550 specialCommonAncestor = enclosingAnchor; | 552 specialCommonAncestor = enclosingAnchor; |
| 551 | 553 |
| 552 return specialCommonAncestor.raw(); | 554 return specialCommonAncestor.raw(); |
| 553 } | 555 } |
| 554 | 556 |
| 555 // FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForIntercha
nge? | 557 // FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForIntercha
nge? |
| 556 // FIXME: At least, annotation and style info should probably not be included in
range.markupString() | 558 // FIXME: At least, annotation and style info should probably not be included in
range.markupString() |
| 557 static String createMarkupInternal(const Handle<Document>& document, const Handl
e<const Range>& range, const Handle<const Range>& updatedRange, Vector<Node*>* n
odes, | 559 static String createMarkupInternal(const Handle<Document>& document, const Handl
e<const Range>& range, const Handle<const Range>& updatedRange, Vector<Node*>* n
odes, |
| 558 EAnnotateForInterchange shouldAnnotate, bool convertBlocksToInlines, EAbsolu
teURLs shouldResolveURLs, Node* constrainingAncestor) | 560 EAnnotateForInterchange shouldAnnotate, bool convertBlocksToInlines, EAbsolu
teURLs shouldResolveURLs, Node* constrainingAncestor) |
| 559 { | 561 { |
| 560 ASSERT(document); | 562 ASSERT(document); |
| 561 ASSERT(range); | 563 ASSERT(range); |
| 562 ASSERT(updatedRange); | 564 ASSERT(updatedRange); |
| 563 DEFINE_STATIC_LOCAL(const String, interchangeNewlineString, (ASCIILiteral("<
br class=\"" AppleInterchangeNewline "\">"))); | 565 DEFINE_STATIC_LOCAL(const String, interchangeNewlineString, (ASCIILiteral("<
br class=\"" AppleInterchangeNewline "\">"))); |
| 564 | 566 |
| 565 bool collapsed = updatedRange->collapsed(ASSERT_NO_EXCEPTION); | 567 bool collapsed = updatedRange->collapsed(ASSERT_NO_EXCEPTION); |
| 566 if (collapsed) | 568 if (collapsed) |
| 567 return emptyString(); | 569 return emptyString(); |
| 568 Handle<Node> commonAncestor = updatedRange->commonAncestorContainer(ASSERT_N
O_EXCEPTION); | 570 Handle<Node> commonAncestor = updatedRange->commonAncestorContainer(ASSERT_N
O_EXCEPTION); |
| 569 if (!commonAncestor) | 571 if (!commonAncestor) |
| 570 return emptyString(); | 572 return emptyString(); |
| 571 | 573 |
| 572 document->updateLayoutIgnorePendingStylesheets(); | 574 document->updateLayoutIgnorePendingStylesheets(); |
| 573 | 575 |
| 574 Node* body = enclosingNodeWithTag(firstPositionInNode(commonAncestor), bodyT
ag); | 576 Handle<Node> body = enclosingNodeWithTag(firstPositionInNode(commonAncestor)
, bodyTag); |
| 575 Node* fullySelectedRoot = 0; | 577 Handle<Node> fullySelectedRoot; |
| 576 // FIXME: Do this for all fully selected blocks, not just the body. | 578 // FIXME: Do this for all fully selected blocks, not just the body. |
| 577 if (body && areRangesEqual(VisibleSelection::selectionFromContentsOfNode(bod
y).toNormalizedRange(), range)) | 579 if (body && areRangesEqual(VisibleSelection::selectionFromContentsOfNode(bod
y.raw()).toNormalizedRange(), range)) |
| 578 fullySelectedRoot = body; | 580 fullySelectedRoot = body; |
| 579 Node* specialCommonAncestor = highestAncestorToWrapMarkup(updatedRange, shou
ldAnnotate, constrainingAncestor); | 581 Handle<Node> specialCommonAncestor = adoptRawResult(highestAncestorToWrapMar
kup(updatedRange, shouldAnnotate, constrainingAncestor)); |
| 580 StyledMarkupAccumulator accumulator(nodes, shouldResolveURLs, shouldAnnotate
, updatedRange, specialCommonAncestor); | 582 StyledMarkupAccumulator accumulator(nodes, shouldResolveURLs, shouldAnnotate
, updatedRange, specialCommonAncestor.raw()); |
| 581 Handle<Node> pastEnd = updatedRange->pastLastNode(); | 583 Handle<Node> pastEnd = updatedRange->pastLastNode(); |
| 582 | 584 |
| 583 Handle<Node> startNode = updatedRange->firstNode(); | 585 Handle<Node> startNode = updatedRange->firstNode(); |
| 584 VisiblePosition visibleStart(updatedRange->startPosition(), VP_DEFAULT_AFFIN
ITY); | 586 VisiblePosition visibleStart(updatedRange->startPosition(), VP_DEFAULT_AFFIN
ITY); |
| 585 VisiblePosition visibleEnd(updatedRange->endPosition(), VP_DEFAULT_AFFINITY)
; | 587 VisiblePosition visibleEnd(updatedRange->endPosition(), VP_DEFAULT_AFFINITY)
; |
| 586 if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(
visibleStart)) { | 588 if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(
visibleStart)) { |
| 587 if (visibleStart == visibleEnd.previous()) | 589 if (visibleStart == visibleEnd.previous()) |
| 588 return interchangeNewlineString; | 590 return interchangeNewlineString; |
| 589 | 591 |
| 590 accumulator.appendString(interchangeNewlineString); | 592 accumulator.appendString(interchangeNewlineString); |
| 591 startNode = visibleStart.next().deepEquivalent().deprecatedNode(); | 593 startNode = visibleStart.next().deepEquivalent().deprecatedNode(); |
| 592 | 594 |
| 593 if (pastEnd && Range::compareBoundaryPoints(startNode, 0, pastEnd, 0, AS
SERT_NO_EXCEPTION) >= 0) | 595 if (pastEnd && Range::compareBoundaryPoints(startNode, 0, pastEnd, 0, AS
SERT_NO_EXCEPTION) >= 0) |
| 594 return interchangeNewlineString; | 596 return interchangeNewlineString; |
| 595 } | 597 } |
| 596 | 598 |
| 597 Node* lastClosed = accumulator.serializeNodes(startNode.raw(), pastEnd.raw()
); | 599 Node* lastClosed = accumulator.serializeNodes(startNode.raw(), pastEnd.raw()
); |
| 598 | 600 |
| 599 if (specialCommonAncestor && lastClosed) { | 601 if (specialCommonAncestor && lastClosed) { |
| 600 HandleScope scope; | 602 HandleScope scope; |
| 601 // Also include all of the ancestors of lastClosed up to this special an
cestor. | 603 // Also include all of the ancestors of lastClosed up to this special an
cestor. |
| 602 for (Handle<ContainerNode> ancestor = lastClosed->parentNode(); ancestor
; ancestor = ancestor->parentNode()) { | 604 for (Handle<ContainerNode> ancestor = lastClosed->parentNode(); ancestor
; ancestor = ancestor->parentNode()) { |
| 603 HandleScope scope; | 605 HandleScope scope; |
| 604 if (ancestor == fullySelectedRoot && !convertBlocksToInlines) { | 606 if (ancestor == fullySelectedRoot && !convertBlocksToInlines) { |
| 605 RefPtr<EditingStyle> fullySelectedRootStyle = styleFromMatchedRu
lesAndInlineDecl(fullySelectedRoot); | 607 RefPtr<EditingStyle> fullySelectedRootStyle = styleFromMatchedRu
lesAndInlineDecl(fullySelectedRoot.raw()); |
| 606 | 608 |
| 607 // Bring the background attribute over, but not as an attribute
because a background attribute on a div | 609 // Bring the background attribute over, but not as an attribute
because a background attribute on a div |
| 608 // appears to have no effect. | 610 // appears to have no effect. |
| 609 if ((!fullySelectedRootStyle || !fullySelectedRootStyle->style()
|| !fullySelectedRootStyle->style()->getPropertyCSSValue(CSSPropertyBackgroundI
mage)) | 611 if ((!fullySelectedRootStyle || !fullySelectedRootStyle->style()
|| !fullySelectedRootStyle->style()->getPropertyCSSValue(CSSPropertyBackgroundI
mage)) |
| 610 && toElement(fullySelectedRoot)->hasAttribute(backgroundAttr
)) | 612 && toElement(fullySelectedRoot)->hasAttribute(backgroundAttr
)) |
| 611 fullySelectedRootStyle->style()->setProperty(CSSPropertyBack
groundImage, "url('" + toElement(fullySelectedRoot)->getAttribute(backgroundAttr
) + "')"); | 613 fullySelectedRootStyle->style()->setProperty(CSSPropertyBack
groundImage, "url('" + toElement(fullySelectedRoot)->getAttribute(backgroundAttr
) + "')"); |
| 612 | 614 |
| 613 if (fullySelectedRootStyle->style()) { | 615 if (fullySelectedRootStyle->style()) { |
| 614 // Reset the CSS properties to avoid an assertion error in a
ddStyleMarkup(). | 616 // Reset the CSS properties to avoid an assertion error in a
ddStyleMarkup(). |
| 615 // This assertion is caused at least when we select all text
of a <body> element whose | 617 // This assertion is caused at least when we select all text
of a <body> element whose |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 730 RefPtr<Node> nodeBeforeContext; | 732 RefPtr<Node> nodeBeforeContext; |
| 731 RefPtr<Node> nodeAfterContext; | 733 RefPtr<Node> nodeAfterContext; |
| 732 if (!findNodesSurroundingContext(taggedDocument, nodeBeforeContext, nodeAfte
rContext)) | 734 if (!findNodesSurroundingContext(taggedDocument, nodeBeforeContext, nodeAfte
rContext)) |
| 733 return nullptr; | 735 return nullptr; |
| 734 | 736 |
| 735 Handle<Range> range = Range::create(taggedDocument, | 737 Handle<Range> range = Range::create(taggedDocument, |
| 736 positionAfterNode(adoptRawResult(nodeBeforeContext.get())).parentAnchore
dEquivalent(), | 738 positionAfterNode(adoptRawResult(nodeBeforeContext.get())).parentAnchore
dEquivalent(), |
| 737 positionBeforeNode(adoptRawResult(nodeAfterContext.get())).parentAnchore
dEquivalent()); | 739 positionBeforeNode(adoptRawResult(nodeAfterContext.get())).parentAnchore
dEquivalent()); |
| 738 | 740 |
| 739 Handle<Node> commonAncestor = range->commonAncestorContainer(ASSERT_NO_EXCEP
TION); | 741 Handle<Node> commonAncestor = range->commonAncestorContainer(ASSERT_NO_EXCEP
TION); |
| 740 Node* specialCommonAncestor = ancestorToRetainStructureAndAppearanceWithNoRe
nderer(commonAncestor.raw()); | 742 Handle<Node> specialCommonAncestor = ancestorToRetainStructureAndAppearanceW
ithNoRenderer(commonAncestor); |
| 741 | 743 |
| 742 // When there's a special common ancestor outside of the fragment, we must i
nclude it as well to | 744 // When there's a special common ancestor outside of the fragment, we must i
nclude it as well to |
| 743 // preserve the structure and appearance of the fragment. For example, if th
e fragment contains | 745 // preserve the structure and appearance of the fragment. For example, if th
e fragment contains |
| 744 // TD, we need to include the enclosing TABLE tag as well. | 746 // TD, we need to include the enclosing TABLE tag as well. |
| 745 Handle<DocumentFragment> fragment = DocumentFragment::create(document); | 747 Handle<DocumentFragment> fragment = DocumentFragment::create(document); |
| 746 if (specialCommonAncestor) | 748 if (specialCommonAncestor) |
| 747 fragment->appendChild(adoptRawResult(specialCommonAncestor), ASSERT_NO_E
XCEPTION); | 749 fragment->appendChild(specialCommonAncestor, ASSERT_NO_EXCEPTION); |
| 748 else | 750 else |
| 749 fragment->takeAllChildrenFrom(toContainerNode(commonAncestor)); | 751 fragment->takeAllChildrenFrom(toContainerNode(commonAncestor)); |
| 750 | 752 |
| 751 trimFragment(fragment, nodeBeforeContext.get(), nodeAfterContext.get()); | 753 trimFragment(fragment, nodeBeforeContext.get(), nodeAfterContext.get()); |
| 752 | 754 |
| 753 return fragment; | 755 return fragment; |
| 754 } | 756 } |
| 755 | 757 |
| 756 String createMarkup(const Node* node, EChildrenOnly childrenOnly, Vector<Node*>*
nodes, EAbsoluteURLs shouldResolveURLs, Vector<QualifiedName>* tagNamesToSkip) | 758 String createMarkup(const Node* node, EChildrenOnly childrenOnly, Vector<Node*>*
nodes, EAbsoluteURLs shouldResolveURLs, Vector<QualifiedName>* tagNamesToSkip) |
| 757 { | 759 { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 804 } | 806 } |
| 805 | 807 |
| 806 bool isPlainTextMarkup(Node *node) | 808 bool isPlainTextMarkup(Node *node) |
| 807 { | 809 { |
| 808 if (!node->isElementNode() || !node->hasTagName(divTag) || toElement(node)->
hasAttributes()) | 810 if (!node->isElementNode() || !node->hasTagName(divTag) || toElement(node)->
hasAttributes()) |
| 809 return false; | 811 return false; |
| 810 | 812 |
| 811 if (node->childNodeCount() == 1 && (node->firstChild()->isTextNode() || (nod
e->firstChild()->firstChild()))) | 813 if (node->childNodeCount() == 1 && (node->firstChild()->isTextNode() || (nod
e->firstChild()->firstChild()))) |
| 812 return true; | 814 return true; |
| 813 | 815 |
| 814 return (node->childNodeCount() == 2 && isTabSpanTextNode(node->firstChild()-
>firstChild().handle().raw()) && node->firstChild()->nextSibling()->isTextNode()
); | 816 return (node->childNodeCount() == 2 && isTabSpanTextNode(node->firstChild()-
>firstChild()) && node->firstChild()->nextSibling()->isTextNode()); |
| 815 } | 817 } |
| 816 | 818 |
| 817 Result<DocumentFragment> createFragmentFromText(const Handle<Range>& context, co
nst String& text) | 819 Result<DocumentFragment> createFragmentFromText(const Handle<Range>& context, co
nst String& text) |
| 818 { | 820 { |
| 819 if (!context) | 821 if (!context) |
| 820 return nullptr; | 822 return nullptr; |
| 821 | 823 |
| 822 Handle<Node> styleNode = context->firstNode(); | 824 Handle<Node> styleNode = context->firstNode(); |
| 823 if (!styleNode) { | 825 if (!styleNode) { |
| 824 styleNode = context->startPosition().deprecatedNode(); | 826 styleNode = context->startPosition().deprecatedNode(); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 847 return fragment; | 849 return fragment; |
| 848 } | 850 } |
| 849 | 851 |
| 850 // A string with no newlines gets added inline, rather than being put into a
paragraph. | 852 // A string with no newlines gets added inline, rather than being put into a
paragraph. |
| 851 if (string.find('\n') == notFound) { | 853 if (string.find('\n') == notFound) { |
| 852 fillContainerFromString(fragment, string); | 854 fillContainerFromString(fragment, string); |
| 853 return fragment; | 855 return fragment; |
| 854 } | 856 } |
| 855 | 857 |
| 856 // Break string into paragraphs. Extra line breaks turn into empty paragraph
s. | 858 // Break string into paragraphs. Extra line breaks turn into empty paragraph
s. |
| 857 Handle<Node> blockNode = enclosingBlock(context->firstNode().handle().raw())
; | 859 Handle<Node> blockNode = enclosingBlock(context->firstNode()); |
| 858 Handle<Element> block = toElement(blockNode); | 860 Handle<Element> block = toElement(blockNode); |
| 859 bool useClonesOfEnclosingBlock = blockNode | 861 bool useClonesOfEnclosingBlock = blockNode |
| 860 && blockNode->isElementNode() | 862 && blockNode->isElementNode() |
| 861 && !block->hasTagName(bodyTag) | 863 && !block->hasTagName(bodyTag) |
| 862 && !block->hasTagName(htmlTag) | 864 && !block->hasTagName(htmlTag) |
| 863 && block != editableRootForPosition(context->startPosition()); | 865 && block != editableRootForPosition(context->startPosition()); |
| 864 bool useLineBreak = enclosingTextFormControl(context->startPosition()); | 866 bool useLineBreak = enclosingTextFormControl(context->startPosition()); |
| 865 | 867 |
| 866 Vector<String> list; | 868 Vector<String> list; |
| 867 string.split('\n', true, list); // true gets us empty strings in the list | 869 string.split('\n', true, list); // true gets us empty strings in the list |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1102 if (hasOneChild(containerNode)) { | 1104 if (hasOneChild(containerNode)) { |
| 1103 containerNode->replaceChild(textNode, containerNode->firstChild(), ec); | 1105 containerNode->replaceChild(textNode, containerNode->firstChild(), ec); |
| 1104 return; | 1106 return; |
| 1105 } | 1107 } |
| 1106 | 1108 |
| 1107 containerNode->removeChildren(); | 1109 containerNode->removeChildren(); |
| 1108 containerNode->appendChild(textNode, ec); | 1110 containerNode->appendChild(textNode, ec); |
| 1109 } | 1111 } |
| 1110 | 1112 |
| 1111 } | 1113 } |
| OLD | NEW |