Title: [268923] trunk
Revision
268923
Author
[email protected]
Date
2020-10-23 05:53:42 -0700 (Fri, 23 Oct 2020)

Log Message

[GTK][WPE] Implement antialiased rounded rectangle clipping in TextureMapper
https://bugs.webkit.org/show_bug.cgi?id=174457

Reviewed by Carlos Garcia Campos.

Source/WebCore:

Implement rounded rectangle clipping in TextureMapperGL, supporting up to 10 simultaneous
rounded rectangle clips. TextureMapper::beginClip() now receives a rounded rectangle, and
it applies the appropriate clipping method as required.

The rounded rectangle clip implementation uses the fragment shader to calculate whether
each pixel is inside the defined rounded rectangles, and paints or skips it as needed.

* platform/graphics/texmap/ClipStack.cpp:
(WebCore::ClipStack::addRoundedRect):
* platform/graphics/texmap/ClipStack.h:
(WebCore::ClipStack::State::State):
(WebCore::ClipStack::roundedRectComponents const):
(WebCore::ClipStack::roundedRectInverseTransformComponents const):
(WebCore::ClipStack::roundedRectCount const):
(WebCore::ClipStack::isRoundedRectClipEnabled const):
(WebCore::ClipStack::isRoundedRectClipAllowed const):
* platform/graphics/texmap/TextureMapper.h:
* platform/graphics/texmap/TextureMapperGL.cpp:
(WebCore::prepareRoundedRectClip):
(WebCore::TextureMapperGL::drawTexture):
(WebCore::TextureMapperGL::drawTexturePlanarYUV):
(WebCore::TextureMapperGL::drawTextureSemiPlanarYUV):
(WebCore::TextureMapperGL::drawTexturePackedYUV):
(WebCore::TextureMapperGL::drawSolidColor):
(WebCore::TextureMapperGL::beginRoundedRectClip):
(WebCore::TextureMapperGL::beginClip):
* platform/graphics/texmap/TextureMapperGL.h:
* platform/graphics/texmap/TextureMapperLayer.cpp:
(WebCore::TextureMapperLayer::paintSelf):
(WebCore::TextureMapperLayer::paintSelfAndChildren):
(WebCore::TextureMapperLayer::paintUsingOverlapRegions):
* platform/graphics/texmap/TextureMapperShaderProgram.cpp:
(WebCore::TextureMapperShaderProgram::create):
* platform/graphics/texmap/TextureMapperShaderProgram.h:

Source/WebKit:

Use the new TextureMapper::beginClip() method that receives a FloatRoundedRect.

* Shared/CoordinatedGraphics/CoordinatedGraphicsScene.cpp:
(WebKit::CoordinatedGraphicsScene::paintToCurrentGLContext):

LayoutTests:

Update expectations for passing test.

* platform/gtk/TestExpectations:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (268922 => 268923)


--- trunk/LayoutTests/ChangeLog	2020-10-23 12:44:44 UTC (rev 268922)
+++ trunk/LayoutTests/ChangeLog	2020-10-23 12:53:42 UTC (rev 268923)
@@ -1,3 +1,14 @@
+2020-10-23  Miguel Gomez  <[email protected]>
+
+        [GTK][WPE] Implement antialiased rounded rectangle clipping in TextureMapper
+        https://bugs.webkit.org/show_bug.cgi?id=174457
+
+        Reviewed by Carlos Garcia Campos.
+
+        Update expectations for passing test.
+
+        * platform/gtk/TestExpectations:
+
 2020-10-22  Fujii Hironori  <[email protected]>
 
         [GTK] Unreviewed test gardening

Modified: trunk/LayoutTests/platform/gtk/TestExpectations (268922 => 268923)


--- trunk/LayoutTests/platform/gtk/TestExpectations	2020-10-23 12:44:44 UTC (rev 268922)
+++ trunk/LayoutTests/platform/gtk/TestExpectations	2020-10-23 12:53:42 UTC (rev 268923)
@@ -3328,7 +3328,6 @@
 
 webkit.org/b/194384 compositing/clipping/border-radius-async-overflow-clipping-layer.html [ Failure ]
 webkit.org/b/206000 compositing/clipping/border-radius-async-overflow-non-stacking.html [ ImageOnlyFailure ]
-webkit.org/b/211121 compositing/clipping/border-radius-on-webgl.html [ ImageOnlyFailure ]
 
 webkit.org/b/194606 accessibility/set-value-not-work-for-disabled-sliders.html [ Failure ]
 

Modified: trunk/Source/WebCore/ChangeLog (268922 => 268923)


--- trunk/Source/WebCore/ChangeLog	2020-10-23 12:44:44 UTC (rev 268922)
+++ trunk/Source/WebCore/ChangeLog	2020-10-23 12:53:42 UTC (rev 268923)
@@ -1,3 +1,45 @@
+2020-10-23  Miguel Gomez  <[email protected]>
+
+        [GTK][WPE] Implement antialiased rounded rectangle clipping in TextureMapper
+        https://bugs.webkit.org/show_bug.cgi?id=174457
+
+        Reviewed by Carlos Garcia Campos.
+
+        Implement rounded rectangle clipping in TextureMapperGL, supporting up to 10 simultaneous
+        rounded rectangle clips. TextureMapper::beginClip() now receives a rounded rectangle, and
+        it applies the appropriate clipping method as required.
+
+        The rounded rectangle clip implementation uses the fragment shader to calculate whether
+        each pixel is inside the defined rounded rectangles, and paints or skips it as needed.
+
+        * platform/graphics/texmap/ClipStack.cpp:
+        (WebCore::ClipStack::addRoundedRect):
+        * platform/graphics/texmap/ClipStack.h:
+        (WebCore::ClipStack::State::State):
+        (WebCore::ClipStack::roundedRectComponents const):
+        (WebCore::ClipStack::roundedRectInverseTransformComponents const):
+        (WebCore::ClipStack::roundedRectCount const):
+        (WebCore::ClipStack::isRoundedRectClipEnabled const):
+        (WebCore::ClipStack::isRoundedRectClipAllowed const):
+        * platform/graphics/texmap/TextureMapper.h:
+        * platform/graphics/texmap/TextureMapperGL.cpp:
+        (WebCore::prepareRoundedRectClip):
+        (WebCore::TextureMapperGL::drawTexture):
+        (WebCore::TextureMapperGL::drawTexturePlanarYUV):
+        (WebCore::TextureMapperGL::drawTextureSemiPlanarYUV):
+        (WebCore::TextureMapperGL::drawTexturePackedYUV):
+        (WebCore::TextureMapperGL::drawSolidColor):
+        (WebCore::TextureMapperGL::beginRoundedRectClip):
+        (WebCore::TextureMapperGL::beginClip):
+        * platform/graphics/texmap/TextureMapperGL.h:
+        * platform/graphics/texmap/TextureMapperLayer.cpp:
+        (WebCore::TextureMapperLayer::paintSelf):
+        (WebCore::TextureMapperLayer::paintSelfAndChildren):
+        (WebCore::TextureMapperLayer::paintUsingOverlapRegions):
+        * platform/graphics/texmap/TextureMapperShaderProgram.cpp:
+        (WebCore::TextureMapperShaderProgram::create):
+        * platform/graphics/texmap/TextureMapperShaderProgram.h:
+
 2020-10-23  Zalan Bujtas  <[email protected]>
 
         [LFC][IFC] Fix inline box relative alignment when line-height is set

Modified: trunk/Source/WebCore/platform/graphics/texmap/ClipStack.cpp (268922 => 268923)


--- trunk/Source/WebCore/platform/graphics/texmap/ClipStack.cpp	2020-10-23 12:44:44 UTC (rev 268922)
+++ trunk/Source/WebCore/platform/graphics/texmap/ClipStack.cpp	2020-10-23 12:53:42 UTC (rev 268923)
@@ -62,6 +62,37 @@
     clipStateDirty = true;
 }
 
+void ClipStack::addRoundedRect(const FloatRoundedRect& roundedRect, const TransformationMatrix& matrix)
+{
+    if (clipState.roundedRectCount >= s_roundedRectMaxClips)
+        return;
+
+    // Ensure that the vectors holding the components have the required size.
+    m_roundedRectComponents.grow(s_roundedRectComponentsArraySize);
+    m_roundedRectInverseTransformComponents.grow(s_roundedRectInverseTransformComponentsArraySize);
+
+    // Copy the RoundedRect components to the appropriate position in the array.
+    int basePosition = clipState.roundedRectCount * s_roundedRectComponentsPerRect;
+    m_roundedRectComponents[basePosition] = roundedRect.rect().x();
+    m_roundedRectComponents[basePosition + 1] = roundedRect.rect().y();
+    m_roundedRectComponents[basePosition + 2] = roundedRect.rect().width();
+    m_roundedRectComponents[basePosition + 3] = roundedRect.rect().height();
+    m_roundedRectComponents[basePosition + 4] = roundedRect.radii().topLeft().width();
+    m_roundedRectComponents[basePosition + 5] = roundedRect.radii().topLeft().height();
+    m_roundedRectComponents[basePosition + 6] = roundedRect.radii().topRight().width();
+    m_roundedRectComponents[basePosition + 7] = roundedRect.radii().topRight().height();
+    m_roundedRectComponents[basePosition + 8] = roundedRect.radii().bottomLeft().width();
+    m_roundedRectComponents[basePosition + 9] = roundedRect.radii().bottomLeft().height();
+    m_roundedRectComponents[basePosition + 10] = roundedRect.radii().bottomRight().width();
+    m_roundedRectComponents[basePosition + 11] = roundedRect.radii().bottomRight().height();
+
+    // Copy the TransformationMatrix components to the appropriate position in the array.
+    basePosition = clipState.roundedRectCount * s_roundedRectInverseTransformComponentsPerRect;
+    memcpy(m_roundedRectInverseTransformComponents.data() + basePosition, matrix.toColumnMajorFloatArray().data(), s_roundedRectInverseTransformComponentsPerRect * sizeof(float));
+
+    clipState.roundedRectCount++;
+}
+
 void ClipStack::apply()
 {
     if (clipState.scissorBox.isEmpty())

Modified: trunk/Source/WebCore/platform/graphics/texmap/ClipStack.h (268922 => 268923)


--- trunk/Source/WebCore/platform/graphics/texmap/ClipStack.h	2020-10-23 12:44:44 UTC (rev 268922)
+++ trunk/Source/WebCore/platform/graphics/texmap/ClipStack.h	2020-10-23 12:53:42 UTC (rev 268923)
@@ -21,22 +21,41 @@
 #ifndef ClipStack_h
 #define ClipStack_h
 
+#include "FloatRoundedRect.h"
 #include "IntRect.h"
 #include "IntSize.h"
+#include "TransformationMatrix.h"
 #include <wtf/Vector.h>
 
 namespace WebCore {
 
+// Because GLSL uniform arrays need to have a defined size, we need to put a limit to the number of simultaneous
+// rounded rectangle clips that we're going to allow. Currently this is defined to 10.
+// This value must be kept in sync with the sizes defined in TextureMapperShaderProgram.cpp.
+static const unsigned s_roundedRectMaxClips = 10;
+
+// When converting a rounded rectangle to an array of floats, we need 12 elements. So the size of the array
+// required to contain the 10 rectangles is 12 * 10 = 120.
+// This value must be kept in sync with the sizes defined in TextureMapperShaderProgram.cpp.
+static const unsigned s_roundedRectComponentsPerRect = 12;
+static const unsigned s_roundedRectComponentsArraySize = s_roundedRectMaxClips * s_roundedRectComponentsPerRect;
+
+// When converting a transformation matrix to an array of floats, we need 16 elements. So the size of the array
+// required to contain the 10 matrices is 16 * 10 = 160.
+// This value must be kept in sync with the sizes defined in TextureMapperShaderProgram.cpp.
+static const unsigned s_roundedRectInverseTransformComponentsPerRect = 16;
+static const unsigned s_roundedRectInverseTransformComponentsArraySize = s_roundedRectMaxClips * s_roundedRectInverseTransformComponentsPerRect;
+
 class ClipStack {
 public:
     struct State {
-        State(const IntRect& scissors = IntRect(), int stencil = 1)
+        explicit State(const IntRect& scissors = IntRect())
             : scissorBox(scissors)
-            , stencilIndex(stencil)
         { }
 
         IntRect scissorBox;
-        int stencilIndex;
+        int stencilIndex { 1 };
+        unsigned roundedRectCount { 0 };
     };
 
     // Y-axis should be inverted only when painting into the window.
@@ -54,6 +73,13 @@
     void setStencilIndex(int);
     int getStencilIndex() const { return clipState.stencilIndex; }
 
+    void addRoundedRect(const FloatRoundedRect&, const TransformationMatrix&);
+    const float* roundedRectComponents() const { return m_roundedRectComponents.data(); }
+    const float* roundedRectInverseTransformComponents() const { return m_roundedRectInverseTransformComponents.data(); }
+    unsigned roundedRectCount() const { return clipState.roundedRectCount; }
+    bool isRoundedRectClipEnabled() const { return !!clipState.roundedRectCount; }
+    bool isRoundedRectClipAllowed() const { return clipState.roundedRectCount < s_roundedRectMaxClips; }
+
     void apply();
     void applyIfNeeded();
 
@@ -65,6 +91,8 @@
     IntSize size;
     bool clipStateDirty { false };
     YAxisMode yAxisMode { YAxisMode::Default };
+    Vector<float, s_roundedRectComponentsArraySize> m_roundedRectComponents;
+    Vector<float, s_roundedRectInverseTransformComponentsArraySize> m_roundedRectInverseTransformComponents;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/graphics/texmap/TextureMapper.h (268922 => 268923)


--- trunk/Source/WebCore/platform/graphics/texmap/TextureMapper.h	2020-10-23 12:44:44 UTC (rev 268922)
+++ trunk/Source/WebCore/platform/graphics/texmap/TextureMapper.h	2020-10-23 12:53:42 UTC (rev 268923)
@@ -37,6 +37,7 @@
 class GraphicsLayer;
 class TextureMapper;
 class FilterOperations;
+class FloatRoundedRect;
 
 class TextureMapper {
     WTF_MAKE_FAST_ALLOCATED;
@@ -75,7 +76,7 @@
 
     // makes a surface the target for the following drawTexture calls.
     virtual void bindSurface(BitmapTexture* surface) = 0;
-    virtual void beginClip(const TransformationMatrix&, const FloatRect&) = 0;
+    virtual void beginClip(const TransformationMatrix&, const FloatRoundedRect&) = 0;
     virtual void endClip() = 0;
     virtual IntRect clipBounds() = 0;
     virtual void beginPreserves3D() { };

Modified: trunk/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp (268922 => 268923)


--- trunk/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp	2020-10-23 12:44:44 UTC (rev 268922)
+++ trunk/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp	2020-10-23 12:53:42 UTC (rev 268923)
@@ -29,6 +29,7 @@
 #include "ExtensionsGL.h"
 #include "FilterOperations.h"
 #include "FloatQuad.h"
+#include "FloatRoundedRect.h"
 #include "GLContext.h"
 #include "GraphicsContext.h"
 #include "Image.h"
@@ -442,6 +443,15 @@
     return matrix;
 }
 
+static void prepareRoundedRectClip(TextureMapperShaderProgram& program, const float* rects, const float* transforms, int nRects)
+{
+    glUseProgram(program.programID());
+
+    glUniform1i(program.roundedRectNumberLocation(), nRects);
+    glUniform4fv(program.roundedRectLocation(), 3 * nRects, rects);
+    glUniformMatrix4fv(program.roundedRectInverseTransformMatrixLocation(), nRects, false, transforms);
+}
+
 void TextureMapperGL::drawTexture(const BitmapTexture& texture, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, unsigned exposedEdges)
 {
     if (!texture.isValid())
@@ -489,11 +499,19 @@
     if (useAntialiasing || opacity < 1)
         flags |= ShouldBlend;
 
+    if (clipStack().isRoundedRectClipEnabled()) {
+        options |= TextureMapperShaderProgram::RoundedRectClip;
+        flags |= ShouldBlend;
+    }
+
     Ref<TextureMapperShaderProgram> program = data().getShaderProgram(options);
 
     if (filter)
         prepareFilterProgram(program.get(), *filter.get(), data().filterInfo->pass, textureSize, filterContentTextureID);
 
+    if (clipStack().isRoundedRectClipEnabled())
+        prepareRoundedRectClip(program.get(), clipStack().roundedRectComponents(), clipStack().roundedRectInverseTransformComponents(), clipStack().roundedRectCount());
+
     drawTexturedQuadWithProgram(program.get(), texture, flags, textureSize, targetRect, modelViewMatrix, opacity);
 }
 
@@ -552,11 +570,19 @@
     if (useAntialiasing || opacity < 1)
         flags |= ShouldBlend;
 
+    if (clipStack().isRoundedRectClipEnabled()) {
+        options |= TextureMapperShaderProgram::RoundedRectClip;
+        flags |= ShouldBlend;
+    }
+
     Ref<TextureMapperShaderProgram> program = data().getShaderProgram(options);
 
     if (filter)
         prepareFilterProgram(program.get(), *filter.get(), data().filterInfo->pass, textureSize, filterContentTextureID);
 
+    if (clipStack().isRoundedRectClipEnabled())
+        prepareRoundedRectClip(program.get(), clipStack().roundedRectComponents(), clipStack().roundedRectInverseTransformComponents(), clipStack().roundedRectCount());
+
     Vector<std::pair<GLuint, GLuint> > texturesAndSamplers = {
         { textures[0], program->samplerYLocation() },
         { textures[1], program->samplerULocation() },
@@ -602,11 +628,19 @@
     if (useAntialiasing || opacity < 1)
         flags |= ShouldBlend;
 
+    if (clipStack().isRoundedRectClipEnabled()) {
+        options |= TextureMapperShaderProgram::RoundedRectClip;
+        flags |= ShouldBlend;
+    }
+
     Ref<TextureMapperShaderProgram> program = data().getShaderProgram(options);
 
     if (filter)
         prepareFilterProgram(program.get(), *filter.get(), data().filterInfo->pass, textureSize, filterContentTextureID);
 
+    if (clipStack().isRoundedRectClipEnabled())
+        prepareRoundedRectClip(program.get(), clipStack().roundedRectComponents(), clipStack().roundedRectInverseTransformComponents(), clipStack().roundedRectCount());
+
     Vector<std::pair<GLuint, GLuint> > texturesAndSamplers = {
         { textures[0], program->samplerYLocation() },
         { textures[1], program->samplerULocation() }
@@ -650,11 +684,19 @@
     if (useAntialiasing || opacity < 1)
         flags |= ShouldBlend;
 
+    if (clipStack().isRoundedRectClipEnabled()) {
+        options |= TextureMapperShaderProgram::RoundedRectClip;
+        flags |= ShouldBlend;
+    }
+
     Ref<TextureMapperShaderProgram> program = data().getShaderProgram(options);
 
     if (filter)
         prepareFilterProgram(program.get(), *filter.get(), data().filterInfo->pass, textureSize, filterContentTextureID);
 
+    if (clipStack().isRoundedRectClipEnabled())
+        prepareRoundedRectClip(program.get(), clipStack().roundedRectComponents(), clipStack().roundedRectInverseTransformComponents(), clipStack().roundedRectCount());
+
     Vector<std::pair<GLuint, GLuint> > texturesAndSamplers = {
         { texture, program->samplerLocation() }
     };
@@ -673,9 +715,17 @@
         flags |= ShouldAntialias | (isBlendingAllowed ? ShouldBlend : 0);
     }
 
+    if (clipStack().isRoundedRectClipEnabled()) {
+        options |= TextureMapperShaderProgram::RoundedRectClip;
+        flags |= ShouldBlend;
+    }
+
     Ref<TextureMapperShaderProgram> program = data().getShaderProgram(options);
     glUseProgram(program->programID());
 
+    if (clipStack().isRoundedRectClipEnabled())
+        prepareRoundedRectClip(program.get(), clipStack().roundedRectComponents(), clipStack().roundedRectInverseTransformComponents(), clipStack().roundedRectCount());
+
     auto [r, g, b, a] = premultiplied(color.toSRGBALossy<float>());
     glUniform4f(program->colorLocation(), r, g, b, a);
     if (a < 1 && isBlendingAllowed)
@@ -884,12 +934,43 @@
     return true;
 }
 
-void TextureMapperGL::beginClip(const TransformationMatrix& modelViewMatrix, const FloatRect& targetRect)
+bool TextureMapperGL::beginRoundedRectClip(const TransformationMatrix& modelViewMatrix, const FloatRoundedRect& targetRect)
 {
+    // This is implemented by telling the fragment shader to check whether each pixel is inside the rounded rectangle
+    // before painting it.
+    //
+    // Inside the shader, the math to check whether a point is inside the rounded rectangle requires the rectangle to
+    // be aligned to the X and Y axis, which is not guaranteed if the transformation matrix includes rotations. In order
+    // to avoid this, instead of applying the transformation to the rounded rectangle, we calculate the inverse
+    // of the transformation and apply it to the pixels before checking whether they are inside the rounded rectangle.
+    // This works fine as long as the transformation matrix is invertible.
+    //
+    // There is a limit to the number of rounded rectangle clippings that can be done, that happens because the GLSL
+    // arrays must have a predefined size. The limit is defined inside ClipStack, and that's why we need to call
+    // clipStack().isRoundedRectClipAllowed() before trying to add a new clip.
+
+    if (!targetRect.isRounded() || !targetRect.isRenderable() || targetRect.isEmpty() || !modelViewMatrix.isInvertible() || !clipStack().isRoundedRectClipAllowed())
+        return false;
+
+    FloatQuad quad = modelViewMatrix.projectQuad(targetRect.rect());
+    IntRect rect = quad.enclosingBoundingBox();
+
+    clipStack().addRoundedRect(targetRect, modelViewMatrix.inverse().value());
+    clipStack().intersect(rect);
+    clipStack().applyIfNeeded();
+
+    return true;
+}
+
+void TextureMapperGL::beginClip(const TransformationMatrix& modelViewMatrix, const FloatRoundedRect& targetRect)
+{
     clipStack().push();
-    if (beginScissorClip(modelViewMatrix, targetRect))
+    if (beginRoundedRectClip(modelViewMatrix, targetRect))
         return;
 
+    if (beginScissorClip(modelViewMatrix, targetRect.rect()))
+        return;
+
     data().initializeStencil();
 
     Ref<TextureMapperShaderProgram> program = data().getShaderProgram(TextureMapperShaderProgram::SolidColor);
@@ -902,7 +983,7 @@
     glVertexAttribPointer(program->vertexLocation(), 2, GL_FLOAT, false, 0, 0);
 
     TransformationMatrix matrix(modelViewMatrix);
-    matrix.multiply(TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), targetRect));
+    matrix.multiply(TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), targetRect.rect()));
 
     static const TransformationMatrix fullProjectionMatrix = TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), FloatRect(-1, -1, 2, 2));
 

Modified: trunk/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h (268922 => 268923)


--- trunk/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h	2020-10-23 12:44:44 UTC (rev 268922)
+++ trunk/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h	2020-10-23 12:53:42 UTC (rev 268923)
@@ -75,7 +75,7 @@
 
     void bindSurface(BitmapTexture* surface) override;
     BitmapTexture* currentSurface();
-    void beginClip(const TransformationMatrix&, const FloatRect&) override;
+    void beginClip(const TransformationMatrix&, const FloatRoundedRect&) override;
     void beginPainting(PaintFlags = 0) override;
     void endPainting() override;
     void endClip() override;
@@ -100,6 +100,7 @@
     void drawEdgeTriangles(TextureMapperShaderProgram&);
 
     bool beginScissorClip(const TransformationMatrix&, const FloatRect&);
+    bool beginRoundedRectClip(const TransformationMatrix&, const FloatRoundedRect&);
     void bindDefaultSurface();
     ClipStack& clipStack();
     inline TextureMapperGLData& data() { return *m_data; }

Modified: trunk/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp (268922 => 268923)


--- trunk/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp	2020-10-23 12:44:44 UTC (rev 268922)
+++ trunk/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp	2020-10-23 12:53:42 UTC (rev 268923)
@@ -196,8 +196,7 @@
 
     bool shouldClip = m_state.contentsClippingRect.isRounded() || !m_state.contentsClippingRect.rect().contains(m_state.contentsRect);
     if (shouldClip) {
-        // FIXME: TextureMapper::beginClip doesn't support FloatRoundedRect, so we need to convert m_state.contentsClippingRect to FloatRect.
-        options.textureMapper.beginClip(transform, m_state.contentsClippingRect.rect());
+        options.textureMapper.beginClip(transform, m_state.contentsClippingRect);
     }
 
     m_contentsLayer->paintToTextureMapper(options.textureMapper, m_state.contentsRect, transform, options.opacity);
@@ -230,7 +229,7 @@
         clipTransform.translate(options.offset.width(), options.offset.height());
         clipTransform.multiply(options.transform);
         clipTransform.multiply(m_layerTransforms.combined);
-        options.textureMapper.beginClip(clipTransform, layerRect());
+        options.textureMapper.beginClip(clipTransform, FloatRoundedRect(layerRect()));
         m_state.backdropLayer->paintRecursive(options);
         options.textureMapper.endClip();
     }
@@ -249,7 +248,7 @@
         clipTransform.translate(options.offset.width(), options.offset.height());
         clipTransform.multiply(options.transform);
         clipTransform.multiply(m_layerTransforms.combined);
-        options.textureMapper.beginClip(clipTransform, layerRect());
+        options.textureMapper.beginClip(clipTransform, FloatRoundedRect(layerRect()));
 
         // If as a result of beginClip(), the clipping area is empty, it means that the intersection of the previous
         // clipping area and the current one don't have any pixels in common. In this case we can skip painting the
@@ -405,7 +404,7 @@
         if (!rect.intersects(options.textureMapper.clipBounds()))
             continue;
 
-        options.textureMapper.beginClip(TransformationMatrix(), rect);
+        options.textureMapper.beginClip(TransformationMatrix(), FloatRoundedRect(rect));
         paintSelfAndChildrenWithReplica(options);
         options.textureMapper.endClip();
     }

Modified: trunk/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.cpp (268922 => 268923)


--- trunk/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.cpp	2020-10-23 12:44:44 UTC (rev 268922)
+++ trunk/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.cpp	2020-10-23 12:53:42 UTC (rev 268923)
@@ -68,6 +68,7 @@
         varying vec2 v_texCoord;
         varying vec2 v_transformedTexCoord;
         varying float v_antialias;
+        varying vec4 v_nonProjectedPosition;
     );
 
 #if !USE(OPENGL_ES)
@@ -78,6 +79,7 @@
         out vec2 v_texCoord;
         out vec2 v_transformedTexCoord;
         out float v_antialias;
+        out vec4 v_nonProjectedPosition;
     );
 #endif
 
@@ -133,7 +135,8 @@
             v_texCoord = position;
             vec4 clampedPosition = clamp(vec4(position, 0., 1.), 0., 1.);
             v_transformedTexCoord = (u_textureSpaceMatrix * clampedPosition).xy;
-            gl_Position = u_projectionMatrix * u_modelViewMatrix * vec4(position, 0., 1.);
+            v_nonProjectedPosition = u_modelViewMatrix * vec4(position, 0., 1.);
+            gl_Position = u_projectionMatrix * v_nonProjectedPosition;
         }
     );
 
@@ -168,6 +171,16 @@
         GLSL_DIRECTIVE(define SamplerExternalOESType sampler2D) \
     GLSL_DIRECTIVE(endif)
 
