https://bugs.webkit.org/show_bug.cgi?id=48672
authorhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 2 Nov 2010 22:21:58 +0000 (22:21 +0000)
committerhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 2 Nov 2010 22:21:58 +0000 (22:21 +0000)
Reviewed by Dan Bernstein.

Make vertical glyph offset hit testing work with inline boxes.  This allows selection to paint
properly for vertical text (although gap-filling is still broken).

Refactored and cleaned up the writing mode flipping functions, and also did some cleanup to
better share code between hit testing and painting.

WebCore:

* rendering/InlineBox.cpp:
(WebCore::InlineBox::locationIncludingFlipping):
(WebCore::InlineBox::flipForWritingMode):
* rendering/InlineBox.h:
* rendering/InlineFlowBox.cpp:
(WebCore::InlineFlowBox::nodeAtPoint):
(WebCore::InlineFlowBox::paint):
(WebCore::InlineFlowBox::paintBoxDecorations):
(WebCore::InlineFlowBox::paintMask):
* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::selectionRect):
(WebCore::InlineTextBox::nodeAtPoint):
(WebCore::InlineTextBox::paint):
(WebCore::InlineTextBox::textPos):
(WebCore::InlineTextBox::offsetForPosition):
(WebCore::InlineTextBox::positionForOffset):
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::paintChildren):
(WebCore::RenderBlock::paintFloats):
(WebCore::RenderBlock::hitTestFloats):
(WebCore::RenderBlock::hitTestContents):
* rendering/RenderBox.cpp:
(WebCore::RenderBox::computeRectForRepaint):
(WebCore::RenderBox::flipForWritingMode):
(WebCore::RenderBox::locationOffsetIncludingFlipping):
* rendering/RenderBox.h:
* rendering/RenderInline.cpp:
(WebCore::RenderInline::clippedOverflowRectForRepaint):
* rendering/RenderLineBoxList.cpp:
(WebCore::RenderLineBoxList::rangeIntersectsRect):
(WebCore::RenderLineBoxList::anyLineIntersectsRect):
(WebCore::RenderLineBoxList::lineIntersectsDirtyRect):
(WebCore::RenderLineBoxList::paint):
(WebCore::RenderLineBoxList::hitTest):
* rendering/RenderLineBoxList.h:
* rendering/RenderText.cpp:
(WebCore::RenderText::positionForPoint):

LayoutTests:

* fast/repaint/selection-rl.html: Added.
* platform/mac/fast/repaint/selection-rl-expected.checksum: Added.
* platform/mac/fast/repaint/selection-rl-expected.png: Added.
* platform/mac/fast/repaint/selection-rl-expected.txt: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@71177 268f45cc-cd09-0410-ab3c-d52691b4dbfc

