OSDN Git Service

WebView Animation support
[android-x86/external-webkit.git] / Source / WebCore / platform / graphics / android / ShaderProgram.cpp
index bf5f760..2a6a488 100644 (file)
@@ -62,6 +62,22 @@ static const char gFragmentShader[] =
     "  gl_FragColor *= alpha; "
     "}\n";
 
+static const char gFragmentShaderInverted[] =
+    "precision mediump float;\n"
+    "varying vec2 v_texCoord; \n"
+    "uniform float alpha; \n"
+    "uniform float contrast; \n"
+    "uniform sampler2D s_texture; \n"
+    "void main() {\n"
+    "  vec4 pixel = texture2D(s_texture, v_texCoord); \n"
+    "  float a = pixel.a; \n"
+    "  float color = a - (0.2989 * pixel.r + 0.5866 * pixel.g + 0.1145 * pixel.b);\n"
+    "  color = ((color - a/2.0) * contrast) + a/2.0; \n"
+    "  pixel.rgb = vec3(color, color, color); \n "
+    "  gl_FragColor = pixel; \n"
+    "  gl_FragColor *= alpha; \n"
+    "}\n";
+
 static const char gVideoVertexShader[] =
     "attribute vec4 vPosition;\n"
     "uniform mat4 textureMatrix;\n"
@@ -179,6 +195,8 @@ GLuint ShaderProgram::createProgram(const char* pVertexSource, const char* pFrag
 ShaderProgram::ShaderProgram()
     : m_blendingEnabled(false)
     , m_contrast(1)
+    , m_alphaLayer(false)
+    , m_currentScale(1.0f)
 {
     init();
 }
@@ -186,6 +204,7 @@ ShaderProgram::ShaderProgram()
 void ShaderProgram::init()
 {
     m_program = createProgram(gVertexShader, gFragmentShader);
+    m_programInverted = createProgram(gVertexShader, gFragmentShaderInverted);
     m_videoProgram = createProgram(gVideoVertexShader, gVideoFragmentShader);
     m_surfTexOESProgram =
         createProgram(gVertexShader, gSurfaceTextureOESFragmentShader);
@@ -193,6 +212,7 @@ void ShaderProgram::init()
         createProgram(gVertexShader, gSurfaceTextureOESFragmentShaderInverted);
 
     if (m_program == -1
+        || m_programInverted == -1
         || m_videoProgram == -1
         || m_surfTexOESProgram == -1
         || m_surfTexOESProgramInverted == -1)
@@ -203,6 +223,12 @@ void ShaderProgram::init()
     m_hTexSampler = glGetUniformLocation(m_program, "s_texture");
     m_hPosition = glGetAttribLocation(m_program, "vPosition");
 
+    m_hProjectionMatrixInverted = glGetUniformLocation(m_programInverted, "projectionMatrix");
+    m_hAlphaInverted = glGetUniformLocation(m_programInverted, "alpha");
+    m_hContrastInverted = glGetUniformLocation(m_surfTexOESProgramInverted, "contrast");
+    m_hTexSamplerInverted = glGetUniformLocation(m_programInverted, "s_texture");
+    m_hPositionInverted = glGetAttribLocation(m_programInverted, "vPosition");
+
     m_hVideoProjectionMatrix =
         glGetUniformLocation(m_videoProgram, "projectionMatrix");
     m_hVideoTextureMatrix = glGetUniformLocation(m_videoProgram, "textureMatrix");
@@ -262,13 +288,14 @@ void ShaderProgram::setBlendingState(bool enableBlending)
 // Drawing
 /////////////////////////////////////////////////////////////////////////////////////////
 
-void ShaderProgram::setViewport(SkRect& viewport)
+void ShaderProgram::setViewport(SkRect& viewport, float scale)
 {
     TransformationMatrix ortho;
     GLUtils::setOrthographicMatrix(ortho, viewport.fLeft, viewport.fTop,
                                    viewport.fRight, viewport.fBottom, -1000, 1000);
     m_projectionMatrix = ortho;
     m_viewport = viewport;
+    m_currentScale = scale;
 }
 
 void ShaderProgram::setProjectionMatrix(SkRect& geometry, GLint projectionMatrixHandle)
@@ -278,7 +305,12 @@ void ShaderProgram::setProjectionMatrix(SkRect& geometry, GLint projectionMatrix
     TransformationMatrix scale;
     scale.scale3d(geometry.width(), geometry.height(), 1.0);
 
-    TransformationMatrix total = m_projectionMatrix * translate * scale;
+    TransformationMatrix total;
+    if (!m_alphaLayer)
+        total = m_projectionMatrix * m_repositionMatrix * m_webViewMatrix
+                * translate * scale;
+    else
+        total = m_projectionMatrix * translate * scale;
 
     GLfloat projectionMatrix[16];
     GLUtils::toGLMatrix(projectionMatrix, total);
@@ -294,6 +326,7 @@ void ShaderProgram::drawQuadInternal(SkRect& geometry,
                                      GLenum textureTarget,
                                      GLint position,
                                      GLint alpha,
+                                     GLint texFilter,
                                      GLint contrast)
 {
     glUseProgram(program);
@@ -313,8 +346,8 @@ void ShaderProgram::drawQuadInternal(SkRect& geometry,
     glActiveTexture(GL_TEXTURE0);
     glUniform1i(texSampler, 0);
     glBindTexture(textureTarget, textureId);
-    glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, texFilter);
+    glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, texFilter);
     glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
@@ -330,26 +363,38 @@ void ShaderProgram::drawQuadInternal(SkRect& geometry,
 }
 
 void ShaderProgram::drawQuad(SkRect& geometry, int textureId, float opacity,
-                             GLenum textureTarget)
+                             GLenum textureTarget, GLint texFilter)
 {
     if (textureTarget == GL_TEXTURE_2D) {
-        drawQuadInternal(geometry, textureId, opacity, m_program,
-                         m_hProjectionMatrix,
-                         m_hTexSampler, GL_TEXTURE_2D,
-                         m_hPosition, alpha());
+        if (!TilesManager::instance()->invertedScreen()) {
+            drawQuadInternal(geometry, textureId, opacity, m_program,
+                             m_hProjectionMatrix,
+                             m_hTexSampler, GL_TEXTURE_2D,
+                             m_hPosition, m_hAlpha, texFilter);
+        } else {
+            // With the new GPU texture upload path, we do not use an FBO
+            // to blit the texture we receive from the TexturesGenerator thread.
+            // To implement inverted rendering, we thus have to do the rendering
+            // live, by using a different shader.
+            drawQuadInternal(geometry, textureId, opacity, m_programInverted,
+                             m_hProjectionMatrixInverted,
+                             m_hTexSamplerInverted, GL_TEXTURE_2D,
+                             m_hPositionInverted, m_hAlphaInverted, texFilter,
+                             m_hContrastInverted);
+        }
     } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES
                && !TilesManager::instance()->invertedScreen()) {
         drawQuadInternal(geometry, textureId, opacity, m_surfTexOESProgram,
                          m_hSTOESProjectionMatrix,
                          m_hSTOESTexSampler, GL_TEXTURE_EXTERNAL_OES,
-                         m_hSTOESPosition, m_hSTOESAlpha);
+                         m_hSTOESPosition, m_hSTOESAlpha, texFilter);
     } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES
                && TilesManager::instance()->invertedScreen()) {
         drawQuadInternal(geometry, textureId, opacity, m_surfTexOESProgramInverted,
                          m_hSTOESProjectionMatrixInverted,
                          m_hSTOESTexSamplerInverted, GL_TEXTURE_EXTERNAL_OES,
                          m_hSTOESPositionInverted, m_hSTOESAlphaInverted,
-                         m_hSTOESContrastInverted);
+                         texFilter, m_hSTOESContrastInverted);
     }
     GLUtils::checkGlError("drawQuad");
 }
@@ -371,6 +416,9 @@ void ShaderProgram::setViewRect(const IntRect& viewRect)
 
     translate.scale3d(1, -1, 1);
     m_documentToInvScreenMatrix = scale * translate * m_projectionMatrix;
+
+    IntRect rect(0, 0, m_webViewRect.width(), m_webViewRect.height());
+    m_documentViewport = m_documentToScreenMatrix.inverse().mapRect(rect);
 }
 
 // This function transform a clip rect extracted from the current layer
@@ -400,6 +448,11 @@ FloatRect ShaderProgram::rectInScreenCoord(const FloatRect& rect)
     return m_documentToScreenMatrix.mapRect(rect);
 }
 
+FloatRect ShaderProgram::convertScreenCoordToDocumentCoord(const FloatRect& rect)
+{
+    return m_documentToScreenMatrix.inverse().mapRect(rect);
+}
+
 FloatRect ShaderProgram::convertInvScreenCoordToScreenCoord(const FloatRect& rect)
 {
     FloatRect documentRect = m_documentToInvScreenMatrix.inverse().mapRect(rect);
@@ -506,23 +559,38 @@ void ShaderProgram::drawLayerQuadInternal(const GLfloat* projectionMatrix,
 
 
 void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix,
-                                  SkRect& geometry, int textureId, float opacity,
-                                  bool forceBlending, GLenum textureTarget)
+                                  const SkRect& geometry, int textureId,
+                                  float opacity, bool forceBlending,
+                                  GLenum textureTarget)
 {
 
     TransformationMatrix modifiedDrawMatrix = drawMatrix;
     // move the drawing depending on where the texture is on the layer
     modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop);
     modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1);
-    TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
+
+    TransformationMatrix renderMatrix;
+    if (!m_alphaLayer)
+        renderMatrix = m_projectionMatrix * m_repositionMatrix
+                       * m_webViewMatrix * modifiedDrawMatrix;
+    else
+        renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
 
     GLfloat projectionMatrix[16];
     GLUtils::toGLMatrix(projectionMatrix, renderMatrix);
     if (textureTarget == GL_TEXTURE_2D) {
-        drawLayerQuadInternal(projectionMatrix, textureId, opacity,
-                              GL_TEXTURE_2D, m_program,
-                              m_hProjectionMatrix, m_hTexSampler,
-                              m_hPosition, alpha());
+        if (!TilesManager::instance()->invertedScreen()) {
+            drawLayerQuadInternal(projectionMatrix, textureId, opacity,
+                                  GL_TEXTURE_2D, m_program,
+                                  m_hProjectionMatrix, m_hTexSampler,
+                                  m_hPosition, m_hAlpha);
+        } else {
+            drawLayerQuadInternal(projectionMatrix, textureId, opacity,
+                                  GL_TEXTURE_2D, m_programInverted,
+                                  m_hProjectionMatrixInverted, m_hTexSamplerInverted,
+                                  m_hPositionInverted, m_hAlphaInverted,
+                                  m_hContrastInverted);
+        }
     } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES
                && !TilesManager::instance()->invertedScreen()) {
         drawLayerQuadInternal(projectionMatrix, textureId, opacity,
@@ -573,6 +641,44 @@ void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix,
     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 }
 
+void ShaderProgram::setWebViewMatrix(const float* matrix, bool alphaLayer)
+{
+    GLUtils::convertToTransformationMatrix(matrix, m_webViewMatrix);
+    m_alphaLayer = alphaLayer;
+}
+
+void ShaderProgram::calculateAnimationDelta()
+{
+    // The matrix contains the scrolling info, so this rect is starting from
+    // the m_viewport.
+    // So we just need to map the webview's visible rect using the matrix,
+    // calculate the difference b/t transformed rect and the webViewRect,
+    // then we can get the delta x , y caused by the animation.
+    // Note that the Y is for reporting back to GL viewport, so it is inverted.
+    // When it is alpha animation, then we rely on the framework implementation
+    // such that there is no matrix applied in native webkit.
+    if (!m_alphaLayer) {
+        FloatRect rect(m_viewport.fLeft * m_currentScale,
+                       m_viewport.fTop * m_currentScale,
+                       m_webViewRect.width(),
+                       m_webViewRect.height());
+        rect = m_webViewMatrix.mapRect(rect);
+        m_animationDelta.setX(rect.x() - m_webViewRect.x() );
+        m_animationDelta.setY(rect.y() + rect.height() - m_webViewRect.y()
+                              - m_webViewRect.height() - m_titleBarHeight);
+
+        m_repositionMatrix.makeIdentity();
+        m_repositionMatrix.translate3d(-m_webViewRect.x(), -m_webViewRect.y() - m_titleBarHeight, 0);
+        m_repositionMatrix.translate3d(m_viewport.fLeft * m_currentScale, m_viewport.fTop * m_currentScale, 0);
+        m_repositionMatrix.translate3d(-m_animationDelta.x(), -m_animationDelta.y(), 0);
+    } else {
+        m_animationDelta.setX(0);
+        m_animationDelta.setY(0);
+        m_repositionMatrix.makeIdentity();
+    }
+
+}
+
 } // namespace WebCore
 
 #endif // USE(ACCELERATED_COMPOSITING)