LCOV - code coverage report
Current view: directory - gfx/layers/opengl - ThebesLayerOGL.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 428 0 0.0 %
Date: 2012-06-02 Functions: 52 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Corporation code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Bas Schouten <bschouten@mozilla.org>
      23                 :  *   Vladimir Vukicevic <vladimir@pobox.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "mozilla/layers/PLayers.h"
      40                 : 
      41                 : /* This must occur *after* layers/PLayers.h to avoid typedefs conflicts. */
      42                 : #include "mozilla/Util.h"
      43                 : 
      44                 : #include "mozilla/layers/ShadowLayers.h"
      45                 : 
      46                 : #include "ThebesLayerBuffer.h"
      47                 : #include "ThebesLayerOGL.h"
      48                 : #include "gfxUtils.h"
      49                 : #include "gfxTeeSurface.h"
      50                 : 
      51                 : namespace mozilla {
      52                 : namespace layers {
      53                 : 
      54                 : using gl::GLContext;
      55                 : using gl::TextureImage;
      56                 : 
      57                 : static const int ALLOW_REPEAT = ThebesLayerBuffer::ALLOW_REPEAT;
      58                 : 
      59                 : // BindAndDrawQuadWithTextureRect can work with either GL_REPEAT (preferred)
      60                 : // or GL_CLAMP_TO_EDGE textures. If ALLOW_REPEAT is set in aFlags, we
      61                 : // select based on whether REPEAT is valid for non-power-of-two textures --
      62                 : // if we have NPOT support we use it, otherwise we stick with CLAMP_TO_EDGE and
      63                 : // decompose.
      64                 : // If ALLOW_REPEAT is not set, we always use GL_CLAMP_TO_EDGE.
      65                 : static already_AddRefed<TextureImage>
      66               0 : CreateClampOrRepeatTextureImage(GLContext *aGl,
      67                 :                                 const nsIntSize& aSize,
      68                 :                                 TextureImage::ContentType aContentType,
      69                 :                                 PRUint32 aFlags)
      70                 : {
      71               0 :   GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
      72               0 :   if ((aFlags & ALLOW_REPEAT) &&
      73               0 :       (aGl->IsExtensionSupported(GLContext::ARB_texture_non_power_of_two) ||
      74               0 :        aGl->IsExtensionSupported(GLContext::OES_texture_npot)))
      75                 :   {
      76               0 :     wrapMode = LOCAL_GL_REPEAT;
      77                 :   }
      78                 : 
      79               0 :   return aGl->CreateTextureImage(aSize, aContentType, wrapMode);
      80                 : }
      81                 : 
      82                 : static void
      83               0 : SetAntialiasingFlags(Layer* aLayer, gfxContext* aTarget)
      84                 : {
      85               0 :   nsRefPtr<gfxASurface> surface = aTarget->CurrentSurface();
      86               0 :   if (surface->GetContentType() != gfxASurface::CONTENT_COLOR_ALPHA) {
      87                 :     // Destination doesn't have alpha channel; no need to set any special flags
      88                 :     return;
      89                 :   }
      90                 : 
      91                 :   surface->SetSubpixelAntialiasingEnabled(
      92               0 :       !(aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA));
      93                 : }
      94                 : 
      95                 : class ThebesLayerBufferOGL
      96                 : {
      97               0 :   NS_INLINE_DECL_REFCOUNTING(ThebesLayerBufferOGL)
      98                 : public:
      99                 :   typedef TextureImage::ContentType ContentType;
     100                 :   typedef ThebesLayerBuffer::PaintState PaintState;
     101                 : 
     102               0 :   ThebesLayerBufferOGL(ThebesLayer* aLayer, LayerOGL* aOGLLayer)
     103                 :     : mLayer(aLayer)
     104               0 :     , mOGLLayer(aOGLLayer)
     105               0 :   {}
     106               0 :   virtual ~ThebesLayerBufferOGL() {}
     107                 : 
     108                 :   enum { PAINT_WILL_RESAMPLE = ThebesLayerBuffer::PAINT_WILL_RESAMPLE };
     109                 :   virtual PaintState BeginPaint(ContentType aContentType,
     110                 :                                 PRUint32 aFlags) = 0;
     111                 : 
     112                 :   void RenderTo(const nsIntPoint& aOffset, LayerManagerOGL* aManager,
     113                 :                 PRUint32 aFlags);
     114                 : 
     115               0 :   nsIntSize GetSize() {
     116               0 :     if (mTexImage)
     117               0 :       return mTexImage->GetSize();
     118               0 :     return nsIntSize(0, 0);
     119                 :   }
     120                 : 
     121                 : protected:
     122                 :   virtual nsIntPoint GetOriginOffset() = 0;
     123                 : 
     124               0 :   GLContext* gl() const { return mOGLLayer->gl(); }
     125                 : 
     126                 :   ThebesLayer* mLayer;
     127                 :   LayerOGL* mOGLLayer;
     128                 :   nsRefPtr<TextureImage> mTexImage;
     129                 :   nsRefPtr<TextureImage> mTexImageOnWhite;
     130                 : };
     131                 : 
     132                 : void
     133               0 : ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
     134                 :                                LayerManagerOGL* aManager,
     135                 :                                PRUint32 aFlags)
     136                 : {
     137               0 :   if (!mTexImage)
     138               0 :     return;
     139                 : 
     140               0 :   if (mTexImage->InUpdate()) {
     141               0 :     mTexImage->EndUpdate();
     142                 :   }
     143                 : 
     144               0 :   if (mTexImageOnWhite && mTexImageOnWhite->InUpdate()) {
     145               0 :     mTexImageOnWhite->EndUpdate();
     146                 :   }
     147                 : 
     148                 : #ifdef MOZ_DUMP_PAINTING
     149               0 :   if (gfxUtils::sDumpPainting) {
     150                 :     nsRefPtr<gfxImageSurface> surf = 
     151               0 :       gl()->GetTexImage(mTexImage->GetTextureID(), false, mTexImage->GetShaderProgramType());
     152                 :     
     153               0 :     WriteSnapshotToDumpFile(mLayer, surf);
     154                 :   }
     155                 : #endif
     156                 : 
     157               0 :   PRInt32 passes = mTexImageOnWhite ? 2 : 1;
     158               0 :   for (PRInt32 pass = 1; pass <= passes; ++pass) {
     159                 :     LayerProgram *program;
     160                 : 
     161               0 :     if (passes == 2) {
     162                 :       ComponentAlphaTextureLayerProgram *alphaProgram;
     163               0 :       if (pass == 1) {
     164               0 :         alphaProgram = aManager->GetComponentAlphaPass1LayerProgram();
     165                 :         gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
     166               0 :                                  LOCAL_GL_ONE, LOCAL_GL_ONE);
     167                 :       } else {
     168               0 :         alphaProgram = aManager->GetComponentAlphaPass2LayerProgram();
     169                 :         gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
     170               0 :                                  LOCAL_GL_ONE, LOCAL_GL_ONE);
     171                 :       }
     172                 : 
     173               0 :       alphaProgram->Activate();
     174               0 :       alphaProgram->SetBlackTextureUnit(0);
     175               0 :       alphaProgram->SetWhiteTextureUnit(1);
     176               0 :       program = alphaProgram;
     177                 :     } else {
     178                 :       // Note BGR: Cairo's image surfaces are always in what
     179                 :       // OpenGL and our shaders consider BGR format.
     180                 :       ColorTextureLayerProgram *basicProgram =
     181               0 :         aManager->GetColorTextureLayerProgram(mTexImage->GetShaderProgramType());
     182                 : 
     183               0 :       basicProgram->Activate();
     184               0 :       basicProgram->SetTextureUnit(0);
     185               0 :       program = basicProgram;
     186                 :     }
     187                 : 
     188               0 :     program->SetLayerOpacity(mLayer->GetEffectiveOpacity());
     189               0 :     program->SetLayerTransform(mLayer->GetEffectiveTransform());
     190               0 :     program->SetRenderOffset(aOffset);
     191                 : 
     192               0 :     const nsIntRegion& visibleRegion = mLayer->GetEffectiveVisibleRegion();
     193               0 :     nsIntRegion tmpRegion;
     194                 :     const nsIntRegion* renderRegion;
     195               0 :     if (aFlags & PAINT_WILL_RESAMPLE) {
     196                 :       // If we're resampling, then the texture image will contain exactly the
     197                 :       // entire visible region's bounds, and we should draw it all in one quad
     198                 :       // to avoid unexpected aliasing.
     199               0 :       tmpRegion = visibleRegion.GetBounds();
     200               0 :       renderRegion = &tmpRegion;
     201                 :     } else {
     202               0 :       renderRegion = &visibleRegion;
     203                 :     }
     204                 : 
     205               0 :     nsIntRegion region(*renderRegion);
     206               0 :     nsIntPoint origin = GetOriginOffset();
     207               0 :     region.MoveBy(-origin);           // translate into TexImage space, buffer origin might not be at texture (0,0)
     208                 : 
     209                 :     // Figure out the intersecting draw region
     210               0 :     nsIntSize texSize = mTexImage->GetSize();
     211               0 :     nsIntRect textureRect = nsIntRect(0, 0, texSize.width, texSize.height);
     212               0 :     textureRect.MoveBy(region.GetBounds().TopLeft());
     213               0 :     nsIntRegion subregion;
     214               0 :     subregion.And(region, textureRect);
     215               0 :     if (subregion.IsEmpty())  // Region is empty, nothing to draw
     216                 :       return;
     217                 : 
     218               0 :     nsIntRegion screenRects;
     219               0 :     nsIntRegion regionRects;
     220                 : 
     221                 :     // Collect texture/screen coordinates for drawing
     222               0 :     nsIntRegionRectIterator iter(subregion);
     223               0 :     while (const nsIntRect* iterRect = iter.Next()) {
     224               0 :         nsIntRect regionRect = *iterRect;
     225               0 :         nsIntRect screenRect = regionRect;
     226               0 :         screenRect.MoveBy(origin);
     227                 : 
     228               0 :         screenRects.Or(screenRects, screenRect);
     229               0 :         regionRects.Or(regionRects, regionRect);
     230                 :     }
     231                 : 
     232               0 :     mTexImage->BeginTileIteration();
     233               0 :     if (mTexImageOnWhite) {
     234               0 :       NS_ASSERTION(mTexImage->GetTileCount() == mTexImageOnWhite->GetTileCount(),
     235                 :                    "Tile count mismatch on component alpha texture");
     236               0 :       mTexImageOnWhite->BeginTileIteration();
     237                 :     }
     238                 : 
     239               0 :     bool usingTiles = (mTexImage->GetTileCount() > 1);
     240               0 :     do {
     241               0 :       if (mTexImageOnWhite) {
     242               0 :         NS_ASSERTION(mTexImageOnWhite->GetTileRect() == mTexImage->GetTileRect(), "component alpha textures should be the same size.");
     243                 :       }
     244                 : 
     245               0 :       nsIntRect tileRect = mTexImage->GetTileRect();
     246                 : 
     247                 :       // Bind textures.
     248               0 :       TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0);
     249               0 :       TextureImage::ScopedBindTexture texOnWhiteBind(mTexImageOnWhite, LOCAL_GL_TEXTURE1);
     250                 : 
     251                 :       // Draw texture. If we're using tiles, we do repeating manually, as texture
     252                 :       // repeat would cause each individual tile to repeat instead of the
     253                 :       // compound texture as a whole. This involves drawing at most 4 sections,
     254                 :       // 2 for each axis that has texture repeat.
     255               0 :       for (int y = 0; y < (usingTiles ? 2 : 1); y++) {
     256               0 :         for (int x = 0; x < (usingTiles ? 2 : 1); x++) {
     257               0 :           nsIntRect currentTileRect(tileRect);
     258               0 :           currentTileRect.MoveBy(x * texSize.width, y * texSize.height);
     259                 : 
     260               0 :           nsIntRegionRectIterator screenIter(screenRects);
     261               0 :           nsIntRegionRectIterator regionIter(regionRects);
     262                 : 
     263                 :           const nsIntRect* screenRect;
     264                 :           const nsIntRect* regionRect;
     265               0 :           while ((screenRect = screenIter.Next()) &&
     266                 :                  (regionRect = regionIter.Next())) {
     267               0 :               nsIntRect tileScreenRect(*screenRect);
     268               0 :               nsIntRect tileRegionRect(*regionRect);
     269                 : 
     270                 :               // When we're using tiles, find the intersection between the tile
     271                 :               // rect and this region rect. Tiling is then handled by the
     272                 :               // outer for-loops and modifying the tile rect.
     273               0 :               if (usingTiles) {
     274               0 :                   tileScreenRect.MoveBy(-origin);
     275               0 :                   tileScreenRect = tileScreenRect.Intersect(currentTileRect);
     276               0 :                   tileScreenRect.MoveBy(origin);
     277                 : 
     278               0 :                   if (tileScreenRect.IsEmpty())
     279               0 :                     continue;
     280                 : 
     281               0 :                   tileRegionRect = regionRect->Intersect(currentTileRect);
     282               0 :                   tileRegionRect.MoveBy(-currentTileRect.TopLeft());
     283                 :               }
     284                 : 
     285                 : #ifdef ANDROID
     286                 :               // Bug 691354
     287                 :               // Using the LINEAR filter we get unexplained artifacts.
     288                 :               // Use NEAREST when no scaling is required.
     289                 :               gfxMatrix matrix;
     290                 :               bool is2D = mLayer->GetEffectiveTransform().Is2D(&matrix);
     291                 :               if (is2D && !matrix.HasNonTranslationOrFlip()) {
     292                 :                 gl()->ApplyFilterToBoundTexture(gfxPattern::FILTER_NEAREST);
     293                 :               } else {
     294                 :                 mTexImage->ApplyFilter();
     295                 :               }
     296                 : #endif
     297               0 :               program->SetLayerQuadRect(tileScreenRect);
     298                 :               aManager->BindAndDrawQuadWithTextureRect(program, tileRegionRect,
     299                 :                                                        tileRect.Size(),
     300               0 :                                                        mTexImage->GetWrapMode());
     301                 :           }
     302                 :         }
     303                 :       }
     304                 : 
     305               0 :       if (mTexImageOnWhite)
     306               0 :           mTexImageOnWhite->NextTile();
     307               0 :     } while (mTexImage->NextTile());
     308                 :   }
     309                 : 
     310               0 :   if (mTexImageOnWhite) {
     311                 :     // Restore defaults
     312                 :     gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
     313               0 :                              LOCAL_GL_ONE, LOCAL_GL_ONE);
     314                 :   }
     315                 : }
     316                 : 
     317                 : 
     318                 : // This implementation is the fast-path for when our TextureImage is
     319                 : // permanently backed with a server-side ASurface.  We can simply
     320                 : // reuse the ThebesLayerBuffer logic in its entirety and profit.
     321                 : class SurfaceBufferOGL : public ThebesLayerBufferOGL, private ThebesLayerBuffer
     322                 : {
     323                 : public:
     324                 :   typedef ThebesLayerBufferOGL::ContentType ContentType;
     325                 :   typedef ThebesLayerBufferOGL::PaintState PaintState;
     326                 : 
     327               0 :   SurfaceBufferOGL(ThebesLayerOGL* aLayer)
     328                 :     : ThebesLayerBufferOGL(aLayer, aLayer)
     329               0 :     , ThebesLayerBuffer(SizedToVisibleBounds)
     330                 :   {
     331               0 :   }
     332               0 :   virtual ~SurfaceBufferOGL() {}
     333                 : 
     334                 :   // ThebesLayerBufferOGL interface
     335               0 :   virtual PaintState BeginPaint(ContentType aContentType, 
     336                 :                                 PRUint32 aFlags)
     337                 :   {
     338                 :     // Let ThebesLayerBuffer do all the hard work for us! :D
     339                 :     return ThebesLayerBuffer::BeginPaint(mLayer, 
     340                 :                                          aContentType, 
     341               0 :                                          aFlags);
     342                 :   }
     343                 : 
     344                 :   // ThebesLayerBuffer interface
     345                 :   virtual already_AddRefed<gfxASurface>
     346               0 :   CreateBuffer(ContentType aType, const nsIntSize& aSize, PRUint32 aFlags)
     347                 :   {
     348               0 :     NS_ASSERTION(gfxASurface::CONTENT_ALPHA != aType,"ThebesBuffer has color");
     349                 : 
     350               0 :     mTexImage = CreateClampOrRepeatTextureImage(gl(), aSize, aType, aFlags);
     351               0 :     return mTexImage ? mTexImage->GetBackingSurface() : nsnull;
     352                 :   }
     353                 : 
     354                 : protected:
     355               0 :   virtual nsIntPoint GetOriginOffset() {
     356               0 :     return BufferRect().TopLeft() - BufferRotation();
     357                 :   }
     358                 : };
     359                 : 
     360                 : 
     361                 : // This implementation is (currently) the slow-path for when we can't
     362                 : // implement pixel retaining using thebes.  This implementation and
     363                 : // the above could be unified by abstracting buffer-copy operations
     364                 : // and implementing them here using GL hacketry.
     365                 : class BasicBufferOGL : public ThebesLayerBufferOGL
     366                 : {
     367                 : public:
     368               0 :   BasicBufferOGL(ThebesLayerOGL* aLayer)
     369                 :     : ThebesLayerBufferOGL(aLayer, aLayer)
     370                 :     , mBufferRect(0,0,0,0)
     371               0 :     , mBufferRotation(0,0)
     372               0 :   {}
     373               0 :   virtual ~BasicBufferOGL() {}
     374                 : 
     375                 :   virtual PaintState BeginPaint(ContentType aContentType,
     376                 :                                 PRUint32 aFlags);
     377                 : 
     378                 : protected:
     379                 :   enum XSide {
     380                 :     LEFT, RIGHT
     381                 :   };
     382                 :   enum YSide {
     383                 :     TOP, BOTTOM
     384                 :   };
     385                 :   nsIntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide);
     386                 : 
     387               0 :   virtual nsIntPoint GetOriginOffset() {
     388               0 :     return mBufferRect.TopLeft() - mBufferRotation;
     389                 :   }
     390                 : 
     391                 : private:
     392                 :   nsIntRect mBufferRect;
     393                 :   nsIntPoint mBufferRotation;
     394                 : };
     395                 : 
     396                 : static void
     397               0 : WrapRotationAxis(PRInt32* aRotationPoint, PRInt32 aSize)
     398                 : {
     399               0 :   if (*aRotationPoint < 0) {
     400               0 :     *aRotationPoint += aSize;
     401               0 :   } else if (*aRotationPoint >= aSize) {
     402               0 :     *aRotationPoint -= aSize;
     403                 :   }
     404               0 : }
     405                 : 
     406                 : nsIntRect
     407               0 : BasicBufferOGL::GetQuadrantRectangle(XSide aXSide, YSide aYSide)
     408                 : {
     409                 :   // quadrantTranslation is the amount we translate the top-left
     410                 :   // of the quadrant by to get coordinates relative to the layer
     411               0 :   nsIntPoint quadrantTranslation = -mBufferRotation;
     412               0 :   quadrantTranslation.x += aXSide == LEFT ? mBufferRect.width : 0;
     413               0 :   quadrantTranslation.y += aYSide == TOP ? mBufferRect.height : 0;
     414               0 :   return mBufferRect + quadrantTranslation;
     415                 : }
     416                 : 
     417                 : static void
     418               0 : FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
     419                 :             const nsIntPoint& aOffset, const gfxRGBA& aColor)
     420                 : {
     421               0 :   nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
     422               0 :   ctx->Translate(-gfxPoint(aOffset.x, aOffset.y));
     423               0 :   gfxUtils::ClipToRegion(ctx, aRegion);
     424               0 :   ctx->SetColor(aColor);
     425               0 :   ctx->Paint();
     426               0 : }
     427                 : 
     428                 : BasicBufferOGL::PaintState
     429               0 : BasicBufferOGL::BeginPaint(ContentType aContentType,
     430                 :                            PRUint32 aFlags)
     431                 : {
     432               0 :   PaintState result;
     433                 :   // We need to disable rotation if we're going to be resampled when
     434                 :   // drawing, because we might sample across the rotation boundary.
     435               0 :   bool canHaveRotation =  !(aFlags & PAINT_WILL_RESAMPLE);
     436                 : 
     437               0 :   nsIntRegion validRegion = mLayer->GetValidRegion();
     438                 : 
     439                 :   Layer::SurfaceMode mode;
     440                 :   ContentType contentType;
     441               0 :   nsIntRegion neededRegion;
     442                 :   bool canReuseBuffer;
     443               0 :   nsIntRect destBufferRect;
     444                 : 
     445               0 :   while (true) {
     446               0 :     mode = mLayer->GetSurfaceMode();
     447               0 :     contentType = aContentType;
     448               0 :     neededRegion = mLayer->GetVisibleRegion();
     449                 :     // If we're going to resample, we need a buffer that's in clamp mode.
     450               0 :     canReuseBuffer = neededRegion.GetBounds().Size() <= mBufferRect.Size() &&
     451               0 :       mTexImage &&
     452               0 :       (!(aFlags & PAINT_WILL_RESAMPLE) ||
     453               0 :        mTexImage->GetWrapMode() == LOCAL_GL_CLAMP_TO_EDGE);
     454                 : 
     455               0 :     if (canReuseBuffer) {
     456               0 :       if (mBufferRect.Contains(neededRegion.GetBounds())) {
     457                 :         // We don't need to adjust mBufferRect.
     458               0 :         destBufferRect = mBufferRect;
     459                 :       } else {
     460                 :         // The buffer's big enough but doesn't contain everything that's
     461                 :         // going to be visible. We'll move it.
     462               0 :         destBufferRect = nsIntRect(neededRegion.GetBounds().TopLeft(), mBufferRect.Size());
     463                 :       }
     464                 :     } else {
     465               0 :       destBufferRect = neededRegion.GetBounds();
     466                 :     }
     467                 : 
     468               0 :     if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
     469                 : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
     470                 :       mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA;
     471                 : #else
     472               0 :       if (!mLayer->GetParent() || !mLayer->GetParent()->SupportsComponentAlphaChildren()) {
     473               0 :         mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA;
     474                 :       } else {
     475               0 :         contentType = gfxASurface::CONTENT_COLOR;
     476                 :       }
     477                 :  #endif
     478                 :     }
     479                 :  
     480               0 :     if ((aFlags & PAINT_WILL_RESAMPLE) &&
     481               0 :         (!neededRegion.GetBounds().IsEqualInterior(destBufferRect) ||
     482               0 :          neededRegion.GetNumRects() > 1)) {
     483                 :       // The area we add to neededRegion might not be painted opaquely
     484               0 :       if (mode == Layer::SURFACE_OPAQUE) {
     485               0 :         contentType = gfxASurface::CONTENT_COLOR_ALPHA;
     486               0 :         mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA;
     487                 :       }
     488                 :       // For component alpha layers, we leave contentType as CONTENT_COLOR.
     489                 : 
     490                 :       // We need to validate the entire buffer, to make sure that only valid
     491                 :       // pixels are sampled
     492               0 :       neededRegion = destBufferRect;
     493                 :     }
     494                 : 
     495               0 :     if (mTexImage &&
     496               0 :         (mTexImage->GetContentType() != contentType ||
     497               0 :          (mode == Layer::SURFACE_COMPONENT_ALPHA) != (mTexImageOnWhite != nsnull))) {
     498                 :       // We're effectively clearing the valid region, so we need to draw
     499                 :       // the entire needed region now.
     500               0 :       result.mRegionToInvalidate = mLayer->GetValidRegion();
     501               0 :       validRegion.SetEmpty();
     502               0 :       mTexImage = nsnull;
     503               0 :       mTexImageOnWhite = nsnull;
     504               0 :       mBufferRect.SetRect(0, 0, 0, 0);
     505               0 :       mBufferRotation.MoveTo(0, 0);
     506                 :       // Restart decision process with the cleared buffer. We can only go
     507                 :       // around the loop one more iteration, since mTexImage is null now.
     508               0 :       continue;
     509                 :     }
     510                 : 
     511                 :     break;
     512                 :   }
     513                 : 
     514               0 :   result.mRegionToDraw.Sub(neededRegion, validRegion);
     515               0 :   if (result.mRegionToDraw.IsEmpty())
     516                 :     return result;
     517                 : 
     518               0 :   if (destBufferRect.width > gl()->GetMaxTextureImageSize() ||
     519               0 :       destBufferRect.height > gl()->GetMaxTextureImageSize()) {
     520                 :     return result;
     521                 :   }
     522                 : 
     523               0 :   nsIntRect drawBounds = result.mRegionToDraw.GetBounds();
     524               0 :   nsRefPtr<TextureImage> destBuffer;
     525               0 :   nsRefPtr<TextureImage> destBufferOnWhite;
     526                 : 
     527               0 :   PRUint32 bufferFlags = canHaveRotation ? ALLOW_REPEAT : 0;
     528               0 :   if (canReuseBuffer) {
     529               0 :     nsIntRect keepArea;
     530               0 :     if (keepArea.IntersectRect(destBufferRect, mBufferRect)) {
     531                 :       // Set mBufferRotation so that the pixels currently in mBuffer
     532                 :       // will still be rendered in the right place when mBufferRect
     533                 :       // changes to destBufferRect.
     534                 :       nsIntPoint newRotation = mBufferRotation +
     535               0 :         (destBufferRect.TopLeft() - mBufferRect.TopLeft());
     536               0 :       WrapRotationAxis(&newRotation.x, mBufferRect.width);
     537               0 :       WrapRotationAxis(&newRotation.y, mBufferRect.height);
     538               0 :       NS_ASSERTION(nsIntRect(nsIntPoint(0,0), mBufferRect.Size()).Contains(newRotation),
     539                 :                    "newRotation out of bounds");
     540               0 :       PRInt32 xBoundary = destBufferRect.XMost() - newRotation.x;
     541               0 :       PRInt32 yBoundary = destBufferRect.YMost() - newRotation.y;
     542               0 :       if ((drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) ||
     543               0 :           (drawBounds.y < yBoundary && yBoundary < drawBounds.YMost()) ||
     544               0 :           (newRotation != nsIntPoint(0,0) && !canHaveRotation)) {
     545                 :         // The stuff we need to redraw will wrap around an edge of the
     546                 :         // buffer, so we will need to do a self-copy
     547                 :         // If mBufferRotation == nsIntPoint(0,0) we could do a real
     548                 :         // self-copy but we're not going to do that in GL yet.
     549                 :         // We can't do a real self-copy because the buffer is rotated.
     550                 :         // So allocate a new buffer for the destination.
     551               0 :         destBufferRect = neededRegion.GetBounds();
     552               0 :         destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferRect.Size(), contentType, bufferFlags);
     553               0 :         if (!destBuffer)
     554                 :           return result;
     555               0 :         if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
     556                 :           destBufferOnWhite =
     557               0 :             CreateClampOrRepeatTextureImage(gl(), destBufferRect.Size(), contentType, bufferFlags);
     558               0 :           if (!destBufferOnWhite)
     559                 :             return result;
     560                 :         }
     561                 :       } else {
     562               0 :         mBufferRect = destBufferRect;
     563               0 :         mBufferRotation = newRotation;
     564                 :       }
     565                 :     } else {
     566                 :       // No pixels are going to be kept. The whole visible region
     567                 :       // will be redrawn, so we don't need to copy anything, so we don't
     568                 :       // set destBuffer.
     569               0 :       mBufferRect = destBufferRect;
     570               0 :       mBufferRotation = nsIntPoint(0,0);
     571                 :     }
     572                 :   } else {
     573                 :     // The buffer's not big enough, so allocate a new one
     574               0 :     destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferRect.Size(), contentType, bufferFlags);
     575               0 :     if (!destBuffer)
     576                 :       return result;
     577                 : 
     578               0 :     if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
     579                 :       destBufferOnWhite = 
     580               0 :         CreateClampOrRepeatTextureImage(gl(), destBufferRect.Size(), contentType, bufferFlags);
     581               0 :       if (!destBufferOnWhite)
     582                 :         return result;
     583                 :     }
     584                 :   }
     585               0 :   NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || destBufferRect == neededRegion.GetBounds(),
     586                 :                "If we're resampling, we need to validate the entire buffer");
     587                 : 
     588               0 :   if (!destBuffer && !mTexImage) {
     589                 :     return result;
     590                 :   }
     591                 : 
     592               0 :   if (destBuffer) {
     593               0 :     if (mTexImage && (mode != Layer::SURFACE_COMPONENT_ALPHA || mTexImageOnWhite)) {
     594                 :       // BlitTextureImage depends on the FBO texture target being
     595                 :       // TEXTURE_2D.  This isn't the case on some older X1600-era Radeons.
     596               0 :       if (mOGLLayer->OGLManager()->FBOTextureTarget() == LOCAL_GL_TEXTURE_2D) {
     597               0 :         nsIntRect overlap;
     598               0 :         overlap.IntersectRect(mBufferRect, destBufferRect);
     599                 : 
     600               0 :         nsIntRect srcRect(overlap), dstRect(overlap);
     601               0 :         srcRect.MoveBy(- mBufferRect.TopLeft() + mBufferRotation);
     602               0 :         dstRect.MoveBy(- destBufferRect.TopLeft());
     603                 :         
     604               0 :         if (mBufferRotation != nsIntPoint(0, 0)) {
     605                 :           // If mBuffer is rotated, then BlitTextureImage will only be copying the bottom-right section
     606                 :           // of the buffer. We need to invalidate the remaining sections so that they get redrawn too.
     607                 :           // Alternatively we could teach BlitTextureImage to rearrange the rotated segments onto
     608                 :           // the new buffer.
     609                 :           
     610                 :           // When the rotated buffer is reorganised, the bottom-right section will be drawn in the top left.
     611                 :           // Find the point where this content ends.
     612                 :           nsIntPoint rotationPoint(mBufferRect.x + mBufferRect.width - mBufferRotation.x, 
     613               0 :                                    mBufferRect.y + mBufferRect.height - mBufferRotation.y);
     614                 : 
     615                 :           // The buffer looks like:
     616                 :           //  ______
     617                 :           // |1  |2 |  Where the center point is offset by mBufferRotation from the top-left corner.
     618                 :           // |___|__|
     619                 :           // |3  |4 |
     620                 :           // |___|__|
     621                 :           //
     622                 :           // This is drawn to the screen as:
     623                 :           //  ______
     624                 :           // |4  |3 |  Where the center point is { width - mBufferRotation.x, height - mBufferRotation.y } from
     625                 :           // |___|__|  from the top left corner - rotationPoint. Since only quadrant 4 will actually be copied, 
     626                 :           // |2  |1 |  we need to invalidate the others.
     627                 :           // |___|__|
     628                 :           //
     629                 :           // Quadrants 2 and 1
     630               0 :           nsIntRect bottom(mBufferRect.x, rotationPoint.y, mBufferRect.width, mBufferRotation.y);
     631                 :           // Quadrant 3
     632               0 :           nsIntRect topright(rotationPoint.x, mBufferRect.y, mBufferRotation.x, rotationPoint.y - mBufferRect.y);
     633                 : 
     634               0 :           if (!bottom.IsEmpty()) {
     635               0 :             nsIntRegion temp;
     636               0 :             temp.And(destBufferRect, bottom);
     637               0 :             result.mRegionToDraw.Or(result.mRegionToDraw, temp);
     638                 :           }
     639               0 :           if (!topright.IsEmpty()) {
     640               0 :             nsIntRegion temp;
     641               0 :             temp.And(destBufferRect, topright);
     642               0 :             result.mRegionToDraw.Or(result.mRegionToDraw, temp);
     643                 :           }
     644                 :         }
     645                 : 
     646               0 :         destBuffer->Resize(destBufferRect.Size());
     647                 : 
     648                 :         gl()->BlitTextureImage(mTexImage, srcRect,
     649               0 :                                destBuffer, dstRect);
     650               0 :         destBuffer->MarkValid();
     651               0 :         if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
     652               0 :           destBufferOnWhite->Resize(destBufferRect.Size());
     653                 :           gl()->BlitTextureImage(mTexImageOnWhite, srcRect,
     654               0 :                                  destBufferOnWhite, dstRect);
     655               0 :           destBufferOnWhite->MarkValid();
     656                 :         }
     657                 :       } else {
     658                 :         // can't blit, just draw everything
     659               0 :         destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferRect.Size(), contentType, bufferFlags);
     660               0 :         if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
     661                 :           destBufferOnWhite = 
     662               0 :             CreateClampOrRepeatTextureImage(gl(), destBufferRect.Size(), contentType, bufferFlags);
     663                 :         }
     664                 :       }
     665                 :     }
     666                 : 
     667               0 :     mTexImage = destBuffer.forget();
     668               0 :     if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
     669               0 :       mTexImageOnWhite = destBufferOnWhite.forget();
     670                 :     }
     671               0 :     mBufferRect = destBufferRect;
     672               0 :     mBufferRotation = nsIntPoint(0,0);
     673                 :   }
     674               0 :   NS_ASSERTION(canHaveRotation || mBufferRotation == nsIntPoint(0,0),
     675                 :                "Rotation disabled, but we have nonzero rotation?");
     676                 : 
     677               0 :   nsIntRegion invalidate;
     678               0 :   invalidate.Sub(mLayer->GetValidRegion(), destBufferRect);
     679               0 :   result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
     680                 : 
     681                 :   // Figure out which quadrant to draw in
     682               0 :   PRInt32 xBoundary = mBufferRect.XMost() - mBufferRotation.x;
     683               0 :   PRInt32 yBoundary = mBufferRect.YMost() - mBufferRotation.y;
     684               0 :   XSide sideX = drawBounds.XMost() <= xBoundary ? RIGHT : LEFT;
     685               0 :   YSide sideY = drawBounds.YMost() <= yBoundary ? BOTTOM : TOP;
     686               0 :   nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
     687               0 :   NS_ASSERTION(quadrantRect.Contains(drawBounds), "Messed up quadrants");
     688                 : 
     689               0 :   nsIntPoint offset = -nsIntPoint(quadrantRect.x, quadrantRect.y);
     690                 : 
     691                 :   // Make the region to draw relative to the buffer, before
     692                 :   // passing to BeginUpdate.
     693               0 :   result.mRegionToDraw.MoveBy(offset);
     694                 :   // BeginUpdate is allowed to modify the given region,
     695                 :   // if it wants more to be repainted than we request.
     696               0 :   if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
     697               0 :     nsIntRegion drawRegionCopy = result.mRegionToDraw;
     698               0 :     gfxASurface *onBlack = mTexImage->BeginUpdate(drawRegionCopy);
     699               0 :     gfxASurface *onWhite = mTexImageOnWhite->BeginUpdate(result.mRegionToDraw);
     700               0 :     NS_ASSERTION(result.mRegionToDraw == drawRegionCopy,
     701                 :                  "BeginUpdate should always modify the draw region in the same way!");
     702               0 :     FillSurface(onBlack, result.mRegionToDraw, nsIntPoint(0,0), gfxRGBA(0.0, 0.0, 0.0, 1.0));
     703               0 :     FillSurface(onWhite, result.mRegionToDraw, nsIntPoint(0,0), gfxRGBA(1.0, 1.0, 1.0, 1.0));
     704               0 :     gfxASurface* surfaces[2] = { onBlack, onWhite };
     705               0 :     nsRefPtr<gfxTeeSurface> surf = new gfxTeeSurface(surfaces, ArrayLength(surfaces));
     706                 : 
     707                 :     // XXX If the device offset is set on the individual surfaces instead of on
     708                 :     // the tee surface, we render in the wrong place. Why?
     709               0 :     gfxPoint deviceOffset = onBlack->GetDeviceOffset();
     710               0 :     onBlack->SetDeviceOffset(gfxPoint(0, 0));
     711               0 :     onWhite->SetDeviceOffset(gfxPoint(0, 0));
     712               0 :     surf->SetDeviceOffset(deviceOffset);
     713                 : 
     714                 :     // Using this surface as a source will likely go horribly wrong, since
     715                 :     // only the onBlack surface will really be used, so alpha information will
     716                 :     // be incorrect.
     717               0 :     surf->SetAllowUseAsSource(false);
     718               0 :     result.mContext = new gfxContext(surf);
     719                 :   } else {
     720               0 :     result.mContext = new gfxContext(mTexImage->BeginUpdate(result.mRegionToDraw));
     721               0 :     if (mTexImage->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
     722               0 :       gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw);
     723               0 :       result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR);
     724               0 :       result.mContext->Paint();
     725               0 :       result.mContext->SetOperator(gfxContext::OPERATOR_OVER);
     726                 :     }
     727                 :   }
     728               0 :   if (!result.mContext) {
     729               0 :     NS_WARNING("unable to get context for update");
     730                 :     return result;
     731                 :   }
     732               0 :   result.mContext->Translate(-gfxPoint(quadrantRect.x, quadrantRect.y));
     733                 :   // Move rgnToPaint back into position so that the thebes callback
     734                 :   // gets the right coordintes.
     735               0 :   result.mRegionToDraw.MoveBy(-offset);
     736                 : 
     737                 :   // If we do partial updates, we have to clip drawing to the regionToDraw.
     738                 :   // If we don't clip, background images will be fillrect'd to the region correctly,
     739                 :   // while text or lines will paint outside of the regionToDraw. This becomes apparent
     740                 :   // with concave regions. Right now the scrollbars invalidate a narrow strip of the awesomebar
     741                 :   // although they never cover it. This leads to two draw rects, the narow strip and the actually
     742                 :   // newly exposed area. It would be wise to fix this glitch in any way to have simpler
     743                 :   // clip and draw regions.
     744               0 :   gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw);
     745                 : 
     746                 :   return result;
     747                 : }
     748                 : 
     749               0 : ThebesLayerOGL::ThebesLayerOGL(LayerManagerOGL *aManager)
     750                 :   : ThebesLayer(aManager, nsnull)
     751                 :   , LayerOGL(aManager)
     752               0 :   , mBuffer(nsnull)
     753                 : {
     754               0 :   mImplData = static_cast<LayerOGL*>(this);
     755               0 : }
     756                 : 
     757               0 : ThebesLayerOGL::~ThebesLayerOGL()
     758                 : {
     759               0 :   Destroy();
     760               0 : }
     761                 : 
     762                 : void
     763               0 : ThebesLayerOGL::Destroy()
     764                 : {
     765               0 :   if (!mDestroyed) {
     766               0 :     mBuffer = nsnull;
     767               0 :     mDestroyed = true;
     768                 :   }
     769               0 : }
     770                 : 
     771                 : bool
     772               0 : ThebesLayerOGL::CreateSurface()
     773                 : {
     774               0 :   NS_ASSERTION(!mBuffer, "buffer already created?");
     775                 : 
     776               0 :   if (mVisibleRegion.IsEmpty()) {
     777               0 :     return false;
     778                 :   }
     779                 : 
     780               0 :   if (gl()->TextureImageSupportsGetBackingSurface()) {
     781                 :     // use the ThebesLayerBuffer fast-path
     782               0 :     mBuffer = new SurfaceBufferOGL(this);
     783                 :   } else {
     784               0 :     mBuffer = new BasicBufferOGL(this);
     785                 :   }
     786               0 :   return true;
     787                 : }
     788                 : 
     789                 : void
     790               0 : ThebesLayerOGL::SetVisibleRegion(const nsIntRegion &aRegion)
     791                 : {
     792               0 :   if (aRegion.IsEqual(mVisibleRegion))
     793               0 :     return;
     794               0 :   ThebesLayer::SetVisibleRegion(aRegion);
     795                 : }
     796                 : 
     797                 : void
     798               0 : ThebesLayerOGL::InvalidateRegion(const nsIntRegion &aRegion)
     799                 : {
     800               0 :   mValidRegion.Sub(mValidRegion, aRegion);
     801               0 : }
     802                 : 
     803                 : void
     804               0 : ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
     805                 :                             const nsIntPoint& aOffset)
     806                 : {
     807               0 :   if (!mBuffer && !CreateSurface()) {
     808               0 :     return;
     809                 :   }
     810               0 :   NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");
     811                 : 
     812               0 :   mOGLManager->MakeCurrent();
     813               0 :   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
     814                 : 
     815                 :   TextureImage::ContentType contentType =
     816               0 :     CanUseOpaqueSurface() ? gfxASurface::CONTENT_COLOR :
     817               0 :                             gfxASurface::CONTENT_COLOR_ALPHA;
     818                 : 
     819               0 :   PRUint32 flags = 0;
     820                 : #ifndef MOZ_GFX_OPTIMIZE_MOBILE
     821               0 :   gfxMatrix transform2d;
     822               0 :   if (GetEffectiveTransform().Is2D(&transform2d)) {
     823               0 :     if (transform2d.HasNonIntegerTranslation()) {
     824               0 :       flags |= ThebesLayerBufferOGL::PAINT_WILL_RESAMPLE;
     825                 :     }
     826                 :   } else {
     827               0 :     flags |= ThebesLayerBufferOGL::PAINT_WILL_RESAMPLE;
     828                 :   }
     829                 : #endif
     830                 : 
     831               0 :   Buffer::PaintState state = mBuffer->BeginPaint(contentType, flags);
     832               0 :   mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
     833                 : 
     834               0 :   if (state.mContext) {
     835               0 :     state.mRegionToInvalidate.And(state.mRegionToInvalidate, mVisibleRegion);
     836                 : 
     837                 :     LayerManager::DrawThebesLayerCallback callback =
     838               0 :       mOGLManager->GetThebesLayerCallback();
     839               0 :     if (!callback) {
     840               0 :       NS_ERROR("GL should never need to update ThebesLayers in an empty transaction");
     841                 :     } else {
     842               0 :       void* callbackData = mOGLManager->GetThebesLayerCallbackData();
     843               0 :       SetAntialiasingFlags(this, state.mContext);
     844                 :       callback(this, state.mContext, state.mRegionToDraw,
     845               0 :                state.mRegionToInvalidate, callbackData);
     846                 :       // Everything that's visible has been validated. Do this instead of just
     847                 :       // OR-ing with aRegionToDraw, since that can lead to a very complex region
     848                 :       // here (OR doesn't automatically simplify to the simplest possible
     849                 :       // representation of a region.)
     850               0 :       nsIntRegion tmp;
     851               0 :       tmp.Or(mVisibleRegion, state.mRegionToDraw);
     852               0 :       mValidRegion.Or(mValidRegion, tmp);
     853                 :     }
     854                 :   }
     855                 : 
     856                 :   // Drawing thebes layers can change the current context, reset it.
     857               0 :   gl()->MakeCurrent();
     858                 : 
     859               0 :   gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
     860               0 :   mBuffer->RenderTo(aOffset, mOGLManager, flags);
     861                 : }
     862                 : 
     863                 : Layer*
     864               0 : ThebesLayerOGL::GetLayer()
     865                 : {
     866               0 :   return this;
     867                 : }
     868                 : 
     869                 : bool
     870               0 : ThebesLayerOGL::IsEmpty()
     871                 : {
     872               0 :   return !mBuffer;
     873                 : }
     874                 : 
     875                 : void
     876               0 : ThebesLayerOGL::CleanupResources()
     877                 : {
     878               0 :   mBuffer = nsnull;
     879               0 : }
     880                 : 
     881                 : class ShadowBufferOGL : public ThebesLayerBufferOGL
     882               0 : {
     883                 : public:
     884               0 :   ShadowBufferOGL(ShadowThebesLayerOGL* aLayer)
     885               0 :     : ThebesLayerBufferOGL(aLayer, aLayer)
     886               0 :   {}
     887                 : 
     888               0 :   virtual PaintState BeginPaint(ContentType aContentType, PRUint32) {
     889               0 :     NS_RUNTIMEABORT("can't BeginPaint for a shadow layer");
     890               0 :     return PaintState();
     891                 :   }
     892                 : 
     893                 :   void Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated,
     894                 :               const nsIntRect& aRect, const nsIntPoint& aRotation);
     895                 : 
     896                 : protected:
     897               0 :   virtual nsIntPoint GetOriginOffset() {
     898               0 :     return mBufferRect.TopLeft() - mBufferRotation;
     899                 :   }
     900                 : 
     901                 : private:
     902                 :   nsIntRect mBufferRect;
     903                 :   nsIntPoint mBufferRotation;
     904                 : };
     905                 : 
     906                 : void
     907               0 : ShadowBufferOGL::Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated,
     908                 :                         const nsIntRect& aRect, const nsIntPoint& aRotation)
     909                 : {
     910               0 :   gfxIntSize size = aUpdate->GetSize();
     911               0 :   if (!mTexImage ||
     912               0 :       GetSize() != nsIntSize(size.width, size.height) ||
     913               0 :       mTexImage->GetContentType() != aUpdate->GetContentType()) {
     914                 :     // XXX we should do something here to decide whether to use REPEAT or not,
     915                 :     // but I'm not sure what
     916                 :     mTexImage = CreateClampOrRepeatTextureImage(gl(),
     917               0 :       nsIntSize(size.width, size.height), aUpdate->GetContentType(), ALLOW_REPEAT);
     918                 :   }
     919                 : 
     920               0 :   nsIntRegion destRegion(aUpdated);
     921                 :   // aUpdated is in screen coordinates.  Move it so that the layer's
     922                 :   // top-left is 0,0
     923               0 :   nsIntPoint visTopLeft = mLayer->GetVisibleRegion().GetBounds().TopLeft();
     924               0 :   destRegion.MoveBy(-visTopLeft);
     925                 : 
     926                 :   // Correct for rotation
     927               0 :   destRegion.MoveBy(aRotation);
     928               0 :   nsIntRect destBounds = destRegion.GetBounds();
     929                 :   destRegion.MoveBy((destBounds.x >= size.width) ? -size.width : 0,
     930               0 :                     (destBounds.y >= size.height) ? -size.height : 0);
     931                 : 
     932                 :   // There's code to make sure that updated regions don't cross rotation
     933                 :   // boundaries, so assert here that this is the case
     934               0 :   NS_ASSERTION(((destBounds.x % size.width) + destBounds.width <= size.width) &&
     935                 :                ((destBounds.y % size.height) + destBounds.height <= size.height),
     936                 :                "Updated region lies across rotation boundaries!");
     937                 : 
     938                 :   // NB: this gfxContext must not escape EndUpdate() below
     939               0 :   mTexImage->DirectUpdate(aUpdate, destRegion);
     940                 : 
     941               0 :   mBufferRect = aRect;
     942               0 :   mBufferRotation = aRotation;
     943               0 : }
     944                 : 
     945               0 : ShadowThebesLayerOGL::ShadowThebesLayerOGL(LayerManagerOGL *aManager)
     946                 :   : ShadowThebesLayer(aManager, nsnull)
     947               0 :   , LayerOGL(aManager)
     948                 : {
     949               0 :   mImplData = static_cast<LayerOGL*>(this);
     950               0 : }
     951                 : 
     952               0 : ShadowThebesLayerOGL::~ShadowThebesLayerOGL()
     953               0 : {}
     954                 : 
     955                 : void
     956               0 : ShadowThebesLayerOGL::Swap(const ThebesBuffer& aNewFront,
     957                 :                            const nsIntRegion& aUpdatedRegion,
     958                 :                            OptionalThebesBuffer* aNewBack,
     959                 :                            nsIntRegion* aNewBackValidRegion,
     960                 :                            OptionalThebesBuffer* aReadOnlyFront,
     961                 :                            nsIntRegion* aFrontUpdatedRegion)
     962                 : {
     963               0 :   if (!mDestroyed) {
     964               0 :     if (!mBuffer) {
     965               0 :       mBuffer = new ShadowBufferOGL(this);
     966                 :     }
     967               0 :     nsRefPtr<gfxASurface> surf = ShadowLayerForwarder::OpenDescriptor(aNewFront.buffer());
     968               0 :     mBuffer->Upload(surf, aUpdatedRegion, aNewFront.rect(), aNewFront.rotation());
     969                 :   }
     970                 : 
     971               0 :   *aNewBack = aNewFront;
     972               0 :   *aNewBackValidRegion = mValidRegion;
     973               0 :   *aReadOnlyFront = null_t();
     974               0 :   aFrontUpdatedRegion->SetEmpty();
     975               0 : }
     976                 : 
     977                 : void
     978               0 : ShadowThebesLayerOGL::DestroyFrontBuffer()
     979                 : {
     980               0 :   mBuffer = nsnull;
     981               0 : }
     982                 : 
     983                 : void
     984               0 : ShadowThebesLayerOGL::Disconnect()
     985                 : {
     986               0 :   Destroy();
     987               0 : }
     988                 : 
     989                 : void
     990               0 : ShadowThebesLayerOGL::Destroy()
     991                 : {
     992               0 :   if (!mDestroyed) {
     993               0 :     mDestroyed = true;
     994               0 :     mBuffer = nsnull;
     995                 :   }
     996               0 : }
     997                 : 
     998                 : Layer*
     999               0 : ShadowThebesLayerOGL::GetLayer()
    1000                 : {
    1001               0 :   return this;
    1002                 : }
    1003                 : 
    1004                 : bool
    1005               0 : ShadowThebesLayerOGL::IsEmpty()
    1006                 : {
    1007               0 :   return !mBuffer;
    1008                 : }
    1009                 : 
    1010                 : void
    1011               0 : ShadowThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
    1012                 :                                   const nsIntPoint& aOffset)
    1013                 : {
    1014               0 :   if (!mBuffer) {
    1015               0 :     return;
    1016                 :   }
    1017               0 :   NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");
    1018                 : 
    1019               0 :   mOGLManager->MakeCurrent();
    1020               0 :   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
    1021                 : 
    1022               0 :   gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
    1023               0 :   mBuffer->RenderTo(aOffset, mOGLManager, 0);
    1024                 : }
    1025                 : 
    1026                 : void
    1027               0 : ShadowThebesLayerOGL::CleanupResources()
    1028                 : {
    1029               0 :   DestroyFrontBuffer();
    1030               0 : }
    1031                 : 
    1032                 : } /* layers */
    1033                 : } /* mozilla */

Generated by: LCOV version 1.7