Commit f8d20922 authored by enrica@apple.com's avatar enrica@apple.com

Source/WebCore: Repeated copy and paste-in-place operation results in increasingly verbose HTML.

<rdar://problem/8690506>
https://bugs.webkit.org/show_bug.cgi?id=56874
        
Reviewed by Darin Adler.

When we calculate the style to apply at the insertion point we compare the initial
style at the insertion point against the style calculated at the span we wrap the
copied markup fragment with. We could end up with a series of unnecessary spans
to remove the initial style that simply grow our markup.
The consists in moving the insertion point outside any inline element that could
affect the fragment being inserted when we are not pasting and matching the style.

Test: editing/pasteboard/paste-text-with-style.html

* editing/ReplaceSelectionCommand.cpp:
(WebCore::isInlineNodeWithStyle): Added.
(WebCore::ReplaceSelectionCommand::doApply): Added logic to change the insertion
point according to the new rules.

LayoutTests: Repeated copy and paste-in-place operation results in increasingly verbose HTML.
<rdar://problem/8690506>
https://bugs.webkit.org/show_bug.cgi?id=56874

Reviewed by Darin Adler.

* editing/pasteboard/paste-text-with-style-expected.txt: Added.
* editing/pasteboard/paste-text-with-style.html: Added.
The following are new results for existing tests that now produce
a different markup.
* platform/mac/editing/pasteboard/5065605-expected.txt:
* platform/mac/editing/pasteboard/display-block-on-spans-expected.txt:
* platform/mac/editing/pasteboard/paste-text-011-expected.txt:
* platform/mac/editing/pasteboard/paste-text-at-tabspan-001-expected.txt:
* platform/mac/editing/pasteboard/paste-text-at-tabspan-002-expected.txt:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@81887 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent d30b8bc3
2011-03-24 Enrica Casucci <enrica@apple.com>
Reviewed by Darin Adler.
Repeated copy and paste-in-place operation results in increasingly verbose HTML.
<rdar://problem/8690506>
https://bugs.webkit.org/show_bug.cgi?id=56874
* editing/pasteboard/paste-text-with-style-expected.txt: Added.
* editing/pasteboard/paste-text-with-style.html: Added.
The following are new results for existing tests that now produce
a different markup.
* platform/mac/editing/pasteboard/5065605-expected.txt:
* platform/mac/editing/pasteboard/display-block-on-spans-expected.txt:
* platform/mac/editing/pasteboard/paste-text-011-expected.txt:
* platform/mac/editing/pasteboard/paste-text-at-tabspan-001-expected.txt:
* platform/mac/editing/pasteboard/paste-text-at-tabspan-002-expected.txt:
2011-03-24 Adam Roben <aroben@apple.com>
Add some flaky tests to the mac-wk2 and win-wk2 Skipped files
......
EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 5 of DIV > BODY > HTML > #document
EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of DIV > BODY > HTML > #document to 0 of DIV > BODY > HTML > #document toDOMRange:range from 0 of #text > I > B > DIV > BODY > HTML > #document to 9 of #text > FONT > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 0 of #text > I > B > DIV > BODY > HTML > #document to 9 of #text > FONT > DIV > DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 9 of #text > FONT > DIV > DIV > BODY > HTML > #document to 9 of #text > FONT > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification
Markup before:
| "
"
| <b>
| <i>
| "<#selection-caret>hello bold and italic"
| <div>
| <i>
| "hello italic"
| <div>
| <font>
| color="#ff0000"
| "hello red"
| "
"
Markup after:
| <b>
| <i>
| "hello bold and italic"
| <div>
| <i>
| "hello italic"
| <div>
| <font>
| color="#ff0000"
| "hello red<#selection-caret>"
| "
"
<!DOCTYPE html>
<html>
<head>
<style>
.editing {
border: 2px solid red;
font-size: 24px;
}
.explanation {
border: 2px solid blue;
padding: 12px;
font-size: 24px;
margin-bottom: 24px;
}
.scenario { margin-bottom: 16px;}
.scenario:first-line { font-weight: bold; margin-bottom: 16px;}
.expected-results:first-line { font-weight: bold }
</style>
<script src=../editing.js></script>
<script src="../../resources/dump-as-markup.js"></script>
<script>
if (window.layoutTestController)
layoutTestController.dumpAsText();
function editingTest() {
Markup.dump('test', 'Markup before');
selectAllCommand();
copyCommand();
pasteCommand();
Markup.dump('test', 'Markup after');
}
</script>
<title>Editing Test</title>
</head>
<body>
<div class="explanation">
<div class="scenario">
Tests:
<br>
Fix for this bug:
<a href="https://bugs.webkit.org/show_bug.cgi?id=56874">&lt;https://bugs.webkit.org/show_bug.cgi?id=56874&gt;</a> Repeated copy and paste-in-place operation results in increasingly verbose HTML.
</div>
<div class="expected-results">
Expected Results:
<br>
The markup before and after should be identical.
</div>
</div>
<div contenteditable id="test" class="editing">
<b><i>hello bold and italic</i></b><div><i>hello italic</I></div><div><font color="#ff0000">hello red</font></div>
</div>
<script>
runEditingTest();
</script>
</body>
</html>
......@@ -17,17 +17,12 @@ layer at (0,0) size 800x600
text run at (0,0) width 148: "This text should be red."
RenderBlock {DIV} at (0,36) size 784x36
RenderBlock (anonymous) at (0,0) size 784x18
RenderInline {FONT} at (0,0) size 148x18 [color=#FF0000]
RenderInline {SPAN} at (0,0) size 148x18 [color=#000000]
RenderInline {FONT} at (0,0) size 148x18 [color=#FF0000]
RenderText {#text} at (0,0) size 148x18
text run at (0,0) width 148: "This text should be red."
RenderBlock (anonymous) at (0,18) size 784x18 [color=#FF0000]
RenderBlock {DIV} at (0,0) size 784x18 [color=#000000]
RenderBlock {DIV} at (0,18) size 784x18
RenderInline {FONT} at (0,0) size 148x18 [color=#FF0000]
RenderText {#text} at (0,0) size 148x18
text run at (0,0) width 148: "This text should be red."
RenderBlock (anonymous) at (0,36) size 784x0
RenderInline {FONT} at (0,0) size 0x0 [color=#FF0000]
RenderInline {FONT} at (0,0) size 0x0 [color=#FF0000]
caret: position 24 of child 0 {#text} of child 0 {FONT} of child 1 {DIV} of child 0 {FONT} of child 2 {DIV} of child 2 {DIV} of body
caret: position 24 of child 0 {#text} of child 0 {FONT} of child 1 {DIV} of child 2 {DIV} of child 2 {DIV} of body
......@@ -5,7 +5,7 @@ EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotificatio
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 0 of #text > B > SPAN > DIV > BODY > HTML > #document to 4 of #text > B > SPAN > DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 4 of #text > B > SPAN > B > SPAN > DIV > BODY > HTML > #document to 4 of #text > B > SPAN > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 4 of #text > B > SPAN > DIV > BODY > HTML > #document to 4 of #text > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
layer at (0,0) size 800x600
......@@ -33,11 +33,10 @@ layer at (0,0) size 800x600
RenderText {#text} at (0,0) size 137x18
text run at (0,0) width 137: "This is a paragraph."
RenderBlock {SPAN} at (0,18) size 784x18
RenderInline {B} at (0,0) size 182x18
RenderInline {SPAN} at (0,0) size 30x18
RenderInline {B} at (0,0) size 30x18
RenderText {#text} at (0,0) size 30x18
text run at (0,0) width 30: "This"
RenderInline {B} at (0,0) size 152x18
RenderText {#text} at (30,0) size 152x18
text run at (30,0) width 152: " is another paragraph."
caret: position 4 of child 0 {#text} of child 0 {B} of child 0 {SPAN} of child 0 {B} of child 2 {SPAN} of child 5 {DIV} of body
caret: position 4 of child 0 {#text} of child 0 {B} of child 2 {SPAN} of child 5 {DIV} of body
......@@ -9,7 +9,7 @@ EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotificatio
EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 0 of P > BODY > HTML > #document to 0 of P > BODY > HTML > #document givenAction:WebViewInsertActionPasted
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 5 of #text > B > FONT > P > B > FONT > P > BODY > HTML > #document to 5 of #text > B > FONT > P > B > FONT > P > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 5 of #text > B > FONT > P > FONT > P > BODY > HTML > #document to 5 of #text > B > FONT > P > FONT > P > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
layer at (0,0) size 800x600
......@@ -30,7 +30,6 @@ layer at (0,0) size 800x600
RenderBlock {P} at (0,74) size 784x58
RenderBlock (anonymous) at (0,0) size 784x0
RenderInline {FONT} at (0,0) size 0x0
RenderInline {B} at (0,0) size 0x0
RenderBlock (anonymous) at (0,0) size 784x58
RenderBlock {P} at (0,0) size 784x21
RenderInline {FONT} at (0,0) size 55x20
......@@ -44,7 +43,5 @@ layer at (0,0) size 800x600
text run at (0,0) width 55: "there"
RenderBlock (anonymous) at (0,74) size 784x0
RenderInline {FONT} at (0,0) size 0x0
RenderInline {B} at (0,0) size 0x0
RenderInline {FONT} at (0,0) size 0x0
RenderInline {B} at (0,0) size 0x0
caret: position 5 of child 0 {#text} of child 0 {B} of child 0 {FONT} of child 1 {P} of child 0 {B} of child 0 {FONT} of child 4 {P} of body
caret: position 5 of child 0 {#text} of child 0 {B} of child 0 {FONT} of child 1 {P} of child 0 {FONT} of child 4 {P} of body
......@@ -4,11 +4,11 @@ EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotificatio
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 1 of #text > SPAN > DIV > BODY > HTML > #document to 1 of #text > SPAN > DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > SPAN > DIV > BODY > HTML > #document to 1 of #text > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 1 of #text > SPAN > SPAN > SPAN > DIV > BODY > HTML > #document to 1 of #text > SPAN > SPAN > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > SPAN > DIV > BODY > HTML > #document to 1 of #text > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 1 of #text > SPAN > DIV > BODY > HTML > #document to 1 of #text > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > SPAN > SPAN > SPAN > DIV > BODY > HTML > #document to 2 of #text > SPAN > SPAN > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > SPAN > SPAN > SPAN > DIV > BODY > HTML > #document to 2 of #text > SPAN > SPAN > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > SPAN > DIV > BODY > HTML > #document to 2 of #text > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > SPAN > DIV > BODY > HTML > #document to 2 of #text > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
layer at (0,0) size 800x600
......@@ -20,13 +20,12 @@ layer at (0,0) size 800x600
RenderInline {SPAN} at (0,0) size 155x28
RenderText {#text} at (14,14) size 11x28
text run at (14,14) width 11: "a"
RenderInline {SPAN} at (0,0) size 133x28
RenderInline {SPAN} at (0,0) size 23x28
RenderText {#text} at (25,14) size 23x28
text run at (25,14) width 23: "ax"
RenderInline {SPAN} at (0,0) size 110x28
RenderText {#text} at (48,14) size 110x28
text run at (48,14) width 110: "\x{9}\x{9}\x{9}"
RenderText {#text} at (158,14) size 11x28
text run at (158,14) width 11: "z"
RenderText {#text} at (0,0) size 0x0
caret: position 2 of child 0 {#text} of child 0 {SPAN} of child 1 {SPAN} of child 1 {SPAN} of child 1 {DIV} of body
caret: position 2 of child 1 {#text} of child 1 {SPAN} of child 1 {DIV} of body
......@@ -6,11 +6,11 @@ EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotificatio
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 1 of #text > SPAN > SPAN > DIV > BODY > HTML > #document to 1 of #text > SPAN > SPAN > DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > SPAN > SPAN > SPAN > DIV > BODY > HTML > #document to 1 of #text > SPAN > SPAN > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 1 of #text > SPAN > SPAN > SPAN > DIV > BODY > HTML > #document to 1 of #text > SPAN > SPAN > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > SPAN > DIV > BODY > HTML > #document to 1 of #text > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 1 of #text > SPAN > DIV > BODY > HTML > #document to 1 of #text > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > SPAN > SPAN > SPAN > DIV > BODY > HTML > #document to 2 of #text > SPAN > SPAN > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > SPAN > SPAN > SPAN > DIV > BODY > HTML > #document to 2 of #text > SPAN > SPAN > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > SPAN > DIV > BODY > HTML > #document to 2 of #text > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > SPAN > DIV > BODY > HTML > #document to 2 of #text > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
layer at (0,0) size 800x600
......@@ -25,13 +25,12 @@ layer at (0,0) size 800x600
RenderInline {SPAN} at (0,0) size 37x28
RenderText {#text} at (25,14) size 37x28
text run at (25,14) width 37: "\x{9}"
RenderInline {SPAN} at (0,0) size 96x28
RenderInline {SPAN} at (0,0) size 23x28
RenderText {#text} at (62,14) size 23x28
text run at (62,14) width 23: "ax"
RenderInline {SPAN} at (0,0) size 73x28
RenderText {#text} at (85,14) size 73x28
text run at (85,14) width 73: "\x{9}\x{9}"
RenderText {#text} at (158,14) size 11x28
text run at (158,14) width 11: "z"
RenderText {#text} at (0,0) size 0x0
caret: position 2 of child 0 {#text} of child 0 {SPAN} of child 2 {SPAN} of child 1 {SPAN} of child 1 {DIV} of body
caret: position 2 of child 2 {#text} of child 1 {SPAN} of child 1 {DIV} of body
2011-03-24 Enrica Casucci <enrica@apple.com>
Reviewed by Darin Adler.
Repeated copy and paste-in-place operation results in increasingly verbose HTML.
<rdar://problem/8690506>
https://bugs.webkit.org/show_bug.cgi?id=56874
When we calculate the style to apply at the insertion point we compare the initial
style at the insertion point against the style calculated at the span we wrap the
copied markup fragment with. We could end up with a series of unnecessary spans
to remove the initial style that simply grow our markup.
The consists in moving the insertion point outside any inline element that could
affect the fragment being inserted when we are not pasting and matching the style.
Test: editing/pasteboard/paste-text-with-style.html
* editing/ReplaceSelectionCommand.cpp:
(WebCore::isInlineNodeWithStyle): Added.
(WebCore::ReplaceSelectionCommand::doApply): Added logic to change the insertion
point according to the new rules.
2011-03-24 Benjamin Poulain <benjamin.poulain@nokia.com>
Reviewed by Kenneth Rohde Christiansen.
......@@ -43,6 +43,7 @@
#include "HTMLInputElement.h"
#include "HTMLInterchange.h"
#include "HTMLNames.h"
#include "NodeList.h"
#include "SelectionController.h"
#include "SmartReplace.h"
#include "TextIterator.h"
......@@ -776,6 +777,34 @@ static Node* enclosingInline(Node* node)
return node;
}
static bool isInlineNodeWithStyle(const Node* node)
{
// We don't want to skip over any block elements.
if (!node->renderer() || !node->renderer()->isInline())
return false;
if (!node->isHTMLElement())
return false;
// We can skip over elements whose class attribute is
// one of our internal classes.
const HTMLElement* element = static_cast<const HTMLElement*>(node);
AtomicString classAttributeValue = element->getAttribute(classAttr);
if (classAttributeValue == AppleStyleSpanClass
|| classAttributeValue == AppleTabSpanClass
|| classAttributeValue == AppleConvertedSpace
|| classAttributeValue == ApplePasteAsQuotation)
return true;
// We can skip inline elements that don't have attributes or whose only
// attribute is the style attribute.
const NamedNodeMap* attributeMap = element->attributeMap();
if (!attributeMap || attributeMap->isEmpty() || (attributeMap->length() == 1 && element->hasAttribute(styleAttr)))
return true;
return false;
}
void ReplaceSelectionCommand::doApply()
{
VisibleSelection selection = endingSelection();
......@@ -917,6 +946,29 @@ void ReplaceSelectionCommand::doApply()
// outside of preceding tags.
insertionPos = positionAvoidingPrecedingNodes(insertionPos);
// If we are not trying to match the destination style we prefer a position
// that is outside inline elements that provide style.
// This way we can produce a less verbose markup.
// We can skip this optimization for fragments not wrapped in one of
// our style spans and for positions inside list items
// since insertAsListItems already does the right thing.
if (!m_matchStyle && !enclosingList(insertionPos.anchorNode()) && isStyleSpan(fragment.firstChild())) {
Node* parentNode = insertionPos.anchorNode()->parentNode();
while (parentNode && parentNode->renderer() && isInlineNodeWithStyle(parentNode)) {
// If we are in the middle of a text node, we need to split it before we can
// move the insertion position.
if (insertionPos.anchorNode()->isTextNode() && insertionPos.anchorType() == Position::PositionIsOffsetInAnchor && insertionPos.offsetInContainerNode() && !insertionPos.atLastEditingPositionForNode())
splitTextNodeContainingElement(static_cast<Text*>(insertionPos.anchorNode()), insertionPos.offsetInContainerNode());
// If the style element has more than one child, we need to split it.
if (parentNode->firstChild()->nextSibling())
splitElement(static_cast<Element*>(parentNode), insertionPos.computeNodeAfterPosition());
insertionPos = positionInParentBeforeNode(parentNode);
parentNode = parentNode->parentNode();
}
}
// FIXME: When pasting rich content we're often prevented from heading down the fast path by style spans. Try
// again here if they've been removed.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment