Title: [119884] trunk
Revision
119884
Author
[email protected]
Date
2012-06-08 18:56:42 -0700 (Fri, 08 Jun 2012)

Log Message

Caret is not rendered in empty inline contenteditable elements
https://bugs.webkit.org/show_bug.cgi?id=85793

Patch by Shezan Baig <[email protected]> on 2012-06-08
Reviewed by Ryosuke Niwa.

Source/WebCore:

Override localCaretRect in RenderInline. The implementation was almost
identical to localCaretRect in RenderBlock for empty block elements, so
I refactored RenderBlock::localCaretRect and moved the logic to a new
method 'localCaretRectForEmptyElement' in RenderBoxModelObject. The
implementation of 'localCaretRect' in RenderBlock and RenderInline both
use this helper method in RenderBoxModelObject.

Tests: editing/selection/caret-in-empty-inline-1.html
       editing/selection/caret-in-empty-inline-2.html

* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::localCaretRect):
Modified to use RenderBoxModelObject::localCaretRectForEmptyElement.
* rendering/RenderBoxModelObject.cpp:
(WebCore::RenderBoxModelObject::localCaretRectForEmptyElement):
(WebCore):
* rendering/RenderBoxModelObject.h:
(RenderBoxModelObject):
Add localCaretRectForEmptyElement helper method.
* rendering/RenderInline.cpp:
(WebCore::RenderInline::localCaretRect):
(WebCore):
* rendering/RenderInline.h:
(RenderInline):
Override localCaretRect using localCaretRectForEmptyElement.

LayoutTests:

Add test cases for caret in empty inline.

* editing/selection/caret-in-empty-inline-1-expected.txt: Added.
* editing/selection/caret-in-empty-inline-1.html: Added.
* editing/selection/caret-in-empty-inline-2-expected.txt: Added.
* editing/selection/caret-in-empty-inline-2.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (119883 => 119884)


--- trunk/LayoutTests/ChangeLog	2012-06-09 01:51:27 UTC (rev 119883)
+++ trunk/LayoutTests/ChangeLog	2012-06-09 01:56:42 UTC (rev 119884)
@@ -1,3 +1,17 @@
+2012-06-08  Shezan Baig  <[email protected]>
+
+        Caret is not rendered in empty inline contenteditable elements
+        https://bugs.webkit.org/show_bug.cgi?id=85793
+
+        Reviewed by Ryosuke Niwa.
+
+        Add test cases for caret in empty inline.
+
+        * editing/selection/caret-in-empty-inline-1-expected.txt: Added.
+        * editing/selection/caret-in-empty-inline-1.html: Added.
+        * editing/selection/caret-in-empty-inline-2-expected.txt: Added.
+        * editing/selection/caret-in-empty-inline-2.html: Added.
+
 2012-06-08  Mike West  <[email protected]>
 
         Excluding blob: and filesystem: schemes from the mixed content check.

Added: trunk/LayoutTests/editing/selection/caret-in-empty-inline-1-expected.txt (0 => 119884)


--- trunk/LayoutTests/editing/selection/caret-in-empty-inline-1-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/selection/caret-in-empty-inline-1-expected.txt	2012-06-09 01:56:42 UTC (rev 119884)
@@ -0,0 +1,13 @@
+Bug 85793: Caret is not rendered in empty inline contenteditable elements
+
+This test verifies that an empty inline contenteditable element gets a valid caret rect.
+
+
+PASS caretRect.left is 8
+PASS caretRect.top is 160
+PASS caretRect.width is 1
+PASS caretRect.height is 20
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/editing/selection/caret-in-empty-inline-1.html (0 => 119884)


--- trunk/LayoutTests/editing/selection/caret-in-empty-inline-1.html	                        (rev 0)
+++ trunk/LayoutTests/editing/selection/caret-in-empty-inline-1.html	2012-06-09 01:56:42 UTC (rev 119884)
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="" type="text/_javascript_"></script>
+<style>
+    body {
+        font: 20px Ahem;
+    }
+</style>
+</head>
+<body>
+<p> Bug <a href="" Caret is not rendered in empty inline contenteditable elements</p>
+<p>This test verifies that an empty inline contenteditable element gets a valid caret rect.</p>
+<span id="testInline" CONTENTEDITABLE></span><br>
+<div id="console"></div>
+</body>
+<script>
+    var testInline = document.getElementById("testInline");
+    getSelection().collapse(testInline, 0);
+    if (window.internals) {
+        var caretRect = internals.absoluteCaretBounds(document);
+        shouldBe("caretRect.left", "8");
+        shouldBe("caretRect.top", "160");
+        shouldBe("caretRect.width", "1");
+        shouldBe("caretRect.height", "20");
+    }
+</script>
+<script src="" type="text/_javascript_"></script>
+</html>

Added: trunk/LayoutTests/editing/selection/caret-in-empty-inline-2-expected.txt (0 => 119884)


--- trunk/LayoutTests/editing/selection/caret-in-empty-inline-2-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/selection/caret-in-empty-inline-2-expected.txt	2012-06-09 01:56:42 UTC (rev 119884)
@@ -0,0 +1,13 @@
+Bug 85793: Caret is not rendered in empty inline contenteditable elements
+
+This test verifies that an empty inline contenteditable element, placed after another inline element, gets a valid caret rect.
+
+Previous span
+PASS caretRect.left is 268
+PASS caretRect.top is 180
+PASS caretRect.width is 1
+PASS caretRect.height is 20
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/editing/selection/caret-in-empty-inline-2.html (0 => 119884)


--- trunk/LayoutTests/editing/selection/caret-in-empty-inline-2.html	                        (rev 0)
+++ trunk/LayoutTests/editing/selection/caret-in-empty-inline-2.html	2012-06-09 01:56:42 UTC (rev 119884)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="" type="text/_javascript_"></script>
+<style>
+    body {
+        font: 20px Ahem;
+    }
+</style>
+</head>
+<body>
+<p> Bug <a href="" Caret is not rendered in empty inline contenteditable elements</p>
+<p>This test verifies that an empty inline contenteditable element, placed after
+another inline element, gets a valid caret rect.</p>
+<span>Previous span</span><span id="testInline" CONTENTEDITABLE></span><br>
+<div id="console"></div>
+</body>
+<script>
+    var testInline = document.getElementById("testInline");
+    getSelection().collapse(testInline, 0);
+    if (window.internals) {
+        var caretRect = internals.absoluteCaretBounds(document);
+        shouldBe("caretRect.left", "268");
+        shouldBe("caretRect.top", "180");
+        shouldBe("caretRect.width", "1");
+        shouldBe("caretRect.height", "20");
+    }
+</script>
+<script src="" type="text/_javascript_"></script>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (119883 => 119884)


--- trunk/Source/WebCore/ChangeLog	2012-06-09 01:51:27 UTC (rev 119883)
+++ trunk/Source/WebCore/ChangeLog	2012-06-09 01:56:42 UTC (rev 119884)
@@ -1,3 +1,36 @@
+2012-06-08  Shezan Baig  <[email protected]>
+
+        Caret is not rendered in empty inline contenteditable elements
+        https://bugs.webkit.org/show_bug.cgi?id=85793
+
+        Reviewed by Ryosuke Niwa.
+
+        Override localCaretRect in RenderInline. The implementation was almost
+        identical to localCaretRect in RenderBlock for empty block elements, so
+        I refactored RenderBlock::localCaretRect and moved the logic to a new
+        method 'localCaretRectForEmptyElement' in RenderBoxModelObject. The
+        implementation of 'localCaretRect' in RenderBlock and RenderInline both
+        use this helper method in RenderBoxModelObject.
+
+        Tests: editing/selection/caret-in-empty-inline-1.html
+               editing/selection/caret-in-empty-inline-2.html
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::localCaretRect):
+        Modified to use RenderBoxModelObject::localCaretRectForEmptyElement.
+        * rendering/RenderBoxModelObject.cpp:
+        (WebCore::RenderBoxModelObject::localCaretRectForEmptyElement):
+        (WebCore):
+        * rendering/RenderBoxModelObject.h:
+        (RenderBoxModelObject):
+        Add localCaretRectForEmptyElement helper method.
+        * rendering/RenderInline.cpp:
+        (WebCore::RenderInline::localCaretRect):
+        (WebCore):
+        * rendering/RenderInline.h:
+        (RenderInline):
+        Override localCaretRect using localCaretRectForEmptyElement.
+
 2012-06-08  Mike West  <[email protected]>
 
         Treat blob: and filesystem: URLs generated via secure origins as secure.

Modified: trunk/Source/WebCore/rendering/RenderBlock.cpp (119883 => 119884)


--- trunk/Source/WebCore/rendering/RenderBlock.cpp	2012-06-09 01:51:27 UTC (rev 119883)
+++ trunk/Source/WebCore/rendering/RenderBlock.cpp	2012-06-09 01:56:42 UTC (rev 119884)
@@ -6489,80 +6489,17 @@
     if (firstChild())
         return RenderBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
 
