void SliderThumbElement::setPositionFromPoint(const LayoutPoint& point) { RefPtrWillBeRawPtr<HTMLInputElement> input(hostInput()); Element* trackElement = input->closedShadowRoot()->getElementById(ShadowElementNames::sliderTrack()); if (!input->layoutObject() || !layoutBox() || !trackElement->layoutBox()) return; LayoutPoint offset = roundedLayoutPoint(input->layoutObject()->absoluteToLocal(FloatPoint(point), UseTransforms)); bool isVertical = hasVerticalAppearance(input.get()); bool isLeftToRightDirection = layoutBox()->style()->isLeftToRightDirection(); LayoutUnit trackSize; LayoutUnit position; LayoutUnit currentPosition; // We need to calculate currentPosition from absolute points becaue the // renderer for this node is usually on a layer and layoutBox()->x() and // y() are unusable. // FIXME: This should probably respect transforms. LayoutPoint absoluteThumbOrigin = layoutBox()->absoluteBoundingBoxRectIgnoringTransforms().location(); LayoutPoint absoluteSliderContentOrigin = roundedLayoutPoint(input->layoutObject()->localToAbsolute()); IntRect trackBoundingBox = trackElement->layoutObject()->absoluteBoundingBoxRectIgnoringTransforms(); IntRect inputBoundingBox = input->layoutObject()->absoluteBoundingBoxRectIgnoringTransforms(); if (isVertical) { trackSize = trackElement->layoutBox()->contentHeight() - layoutBox()->size().height(); position = offset.y() - layoutBox()->size().height() / 2 - trackBoundingBox.y() + inputBoundingBox.y() - layoutBox()->marginBottom(); currentPosition = absoluteThumbOrigin.y() - absoluteSliderContentOrigin.y(); } else { trackSize = trackElement->layoutBox()->contentWidth() - layoutBox()->size().width(); position = offset.x() - layoutBox()->size().width() / 2 - trackBoundingBox.x() + inputBoundingBox.x(); position -= isLeftToRightDirection ? layoutBox()->marginLeft() : layoutBox()->marginRight(); currentPosition = absoluteThumbOrigin.x() - absoluteSliderContentOrigin.x(); } position = std::max<LayoutUnit>(0, std::min(position, trackSize)); const Decimal ratio = Decimal::fromDouble(static_cast<double>(position) / trackSize); const Decimal fraction = isVertical || !isLeftToRightDirection ? Decimal(1) - ratio : ratio; StepRange stepRange(input->createStepRange(RejectAny)); Decimal value = stepRange.clampValue(stepRange.valueFromProportion(fraction)); Decimal closest = input->findClosestTickMarkValue(value); if (closest.isFinite()) { double closestFraction = stepRange.proportionFromValue(closest).toDouble(); double closestRatio = isVertical || !isLeftToRightDirection ? 1.0 - closestFraction : closestFraction; LayoutUnit closestPosition = trackSize * closestRatio; const LayoutUnit snappingThreshold = 5; if ((closestPosition - position).abs() <= snappingThreshold) value = closest; } String valueString = serializeForNumberType(value); if (valueString == input->value()) return; // FIXME: This is no longer being set from renderer. Consider updating the method name. input->setValueFromRenderer(valueString); if (layoutObject()) layoutObject()->setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationReason::SliderValueChanged); }
bool BasicShape::canBlend(const BasicShape* other) const { // FIXME: Support animations between different shapes in the future. if (type() != other->type()) return false; // Both shapes must use the same reference box. if (layoutBox() != other->layoutBox()) return false; // Just polygons with same number of vertices can be animated. if (type() == BasicShape::BasicShapePolygonType && (static_cast<const BasicShapePolygon*>(this)->values().size() != static_cast<const BasicShapePolygon*>(other)->values().size() || static_cast<const BasicShapePolygon*>(this)->windRule() != static_cast<const BasicShapePolygon*>(other)->windRule())) return false; // Circles with keywords for radii coordinates cannot be animated. if (type() == BasicShape::BasicShapeCircleType) { const BasicShapeCircle* thisCircle = static_cast<const BasicShapeCircle*>(this); const BasicShapeCircle* otherCircle = static_cast<const BasicShapeCircle*>(other); if (!thisCircle->radius().canBlend(otherCircle->radius())) return false; } // Ellipses with keywords for radii coordinates cannot be animated. if (type() != BasicShape::BasicShapeEllipseType) return true; const BasicShapeEllipse* thisEllipse = static_cast<const BasicShapeEllipse*>(this); const BasicShapeEllipse* otherEllipse = static_cast<const BasicShapeEllipse*>(other); return (thisEllipse->radiusX().canBlend(otherEllipse->radiusX()) && thisEllipse->radiusY().canBlend(otherEllipse->radiusY())); }