Changeset 92823 in webkit
- Timestamp:
- Aug 10, 2011, 11:29:18 PM (14 years ago)
- Location:
- trunk
- Files:
-
- 4 deleted
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r92822 r92823 1 2011-08-10 Ryosuke Niwa <rniwa@webkit.org> 2 3 Copying can result in span around block elements on the clipboard 4 https://bugs.webkit.org/show_bug.cgi?id=34564 5 6 Reviewed by Tony Chang. 7 8 This patch overhauled the way we preserve styles when copying and pasting HTML contents. Many tests progressed 9 and lost wrapping spans while others are observing different markup on the clipboard as expected. 10 11 * editing/deleting/deleting-line-break-preserves-underline-color-expected.txt: span's style attribute now has 12 a trailing space. 13 * editing/execCommand/insert-list-with-noneditable-content-expected.txt: LightGray is now rgb(211, 211, 211). 14 * editing/pasteboard/data-transfer-items-expected.txt: Different serialization. 15 * editing/pasteboard/onpaste-text-html-expected.txt: Ditto. 16 * editing/pasteboard/paste-4039777-fix-expected.txt: No longer nests ul erroneously or aligns the inner list 17 to the right. 18 * editing/pasteboard/paste-code-in-pre-expected.txt: No longer produces erroneous wrapping span. 19 * editing/pasteboard/paste-pre-001-expected.txt: Ditto. 20 * editing/pasteboard/paste-pre-002-expected.txt: Ditto. 21 * editing/pasteboard/paste-text-012-expected.txt: Ditto. 22 * editing/pasteboard/paste-text-with-style-4-expected.txt: Ditto. 23 * fast/events/ondrop-text-html-expected.txt: Different serialization. 24 * platform/chromium-win/editing/pasteboard/paste-code-in-pre-expected.txt: Removed. 25 * platform/chromium-win/editing/pasteboard/paste-pre-001-expected.txt: Removed. 26 * platform/chromium-win/editing/pasteboard/paste-pre-002-expected.txt: Removed. 27 * platform/qt-mac/editing/pasteboard/paste-code-in-pre-expected.txt: Removed. 28 1 29 2011-08-10 Ryosuke Niwa <rniwa@webkit.org> 2 30 -
trunk/LayoutTests/editing/deleting/deleting-line-break-preserves-underline-color-expected.txt
r86619 r92823 14 14 | "This should not be underlined.<#selection-caret>" 15 15 | <span> 16 | style="text-decoration: underline; color: blue; "16 | style="text-decoration: underline; color: blue; " 17 17 | <span> 18 18 | style="color:red;" -
trunk/LayoutTests/editing/execCommand/insert-list-with-noneditable-content-expected.txt
r80780 r92823 5 5 | <span> 6 6 | contenteditable="false" 7 | style="background-color: LightGray;"7 | style="background-color: rgb(211, 211, 211); " 8 8 | "non-editable" 9 9 | " in the middle" -
trunk/LayoutTests/editing/pasteboard/data-transfer-items-expected.txt
r87466 r92823 21 21 copy: items[0] value: Hello World! 22 22 copy: items[1] value: <b>Hello World! 23 paste: items[0] value: <span class="Apple-style-span" style="color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text- decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; ">This file tests the basic functionality and properties of DataTransferItems. This test requires DRT.</span>23 paste: items[0] value: <span class="Apple-style-span" style="color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; display: inline !important; float: none; ">This file tests the basic functionality and properties of DataTransferItems. This test requires DRT.</span> 24 24 paste: items[1] value: This file tests the basic functionality and properties of DataTransferItems. This test requires DRT. 25 25 -
trunk/LayoutTests/editing/pasteboard/onpaste-text-html-expected.txt
r87466 r92823 1 1 CONSOLE MESSAGE: line 21: text/plain: This test verifies that we can get text/html from the clipboard during an onpaste event. 2 CONSOLE MESSAGE: line 23: text/html: <span class="Apple-style-span" style="color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text- decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; ">This test verifies that we can get text/html from the clipboard during an onpaste event.<span class="Apple-converted-space"> </span></span>2 CONSOLE MESSAGE: line 23: text/html: <span class="Apple-style-span" style="color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; display: inline !important; float: none; ">This test verifies that we can get text/html from the clipboard during an onpaste event.<span class="Apple-converted-space"> </span></span> 3 3 This test verifies that we can get text/html from the clipboard during an onpaste event. This test requires DRT. 4 4 Paste content in this div.This test verifies that we can get text/html from the clipboard during an onpaste event. -
trunk/LayoutTests/editing/pasteboard/paste-4039777-fix-expected.txt
r86983 r92823 52 52 | <ul> 53 53 | style="text-align:right;" 54 | <ul> 55 | style="text-align: right; " 56 | <li> 57 | "A" 54 | <li> 55 | "A" 58 56 | <div> 57 | style="text-align: -webkit-auto; " 59 58 | <ul> 60 59 | <li> -
trunk/LayoutTests/editing/pasteboard/paste-code-in-pre-expected.txt
r87468 r92823 4 4 | contenteditable="true" 5 5 | id="pre" 6 | <span> 7 | class="Apple-style-span" 8 | style="font-family: Times; white-space: normal; " 9 | <pre> 10 | contenteditable="true" 11 | id="pre" 12 | "<input type='button'>foo<br>bar<b>baz</b><#selection-caret>" 6 | <pre> 7 | contenteditable="true" 8 | id="pre" 9 | "<input type='button'>foo<br>bar<b>baz</b><#selection-caret>" -
trunk/LayoutTests/editing/pasteboard/paste-pre-001-expected.txt
r92537 r92823 8 8 bar 9 9 execCutCommand: <div id="test" class="editing"> <pre><br></pre> </div> 10 execPasteCommand: <div id="test" class="editing"> <pre>< span class="Apple-style-span" style="font-family: Times; white-space: normal; "><pre>foo bar</pre></span></pre> </div>10 execPasteCommand: <div id="test" class="editing"> <pre><pre>foo bar</pre></pre> </div> -
trunk/LayoutTests/editing/pasteboard/paste-pre-002-expected.txt
r92537 r92823 3 3 bar 4 4 execCopyCommand: <div id="test" class="editing"> <pre>foo bar</pre> </div> 5 execPasteCommand: <div id="test" class="editing"> <pre>< span class="Apple-style-span" style="font-family: Times; white-space: normal; "><pre>foo bar</pre></span></pre> </div>5 execPasteCommand: <div id="test" class="editing"> <pre><pre>foo bar</pre></pre> </div> -
trunk/LayoutTests/editing/pasteboard/paste-text-012-expected.txt
r87400 r92823 7 7 8 8 execCopyCommand: <div id="test" class="editing"><div><blockquote>foo</blockquote></div></div> <div class="editing"></div> 9 execPasteCommand: <div id="test" class="editing"><div><blockquote>foo</blockquote></div></div> <div class="editing">< span class="Apple-style-span" style="font-size: medium; "><div id="test" class="editing"><div><blockquote>foo</blockquote></div><div><br></div></div></span></div>9 execPasteCommand: <div id="test" class="editing"><div><blockquote>foo</blockquote></div></div> <div class="editing"><div id="test" class="editing"><div><blockquote>foo</blockquote></div><div><br></div></div></div> -
trunk/LayoutTests/editing/pasteboard/paste-text-with-style-4-expected.txt
r92695 r92823 10 10 | <b> 11 11 | style="border: solid 5px blue;padding: 5px;" 12 | <span> 13 | class="Apple-style-span" 12 | <i> 14 13 | style="font-weight: normal; " 15 | <i> 16 | "hello<#selection-caret>" 14 | "hello<#selection-caret>" 17 15 | <br> -
trunk/LayoutTests/fast/events/ondrop-text-html-expected.txt
r87466 r92823 1 1 CONSOLE MESSAGE: line 21: text/plain: This test verifies that we can get text/html from the drag object during an ondrop event. 2 CONSOLE MESSAGE: line 23: text/html: <span class="Apple-style-span" style="color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text- decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; ">This test verifies that we can get text/html from the drag object during an ondrop event.<span class="Apple-converted-space"> </span></span>2 CONSOLE MESSAGE: line 23: text/html: <span class="Apple-style-span" style="color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; display: inline !important; float: none; ">This test verifies that we can get text/html from the drag object during an ondrop event.<span class="Apple-converted-space"> </span></span> 3 3 This test verifies that we can get text/html from the drag object during an ondrop event. This test requires DRT. 4 4 PASS -
trunk/Source/WebCore/ChangeLog
r92816 r92823 1 2011-08-10 Ryosuke Niwa <rniwa@webkit.org> 2 3 Copying can result in span around block elements on the clipboard 4 https://bugs.webkit.org/show_bug.cgi?id=34564 5 6 Reviewed by Tony Chang. 7 8 Completely overhauled the way WebKit preserves style in copy and paste. Instead of wrapping the entire 9 serialized contents by a Apple style span, WebKit now adds inline style to the top level elements, 10 wrap top level text nodes by a style span. 11 12 * editing/EditingStyle.cpp: 13 (WebCore::EditingStyle::collapseTextDecorationProperties): Remove text-decoration property when the value 14 of -webkit-text-decorations-in-effect is none. 15 (WebCore::EditingStyle::removeStyleFromRulesAndContext): Since display: inline and float: none are now 16 added on copy, remove these properties on paste. 17 (WebCore::EditingStyle::removePropertiesInElementDefaultStyle): Takes Element* instead of StyledElement*. 18 (WebCore::EditingStyle::forceInline): Added. 19 (WebCore::getPropertiesNotIn): Remove properties only when the base style has them. 20 * editing/EditingStyle.h: 21 * editing/markup.cpp: 22 (WebCore::StyledMarkupAccumulator::shouldApplyWrappingStyle): Added. 23 (WebCore::StyledMarkupAccumulator::StyledMarkupAccumulator): Takes highestNodeToBeSerialized. 24 (WebCore::StyledMarkupAccumulator::wrapWithStyleNode): Calls appendStyleNodeOpenTag and styleNodeCloseTag. 25 (WebCore::StyledMarkupAccumulator::appendStyleNodeOpenTag): Extracted from wrapWithStyleNode. 26 (WebCore::StyledMarkupAccumulator::styleNodeCloseTag): Ditto. 27 (WebCore::StyledMarkupAccumulator::appendText): Wraps text node with a style span if needed. 28 Set display: inline and float: none so that it won't be converted to a block on paste side. 29 (WebCore::StyledMarkupAccumulator::appendElement): Add wrapping style if appropriate; Remove any properties 30 that are overridden by default style and any style that may conflict with the computed style of node to 31 avoid modifying the appearance of the serialized nodes. 32 (WebCore::StyledMarkupAccumulator::serializeNodes): Compute wrapping style; copies of this style are 33 modified as needed when serializing top-level elements or text nodes. We call traverseNodesForSerialization 34 with NodeTraversalMode set to DoNotEmitString first to compute the highest node to be serialized. The second 35 call to the function actually serialize the nodes. 36 (WebCore::StyledMarkupAccumulator::traverseNodesForSerialization): Extracted from serializeNodes. 37 Outputs string only if NodeTraversalMode is set to EmitString. 38 (WebCore::createMarkup): No longer adds wrapping spans. 39 1 40 2011-08-10 Adam Barth <abarth@webkit.org> 2 41 -
trunk/Source/WebCore/editing/EditingStyle.cpp
r92695 r92823 558 558 return; 559 559 560 m_mutableStyle->setProperty(CSSPropertyTextDecoration, textDecorationsInEffect->cssText(), m_mutableStyle->getPropertyPriority(CSSPropertyTextDecoration)); 560 if (textDecorationsInEffect->isValueList()) 561 m_mutableStyle->setProperty(CSSPropertyTextDecoration, textDecorationsInEffect->cssText(), m_mutableStyle->getPropertyPriority(CSSPropertyTextDecoration)); 562 else 563 m_mutableStyle->removeProperty(CSSPropertyTextDecoration); 561 564 m_mutableStyle->removeProperty(CSSPropertyWebkitTextDecorationsInEffect); 562 565 } … … 958 961 m_mutableStyle = getPropertiesNotIn(m_mutableStyle.get(), computedStyle->m_mutableStyle.get()); 959 962 } 960 } 961 962 void EditingStyle::removePropertiesInElementDefaultStyle(StyledElement* element) 963 964 // 3. If this element is a span and has display: inline or float: none, remove them unless they are overriden by rules. 965 // These rules are added by serialization code to wrap text nodes. 966 if (isStyleSpan(element)) { 967 if (!styleFromMatchedRules->getPropertyCSSValue(CSSPropertyDisplay) && getIdentifierValue(m_mutableStyle.get(), CSSPropertyDisplay) == CSSValueInline) 968 m_mutableStyle->removeProperty(CSSPropertyDisplay); 969 if (!styleFromMatchedRules->getPropertyCSSValue(CSSPropertyFloat) && getIdentifierValue(m_mutableStyle.get(), CSSPropertyFloat) == CSSValueNone) 970 m_mutableStyle->removeProperty(CSSPropertyFloat); 971 } 972 } 973 974 void EditingStyle::removePropertiesInElementDefaultStyle(Element* element) 963 975 { 964 976 if (!m_mutableStyle || !m_mutableStyle->length()) … … 974 986 975 987 m_mutableStyle->removePropertiesInSet(propertiesToRemove.data(), propertiesToRemove.size()); 988 } 989 990 void EditingStyle::forceInline() 991 { 992 if (!m_mutableStyle) 993 m_mutableStyle = CSSMutableStyleDeclaration::create(); 994 const bool propertyIsImportant = true; 995 m_mutableStyle->setProperty(CSSPropertyDisplay, CSSValueInline, propertyIsImportant); 976 996 } 977 997 … … 1179 1199 diffTextDecorations(result.get(), CSSPropertyWebkitTextDecorationsInEffect, baseTextDecorationsInEffect.get()); 1180 1200 1181 if ( fontWeightIsBold(result.get()) == fontWeightIsBold(baseStyle))1201 if (baseStyle->getPropertyCSSValue(CSSPropertyFontSize) && fontWeightIsBold(result.get()) == fontWeightIsBold(baseStyle)) 1182 1202 result->removeProperty(CSSPropertyFontWeight); 1183 1203 1184 if ( getRGBAFontColor(result.get()) == getRGBAFontColor(baseStyle))1204 if (baseStyle->getPropertyCSSValue(CSSPropertyColor) && getRGBAFontColor(result.get()) == getRGBAFontColor(baseStyle)) 1185 1205 result->removeProperty(CSSPropertyColor); 1186 1206 1187 if ( getTextAlignment(result.get()) == getTextAlignment(baseStyle))1207 if (baseStyle->getPropertyCSSValue(CSSPropertyTextAlign) && getTextAlignment(result.get()) == getTextAlignment(baseStyle)) 1188 1208 result->removeProperty(CSSPropertyTextAlign); 1189 1209 -
trunk/Source/WebCore/editing/EditingStyle.h
r92695 r92823 48 48 class CSSValue; 49 49 class Document; 50 class Element; 50 51 class HTMLElement; 51 52 class Node; … … 127 128 void mergeStyleFromRulesForSerialization(StyledElement*); 128 129 void removeStyleFromRulesAndContext(StyledElement*, Node* context); 130 void removePropertiesInElementDefaultStyle(Element*); 131 void forceInline(); 129 132 130 133 float fontSizeDelta() const { return m_fontSizeDelta; } … … 145 148 bool conflictsWithInlineStyleOfElement(StyledElement*, EditingStyle* extractedStyle, Vector<CSSPropertyID>* conflictingProperties) const; 146 149 void mergeStyle(CSSMutableStyleDeclaration*); 147 void removePropertiesInElementDefaultStyle(StyledElement*);148 150 149 151 RefPtr<CSSMutableStyleDeclaration> m_mutableStyle; -
trunk/Source/WebCore/editing/markup.cpp
r92769 r92823 121 121 enum RangeFullySelectsNode { DoesFullySelectNode, DoesNotFullySelectNode }; 122 122 123 StyledMarkupAccumulator(Vector<Node*>* nodes, EAbsoluteURLs shouldResolveURLs, EAnnotateForInterchange shouldAnnotate, const Range* range) 124 : MarkupAccumulator(nodes, shouldResolveURLs, range) 125 , m_shouldAnnotate(shouldAnnotate) 126 { 127 } 128 123 StyledMarkupAccumulator(Vector<Node*>* nodes, EAbsoluteURLs, EAnnotateForInterchange, const Range*, Node* highestNodeToBeSerialized = 0); 129 124 Node* serializeNodes(Node* startNode, Node* pastEnd); 130 125 virtual void appendString(const String& s) { return MarkupAccumulator::appendString(s); } … … 134 129 135 130 private: 131 void appendStyleNodeOpenTag(Vector<UChar>&, CSSStyleDeclaration*, Document*, bool isBlock = false); 132 const String styleNodeCloseTag(bool isBlock = false); 136 133 virtual void appendText(Vector<UChar>& out, Text*); 137 134 String renderedText(const Node*, const Range*); … … 140 137 void appendElement(Vector<UChar>& out, Element* element, Namespaces*) { appendElement(out, element, false, DoesFullySelectNode); } 141 138 139 enum NodeTraversalMode { EmitString, DoNotEmitString }; 140 Node* traverseNodesForSerialization(Node* startNode, Node* pastEnd, NodeTraversalMode); 141 142 142 bool shouldAnnotate() { return m_shouldAnnotate == AnnotateForInterchange; } 143 bool shouldApplyWrappingStyle(Node* node) const 144 { 145 return m_highestNodeToBeSerialized && m_highestNodeToBeSerialized->parentNode() == node->parentNode() 146 && m_wrappingStyle && m_wrappingStyle->style(); 147 } 143 148 144 149 Vector<String> m_reversedPrecedingMarkup; 145 150 const EAnnotateForInterchange m_shouldAnnotate; 151 Node* m_highestNodeToBeSerialized; 152 RefPtr<EditingStyle> m_wrappingStyle; 146 153 }; 154 155 inline StyledMarkupAccumulator::StyledMarkupAccumulator(Vector<Node*>* nodes, EAbsoluteURLs shouldResolveURLs, EAnnotateForInterchange shouldAnnotate, 156 const Range* range, Node* highestNodeToBeSerialized) 157 : MarkupAccumulator(nodes, shouldResolveURLs, range) 158 , m_shouldAnnotate(shouldAnnotate) 159 , m_highestNodeToBeSerialized(highestNodeToBeSerialized) 160 { 161 } 147 162 148 163 void StyledMarkupAccumulator::wrapWithNode(Node* node, bool convertBlocksToInlines, RangeFullySelectsNode rangeFullySelectsNode) … … 161 176 void StyledMarkupAccumulator::wrapWithStyleNode(CSSStyleDeclaration* style, Document* document, bool isBlock) 162 177 { 178 Vector<UChar> openTag; 179 appendStyleNodeOpenTag(openTag, style, document, isBlock); 180 m_reversedPrecedingMarkup.append(String::adopt(openTag)); 181 appendString(styleNodeCloseTag(isBlock)); 182 } 183 184 void StyledMarkupAccumulator::appendStyleNodeOpenTag(Vector<UChar>& out, CSSStyleDeclaration* style, Document* document, bool isBlock) 185 { 163 186 // All text-decoration-related elements should have been treated as special ancestors 164 187 // If we ever hit this ASSERT, we should export StyleChange in ApplyStyleCommand and use it here 165 188 ASSERT(propertyMissingOrEqualToNone(style, CSSPropertyTextDecoration) && propertyMissingOrEqualToNone(style, CSSPropertyWebkitTextDecorationsInEffect)); 166 189 DEFINE_STATIC_LOCAL(const String, divStyle, ("<div style=\"")); 190 DEFINE_STATIC_LOCAL(const String, styleSpanOpen, ("<span class=\"" AppleStyleSpanClass "\" style=\"")); 191 append(out, isBlock ? divStyle : styleSpanOpen); 192 appendAttributeValue(out, style->cssText(), document->isHTMLDocument()); 193 out.append('\"'); 194 out.append('>'); 195 } 196 197 const String StyledMarkupAccumulator::styleNodeCloseTag(bool isBlock) 198 { 167 199 DEFINE_STATIC_LOCAL(const String, divClose, ("</div>")); 168 DEFINE_STATIC_LOCAL(const String, styleSpanOpen, ("<span class=\"" AppleStyleSpanClass "\" style=\""));169 200 DEFINE_STATIC_LOCAL(const String, styleSpanClose, ("</span>")); 170 Vector<UChar> openTag; 171 append(openTag, isBlock ? divStyle : styleSpanOpen); 172 appendAttributeValue(openTag, style->cssText(), document->isHTMLDocument()); 173 openTag.append('\"'); 174 openTag.append('>'); 175 m_reversedPrecedingMarkup.append(String::adopt(openTag)); 176 appendString(isBlock ? divClose : styleSpanClose); 201 return isBlock ? divClose : styleSpanClose; 177 202 } 178 203 … … 192 217 193 218 void StyledMarkupAccumulator::appendText(Vector<UChar>& out, Text* text) 194 { 195 if (!shouldAnnotate() || (text->parentElement() && text->parentElement()->tagQName() == textareaTag)) { 219 { 220 const bool parentIsTextarea = text->parentElement() && text->parentElement()->tagQName() == textareaTag; 221 const bool wrappingSpan = shouldApplyWrappingStyle(text) && !parentIsTextarea; 222 if (wrappingSpan) { 223 RefPtr<EditingStyle> wrappingStyle = m_wrappingStyle->copy(); 224 // FIXME: <rdar://problem/5371536> Style rules that match pasted content can change it's appearance 225 // Make sure spans are inline style in paste side e.g. span { display: block }. 226 wrappingStyle->forceInline(); 227 // FIXME: Should this be included in forceInline? 228 wrappingStyle->style()->setProperty(CSSPropertyFloat, CSSValueNone); 229 230 Vector<UChar> openTag; 231 appendStyleNodeOpenTag(openTag, wrappingStyle->style(), text->document()); 232 append(out, String::adopt(openTag)); 233 } 234 235 if (!shouldAnnotate() || parentIsTextarea) 196 236 MarkupAccumulator::appendText(out, text); 197 return; 198 } 199 200 bool useRenderedText = !enclosingNodeWithTag(firstPositionInNode(text), selectTag); 201 String content = useRenderedText ? renderedText(text, m_range) : stringValueForRange(text, m_range); 202 Vector<UChar> buffer; 203 appendCharactersReplacingEntities(buffer, content.characters(), content.length(), EntityMaskInPCDATA); 204 append(out, convertHTMLTextToInterchangeFormat(String::adopt(buffer), text)); 237 else { 238 const bool useRenderedText = !enclosingNodeWithTag(firstPositionInNode(text), selectTag); 239 String content = useRenderedText ? renderedText(text, m_range) : stringValueForRange(text, m_range); 240 Vector<UChar> buffer; 241 appendCharactersReplacingEntities(buffer, content.characters(), content.length(), EntityMaskInPCDATA); 242 append(out, convertHTMLTextToInterchangeFormat(String::adopt(buffer), text)); 243 } 244 245 if (wrappingSpan) 246 append(out, styleNodeCloseTag()); 205 247 } 206 248 … … 241 283 void StyledMarkupAccumulator::appendElement(Vector<UChar>& out, Element* element, bool addDisplayInline, RangeFullySelectsNode rangeFullySelectsNode) 242 284 { 243 bool documentIsHTML = element->document()->isHTMLDocument();285 const bool documentIsHTML = element->document()->isHTMLDocument(); 244 286 appendOpenTag(out, element, 0); 245 287 246 288 NamedNodeMap* attributes = element->attributes(); 247 unsigned length = attributes->length(); 289 const unsigned length = attributes->length(); 290 const bool shouldAnnotateOrForceInline = element->isHTMLElement() && (shouldAnnotate() || addDisplayInline); 291 const bool shouldOverrideStyleAttr = shouldAnnotateOrForceInline || shouldApplyWrappingStyle(element); 248 292 for (unsigned int i = 0; i < length; i++) { 249 293 Attribute* attribute = attributes->attributeItem(i); 250 294 // We'll handle the style attribute separately, below. 251 if (attribute->name() == styleAttr && element->isHTMLElement() && (shouldAnnotate() || addDisplayInline))295 if (attribute->name() == styleAttr && shouldOverrideStyleAttr) 252 296 continue; 253 297 appendAttribute(out, element, *attribute, 0); 254 298 } 255 299 256 if (element->isHTMLElement() && (shouldAnnotate() || addDisplayInline)) { 257 RefPtr<EditingStyle> style = EditingStyle::create(toHTMLElement(element)->getInlineStyleDecl()); 258 if (shouldAnnotate()) 259 style->mergeStyleFromRulesForSerialization(toHTMLElement(element)); 260 if (addDisplayInline) 261 style->style()->setProperty(CSSPropertyDisplay, CSSValueInline, true); 262 263 // If the node is not fully selected by the range, then we don't want to keep styles that affect its relationship to the nodes around it 264 // only the ones that affect it and the nodes within it. 265 if (rangeFullySelectsNode == DoesNotFullySelectNode) 266 style->style()->removeProperty(CSSPropertyFloat); 267 268 if (!style->isEmpty()) { 300 if (shouldOverrideStyleAttr) { 301 RefPtr<EditingStyle> newInlineStyle; 302 303 if (shouldApplyWrappingStyle(element)) { 304 newInlineStyle = m_wrappingStyle->copy(); 305 newInlineStyle->removePropertiesInElementDefaultStyle(element); 306 newInlineStyle->removeStyleConflictingWithStyleOfNode(element); 307 } else 308 newInlineStyle = EditingStyle::create(); 309 310 if (element->isStyledElement() && static_cast<StyledElement*>(element)->inlineStyleDecl()) 311 newInlineStyle->overrideWithStyle(static_cast<StyledElement*>(element)->inlineStyleDecl()); 312 313 if (shouldAnnotateOrForceInline) { 314 if (shouldAnnotate()) 315 newInlineStyle->mergeStyleFromRulesForSerialization(toHTMLElement(element)); 316 317 if (addDisplayInline) 318 newInlineStyle->forceInline(); 319 320 // If the node is not fully selected by the range, then we don't want to keep styles that affect its relationship to the nodes around it 321 // only the ones that affect it and the nodes within it. 322 if (rangeFullySelectsNode == DoesNotFullySelectNode && newInlineStyle->style()) 323 newInlineStyle->style()->removeProperty(CSSPropertyFloat); 324 } 325 326 if (!newInlineStyle->isEmpty()) { 269 327 DEFINE_STATIC_LOCAL(const String, stylePrefix, (" style=\"")); 270 328 append(out, stylePrefix); 271 appendAttributeValue(out, style->style()->cssText(), documentIsHTML);329 appendAttributeValue(out, newInlineStyle->style()->cssText(), documentIsHTML); 272 330 out.append('\"'); 273 331 } … … 279 337 Node* StyledMarkupAccumulator::serializeNodes(Node* startNode, Node* pastEnd) 280 338 { 339 if (!m_highestNodeToBeSerialized) { 340 Node* lastClosed = traverseNodesForSerialization(startNode, pastEnd, DoNotEmitString); 341 m_highestNodeToBeSerialized = lastClosed; 342 } 343 344 Node* parentOfHighestNode = m_highestNodeToBeSerialized ? m_highestNodeToBeSerialized->parentNode() : 0; 345 if (parentOfHighestNode) { 346 m_wrappingStyle = EditingStyle::create(parentOfHighestNode, EditingStyle::EditingInheritablePropertiesAndBackgroundColorInEffect); 347 348 // Styles that Mail blockquotes contribute should only be placed on the Mail blockquote, 349 // to help us differentiate those styles from ones that the user has applied. 350 // This helps us get the color of content pasted into blockquotes right. 351 m_wrappingStyle->removeStyleAddedByNode(enclosingNodeOfType(firstPositionInOrBeforeNode(parentOfHighestNode), isMailBlockquote, CanCrossEditingBoundary)); 352 353 // Call collapseTextDecorationProperties first or otherwise it'll copy the value over from in-effect to text-decorations. 354 m_wrappingStyle->collapseTextDecorationProperties(); 355 } 356 357 return traverseNodesForSerialization(startNode, pastEnd, EmitString); 358 } 359 360 Node* StyledMarkupAccumulator::traverseNodesForSerialization(Node* startNode, Node* pastEnd, NodeTraversalMode traversalMode) 361 { 362 const bool shouldEmit = traversalMode == EmitString; 281 363 Vector<Node*> ancestorsToClose; 282 364 Node* next; … … 305 387 } else { 306 388 // Add the node to the markup if we're not skipping the descendants 307 appendStartTag(n); 389 if (shouldEmit) 390 appendStartTag(n); 308 391 309 392 // If node has no children, close the tag now. 310 393 if (!n->childNodeCount()) { 311 appendEndTag(n); 394 if (shouldEmit) 395 appendEndTag(n); 312 396 lastClosed = n; 313 397 } else { … … 326 410 break; 327 411 // Not at the end of the range, close ancestors up to sibling of next node. 328 appendEndTag(ancestor); 412 if (shouldEmit) 413 appendEndTag(ancestor); 329 414 lastClosed = ancestor; 330 415 ancestorsToClose.removeLast(); … … 341 426 // or b) ancestors that we never encountered during a pre-order traversal starting at startNode: 342 427 ASSERT(startNode->isDescendantOf(parent)); 343 wrapWithNode(parent); 428 if (shouldEmit) 429 wrapWithNode(parent); 344 430 lastClosed = parent; 345 431 } … … 514 600 document->updateLayoutIgnorePendingStylesheets(); 515 601 516 StyledMarkupAccumulator accumulator(nodes, shouldResolveURLs, shouldAnnotate, updatedRange.get()); 602 Node* body = enclosingNodeWithTag(firstPositionInNode(commonAncestor), bodyTag); 603 Node* fullySelectedRoot = 0; 604 // FIXME: Do this for all fully selected blocks, not just the body. 605 if (body && areRangesEqual(VisibleSelection::selectionFromContentsOfNode(body).toNormalizedRange().get(), range)) 606 fullySelectedRoot = body; 607 Node* specialCommonAncestor = highestAncestorToWrapMarkup(updatedRange.get(), fullySelectedRoot, shouldAnnotate); 608 StyledMarkupAccumulator accumulator(nodes, shouldResolveURLs, shouldAnnotate, updatedRange.get(), specialCommonAncestor); 517 609 Node* pastEnd = updatedRange->pastLastNode(); 518 610 … … 539 631 ASSERT(!ec); 540 632 } 541 542 Node* body = enclosingNodeWithTag(firstPositionInNode(commonAncestor), bodyTag);543 Node* fullySelectedRoot = 0;544 // FIXME: Do this for all fully selected blocks, not just the body.545 if (body && areRangesEqual(VisibleSelection::selectionFromContentsOfNode(body).toNormalizedRange().get(), range))546 fullySelectedRoot = body;547 548 Node* specialCommonAncestor = highestAncestorToWrapMarkup(updatedRange.get(), fullySelectedRoot, shouldAnnotate);549 633 550 634 Node* lastClosed = accumulator.serializeNodes(startNode, pastEnd); … … 587 671 } 588 672 589 // Add a wrapper span with the styles that all of the nodes in the markup inherit.590 ContainerNode* parentOfLastClosed = lastClosed ? lastClosed->parentNode() : 0;591 if (parentOfLastClosed && parentOfLastClosed->renderer()) {592 RefPtr<EditingStyle> style = EditingStyle::create(parentOfLastClosed, EditingStyle::EditingInheritablePropertiesAndBackgroundColorInEffect);593 594 // Styles that Mail blockquotes contribute should only be placed on the Mail blockquote, to help595 // us differentiate those styles from ones that the user has applied. This helps us596 // get the color of content pasted into blockquotes right.597 style->removeStyleAddedByNode(enclosingNodeOfType(firstPositionInNode(parentOfLastClosed), isMailBlockquote, CanCrossEditingBoundary));598 599 if (!style->isEmpty())600 accumulator.wrapWithStyleNode(style->style(), document);601 }602 603 673 // FIXME: The interchange newline should be placed in the block that it's in, not after all of the content, unconditionally. 604 674 if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(visibleEnd.previous()))
Note:
See TracChangeset
for help on using the changeset viewer.