This commit is contained in:
Andreas Gal 2012-03-17 15:20:01 -07:00
Родитель 5a21426f72
Коммит f8ebf3db54
7 изменённых файлов: 162 добавлений и 22 удалений

Просмотреть файл

@ -698,6 +698,39 @@ public:
Mutated();
}
/**
* CONSTRUCTION PHASE ONLY
*
* Define a subrect of this layer that will be used as the source
* image for tiling this layer's visible region. The coordinates
* are in the un-transformed space of this layer (i.e. the visible
* region of this this layer is tiled before being transformed).
* The visible region is tiled "outwards" from the source rect; that
* is, the source rect is drawn "in place", then repeated to cover
* the layer's visible region.
*
* The interpretation of the source rect varies depending on
* underlying layer type. For ImageLayers and CanvasLayers, it
* doesn't make sense to set a source rect not fully contained by
* the bounds of their underlying images. For ThebesLayers, thebes
* content may need to be rendered to fill the source rect. For
* ColorLayers, a source rect for tiling doesn't make sense at all.
*
* If aRect is null no tiling will be performed.
*
* NB: this interface is only implemented for BasicImageLayers, and
* then only for source rects the same size as the layers'
* underlying images.
*/
void SetTileSourceRect(const nsIntRect* aRect)
{
mUseTileSourceRect = aRect != nsnull;
if (aRect) {
mTileSourceRect = *aRect;
}
Mutated();
}
void SetIsFixedPosition(bool aFixedPosition) { mIsFixedPosition = aFixedPosition; }
// These getters can be used anytime.
@ -711,6 +744,7 @@ public:
virtual Layer* GetFirstChild() { return nsnull; }
virtual Layer* GetLastChild() { return nsnull; }
const gfx3DMatrix& GetTransform() { return mTransform; }
const nsIntRect* GetTileSourceRect() { return mUseTileSourceRect ? &mTileSourceRect : nsnull; }
bool GetIsFixedPosition() { return mIsFixedPosition; }
/**

Просмотреть файл

@ -880,6 +880,7 @@ public:
static void PaintContext(gfxPattern* aPattern,
const nsIntRegion& aVisible,
const nsIntRect* aTileSourceRect,
float aOpacity,
gfxContext* aContext);
@ -939,11 +940,14 @@ BasicImageLayer::GetAndPaintCurrentImage(gfxContext* aContext,
size = mScaleToSize;
}
// The visible region can extend outside the image, so just draw
// within the image bounds.
// The visible region can extend outside the image. If we're not
// tiling, we don't want to draw into that area, so just draw within
// the image bounds.
const nsIntRect* tileSrcRect = GetTileSourceRect();
AutoSetOperator setOperator(aContext, GetOperator());
PaintContext(pat,
nsIntRegion(nsIntRect(0, 0, size.width, size.height)),
tileSrcRect ? GetVisibleRegion() : nsIntRegion(nsIntRect(0, 0, size.width, size.height)),
tileSrcRect,
aOpacity, aContext);
GetContainer()->NotifyPaintedImage(image);
@ -954,6 +958,7 @@ BasicImageLayer::GetAndPaintCurrentImage(gfxContext* aContext,
/*static*/ void
BasicImageLayer::PaintContext(gfxPattern* aPattern,
const nsIntRegion& aVisible,
const nsIntRect* aTileSourceRect,
float aOpacity,
gfxContext* aContext)
{
@ -973,13 +978,31 @@ BasicImageLayer::PaintContext(gfxPattern* aPattern,
}
}
aContext->NewPath();
// No need to snap here; our transform has already taken care of it.
// XXX true for arbitrary regions? Don't care yet though
gfxUtils::PathFromRegion(aContext, aVisible);
aPattern->SetExtend(extend);
aContext->SetPattern(aPattern);
aContext->FillWithOpacity(aOpacity);
if (!aTileSourceRect) {
aContext->NewPath();
// No need to snap here; our transform has already taken care of it.
// XXX true for arbitrary regions? Don't care yet though
gfxUtils::PathFromRegion(aContext, aVisible);
aPattern->SetExtend(extend);
aContext->SetPattern(aPattern);
aContext->FillWithOpacity(aOpacity);
} else {
nsRefPtr<gfxASurface> source = aPattern->GetSurface();
NS_ABORT_IF_FALSE(source, "Expecting a surface pattern");
gfxIntSize sourceSize = source->GetSize();
nsIntRect sourceRect(0, 0, sourceSize.width, sourceSize.height);
NS_ABORT_IF_FALSE(sourceRect == *aTileSourceRect,
"Cowardly refusing to create a temporary surface for tiling");
gfxContextAutoSaveRestore saveRestore(aContext);
aContext->NewPath();
gfxUtils::PathFromRegion(aContext, aVisible);
aPattern->SetExtend(gfxPattern::EXTEND_REPEAT);
aContext->SetPattern(aPattern);
aContext->FillWithOpacity(aOpacity);
}
// Reset extend mode for callers that need to reuse the pattern
aPattern->SetExtend(extend);
@ -2606,7 +2629,7 @@ BasicShadowableImageLayer::Paint(gfxContext* aContext)
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
PaintContext(pat,
nsIntRegion(nsIntRect(0, 0, mSize.width, mSize.height)),
1.0, tmpCtx);
nsnull, 1.0, tmpCtx);
BasicManager()->PaintedImage(BasicManager()->Hold(this),
mBackBuffer);
@ -3052,11 +3075,14 @@ BasicShadowImageLayer::Paint(gfxContext* aContext)
nsRefPtr<gfxPattern> pat = new gfxPattern(surface);
pat->SetFilter(mFilter);
// The visible region can extend outside the image, so just draw
// within the image bounds.
// The visible region can extend outside the image. If we're not
// tiling, we don't want to draw into that area, so just draw within
// the image bounds.
const nsIntRect* tileSrcRect = GetTileSourceRect();
AutoSetOperator setOperator(aContext, GetOperator());
BasicImageLayer::PaintContext(pat,
nsIntRegion(nsIntRect(0, 0, mSize.width, mSize.height)),
tileSrcRect ? GetEffectiveVisibleRegion() : nsIntRegion(nsIntRect(0, 0, mSize.width, mSize.height)),
tileSrcRect,
GetEffectiveOpacity(), aContext);
}