17 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/repaint/selection-rl.html [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/selection-rl-expected.checksum [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/selection-rl-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/selection-rl-expected.txt [new file with mode: 0644]
WebCore/ChangeLog
WebCore/rendering/InlineBox.cpp
WebCore/rendering/InlineBox.h
WebCore/rendering/InlineFlowBox.cpp
WebCore/rendering/InlineTextBox.cpp
WebCore/rendering/RenderBlock.cpp
WebCore/rendering/RenderBox.cpp
WebCore/rendering/RenderBox.h
WebCore/rendering/RenderInline.cpp
WebCore/rendering/RenderLineBoxList.cpp
WebCore/rendering/RenderLineBoxList.h
WebCore/rendering/RenderText.cpp

index 4dc1951..b423e31 100644 (file)
@@ -1,3 +1,20 @@
+2010-11-02  David Hyatt  <hyatt@apple.com>
+
+        Reviewed by Dan Bernstein.
+
+        https://bugs.webkit.org/show_bug.cgi?id=48672
+        
+        Make vertical glyph offset hit testing work with inline boxes.  This allows selection to paint
+        properly for vertical text (although gap-filling is still broken).
+        
+        Refactored and cleaned up the writing mode flipping functions, and also did some cleanup to
+        better share code between hit testing and painting.
+
+        * fast/repaint/selection-rl.html: Added.
+        * platform/mac/fast/repaint/selection-rl-expected.checksum: Added.
+        * platform/mac/fast/repaint/selection-rl-expected.png: Added.
+        * platform/mac/fast/repaint/selection-rl-expected.txt: Added.
+
 2010-11-02  Mihai Parparita  <mihaip@chromium.org>
 
         Reviewed by Adam Barth.
diff --git a/LayoutTests/fast/repaint/selection-rl.html b/LayoutTests/fast/repaint/selection-rl.html
new file mode 100644 (file)
index 0000000..4c5ab0b
--- /dev/null
@@ -0,0 +1,29 @@
+<!doctype html>
+<html>
+<head>
+<script src="resources/repaint.js"></script>
+<script>
+function repaintTest() {
+    if (eventSender) {
+        eventSender.mouseMoveTo(790, 40);
+        eventSender.mouseDown();
+        eventSender.mouseMoveTo(790, 40);
+        eventSender.mouseMoveTo(790, 120);
+        eventSender.mouseUp();
+    }
+}
+</script>
+
+</head>
+<body style="-webkit-writing-mode:vertical-rl" onload="runRepaintTest()">
+<span>Testing both hit testing</span> and painting of selection.<br>
+Testing both hit testing and painting of selection.<br>
+Testing both hit testing and painting of selection.<br>
+Testing both hit testing and painting of selection.<br>
+Testing both hit testing and painting of selection.<br>
+Testing both hit testing and painting of selection.<br>
+Testing both hit testing and painting of selection.<br>
+Testing both hit testing and painting of selection.<br>
+Testing both hit testing and painting of selection.<br>
+Testing both hit testing and painting of selection.<br>
+</body>
diff --git a/LayoutTests/platform/mac/fast/repaint/selection-rl-expected.checksum b/LayoutTests/platform/mac/fast/repaint/selection-rl-expected.checksum
new file mode 100644 (file)
index 0000000..f49c8d9
--- /dev/null
@@ -0,0 +1 @@
+3b62e931769e73b3d2d9431ae2c44036
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/fast/repaint/selection-rl-expected.png b/LayoutTests/platform/mac/fast/repaint/selection-rl-expected.png
new file mode 100644 (file)
index 0000000..632f86d
Binary files /dev/null and b/LayoutTests/platform/mac/fast/repaint/selection-rl-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/repaint/selection-rl-expected.txt b/LayoutTests/platform/mac/fast/repaint/selection-rl-expected.txt
new file mode 100644 (file)
index 0000000..98ef66f
--- /dev/null
@@ -0,0 +1,40 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (604,0) size 196x600
+  RenderBlock {HTML} at (0,0) size 196x600
+    RenderBody {BODY} at (8,8) size 180x584
+      RenderInline {SPAN} at (0,0) size 18x144
+        RenderText {#text} at (0,0) size 18x144
+          text run at (0,0) width 144: "Testing both hit testing"
+      RenderText {#text} at (0,144) size 18x162
+        text run at (0,144) width 162: " and painting of selection."
+      RenderBR {BR} at (0,306) size 18x0
+      RenderText {#text} at (18,0) size 18x306
+        text run at (18,0) width 306: "Testing both hit testing and painting of selection."
+      RenderBR {BR} at (18,306) size 18x0
+      RenderText {#text} at (36,0) size 18x306
+        text run at (36,0) width 306: "Testing both hit testing and painting of selection."
+      RenderBR {BR} at (36,306) size 18x0
+      RenderText {#text} at (54,0) size 18x306
+        text run at (54,0) width 306: "Testing both hit testing and painting of selection."
+      RenderBR {BR} at (54,306) size 18x0
+      RenderText {#text} at (72,0) size 18x306
+        text run at (72,0) width 306: "Testing both hit testing and painting of selection."
+      RenderBR {BR} at (72,306) size 18x0
+      RenderText {#text} at (90,0) size 18x306
+        text run at (90,0) width 306: "Testing both hit testing and painting of selection."
+      RenderBR {BR} at (90,306) size 18x0
+      RenderText {#text} at (108,0) size 18x306
+        text run at (108,0) width 306: "Testing both hit testing and painting of selection."
+      RenderBR {BR} at (108,306) size 18x0
+      RenderText {#text} at (126,0) size 18x306
+        text run at (126,0) width 306: "Testing both hit testing and painting of selection."
+      RenderBR {BR} at (126,306) size 18x0
+      RenderText {#text} at (144,0) size 18x306
+        text run at (144,0) width 306: "Testing both hit testing and painting of selection."
+      RenderBR {BR} at (144,306) size 18x0
+      RenderText {#text} at (162,0) size 18x306
+        text run at (162,0) width 306: "Testing both hit testing and painting of selection."
+      RenderBR {BR} at (162,306) size 18x0
+selection start: position 5 of child 0 {#text} of child 1 {SPAN} of body
+selection end:   position 19 of child 0 {#text} of child 1 {SPAN} of body
index 48e64d6..2d3ee3d 100644 (file)
@@ -1,3 +1,53 @@
+2010-11-02  David Hyatt  <hyatt@apple.com>
+
+        Reviewed by Dan Bernstein.
+
+        https://bugs.webkit.org/show_bug.cgi?id=48672
+        
+        Make vertical glyph offset hit testing work with inline boxes.  This allows selection to paint
+        properly for vertical text (although gap-filling is still broken).
+        
+        Refactored and cleaned up the writing mode flipping functions, and also did some cleanup to
+        better share code between hit testing and painting.
+
+        * rendering/InlineBox.cpp:
+        (WebCore::InlineBox::locationIncludingFlipping):
+        (WebCore::InlineBox::flipForWritingMode):
+        * rendering/InlineBox.h:
+        * rendering/InlineFlowBox.cpp:
+        (WebCore::InlineFlowBox::nodeAtPoint):
+        (WebCore::InlineFlowBox::paint):
+        (WebCore::InlineFlowBox::paintBoxDecorations):
+        (WebCore::InlineFlowBox::paintMask):
+        * rendering/InlineTextBox.cpp:
+        (WebCore::InlineTextBox::selectionRect):
+        (WebCore::InlineTextBox::nodeAtPoint):
+        (WebCore::InlineTextBox::paint):
+        (WebCore::InlineTextBox::textPos):
+        (WebCore::InlineTextBox::offsetForPosition):
+        (WebCore::InlineTextBox::positionForOffset):
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::paintChildren):
+        (WebCore::RenderBlock::paintFloats):
+        (WebCore::RenderBlock::hitTestFloats):
+        (WebCore::RenderBlock::hitTestContents):
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::computeRectForRepaint):
+        (WebCore::RenderBox::flipForWritingMode):
+        (WebCore::RenderBox::locationOffsetIncludingFlipping):
+        * rendering/RenderBox.h:
+        * rendering/RenderInline.cpp:
+        (WebCore::RenderInline::clippedOverflowRectForRepaint):
+        * rendering/RenderLineBoxList.cpp:
+        (WebCore::RenderLineBoxList::rangeIntersectsRect):
+        (WebCore::RenderLineBoxList::anyLineIntersectsRect):
+        (WebCore::RenderLineBoxList::lineIntersectsDirtyRect):
+        (WebCore::RenderLineBoxList::paint):
+        (WebCore::RenderLineBoxList::hitTest):
+        * rendering/RenderLineBoxList.h:
+        * rendering/RenderText.cpp:
+        (WebCore::RenderText::positionForPoint):
+
 2010-11-02  Adam Barth  <abarth@webkit.org>
 
         Reviewed by Eric Seidel.
index fa3bb66..b8f0ce1 100644 (file)
@@ -279,23 +279,29 @@ int InlineBox::placeEllipsisBox(bool, int, int, int, bool&)
     return -1;
 }
 
-void InlineBox::adjustForFlippedBlocksWritingMode(IntPoint& point)
+IntPoint InlineBox::locationIncludingFlipping()
 {
     if (!renderer()->style()->isFlippedBlocksWritingMode())
-        return;
-    
+        return IntPoint(x(), y());
     RenderBlock* block = root()->block();
     if (block->style()->isHorizontalWritingMode())
-        point.setY(block->height() - height() - point.y());
+        return IntPoint(x(), block->height() - height() - y());
     else
-        point.setX(block->width() - width() - point.x());
+        return IntPoint(block->width() - width() - x(), y());
 }
 
-void InlineBox::adjustForFlippedBlocksWritingMode(IntRect& rect)
+void InlineBox::flipForWritingMode(IntRect& rect)
 {
     if (!renderer()->style()->isFlippedBlocksWritingMode())
         return;
-    return root()->block()->adjustForFlippedBlocksWritingMode(rect);
+    root()->block()->flipForWritingMode(rect);
+}
+
+IntPoint InlineBox::flipForWritingMode(const IntPoint& point)
+{
+    if (!renderer()->style()->isFlippedBlocksWritingMode())
+        return point;
+    return root()->block()->flipForWritingMode(point);
 }
 
 } // namespace WebCore
index a55bf80..72e5534 100644 (file)
@@ -290,8 +290,9 @@ public:
         return 0;
     }
 
-    void adjustForFlippedBlocksWritingMode(IntPoint&);
-    void adjustForFlippedBlocksWritingMode(IntRect&);
+    IntPoint locationIncludingFlipping();
+    void flipForWritingMode(IntRect&);
+    IntPoint flipForWritingMode(const IntPoint&);
 
 private:
     InlineBox* m_next; // The next element on the same line as us.
index a04c16e..1187a8b 100644 (file)
@@ -654,7 +654,7 @@ void InlineFlowBox::computeBlockDirectionOverflow(int lineTop, int lineBottom, b
 bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
 {
     IntRect overflowRect(visibleOverflowRect());
-    adjustForFlippedBlocksWritingMode(overflowRect);
+    flipForWritingMode(overflowRect);
     overflowRect.move(tx, ty);
     if (!overflowRect.intersects(result.rectForPoint(x, y)))
         return false;
@@ -668,12 +668,11 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
     }
 
     // Now check ourselves.
-    IntPoint boxOrigin(m_x, m_y);
-    adjustForFlippedBlocksWritingMode(boxOrigin);
+    IntPoint boxOrigin = locationIncludingFlipping();
     boxOrigin.move(tx, ty);
     IntRect rect(boxOrigin, IntSize(width(), height()));
     if (visibleToHitTesting() && rect.intersects(result.rectForPoint(x, y))) {
-        renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); // Don't add in m_x or m_y here, we want coords in the containing block's space.
+        renderer()->updateHitTestResult(result, flipForWritingMode(IntPoint(x - tx, y - ty))); // Don't add in m_x or m_y here, we want coords in the containing block's space.
         if (!result.addNodeToRectBasedTestResult(renderer()->node(), x, y, rect))
             return true;
     }
@@ -685,7 +684,7 @@ void InlineFlowBox::paint(PaintInfo& paintInfo, int tx, int ty)
 {
     IntRect overflowRect(visibleOverflowRect());
     overflowRect.inflate(renderer()->maximalOutlineSize(paintInfo.phase));
-    adjustForFlippedBlocksWritingMode(overflowRect);
+    flipForWritingMode(overflowRect);
     overflowRect.move(tx, ty);
     
     if (!paintInfo.rect.intersects(overflowRect))
@@ -817,10 +816,10 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
     }
     
     // Move x/y to our coordinates.
-    IntPoint localPoint(x, y);
-    adjustForFlippedBlocksWritingMode(localPoint);
-    tx += localPoint.x();
-    ty += localPoint.y();
+    IntRect localRect(x, y, w, h);
+    flipForWritingMode(localRect);
+    tx += localRect.x();
+    ty += localRect.y();
     
     GraphicsContext* context = paintInfo.context;
     
@@ -900,10 +899,10 @@ void InlineFlowBox::paintMask(PaintInfo& paintInfo, int tx, int ty)
     }
     
     // Move x/y to our coordinates.
-    IntPoint localPoint(x, y);
-    adjustForFlippedBlocksWritingMode(localPoint);
-    tx += localPoint.x();
-    ty += localPoint.y();
+    IntRect localRect(x, y, w, h);
+    flipForWritingMode(localRect);
+    tx += localRect.x();
+    ty += localRect.y();
 
     const NinePieceImage& maskNinePieceImage = renderer()->style()->maskBoxImage();
     StyleImage* maskBoxImage = renderer()->style()->maskBoxImage().image();
index f29805e..1193288 100644 (file)
@@ -166,7 +166,9 @@ IntRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos)
     int width = isHorizontal() ? logicalWidth : selHeight;
     int height = isHorizontal() ? selHeight : logicalWidth;
     
-    return IntRect(topPoint, IntSize(width, height));
+    IntRect result = IntRect(topPoint, IntSize(width, height));
+    flipForWritingMode(result);
+    return result;
 }
 
 void InlineTextBox::deleteLine(RenderArena* arena)
@@ -309,12 +311,11 @@ bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, in
     if (isLineBreak())
         return false;
 
-    IntPoint boxOrigin(m_x, m_y);
-    adjustForFlippedBlocksWritingMode(boxOrigin);
+    IntPoint boxOrigin = locationIncludingFlipping();
     boxOrigin.move(tx, ty);
     IntRect rect(boxOrigin, IntSize(width(), height()));
     if (m_truncation != cFullTruncation && visibleToHitTesting() && rect.intersects(result.rectForPoint(x, y))) {
-        renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
+        renderer()->updateHitTestResult(result, flipForWritingMode(IntPoint(x - tx, y - ty)));
         if (!result.addNodeToRectBasedTestResult(renderer()->node(), x, y, rect))
             return true;
     }
@@ -440,12 +441,10 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
     
     ty -= styleToUse->isHorizontalWritingMode() ? 0 : logicalHeight();
 
-    IntPoint boxOrigin(m_x, m_y);
-    adjustForFlippedBlocksWritingMode(boxOrigin);
-    boxOrigin.move(tx, ty);
-    
-    IntPoint textOrigin = IntPoint(boxOrigin.x(), boxOrigin.y() + styleToUse->font().ascent());
+    IntPoint boxOrigin = locationIncludingFlipping();
+    boxOrigin.move(tx, ty);    
     IntRect boxRect(boxOrigin, IntSize(logicalWidth(), logicalHeight()));
+    IntPoint textOrigin = IntPoint(boxOrigin.x(), boxOrigin.y() + styleToUse->font().ascent());
 
     if (!isHorizontal()) {
         context->save();
@@ -1083,15 +1082,13 @@ unsigned InlineTextBox::caretMaxRenderedOffset() const
 
 int InlineTextBox::textPos() const
 {
-    if (x() == 0)
+    if (logicalLeft() == 0)
         return 0;
-        
     RenderBlock* blockElement = renderer()->containingBlock();
-    return !isLeftToRightDirection() ? x() - blockElement->borderRight() - blockElement->paddingRight()
-                      : x() - blockElement->borderLeft() - blockElement->paddingLeft();
+    return logicalLeft() - blockElement->borderStart() - blockElement->paddingStart();
 }
 
-int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const
+int InlineTextBox::offsetForPosition(int lineOffset, bool includePartialGlyphs) const
 {
     if (isLineBreak())
         return 0;
@@ -1100,7 +1097,7 @@ int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const
     RenderStyle* style = text->style(m_firstLine);
     const Font* f = &style->font();
     return f->offsetForPosition(TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()),
-                                _x - m_x, includePartialGlyphs);
+                                lineOffset - logicalLeft(), includePartialGlyphs);
 }
 
 int InlineTextBox::positionForOffset(int offset) const
@@ -1109,7 +1106,7 @@ int InlineTextBox::positionForOffset(int offset) const
     ASSERT(offset <= m_start + m_len);
 
     if (isLineBreak())
-        return m_x;
+        return logicalLeft();
 
     RenderText* text = toRenderText(renderer());
     const Font& f = text->style(m_firstLine)->font();
@@ -1117,7 +1114,7 @@ int InlineTextBox::positionForOffset(int offset) const
     int to = !isLeftToRightDirection() ? m_len : offset - m_start;
     // FIXME: Do we need to add rightBearing here?
     return enclosingIntRect(f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride),
-                                                   IntPoint(m_x, 0), 0, from, to)).right();
+                                                   IntPoint(logicalLeft(), 0), 0, from, to)).right();
 }
 
 bool InlineTextBox::containsCaretOffset(int offset) const
index 0644586..9e89930 100644 (file)
@@ -2268,8 +2268,7 @@ void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty)
             }
         }
 
-        IntPoint childPoint(tx, ty);
-        adjustForFlippedBlocksWritingMode(child, childPoint, ParentToChildFlippingAdjustment);
+        IntPoint childPoint = flipForWritingMode(child, IntPoint(tx, ty), ParentToChildFlippingAdjustment);
         if (!child->hasSelfPaintingLayer() && !child->isFloating())
             child->paint(info, childPoint.x(), childPoint.y());
 
@@ -2404,9 +2403,7 @@ void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preserv
         if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) {
             PaintInfo currentPaintInfo(paintInfo);
             currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
-            IntPoint childPoint(tx + r->left() + r->m_renderer->marginLeft() - r->m_renderer->x(),
-                                ty + r->top() + r->m_renderer->marginTop() - r->m_renderer->y());
-            adjustForFlippedBlocksWritingMode(r->m_renderer, childPoint, ParentToChildFlippingAdjustment);
+            IntPoint childPoint = flipForWritingMode(r->m_renderer, IntPoint(tx + r->left() + r->m_renderer->marginLeft() - r->m_renderer->x(), ty + r->top() + r->m_renderer->marginTop() - r->m_renderer->y()), ParentToChildFlippingAdjustment);
             r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y());
             if (!preservePhase) {
                 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
@@ -4152,8 +4149,7 @@ bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& re
         if (floatingObject->m_shouldPaint && !floatingObject->m_renderer->hasSelfPaintingLayer()) {
             int xOffset = floatingObject->left() + floatingObject->m_renderer->marginLeft() - floatingObject->m_renderer->x();
             int yOffset =  floatingObject->top() + floatingObject->m_renderer->marginTop() - floatingObject->m_renderer->y();
-            IntPoint childPoint(tx + xOffset, ty + yOffset);
-            adjustForFlippedBlocksWritingMode(floatingObject->m_renderer, childPoint, ParentToChildFlippingAdjustment);
+            IntPoint childPoint= flipForWritingMode(floatingObject->m_renderer, IntPoint(tx + xOffset, ty + yOffset), ParentToChildFlippingAdjustment);
             if (floatingObject->m_renderer->hitTest(request, result, IntPoint(x, y), childPoint.x(), childPoint.y())) {
                 updateHitTestResult(result, IntPoint(x - childPoint.x(), y - childPoint.y()));
                 return true;
@@ -4210,8 +4206,7 @@ bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult&
         if (hitTestAction == HitTestChildBlockBackgrounds)
             childHitTest = HitTestChildBlockBackground;
         for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) {
-            IntPoint childPoint(tx, ty);
-            adjustForFlippedBlocksWritingMode(child, childPoint, ParentToChildFlippingAdjustment);
+            IntPoint childPoint = flipForWritingMode(child, IntPoint(tx, ty), ParentToChildFlippingAdjustment);
             if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, x, y, childPoint.x(), childPoint.y(), childHitTest))
                 return true;
         }
