Commit ebf3a528 authored by Javier Fernandez's avatar Javier Fernandez Committed by Commit Bot

Consider floats as HitTest candidate for selection

Selection with floats has a weird and unpredictable behavior. The root
cause is that floats are not considered valid HitTest candidates.

There are many other cases where float elements are ignored when
traversing the tree looking for the closes element to a specific
LayoutPoint.

This patch address just one of this cases, where floats are children
of a in-flow block-level box.

Bug: 758526
Change-Id: I918af3ee21aa1070fa03a9fe1073205cc0a57300
Reviewed-on: https://chromium-review.googlesource.com/643106Reviewed-by: default avatarPhilip Rogers (OOO) <pdr@chromium.org>
Commit-Queue: Javier Fernandez <jfernandez@igalia.com>
Cr-Commit-Position: refs/heads/master@{#523410}
parent a22b9873
<!doctype html>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../assert_selection.js"></script>
<script>
const kFontSize = '10px';
const kMouseStep = '5';
function startDrag(x, y) {
assert_exists(window, 'eventSender', 'This test requires window.eventSender');
eventSender.dragMode = false;
// Clear click count
eventSender.mouseMoveTo(0, 0);
eventSender.mouseDown();
eventSender.mouseUp();
eventSender.mouseMoveTo(x, y);
eventSender.mouseDown();
}
function endDrag() {
eventSender.mouseUp();
}
function testIt(sample, offset, expected, expectedText, description) {
test(() => assert_selection(
sample,
selection => {
selection.document.body.style.fontFamily = 'monospace';
selection.document.body.style.fontSize = kFontSize;
const target = selection.document.querySelector('.target');
const x = selection.computeLeft(target);
const right = x + target.offsetWidth + offset*kMouseStep;
const y = selection.computeTop(target);
startDrag(x, y);
eventSender.mouseMoveTo(right, y);
endDrag();
assert_equals(selection.toString(), expectedText);
},
expected),
description);
}
const kSample1 = '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">One float</div><div style="float: left">Another float</div>inline-level text after the floats';
testIt(kSample1, 2,
'<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div><div style="float: left">Another float</div>|inline-level text after the floats',
"One floatAnother float",
"Dragging 2 mouse-steps out of a float element with margin in a block-level with block level text before and another float and inline-level text after floats.");
testIt(kSample1, 5,
'<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div><div style="float: left">A|nother float</div>inline-level text after the floats',
"One floatA",
"Dragging 5 mouse-steps out of a float element with margin in a block-level with block level text before and another float and inline-level text after floats.");
testIt(kSample1, 20,
'<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div><div style="float: left">Another float</div>|inline-level text after the floats',
"One floatAnother float",
"Dragging 20 mouse-steps out of a float element with margin in a block-level with block level text before and another float and inline-level text after floats.");
testIt(kSample1, 30,
'<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div><div style="float: left">Another float</div>inline-le|vel text after the floats',
"One floatAnother floatinline-le",
"Dragging 30 mouse-steps out of a float element with margin in a block-level with block level text before and another float and inline-level text after floats.");
const kSample2 = '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">One float</div>inline-level text after the floats';
testIt(kSample2, 2,
'<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div>|inline-level text after the floats',
"One float",
"Dragging 2 mouse-steps out of a float element with margin in a block-level with block level text before and inline-level text after floats.");
testIt(kSample2, 5,
'<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div>i|nline-level text after the floats',
"One floati",
"Dragging 5 mouse-steps out of a float element with margin in a block-level with block level text before and inline-level text after floats.");
const kSample3 = '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">One float</div><div style="float: left">Another float</div>';
testIt(kSample3, 2,
'<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div><div style="float: left">|Another float</div>',
"One float",
"Dragging 2 mouse-steps out of a float element with margin in a block-level with block level text before and another float after.");
testIt(kSample3, 5,
'<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div><div style="float: left">A|nother float</div>',
"One floatA",
"Dragging 5 mouse-steps out of a float element with margin in a block-level with block level text before and another float after.");
testIt(kSample3, 20,
'<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div><div style="float: left">Another float|</div>',
"One floatAnother float",
"Dragging 20 mouse-steps out of a float element with margin in a block-level with block level text before and another float after.");
const kSample4 = '<div>block-level text before floats</div><div class="target" style="float: left;">One float</div><div style="float: left">Another float</div>';
testIt(kSample4, 0,
'<div>block-level text before floats</div><div class="target" style="float: left;">^One float</div><div style="float: left">|Another float</div>',
"One float",
"Dragging 0 mouse-steps out of a float element in a block-level with block level text before and another float after.");
testIt(kSample4, 1,
'<div>block-level text before floats</div><div class="target" style="float: left;">^One float</div><div style="float: left">A|nother float</div>',
"One floatA",
"Dragging 2 mouse-steps out of a float element in a block-level with block level text before and another float after.");
const kSample5 = '<div>block-level text before floats</div><div class="target" style="float: left;">One float</div>';
testIt(kSample5, 2,
'<div>block-level text before floats</div><div class="target" style="float: left;">^One float|</div>',
"One float",
"Dragging 2 mouse-steps out of a float element in a block-level with block level text before .");
const kSample6 = '<div><div>block-level text before floats</div><div class="target" style="float: left;">One float</div></div><p>Additional block-level sibling</p>';
testIt(kSample6, 10,
'<div><div>block-level text before floats</div><div class="target" style="float: left;">^One float|</div></div><p>Additional block-level sibling</p>',
"One float",
"Dragging 2 mouse-steps out of a float element in a block-level with block level text before with an additional block-level sibling.");
</script>
...@@ -1261,7 +1261,7 @@ PositionWithAffinity LayoutBlock::PositionForPointIfOutsideAtomicInlineLevel( ...@@ -1261,7 +1261,7 @@ PositionWithAffinity LayoutBlock::PositionForPointIfOutsideAtomicInlineLevel(
static inline bool IsChildHitTestCandidate(LayoutBox* box) { static inline bool IsChildHitTestCandidate(LayoutBox* box) {
return box->Size().Height() && return box->Size().Height() &&
box->Style()->Visibility() == EVisibility::kVisible && box->Style()->Visibility() == EVisibility::kVisible &&
!box->IsFloatingOrOutOfFlowPositioned() && !box->IsLayoutFlowThread(); !box->IsOutOfFlowPositioned() && !box->IsLayoutFlowThread();
} }
PositionWithAffinity LayoutBlock::PositionForPoint(const LayoutPoint& point) { PositionWithAffinity LayoutBlock::PositionForPoint(const LayoutPoint& point) {
...@@ -1302,6 +1302,9 @@ PositionWithAffinity LayoutBlock::PositionForPoint(const LayoutPoint& point) { ...@@ -1302,6 +1302,9 @@ PositionWithAffinity LayoutBlock::PositionForPoint(const LayoutPoint& point) {
continue; continue;
LayoutUnit child_logical_bottom = LayoutUnit child_logical_bottom =
LogicalTopForChild(*child_box) + LogicalHeightForChild(*child_box); LogicalTopForChild(*child_box) + LogicalHeightForChild(*child_box);
if (child_box->IsLayoutBlockFlow())
child_logical_bottom += ToLayoutBlockFlow(child_box)->LowestFloatLogicalBottom();
// We hit child if our click is above the bottom of its padding box (like // We hit child if our click is above the bottom of its padding box (like
// IE6/7 and FF3). // IE6/7 and FF3).
if (point_in_logical_contents.Y() < child_logical_bottom || if (point_in_logical_contents.Y() < child_logical_bottom ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment