void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const { // Spec: http://www.w3.org/TR/SVG/coords.html#IntrinsicSizing // SVG needs to specify how to calculate some intrinsic sizing properties to enable inclusion within other languages. // The intrinsic width and height of the viewport of SVG content must be determined from the ‘width’ and ‘height’ attributes. // If either of these are not specified, a value of '100%' must be assumed. Note: the ‘width’ and ‘height’ attributes are not // the same as the CSS width and height properties. Specifically, percentage values do not provide an intrinsic width or height, // and do not indicate a percentage of the containing block. Rather, once the viewport is established, they indicate the portion // of the viewport that is actually covered by image data. SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); Length intrinsicWidthAttribute = svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties); Length intrinsicHeightAttribute = svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties); // The intrinsic aspect ratio of the viewport of SVG content is necessary for example, when including SVG from an ‘object’ // element in HTML styled with CSS. It is possible (indeed, common) for an SVG graphic to have an intrinsic aspect ratio but // not to have an intrinsic width or height. The intrinsic aspect ratio must be calculated based upon the following rules: // - The aspect ratio is calculated by dividing a width by a height. // - If the ‘width’ and ‘height’ of the rootmost ‘svg’ element are both specified with unit identifiers (in, mm, cm, pt, pc, // px, em, ex) or in user units, then the aspect ratio is calculated from the ‘width’ and ‘height’ attributes after // resolving both values to user units. if (intrinsicWidthAttribute.isFixed() || intrinsicHeightAttribute.isFixed()) { if (intrinsicWidthAttribute.isFixed()) intrinsicSize.setWidth(floatValueForLength(intrinsicWidthAttribute, 0)); if (intrinsicHeightAttribute.isFixed()) intrinsicSize.setHeight(floatValueForLength(intrinsicHeightAttribute, 0)); if (!intrinsicSize.isEmpty()) intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); return; } // - If either/both of the ‘width’ and ‘height’ of the rootmost ‘svg’ element are in percentage units (or omitted), the // aspect ratio is calculated from the width and height values of the ‘viewBox’ specified for the current SVG document // fragment. If the ‘viewBox’ is not correctly specified, or set to 'none', the intrinsic aspect ratio cannot be // calculated and is considered unspecified. intrinsicSize = svg->viewBox().size(); if (!intrinsicSize.isEmpty()) { // The viewBox can only yield an intrinsic ratio, not an intrinsic size. intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); intrinsicSize = FloatSize(); return; } // If our intrinsic size is in percentage units, return those to the caller through the intrinsicSize. Notify the caller // about the special situation, by setting isPercentageIntrinsicSize=true, so it knows how to interpret the return values. if (intrinsicWidthAttribute.isPercent() && intrinsicHeightAttribute.isPercent()) { isPercentageIntrinsicSize = true; intrinsicSize = FloatSize(intrinsicWidthAttribute.percent(), intrinsicHeightAttribute.percent()); } }
void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox) { ASSERT(path.isEmpty()); float diagonal = sqrtf((boundingBox.width() * boundingBox.width() + boundingBox.height() * boundingBox.height()) / 2); float centerX = floatValueForLength(m_centerX, boundingBox.width()); float centerY = floatValueForLength(m_centerY, boundingBox.height()); float radius = floatValueForLength(m_radius, diagonal); path.addEllipse(FloatRect( centerX - radius + boundingBox.x(), centerY - radius + boundingBox.y(), radius * 2, radius * 2 )); }
void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox) { ASSERT(path.isEmpty()); float centerX = floatValueForLength(m_centerX, boundingBox.width()); float centerY = floatValueForLength(m_centerY, boundingBox.height()); float radiusX = floatValueForLength(m_radiusX, boundingBox.width()); float radiusY = floatValueForLength(m_radiusY, boundingBox.height()); path.addEllipse(FloatRect( centerX - radiusX + boundingBox.x(), centerY - radiusY + boundingBox.y(), radiusX * 2, radiusY * 2 )); }
PassOwnPtr<Shape> Shape::createLayoutBoxShape(const LayoutSize& logicalSize, WritingMode writingMode, const Length& margin, const Length& padding) { FloatRect rect(0, 0, logicalSize.width(), logicalSize.height()); FloatSize radii(0, 0); FloatRoundedRect bounds(rect, radii, radii, radii, radii); float shapeMargin = floatValueForLength(margin, 0); float shapePadding = floatValueForLength(padding, 0); OwnPtr<Shape> shape = createBoxShape(bounds, shapeMargin, shapePadding); shape->m_writingMode = writingMode; shape->m_margin = shapeMargin; shape->m_padding = shapePadding; return shape.release(); }
FloatSize SVGSVGElement::currentViewportSize() const { if (hasIntrinsicWidth() && hasIntrinsicHeight()) return FloatSize(floatValueForLength(intrinsicWidth(), 0), floatValueForLength(intrinsicHeight(), 0)); if (!renderer()) return { }; if (is<RenderSVGRoot>(*renderer())) { auto& root = downcast<RenderSVGRoot>(*renderer()); return root.contentBoxRect().size() / root.style().effectiveZoom(); } return downcast<RenderSVGViewportContainer>(*renderer()).viewport().size(); }
const Path& BasicShapeInset::path(const FloatRect& boundingBox) { float left = floatValueForLength(m_left, boundingBox.width()); float top = floatValueForLength(m_top, boundingBox.height()); auto rect = FloatRect(left + boundingBox.x(), top + boundingBox.y(), std::max<float>(boundingBox.width() - left - floatValueForLength(m_right, boundingBox.width()), 0), std::max<float>(boundingBox.height() - top - floatValueForLength(m_bottom, boundingBox.height()), 0)); auto radii = FloatRoundedRect::Radii(floatSizeForLengthSize(m_topLeftRadius, boundingBox), floatSizeForLengthSize(m_topRightRadius, boundingBox), floatSizeForLengthSize(m_bottomLeftRadius, boundingBox), floatSizeForLengthSize(m_bottomRightRadius, boundingBox)); radii.scale(calcBorderRadiiConstraintScaleFor(rect, radii)); return cachedRoundedRectPath(FloatRoundedRect(rect, radii)); }
void SVGImage::computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio) { SVGSVGElement* rootElement = this->rootElement(); if (!rootElement) return; intrinsicWidth = rootElement->intrinsicWidth(); intrinsicHeight = rootElement->intrinsicHeight(); if (rootElement->preserveAspectRatio().align() == SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) return; intrinsicRatio = rootElement->viewBox().size(); if (intrinsicRatio.isEmpty() && intrinsicWidth.isFixed() && intrinsicHeight.isFixed()) intrinsicRatio = FloatSize(floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0)); }
float TextAutosizer::widthFromBlock(const LayoutBlock* block) const { RELEASE_ASSERT(block); RELEASE_ASSERT(block->style()); if (!(block->isTable() || block->isTableCell() || block->isListItem())) return block->contentLogicalWidth().toFloat(); if (!block->containingBlock()) return 0; // Tables may be inflated before computing their preferred widths. Try several methods to // obtain a width, and fall back on a containing block's width. for (; block; block = block->containingBlock()) { float width; Length specifiedWidth = block->isTableCell() ? toLayoutTableCell(block)->styleOrColLogicalWidth() : block->style()->logicalWidth(); if (specifiedWidth.isFixed()) { if ((width = specifiedWidth.value()) > 0) return width; } if (specifiedWidth.hasPercent()) { if (float containerWidth = block->containingBlock()->contentLogicalWidth().toFloat()) { if ((width = floatValueForLength(specifiedWidth, containerWidth)) > 0) return width; } } if ((width = block->contentLogicalWidth().toFloat()) > 0) return width; } return 0; }
const Shape& ShapeOutsideInfo::computedShape() const { if (Shape* shape = m_shape.get()) return *shape; const RenderStyle& style = m_renderer.style(); ASSERT(m_renderer.containingBlock()); const RenderStyle& containingBlockStyle = m_renderer.containingBlock()->style(); WritingMode writingMode = containingBlockStyle.writingMode(); float margin = floatValueForLength(m_renderer.style().shapeMargin(), m_renderer.containingBlock() ? m_renderer.containingBlock()->contentWidth() : LayoutUnit()); float shapeImageThreshold = style.shapeImageThreshold(); const ShapeValue& shapeValue = *style.shapeOutside(); switch (shapeValue.type()) { case ShapeValue::Type::Shape: ASSERT(shapeValue.shape()); m_shape = Shape::createShape(shapeValue.shape(), m_referenceBoxLogicalSize, writingMode, margin); break; case ShapeValue::Type::Image: ASSERT(shapeValue.isImageValid()); m_shape = createShapeForImage(shapeValue.image(), shapeImageThreshold, writingMode, margin); break; case ShapeValue::Type::Box: { RoundedRect shapeRect = computeRoundedRectForBoxShape(referenceBox(shapeValue), m_renderer); if (!containingBlockStyle.isHorizontalWritingMode()) shapeRect = shapeRect.transposedRect(); m_shape = Shape::createBoxShape(shapeRect, writingMode, margin); break; } } ASSERT(m_shape); return *m_shape; }
FilterOutsets FilterOperations::outsets() const { FilterOutsets totalOutsets; for (size_t i = 0; i < m_operations.size(); ++i) { FilterOperation* filterOperation = m_operations.at(i).get(); switch (filterOperation->type()) { case FilterOperation::BLUR: { BlurFilterOperation* blurOperation = toBlurFilterOperation(filterOperation); float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0); IntSize outsetSize = outsetSizeForBlur(stdDeviation); FilterOutsets outsets(outsetSize.height(), outsetSize.width(), outsetSize.height(), outsetSize.width()); totalOutsets += outsets; break; } case FilterOperation::DROP_SHADOW: { DropShadowFilterOperation* dropShadowOperation = toDropShadowFilterOperation(filterOperation); IntSize outsetSize = outsetSizeForBlur(dropShadowOperation->stdDeviation()); FilterOutsets outsets( std::max(0, outsetSize.height() - dropShadowOperation->y()), std::max(0, outsetSize.width() + dropShadowOperation->x()), std::max(0, outsetSize.height() + dropShadowOperation->y()), std::max(0, outsetSize.width() - dropShadowOperation->x()) ); totalOutsets += outsets; break; } default: break; } } return totalOutsets; }
float floatValueForCenterCoordinate(const BasicShapeCenterCoordinate& center, float boxDimension) { float offset = floatValueForLength(center.length(), boxDimension); if (center.direction() == BasicShapeCenterCoordinate::TopLeft) return offset; return boxDimension - offset; }
void BasicShapeInset::path(Path& path, const FloatRect& boundingBox) { ASSERT(path.isEmpty()); float left = floatValueForLength(m_left, boundingBox.width()); float top = floatValueForLength(m_top, boundingBox.height()); FloatRect rect(left + boundingBox.x(), top + boundingBox.y(), std::max<float>(boundingBox.width() - left - floatValueForLength(m_right, boundingBox.width()), 0), std::max<float>(boundingBox.height() - top - floatValueForLength(m_bottom, boundingBox.height()), 0)); auto radii = FloatRoundedRect::Radii(floatSizeForLengthSize(m_topLeftRadius, boundingBox), floatSizeForLengthSize(m_topRightRadius, boundingBox), floatSizeForLengthSize(m_bottomLeftRadius, boundingBox), floatSizeForLengthSize(m_bottomRightRadius, boundingBox)); FloatRoundedRect finalRect(rect, radii); finalRect.constrainRadii(); path.addRoundedRect(finalRect); }
void BasicShapePolygon::path(Path& path, const FloatRect& boundingBox) { ASSERT(path.isEmpty()); ASSERT(!(m_values.size() % 2)); size_t length = m_values.size(); if (!length) return; path.moveTo(FloatPoint(floatValueForLength(m_values.at(0), boundingBox.width()) + boundingBox.x(), floatValueForLength(m_values.at(1), boundingBox.height()) + boundingBox.y())); for (size_t i = 2; i < length; i = i + 2) { path.addLineTo(FloatPoint(floatValueForLength(m_values.at(i), boundingBox.width()) + boundingBox.x(), floatValueForLength(m_values.at(i + 1), boundingBox.height()) + boundingBox.y())); } path.closeSubpath(); }
bool AnimationBase::computeTransformedExtentViaTransformList(const FloatRect& rendererBox, const RenderStyle& style, LayoutRect& bounds) const { FloatRect floatBounds = bounds; FloatPoint transformOrigin; bool applyTransformOrigin = containsRotation(style.transform().operations()) || style.transform().affectedByTransformOrigin(); if (applyTransformOrigin) { float offsetX = style.transformOriginX().isPercent() ? rendererBox.x() : 0; float offsetY = style.transformOriginY().isPercent() ? rendererBox.y() : 0; transformOrigin.setX(floatValueForLength(style.transformOriginX(), rendererBox.width()) + offsetX); transformOrigin.setY(floatValueForLength(style.transformOriginY(), rendererBox.height()) + offsetY); // Ignore transformOriginZ because we'll bail if we encounter any 3D transforms. floatBounds.moveBy(-transformOrigin); } for (const auto& operation : style.transform().operations()) { if (operation->type() == TransformOperation::ROTATE) { // For now, just treat this as a full rotation. This could take angle into account to reduce inflation. floatBounds = boundsOfRotatingRect(floatBounds); } else { TransformationMatrix transform; operation->apply(transform, rendererBox.size()); if (!transform.isAffine()) return false; if (operation->type() == TransformOperation::MATRIX || operation->type() == TransformOperation::MATRIX_3D) { TransformationMatrix::Decomposed2Type toDecomp; transform.decompose2(toDecomp); // Any rotation prevents us from using a simple start/end rect union. if (toDecomp.angle) return false; } floatBounds = transform.mapRect(floatBounds); } } if (applyTransformOrigin) floatBounds.moveBy(transformOrigin); bounds = LayoutRect(floatBounds); return true; }
FloatSize SVGSVGElement::currentViewportSize() const { Length intrinsicWidth = this->intrinsicWidth(); Length intrinsicHeight = this->intrinsicHeight(); if (intrinsicWidth.isFixed() && intrinsicHeight.isFixed()) return FloatSize(floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0)); if (!renderer()) return FloatSize(); if (renderer()->isSVGRoot()) { LayoutRect contentBoxRect = toRenderSVGRoot(renderer())->contentBoxRect(); return FloatSize(contentBoxRect.width() / renderer()->style()->effectiveZoom(), contentBoxRect.height() / renderer()->style()->effectiveZoom()); } FloatRect viewportRect = toRenderSVGViewportContainer(renderer())->viewport(); return FloatSize(viewportRect.width() / renderer()->style()->effectiveZoom(), viewportRect.height() / renderer()->style()->effectiveZoom()); }
float SVGLengthContext::valueForLength(const Length& length, float zoom, float dimension) { ASSERT(zoom != 0); // isIntrinsic can occur for 'width' and 'height', but has no // real meaning for svg. if (length.isIntrinsic()) return 0; return floatValueForLength(length, dimension * zoom) / zoom; }
void SVGImage::computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio) { if (!m_page) return; Frame* frame = m_page->mainFrame(); SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->rootElement(); if (!rootElement) return; intrinsicWidth = rootElement->intrinsicWidth(); intrinsicHeight = rootElement->intrinsicHeight(); if (rootElement->preserveAspectRatio().align() == SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) return; intrinsicRatio = rootElement->viewBox().size(); if (intrinsicRatio.isEmpty() && intrinsicWidth.isFixed() && intrinsicHeight.isFixed()) intrinsicRatio = FloatSize(floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0)); }
FloatSize SVGSVGElement::currentViewportSize() const { if (hasIntrinsicWidth() && hasIntrinsicHeight()) { Length intrinsicWidth = this->intrinsicWidth(); Length intrinsicHeight = this->intrinsicHeight(); return FloatSize(floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0)); } if (!renderer()) return FloatSize(); if (is<RenderSVGRoot>(*renderer())) { LayoutRect contentBoxRect = downcast<RenderSVGRoot>(*renderer()).contentBoxRect(); return FloatSize(contentBoxRect.width() / renderer()->style().effectiveZoom(), contentBoxRect.height() / renderer()->style().effectiveZoom()); } FloatRect viewportRect = downcast<RenderSVGViewportContainer>(*renderer()).viewport(); return FloatSize(viewportRect.width(), viewportRect.height()); }
PassOwnPtr<Shape> Shape::createRasterShape(Image* image, float threshold, const LayoutRect& imageR, const LayoutRect& marginR, WritingMode writingMode, Length margin, Length padding) { IntRect imageRect = pixelSnappedIntRect(imageR); IntRect marginRect = pixelSnappedIntRect(marginR); OwnPtr<RasterShapeIntervals> intervals = adoptPtr(new RasterShapeIntervals(marginRect.height(), -marginRect.y())); std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(imageRect.size()); if (imageBuffer) { GraphicsContext* graphicsContext = imageBuffer->context(); graphicsContext->drawImage(image, ColorSpaceDeviceRGB, IntRect(IntPoint(), imageRect.size())); RefPtr<Uint8ClampedArray> pixelArray = imageBuffer->getUnmultipliedImageData(IntRect(IntPoint(), imageRect.size())); unsigned pixelArrayLength = pixelArray->length(); unsigned pixelArrayOffset = 3; // Each pixel is four bytes: RGBA. uint8_t alphaPixelThreshold = threshold * 255; int minBufferY = std::max(0, marginRect.y() - imageRect.y()); int maxBufferY = std::min(imageRect.height(), marginRect.maxY() - imageRect.y()); if (static_cast<unsigned>(imageRect.width() * imageRect.height() * 4) == pixelArrayLength) { // sanity check for (int y = minBufferY; y < maxBufferY; ++y) { int startX = -1; for (int x = 0; x < imageRect.width(); ++x, pixelArrayOffset += 4) { uint8_t alpha = pixelArray->item(pixelArrayOffset); bool alphaAboveThreshold = alpha > alphaPixelThreshold; if (startX == -1 && alphaAboveThreshold) { startX = x; } else if (startX != -1 && (!alphaAboveThreshold || x == imageRect.width() - 1)) { intervals->appendInterval(y + imageRect.y(), startX + imageRect.x(), x + imageRect.x()); startX = -1; } } } } } OwnPtr<RasterShape> rasterShape = adoptPtr(new RasterShape(intervals.release(), marginRect.size())); rasterShape->m_writingMode = writingMode; rasterShape->m_margin = floatValueForLength(margin, 0); rasterShape->m_padding = floatValueForLength(padding, 0); return rasterShape.release(); }
PassOwnPtr<Shape> Shape::createShape(const StyleImage* styleImage, float threshold, const LayoutSize&, WritingMode writingMode, Length margin, Length padding) { ASSERT(styleImage && styleImage->isCachedImage() && styleImage->cachedImage() && styleImage->cachedImage()->image()); Image* image = styleImage->cachedImage()->image(); const IntSize& imageSize = image->size(); OwnPtr<RasterShapeIntervals> intervals = adoptPtr(new RasterShapeIntervals(imageSize.height())); OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(imageSize); if (imageBuffer) { GraphicsContext* graphicsContext = imageBuffer->context(); graphicsContext->drawImage(image, ColorSpaceDeviceRGB, IntPoint()); RefPtr<Uint8ClampedArray> pixelArray = imageBuffer->getUnmultipliedImageData(IntRect(IntPoint(), imageSize)); unsigned pixelArrayLength = pixelArray->length(); unsigned pixelArrayOffset = 3; // Each pixel is four bytes: RGBA. uint8_t alphaPixelThreshold = threshold * 255; if (static_cast<unsigned>(imageSize.width() * imageSize.height() * 4) == pixelArrayLength) { // sanity check for (int y = 0; y < imageSize.height(); ++y) { int startX = -1; for (int x = 0; x < imageSize.width(); ++x, pixelArrayOffset += 4) { uint8_t alpha = pixelArray->item(pixelArrayOffset); bool alphaAboveThreshold = alpha > alphaPixelThreshold; if (startX == -1 && alphaAboveThreshold) { startX = x; } else if (startX != -1 && (!alphaAboveThreshold || x == imageSize.width() - 1)) { intervals->appendInterval(y, startX, x); startX = -1; } } } } } OwnPtr<RasterShape> rasterShape = adoptPtr(new RasterShape(intervals.release())); rasterShape->m_writingMode = writingMode; rasterShape->m_margin = floatValueForLength(margin, 0); rasterShape->m_padding = floatValueForLength(padding, 0); return rasterShape.release(); }
float SVGLengthContext::valueForLength(const Length& length, SVGLengthMode mode) { if (length.isPercent()) return convertValueFromPercentageToUserUnits(length.value() / 100, mode, IGNORE_EXCEPTION); if (length.isAuto() || !length.isSpecified()) return 0; FloatSize viewportSize; determineViewport(viewportSize); switch (mode) { case LengthModeWidth: return floatValueForLength(length, viewportSize.width()); case LengthModeHeight: return floatValueForLength(length, viewportSize.height()); case LengthModeOther: return floatValueForLength(length, sqrtf(viewportSize.diagonalLengthSquared() / 2)); }; return 0; }
float BasicShapeEllipse::floatValueForRadiusInBox(const BasicShapeRadius& radius, float center, float boxWidthOrHeight) const { if (radius.type() == BasicShapeRadius::Value) return floatValueForLength(radius.value(), boxWidthOrHeight); if (radius.type() == BasicShapeRadius::ClosestSide) return std::min(center, boxWidthOrHeight - center); ASSERT(radius.type() == BasicShapeRadius::FarthestSide); return std::max(center, boxWidthOrHeight - center); }
FloatRect SVGSVGElement::currentViewBoxRect() const { if (m_useCurrentView) return m_viewSpec ? m_viewSpec->viewBox() : FloatRect(); FloatRect useViewBox = viewBox(); if (!useViewBox.isEmpty()) return useViewBox; if (!renderer() || !renderer()->isSVGRoot()) return FloatRect(); if (!toRenderSVGRoot(renderer())->isEmbeddedThroughSVGImage()) return FloatRect(); Length intrinsicWidth = this->intrinsicWidth(); Length intrinsicHeight = this->intrinsicHeight(); if (!intrinsicWidth.isFixed() || !intrinsicHeight.isFixed()) return FloatRect(); // If no viewBox is specified but non-relative width/height values, then we // should always synthesize a viewBox if we're embedded through a SVGImage. return FloatRect(FloatPoint(), FloatSize(floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0))); }
const Shape& ShapeOutsideInfo::computedShape() const { if (Shape* shape = m_shape.get()) return *shape; AutoReset<bool> isInComputingShape(&m_isComputingShape, true); const ComputedStyle& style = *m_layoutBox.style(); ASSERT(m_layoutBox.containingBlock()); const ComputedStyle& containingBlockStyle = *m_layoutBox.containingBlock()->style(); WritingMode writingMode = containingBlockStyle.getWritingMode(); // Make sure contentWidth is not negative. This can happen when containing // block has a vertical scrollbar and its content is smaller than the // scrollbar width. LayoutUnit maximumValue = m_layoutBox.containingBlock() ? std::max(LayoutUnit(), m_layoutBox.containingBlock()->contentWidth()) : LayoutUnit(); float margin = floatValueForLength(m_layoutBox.style()->shapeMargin(), maximumValue.toFloat()); float shapeImageThreshold = style.shapeImageThreshold(); ASSERT(style.shapeOutside()); const ShapeValue& shapeValue = *style.shapeOutside(); switch (shapeValue.type()) { case ShapeValue::Shape: ASSERT(shapeValue.shape()); m_shape = Shape::createShape( shapeValue.shape(), m_referenceBoxLogicalSize, writingMode, margin); break; case ShapeValue::Image: ASSERT(shapeValue.isImageValid()); m_shape = createShapeForImage(shapeValue.image(), shapeImageThreshold, writingMode, margin); break; case ShapeValue::Box: { const FloatRoundedRect& shapeRect = style.getRoundedBorderFor( LayoutRect(LayoutPoint(), m_referenceBoxLogicalSize), m_layoutBox.view()); m_shape = Shape::createLayoutBoxShape(shapeRect, writingMode, margin); break; } } ASSERT(m_shape); return *m_shape; }
float BasicShapeCircle::floatValueForRadiusInBox(float boxWidth, float boxHeight) const { if (m_radius.type() == BasicShapeRadius::Value) return floatValueForLength(m_radius.value(), sqrtf((boxWidth * boxWidth + boxHeight * boxHeight) / 2)); float centerX = floatValueForCenterCoordinate(m_centerX, boxWidth); float centerY = floatValueForCenterCoordinate(m_centerY, boxHeight); if (m_radius.type() == BasicShapeRadius::ClosestSide) return std::min(std::min(centerX, boxWidth - centerX), std::min(centerY, boxHeight - centerY)); // If radius.type() == BasicShapeRadius::FarthestSide. return std::max(std::max(centerX, boxWidth - centerX), std::max(centerY, boxHeight - centerY)); }
FloatRect SVGSVGElement::currentViewBoxRect() const { if (m_useCurrentView) return m_viewSpec ? m_viewSpec->viewBox() : FloatRect(); FloatRect viewBox = this->viewBox(); if (!viewBox.isEmpty()) return viewBox; if (!is<RenderSVGRoot>(renderer())) return { }; if (!downcast<RenderSVGRoot>(*renderer()).isEmbeddedThroughSVGImage()) return { }; Length intrinsicWidth = this->intrinsicWidth(); Length intrinsicHeight = this->intrinsicHeight(); if (!intrinsicWidth.isFixed() || !intrinsicHeight.isFixed()) return { }; // If no viewBox is specified but non-relative width/height values, then we // should always synthesize a viewBox if we're embedded through a SVGImage. return { 0, 0, floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0) }; }
void RenderStyle::applyTransform(TransformationMatrix& transform, const FloatRect& boundingBox, ApplyTransformOrigin applyOrigin) const { const Vector<RefPtr<TransformOperation> >& transformOperations = rareNonInheritedData->m_transform->m_operations.operations(); bool applyTransformOrigin = requireTransformOrigin(transformOperations, applyOrigin); float offsetX = transformOriginX().type() == Percent ? boundingBox.x() : 0; float offsetY = transformOriginY().type() == Percent ? boundingBox.y() : 0; if (applyTransformOrigin) { transform.translate3d(floatValueForLength(transformOriginX(), boundingBox.width()) + offsetX, floatValueForLength(transformOriginY(), boundingBox.height()) + offsetY, transformOriginZ()); } unsigned size = transformOperations.size(); for (unsigned i = 0; i < size; ++i) transformOperations[i]->apply(transform, boundingBox.size()); if (applyTransformOrigin) { transform.translate3d(-floatValueForLength(transformOriginX(), boundingBox.width()) - offsetX, -floatValueForLength(transformOriginY(), boundingBox.height()) - offsetY, -transformOriginZ()); } }
float BasicShapeCircle::floatValueForRadiusInBox(FloatSize boxSize) const { if (m_radius.type() == BasicShapeRadius::Value) return floatValueForLength(m_radius.value(), hypotf(boxSize.width(), boxSize.height()) / sqrtf(2)); FloatPoint center = floatPointForCenterCoordinate(m_centerX, m_centerY, boxSize); float widthDelta = std::abs(boxSize.width() - center.x()); float heightDelta = std::abs(boxSize.height() - center.y()); if (m_radius.type() == BasicShapeRadius::ClosestSide) return std::min(std::min(std::abs(center.x()), widthDelta), std::min(std::abs(center.y()), heightDelta)); // If radius.type() == BasicShapeRadius::FarthestSide. return std::max(std::max(center.x(), widthDelta), std::max(center.y(), heightDelta)); }
float SVGLengthContext::valueForLength(const Length& length, SVGLengthMode mode) { if (length.isPercent()) { auto result = convertValueFromPercentageToUserUnits(length.value() / 100, mode); if (result.hasException()) return 0; return result.releaseReturnValue(); } if (length.isAuto() || !length.isSpecified()) return 0; FloatSize viewportSize; determineViewport(viewportSize); switch (mode) { case LengthModeWidth: return floatValueForLength(length, viewportSize.width()); case LengthModeHeight: return floatValueForLength(length, viewportSize.height()); case LengthModeOther: return floatValueForLength(length, std::sqrt(viewportSize.diagonalLengthSquared() / 2)); }; return 0; }
FilterOutsets FilterOperations::outsets() const { FilterOutsets totalOutsets; for (size_t i = 0; i < m_operations.size(); ++i) { FilterOperation* filterOperation = m_operations.at(i).get(); switch (filterOperation->type()) { case FilterOperation::BLUR: { BlurFilterOperation* blurOperation = toBlurFilterOperation(filterOperation); float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0); IntSize outsetSize = outsetSizeForBlur(stdDeviation); FilterOutsets outsets(outsetSize.height(), outsetSize.width(), outsetSize.height(), outsetSize.width()); totalOutsets += outsets; break; } case FilterOperation::DROP_SHADOW: { DropShadowFilterOperation* dropShadowOperation = toDropShadowFilterOperation(filterOperation); IntSize outsetSize = outsetSizeForBlur(dropShadowOperation->stdDeviation()); FilterOutsets outsets( std::max(0, outsetSize.height() - dropShadowOperation->y()), std::max(0, outsetSize.width() + dropShadowOperation->x()), std::max(0, outsetSize.height() + dropShadowOperation->y()), std::max(0, outsetSize.width() - dropShadowOperation->x()) ); totalOutsets += outsets; break; } case FilterOperation::REFERENCE: { ReferenceFilterOperation* referenceOperation = toReferenceFilterOperation(filterOperation); if (referenceOperation->filter() && referenceOperation->filter()->lastEffect()) { FloatRect outsetRect(0, 0, 1, 1); outsetRect = referenceOperation->filter()->lastEffect()->mapRectRecursive(outsetRect); FilterOutsets outsets( std::max(0.0f, -outsetRect.y()), std::max(0.0f, outsetRect.x() + outsetRect.width() - 1), std::max(0.0f, outsetRect.y() + outsetRect.height() - 1), std::max(0.0f, -outsetRect.x()) ); totalOutsets += outsets; } break; } default: break; } } return totalOutsets; }