RenderBlock {DIV} at (0,0) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 34x28
text run at (14,14) width 34: "test"
- RenderBlock {DIV} at (0,56) size 784x28 [border: (2px solid #FF0000)]
- RenderBlock {DIV} at (0,84) size 784x28 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,56) size 784x56 [border: (2px solid #FF0000)]
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock {DIV} at (0,112) size 784x56 [border: (2px solid #FF0000)]
+ RenderBR {BR} at (14,14) size 0x28
selection is CARET:
-start: position 0 of child 3 {DIV} of root {BODY}
+start: position 0 of child 1 {BR} of child 3 {DIV} of root {BODY}
upstream: position 0 of child 3 {DIV} of root {BODY}
-downstream: position 1 of child 3 {DIV} of root {BODY}
+downstream: position 0 of child 1 {BR} of child 3 {DIV} of root {BODY}
RenderBlock {DIV} at (0,0) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 34x28
text run at (14,14) width 34: "test"
- RenderBlock {DIV} at (0,56) size 784x28 [border: (2px solid #FF0000)]
- RenderBlock {DIV} at (0,84) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,56) size 784x56 [border: (2px solid #FF0000)]
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock {DIV} at (0,112) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 12x28
text run at (14,14) width 12: "x"
selection is CARET:
layer at (0,0) size 800x600
RenderBlock {HTML} at (0,0) size 800x600
RenderBody {BODY} at (8,8) size 784x584
- RenderBlock {DIV} at (0,0) size 784x28 [border: (2px solid #FF0000)]
- RenderBlock {DIV} at (0,28) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,0) size 784x56 [border: (2px solid #FF0000)]
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock {DIV} at (0,56) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 46x28
text run at (14,14) width 46: "xtest"
selection is CARET:
layer at (0,0) size 800x600
RenderBlock {HTML} at (0,0) size 800x600
RenderBody {BODY} at (8,8) size 784x584
- RenderBlock {DIV} at (0,0) size 784x28 [border: (2px solid #FF0000)]
- RenderBlock {DIV} at (0,28) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,0) size 784x56 [border: (2px solid #FF0000)]
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock {DIV} at (0,56) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 44x28
text run at (14,14) width 44: "xfoo"
selection is CARET:
RenderText {TEXT} at (0,0) size 629x28
text run at (0,0) width 629: "Test inserting paragraphs: should see empty red box above \"baz\""
RenderBlock {DIV} at (0,28) size 784x12
- RenderBlock {DIV} at (0,40) size 784x28 [border: (2px solid #FF0000)]
- RenderBlock {DIV} at (0,68) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,40) size 784x56 [border: (2px solid #FF0000)]
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock {DIV} at (0,96) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 34x28
text run at (14,14) width 34: "baz"
- RenderBlock (anonymous) at (0,124) size 784x28
+ RenderBlock (anonymous) at (0,152) size 784x28
RenderText {TEXT} at (0,0) size 31x28
text run at (0,0) width 31: "bar"
- RenderBlock {DIV} at (0,152) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,180) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 32x28
text run at (14,14) width 32: "foo"
- RenderBlock {DIV} at (0,208) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,236) size 784x56 [border: (2px solid #FF0000)]
RenderBR {BR} at (14,14) size 0x28
selection is CARET:
start: position 0 of child 1 {TEXT} of child 5 {DIV} of root {BODY}
RenderBlock {DIV} at (0,40) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 34x28
text run at (14,14) width 34: "baz"
- RenderBlock {DIV} at (0,96) size 784x28 [border: (2px solid #FF0000)]
- RenderBlock (anonymous) at (0,124) size 784x28
+ RenderBlock {DIV} at (0,96) size 784x56 [border: (2px solid #FF0000)]
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock (anonymous) at (0,152) size 784x28
RenderText {TEXT} at (0,0) size 31x28
text run at (0,0) width 31: "bar"
- RenderBlock {DIV} at (0,152) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,180) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 32x28
text run at (14,14) width 32: "foo"
- RenderBlock {DIV} at (0,208) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,236) size 784x56 [border: (2px solid #FF0000)]
RenderBR {BR} at (14,14) size 0x28
selection is CARET:
-start: position 0 of child 5 {DIV} of root {BODY}
+start: position 0 of child 1 {BR} of child 5 {DIV} of root {BODY}
upstream: position 0 of child 5 {DIV} of root {BODY}
-downstream: position 1 of child 5 {DIV} of root {BODY}
+downstream: position 0 of child 1 {BR} of child 5 {DIV} of root {BODY}
RenderBlock {DIV} at (0,40) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 34x28
text run at (14,14) width 34: "baz"
- RenderBlock {P} at (0,96) size 784x28 [border: (2px solid #0000FF)]
- RenderBlock (anonymous) at (0,124) size 784x28
+ RenderBlock {P} at (0,96) size 784x56 [border: (2px solid #0000FF)]
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock (anonymous) at (0,152) size 784x28
RenderText {TEXT} at (0,0) size 31x28
text run at (0,0) width 31: "bar"
- RenderBlock {DIV} at (0,152) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,180) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 32x28
text run at (14,14) width 32: "foo"
- RenderBlock {DIV} at (0,208) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,236) size 784x56 [border: (2px solid #FF0000)]
RenderBR {BR} at (14,14) size 0x28
selection is CARET:
start: position 0 of child 6 {TEXT} of root {BODY}
RenderBlock (anonymous) at (0,96) size 784x28
RenderText {TEXT} at (0,0) size 31x28
text run at (0,0) width 31: "bar"
- RenderBlock {P} at (0,124) size 784x28 [border: (2px solid #0000FF)]
- RenderBlock {DIV} at (0,152) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {P} at (0,124) size 784x56 [border: (2px solid #0000FF)]
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock {DIV} at (0,180) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 32x28
text run at (14,14) width 32: "foo"
- RenderBlock {DIV} at (0,208) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,236) size 784x56 [border: (2px solid #FF0000)]
RenderBR {BR} at (14,14) size 0x28
selection is CARET:
-start: position 0 of child 6 {P} of root {BODY}
+start: position 0 of child 1 {BR} of child 6 {P} of root {BODY}
upstream: position 0 of child 6 {P} of root {BODY}
-downstream: position 1 of child 6 {P} of root {BODY}
+downstream: position 0 of child 1 {BR} of child 6 {P} of root {BODY}
RenderBlock (anonymous) at (0,96) size 784x28
RenderText {TEXT} at (0,0) size 31x28
text run at (0,0) width 31: "bar"
- RenderBlock {DIV} at (0,124) size 784x28 [border: (2px solid #FF0000)]
- RenderBlock {DIV} at (0,152) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,124) size 784x56 [border: (2px solid #FF0000)]
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock {DIV} at (0,180) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 32x28
text run at (14,14) width 32: "foo"
- RenderBlock {DIV} at (0,208) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,236) size 784x56 [border: (2px solid #FF0000)]
RenderBR {BR} at (14,14) size 0x28
selection is CARET:
start: position 0 of child 1 {TEXT} of child 7 {DIV} of root {BODY}
RenderBlock {DIV} at (0,124) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 32x28
text run at (14,14) width 32: "foo"
- RenderBlock {DIV} at (0,180) size 784x28 [border: (2px solid #FF0000)]
- RenderBlock {DIV} at (0,208) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,180) size 784x56 [border: (2px solid #FF0000)]
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock {DIV} at (0,236) size 784x56 [border: (2px solid #FF0000)]
RenderBR {BR} at (14,14) size 0x28
selection is CARET:
-start: position 0 of child 7 {DIV} of root {BODY}
+start: position 0 of child 1 {BR} of child 7 {DIV} of root {BODY}
upstream: position 0 of child 7 {DIV} of root {BODY}
-downstream: position 1 of child 7 {DIV} of root {BODY}
+downstream: position 0 of child 1 {BR} of child 7 {DIV} of root {BODY}
text run at (14,14) width 32: "foo"
RenderBlock {DIV} at (0,180) size 784x56 [border: (2px solid #FF0000)]
RenderBR {BR} at (14,14) size 0x28
- RenderBlock {DIV} at (0,236) size 784x28 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (0,236) size 784x56 [border: (2px solid #FF0000)]
+ RenderBR {BR} at (14,14) size 0x28
selection is CARET:
-start: position 0 of child 9 {DIV} of root {BODY}
+start: position 0 of child 1 {BR} of child 9 {DIV} of root {BODY}
upstream: position 0 of child 9 {DIV} of root {BODY}
-downstream: position 1 of child 9 {DIV} of root {BODY}
+downstream: position 0 of child 1 {BR} of child 9 {DIV} of root {BODY}
RenderBlock (anonymous) at (0,40) size 784x28
RenderText {TEXT} at (0,0) size 31x28
text run at (0,0) width 31: "bar"
- RenderBlock {P} at (0,68) size 784x28 [border: (2px solid #0000FF)]
- RenderBlock {DIV} at (0,96) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {P} at (0,68) size 784x56 [border: (2px solid #0000FF)]
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock {DIV} at (0,124) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 34x28
text run at (14,14) width 34: "baz"
selection is CARET:
-start: position 0 of child 4 {P} of root {BODY}
+start: position 0 of child 1 {BR} of child 4 {P} of root {BODY}
upstream: position 0 of child 4 {P} of root {BODY}
-downstream: position 1 of child 4 {P} of root {BODY}
+downstream: position 0 of child 1 {BR} of child 4 {P} of root {BODY}
RenderBlock {P} at (0,92) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 32x28
text run at (14,14) width 32: "foo"
- RenderBlock {P} at (0,172) size 784x28 [border: (2px solid #0000FF)]
- RenderBlock (anonymous) at (0,200) size 784x28
+ RenderBlock {P} at (0,172) size 784x56 [border: (2px solid #0000FF)]
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock (anonymous) at (0,228) size 784x28
RenderBR {BR} at (0,0) size 0x28
- RenderBlock {P} at (0,252) size 784x56 [border: (2px solid #FF0000)]
+ RenderBlock {P} at (0,280) size 784x56 [border: (2px solid #FF0000)]
RenderText {TEXT} at (14,14) size 31x28
text run at (14,14) width 31: "bar"
selection is CARET:
RenderInline {SPAN} at (0,0) size 32x28
RenderText {TEXT} at (0,0) size 32x28
text run at (0,0) width 32: "foo"
- RenderBlock {P} at (0,152) size 784x28 [border: (2px solid #0000FF)]
- RenderBlock {P} at (0,180) size 784x56 [border: (2px solid #0000FF)]
+ RenderBlock {P} at (0,152) size 784x56 [border: (2px solid #0000FF)]
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock {P} at (0,208) size 784x56 [border: (2px solid #0000FF)]
RenderText {TEXT} at (14,14) size 31x28
text run at (14,14) width 31: "bar"
selection is CARET:
RenderInline {B} at (0,0) size 12x28
RenderText {TEXT} at (14,14) size 12x28
text run at (14,14) width 12: "x"
- RenderBR {BR} at (0,0) size 0x0
+ RenderBR {BR} at (0,0) size 0x0
RenderText {TEXT} at (14,42) size 31x28
text run at (14,42) width 31: "bar"
selection is CARET:
start: position 1 of child 1 {TEXT} of child 1 {B} of child 7 {P} of root {BODY}
upstream: position 1 of child 1 {TEXT} of child 1 {B} of child 7 {P} of root {BODY}
-downstream: position 0 of child 2 {BR} of child 7 {P} of root {BODY}
+downstream: position 0 of child 2 {BR} of child 1 {B} of child 7 {P} of root {BODY}
-layer at (0,0) size 800x660
+layer at (0,0) size 800x688
RenderCanvas at (0,0) size 800x600
-layer at (0,0) size 800x660
- RenderBlock {HTML} at (0,0) size 800x660
- RenderBody {BODY} at (8,8) size 784x628
+layer at (0,0) size 800x688
+ RenderBlock {HTML} at (0,0) size 800x688
+ RenderBody {BODY} at (8,8) size 784x656
RenderBlock (anonymous) at (0,0) size 784x84
RenderText {TEXT} at (0,0) size 766x56
text run at (0,0) width 766: "Test inserting paragraphs and managing typing style correctly: \"x\" under \"line "
RenderInline {B} at (0,0) size 56x28
RenderText {TEXT} at (14,14) size 56x28
text run at (14,14) width 56: "line 2"
- RenderBlock {P} at (0,360) size 784x28 [border: (2px solid #0000FF)]
- RenderBlock {P} at (0,412) size 784x56 [border: (2px solid #0000FF)]
+ RenderBlock {P} at (0,360) size 784x56 [border: (2px solid #0000FF)]
+ RenderInline {B} at (0,0) size 0x28
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock {P} at (0,440) size 784x56 [border: (2px solid #0000FF)]
RenderInline {B} at (0,0) size 12x28
RenderText {TEXT} at (14,14) size 12x28
text run at (14,14) width 12: "x"
- RenderBlock {P} at (0,492) size 784x56 [border: (2px solid #0000FF)]
+ RenderBlock {P} at (0,520) size 784x56 [border: (2px solid #0000FF)]
RenderBR {BR} at (14,14) size 0x28
- RenderBlock {P} at (0,572) size 784x56 [border: (2px solid #0000FF)]
+ RenderBlock {P} at (0,600) size 784x56 [border: (2px solid #0000FF)]
RenderText {TEXT} at (14,14) size 55x28
text run at (14,14) width 55: "line 3"
selection is CARET:
RenderText {TEXT} at (14,14) size 56x28
text run at (14,14) width 56: "line 1"
RenderBlock {P} at (0,228) size 784x56 [border: (2px solid #0000FF)]
- RenderText {TEXT} at (14,14) size 36x28
- text run at (14,14) width 36: "xxx"
- RenderBlock {P} at (0,308) size 784x28 [border: (2px solid #0000FF)]
- RenderBlock {P} at (0,360) size 784x56 [border: (2px solid #0000FF)]
+ RenderInline {B} at (0,0) size 36x28
+ RenderInline {SPAN} at (0,0) size 36x28
+ RenderText {TEXT} at (14,14) size 36x28
+ text run at (14,14) width 36: "xxx"
+ RenderBlock {P} at (0,308) size 784x56 [border: (2px solid #0000FF)]
+ RenderBR {BR} at (14,14) size 0x28
+ RenderBlock {P} at (0,388) size 784x56 [border: (2px solid #0000FF)]
RenderText {TEXT} at (14,14) size 36x28
text run at (14,14) width 36: "xxx"
selection is CARET:
--- /dev/null
+layer at (0,0) size 800x600
+ RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+ RenderBlock {HTML} at (0,0) size 800x600
+ RenderBody {BODY} at (8,8) size 784x584
+ RenderBlock {DIV} at (0,0) size 784x140 [border: (2px solid #0000FF)]
+ RenderText {TEXT} at (14,14) size 742x56
+ text run at (14,14) width 742: "You should see one \"x\" followed by two blank lines, then one more \"x\". The"
+ text run at (14,42) width 740: "blank lines in between the characters should be the same height. The second"
+ RenderInline {B} at (0,0) size 50x28
+ RenderText {TEXT} at (14,70) size 50x28
+ text run at (14,70) width 50: "must"
+ RenderText {TEXT} at (64,70) size 369x28
+ text run at (64,70) width 369: " be the same height as the first. See: <"
+ RenderInline {A} at (0,0) size 232x28 [color=#0000EE]
+ RenderText {TEXT} at (433,70) size 232x28
+ text run at (433,70) width 232: "rdar://problem/3959727"
+ RenderText {TEXT} at (665,70) size 665x56
+ text run at (665,70) width 14: ">"
+ text run at (14,98) width 557: "REGRESSION (Mail): Style not preserved on blank lines"
+ RenderBlock {DIV} at (0,164) size 784x276
+ RenderBlock {DIV} at (0,0) size 784x69
+ RenderInline {SPAN} at (0,0) size 30x69
+ RenderText {TEXT} at (0,0) size 30x69
+ text run at (0,0) width 30: "x"
+ RenderBlock {DIV} at (0,69) size 784x69
+ RenderInline {SPAN} at (0,0) size 0x69
+ RenderBR {BR} at (0,0) size 0x69
+ RenderBlock {DIV} at (0,138) size 784x69
+ RenderInline {SPAN} at (0,0) size 0x69
+ RenderBR {BR} at (0,0) size 0x69
+ RenderBlock {DIV} at (0,207) size 784x69
+ RenderInline {SPAN} at (0,0) size 30x69
+ RenderText {TEXT} at (0,0) size 30x69
+ text run at (0,0) width 30: "x"
+selection is CARET:
+start: position 0 of child 1 {BR} of child 1 {SPAN} of child 3 {DIV} of root {DIV}
+upstream: position 0 of child 3 {DIV} of root {DIV}
+downstream: position 0 of child 1 {BR} of child 1 {SPAN} of child 3 {DIV} of root {DIV}
--- /dev/null
+<html>
+<head>
+
+<style>
+.editing {
+ font-size: 16px;
+}
+.explanation {
+ border: 2px solid blue;
+ padding: 12px;
+ font-size: 24px;
+ margin-bottom: 24px;
+}
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+ moveSelectionForwardByCharacterCommand();
+ insertParagraphCommand();
+ insertParagraphCommand();
+ typeCharacterCommand();
+ for (i = 0; i < 3; i++)
+ extendSelectionBackwardByLineCommand();
+ fontSizeCommand("60px");
+ moveSelectionBackwardByCharacterCommand();
+ moveSelectionForwardByLineCommand();
+ insertParagraphCommand();
+}
+
+</script>
+
+<title>Editing Test</title>
+</head>
+<body>
+<div class="explanation">
+You should see one "x" followed by two blank lines, then one more "x". The blank lines in between the characters
+should be the same height. The second <b>must</b> be the same height as the first.
+See: <<a href="rdar://problem/3959727">rdar://problem/3959727</a>> REGRESSION (Mail): Style not preserved on blank lines
+</div>
+
+<div contenteditable="true" id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing">x</div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
--- /dev/null
+layer at (0,0) size 800x600
+ RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+ RenderBlock {HTML} at (0,0) size 800x600
+ RenderBody {BODY} at (8,8) size 784x584
+ RenderBlock {DIV} at (0,0) size 784x140 [border: (2px solid #0000FF)]
+ RenderText {TEXT} at (14,14) size 735x56
+ text run at (14,14) width 735: "You should see one \"x\" followed by two blank lines. The blank lines should"
+ text run at (14,42) width 194: "be the same height. "
+ text run at (208,42) width 160: "The second line "
+ RenderInline {B} at (0,0) size 50x28
+ RenderText {TEXT} at (368,42) size 50x28
+ text run at (368,42) width 50: "must"
+ RenderText {TEXT} at (418,42) size 753x56
+ text run at (418,42) width 349: " be the same height as the first. See:"
+ text run at (14,70) width 14: "<"
+ RenderInline {A} at (0,0) size 232x28 [color=#0000EE]
+ RenderText {TEXT} at (28,70) size 232x28
+ text run at (28,70) width 232: "rdar://problem/3959727"
+ RenderText {TEXT} at (260,70) size 711x56
+ text run at (260,70) width 465: "> REGRESSION (Mail): Style not preserved on"
+ text run at (14,98) width 106: "blank lines"
+ RenderBlock {DIV} at (0,164) size 784x207
+ RenderBlock {DIV} at (0,0) size 784x69
+ RenderInline {SPAN} at (0,0) size 30x69
+ RenderText {TEXT} at (0,0) size 30x69
+ text run at (0,0) width 30: "x"
+ RenderBlock {DIV} at (0,69) size 784x69
+ RenderInline {SPAN} at (0,0) size 0x69
+ RenderBR {BR} at (0,0) size 0x69
+ RenderBlock {DIV} at (0,138) size 784x69
+ RenderInline {SPAN} at (0,0) size 0x69
+ RenderBR {BR} at (0,0) size 0x69
+selection is CARET:
+start: position 0 of child 1 {BR} of child 1 {SPAN} of child 3 {DIV} of root {DIV}
+upstream: position 0 of child 3 {DIV} of root {DIV}
+downstream: position 0 of child 1 {BR} of child 1 {SPAN} of child 3 {DIV} of root {DIV}
--- /dev/null
+<html>
+<head>
+
+<style>
+.editing {
+ font-size: 16px;
+}
+.explanation {
+ border: 2px solid blue;
+ padding: 12px;
+ font-size: 24px;
+ margin-bottom: 24px;
+}
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+ moveSelectionForwardByCharacterCommand();
+ insertParagraphCommand();
+ insertParagraphCommand();
+ typeCharacterCommand();
+ for (i = 0; i < 3; i++)
+ extendSelectionBackwardByLineCommand();
+ fontSizeCommand("60px");
+ for (i = 0; i < 3; i++)
+ moveSelectionForwardByLineCommand();
+ deleteCommand();
+}
+
+</script>
+
+<title>Editing Test</title>
+</head>
+<body>
+<div class="explanation">
+You should see one "x" followed by two blank lines. The blank lines should be the same height.
+The second line <b>must</b> be the same height as the first.
+See: <<a href="rdar://problem/3959727">rdar://problem/3959727</a>> REGRESSION (Mail): Style not preserved on blank lines
+</div>
+
+<div contenteditable="true" id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing">x</div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
--- /dev/null
+layer at (0,0) size 800x600
+ RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+ RenderBlock {HTML} at (0,0) size 800x600
+ RenderBody {BODY} at (8,8) size 784x584
+ RenderBlock {DIV} at (0,0) size 784x140 [border: (2px solid #0000FF)]
+ RenderText {TEXT} at (14,14) size 742x56
+ text run at (14,14) width 742: "You should see one \"x\" followed by two blank lines, then one more \"x\". The"
+ text run at (14,42) width 376: "blank lines should be the same height. "
+ text run at (390,42) width 262: "The second and third lines "
+ RenderInline {B} at (0,0) size 50x28
+ RenderText {TEXT} at (652,42) size 50x28
+ text run at (652,42) width 50: "must"
+ RenderText {TEXT} at (702,42) size 753x56
+ text run at (702,42) width 65: " be the"
+ text run at (14,70) width 191: "same height. See: <"
+ RenderInline {A} at (0,0) size 232x28 [color=#0000EE]
+ RenderText {TEXT} at (205,70) size 232x28
+ text run at (205,70) width 232: "rdar://problem/3959727"
+ RenderText {TEXT} at (437,70) size 721x56
+ text run at (437,70) width 298: "> REGRESSION (Mail): Style"
+ text run at (14,98) width 273: "not preserved on blank lines"
+ RenderBlock {DIV} at (0,164) size 784x276
+ RenderBlock {DIV} at (0,0) size 784x69
+ RenderInline {SPAN} at (0,0) size 30x69
+ RenderText {TEXT} at (0,0) size 30x69
+ text run at (0,0) width 30: "x"
+ RenderBlock {DIV} at (0,69) size 784x69
+ RenderInline {SPAN} at (0,0) size 0x69
+ RenderBR {BR} at (0,0) size 0x69
+ RenderBlock {DIV} at (0,138) size 784x69
+ RenderInline {SPAN} at (0,0) size 0x69
+ RenderBR {BR} at (0,0) size 0x69
+ RenderBlock {DIV} at (0,207) size 784x69
+ RenderInline {SPAN} at (0,0) size 30x69
+ RenderText {TEXT} at (0,0) size 30x69
+ text run at (0,0) width 30: "x"
+selection is CARET:
+start: position 0 of child 1 {TEXT} of child 1 {SPAN} of child 4 {DIV} of root {DIV}
+upstream: position 0 of child 4 {DIV} of root {DIV}
+downstream: position 0 of child 1 {TEXT} of child 1 {SPAN} of child 4 {DIV} of root {DIV}
--- /dev/null
+<html>
+<head>
+
+<style>
+.editing {
+ font-size: 16px;
+}
+.explanation {
+ border: 2px solid blue;
+ padding: 12px;
+ font-size: 24px;
+ margin-bottom: 24px;
+}
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+ moveSelectionForwardByCharacterCommand();
+ insertParagraphCommand();
+ insertParagraphCommand();
+ typeCharacterCommand();
+ for (i = 0; i < 3; i++)
+ extendSelectionBackwardByLineCommand();
+ fontSizeCommand("60px");
+ for (i = 0; i < 3; i++)
+ moveSelectionForwardByLineCommand();
+ moveSelectionBackwardByCharacterCommand();
+ insertParagraphCommand();
+}
+
+</script>
+
+<title>Editing Test</title>
+</head>
+<body>
+<div class="explanation">
+You should see one "x" followed by two blank lines, then one more "x". The blank lines should be the same height.
+The second and third lines <b>must</b> be the same height.
+See: <<a href="rdar://problem/3959727">rdar://problem/3959727</a>> REGRESSION (Mail): Style not preserved on blank lines
+</div>
+
+<div contenteditable="true" id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing">x</div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
+2005-01-19 Ken Kocienda <kocienda@apple.com>
+
+ Reviewed by John
+
+ Fix for this bug:
+
+ <rdar://problem/3959727> REGRESSION (Mail): Style not preserved on blank lines
+
+ * khtml/editing/htmlediting.cpp:
+ (khtml::CompositeEditCommand::applyStyle):
+ (khtml::CompositeEditCommand::insertBlockPlaceholder): New function that unconditionally adds a block placeholder.
+ (khtml::CompositeEditCommand::insertBlockPlaceholderIfNeeded): Now returns bool based on whether
+ placeholder was added or not.
+ (khtml::CompositeEditCommand::removeBlockPlaceholderIfNeeded): Now searches all the descendents of a block
+ looking for a placeholder. The old code, which just looked at the last child of a node, started missing
+ once block placeholders became styled (which started happening with this patch).
+ (khtml::DeleteSelectionCommand::calculateTypingStyleAfterDelete): Now handles applying typing style
+ to a block placeholder at call time, rather than setting the typing style as a latent style that
+ might be applied later. This is an important part of the bug fix.
+ (khtml::DeleteSelectionCommand::doApply): Now uses bool return value from insertBlockPlaceholderIfNeeded()
+ and passes it along to calculateStyleBeforeInsertion, so the case where a block placeholder needs to
+ be styled can be detected.
+ (khtml::InsertParagraphSeparatorCommand::InsertParagraphSeparatorCommand): Changed the way this class
+ managed style. Before it would calculate and set typing style for the block added. This is not
+ sufficient. Added blocks need to styled immediately. Some name changes to instance variables in
+ this class due to the change to accommodate this change.
+ (khtml::InsertParagraphSeparatorCommand::~InsertParagraphSeparatorCommand): Name changes, as above.
+ (khtml::InsertParagraphSeparatorCommand::calculateStyleBeforeInsertion): Ditto.
+ (khtml::InsertParagraphSeparatorCommand::applyStyleAfterInsertion): Ditto.
+ (khtml::InsertParagraphSeparatorCommand::doApply): Ditto.
+ (khtml::ReplaceSelectionCommand::doApply): Improve check for testing when a placeholder
+ block can be removed in its entirety after the insertion.
+ * khtml/editing/htmlediting.h: Update header accordingly.
+ * khtml/khtml_part.cpp:
+ (KHTMLPart::selectionComputedStyle): Move position for computed style check downstream before
+ doing check when the position is in an empty block (this makes sure any style on any block
+ placeholder is accounted for).
+
+ New layout tests to check bug fix.
+
+ * layout-tests/editing/style/block-style-004-expected.txt: Added.
+ * layout-tests/editing/style/block-style-004.html: Added.
+ * layout-tests/editing/style/block-style-005-expected.txt: Added.
+ * layout-tests/editing/style/block-style-005.html: Added.
+ * layout-tests/editing/style/block-style-006-expected.txt: Added.
+ * layout-tests/editing/style/block-style-006.html: Added.
+
+ Results updated to reflect new block placeholder code.
+
+ * layout-tests/editing/inserting/insert-div-004-expected.txt
+ * layout-tests/editing/inserting/insert-div-005-expected.txt
+ * layout-tests/editing/inserting/insert-div-006-expected.txt
+ * layout-tests/editing/inserting/insert-div-008-expected.txt
+ * layout-tests/editing/inserting/insert-div-011-expected.txt
+ * layout-tests/editing/inserting/insert-div-012-expected.txt
+ * layout-tests/editing/inserting/insert-div-013-expected.txt
+ * layout-tests/editing/inserting/insert-div-014-expected.txt
+ * layout-tests/editing/inserting/insert-div-015-expected.txt
+ * layout-tests/editing/inserting/insert-div-016-expected.txt
+ * layout-tests/editing/inserting/insert-div-017-expected.txt
+ * layout-tests/editing/inserting/insert-div-018-expected.txt
+ * layout-tests/editing/inserting/insert-div-019-expected.txt
+ * layout-tests/editing/inserting/insert-div-021-expected.txt
+ * layout-tests/editing/inserting/insert-div-022-expected.txt
+ * layout-tests/editing/inserting/insert-div-023-expected.txt
+ * layout-tests/editing/inserting/insert-div-024-expected.txt
+
2005-01-19 David Hyatt <hyatt@apple.com>
Dont null-check the renderer before submitting, since a script can set it to display:none and still expect the
m_cmds.append(cmd);
}
+void CompositeEditCommand::applyStyle(CSSStyleDeclarationImpl *style, EditAction editingAction)
+{
+ EditCommandPtr cmd(new ApplyStyleCommand(document(), style, editingAction));
+ applyCommandToComposite(cmd);
+}
+
void CompositeEditCommand::insertParagraphSeparator()
{
EditCommandPtr cmd(new InsertParagraphSeparatorCommand(document()));
deleteInsignificantText(pos, end);
}
-void CompositeEditCommand::insertBlockPlaceholderIfNeeded(NodeImpl *node)
+void CompositeEditCommand::insertBlockPlaceholder(NodeImpl *node)
{
if (!node)
return;
+ ASSERT(node->renderer() && node->renderer()->isBlockFlow());
+
+ appendNode(createBlockPlaceholderElement(document()), node);
+}
+
+bool CompositeEditCommand::insertBlockPlaceholderIfNeeded(NodeImpl *node)
+{
+ if (!node)
+ return false;
+
document()->updateLayout();
RenderObject *renderer = node->renderer();
if (!renderer || !renderer->isBlockFlow())
- return;
+ return false;
if (renderer->height() > 0)
- return;
+ return false;
- appendNode(createBlockPlaceholderElement(document()), node);
+ insertBlockPlaceholder(node);
+ return true;
}
bool CompositeEditCommand::removeBlockPlaceholderIfNeeded(NodeImpl *node)
if (!renderer || !renderer->isBlockFlow())
return false;
- // This code will remove a block placeholder if it still is at the end
- // of a block, where we placed it in insertBlockPlaceholderIfNeeded().
- // Of course, a person who hand-edits an HTML file could move a
- // placeholder around, but it seems OK to be unconcerned about that case.
- NodeImpl *last = node->lastChild();
- if (last && last->isHTMLElement()) {
- ElementImpl *element = static_cast<ElementImpl *>(last);
- if (element->getAttribute(ATTR_CLASS) == blockPlaceholderClassString()) {
- removeNode(element);
- return true;
+ for (NodeImpl *checkMe = node; checkMe; checkMe = checkMe->traverseNextNode(node)) {
+ if (checkMe->isElementNode()) {
+ ElementImpl *element = static_cast<ElementImpl *>(checkMe);
+ if (element->getAttribute(ATTR_CLASS) == blockPlaceholderClassString()) {
+ removeNode(element);
+ return true;
+ }
}
}
+
return false;
}
m_endingPosition = Position(document()->documentElement(), 0);
}
-void DeleteSelectionCommand::calculateTypingStyleAfterDelete()
+void DeleteSelectionCommand::calculateTypingStyleAfterDelete(bool insertedPlaceholder)
{
// Compute the difference between the style before the delete and the style now
// after the delete has been done. Set this style on the part, so other editing
m_typingStyle->deref();
m_typingStyle = 0;
}
+ if (insertedPlaceholder && m_typingStyle) {
+ // Apply style to the placeholder. This makes sure that the single line in the
+ // paragraph has the right height, and that the paragraph takes on the style
+ // of the preceding line and retains it even if you click away, click back, and
+ // then start typing. In this case, the typing style is applied right now, and
+ // is not retained until the next typing action.
+ Position pastPlaceholder = endOfParagraph(VisiblePosition(m_endingPosition)).deepEquivalent();
+ setEndingSelection(Selection(m_endingPosition, pastPlaceholder));
+ applyStyle(m_typingStyle, EditActionUnspecified);
+ m_typingStyle->deref();
+ m_typingStyle = 0;
+ }
+ // Set m_typingStyle as the typing style.
+ // It's perfectly OK for m_typingStyle to be null.
document()->part()->setTypingStyle(m_typingStyle);
setTypingStyle(m_typingStyle);
}
// If the delete emptied a block, add in a placeholder so the block does not
// seem to disappear.
- insertBlockPlaceholderIfNeeded(m_endingPosition.node());
- calculateTypingStyleAfterDelete();
- setEndingSelection(m_endingPosition);
+ bool insertedPlaceholder = insertBlockPlaceholderIfNeeded(m_endingPosition.node());
+ calculateTypingStyleAfterDelete(insertedPlaceholder);
debugPosition("endingPosition ", m_endingPosition);
+ setEndingSelection(m_endingPosition);
clearTransientState();
rebalanceWhitespace();
}
// InsertParagraphSeparatorCommand
InsertParagraphSeparatorCommand::InsertParagraphSeparatorCommand(DocumentImpl *document)
- : CompositeEditCommand(document), m_fullTypingStyle(0)
+ : CompositeEditCommand(document), m_style(0)
{
}
InsertParagraphSeparatorCommand::~InsertParagraphSeparatorCommand()
{
derefNodesInList(clonedNodes);
- if (m_fullTypingStyle)
- m_fullTypingStyle->deref();
+ if (m_style)
+ m_style->deref();
}
bool InsertParagraphSeparatorCommand::preservesTypingStyle() const
return element;
}
-void InsertParagraphSeparatorCommand::setFullTypingStyleBeforeInsertion(const Position &pos)
+void InsertParagraphSeparatorCommand::calculateStyleBeforeInsertion(const Position &pos)
{
// FIXME: Improve typing style.
// See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
CSSComputedStyleDeclarationImpl *computedStyle = pos.computedStyle();
computedStyle->ref();
- if (m_fullTypingStyle)
- m_fullTypingStyle->deref();
- m_fullTypingStyle = computedStyle->copyInheritableProperties();
- m_fullTypingStyle->ref();
+ if (m_style)
+ m_style->deref();
+ m_style = computedStyle->copyInheritableProperties();
+ m_style->ref();
computedStyle->deref();
CSSMutableStyleDeclarationImpl *typingStyle = document()->part()->typingStyle();
if (typingStyle)
- m_fullTypingStyle->merge(typingStyle);
+ m_style->merge(typingStyle);
}
-void InsertParagraphSeparatorCommand::calculateAndSetTypingStyleAfterInsertion()
+void InsertParagraphSeparatorCommand::applyStyleAfterInsertion()
{
// FIXME: Improve typing style.
// See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
- if (!m_fullTypingStyle)
+ if (!m_style)
return;
CSSComputedStyleDeclarationImpl endingStyle(endingSelection().start().node());
- endingStyle.diff(m_fullTypingStyle);
- if (!m_fullTypingStyle->length()) {
- m_fullTypingStyle->deref();
- m_fullTypingStyle = 0;
+ endingStyle.diff(m_style);
+ if (!m_style->length()) {
+ m_style->deref();
+ m_style = 0;
+ }
+ else {
+ applyStyle(m_style);
}
- document()->part()->setTypingStyle(m_fullTypingStyle);
- setTypingStyle(m_fullTypingStyle);
}
void InsertParagraphSeparatorCommand::doApply()
NodeImpl *startBlockBeforeDelete = selection.start().node()->enclosingBlockFlowElement();
NodeImpl *endBlockBeforeDelete = selection.end().node()->enclosingBlockFlowElement();
bool doneAfterDelete = startBlockBeforeDelete != endBlockBeforeDelete;
- setFullTypingStyleBeforeInsertion(pos);
+ calculateStyleBeforeInsertion(pos);
deleteSelection(false, false);
if (doneAfterDelete) {
document()->updateLayout();
setEndingSelection(endingSelection().start().downstream());
rebalanceWhitespace();
- calculateAndSetTypingStyleAfterInsertion();
+ applyStyleAfterInsertion();
return;
}
pos = endingSelection().start();
}
- setFullTypingStyleBeforeInsertion(pos);
+ calculateStyleBeforeInsertion(pos);
// Find the start block.
NodeImpl *startNode = pos.node();
if (startBlockIsRoot) {
NodeImpl *extraBlock = createParagraphElement();
appendNode(extraBlock, startBlock);
- insertBlockPlaceholderIfNeeded(extraBlock);
+ insertBlockPlaceholder(extraBlock);
appendNode(blockToInsert, startBlock);
}
else {
insertNodeAfter(blockToInsert, startBlock);
}
- insertBlockPlaceholderIfNeeded(blockToInsert);
+ insertBlockPlaceholder(blockToInsert);
setEndingSelection(Position(blockToInsert, 0));
- calculateAndSetTypingStyleAfterInsertion();
+ applyStyleAfterInsertion();
return;
}
pos = pos.downstream(StayInBlock);
NodeImpl *refNode = isFirstInBlock && !startBlockIsRoot ? startBlock : pos.node();
insertNodeBefore(blockToInsert, refNode);
- insertBlockPlaceholderIfNeeded(blockToInsert);
+ insertBlockPlaceholder(blockToInsert);
+ setEndingSelection(Position(blockToInsert, 0));
+ applyStyleAfterInsertion();
setEndingSelection(pos);
- calculateAndSetTypingStyleAfterInsertion();
return;
}
LOG(Editing, "insert paragraph separator: last in block case");
NodeImpl *refNode = isLastInBlock && !startBlockIsRoot ? startBlock : pos.node();
insertNodeAfter(blockToInsert, refNode);
- insertBlockPlaceholderIfNeeded(blockToInsert);
+ insertBlockPlaceholder(blockToInsert);
setEndingSelection(Position(blockToInsert, 0));
- calculateAndSetTypingStyleAfterInsertion();
+ applyStyleAfterInsertion();
return;
}
setEndingSelection(Position(blockToInsert, 0));
rebalanceWhitespace();
- calculateAndSetTypingStyleAfterInsertion();
+ applyStyleAfterInsertion();
}
//------------------------------------------------------------------------------------------
completeHTMLReplacement(firstNodeInserted, lastNodeInserted);
}
- if (placeholderBlock && placeholderBlock->childNodeCount() == 0) {
- removeNode(placeholderBlock);
+ if (placeholderBlock) {
+ document()->updateLayout();
+ if (!placeholderBlock->renderer() || placeholderBlock->renderer()->height() == 0)
+ removeNode(placeholderBlock);
}
}
//
void appendNode(DOM::NodeImpl *appendChild, DOM::NodeImpl *parentNode);
void applyCommandToComposite(EditCommandPtr &);
+ void applyStyle(DOM::CSSStyleDeclarationImpl *style, EditAction editingAction=EditActionChangeAttributes);
void deleteKeyPressed();
void deleteSelection(bool smartDelete=false, bool mergeBlocksAfterDelete=true);
void deleteSelection(const Selection &selection, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
void deleteInsignificantText(const DOM::Position &start, const DOM::Position &end);
void deleteInsignificantTextDownstream(const DOM::Position &);
- void insertBlockPlaceholderIfNeeded(DOM::NodeImpl *);
+ void insertBlockPlaceholder(DOM::NodeImpl *);
+ bool insertBlockPlaceholderIfNeeded(DOM::NodeImpl *);
bool removeBlockPlaceholderIfNeeded(DOM::NodeImpl *);
void moveParagraphContentsToNewBlockIfNecessary(const DOM::Position &);
void fixupWhitespace();
void moveNodesAfterNode();
void calculateEndingPosition();
- void calculateTypingStyleAfterDelete();
+ void calculateTypingStyleAfterDelete(bool insertedPlaceholder);
void clearTransientState();
bool m_hasSelectionToDelete;
private:
DOM::ElementImpl *createParagraphElement();
- void setFullTypingStyleBeforeInsertion(const DOM::Position &);
- void calculateAndSetTypingStyleAfterInsertion();
+ void calculateStyleBeforeInsertion(const DOM::Position &);
+ void applyStyleAfterInsertion();
virtual bool preservesTypingStyle() const;
QPtrList<DOM::NodeImpl> ancestors;
QPtrList<DOM::NodeImpl> clonedNodes;
- DOM::CSSMutableStyleDeclarationImpl *m_fullTypingStyle;
+ DOM::CSSMutableStyleDeclarationImpl *m_style;
};
//------------------------------------------------------------------------------------------
return 0;
Range range(d->m_selection.toRange());
- Position pos(range.startContainer().handle(), range.startOffset());
+ Position pos = Position(range.startContainer().handle(), range.startOffset());
assert(pos.isNotNull());
+
+ // If the position is in an empty block, which this test checks, then move the position
+ // for the style check downstream. There may be a block placeholder in this block
+ // which has been styled, and we want to use that for the style calculation.
+ VisiblePosition visiblePos(pos);
+ if (isFirstVisiblePositionInBlock(visiblePos) && isLastVisiblePositionInBlock(visiblePos))
+ pos = pos.downstream(StayInBlock);
+
ElementImpl *elem = pos.element();
if (!elem)
return 0;