summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp')
-rw-r--r--Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp315
1 files changed, 273 insertions, 42 deletions
diff --git a/Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp b/Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp
index dcfa2bf33..9ce65155c 100644
--- a/Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp
+++ b/Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp
@@ -29,16 +29,263 @@
#include "config.h"
-#if ENABLE(CSS_SHAPES)
-
#include "ShapeOutsideInfo.h"
+#include "BoxShape.h"
#include "FloatingObjects.h"
+#include "LengthFunctions.h"
#include "RenderBlockFlow.h"
#include "RenderBox.h"
+#include "RenderImage.h"
+#include "RenderRegion.h"
namespace WebCore {
+LayoutRect ShapeOutsideInfo::computedShapePhysicalBoundingBox() const
+{
+ LayoutRect physicalBoundingBox = computedShape().shapeMarginLogicalBoundingBox();
+ physicalBoundingBox.setX(physicalBoundingBox.x() + logicalLeftOffset());
+ physicalBoundingBox.setY(physicalBoundingBox.y() + logicalTopOffset());
+ if (m_renderer.style().isFlippedBlocksWritingMode())
+ physicalBoundingBox.setY(m_renderer.logicalHeight() - physicalBoundingBox.maxY());
+ if (!m_renderer.style().isHorizontalWritingMode())
+ physicalBoundingBox = physicalBoundingBox.transposedRect();
+ return physicalBoundingBox;
+}
+
+FloatPoint ShapeOutsideInfo::shapeToRendererPoint(const FloatPoint& point) const
+{
+ FloatPoint result = FloatPoint(point.x() + logicalLeftOffset(), point.y() + logicalTopOffset());
+ if (m_renderer.style().isFlippedBlocksWritingMode())
+ result.setY(m_renderer.logicalHeight() - result.y());
+ if (!m_renderer.style().isHorizontalWritingMode())
+ result = result.transposedPoint();
+ return result;
+}
+
+FloatSize ShapeOutsideInfo::shapeToRendererSize(const FloatSize& size) const
+{
+ if (!m_renderer.style().isHorizontalWritingMode())
+ return size.transposedSize();
+ return size;
+}
+
+static inline CSSBoxType referenceBox(const ShapeValue& shapeValue)
+{
+ if (shapeValue.cssBox() == BoxMissing) {
+ if (shapeValue.type() == ShapeValue::Type::Image)
+ return ContentBox;
+ return MarginBox;
+ }
+ return shapeValue.cssBox();
+}
+
+void ShapeOutsideInfo::setReferenceBoxLogicalSize(LayoutSize newReferenceBoxLogicalSize)
+{
+ bool isHorizontalWritingMode = m_renderer.containingBlock()->style().isHorizontalWritingMode();
+ switch (referenceBox(*m_renderer.style().shapeOutside())) {
+ case MarginBox:
+ if (isHorizontalWritingMode)
+ newReferenceBoxLogicalSize.expand(m_renderer.horizontalMarginExtent(), m_renderer.verticalMarginExtent());
+ else
+ newReferenceBoxLogicalSize.expand(m_renderer.verticalMarginExtent(), m_renderer.horizontalMarginExtent());
+ break;
+ case BorderBox:
+ break;
+ case PaddingBox:
+ if (isHorizontalWritingMode)
+ newReferenceBoxLogicalSize.shrink(m_renderer.horizontalBorderExtent(), m_renderer.verticalBorderExtent());
+ else
+ newReferenceBoxLogicalSize.shrink(m_renderer.verticalBorderExtent(), m_renderer.horizontalBorderExtent());
+ break;
+ case ContentBox:
+ if (isHorizontalWritingMode)
+ newReferenceBoxLogicalSize.shrink(m_renderer.horizontalBorderAndPaddingExtent(), m_renderer.verticalBorderAndPaddingExtent());
+ else
+ newReferenceBoxLogicalSize.shrink(m_renderer.verticalBorderAndPaddingExtent(), m_renderer.horizontalBorderAndPaddingExtent());
+ break;
+ case Fill:
+ case Stroke:
+ case ViewBox:
+ case BoxMissing:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ if (m_referenceBoxLogicalSize == newReferenceBoxLogicalSize)
+ return;
+ markShapeAsDirty();
+ m_referenceBoxLogicalSize = newReferenceBoxLogicalSize;
+}
+
+static inline bool checkShapeImageOrigin(Document& document, const StyleImage& styleImage)
+{
+ if (styleImage.isGeneratedImage())
+ return true;
+
+ ASSERT(styleImage.cachedImage());
+ CachedImage& cachedImage = *(styleImage.cachedImage());
+ if (cachedImage.isOriginClean(&document.securityOrigin()))
+ return true;
+
+ const URL& url = cachedImage.url();
+ String urlString = url.isNull() ? "''" : url.stringCenterEllipsizedToLength();
+ document.addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Unsafe attempt to load URL " + urlString + ".");
+
+ return false;
+}
+
+static LayoutRect getShapeImageMarginRect(const RenderBox& renderBox, const LayoutSize& referenceBoxLogicalSize)
+{
+ LayoutPoint marginBoxOrigin(-renderBox.marginLogicalLeft() - renderBox.borderAndPaddingLogicalLeft(), -renderBox.marginBefore() - renderBox.borderBefore() - renderBox.paddingBefore());
+ LayoutSize marginBoxSizeDelta(renderBox.marginLogicalWidth() + renderBox.borderAndPaddingLogicalWidth(), renderBox.marginLogicalHeight() + renderBox.borderAndPaddingLogicalHeight());
+ LayoutSize marginRectSize(referenceBoxLogicalSize + marginBoxSizeDelta);
+ marginRectSize.clampNegativeToZero();
+ return LayoutRect(marginBoxOrigin, marginRectSize);
+}
+
+std::unique_ptr<Shape> ShapeOutsideInfo::createShapeForImage(StyleImage* styleImage, float shapeImageThreshold, WritingMode writingMode, float margin) const
+{
+ LayoutSize imageSize = m_renderer.calculateImageIntrinsicDimensions(styleImage, m_referenceBoxLogicalSize, RenderImage::ScaleByEffectiveZoom);
+ styleImage->setContainerSizeForRenderer(&m_renderer, imageSize, m_renderer.style().effectiveZoom());
+
+ const LayoutRect& marginRect = getShapeImageMarginRect(m_renderer, m_referenceBoxLogicalSize);
+ const LayoutRect& imageRect = is<RenderImage>(m_renderer)
+ ? downcast<RenderImage>(m_renderer).replacedContentRect(m_renderer.intrinsicSize())
+ : LayoutRect(LayoutPoint(), imageSize);
+
+ ASSERT(!styleImage->isPending());
+ RefPtr<Image> image = styleImage->image(const_cast<RenderBox*>(&m_renderer), imageSize);
+ return Shape::createRasterShape(image.get(), shapeImageThreshold, imageRect, marginRect, writingMode, margin);
+}
+
+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;
+}
+
+static inline LayoutUnit borderBeforeInWritingMode(const RenderBox& renderer, WritingMode writingMode)
+{
+ switch (writingMode) {
+ case TopToBottomWritingMode: return renderer.borderTop();
+ case BottomToTopWritingMode: return renderer.borderBottom();
+ case LeftToRightWritingMode: return renderer.borderLeft();
+ case RightToLeftWritingMode: return renderer.borderRight();
+ }
+
+ ASSERT_NOT_REACHED();
+ return renderer.borderBefore();
+}
+
+static inline LayoutUnit borderAndPaddingBeforeInWritingMode(const RenderBox& renderer, WritingMode writingMode)
+{
+ switch (writingMode) {
+ case TopToBottomWritingMode: return renderer.borderTop() + renderer.paddingTop();
+ case BottomToTopWritingMode: return renderer.borderBottom() + renderer.paddingBottom();
+ case LeftToRightWritingMode: return renderer.borderLeft() + renderer.paddingLeft();
+ case RightToLeftWritingMode: return renderer.borderRight() + renderer.paddingRight();
+ }
+
+ ASSERT_NOT_REACHED();
+ return renderer.borderAndPaddingBefore();
+}
+
+LayoutUnit ShapeOutsideInfo::logicalTopOffset() const
+{
+ switch (referenceBox(*m_renderer.style().shapeOutside())) {
+ case MarginBox: return -m_renderer.marginBefore(&m_renderer.containingBlock()->style());
+ case BorderBox: return LayoutUnit();
+ case PaddingBox: return borderBeforeInWritingMode(m_renderer, m_renderer.containingBlock()->style().writingMode());
+ case ContentBox: return borderAndPaddingBeforeInWritingMode(m_renderer, m_renderer.containingBlock()->style().writingMode());
+ case Fill: break;
+ case Stroke: break;
+ case ViewBox: break;
+ case BoxMissing: break;
+ }
+
+ ASSERT_NOT_REACHED();
+ return LayoutUnit();
+}
+
+static inline LayoutUnit borderStartWithStyleForWritingMode(const RenderBox& renderer, const RenderStyle& style)
+{
+ if (style.isHorizontalWritingMode()) {
+ if (style.isLeftToRightDirection())
+ return renderer.borderLeft();
+
+ return renderer.borderRight();
+ }
+ if (style.isLeftToRightDirection())
+ return renderer.borderTop();
+
+ return renderer.borderBottom();
+}
+
+static inline LayoutUnit borderAndPaddingStartWithStyleForWritingMode(const RenderBox& renderer, const RenderStyle& style)
+{
+ if (style.isHorizontalWritingMode()) {
+ if (style.isLeftToRightDirection())
+ return renderer.borderLeft() + renderer.paddingLeft();
+
+ return renderer.borderRight() + renderer.paddingRight();
+ }
+ if (style.isLeftToRightDirection())
+ return renderer.borderTop() + renderer.paddingTop();
+
+ return renderer.borderBottom() + renderer.paddingBottom();
+}
+
+LayoutUnit ShapeOutsideInfo::logicalLeftOffset() const
+{
+ if (m_renderer.isRenderRegion())
+ return LayoutUnit();
+
+ switch (referenceBox(*m_renderer.style().shapeOutside())) {
+ case MarginBox: return -m_renderer.marginStart(&m_renderer.containingBlock()->style());
+ case BorderBox: return LayoutUnit();
+ case PaddingBox: return borderStartWithStyleForWritingMode(m_renderer, m_renderer.containingBlock()->style());
+ case ContentBox: return borderAndPaddingStartWithStyleForWritingMode(m_renderer, m_renderer.containingBlock()->style());
+ case Fill: break;
+ case Stroke: break;
+ case ViewBox: break;
+ case BoxMissing: break;
+ }
+
+ ASSERT_NOT_REACHED();
+ return LayoutUnit();
+}
+
bool ShapeOutsideInfo::isEnabledFor(const RenderBox& box)
{
ShapeValue* shapeValue = box.style().shapeOutside();
@@ -46,64 +293,48 @@ bool ShapeOutsideInfo::isEnabledFor(const RenderBox& box)
return false;
switch (shapeValue->type()) {
- case ShapeValue::Shape:
- return shapeValue->shape();
- case ShapeValue::Image:
- return shapeValue->isImageValid() && checkShapeImageOrigin(box.document(), *(shapeValue->image()->cachedImage()));
- case ShapeValue::Box:
- return true;
- case ShapeValue::Outside:
- break;
+ case ShapeValue::Type::Shape: return shapeValue->shape();
+ case ShapeValue::Type::Image: return shapeValue->isImageValid() && checkShapeImageOrigin(box.document(), *(shapeValue->image()));
+ case ShapeValue::Type::Box: return true;
}
+
ASSERT_NOT_REACHED();
return false;
}
-void ShapeOutsideInfo::updateDeltasForContainingBlockLine(const RenderBlockFlow& containingBlock, const FloatingObject& floatingObject, LayoutUnit lineTop, LayoutUnit lineHeight)
+ShapeOutsideDeltas ShapeOutsideInfo::computeDeltasForContainingBlockLine(const RenderBlockFlow& containingBlock, const FloatingObject& floatingObject, LayoutUnit lineTop, LayoutUnit lineHeight)
{
- LayoutUnit shapeTop = containingBlock.logicalTopForFloat(&floatingObject) + std::max(LayoutUnit(), containingBlock.marginBeforeForChild(m_renderer));
- LayoutUnit floatRelativeLineTop = lineTop - shapeTop;
+ ASSERT(lineHeight >= 0);
+ LayoutUnit borderBoxTop = containingBlock.logicalTopForFloat(floatingObject) + containingBlock.marginBeforeForChild(m_renderer);
+ LayoutUnit borderBoxLineTop = lineTop - borderBoxTop;
- if (shapeSizeDirty() || m_lineTop != floatRelativeLineTop || m_lineHeight != lineHeight) {
- m_lineTop = floatRelativeLineTop;
- m_shapeLineTop = floatRelativeLineTop - logicalTopOffset();
- m_lineHeight = lineHeight;
+ if (isShapeDirty() || !m_shapeOutsideDeltas.isForLine(borderBoxLineTop, lineHeight)) {
+ LayoutUnit referenceBoxLineTop = borderBoxLineTop - logicalTopOffset();
+ LayoutUnit floatMarginBoxWidth = std::max<LayoutUnit>(LayoutUnit(), containingBlock.logicalWidthForFloat(floatingObject));
- LayoutUnit floatMarginBoxWidth = containingBlock.logicalWidthForFloat(&floatingObject);
+ if (computedShape().lineOverlapsShapeMarginBounds(referenceBoxLineTop, lineHeight)) {
+ LineSegment segment = computedShape().getExcludedInterval((borderBoxLineTop - logicalTopOffset()), std::min(lineHeight, shapeLogicalBottom() - borderBoxLineTop));
+ if (segment.isValid) {
+ LayoutUnit logicalLeftMargin = containingBlock.style().isLeftToRightDirection() ? containingBlock.marginStartForChild(m_renderer) : containingBlock.marginEndForChild(m_renderer);
+ LayoutUnit rawLeftMarginBoxDelta = segment.logicalLeft + logicalLeftOffset() + logicalLeftMargin;
+ LayoutUnit leftMarginBoxDelta = clampTo<LayoutUnit>(rawLeftMarginBoxDelta, LayoutUnit(), floatMarginBoxWidth);
- if (lineOverlapsShapeBounds()) {
- SegmentList segments = computeSegmentsForLine(floatRelativeLineTop, lineHeight);
- if (segments.size()) {
- LayoutUnit rawLeftMarginBoxDelta = segments.first().logicalLeft + containingBlock.marginStartForChild(m_renderer);
- m_leftMarginBoxDelta = clampTo<LayoutUnit>(rawLeftMarginBoxDelta, LayoutUnit(), floatMarginBoxWidth);
+ LayoutUnit logicalRightMargin = containingBlock.style().isLeftToRightDirection() ? containingBlock.marginEndForChild(m_renderer) : containingBlock.marginStartForChild(m_renderer);
+ LayoutUnit rawRightMarginBoxDelta = segment.logicalRight + logicalLeftOffset() - containingBlock.logicalWidthForChild(m_renderer) - logicalRightMargin;
+ LayoutUnit rightMarginBoxDelta = clampTo<LayoutUnit>(rawRightMarginBoxDelta, -floatMarginBoxWidth, LayoutUnit());
- LayoutUnit rawRightMarginBoxDelta = segments.last().logicalRight - containingBlock.logicalWidthForChild(m_renderer) - containingBlock.marginEndForChild(m_renderer);
- m_rightMarginBoxDelta = clampTo<LayoutUnit>(rawRightMarginBoxDelta, -floatMarginBoxWidth, LayoutUnit());
- m_lineOverlapsShape = true;
- return;
+ m_shapeOutsideDeltas = ShapeOutsideDeltas(leftMarginBoxDelta, rightMarginBoxDelta, true, borderBoxLineTop, lineHeight);
+ return m_shapeOutsideDeltas;
}
}
// Lines that do not overlap the shape should act as if the float
// wasn't there for layout purposes. So we set the deltas to remove the
// entire width of the float
- m_leftMarginBoxDelta = floatMarginBoxWidth;
- m_rightMarginBoxDelta = -floatMarginBoxWidth;
- m_lineOverlapsShape = false;
+ m_shapeOutsideDeltas = ShapeOutsideDeltas(floatMarginBoxWidth, -floatMarginBoxWidth, false, borderBoxLineTop, lineHeight);
}
-}
-ShapeValue* ShapeOutsideInfo::shapeValue() const
-{
- return m_renderer.style().shapeOutside();
+ return m_shapeOutsideDeltas;
}
-WritingMode ShapeOutsideInfo::writingMode() const
-{
- ASSERT(m_renderer.containingBlock());
- return m_renderer.containingBlock()->style().writingMode();
}
-
-}
-
-#endif