1/* 2 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above 9 * copyright notice, this list of conditions and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following 13 * disclaimer in the documentation and/or other materials 14 * provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 21 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 25 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 26 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include "config.h" 31 32#include "core/css/LengthFunctions.h" 33#include "core/platform/graphics/FloatRect.h" 34#include "core/platform/graphics/Path.h" 35#include "core/rendering/style/BasicShapes.h" 36 37namespace WebCore { 38 39bool BasicShape::canBlend(const BasicShape* other) const 40{ 41 // FIXME: Support animations between different shapes in the future. 42 if (type() != other->type()) 43 return false; 44 45 // Just polygons with same number of vertices can be animated. 46 if (type() == BasicShape::BasicShapePolygonType 47 && static_cast<const BasicShapePolygon*>(this)->values().size() != static_cast<const BasicShapePolygon*>(other)->values().size()) 48 return false; 49 50 return true; 51} 52 53void BasicShapeRectangle::path(Path& path, const FloatRect& boundingBox) 54{ 55 ASSERT(path.isEmpty()); 56 path.addRoundedRect( 57 FloatRect( 58 floatValueForLength(m_x, boundingBox.width()) + boundingBox.x(), 59 floatValueForLength(m_y, boundingBox.height()) + boundingBox.y(), 60 floatValueForLength(m_width, boundingBox.width()), 61 floatValueForLength(m_height, boundingBox.height()) 62 ), 63 FloatSize( 64 floatValueForLength(m_cornerRadiusX, boundingBox.width()), 65 floatValueForLength(m_cornerRadiusY, boundingBox.height()) 66 ) 67 ); 68} 69 70PassRefPtr<BasicShape> BasicShapeRectangle::blend(const BasicShape* other, double progress) const 71{ 72 ASSERT(type() == other->type()); 73 74 const BasicShapeRectangle* o = static_cast<const BasicShapeRectangle*>(other); 75 RefPtr<BasicShapeRectangle> result = BasicShapeRectangle::create(); 76 result->setX(m_x.blend(o->x(), progress)); 77 result->setY(m_y.blend(o->y(), progress)); 78 result->setWidth(m_width.blend(o->width(), progress)); 79 result->setHeight(m_height.blend(o->height(), progress)); 80 result->setCornerRadiusX(m_cornerRadiusX.blend(o->cornerRadiusX(), progress)); 81 result->setCornerRadiusY(m_cornerRadiusY.blend(o->cornerRadiusY(), progress)); 82 return result.release(); 83} 84 85void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox) 86{ 87 ASSERT(path.isEmpty()); 88 float diagonal = sqrtf((boundingBox.width() * boundingBox.width() + boundingBox.height() * boundingBox.height()) / 2); 89 float centerX = floatValueForLength(m_centerX, boundingBox.width()); 90 float centerY = floatValueForLength(m_centerY, boundingBox.height()); 91 float radius = floatValueForLength(m_radius, diagonal); 92 path.addEllipse(FloatRect( 93 centerX - radius + boundingBox.x(), 94 centerY - radius + boundingBox.y(), 95 radius * 2, 96 radius * 2 97 )); 98} 99 100PassRefPtr<BasicShape> BasicShapeCircle::blend(const BasicShape* other, double progress) const 101{ 102 ASSERT(type() == other->type()); 103 104 const BasicShapeCircle* o = static_cast<const BasicShapeCircle*>(other); 105 RefPtr<BasicShapeCircle> result = BasicShapeCircle::create(); 106 result->setCenterX(m_centerX.blend(o->centerX(), progress)); 107 result->setCenterY(m_centerY.blend(o->centerY(), progress)); 108 result->setRadius(m_radius.blend(o->radius(), progress)); 109 return result.release(); 110} 111 112void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox) 113{ 114 ASSERT(path.isEmpty()); 115 float centerX = floatValueForLength(m_centerX, boundingBox.width()); 116 float centerY = floatValueForLength(m_centerY, boundingBox.height()); 117 float radiusX = floatValueForLength(m_radiusX, boundingBox.width()); 118 float radiusY = floatValueForLength(m_radiusY, boundingBox.height()); 119 path.addEllipse(FloatRect( 120 centerX - radiusX + boundingBox.x(), 121 centerY - radiusY + boundingBox.y(), 122 radiusX * 2, 123 radiusY * 2 124 )); 125} 126 127PassRefPtr<BasicShape> BasicShapeEllipse::blend(const BasicShape* other, double progress) const 128{ 129 ASSERT(type() == other->type()); 130 131 const BasicShapeEllipse* o = static_cast<const BasicShapeEllipse*>(other); 132 RefPtr<BasicShapeEllipse> result = BasicShapeEllipse::create(); 133 result->setCenterX(m_centerX.blend(o->centerX(), progress)); 134 result->setCenterY(m_centerY.blend(o->centerY(), progress)); 135 result->setRadiusX(m_radiusX.blend(o->radiusX(), progress)); 136 result->setRadiusY(m_radiusY.blend(o->radiusY(), progress)); 137 return result.release(); 138} 139 140void BasicShapePolygon::path(Path& path, const FloatRect& boundingBox) 141{ 142 ASSERT(path.isEmpty()); 143 ASSERT(!(m_values.size() % 2)); 144 size_t length = m_values.size(); 145 146 if (!length) 147 return; 148 149 path.moveTo(FloatPoint(floatValueForLength(m_values.at(0), boundingBox.width()) + boundingBox.x(), 150 floatValueForLength(m_values.at(1), boundingBox.height()) + boundingBox.y())); 151 for (size_t i = 2; i < length; i = i + 2) { 152 path.addLineTo(FloatPoint(floatValueForLength(m_values.at(i), boundingBox.width()) + boundingBox.x(), 153 floatValueForLength(m_values.at(i + 1), boundingBox.height()) + boundingBox.y())); 154 } 155 path.closeSubpath(); 156} 157 158PassRefPtr<BasicShape> BasicShapePolygon::blend(const BasicShape* other, double progress) const 159{ 160 ASSERT(type() == other->type()); 161 162 const BasicShapePolygon* o = static_cast<const BasicShapePolygon*>(other); 163 ASSERT(m_values.size() == o->values().size()); 164 ASSERT(!(m_values.size() % 2)); 165 166 size_t length = m_values.size(); 167 RefPtr<BasicShapePolygon> result = BasicShapePolygon::create(); 168 if (!length) 169 return result.release(); 170 171 result->setWindRule(o->windRule()); 172 173 for (size_t i = 0; i < length; i = i + 2) { 174 result->appendPoint(m_values.at(i).blend(o->values().at(i), progress), 175 m_values.at(i + 1).blend(o->values().at(i + 1), progress)); 176 } 177 178 return result.release(); 179} 180 181void BasicShapeInsetRectangle::path(Path& path, const FloatRect& boundingBox) 182{ 183 ASSERT(path.isEmpty()); 184 float left = floatValueForLength(m_left, boundingBox.width()); 185 float top = floatValueForLength(m_top, boundingBox.height()); 186 path.addRoundedRect( 187 FloatRect( 188 left + boundingBox.x(), 189 top + boundingBox.y(), 190 std::max<float>(boundingBox.width() - left - floatValueForLength(m_right, boundingBox.width()), 0), 191 std::max<float>(boundingBox.height() - top - floatValueForLength(m_bottom, boundingBox.height()), 0) 192 ), 193 FloatSize( 194 floatValueForLength(m_cornerRadiusX, boundingBox.width()), 195 floatValueForLength(m_cornerRadiusY, boundingBox.height()) 196 ) 197 ); 198} 199 200PassRefPtr<BasicShape> BasicShapeInsetRectangle::blend(const BasicShape* other, double progress) const 201{ 202 ASSERT(type() == other->type()); 203 204 const BasicShapeInsetRectangle* o = static_cast<const BasicShapeInsetRectangle*>(other); 205 RefPtr<BasicShapeInsetRectangle> result = BasicShapeInsetRectangle::create(); 206 result->setTop(m_top.blend(o->top(), progress)); 207 result->setRight(m_right.blend(o->right(), progress)); 208 result->setBottom(m_bottom.blend(o->bottom(), progress)); 209 result->setLeft(m_left.blend(o->left(), progress)); 210 result->setCornerRadiusX(m_cornerRadiusX.blend(o->cornerRadiusX(), progress)); 211 result->setCornerRadiusY(m_cornerRadiusY.blend(o->cornerRadiusY(), progress)); 212 return result.release(); 213} 214} 215