index 45bca17..625a643 100644 (file)
@@ -1428,7 +1428,7 @@ void RenderBox::computeRectForRepaint(RenderBoxModelObject* repaintContainer, In
     }
     
     if (o->isBox())
-        toRenderBox(o)->adjustForFlippedBlocksWritingMode(rect);
+        toRenderBox(o)->flipForWritingMode(rect);
     
     o->computeRectForRepaint(repaintContainer, rect, fixed);
 }
@@ -3201,35 +3201,41 @@ void RenderBox::blockDirectionOverflow(bool isLineHorizontal, int& logicalTopLay
     } 
 }
 
-void RenderBox::adjustForFlippedBlocksWritingMode(RenderBox* child, IntPoint& point, FlippingAdjustment adjustment)
+IntPoint RenderBox::flipForWritingMode(RenderBox* child, const IntPoint& point, FlippingAdjustment adjustment)
 {
     if (!style()->isFlippedBlocksWritingMode())
-        return;
+        return point;
     
     // The child is going to add in its x() and y(), so we have to make sure it ends up in
     // the right place.
     if (style()->isHorizontalWritingMode())
-        point.move(0, height() - child->height() - child->y() - (adjustment == ParentToChildFlippingAdjustment ? child->y() : 0));
-    else
-        point.move(width() - child->width() - child->x() - (adjustment == ParentToChildFlippingAdjustment ? child->x() : 0), 0);
+        return IntPoint(point.x(), point.y() + height() - child->height() - child->y() - (adjustment == ParentToChildFlippingAdjustment ? child->y() : 0));
+    return IntPoint(point.x() + width() - child->width() - child->x() - (adjustment == ParentToChildFlippingAdjustment ? child->x() : 0), point.y());
 }
 
-void RenderBox::adjustForFlippedBlocksWritingMode(IntRect& rect)
+void RenderBox::flipForWritingMode(IntRect& rect)
 {
     if (!style()->isFlippedBlocksWritingMode())
         return;
-    
+
     if (style()->isHorizontalWritingMode())
         rect.setY(height() - rect.bottom());
     else
         rect.setX(width() - rect.right());
 }
 
-int RenderBox::convertFromFlippedWritingMode(int logicalPosition)
+int RenderBox::flipForWritingMode(int position)
+{
+    if (!style()->isFlippedBlocksWritingMode())
+        return position;
+    return logicalHeight() - position;
+}
+
+IntPoint RenderBox::flipForWritingMode(const IntPoint& position)
 {
     if (!style()->isFlippedBlocksWritingMode())
-        return logicalPosition;
-    return logicalHeight() - logicalPosition;
+        return position;
+    return style()->isHorizontalWritingMode() ? IntPoint(position.x(), logicalHeight() - position.y()) : IntPoint(logicalHeight() - position.x(), position.y());
 }
 
 IntSize RenderBox::locationOffsetIncludingFlipping()
@@ -3238,8 +3244,7 @@ IntSize RenderBox::locationOffsetIncludingFlipping()
         return locationOffset();
     
     RenderBox* parent = parentBox();
