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 42 namespace WebCore { 43 44 static 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 50 static 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 56 static 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 62 static PassOwnPtr<Shape> createPolygonShape(PassOwnPtr<Vector<FloatPoint> > vertices, WindRule fillRule) 63 { 64 return adoptPtr(new PolygonShape(vertices, fillRule)); 65 } 66 67 static 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 76 static 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 85 static inline FloatSize physicalSizeToLogical(const FloatSize& size, WritingMode writingMode) 86 { 87 if (isHorizontalWritingMode(writingMode)) 88 return size; 89 return size.transposedSize(); 90 } 91 92 static 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 103 PassOwnPtr<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