-    // This is a special case:
-    // The element is not an inline element, and it's empty. So we have to
-    // calculate a fake position to indicate where objects are to be inserted.
-    
-    // FIXME: This does not take into account either :first-line or :first-letter
-    // However, as soon as some content is entered, the line boxes will be
-    // constructed and this kludge is not called any more. So only the caret size
-    // of an empty :first-line'd block is wrong. I think we can live with that.
-    RenderStyle* currentStyle = firstLineStyle();
-    LayoutUnit height = lineHeight(true, currentStyle->isHorizontalWritingMode() ? HorizontalLine : VerticalLine);
+    LayoutRect caretRect = localCaretRectForEmptyElement(width(), textIndentOffset());
 
-    enum CaretAlignment { alignLeft, alignRight, alignCenter };
-
-    CaretAlignment alignment = alignLeft;
-
-    switch (currentStyle->textAlign()) {
-        case TAAUTO:
-        case JUSTIFY:
-            if (!currentStyle->isLeftToRightDirection())
-                alignment = alignRight;
-            break;
-        case LEFT:
-        case WEBKIT_LEFT:
-            break;
-        case CENTER:
-        case WEBKIT_CENTER:
-            alignment = alignCenter;
-            break;
-        case RIGHT:
-        case WEBKIT_RIGHT:
-            alignment = alignRight;
-            break;
-        case TASTART:
-            if (!currentStyle->isLeftToRightDirection())
-                alignment = alignRight;
-            break;
-        case TAEND:
-            if (currentStyle->isLeftToRightDirection())
-                alignment = alignRight;
-            break;
-    }
-
-    LayoutUnit x = borderLeft() + paddingLeft();
-    LayoutUnit w = width();
-
-    switch (alignment) {
-        case alignLeft:
-            if (currentStyle->isLeftToRightDirection())
-                x += textIndentOffset();
-            break;
-        case alignCenter:
-            x = (x + w - (borderRight() + paddingRight())) / 2;
-            if (currentStyle->isLeftToRightDirection())
-                x += textIndentOffset() / 2;
-            else
-                x -= textIndentOffset() / 2;
-            break;
-        case alignRight:
-            x = w - (borderRight() + paddingRight()) - caretWidth;
-            if (!currentStyle->isLeftToRightDirection())
-                x -= textIndentOffset();
-            break;
-    }
-    x = min(x, w - borderRight() - paddingRight() - caretWidth);
-
     if (extraWidthToEndOfLine) {
         if (isRenderBlock()) {
-            *extraWidthToEndOfLine = w - (x + caretWidth);
+            *extraWidthToEndOfLine = width() - caretRect.maxX();
         } else {
             // FIXME: This code looks wrong.
             // myRight and containerRight are set up, but then clobbered.
             // So *extraWidthToEndOfLine will always be 0 here.
 
-            LayoutUnit myRight = x + caretWidth;
+            LayoutUnit myRight = caretRect.maxX();
             // FIXME: why call localToAbsoluteForContent() twice here, too?
             FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0));
 
@@ -6573,9 +6510,7 @@
         }
     }
 
-    LayoutUnit y = paddingTop() + borderTop();
-
-    return LayoutRect(x, y, caretWidth, height);
+    return caretRect;
 }
 
 void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)

Modified: trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp (119883 => 119884)


--- trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp	2012-06-09 01:51:27 UTC (rev 119883)
+++ trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp	2012-06-09 01:56:42 UTC (rev 119884)
@@ -2650,6 +2650,76 @@
         firstLetterRemainingTextMap->remove(this);
 }
 
+LayoutRect RenderBoxModelObject::localCaretRectForEmptyElement(LayoutUnit width, LayoutUnit textIndentOffset)
+{
+    ASSERT(!firstChild());
+
+    // FIXME: This does not take into account either :first-line or :first-letter
+    // However, as soon as some content is entered, the line boxes will be
+    // constructed and this kludge is not called any more. So only the caret size
+    // of an empty :first-line'd block is wrong. I think we can live with that.
+    RenderStyle* currentStyle = firstLineStyle();
+    LayoutUnit height = lineHeight(true, currentStyle->isHorizontalWritingMode() ? HorizontalLine : VerticalLine);
+
+    enum CaretAlignment { alignLeft, alignRight, alignCenter };
+
+    CaretAlignment alignment = alignLeft;
+
+    switch (currentStyle->textAlign()) {
+    case TAAUTO:
+    case JUSTIFY:
+        if (!currentStyle->isLeftToRightDirection())
+            alignment = alignRight;
+        break;
+    case LEFT:
+    case WEBKIT_LEFT:
+        break;
+    case CENTER:
+    case WEBKIT_CENTER:
+        alignment = alignCenter;
+        break;
+    case RIGHT:
+    case WEBKIT_RIGHT:
+        alignment = alignRight;
+        break;
+    case TASTART:
+        if (!currentStyle->isLeftToRightDirection())
+            alignment = alignRight;
+        break;
+    case TAEND:
+        if (currentStyle->isLeftToRightDirection())
+            alignment = alignRight;
+        break;
+    }
+
+    LayoutUnit x = borderLeft() + paddingLeft();
+    LayoutUnit maxX = width - borderRight() - paddingRight();
+
+    switch (alignment) {
+    case alignLeft:
+        if (currentStyle->isLeftToRightDirection())
+            x += textIndentOffset;
+        break;
+    case alignCenter:
+        x = (x + maxX) / 2;
+        if (currentStyle->isLeftToRightDirection())
+            x += textIndentOffset / 2;
+        else
+            x -= textIndentOffset / 2;
+        break;
+    case alignRight:
+        x = maxX - caretWidth;
+        if (!currentStyle->isLeftToRightDirection())
+            x -= textIndentOffset;
+        break;
+    }
+    x = min(x, max(maxX - caretWidth, ZERO_LAYOUT_UNIT));
+
+    LayoutUnit y = paddingTop() + borderTop();
+
+    return LayoutRect(x, y, caretWidth, height);
+}
+
 bool RenderBoxModelObject::shouldAntialiasLines(GraphicsContext* context)
 {
     // FIXME: We may want to not antialias when scaled by an integral value,

Modified: trunk/Source/WebCore/rendering/RenderBoxModelObject.h (119883 => 119884)


--- trunk/Source/WebCore/rendering/RenderBoxModelObject.h	2012-06-09 01:51:27 UTC (rev 119883)
+++ trunk/Source/WebCore/rendering/RenderBoxModelObject.h	2012-06-09 01:56:42 UTC (rev 119884)
@@ -237,6 +237,8 @@
     RenderBoxModelObject* continuation() const;
     void setContinuation(RenderBoxModelObject*);
 
+    LayoutRect localCaretRectForEmptyElement(LayoutUnit width, LayoutUnit textIndentOffset);
+
     static bool shouldAntialiasLines(GraphicsContext*);
 
 public:

Modified: trunk/Source/WebCore/rendering/RenderInline.cpp (119883 => 119884)


--- trunk/Source/WebCore/rendering/RenderInline.cpp	2012-06-09 01:51:27 UTC (rev 119883)
+++ trunk/Source/WebCore/rendering/RenderInline.cpp	2012-06-09 01:56:42 UTC (rev 119884)
@@ -233,6 +233,30 @@
     }
 }
 
+LayoutRect RenderInline::localCaretRect(InlineBox* inlineBox, int, LayoutUnit* extraWidthToEndOfLine)
+{
+    if (firstChild()) {
+        // This condition is possible if the RenderInline is at an editing boundary,
+        // i.e. the VisiblePosition is:
+        //   <RenderInline editingBoundary=true>|<RenderText> </RenderText></RenderInline>
+        // FIXME: need to figure out how to make this return a valid rect, note that
+        // there are no line boxes created in the above case.
+        return LayoutRect();
+    }
+
+    ASSERT_UNUSED(inlineBox, !inlineBox);
+
+    if (extraWidthToEndOfLine)
+        *extraWidthToEndOfLine = 0;
+
+    LayoutRect caretRect = localCaretRectForEmptyElement(borderAndPaddingWidth(), 0);
+
+    if (InlineBox* firstBox = firstLineBox())
+        caretRect.moveBy(roundedLayoutPoint(firstBox->topLeft()));
+
+    return caretRect;
+}
+
 void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
 {
     if (continuation())

Modified: trunk/Source/WebCore/rendering/RenderInline.h (119883 => 119884)


--- trunk/Source/WebCore/rendering/RenderInline.h	2012-06-09 01:51:27 UTC (rev 119883)
+++ trunk/Source/WebCore/rendering/RenderInline.h	2012-06-09 01:56:42 UTC (rev 119884)
@@ -84,6 +84,8 @@
     void setAlwaysCreateLineBoxes() { m_alwaysCreateLineBoxes = true; }
     void updateAlwaysCreateLineBoxes(bool fullLayout);
 
+    virtual LayoutRect localCaretRect(InlineBox*, int, LayoutUnit* extraWidthToEndOfLine) OVERRIDE;
+
 protected:
     virtual void willBeDestroyed();
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to