-    IntPoint localPoint(x(), y());
-    parent->adjustForFlippedBlocksWritingMode(this, localPoint, ChildToParentFlippingAdjustment);
+    IntPoint localPoint = parent->flipForWritingMode(this, location(), ChildToParentFlippingAdjustment);
     return IntSize(localPoint.x(), localPoint.y());
 }
 
index f3a3bc1..f1b57a2 100644 (file)
@@ -51,9 +51,11 @@ public:
     void setHeight(int height) { m_frameRect.setHeight(height); }
 
     int logicalLeft() const { return style()->isHorizontalWritingMode() ? x() : y(); }
+    int logicalRight() const { return logicalLeft() + logicalWidth(); }
     int logicalTop() const { return style()->isHorizontalWritingMode() ? y() : x(); }
     int logicalWidth() const { return style()->isHorizontalWritingMode() ? width() : height(); }
     int logicalHeight() const { return style()->isHorizontalWritingMode() ? height() : width(); }
+
     void setLogicalLeft(int left)
     {
         if (style()->isHorizontalWritingMode())
@@ -378,9 +380,10 @@ public:
     virtual int baselinePosition(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
 
     enum FlippingAdjustment { ChildToParentFlippingAdjustment, ParentToChildFlippingAdjustment };
-    void adjustForFlippedBlocksWritingMode(RenderBox* child, IntPoint&, FlippingAdjustment);
-    void adjustForFlippedBlocksWritingMode(IntRect&); // Unflips a rect in our coordinate space.
-    int convertFromFlippedWritingMode(int position);
+    IntPoint flipForWritingMode(RenderBox* child, const IntPoint&, FlippingAdjustment);
+    int flipForWritingMode(int position);
+    IntPoint flipForWritingMode(const IntPoint&);
+    void flipForWritingMode(IntRect&);
     IntSize locationOffsetIncludingFlipping();
 
 protected:
index 54957fc..1a792e7 100644 (file)
@@ -628,7 +628,7 @@ IntRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repain
     }
 
     IntRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2);
-    cb->adjustForFlippedBlocksWritingMode(r);
+    cb->flipForWritingMode(r);
 
     if (cb->hasColumns())
         cb->adjustRectForColumns(r);
index b4e8286..3139fd5 100644 (file)
@@ -145,55 +145,55 @@ void RenderLineBoxList::dirtyLineBoxes()
         curr->dirtyLineBoxes();
 }
 
-bool RenderLineBoxList::rangeIntersectsDirtyRect(RenderBoxModelObject* renderer, int logicalTop, int logicalBottom, const PaintInfo& paintInfo, int tx, int ty) const
+bool RenderLineBoxList::rangeIntersectsRect(RenderBoxModelObject* renderer, int logicalTop, int logicalBottom, const IntRect& rect, int tx, int ty) const
 {
     RenderBox* block;
     if (renderer->isBox())
         block = toRenderBox(renderer);
     else
         block = renderer->containingBlock();
-    int physicalStart = block->convertFromFlippedWritingMode(logicalTop);
-    int physicalEnd = block->convertFromFlippedWritingMode(logicalBottom);
+    int physicalStart = block->flipForWritingMode(logicalTop);
+    int physicalEnd = block->flipForWritingMode(logicalBottom);
     int physicalExtent = abs(physicalEnd - physicalStart);
     physicalStart = min(physicalStart, physicalEnd);
     
     if (renderer->style()->isHorizontalWritingMode()) {
         physicalStart += ty;
-        if (physicalStart >= paintInfo.rect.bottom() || physicalStart + physicalExtent <= paintInfo.rect.y())
+        if (physicalStart >= rect.bottom() || physicalStart + physicalExtent <= rect.y())
             return false;
     } else {
         physicalStart += tx;
-        if (physicalStart >= paintInfo.rect.right() || physicalStart + physicalExtent <= paintInfo.rect.x())
+        if (physicalStart >= rect.right() || physicalStart + physicalExtent <= rect.x())
             return false;
     }
     
     return true;
 }
 
