| 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 29 matching lines...) Expand all Loading... |
| 40 #include "core/editing/iterators/TextIterator.h" | 40 #include "core/editing/iterators/TextIterator.h" |
| 41 #include "core/editing/markup.h" | 41 #include "core/editing/markup.h" |
| 42 #include "core/html/HTMLBodyElement.h" | 42 #include "core/html/HTMLBodyElement.h" |
| 43 #include "core/html/HTMLElement.h" | 43 #include "core/html/HTMLElement.h" |
| 44 #include "wtf/text/StringBuilder.h" | 44 #include "wtf/text/StringBuilder.h" |
| 45 | 45 |
| 46 namespace blink { | 46 namespace blink { |
| 47 | 47 |
| 48 namespace { | 48 namespace { |
| 49 | 49 |
| 50 const String& styleNodeCloseTag(bool isBlock) | |
| 51 { | |
| 52 DEFINE_STATIC_LOCAL(const String, divClose, ("</div>")); | |
| 53 DEFINE_STATIC_LOCAL(const String, styleSpanClose, ("</span>")); | |
| 54 return isBlock ? divClose : styleSpanClose; | |
| 55 } | |
| 56 | |
| 57 template<typename PositionType> | 50 template<typename PositionType> |
| 58 TextOffset toTextOffset(const PositionType& position) | 51 TextOffset toTextOffset(const PositionType& position) |
| 59 { | 52 { |
| 60 if (position.isNull()) | 53 if (position.isNull()) |
| 61 return TextOffset(); | 54 return TextOffset(); |
| 62 | 55 |
| 63 if (!position.containerNode()->isTextNode()) | 56 if (!position.containerNode()->isTextNode()) |
| 64 return TextOffset(); | 57 return TextOffset(); |
| 65 | 58 |
| 66 return TextOffset(toText(position.containerNode()), position.offsetInContain
erNode()); | 59 return TextOffset(toText(position.containerNode()), position.offsetInContain
erNode()); |
| 67 } | 60 } |
| 68 | 61 |
| 69 } // namespace | 62 } // namespace |
| 70 | 63 |
| 71 using namespace HTMLNames; | 64 using namespace HTMLNames; |
| 72 | 65 |
| 73 static Position toPositionInDOMTree(const Position& position) | 66 static Position toPositionInDOMTree(const Position& position) |
| 74 { | 67 { |
| 75 return position; | 68 return position; |
| 76 } | 69 } |
| 77 | 70 |
| 78 template<typename Strategy> | 71 template<typename Strategy> |
| 79 StyledMarkupSerializer<Strategy>::StyledMarkupSerializer(EAbsoluteURLs shouldRes
olveURLs, EAnnotateForInterchange shouldAnnotate, const PositionType& start, con
st PositionType& end, Node* highestNodeToBeSerialized, ConvertBlocksToInlines co
nvertBlocksToInlines) | 72 StyledMarkupSerializer<Strategy>::StyledMarkupSerializer(EAbsoluteURLs shouldRes
olveURLs, EAnnotateForInterchange shouldAnnotate, const PositionType& start, con
st PositionType& end, Node* highestNodeToBeSerialized, ConvertBlocksToInlines co
nvertBlocksToInlines) |
| 80 : m_markupAccumulator(shouldResolveURLs, toTextOffset(start.parentAnchoredEq
uivalent()), toTextOffset(end.parentAnchoredEquivalent()), start.document(), sho
uldAnnotate, highestNodeToBeSerialized) | 73 : m_markupAccumulator(shouldResolveURLs, toTextOffset(start.parentAnchoredEq
uivalent()), toTextOffset(end.parentAnchoredEquivalent()), start.document(), sho
uldAnnotate, highestNodeToBeSerialized, convertBlocksToInlines) |
| 81 , m_start(start) | 74 , m_start(start) |
| 82 , m_end(end) | 75 , m_end(end) |
| 83 , m_shouldAnnotate(shouldAnnotate) | 76 , m_shouldAnnotate(shouldAnnotate) |
| 84 , m_highestNodeToBeSerialized(highestNodeToBeSerialized) | 77 , m_highestNodeToBeSerialized(highestNodeToBeSerialized) |
| 85 , m_convertBlocksToInlines(convertBlocksToInlines) | |
| 86 { | 78 { |
| 87 } | 79 } |
| 88 | 80 |
| 89 static bool needInterchangeNewlineAfter(const VisiblePosition& v) | 81 static bool needInterchangeNewlineAfter(const VisiblePosition& v) |
| 90 { | 82 { |
| 91 VisiblePosition next = v.next(); | 83 VisiblePosition next = v.next(); |
| 92 Node* upstreamNode = next.deepEquivalent().upstream().deprecatedNode(); | 84 Node* upstreamNode = next.deepEquivalent().upstream().deprecatedNode(); |
| 93 Node* downstreamNode = v.deepEquivalent().downstream().deprecatedNode(); | 85 Node* downstreamNode = v.deepEquivalent().downstream().deprecatedNode(); |
| 94 // Add an interchange newline if a paragraph break is selected and a br won'
t already be added to the markup to represent it. | 86 // Add an interchange newline if a paragraph break is selected and a br won'
t already be added to the markup to represent it. |
| 95 return isEndOfParagraph(v) && isStartOfParagraph(next) && !(isHTMLBRElement(
*upstreamNode) && upstreamNode == downstreamNode); | 87 return isEndOfParagraph(v) && isStartOfParagraph(next) && !(isHTMLBRElement(
*upstreamNode) && upstreamNode == downstreamNode); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 ASSERT(commonAncestor); | 144 ASSERT(commonAncestor); |
| 153 HTMLBodyElement* body = toHTMLBodyElement(enclosingElementWithTag(firstP
ositionInNode(commonAncestor), bodyTag)); | 145 HTMLBodyElement* body = toHTMLBodyElement(enclosingElementWithTag(firstP
ositionInNode(commonAncestor), bodyTag)); |
| 154 HTMLBodyElement* fullySelectedRoot = nullptr; | 146 HTMLBodyElement* fullySelectedRoot = nullptr; |
| 155 // FIXME: Do this for all fully selected blocks, not just the body. | 147 // FIXME: Do this for all fully selected blocks, not just the body. |
| 156 if (body && areSameRanges(body, m_start, m_end)) | 148 if (body && areSameRanges(body, m_start, m_end)) |
| 157 fullySelectedRoot = body; | 149 fullySelectedRoot = body; |
| 158 | 150 |
| 159 // Also include all of the ancestors of lastClosed up to this special an
cestor. | 151 // Also include all of the ancestors of lastClosed up to this special an
cestor. |
| 160 // FIXME: What is ancestor? | 152 // FIXME: What is ancestor? |
| 161 for (ContainerNode* ancestor = Strategy::parent(*lastClosed); ancestor;
ancestor = Strategy::parent(*ancestor)) { | 153 for (ContainerNode* ancestor = Strategy::parent(*lastClosed); ancestor;
ancestor = Strategy::parent(*ancestor)) { |
| 162 if (ancestor == fullySelectedRoot && !convertBlocksToInlines()) { | 154 if (ancestor == fullySelectedRoot && !m_markupAccumulator.convertBlo
cksToInlines()) { |
| 163 RefPtrWillBeRawPtr<EditingStyle> fullySelectedRootStyle = styleF
romMatchedRulesAndInlineDecl(fullySelectedRoot); | 155 RefPtrWillBeRawPtr<EditingStyle> fullySelectedRootStyle = styleF
romMatchedRulesAndInlineDecl(fullySelectedRoot); |
| 164 | 156 |
| 165 // Bring the background attribute over, but not as an attribute
because a background attribute on a div | 157 // Bring the background attribute over, but not as an attribute
because a background attribute on a div |
| 166 // appears to have no effect. | 158 // appears to have no effect. |
| 167 if ((!fullySelectedRootStyle || !fullySelectedRootStyle->style()
|| !fullySelectedRootStyle->style()->getPropertyCSSValue(CSSPropertyBackgroundI
mage)) | 159 if ((!fullySelectedRootStyle || !fullySelectedRootStyle->style()
|| !fullySelectedRootStyle->style()->getPropertyCSSValue(CSSPropertyBackgroundI
mage)) |
| 168 && fullySelectedRoot->hasAttribute(backgroundAttr)) | 160 && fullySelectedRoot->hasAttribute(backgroundAttr)) |
| 169 fullySelectedRootStyle->style()->setProperty(CSSPropertyBack
groundImage, "url('" + fullySelectedRoot->getAttribute(backgroundAttr) + "')"); | 161 fullySelectedRootStyle->style()->setProperty(CSSPropertyBack
groundImage, "url('" + fullySelectedRoot->getAttribute(backgroundAttr) + "')"); |
| 170 | 162 |
| 171 if (fullySelectedRootStyle->style()) { | 163 if (fullySelectedRootStyle->style()) { |
| 172 // Reset the CSS properties to avoid an assertion error in a
ddStyleMarkup(). | 164 // Reset the CSS properties to avoid an assertion error in a
ddStyleMarkup(). |
| 173 // This assertion is caused at least when we select all text
of a <body> element whose | 165 // This assertion is caused at least when we select all text
of a <body> element whose |
| 174 // 'text-decoration' property is "inherit", and copy it. | 166 // 'text-decoration' property is "inherit", and copy it. |
| 175 if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->st
yle(), CSSPropertyTextDecoration)) | 167 if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->st
yle(), CSSPropertyTextDecoration)) |
| 176 fullySelectedRootStyle->style()->setProperty(CSSProperty
TextDecoration, CSSValueNone); | 168 fullySelectedRootStyle->style()->setProperty(CSSProperty
TextDecoration, CSSValueNone); |
| 177 if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->st
yle(), CSSPropertyWebkitTextDecorationsInEffect)) | 169 if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->st
yle(), CSSPropertyWebkitTextDecorationsInEffect)) |
| 178 fullySelectedRootStyle->style()->setProperty(CSSProperty
WebkitTextDecorationsInEffect, CSSValueNone); | 170 fullySelectedRootStyle->style()->setProperty(CSSProperty
WebkitTextDecorationsInEffect, CSSValueNone); |
| 179 wrapWithStyleNode(fullySelectedRootStyle->style(), true); | 171 m_markupAccumulator.wrapWithStyleNode(fullySelectedRootStyle
->style(), true); |
| 180 } | 172 } |
| 181 } else { | 173 } else { |
| 182 // Since this node and all the other ancestors are not in the se
lection we want to set RangeFullySelectsNode to DoesNotFullySelectNode | 174 // Since this node and all the other ancestors are not in the se
lection we want to set RangeFullySelectsNode to DoesNotFullySelectNode |
| 183 // so that styles that affect the exterior of the node are not i
ncluded. | 175 // so that styles that affect the exterior of the node are not i
ncluded. |
| 184 wrapWithNode(*ancestor, StyledMarkupAccumulator::DoesNotFullySel
ectNode); | 176 m_markupAccumulator.wrapWithNode(*ancestor, StyledMarkupAccumula
tor::DoesNotFullySelectNode); |
| 185 } | 177 } |
| 186 | 178 |
| 187 if (ancestor == m_highestNodeToBeSerialized) | 179 if (ancestor == m_highestNodeToBeSerialized) |
| 188 break; | 180 break; |
| 189 } | 181 } |
| 190 } | 182 } |
| 191 | 183 |
| 192 // FIXME: The interchange newline should be placed in the block that it's in
, not after all of the content, unconditionally. | 184 // FIXME: The interchange newline should be placed in the block that it's in
, not after all of the content, unconditionally. |
| 193 if (m_shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAt(v
isibleEnd)) | 185 if (m_shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAt(v
isibleEnd)) |
| 194 m_markupAccumulator.appendString(interchangeNewlineString); | 186 m_markupAccumulator.appendString(interchangeNewlineString); |
| 195 | 187 |
| 196 return takeResults(); | 188 return m_markupAccumulator.takeResults(); |
| 197 } | 189 } |
| 198 | 190 |
| 199 template<typename Strategy> | 191 template<typename Strategy> |
| 200 void StyledMarkupSerializer<Strategy>::wrapWithNode(ContainerNode& node, typenam
e StyledMarkupAccumulator::RangeFullySelectsNode rangeFullySelectsNode) | |
| 201 { | |
| 202 StringBuilder markup; | |
| 203 if (node.isElementNode()) | |
| 204 m_markupAccumulator.appendElement(markup, toElement(node), convertBlocks
ToInlines() && isBlock(&node), rangeFullySelectsNode); | |
| 205 else | |
| 206 m_markupAccumulator.appendStartMarkup(markup, node); | |
| 207 m_reversedPrecedingMarkup.append(markup.toString()); | |
| 208 if (node.isElementNode()) | |
| 209 m_markupAccumulator.appendEndTag(toElement(node)); | |
| 210 } | |
| 211 | |
| 212 template<typename Strategy> | |
| 213 void StyledMarkupSerializer<Strategy>::wrapWithStyleNode(StylePropertySet* style
, bool isBlock) | |
| 214 { | |
| 215 StringBuilder openTag; | |
| 216 m_markupAccumulator.appendStyleNodeOpenTag(openTag, style, isBlock); | |
| 217 m_reversedPrecedingMarkup.append(openTag.toString()); | |
| 218 m_markupAccumulator.appendString(styleNodeCloseTag(isBlock)); | |
| 219 } | |
| 220 | |
| 221 template<typename Strategy> | |
| 222 String StyledMarkupSerializer<Strategy>::takeResults() | |
| 223 { | |
| 224 StringBuilder result; | |
| 225 result.reserveCapacity(MarkupAccumulator::totalLength(m_reversedPrecedingMar
kup) + m_markupAccumulator.length()); | |
| 226 | |
| 227 for (size_t i = m_reversedPrecedingMarkup.size(); i > 0; --i) | |
| 228 result.append(m_reversedPrecedingMarkup[i - 1]); | |
| 229 | |
| 230 m_markupAccumulator.concatenateMarkup(result); | |
| 231 | |
| 232 // We remove '\0' characters because they are not visibly rendered to the us
er. | |
| 233 return result.toString().replace(0, ""); | |
| 234 } | |
| 235 | |
| 236 template<typename Strategy> | |
| 237 Node* StyledMarkupSerializer<Strategy>::serializeNodes(Node* startNode, Node* pa
stEnd) | 192 Node* StyledMarkupSerializer<Strategy>::serializeNodes(Node* startNode, Node* pa
stEnd) |
| 238 { | 193 { |
| 239 if (!m_markupAccumulator.highestNodeToBeSerialized()) { | 194 if (!m_markupAccumulator.highestNodeToBeSerialized()) { |
| 240 Node* lastClosed = traverseNodesForSerialization(startNode, pastEnd, Nod
eTraversalMode::DoNotEmitString); | 195 Node* lastClosed = traverseNodesForSerialization(startNode, pastEnd, Nod
eTraversalMode::DoNotEmitString); |
| 241 m_markupAccumulator.setHighestNodeToBeSerialized(lastClosed); | 196 m_markupAccumulator.setHighestNodeToBeSerialized(lastClosed); |
| 242 } | 197 } |
| 243 | 198 |
| 244 Node* highestNodeToBeSerialized = m_markupAccumulator.highestNodeToBeSeriali
zed(); | 199 Node* highestNodeToBeSerialized = m_markupAccumulator.highestNodeToBeSeriali
zed(); |
| 245 if (highestNodeToBeSerialized && Strategy::parent(*highestNodeToBeSerialized
)) { | 200 if (highestNodeToBeSerialized && Strategy::parent(*highestNodeToBeSerialized
)) { |
| 246 bool shouldAnnotate = m_shouldAnnotate == AnnotateForInterchange; | 201 bool shouldAnnotate = m_shouldAnnotate == AnnotateForInterchange; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 ASSERT(n); | 274 ASSERT(n); |
| 320 Node* lastAncestorClosedOrSelf = Strategy::isDescendantOf(*n, *lastClose
d) ? lastClosed : n; | 275 Node* lastAncestorClosedOrSelf = Strategy::isDescendantOf(*n, *lastClose
d) ? lastClosed : n; |
| 321 for (ContainerNode* parent = Strategy::parent(*lastAncestorClosedOrSelf)
; parent && parent != nextParent; parent = Strategy::parent(*parent)) { | 276 for (ContainerNode* parent = Strategy::parent(*lastAncestorClosedOrSelf)
; parent && parent != nextParent; parent = Strategy::parent(*parent)) { |
| 322 // All ancestors that aren't in the ancestorsToClose list should eit
her be a) unrendered: | 277 // All ancestors that aren't in the ancestorsToClose list should eit
her be a) unrendered: |
| 323 if (!parent->layoutObject()) | 278 if (!parent->layoutObject()) |
| 324 continue; | 279 continue; |
| 325 // or b) ancestors that we never encountered during a pre-order trav
ersal starting at startNode: | 280 // or b) ancestors that we never encountered during a pre-order trav
ersal starting at startNode: |
| 326 ASSERT(startNode); | 281 ASSERT(startNode); |
| 327 ASSERT(Strategy::isDescendantOf(*startNode, *parent)); | 282 ASSERT(Strategy::isDescendantOf(*startNode, *parent)); |
| 328 if (shouldEmit) | 283 if (shouldEmit) |
| 329 wrapWithNode(*parent); | 284 m_markupAccumulator.wrapWithNode(*parent); |
| 330 lastClosed = parent; | 285 lastClosed = parent; |
| 331 } | 286 } |
| 332 } | 287 } |
| 333 | 288 |
| 334 return lastClosed; | 289 return lastClosed; |
| 335 } | 290 } |
| 336 | 291 |
| 337 template class StyledMarkupSerializer<EditingStrategy>; | 292 template class StyledMarkupSerializer<EditingStrategy>; |
| 338 | 293 |
| 339 } // namespace blink | 294 } // namespace blink |
| OLD | NEW |