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 HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 20 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 27 * OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#include "config.h" 31#include "core/rendering/shapes/Shape.h" 32 33#include "core/css/LengthFunctions.h" 34#include "core/platform/graphics/FloatSize.h" 35#include "core/platform/graphics/WindRule.h" 36#include "core/rendering/shapes/PolygonShape.h" 37#include "core/rendering/shapes/RectangleShape.h" 38#include "wtf/MathExtras.h" 39#include "wtf/OwnPtr.h" 40#include "wtf/PassOwnPtr.h" 41 42namespace WebCore { 43 44static PassOwnPtr<Shape> createRectangleShape(const FloatRect& bounds, const FloatSize& radii) 45{ 46 ASSERT(bounds.width() >= 0 && bounds.height() >= 0 && radii.width() >= 0 && radii.height() >= 0); 47 return adoptPtr(new RectangleShape(bounds, radii)); 48} 49 50static PassOwnPtr<Shape> createCircleShape(const FloatPoint& center, float radius) 51{ 52 ASSERT(radius >= 0); 53 return adoptPtr(new RectangleShape(FloatRect(center.x() - radius, center.y() - radius, radius*2, radius*2), FloatSize(radius, radius))); 54} 55 56static PassOwnPtr<Shape> createEllipseShape(const FloatPoint& center, const FloatSize& radii) 57{ 58 ASSERT(radii.width() >= 0 && radii.height() >= 0); 59 return adoptPtr(new RectangleShape(FloatRect(center.x() - radii.width(), center.y() - radii.height(), radii.width()*2, radii.height()*2), radii)); 60} 61 62static PassOwnPtr<Shape> createPolygonShape(PassOwnPtr<Vector<FloatPoint> > vertices, WindRule fillRule) 63{ 64 return adoptPtr(new PolygonShape(vertices, fillRule)); 65} 66 67static inline FloatRect physicalRectToLogical(const FloatRect& rect, float logicalBoxHeight, WritingMode writingMode) 68{ 69 if (isHorizontalWritingMode(writingMode)) 70 return rect; 71 if (isFlippedBlocksWritingMode(writingMode)) 72 return FloatRect(rect.y(), logicalBoxHeight - rect.maxX(), rect.height(), rect.width()); 73 return rect.transposedRect(); 74} 75 76static inline FloatPoint physicalPointToLogical(const FloatPoint& point, float logicalBoxHeight, WritingMode writingMode) 77{ 78 if (isHorizontalWritingMode(writingMode)) 79 return point; 80 if (isFlippedBlocksWritingMode(writingMode)) 81 return FloatPoint(point.y(), logicalBoxHeight - point.x()); 82 return point.transposedPoint(); 83} 84 85static inline FloatSize physicalSizeToLogical(const FloatSize& size, WritingMode writingMode) 86{ 87 if (isHorizontalWritingMode(writingMode)) 88 return size; 89 return size.transposedSize(); 90} 91 92static inline void ensureRadiiDoNotOverlap(FloatRect &bounds, FloatSize &radii) 93{ 94 float widthRatio = bounds.width() / (2 * radii.width()); 95 float heightRatio = bounds.height() / (2 * radii.height()); 96 float reductionRatio = std::min<float>(widthRatio, heightRatio); 97 if (reductionRatio < 1) { 98 radii.setWidth(reductionRatio * radii.width()); 99 radii.setHeight(reductionRatio * radii.height()); 100 } 101} 102 103PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, Length margin, Length padding) 104{ 105 ASSERT(basicShape); 106 107 bool horizontalWritingMode = isHorizontalWritingMode(writingMode); 108 float boxWidth = horizontalWritingMode ? logicalBoxSize.width() : logicalBoxSize.height(); 109 float boxHeight = horizontalWritingMode ? logicalBoxSize.height() : logicalBoxSize.width(); 110 OwnPtr<Shape> shape; 111 112 switch (basicShape->type()) { 113 114 case BasicShape::BasicShapeRectangleType: { 115 const BasicShapeRectangle* rectangle = static_cast<const BasicShapeRectangle*>(basicShape); 116 FloatRect bounds( 117 floatValueForLength(rectangle->x(), boxWidth), 118 floatValueForLength(rectangle->y(), boxHeight), 119 floatValueForLength(rectangle->width(), boxWidth), 120 floatValueForLength(rectangle->height(), boxHeight)); 121 FloatSize cornerRadii( 122 floatValueForLength(rectangle->cornerRadiusX(), boxWidth), 123 floatValueForLength(rectangle->cornerRadiusY(), boxHeight)); 124 ensureRadiiDoNotOverlap(bounds, cornerRadii); 125 FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxSize.height(), writingMode); 126 127 shape = createRectangleShape(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode)); 128 break; 129 } 130 131 case BasicShape::BasicShapeCircleType: { 132 const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape); 133 float centerX = floatValueForLength(circle->centerX(), boxWidth); 134 float centerY = floatValueForLength(circle->centerY(), boxHeight); 135 float radius = floatValueForLength(circle->radius(), std::min(boxHeight, boxWidth)); 136 FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode); 137 138 shape = createCircleShape(logicalCenter, radius); 139 break; 140 } 141 142 case BasicShape::BasicShapeEllipseType: { 143 const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape); 144 float centerX = floatValueForLength(ellipse->centerX(), boxWidth); 145 float centerY = floatValueForLength(ellipse->centerY(), boxHeight); 146 float radiusX = floatValueForLength(ellipse->radiusX(), boxWidth); 147 float radiusY = floatValueForLength(ellipse->radiusY(), boxHeight); 148 FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode); 149 FloatSize logicalRadii = physicalSizeToLogical(FloatSize(radiusX, radiusY), writingMode); 150 151 shape = createEllipseShape(logicalCenter, logicalRadii); 152 break; 153 } 154 155 case BasicShape::BasicShapePolygonType: { 156 const BasicShapePolygon* polygon = static_cast<const BasicShapePolygon*>(basicShape); 157 const Vector<Length>& values = polygon->values(); 158 size_t valuesSize = values.size(); 159 ASSERT(!(valuesSize % 2)); 160 OwnPtr<Vector<FloatPoint> > vertices = adoptPtr(new Vector<FloatPoint>(valuesSize / 2)); 161 for (unsigned i = 0; i < valuesSize; i += 2) { 162 FloatPoint vertex( 163 floatValueForLength(values.at(i), boxWidth), 164 floatValueForLength(values.at(i + 1), boxHeight)); 165 (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height(), writingMode); 166 } 167 shape = createPolygonShape(vertices.release(), polygon->windRule()); 168 break; 169 } 170 171 case BasicShape::BasicShapeInsetRectangleType: { 172 const BasicShapeInsetRectangle* rectangle = static_cast<const BasicShapeInsetRectangle*>(basicShape); 173 float left = floatValueForLength(rectangle->left(), boxWidth); 174 float top = floatValueForLength(rectangle->top(), boxHeight); 175 FloatRect bounds( 176 left, 177 top, 178 boxWidth - left - floatValueForLength(rectangle->right(), boxWidth), 179 boxHeight - top - floatValueForLength(rectangle->bottom(), boxHeight)); 180 FloatSize cornerRadii( 181 floatValueForLength(rectangle->cornerRadiusX(), boxWidth), 182 floatValueForLength(rectangle->cornerRadiusY(), boxHeight)); 183 ensureRadiiDoNotOverlap(bounds, cornerRadii); 184 FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxSize.height(), writingMode); 185 186 shape = createRectangleShape(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode)); 187 break; 188 } 189 190 default: 191 ASSERT_NOT_REACHED(); 192 } 193 194 shape->m_writingMode = writingMode; 195 shape->m_margin = floatValueForLength(margin, 0); 196 shape->m_padding = floatValueForLength(padding, 0); 197 198 return shape.release(); 199} 200 201} // namespace WebCore 202