summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp')
-rw-r--r--chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp297
1 files changed, 272 insertions, 25 deletions
diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp
index 98bea9a0a16..216d3091acf 100644
--- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp
+++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp
@@ -33,48 +33,269 @@
#include "core/rendering/FloatingObjects.h"
#include "core/rendering/RenderBlockFlow.h"
#include "core/rendering/RenderBox.h"
+#include "core/rendering/RenderImage.h"
+#include "platform/LengthFunctions.h"
namespace WebCore {
-bool ShapeOutsideInfo::isEnabledFor(const RenderBox* box)
+
+CSSBoxType referenceBox(const ShapeValue& shapeValue)
+{
+ if (shapeValue.cssBox() == BoxMissing)
+ 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.marginWidth(), m_renderer.marginHeight());
+ else
+ newReferenceBoxLogicalSize.expand(m_renderer.marginHeight(), m_renderer.marginWidth());
+ break;
+ case BorderBox:
+ break;
+ case PaddingBox:
+ if (isHorizontalWritingMode)
+ newReferenceBoxLogicalSize.shrink(m_renderer.borderWidth(), m_renderer.borderHeight());
+ else
+ newReferenceBoxLogicalSize.shrink(m_renderer.borderHeight(), m_renderer.borderWidth());
+ break;
+ case ContentBox:
+ if (isHorizontalWritingMode)
+ newReferenceBoxLogicalSize.shrink(m_renderer.borderAndPaddingWidth(), m_renderer.borderAndPaddingHeight());
+ else
+ newReferenceBoxLogicalSize.shrink(m_renderer.borderAndPaddingHeight(), m_renderer.borderAndPaddingWidth());
+ break;
+ case BoxMissing:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ if (m_referenceBoxLogicalSize == newReferenceBoxLogicalSize)
+ return;
+ markShapeAsDirty();
+ m_referenceBoxLogicalSize = newReferenceBoxLogicalSize;
+}
+
+static bool checkShapeImageOrigin(Document& document, const StyleImage& styleImage)
{
- ShapeValue* shapeValue = box->style()->shapeOutside();
- if (!box->isFloating() || !shapeValue)
+ if (styleImage.isGeneratedImage())
+ return true;
+
+ ASSERT(styleImage.cachedImage());
+ ImageResource& imageResource = *(styleImage.cachedImage());
+ if (imageResource.isAccessAllowed(document.securityOrigin()))
+ return true;
+
+ const KURL& url = imageResource.url();
+ String urlString = url.isNull() ? "''" : url.elidedString();
+ document.addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "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());
+ return LayoutRect(marginBoxOrigin, referenceBoxLogicalSize + marginBoxSizeDelta);
+}
+
+PassOwnPtr<Shape> ShapeOutsideInfo::createShapeForImage(StyleImage* styleImage, float shapeImageThreshold, WritingMode writingMode, float margin) const
+{
+ const IntSize& imageSize = m_renderer.calculateImageIntrinsicDimensions(styleImage, roundedIntSize(m_referenceBoxLogicalSize), RenderImage::ScaleByEffectiveZoom);
+ styleImage->setContainerSizeForRenderer(&m_renderer, imageSize, m_renderer.style()->effectiveZoom());
+
+ const LayoutRect& marginRect = getShapeImageMarginRect(m_renderer, m_referenceBoxLogicalSize);
+ const LayoutRect& imageRect = (m_renderer.isRenderImage())
+ ? toRenderImage(&m_renderer)->replacedContentRect()
+ : LayoutRect(LayoutPoint(), imageSize);
+
+ ASSERT(!styleImage->isPendingImage());
+ 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();
+ LayoutUnit maximumValue = m_renderer.containingBlock() ? m_renderer.containingBlock()->contentWidth() : LayoutUnit();
+ float margin = floatValueForLength(m_renderer.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 RoundedRect& shapeRect = style.getRoundedBorderFor(LayoutRect(LayoutPoint(), m_referenceBoxLogicalSize), m_renderer.view());
+ m_shape = Shape::createLayoutBoxShape(shapeRect, writingMode, margin);
+ break;
+ }
+ }
+
+ ASSERT(m_shape);
+ return *m_shape;
+}
+
+SegmentList ShapeOutsideInfo::computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) const
+{
+ ASSERT(lineHeight >= 0);
+ SegmentList segments;
+
+ computedShape().getExcludedIntervals((lineTop - logicalTopOffset()), std::min(lineHeight, shapeLogicalBottom() - lineTop), segments);
+
+ for (size_t i = 0; i < segments.size(); i++) {
+ segments[i].logicalLeft += logicalLeftOffset();
+ segments[i].logicalRight += logicalLeftOffset();
+ }
+
+ return segments;
+}
+
+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();
+}
+
+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 BoxMissing: break;
+ }
+
+ ASSERT_NOT_REACHED();
+ return LayoutUnit();
+}
+
+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();
+}
+
+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
+{
+ 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 BoxMissing: break;
+ }
+
+ ASSERT_NOT_REACHED();
+ return LayoutUnit();
+}
+
+
+bool ShapeOutsideInfo::isEnabledFor(const RenderBox& box)
+{
+ ShapeValue* shapeValue = box.style()->shapeOutside();
+ if (!box.isFloating() || !shapeValue)
return false;
switch (shapeValue->type()) {
case ShapeValue::Shape:
return shapeValue->shape();
case ShapeValue::Image:
- return shapeValue->isImageValid() && checkShapeImageOrigin(box->document(), *(shapeValue->image()->cachedImage()));
+ return shapeValue->isImageValid() && checkShapeImageOrigin(box.document(), *(shapeValue->image()));
case ShapeValue::Box:
return true;
- case ShapeValue::Outside:
- return false;
}
return false;
}
-void ShapeOutsideInfo::updateDeltasForContainingBlockLine(const RenderBlockFlow* containingBlock, const FloatingObject* floatingObject, LayoutUnit lineTop, LayoutUnit lineHeight)
+void ShapeOutsideInfo::updateDeltasForContainingBlockLine(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;
+ 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();
+ if (isShapeDirty() || m_borderBoxLineTop != borderBoxLineTop || m_lineHeight != lineHeight) {
+ m_borderBoxLineTop = borderBoxLineTop;
+ m_referenceBoxLineTop = borderBoxLineTop - logicalTopOffset();
m_lineHeight = lineHeight;
- LayoutUnit floatMarginBoxWidth = containingBlock->logicalWidthForFloat(floatingObject);
+ LayoutUnit floatMarginBoxWidth = containingBlock.logicalWidthForFloat(&floatingObject);
if (lineOverlapsShapeBounds()) {
- SegmentList segments = computeSegmentsForLine(floatRelativeLineTop, lineHeight);
+ SegmentList segments = computeSegmentsForLine(borderBoxLineTop, lineHeight);
if (segments.size()) {
- LayoutUnit rawLeftMarginBoxDelta = segments.first().logicalLeft + containingBlock->marginStartForChild(m_renderer);
- m_leftMarginBoxDelta = clampTo<LayoutUnit>(rawLeftMarginBoxDelta, LayoutUnit(), floatMarginBoxWidth);
+ LayoutUnit logicalLeftMargin = containingBlock.style()->isLeftToRightDirection() ? containingBlock.marginStartForChild(&m_renderer) : containingBlock.marginEndForChild(&m_renderer);
+ LayoutUnit rawLeftMarginBoxDelta = segments.first().logicalLeft + logicalLeftMargin;
+ m_leftMarginBoxDelta = clampToLayoutUnit(rawLeftMarginBoxDelta, LayoutUnit(), floatMarginBoxWidth);
- LayoutUnit rawRightMarginBoxDelta = segments.last().logicalRight - containingBlock->logicalWidthForChild(m_renderer) - containingBlock->marginEndForChild(m_renderer);
- m_rightMarginBoxDelta = clampTo<LayoutUnit>(rawRightMarginBoxDelta, -floatMarginBoxWidth, LayoutUnit());
+ LayoutUnit logicalRightMargin = containingBlock.style()->isLeftToRightDirection() ? containingBlock.marginEndForChild(&m_renderer) : containingBlock.marginStartForChild(&m_renderer);
+ LayoutUnit rawRightMarginBoxDelta = segments.last().logicalRight - containingBlock.logicalWidthForChild(&m_renderer) - logicalRightMargin;
+ m_rightMarginBoxDelta = clampToLayoutUnit(rawRightMarginBoxDelta, -floatMarginBoxWidth, LayoutUnit());
+ m_lineOverlapsShape = true;
return;
}
}
@@ -82,19 +303,45 @@ void ShapeOutsideInfo::updateDeltasForContainingBlockLine(const RenderBlockFlow*
// 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.
- // FIXME: The latest CSS Shapes spec says that in this case, the
- // content should interact with previously stacked floats on the line
- // as if this outermost float did not exist. Perhaps obviously, this
- // solution cannot do that, and will be revisted when that part of the
- // spec is implemented.
m_leftMarginBoxDelta = floatMarginBoxWidth;
m_rightMarginBoxDelta = -floatMarginBoxWidth;
+ m_lineOverlapsShape = false;
}
}
-ShapeValue* ShapeOutsideInfo::shapeValue() const
+LayoutRect ShapeOutsideInfo::computedShapePhysicalBoundingBox() const
+{
+ LayoutRect physicalBoundingBox = computedShape().shapeMarginLogicalBoundingBox();
+ physicalBoundingBox.setX(physicalBoundingBox.x() + logicalLeftOffset());
+
+ if (m_renderer.style()->isFlippedBlocksWritingMode())
+ physicalBoundingBox.setY(m_renderer.logicalHeight() - physicalBoundingBox.maxY());
+ else
+ physicalBoundingBox.setY(physicalBoundingBox.y() + logicalTopOffset());
+
+ if (!m_renderer.style()->isHorizontalWritingMode())
+ physicalBoundingBox = physicalBoundingBox.transposedRect();
+ else
+ physicalBoundingBox.setY(physicalBoundingBox.y() + logicalTopOffset());
+
+ return physicalBoundingBox;
+}
+
+FloatPoint ShapeOutsideInfo::shapeToRendererPoint(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(FloatSize size) const
{
- return m_renderer->style()->shapeOutside();
+ if (!m_renderer.style()->isHorizontalWritingMode())
+ return size.transposedSize();
+ return size;
}
}