bool BasicShape::canBlend(const BasicShape* other) const { // FIXME: Support animations between different shapes in the future. if (!other || !isSameType(*other)) return false; // Just polygons with same number of vertices can be animated. if (type() == BasicShape::BasicShapePolygonType && (toBasicShapePolygon(this)->values().size() != toBasicShapePolygon(other)->values().size() || toBasicShapePolygon(this)->windRule() != toBasicShapePolygon(other)->windRule())) return false; // Circles with keywords for radii or center coordinates cannot be animated. if (type() == BasicShape::BasicShapeCircleType) { if (!toBasicShapeCircle(this)->radius().canBlend(toBasicShapeCircle(other)->radius())) return false; } // Ellipses with keywords for radii or center coordinates cannot be animated. if (type() != BasicShape::BasicShapeEllipseType) return true; return (toBasicShapeEllipse(this)->radiusX().canBlend(toBasicShapeEllipse(other)->radiusX()) && toBasicShapeEllipse(this)->radiusY().canBlend(toBasicShapeEllipse(other)->radiusY())); }
bool BasicShapePolygon::operator==(const BasicShape& o) const { if (!isSameType(o)) return false; const BasicShapePolygon& other = toBasicShapePolygon(o); return m_windRule == other.m_windRule && m_values == other.m_values; }
CSSValue* valueForBasicShape(const ComputedStyle& style, const BasicShape* basicShape) { switch (basicShape->type()) { case BasicShape::BasicShapeCircleType: { const BasicShapeCircle* circle = toBasicShapeCircle(basicShape); CSSBasicShapeCircleValue* circleValue = CSSBasicShapeCircleValue::create(); circleValue->setCenterX(valueForCenterCoordinate(style, circle->centerX(), HORIZONTAL)); circleValue->setCenterY(valueForCenterCoordinate(style, circle->centerY(), VERTICAL)); circleValue->setRadius(basicShapeRadiusToCSSValue(style, circle->radius())); return circleValue; } case BasicShape::BasicShapeEllipseType: { const BasicShapeEllipse* ellipse = toBasicShapeEllipse(basicShape); CSSBasicShapeEllipseValue* ellipseValue = CSSBasicShapeEllipseValue::create(); ellipseValue->setCenterX(valueForCenterCoordinate(style, ellipse->centerX(), HORIZONTAL)); ellipseValue->setCenterY(valueForCenterCoordinate(style, ellipse->centerY(), VERTICAL)); ellipseValue->setRadiusX(basicShapeRadiusToCSSValue(style, ellipse->radiusX())); ellipseValue->setRadiusY(basicShapeRadiusToCSSValue(style, ellipse->radiusY())); return ellipseValue; } case BasicShape::BasicShapePolygonType: { const BasicShapePolygon* polygon = toBasicShapePolygon(basicShape); CSSBasicShapePolygonValue* polygonValue = CSSBasicShapePolygonValue::create(); polygonValue->setWindRule(polygon->getWindRule()); const Vector<Length>& values = polygon->values(); for (unsigned i = 0; i < values.size(); i += 2) polygonValue->appendPoint(CSSPrimitiveValue::create(values.at(i), style), CSSPrimitiveValue::create(values.at(i + 1), style)); return polygonValue; } case BasicShape::BasicShapeInsetType: { const BasicShapeInset* inset = toBasicShapeInset(basicShape); CSSBasicShapeInsetValue* insetValue = CSSBasicShapeInsetValue::create(); insetValue->setTop(CSSPrimitiveValue::create(inset->top(), style)); insetValue->setRight(CSSPrimitiveValue::create(inset->right(), style)); insetValue->setBottom(CSSPrimitiveValue::create(inset->bottom(), style)); insetValue->setLeft(CSSPrimitiveValue::create(inset->left(), style)); insetValue->setTopLeftRadius(CSSValuePair::create(inset->topLeftRadius(), style)); insetValue->setTopRightRadius(CSSValuePair::create(inset->topRightRadius(), style)); insetValue->setBottomRightRadius(CSSValuePair::create(inset->bottomRightRadius(), style)); insetValue->setBottomLeftRadius(CSSValuePair::create(inset->bottomLeftRadius(), style)); return insetValue; } default: return nullptr; } }
PassRefPtr<BasicShape> BasicShapePolygon::blend(const BasicShape* other, double progress) const { ASSERT(other && isSameType(*other)); const BasicShapePolygon* o = toBasicShapePolygon(other); ASSERT(m_values.size() == o->values().size()); ASSERT(!(m_values.size() % 2)); size_t length = m_values.size(); RefPtr<BasicShapePolygon> result = BasicShapePolygon::create(); if (!length) return result.release(); result->setWindRule(o->windRule()); for (size_t i = 0; i < length; i = i + 2) { result->appendPoint(m_values.at(i).blend(o->values().at(i), progress, ValueRangeAll), m_values.at(i + 1).blend(o->values().at(i + 1), progress, ValueRangeAll)); } return result.release(); }
PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, float margin) { ASSERT(basicShape); bool horizontalWritingMode = isHorizontalWritingMode(writingMode); float boxWidth = horizontalWritingMode ? logicalBoxSize.width().toFloat() : logicalBoxSize.height().toFloat(); float boxHeight = horizontalWritingMode ? logicalBoxSize.height().toFloat() : logicalBoxSize.width().toFloat(); OwnPtr<Shape> shape; switch (basicShape->type()) { case BasicShape::BasicShapeCircleType: { const BasicShapeCircle* circle = toBasicShapeCircle(basicShape); FloatPoint center = floatPointForCenterCoordinate(circle->centerX(), circle->centerY(), FloatSize(boxWidth, boxHeight)); float radius = circle->floatValueForRadiusInBox(FloatSize(boxWidth, boxHeight)); FloatPoint logicalCenter = physicalPointToLogical(center, logicalBoxSize.height().toFloat(), writingMode); shape = createCircleShape(logicalCenter, radius); break; } case BasicShape::BasicShapeEllipseType: { const BasicShapeEllipse* ellipse = toBasicShapeEllipse(basicShape); FloatPoint center = floatPointForCenterCoordinate(ellipse->centerX(), ellipse->centerY(), FloatSize(boxWidth, boxHeight)); float radiusX = ellipse->floatValueForRadiusInBox(ellipse->radiusX(), center.x(), boxWidth); float radiusY = ellipse->floatValueForRadiusInBox(ellipse->radiusY(), center.y(), boxHeight); FloatPoint logicalCenter = physicalPointToLogical(center, logicalBoxSize.height().toFloat(), writingMode); shape = createEllipseShape(logicalCenter, FloatSize(radiusX, radiusY)); break; } case BasicShape::BasicShapePolygonType: { const BasicShapePolygon* polygon = toBasicShapePolygon(basicShape); const Vector<Length>& values = polygon->values(); size_t valuesSize = values.size(); ASSERT(!(valuesSize % 2)); OwnPtr<Vector<FloatPoint>> vertices = adoptPtr(new Vector<FloatPoint>(valuesSize / 2)); for (unsigned i = 0; i < valuesSize; i += 2) { FloatPoint vertex( floatValueForLength(values.at(i), boxWidth), floatValueForLength(values.at(i + 1), boxHeight)); (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height().toFloat(), writingMode); } shape = createPolygonShape(vertices.release(), polygon->windRule()); break; } case BasicShape::BasicShapeInsetType: { const BasicShapeInset& inset = *toBasicShapeInset(basicShape); float left = floatValueForLength(inset.left(), boxWidth); float top = floatValueForLength(inset.top(), boxHeight); float right = floatValueForLength(inset.right(), boxWidth); float bottom = floatValueForLength(inset.bottom(), boxHeight); FloatRect rect(left, top, std::max<float>(boxWidth - left - right, 0), std::max<float>(boxHeight - top - bottom, 0)); FloatRect logicalRect = physicalRectToLogical(rect, logicalBoxSize.height().toFloat(), writingMode); FloatSize boxSize(boxWidth, boxHeight); FloatSize topLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topLeftRadius(), boxSize), writingMode); FloatSize topRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topRightRadius(), boxSize), writingMode); FloatSize bottomLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomLeftRadius(), boxSize), writingMode); FloatSize bottomRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomRightRadius(), boxSize), writingMode); FloatRoundedRect::Radii cornerRadii(topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); FloatRoundedRect finalRect(logicalRect, cornerRadii); finalRect.constrainRadii(); shape = createInsetShape(finalRect); break; } default: ASSERT_NOT_REACHED(); } shape->m_writingMode = writingMode; shape->m_margin = margin; return shape.release(); }