+// The max number of stacked rounded rectangle clips allowed is 10, which is also the
+// max number of transforms that we can get. We need 3 components for each rounded
+// rectangle so we need 30 components to receive the 10 rectangles.
+//
+// Keep this is sync with the values defined in ClipStack.h
+#define ROUNDED_RECT_CONSTANTS                       \
+    GLSL_DIRECTIVE(define ROUNDED_RECT_MAX_RECTS 10) \
+    GLSL_DIRECTIVE(define ROUNDED_RECT_ARRAY_SIZE 30) \
+    GLSL_DIRECTIVE(define ROUNDED_RECT_INVERSE_TRANSFORM_ARRAY_SIZE 10)
+
 // Common header for all versions. We define the matrices variables here to keep the precision
 // directives scope: the first one applies to the matrices variables and the next one to the
 // rest of them. The precision is only used in GLES.
@@ -175,6 +188,7 @@
     RECT_TEXTURE_DIRECTIVE
     ANTIALIASING_TEX_COORD_DIRECTIVE
     BLUR_CONSTANTS
+    ROUNDED_RECT_CONSTANTS
     OES_EGL_IMAGE_EXTERNAL_DIRECTIVE
 #if USE(OPENGL_ES)
     TEXTURE_SPACE_MATRIX_PRECISION_DIRECTIVE
@@ -199,6 +213,7 @@
         varying float v_antialias;
         varying vec2 v_texCoord;
         varying vec2 v_transformedTexCoord;
+        varying vec4 v_nonProjectedPosition;
     );
 
 #if !USE(OPENGL_ES)
@@ -208,6 +223,7 @@
         in float v_antialias;
         in vec2 v_texCoord;
         in vec2 v_transformedTexCoord;
+        in vec4 v_nonProjectedPosition;
     );
 #endif
 
@@ -226,6 +242,9 @@
         uniform vec2 u_shadowOffset;
         uniform vec4 u_color;
         uniform float u_gaussianKernel[GAUSSIAN_KERNEL_HALF_WIDTH];
+        uniform int u_roundedRectNumber;
+        uniform vec4 u_roundedRect[ROUNDED_RECT_ARRAY_SIZE];
+        uniform mat4 u_roundedRectInverseTransformMatrix[ROUNDED_RECT_INVERSE_TRANSFORM_ARRAY_SIZE];
 
         void noop(inout vec4 dummyParameter) { }
         void noop(inout vec4 dummyParameter, vec2 texCoord) { }
@@ -390,6 +409,70 @@
 
         void applySolidColor(inout vec4 color) { color *= u_color; }
 
+        float ellipsisDist(vec2 p, vec2 radius)
+        {
+            if (radius == vec2(0, 0))
+                return 0.0;
+
+            vec2 p0 = p / radius;
+            vec2 p1 = 2.0 * p0 / radius;
+
+            return (dot(p0, p0) - 1.0) / length (p1);
+        }
+
+        float ellipsisCoverage(vec2 point, vec2 center, vec2 radius)
+        {
+            float d = ellipsisDist(point - center, radius);
+            return clamp(0.5 - d, 0.0, 1.0);
+        }
+
+        float roundedRectCoverage(vec2 p, int index)
+        {
+            vec4 bounds = vec4(u_roundedRect[index].xy, u_roundedRect[index].xy + u_roundedRect[index].zw);
+
+            if (p.x < bounds.x || p.y < bounds.y || p.x >= bounds.z || p.y >= bounds.w)
+                return 0.0;
+
+            vec2 topLeftRadii = u_roundedRect[index + 1].xy;
+            vec2 topRightRadii = u_roundedRect[index + 1].zw;
+            vec2 bottomLeftRadii = u_roundedRect[index + 2].xy;
+            vec2 bottomRightRadii = u_roundedRect[index + 2].zw;
+
+            vec2 topLeftCenter = bounds.xy + topLeftRadii;
+            vec2 topRightCenter = bounds.zy + (topRightRadii * vec2(-1, 1));
+            vec2 bottomLeftCenter = bounds.xw + (bottomLeftRadii * vec2(1, -1));
+            vec2 bottomRightCenter = bounds.zw + (bottomRightRadii * vec2(-1, -1));
+
+            if (p.x < topLeftCenter.x && p.y < topLeftCenter.y)
+                return ellipsisCoverage(p, topLeftCenter, topLeftRadii);
+
+            if (p.x > topRightCenter.x && p.y < topRightCenter.y)
+                return ellipsisCoverage(p, topRightCenter, topRightRadii);
+
+            if (p.x < bottomLeftCenter.x && p.y > bottomLeftCenter.y)
+                return ellipsisCoverage(p, bottomLeftCenter, bottomLeftRadii);
+
+            if (p.x > bottomRightCenter.x && p.y > bottomRightCenter.y)
+                return ellipsisCoverage(p, bottomRightCenter, bottomRightRadii);
+
+            return 1.0;
+        }
+
+        void applyRoundedRectClip(inout vec4 color)
+        {
+            // This works by checking whether the fragment position, once the transform is applied,
+            // is inside the defined rounded rectangle or not.
+            //
+            // We can't use gl_fragCoord for the fragment position because thats the projected point
+            // and the projection screws the Z component. We need the real 3D position that comes from
+            // the nonProjectedPosition variable.
+            int nRects = min(ROUNDED_RECT_MAX_RECTS, u_roundedRectNumber);
+            for (int rectIndex = 0; rectIndex < nRects; rectIndex++) {
+                vec4 fragCoord = u_roundedRectInverseTransformMatrix[rectIndex] * v_nonProjectedPosition;
+                color *= roundedRectCoverage(fragCoord.xy, rectIndex * 3);
+            }
+        }
+
         void main(void)
         {
             vec4 color = vec4(1., 1., 1., 1.);
@@ -415,6 +498,7 @@
             applyAlphaBlurIfNeeded(color, texCoord);
             applyContentTextureIfNeeded(color, texCoord);
             applyTextureExternalOESIfNeeded(color, texCoord);
+            applyRoundedRectClipIfNeeded(color);
             gl_FragColor = color;
         }
     );