Просмотреть файл

@ -117,6 +117,8 @@ struct CommonLayerAttributes {
float opacity;
bool useClipRect;
nsIntRect clipRect;
bool useTileSourceRect;
nsIntRect tileSourceRect;
bool isFixedPosition;
};

Просмотреть файл

@ -298,6 +298,9 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies)
common.clipRect() = (common.useClipRect() ?
*mutant->GetClipRect() : nsIntRect());
common.isFixedPosition() = mutant->GetIsFixedPosition();
common.useTileSourceRect() = !!mutant->GetTileSourceRect();
common.tileSourceRect() = (common.useTileSourceRect() ?
*mutant->GetTileSourceRect() : nsIntRect());
attrs.specific() = null_t();
mutant->FillSpecificAttributes(attrs.specific());

Просмотреть файл

@ -225,6 +225,7 @@ ShadowLayersParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
layer->SetOpacity(common.opacity());
layer->SetClipRect(common.useClipRect() ? &common.clipRect() : NULL);
layer->SetTransform(common.transform());
layer->SetTileSourceRect(common.useTileSourceRect() ? &common.tileSourceRect() : NULL);
static bool fixedPositionLayersEnabled = getenv("MOZ_ENABLE_FIXED_POSITION_LAYERS") != 0;
if (fixedPositionLayersEnabled) {
layer->SetIsFixedPosition(common.isFixedPosition());

Просмотреть файл

@ -305,6 +305,7 @@ ImageLayerOGL::RenderLayer(int,
return;
}
data->SetTiling(mUseTileSourceRect);
gl()->MakeCurrent();
unsigned int iwidth = cairoImage->mSize.width;
unsigned int iheight = cairoImage->mSize.height;
@ -341,16 +342,68 @@ ImageLayerOGL::RenderLayer(int,
nsIntRect rect = GetVisibleRegion().GetBounds();
bool tileIsWholeImage = (mTileSourceRect == nsIntRect(0, 0, iwidth, iheight))
|| !mUseTileSourceRect;
bool imageIsPowerOfTwo = IsPowerOfTwo(iwidth) &&
IsPowerOfTwo(iheight);
bool canDoNPOT = (
gl()->IsExtensionSupported(GLContext::ARB_texture_non_power_of_two) ||
gl()->IsExtensionSupported(GLContext::OES_texture_npot));
GLContext::RectTriangles triangleBuffer;
// do GL_REPEAT if we can - should be the fastest option.
// draw a single rect for the whole region, a little overdraw
// on the gpu should be faster than tesselating
// maybe we can write a shader that can also handle texture subrects
// and repeat?
if (tileIsWholeImage && (imageIsPowerOfTwo || canDoNPOT)) {
// we need to anchor the repeating texture appropriately
// otherwise it will start from the region border instead
// of the layer origin. This is the offset into the texture
// that the region border represents
float tex_offset_u = (float)(rect.x % iwidth) / iwidth;
float tex_offset_v = (float)(rect.y % iheight) / iheight;
triangleBuffer.addRect(rect.x, rect.y,
rect.x + rect.width, rect.y + rect.height,
tex_offset_u, tex_offset_v,
tex_offset_u + (float)rect.width / (float)iwidth,
tex_offset_v + (float)rect.height / (float)iheight);
}
// can't do fast path via GL_REPEAT - we have to tessellate individual rects.
else {
unsigned int twidth = mTileSourceRect.width;
unsigned int theight = mTileSourceRect.height;
float tex_offset_u = float(rect.x % iwidth) / iwidth;
float tex_offset_v = float(rect.y % iheight) / iheight;
triangleBuffer.addRect(rect.x, rect.y,
rect.x + rect.width, rect.y + rect.height,
tex_offset_u, tex_offset_v,
tex_offset_u + float(rect.width) / float(iwidth),
tex_offset_v + float(rect.height) / float(iheight);
nsIntRegion region = GetVisibleRegion();
// image subrect in texture coordinates
float subrect_tl_u = float(mTileSourceRect.x) / float(iwidth);
float subrect_tl_v = float(mTileSourceRect.y) / float(iheight);
float subrect_br_u = float(mTileSourceRect.width + mTileSourceRect.x) / float(iwidth);
float subrect_br_v = float(mTileSourceRect.height + mTileSourceRect.y) / float(iheight);
// round rect position down to multiples of texture size
// this way we start at multiples of rect positions
rect.x = (rect.x / iwidth) * iwidth;
rect.y = (rect.y / iheight) * iheight;
// round up size to accomodate for rounding down above
rect.width = (rect.width / iwidth + 2) * iwidth;
rect.height = (rect.height / iheight + 2) * iheight;
// tesselate the visible region with tiles of subrect size
for (int y = rect.y; y < rect.y + rect.height; y += theight) {
for (int x = rect.x; x < rect.x + rect.width; x += twidth) {
// when we already tessellate, we might as well save on overdraw here
if (!region.Intersects(nsIntRect(x, y, twidth, theight))) {
continue;
}
triangleBuffer.addRect(x, y,
x + twidth, y + theight,
subrect_tl_u, subrect_tl_v,
subrect_br_u, subrect_br_v);
}
}
}
GLuint vertAttribIndex =
program->AttribLocation(LayerProgram::VertexAttrib);
GLuint texCoordAttribIndex =
@ -575,6 +628,25 @@ ImageLayerOGL::AllocateTexturesCairo(CairoImage *aImage)
aImage->SetBackendData(LayerManager::LAYERS_OPENGL, backendData.forget());
}
void CairoOGLBackendData::SetTiling(bool aTiling)
{
if (aTiling == mTiling)
return;
mozilla::gl::GLContext *gl = mTexture.GetGLContext();
gl->MakeCurrent();
gl->fActiveTexture(LOCAL_GL_TEXTURE0);
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture.GetTextureID());
mTiling = aTiling;
if (aTiling) {
gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_REPEAT);
gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_REPEAT);
} else {
gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
}
}
ShadowImageLayerOGL::ShadowImageLayerOGL(LayerManagerOGL* aManager)
: ShadowImageLayer(aManager, nsnull)
, LayerOGL(aManager)

Просмотреть файл

@ -172,9 +172,11 @@ struct THEBES_API PlanarYCbCrOGLBackendData : public ImageBackendData
struct CairoOGLBackendData : public ImageBackendData
{
CairoOGLBackendData() : mLayerProgram(gl::RGBALayerProgramType) {}
CairoOGLBackendData() : mLayerProgram(gl::RGBALayerProgramType), mTiling(false) {}
void SetTiling(bool aTiling);
GLTexture mTexture;
gl::ShaderProgramType mLayerProgram;
bool mTiling;
};
class ShadowImageLayerOGL : public ShadowImageLayer,