--- /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 784x156 [border: (2px solid #0000FF)]
+ RenderBlock {DIV} at (14,14) size 756x56
+ RenderText {TEXT} at (0,0) size 67x28
+ text run at (0,0) width 67: "Tests: "
+ RenderBR {BR} at (0,0) size 0x0
+ RenderText {TEXT} at (0,28) size 600x28
+ text run at (0,28) width 600: "Style checks performed on boundaries between style changes."
+ RenderBlock {DIV} at (14,86) size 756x56
+ RenderText {TEXT} at (0,0) size 189x28
+ text run at (0,0) width 189: "Expected Results: "
+ RenderBR {BR} at (0,0) size 0x0
+ RenderText {TEXT} at (0,28) size 442x28
+ text run at (0,28) width 442: "Should see this content in the red box below: "
+ RenderInline {B} at (0,0) size 25x28
+ RenderText {TEXT} at (442,28) size 25x28
+ text run at (442,28) width 25: "ab"
+ RenderText {TEXT} at (0,0) size 0x0
+ RenderBlock {DIV} at (0,180) size 784x32
+ RenderBlock {DIV} at (0,0) size 784x32 [border: (2px solid #FF0000)]
+ RenderInline {B} at (0,0) size 12x28
+ RenderText {TEXT} at (2,2) size 12x28
+ text run at (2,2) width 12: "a"
+ RenderInline {B} at (0,0) size 13x28
+ RenderText {TEXT} at (14,2) size 13x28
+ text run at (14,2) width 13: "b"
+selection is RANGE:
+start: position 0 of child 1 {TEXT} of child 2 {B} of child 1 {DIV} of root {DIV}
+upstream: position 1 of child 1 {TEXT} of child 1 {B} of child 1 {DIV} of root {DIV}
+downstream: position 0 of child 1 {TEXT} of child 2 {B} of child 1 {DIV} of root {DIV}
+end: position 1 of child 1 {TEXT} of child 2 {B} of child 1 {DIV} of root {DIV}
+upstream: position 1 of child 1 {TEXT} of child 2 {B} of child 1 {DIV} of root {DIV}
+downstream: position 1 of child 1 {TEXT} of child 2 {B} of child 1 {DIV} of root {DIV}
--- /dev/null
+<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 language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+ moveSelectionForwardByCharacterCommand();
+ extendSelectionForwardByCharacterCommand();
+ boldCommand();
+}
+
+</script>
+
+<title>Editing Test</title>
+</head>
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests:
+<br>
+Style checks performed on boundaries between style changes.
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see this content in the red box below: <b>ab</b>
+</div>
+</div>
+
+<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing"><b>a</b>b</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 784x156 [border: (2px solid #0000FF)]
+ RenderBlock {DIV} at (14,14) size 756x56
+ RenderText {TEXT} at (0,0) size 67x28
+ text run at (0,0) width 67: "Tests: "
+ RenderBR {BR} at (0,0) size 0x0
+ RenderText {TEXT} at (0,28) size 600x28
+ text run at (0,28) width 600: "Style checks performed on boundaries between style changes."
+ RenderBlock {DIV} at (14,86) size 756x56
+ RenderText {TEXT} at (0,0) size 189x28
+ text run at (0,0) width 189: "Expected Results: "
+ RenderBR {BR} at (0,0) size 0x0
+ RenderText {TEXT} at (0,28) size 442x28
+ text run at (0,28) width 442: "Should see this content in the red box below: "
+ RenderInline {B} at (0,0) size 25x28
+ RenderText {TEXT} at (442,28) size 25x28
+ text run at (442,28) width 25: "ab"
+ RenderText {TEXT} at (467,28) size 11x28
+ text run at (467,28) width 11: "c"
+ RenderBlock {DIV} at (0,180) size 784x32
+ RenderBlock {DIV} at (0,0) size 784x32 [border: (2px solid #FF0000)]
+ RenderInline {B} at (0,0) size 25x28
+ RenderText {TEXT} at (2,2) size 25x28
+ text run at (2,2) width 25: "ab"
+ RenderText {TEXT} at (27,2) size 11x28
+ text run at (27,2) width 11: "c"
+selection is CARET:
+start: position 2 of child 1 {TEXT} of child 1 {B} of child 1 {DIV} of root {DIV}
+upstream: position 2 of child 1 {TEXT} of child 1 {B} of child 1 {DIV} of root {DIV}
+downstream: position 0 of child 2 {TEXT} of child 1 {DIV} of root {DIV}
--- /dev/null
+<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 language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+ moveSelectionForwardByCharacterCommand();
+ typeCharacterCommand("b");
+}
+
+</script>
+
+<title>Editing Test</title>
+</head>
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests:
+<br>
+Style checks performed on boundaries between style changes.
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see this content in the red box below: <b>ab</b>c
+</div>
+</div>
+
+<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing"><b>a</b>c</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 784x156 [border: (2px solid #0000FF)]
+ RenderBlock {DIV} at (14,14) size 756x56
+ RenderText {TEXT} at (0,0) size 67x28
+ text run at (0,0) width 67: "Tests: "
+ RenderBR {BR} at (0,0) size 0x0
+ RenderText {TEXT} at (0,28) size 600x28
+ text run at (0,28) width 600: "Style checks performed on boundaries between style changes."
+ RenderBlock {DIV} at (14,86) size 756x56
+ RenderText {TEXT} at (0,0) size 189x28
+ text run at (0,0) width 189: "Expected Results: "
+ RenderBR {BR} at (0,0) size 0x0
+ RenderText {TEXT} at (0,28) size 442x28
+ text run at (0,28) width 442: "Should see this content in the red box below: "
+ RenderInline {B} at (0,0) size 12x28
+ RenderText {TEXT} at (442,28) size 12x28
+ text run at (442,28) width 12: "a"
+ RenderText {TEXT} at (454,28) size 23x28
+ text run at (454,28) width 23: "bc"
+ RenderBlock {DIV} at (0,180) size 784x32
+ RenderBlock {DIV} at (0,0) size 784x32 [border: (2px solid #FF0000)]
+ RenderInline {B} at (0,0) size 12x28
+ RenderText {TEXT} at (2,2) size 12x28
+ text run at (2,2) width 12: "a"
+ RenderText {TEXT} at (14,2) size 12x28
+ text run at (14,2) width 12: "b"
+ RenderText {TEXT} at (26,2) size 11x28
+ text run at (26,2) width 11: "c"
+selection is CARET:
+start: position 1 of child 2 {TEXT} of child 1 {DIV} of root {DIV}
+upstream: position 1 of child 2 {TEXT} of child 1 {DIV} of root {DIV}
+downstream: position 0 of child 3 {TEXT} of child 1 {DIV} of root {DIV}
--- /dev/null
+<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 language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+ moveSelectionForwardByCharacterCommand();
+ boldCommand();
+ typeCharacterCommand("b");
+}
+
+</script>
+
+<title>Editing Test</title>
+</head>
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests:
+<br>
+Style checks performed on boundaries between style changes.
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see this content in the red box below: <b>a</b>bc
+</div>
+</div>
+
+<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing"><b>a</b>c</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 784x212 [border: (2px solid #0000FF)]
+ RenderBlock {DIV} at (14,14) size 756x56
+ RenderText {TEXT} at (0,0) size 67x28
+ text run at (0,0) width 67: "Tests: "
+ RenderBR {BR} at (0,0) size 0x0
+ RenderText {TEXT} at (0,28) size 600x28
+ text run at (0,28) width 600: "Style checks performed on boundaries between style changes."
+ RenderBlock {DIV} at (14,86) size 756x112
+ RenderBlock (anonymous) at (0,0) size 756x56
+ RenderText {TEXT} at (0,0) size 189x28
+ text run at (0,0) width 189: "Expected Results: "
+ RenderBR {BR} at (0,0) size 0x0
+ RenderText {TEXT} at (0,28) size 436x28
+ text run at (0,28) width 436: "Should see this content in the red box below:"
+ RenderInline {B} at (0,0) size 0x0
+ RenderBlock (anonymous) at (0,56) size 756x56
+ RenderBlock {DIV} at (0,0) size 756x28
+ RenderText {TEXT} at (0,0) size 12x28
+ text run at (0,0) width 12: "a"
+ RenderBlock {DIV} at (0,28) size 756x28
+ RenderText {TEXT} at (0,0) size 13x28
+ text run at (0,0) width 13: "b"
+ RenderBlock (anonymous) at (0,112) size 756x0
+ RenderInline {B} at (0,0) size 0x0
+ RenderText {TEXT} at (0,0) size 0x0
+ RenderBlock {DIV} at (0,236) size 784x60
+ RenderBlock {DIV} at (0,0) size 784x60 [border: (2px solid #FF0000)]
+ RenderBlock {DIV} at (2,2) size 780x28
+ RenderInline {B} at (0,0) size 12x28
+ RenderText {TEXT} at (0,0) size 12x28
+ text run at (0,0) width 12: "a"
+ RenderBlock {DIV} at (2,30) size 780x28
+ RenderInline {B} at (0,0) size 13x28
+ RenderText {TEXT} at (0,0) size 13x28
+ text run at (0,0) width 13: "b"
+selection is RANGE:
+start: position 1 of child 1 {TEXT} of child 1 {B} of child 1 {DIV} of child 1 {DIV} of root {DIV}
+upstream: position 1 of child 1 {TEXT} of child 1 {B} of child 1 {DIV} of child 1 {DIV} of root {DIV}
+downstream: position 1 of child 1 {TEXT} of child 1 {B} of child 1 {DIV} of child 1 {DIV} of root {DIV}
+end: position 1 of child 1 {TEXT} of child 1 {B} of child 2 {DIV} of child 1 {DIV} of root {DIV}
+upstream: position 1 of child 1 {TEXT} of child 1 {B} of child 2 {DIV} of child 1 {DIV} of root {DIV}
+downstream: position 1 of child 1 {TEXT} of child 1 {B} of child 2 {DIV} of child 1 {DIV} of root {DIV}
--- /dev/null
+<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 language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+ moveSelectionForwardByCharacterCommand();
+ extendSelectionForwardByCharacterCommand();
+ extendSelectionForwardByCharacterCommand();
+ boldCommand();
+}
+
+</script>
+
+<title>Editing Test</title>
+</head>
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests:
+<br>
+Style checks performed on boundaries between style changes.
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see this content in the red box below: <b><div>a</div><div>b</div></b>
+</div>
+</div>
+
+<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing"><div><b>a</b></div><div>b</div></div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
+2005-02-23 Ken Kocienda <kocienda@apple.com>
+
+ Reviewed by Hyatt
+
+ Fix for this bug:
+
+ <rdar://problem/4017641> REGRESSION (Mail): you can only bold/unbold a selection starting from end of line once
+
+ Problem is with the way we figure out whether to add or remove a style based on
+ the current selection. In this case, the code is looking at the end of the
+ previous line, which is not bold, and deduces incorrectly that the operation is
+ a "make bold". Then the style code runs to make bold, but there is nothing on
+ the end of the previous line to embolden, so we get into a cycle where the same
+ thing happens each time cmd-b is hit.
+
+ * khtml/khtml_part.cpp:
+ (KHTMLPart::selectionComputedStyle): Call editingStartPosition() to get the right position for the font determination.
+ * khtml/xml/dom2_rangeimpl.cpp:
+ (DOM::RangeImpl::editingStartPosition): New helper function that "does the right thing" based on whether the
+ selection is a caret or a range, moving upstream for the former, and downstream for the latter.
+ * khtml/xml/dom2_rangeimpl.h:
+ * kwq/KWQKHTMLPart.mm:
+ (KWQKHTMLPart::fontForSelection): Call editingStartPosition() to get the right position for the font determination.
+
+ New tests:
+
+ * layout-tests/editing/style/style-boundary-001-expected.txt
+ * layout-tests/editing/style/style-boundary-001.html
+ * layout-tests/editing/style/style-boundary-002-expected.txt
+ * layout-tests/editing/style/style-boundary-002.html
+ * layout-tests/editing/style/style-boundary-003-expected.txt
+ * layout-tests/editing/style/style-boundary-003.html
+ * layout-tests/editing/style/style-boundary-004-expected.txt
+ * layout-tests/editing/style/style-boundary-004.html
+
2005-02-23 Richard Williamson <rjw@apple.com>
Fixed <rdar://problem/3985579> 8A367: Dashboard: Stock widget not visible when click remove to remove single char ticker symbol
return 0;
Range range(d->m_selection.toRange());
- 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, d->m_selection.startAffinity());
- if (isFirstVisiblePositionInBlock(visiblePos) && isLastVisiblePositionInBlock(visiblePos))
- pos = pos.downstream(StayInBlock);
+ Position pos = range.handle()->editingStartPosition();
ElementImpl *elem = pos.element();
if (!elem)
using khtml::createMarkup;
using khtml::RenderBlock;
using khtml::RenderObject;
+using khtml::VisiblePosition;
+using khtml::UPSTREAM;
namespace DOM {
return m_startContainer->traverseNextSibling();
}
+Position RangeImpl::editingStartPosition() const
+{
+ // This function is used to avoid bugs like:
+ // <rdar://problem/4017641> REGRESSION (Mail): you can only bold/unbold a selection starting from end of line once
+ // The issue here is that calculating the selection using the start of a range sometimes considers nodes that
+ // should not be considered. In the case of this bug, we need to move past the offset after the last character
+ // in a text node in order to make the right style calculation, so we do not wind up with a false "mixed"
+ // style.
+
+ Position pos(m_startContainer, m_startOffset);
+ if (pos.isNull())
+ return Position();
+
+ int exceptionCode = 0;
+ return collapsed(exceptionCode) ? VisiblePosition(pos, UPSTREAM).deepEquivalent() : pos.downstream(DoNotStayInBlock);
+}
+
NodeImpl *RangeImpl::pastEndNode() const
{
if (!m_endContainer)
NodeImpl *startNode() const;
NodeImpl *pastEndNode() const;
+ Position editingStartPosition() const;
+
#if APPLE_CHANGES
static Range createInstance (RangeImpl *impl);
#endif
Range r = d->m_selection.toRange();
RangeImpl *range = r.handle();
+ NodeImpl *startNode = range->editingStartPosition().node();
NodeImpl *pastEnd = range->pastEndNode();
- for (NodeImpl *n = range->startNode(); n != pastEnd; n = n->traverseNextNode()) {
+ for (NodeImpl *n = startNode; n != pastEnd; n = n->traverseNextNode()) {
RenderObject *renderer = n->renderer();
if (!renderer)
continue;