@@ -448,6 +532,7 @@
     SET_APPLIER_FROM_OPTIONS(ContentTexture);
     SET_APPLIER_FROM_OPTIONS(ManualRepeat);
     SET_APPLIER_FROM_OPTIONS(TextureExternalOES);
+    SET_APPLIER_FROM_OPTIONS(RoundedRectClip);
 
     StringBuilder vertexShaderBuilder;
 

Modified: trunk/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.h (268922 => 268923)


--- trunk/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.h	2020-10-23 12:44:44 UTC (rev 268922)
+++ trunk/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.h	2020-10-23 12:53:42 UTC (rev 268923)
@@ -48,6 +48,9 @@
     macro(gaussianKernel) \
     macro(blurRadius) \
     macro(shadowOffset) \
+    macro(roundedRectNumber) \
+    macro(roundedRect) \
+    macro(roundedRectInverseTransformMatrix) \
 
 #define TEXMAP_SAMPLER_VARIABLES(macro) \
     macro(sampler) \
@@ -99,6 +102,7 @@
         TextureNV21      = 1L << 20,
         TexturePackedYUV = 1L << 21,
         TextureExternalOES = 1L << 22,
+        RoundedRectClip  = 1L << 23,
     };
 
     enum class VariableID {

Modified: trunk/Source/WebKit/ChangeLog (268922 => 268923)


--- trunk/Source/WebKit/ChangeLog	2020-10-23 12:44:44 UTC (rev 268922)
+++ trunk/Source/WebKit/ChangeLog	2020-10-23 12:53:42 UTC (rev 268923)
@@ -1,3 +1,15 @@
+2020-10-23  Miguel Gomez  <[email protected]>
+
+        [GTK][WPE] Implement antialiased rounded rectangle clipping in TextureMapper
+        https://bugs.webkit.org/show_bug.cgi?id=174457
+
+        Reviewed by Carlos Garcia Campos.
+
+        Use the new TextureMapper::beginClip() method that receives a FloatRoundedRect.
+
+        * Shared/CoordinatedGraphics/CoordinatedGraphicsScene.cpp:
+        (WebKit::CoordinatedGraphicsScene::paintToCurrentGLContext):
+
 2020-10-23  Michael Catanzaro  <[email protected]>
 
         [SOUP] Fix crash in WebSocketTask

Modified: trunk/Source/WebKit/Shared/CoordinatedGraphics/CoordinatedGraphicsScene.cpp (268922 => 268923)


--- trunk/Source/WebKit/Shared/CoordinatedGraphics/CoordinatedGraphicsScene.cpp	2020-10-23 12:44:44 UTC (rev 268922)
+++ trunk/Source/WebKit/Shared/CoordinatedGraphics/CoordinatedGraphicsScene.cpp	2020-10-23 12:53:42 UTC (rev 268923)
@@ -71,7 +71,7 @@
     currentRootLayer->setTextureMapper(m_textureMapper.get());
     bool sceneHasRunningAnimations = currentRootLayer->applyAnimationsRecursively(MonotonicTime::now());
     m_textureMapper->beginPainting(PaintFlags);
-    m_textureMapper->beginClip(TransformationMatrix(), clipRect);
+    m_textureMapper->beginClip(TransformationMatrix(), FloatRoundedRect(clipRect));
 
     if (currentRootLayer->transform() != matrix)
         currentRootLayer->setTransform(matrix);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to