Bug 607936 - Make possible to apply transform on topLevel LayerManager scene r=matt,roc a=joe
authorOleg Romashin <romaxa@gmail.com>
Fri, 04 Feb 2011 14:47:06 -0500
changeset 61955 c8a2a8063a1cb47a343b8fffed522d4b1eb83e9b
parent 61954 beb7483fcb5d1236d46a399f4e35cb5471d53ade
child 61956 261614faec16fd03500260004219bda4bd341b66
push id1
push userroot
push dateTue, 10 Dec 2013 15:46:25 +0000
reviewersmatt, roc, joe
bugs607936
milestone2.0b12pre
Bug 607936 - Make possible to apply transform on topLevel LayerManager scene r=matt,roc a=joe
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/thebes/gfxMatrix.h
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -206,17 +206,18 @@ ContainerRender(Container* aContainer,
     aManager->CreateFBOWithTexture(framebufferRect,
                                    mode,
                                    &frameBuffer,
                                    &containerSurface);
     childOffset.x = visibleRect.x;
     childOffset.y = visibleRect.y;
 
     aContainer->gl()->PushViewportRect();
-    aManager->SetupPipeline(visibleRect.width, visibleRect.height);
+    aManager->SetupPipeline(visibleRect.width, visibleRect.height,
+                            LayerManagerOGL::DontApplyWorldTransform);
 
   } else {
     frameBuffer = aPreviousFrameBuffer;
     aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) ||
       (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren());
 #ifdef DEBUG
     PRBool is2d =
 #endif
@@ -251,16 +252,21 @@ ContainerRender(Container* aContainer,
           scissorRect = visibleRect;
         }
       }
     }
 
     if (needsFramebuffer) {
       scissorRect.MoveBy(- visibleRect.TopLeft());
     } else {
+      if (!frameBuffer) {
+        // Transform scissorRect here
+        aManager->WorldTransformRect(scissorRect);
+      }
+
       if (!aPreviousFrameBuffer) {
         /**
          * glScissor coordinates are oriented with 0,0 being at the bottom left,
          * the opposite to layout (0,0 at the top left).
          * All rendering to an FBO is upside-down, making the coordinate systems
          * match.
          * When rendering directly to a window (No current or previous FBO),
          * we need to flip the scissor rect.
@@ -293,17 +299,18 @@ ContainerRender(Container* aContainer,
   aContainer->gl()->PopScissorRect();
 
   if (needsFramebuffer) {
     // Unbind the current framebuffer and rebind the previous one.
     
     // Restore the viewport
     aContainer->gl()->PopViewportRect();
     nsIntRect viewport = aContainer->gl()->ViewportRect();
-    aManager->SetupPipeline(viewport.width, viewport.height);
+    aManager->SetupPipeline(viewport.width, viewport.height,
+                            LayerManagerOGL::ApplyWorldTransform);
 
     aContainer->gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
     aContainer->gl()->fDeleteFramebuffers(1, &frameBuffer);
 
     aContainer->gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 
     aContainer->gl()->fBindTexture(aManager->FBOTextureTarget(), containerSurface);
 
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -545,16 +545,17 @@ LayerManagerOGL::Render()
 {
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return;
   }
 
   nsIntRect rect;
   mWidget->GetClientBounds(rect);
+  WorldTransformRect(rect);
 
   GLint width = rect.width;
   GLint height = rect.height;
 
   // We can't draw anything to something with no area
   // so just return
   if (width == 0 || height == 0)
     return;
@@ -570,29 +571,30 @@ LayerManagerOGL::Render()
     mWidgetSize.height = height;
   } else {
     MakeCurrent();
   }
 
   DEBUG_GL_ERROR_CHECK(mGLContext);
 
   SetupBackBuffer(width, height);
-  SetupPipeline(width, height);
+  SetupPipeline(width, height, ApplyWorldTransform);
 
   // Default blend function implements "OVER"
   mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
                                  LOCAL_GL_ONE, LOCAL_GL_ONE);
   mGLContext->fEnable(LOCAL_GL_BLEND);
 
   DEBUG_GL_ERROR_CHECK(mGLContext);
 
   const nsIntRect *clipRect = mRoot->GetClipRect();
 
   if (clipRect) {
     nsIntRect r = *clipRect;
+    WorldTransformRect(r);
     if (!mGLContext->IsDoubleBuffered() && !mTarget)
       mGLContext->FixWindowCoordinateRect(r, mWidgetSize.height);
     mGLContext->fScissor(r.x, r.y, r.width, r.height);
   } else {
     mGLContext->fScissor(0, 0, width, height);
   }
 
   mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
@@ -657,16 +659,18 @@ LayerManagerOGL::Render()
 
   mGLContext->fEnableVertexAttribArray(vcattr);
   mGLContext->fEnableVertexAttribArray(tcattr);
 
   const nsIntRect *r;
   nsIntRegionRectIterator iter(mClippingRegion);
 
   while ((r = iter.Next()) != nsnull) {
+    nsIntRect cRect = *r; r = &cRect;
+    WorldTransformRect(cRect);
     float left = (GLfloat)r->x / width;
     float right = (GLfloat)r->XMost() / width;
     float top = (GLfloat)r->y / height;
     float bottom = (GLfloat)r->YMost() / height;
 
     float vertices[] = { left * 2.0f - 1.0f,
                          -(top * 2.0f - 1.0f),
                          right * 2.0f - 1.0f,
@@ -701,17 +705,42 @@ LayerManagerOGL::Render()
   DEBUG_GL_ERROR_CHECK(mGLContext);
 
   mGLContext->fFlush();
 
   DEBUG_GL_ERROR_CHECK(mGLContext);
 }
 
 void
-LayerManagerOGL::SetupPipeline(int aWidth, int aHeight)
+LayerManagerOGL::SetWorldTransform(const gfxMatrix& aMatrix)
+{
+  NS_ASSERTION(aMatrix.PreservesAxisAlignedRectangles(),
+               "SetWorldTransform only accepts matrices that satisfy PreservesAxisAlignedRectangles");
+  NS_ASSERTION(!aMatrix.HasNonIntegerScale(),
+               "SetWorldTransform only accepts matrices with integer scale");
+
+  mWorldMatrix = aMatrix;
+}
+
+gfxMatrix&
+LayerManagerOGL::GetWorldTransform(void)
+{
+  return mWorldMatrix;
+}
+
+void
+LayerManagerOGL::WorldTransformRect(nsIntRect& aRect)
+{
+  gfxRect grect(aRect.x, aRect.y, aRect.width, aRect.height);
+  grect = mWorldMatrix.TransformBounds(grect);
+  aRect.SetRect(grect.pos.x, grect.pos.y, grect.size.width, grect.size.height);
+}
+
+void
+LayerManagerOGL::SetupPipeline(int aWidth, int aHeight, WorldTransforPolicy aTransformPolicy)
 {
   // Set the viewport correctly. 
   //
   // When we're not double buffering, we use a FBO as our backbuffer.
   // We use a normal view transform in that case, meaning that our FBO
   // and all other FBOs look upside down.  We then do a Y-flip when
   // we draw it into the window.
   mGLContext->fViewport(0, 0, aWidth, aHeight);
@@ -739,16 +768,20 @@ LayerManagerOGL::SetupPipeline(int aWidt
     viewMatrix._42 = 1.0f;
   } else {
     viewMatrix._11 = 2.0f / float(aWidth);
     viewMatrix._22 = 2.0f / float(aHeight);
     viewMatrix._41 = -1.0f;
     viewMatrix._42 = -1.0f;
   }
 
+  if (aTransformPolicy == ApplyWorldTransform) {
+    viewMatrix = gfx3DMatrix::From2D(mWorldMatrix) * viewMatrix;
+  }
+
   SetLayerProgramProjectionMatrix(viewMatrix);
 }
 
 void
 LayerManagerOGL::SetupBackBuffer(int aWidth, int aHeight)
 {
   if (mGLContext->IsDoubleBuffered() && !mTarget) {
     mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -367,21 +367,35 @@ public:
 #ifdef MOZ_LAYERS_HAVE_LOG
   virtual const char* Name() const { return "OGL"; }
 #endif // MOZ_LAYERS_HAVE_LOG
 
   const nsIntSize& GetWigetSize() {
     return mWidgetSize;
   }
 
+  enum WorldTransforPolicy {
+    ApplyWorldTransform,
+    DontApplyWorldTransform
+  };
+
   /**
    * Setup the viewport and projection matrix for rendering
    * to a window of the given dimensions.
    */
-  void SetupPipeline(int aWidth, int aHeight);
+  void SetupPipeline(int aWidth, int aHeight, WorldTransforPolicy aTransformPolicy);
+
+  /**
+   * Setup World transform matrix.
+   * Transform will be ignored if it is not PreservesAxisAlignedRectangles
+   * or has non integer scale
+   */
+  void SetWorldTransform(const gfxMatrix& aMatrix);
+  gfxMatrix& GetWorldTransform(void);
+  void WorldTransformRect(nsIntRect& aRect);
 
 private:
   /** Widget associated with this layer manager */
   nsIWidget *mWidget;
   nsIntSize mWidgetSize;
 
   /** 
    * Context target, NULL when drawing directly to our swap chain.
@@ -450,16 +464,17 @@ private:
    * If we have any more similar updates, then we should delay.
    */
   void SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix);
 
   /* Thebes layer callbacks; valid at the end of a transaciton,
    * while rendering */
   DrawThebesLayerCallback mThebesLayerCallback;
   void *mThebesLayerCallbackData;
+  gfxMatrix mWorldMatrix;
 };
 
 /**
  * General information and tree management for OGL layers.
  */
 class LayerOGL
 {
 public:
--- a/gfx/thebes/gfxMatrix.h
+++ b/gfx/thebes/gfxMatrix.h
@@ -276,15 +276,23 @@ public:
      * Returns true if matrix is multiple of 90 degrees rotation with flipping,
      * scaling and translation.
      */
     PRBool PreservesAxisAlignedRectangles() const {
         return ((FuzzyEqual(xx, 0.0) && FuzzyEqual(yy, 0.0))
             || (FuzzyEqual(xy, 0.0) && FuzzyEqual(yx, 0.0)));
     }
 
+    /**
+     * Returns true if the matrix has non-integer scale
+     */
+    PRBool HasNonIntegerScale() const {
+        return !FuzzyEqual(xx, NS_floor(xx + 0.5)) ||
+               !FuzzyEqual(yy, NS_floor(yy + 0.5));
+    }
+
 private:
     static PRBool FuzzyEqual(gfxFloat aV1, gfxFloat aV2) {
         return fabs(aV2 - aV1) < 1e-6;
     }
 };
 
 #endif /* GFX_MATRIX_H */