summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/ContextShadow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics/ContextShadow.cpp')
-rw-r--r--WebCore/platform/graphics/ContextShadow.cpp105
1 files changed, 93 insertions, 12 deletions
diff --git a/WebCore/platform/graphics/ContextShadow.cpp b/WebCore/platform/graphics/ContextShadow.cpp
index 87a1c5c..b34e546 100644
--- a/WebCore/platform/graphics/ContextShadow.cpp
+++ b/WebCore/platform/graphics/ContextShadow.cpp
@@ -29,6 +29,8 @@
#include "config.h"
#include "ContextShadow.h"
+#include "FloatQuad.h"
+#include <cmath>
#include <wtf/MathExtras.h>
#include <wtf/Noncopyable.h>
@@ -41,6 +43,7 @@ ContextShadow::ContextShadow()
: m_type(NoShadow)
, m_blurDistance(0)
, m_layerContext(0)
+ , m_shadowsIgnoreTransforms(false)
{
}
@@ -49,6 +52,7 @@ ContextShadow::ContextShadow(const Color& color, float radius, const FloatSize&
, m_blurDistance(round(radius))
, m_offset(offset)
, m_layerContext(0)
+ , m_shadowsIgnoreTransforms(false)
{
// See comments in http://webkit.org/b/40793, it seems sensible
// to follow Skia's limit of 128 pixels of blur radius
@@ -77,6 +81,23 @@ void ContextShadow::clear()
m_offset = FloatSize();
}
+bool ContextShadow::mustUseContextShadow(PlatformContext context)
+{
+ // We can't avoid ContextShadow, since the shadow has blur.
+ if (m_type == ContextShadow::BlurShadow)
+ return true;
+ // We can avoid ContextShadow and optimize, since we're not drawing on a
+ // canvas and box shadows are affected by the transformation matrix.
+ if (!shadowsIgnoreTransforms())
+ return false;
+ // We can avoid ContextShadow, since there are no transformations to apply to the canvas.
+ const TransformationMatrix transform(getTransformationMatrixFromContext(context));
+ if (transform.isIdentity())
+ return false;
+ // Otherwise, no chance avoiding ContextShadow.
+ return true;
+}
+
// Instead of integer division, we use 17.15 for fixed-point division.
static const int BlurSumShift = 15;
@@ -149,29 +170,89 @@ void ContextShadow::blurLayerImage(unsigned char* imageData, const IntSize& size
}
}
-void ContextShadow::calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect)
+void ContextShadow::adjustBlurDistance(const PlatformContext context)
+{
+ // Adjust blur if we're scaling, since the radius must not be affected by transformations.
+ const TransformationMatrix transform(getTransformationMatrixFromContext(context));
+
+ if (transform.isIdentity())
+ return;
+
+ // Calculale transformed unit vectors.
+ const FloatQuad unitQuad(FloatPoint(0, 0), FloatPoint(1, 0),
+ FloatPoint(0, 1), FloatPoint(1, 1));
+ const FloatQuad transformedUnitQuad = transform.mapQuad(unitQuad);
+
+ // Calculate X axis scale factor.
+ const FloatSize xUnitChange = transformedUnitQuad.p2() - transformedUnitQuad.p1();
+ const float xAxisScale = sqrtf(xUnitChange.width() * xUnitChange.width()
+ + xUnitChange.height() * xUnitChange.height());
+
+ // Calculate Y axis scale factor.
+ const FloatSize yUnitChange = transformedUnitQuad.p3() - transformedUnitQuad.p1();
+ const float yAxisScale = sqrtf(yUnitChange.width() * yUnitChange.width()
+ + yUnitChange.height() * yUnitChange.height());
+
+ // blurLayerImage() does not support per-axis blurring, so calculate a balanced scaling.
+ const float scale = sqrtf(xAxisScale * yAxisScale);
+ m_blurDistance = roundf(static_cast<float>(m_blurDistance) / scale);
+}
+
+IntRect ContextShadow::calculateLayerBoundingRect(const PlatformContext context, const FloatRect& layerArea, const IntRect& clipRect)
{
- // Calculate the destination of the blurred layer.
- FloatRect destinationRect(layerArea);
- destinationRect.move(m_offset);
- m_layerRect = enclosingIntRect(destinationRect);
+ // Calculate the destination of the blurred and/or transformed layer.
+ FloatRect layerFloatRect;
+ float inflation = 0;
+
+ const TransformationMatrix transform(getTransformationMatrixFromContext(context));
+ if (m_shadowsIgnoreTransforms && !transform.isIdentity()) {
+ FloatQuad transformedPolygon = transform.mapQuad(FloatQuad(layerArea));
+ transformedPolygon.move(m_offset);
+ layerFloatRect = transform.inverse().mapQuad(transformedPolygon).boundingBox();
+ } else {
+ layerFloatRect = layerArea;
+ layerFloatRect.move(m_offset);
+ }
// We expand the area by the blur radius to give extra space for the blur transition.
- m_layerRect.inflate(m_type == BlurShadow ? m_blurDistance : 0);
+ if (m_type == BlurShadow) {
+ layerFloatRect.inflate(m_blurDistance);
+ inflation += m_blurDistance;
+ }
+
+ FloatRect unclippedLayerRect = layerFloatRect;
- if (!clipRect.contains(m_layerRect)) {
+ if (!clipRect.contains(enclosingIntRect(layerFloatRect))) {
// No need to have the buffer larger than the clip.
- m_layerRect.intersect(clipRect);
+ layerFloatRect.intersect(clipRect);
// If we are totally outside the clip region, we aren't painting at all.
- if (m_layerRect.isEmpty())
- return;
+ if (layerFloatRect.isEmpty())
+ return IntRect(0, 0, 0, 0);
// We adjust again because the pixels at the borders are still
// potentially affected by the pixels outside the buffer.
- if (m_type == BlurShadow)
- m_layerRect.inflate(m_type == BlurShadow ? m_blurDistance : 0);
+ if (m_type == BlurShadow) {
+ layerFloatRect.inflate(m_blurDistance);
+ unclippedLayerRect.inflate(m_blurDistance);
+ inflation += m_blurDistance;
+ }
}
+
+ const int frameSize = inflation * 2;
+ m_sourceRect = IntRect(0, 0, layerArea.width() + frameSize, layerArea.height() + frameSize);
+ m_layerOrigin = FloatPoint(layerFloatRect.x(), layerFloatRect.y());
+
+ const FloatPoint m_unclippedLayerOrigin = FloatPoint(unclippedLayerRect.x(), unclippedLayerRect.y());
+ const FloatSize clippedOut = m_unclippedLayerOrigin - m_layerOrigin;
+
+ // Set the origin as the top left corner of the scratch image, or, in case there's a clipped
+ // out region, set the origin accordingly to the full bounding rect's top-left corner.
+ const float translationX = -layerArea.x() + inflation - fabsf(clippedOut.width());
+ const float translationY = -layerArea.y() + inflation - fabsf(clippedOut.height());
+ m_layerContextTranslation = FloatPoint(translationX, translationY);
+
+ return enclosingIntRect(layerFloatRect);
}
} // namespace WebCore