-bool RenderLineBoxList::anyLineIntersectsDirtyRect(RenderBoxModelObject* renderer, const PaintInfo& paintInfo, int tx, int ty, bool usePrintRect) const
+bool RenderLineBoxList::anyLineIntersectsRect(RenderBoxModelObject* renderer, const IntRect& rect, int tx, int ty, bool usePrintRect, int outlineSize) const
 {
-    // We can check the first box and last box and avoid painting if we don't
+    // We can check the first box and last box and avoid painting/hit testing if we don't
     // intersect.  This is a quick short-circuit that we can take to avoid walking any lines.
     // FIXME: This check is flawed in the following extremely obscure way:
     // if some line in the middle has a huge overflow, it might actually extend below the last line.
-    int firstLineTop = firstLineBox()->topVisibleOverflow();
+    int firstLineTop = firstLineBox()->logicalTopVisibleOverflow();
     if (usePrintRect && !firstLineBox()->parent())
         firstLineTop = min(firstLineTop, firstLineBox()->root()->lineTop());
-    int lastLineBottom = lastLineBox()->bottomVisibleOverflow();
+    int lastLineBottom = lastLineBox()->logicalBottomVisibleOverflow();
     if (usePrintRect && !lastLineBox()->parent())
         lastLineBottom = max(lastLineBottom, lastLineBox()->root()->lineBottom());
-    int logicalTop = firstLineTop - renderer->maximalOutlineSize(paintInfo.phase);
-    int logicalBottom = renderer->maximalOutlineSize(paintInfo.phase) + lastLineBottom;
+    int logicalTop = firstLineTop - outlineSize;
+    int logicalBottom = outlineSize + lastLineBottom;
     
-    return rangeIntersectsDirtyRect(renderer, logicalTop, logicalBottom, paintInfo, tx, ty);
+    return rangeIntersectsRect(renderer, logicalTop, logicalBottom, rect, tx, ty);
 }
 
 bool RenderLineBoxList::lineIntersectsDirtyRect(RenderBoxModelObject* renderer, InlineFlowBox* box, const PaintInfo& paintInfo, int tx, int ty) const
 {
-    int logicalTop = min(box->topVisibleOverflow(), box->root()->selectionTop()) - renderer->maximalOutlineSize(paintInfo.phase);
-    int logicalBottom = box->bottomVisibleOverflow() + renderer->maximalOutlineSize(paintInfo.phase);
+    int logicalTop = min(box->logicalTopVisibleOverflow(), box->root()->selectionTop()) - renderer->maximalOutlineSize(paintInfo.phase);
+    int logicalBottom = box->logicalBottomVisibleOverflow() + renderer->maximalOutlineSize(paintInfo.phase);
     
-    return rangeIntersectsDirtyRect(renderer, logicalTop, logicalBottom, paintInfo, tx, ty);
+    return rangeIntersectsRect(renderer, logicalTop, logicalBottom, paintInfo.rect, tx, ty);
 }
 
 void RenderLineBoxList::paint(RenderBoxModelObject* renderer, PaintInfo& paintInfo, int tx, int ty) const
@@ -214,8 +214,8 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, PaintInfo& paintIn
     // NSViews.  Do not add any more code for this.
     RenderView* v = renderer->view();
     bool usePrintRect = !v->printRect().isEmpty();
-    
-    if (!anyLineIntersectsDirtyRect(renderer, paintInfo, tx, ty, usePrintRect))
+    int outlineSize = renderer->maximalOutlineSize(paintInfo.phase);
+    if (!anyLineIntersectsRect(renderer, paintInfo.rect, tx, ty, usePrintRect, outlineSize))
         return;
 
     PaintInfo info(paintInfo);
