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 "Shape.h" 32 33#include "BasicShapeFunctions.h" 34#include "BoxShape.h" 35#include "GraphicsContext.h" 36#include "ImageBuffer.h" 37#include "LengthFunctions.h" 38#include "PolygonShape.h" 39#include "RasterShape.h" 40#include "RectangleShape.h" 41#include "WindRule.h" 42 43namespace WebCore { 44 45static std::unique_ptr<Shape> createInsetShape(const FloatRoundedRect& bounds) 46{ 47 ASSERT(bounds.rect().width() >= 0 && bounds.rect().height() >= 0); 48 return std::make_unique<BoxShape>(bounds); 49} 50 51static std::unique_ptr<Shape> createCircleShape(const FloatPoint& center, float radius) 52{ 53 ASSERT(radius >= 0); 54 return std::make_unique<RectangleShape>(FloatRect(center.x() - radius, center.y() - radius, radius*2, radius*2), FloatSize(radius, radius)); 55} 56 57static std::unique_ptr<Shape> createEllipseShape(const FloatPoint& center, const FloatSize& radii) 58{ 59 ASSERT(radii.width() >= 0 && radii.height() >= 0); 60 return std::make_unique<RectangleShape>(FloatRect(center.x() - radii.width(), center.y() - radii.height(), radii.width()*2, radii.height()*2), radii); 61} 62 63static std::unique_ptr<Shape> createPolygonShape(std::unique_ptr<Vector<FloatPoint>> vertices, WindRule fillRule) 64{ 65 return std::make_unique<PolygonShape>(WTF::move(vertices), fillRule); 66} 67 68static inline FloatRect physicalRectToLogical(const FloatRect& rect, float logicalBoxHeight, WritingMode writingMode) 69{ 70 if (isHorizontalWritingMode(writingMode)) 71 return rect; 72 if (isFlippedBlocksWritingMode(writingMode)) 73 return FloatRect(rect.y(), logicalBoxHeight - rect.maxX(), rect.height(), rect.width()); 74 return rect.transposedRect(); 75} 76 77static inline FloatPoint physicalPointToLogical(const FloatPoint& point, float logicalBoxHeight, WritingMode writingMode) 78{ 79 if (isHorizontalWritingMode(writingMode)) 80 return point; 81 if (isFlippedBlocksWritingMode(writingMode)) 82 return FloatPoint(point.y(), logicalBoxHeight - point.x()); 83 return point.transposedPoint(); 84} 85 86static inline FloatSize physicalSizeToLogical(const FloatSize& size, WritingMode writingMode) 87{ 88 if (isHorizontalWritingMode(writingMode)) 89 return size; 90 return size.transposedSize(); 91} 92 93std::unique_ptr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, float margin) 94{ 95 ASSERT(basicShape); 96 97 bool horizontalWritingMode = isHorizontalWritingMode(writingMode); 98 float boxWidth = horizontalWritingMode ? logicalBoxSize.width() : logicalBoxSize.height(); 99 float boxHeight = horizontalWritingMode ? logicalBoxSize.height() : logicalBoxSize.width(); 100 std::unique_ptr<Shape> shape; 101 102 switch (basicShape->type()) { 103 104 case BasicShape::BasicShapeCircleType: { 105 const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape); 106 float centerX = floatValueForCenterCoordinate(circle->centerX(), boxWidth); 107 float centerY = floatValueForCenterCoordinate(circle->centerY(), boxHeight); 108 float radius = circle->floatValueForRadiusInBox(boxWidth, boxHeight); 109 FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode); 110 111 shape = createCircleShape(logicalCenter, radius); 112 break; 113 } 114 115 case BasicShape::BasicShapeEllipseType: { 116 const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape); 117 float centerX = floatValueForCenterCoordinate(ellipse->centerX(), boxWidth); 118 float centerY = floatValueForCenterCoordinate(ellipse->centerY(), boxHeight); 119 float radiusX = ellipse->floatValueForRadiusInBox(ellipse->radiusX(), centerX, boxWidth); 120 float radiusY = ellipse->floatValueForRadiusInBox(ellipse->radiusY(), centerY, boxHeight); 121 FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode); 122 123 shape = createEllipseShape(logicalCenter, FloatSize(radiusX, radiusY)); 124 break; 125 } 126 127 case BasicShape::BasicShapePolygonType: { 128 const BasicShapePolygon& polygon = *static_cast<const BasicShapePolygon*>(basicShape); 129 const Vector<Length>& values = polygon.values(); 130 size_t valuesSize = values.size(); 131 ASSERT(!(valuesSize % 2)); 132 std::unique_ptr<Vector<FloatPoint>> vertices = std::make_unique<Vector<FloatPoint>>(valuesSize / 2); 133 for (unsigned i = 0; i < valuesSize; i += 2) { 134 FloatPoint vertex( 135 floatValueForLength(values.at(i), boxWidth), 136 floatValueForLength(values.at(i + 1), boxHeight)); 137 (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height(), writingMode); 138 } 139 140 shape = createPolygonShape(WTF::move(vertices), polygon.windRule()); 141 break; 142 } 143 144 case BasicShape::BasicShapeInsetType: { 145 const BasicShapeInset& inset = *static_cast<const BasicShapeInset*>(basicShape); 146 float left = floatValueForLength(inset.left(), boxWidth); 147 float top = floatValueForLength(inset.top(), boxHeight); 148 FloatRect rect(left, 149 top, 150 std::max<float>(boxWidth - left - floatValueForLength(inset.right(), boxWidth), 0), 151 std::max<float>(boxHeight - top - floatValueForLength(inset.bottom(), boxHeight), 0)); 152 FloatRect logicalRect = physicalRectToLogical(rect, logicalBoxSize.height(), writingMode); 153 154 FloatSize boxSize(boxWidth, boxHeight); 155 FloatSize topLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topLeftRadius(), boxSize), writingMode); 156 FloatSize topRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topRightRadius(), boxSize), writingMode); 157 FloatSize bottomLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomLeftRadius(), boxSize), writingMode); 158 FloatSize bottomRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomRightRadius(), boxSize), writingMode); 159 FloatRoundedRect::Radii cornerRadii(topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); 160 161 cornerRadii.scale(calcBorderRadiiConstraintScaleFor(logicalRect, cornerRadii)); 162 163 shape = createInsetShape(FloatRoundedRect(logicalRect, cornerRadii)); 164 break; 165 } 166 167 default: 168 ASSERT_NOT_REACHED(); 169 } 170 171 shape->m_writingMode = writingMode; 172 shape->m_margin = margin; 173 174 return shape; 175} 176 177std::unique_ptr<Shape> Shape::createRasterShape(Image* image, float threshold, const LayoutRect& imageR, const LayoutRect& marginR, WritingMode writingMode, float margin) 178{ 179 IntRect imageRect = pixelSnappedIntRect(imageR); 180 IntRect marginRect = pixelSnappedIntRect(marginR); 181 auto intervals = std::make_unique<RasterShapeIntervals>(marginRect.height(), -marginRect.y()); 182 std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(imageRect.size()); 183 184 if (imageBuffer) { 185 GraphicsContext* graphicsContext = imageBuffer->context(); 186 graphicsContext->drawImage(image, ColorSpaceDeviceRGB, IntRect(IntPoint(), imageRect.size())); 187 188 RefPtr<Uint8ClampedArray> pixelArray = imageBuffer->getUnmultipliedImageData(IntRect(IntPoint(), imageRect.size())); 189 unsigned pixelArrayLength = pixelArray->length(); 190 unsigned pixelArrayOffset = 3; // Each pixel is four bytes: RGBA. 191 uint8_t alphaPixelThreshold = threshold * 255; 192 193 int minBufferY = std::max(0, marginRect.y() - imageRect.y()); 194 int maxBufferY = std::min(imageRect.height(), marginRect.maxY() - imageRect.y()); 195 196 if (static_cast<unsigned>(imageRect.width() * imageRect.height() * 4) == pixelArrayLength) { 197 for (int y = minBufferY; y < maxBufferY; ++y) { 198 int startX = -1; 199 for (int x = 0; x < imageRect.width(); ++x, pixelArrayOffset += 4) { 200 uint8_t alpha = pixelArray->item(pixelArrayOffset); 201 bool alphaAboveThreshold = alpha > alphaPixelThreshold; 202 if (startX == -1 && alphaAboveThreshold) { 203 startX = x; 204 } else if (startX != -1 && (!alphaAboveThreshold || x == imageRect.width() - 1)) { 205 // We're creating "end-point exclusive" intervals here. The value of an interval's x1 is 206 // the first index of an above-threshold pixel for y, and the value of x2 is 1+ the index 207 // of the last above-threshold pixel. 208 int endX = alphaAboveThreshold ? x + 1 : x; 209 intervals->intervalAt(y + imageRect.y()).unite(IntShapeInterval(startX + imageRect.x(), endX + imageRect.x())); 210 startX = -1; 211 } 212 } 213 } 214 } 215 } 216 217 auto rasterShape = std::make_unique<RasterShape>(WTF::move(intervals), marginRect.size()); 218 rasterShape->m_writingMode = writingMode; 219 rasterShape->m_margin = margin; 220 return WTF::move(rasterShape); 221} 222 223std::unique_ptr<Shape> Shape::createBoxShape(const RoundedRect& roundedRect, WritingMode writingMode, float margin) 224{ 225 ASSERT(roundedRect.rect().width() >= 0 && roundedRect.rect().height() >= 0); 226 227 FloatRect rect(0, 0, roundedRect.rect().width(), roundedRect.rect().height()); 228 FloatRoundedRect bounds(rect, roundedRect.radii()); 229 auto shape = std::make_unique<BoxShape>(bounds); 230 shape->m_writingMode = writingMode; 231 shape->m_margin = margin; 232 233 return WTF::move(shape); 234} 235 236} // namespace WebCore 237