@@ -281,23 +281,18 @@ bool RenderLineBoxList::hitTest(RenderBoxModelObject* renderer, const HitTestReq
     bool isHorizontal = firstLineBox()->isHorizontal();
     
     int logicalPointStart = isHorizontal ? y - result.topPadding() : x - result.leftPadding();
-    int logicalPointEnd = isHorizontal ? y + result.bottomPadding() : x + result.rightPadding();
-    int offset = isHorizontal ? ty : tx;
-
-    // We can check the first box and last box and avoid hit testing if we don't
-    // contain the point.  This is a quick short-circuit that we can take to avoid walking any lines.
-    // FIXME: This check is flawed in the following extremely obscure way:
-    // if some line in the middle has a huge overflow, it might actually extend below the last line.
-    if (logicalPointStart >= offset + lastLineBox()->root()->logicalBottomVisibleOverflow()
-        || logicalPointEnd < offset + firstLineBox()->root()->logicalTopVisibleOverflow())
+    int logicalPointEnd = (isHorizontal ? y + result.bottomPadding() : x + result.rightPadding()) + 1;
+    IntRect rect(isHorizontal ? x : logicalPointStart, isHorizontal ? logicalPointStart : y,
+                 isHorizontal ? 1 : logicalPointEnd - logicalPointStart,
+                 isHorizontal ? logicalPointEnd - logicalPointStart : 1);    
+    if (!anyLineIntersectsRect(renderer, rect, tx, ty))
         return false;
 
     // See if our root lines contain the point.  If so, then we hit test
     // them further.  Note that boxes can easily overlap, so we can't make any assumptions
     // based off positions of our first line box or our last line box.
     for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevLineBox()) {
-        if (logicalPointEnd >= offset + curr->root()->logicalTopVisibleOverflow()
-            && logicalPointStart < offset + curr->root()->logicalBottomVisibleOverflow()) {
+        if (rangeIntersectsRect(renderer, curr->logicalTopVisibleOverflow(), curr->logicalBottomVisibleOverflow(), rect, tx, ty)) {
             bool inside = curr->nodeAtPoint(request, result, x, y, tx, ty);
             if (inside) {
                 renderer->updateHitTestResult(result, IntPoint(x - tx, y - ty));
index 9ffacdf..9708d67 100644 (file)
@@ -67,9 +67,9 @@ public:
     bool hitTest(RenderBoxModelObject*, const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction) const;
     
 private:
-    bool anyLineIntersectsDirtyRect(RenderBoxModelObject*, const PaintInfo&, int x, int y, bool usePrintRect) const;
-    bool lineIntersectsDirtyRect(RenderBoxModelObject*, InlineFlowBox*, const PaintInfo&, int x, int y) const;
-    bool rangeIntersectsDirtyRect(RenderBoxModelObject*, int logicalTop, int logicalBottom, const PaintInfo&, int x, int y) const;
+    bool anyLineIntersectsRect(RenderBoxModelObject*, const IntRect&, int tx, int ty, bool usePrintRect = false, int outlineSize = 0) const;
+    bool lineIntersectsDirtyRect(RenderBoxModelObject*, InlineFlowBox*, const PaintInfo&, int tx, int ty) const;
+    bool rangeIntersectsRect(RenderBoxModelObject*, int logicalTop, int logicalBottom, const IntRect&, int tx, int ty) const;
 
     // For block flows, each box represents the root inline box for a line in the
     // paragraph.
index f08e8fb..aa362b3 100644 (file)
@@ -418,38 +418,41 @@ VisiblePosition RenderText::positionForPoint(const IntPoint& point)
     // Get the offset for the position, since this will take rtl text into account.
     int offset;
 
+    int pointLineDirection = firstTextBox()->isHorizontal() ? point.x() : point.y();
+    int pointBlockDirection = firstTextBox()->isHorizontal() ? point.y() : point.x();
+    
     // FIXME: We should be able to roll these special cases into the general cases in the loop below.
-    if (firstTextBox() && point.y() <  firstTextBox()->root()->lineBottom() && point.x() < firstTextBox()->m_x) {
+    if (firstTextBox() && pointBlockDirection <  firstTextBox()->root()->lineBottom() && pointLineDirection < firstTextBox()->logicalLeft()) {
         // at the y coordinate of the first line or above
         // and the x coordinate is to the left of the first text box left edge
-        offset = firstTextBox()->offsetForPosition(point.x());
+        offset = firstTextBox()->offsetForPosition(pointLineDirection);
         return createVisiblePosition(offset + firstTextBox()->start(), DOWNSTREAM);
     }
-    if (lastTextBox() && point.y() >= lastTextBox()->root()->lineTop() && point.x() >= lastTextBox()->m_x + lastTextBox()->logicalWidth()) {
+    if (lastTextBox() && pointBlockDirection >= lastTextBox()->root()->lineTop() && pointLineDirection >= lastTextBox()->logicalRight()) {
         // at the y coordinate of the last line or below
         // and the x coordinate is to the right of the last text box right edge
-        offset = lastTextBox()->offsetForPosition(point.x());
+        offset = lastTextBox()->offsetForPosition(pointLineDirection);
         return createVisiblePosition(offset + lastTextBox()->start(), VP_UPSTREAM_IF_POSSIBLE);
     }
 
     InlineTextBox* lastBoxAbove = 0;
     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
-        if (point.y() >= box->root()->lineTop()) {
+        if (pointBlockDirection >= box->root()->lineTop()) {
             int bottom = box->root()->nextRootBox() ? box->root()->nextRootBox()->lineTop() : box->root()->lineBottom();
-            if (point.y() < bottom) {
-                offset = box->offsetForPosition(point.x());
+            if (pointBlockDirection < bottom) {
+                offset = box->offsetForPosition(pointLineDirection);
 
-                if (point.x() == box->m_x)
+                if (pointLineDirection == box->logicalLeft())
                     // the x coordinate is equal to the left edge of this box
                     // the affinity must be downstream so the position doesn't jump back to the previous line
                     return createVisiblePosition(offset + box->start(), DOWNSTREAM);
 
-                if (point.x() < box->m_x + box->logicalWidth())
+                if (pointLineDirection < box->logicalRight())
                     // and the x coordinate is to the left of the right edge of this box
                     // check to see if position goes in this box
                     return createVisiblePosition(offset + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
 
-                if (!box->prevOnLine() && point.x() < box->m_x)
+                if (!box->prevOnLine() && pointLineDirection < box->logicalLeft())
                     // box is first on line
                     // and the x coordinate is to the left of the first text box left edge
                     return createVisiblePosition(offset + box->start(), DOWNSTREAM);
@@ -488,7 +491,7 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e
     left -= caretWidthLeftOfOffset;
     int caretWidthRightOfOffset = caretWidth - caretWidthLeftOfOffset;
 
-    int rootLeft = box->root()->x();
+    int rootLeft = box->root()->logicalLeft();
     int rootRight = rootLeft + box->root()->logicalWidth();
     // FIXME: should we use the width of the root inline box or the
     // width of the containing block for this?
@@ -500,11 +503,11 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e
     int leftEdge;
     int rightEdge;
     if (style()->autoWrap()) {
-        leftEdge = cb->x();
-        rightEdge = cb->frameRect().right();
+        leftEdge = cb->logicalLeft();
+        rightEdge = cb->logicalRight();
     } else {
-        leftEdge = min(cb->x(), rootLeft);
-        rightEdge = max(cb->frameRect().right(), rootRight);
+        leftEdge = min(cb->logicalLeft(), rootLeft);
+        rightEdge = max(cb->logicalRight(), rootRight);
     }
 
     bool rightAligned = false;
@@ -532,7 +535,7 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e
         left = max(left, rootLeft);
     }
 
-    return IntRect(left, top, caretWidth, height);
+    return style()->isHorizontalWritingMode() ? IntRect(left, top, caretWidth, height) : IntRect(top, left, height, caretWidth);
 }
 
 ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, int xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const