mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Support 3D transforms in the basic compositor (bug 935265, r=mattwoodrow).
This commit is contained in:
parent
fda70b1aad
commit
159a927b97
@ -0,0 +1,35 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_2D_HELPERS_H_
|
||||
#define MOZILLA_GFX_2D_HELPERS_H_
|
||||
|
||||
#include "2D.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
class AutoSaveTransform
|
||||
{
|
||||
public:
|
||||
AutoSaveTransform(DrawTarget *aTarget)
|
||||
: mDrawTarget(aTarget),
|
||||
mOldTransform(aTarget->GetTransform())
|
||||
{
|
||||
}
|
||||
~AutoSaveTransform()
|
||||
{
|
||||
mDrawTarget->SetTransform(mOldTransform);
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<DrawTarget> mDrawTarget;
|
||||
Matrix mOldTransform;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_GFX_2D_HELPERS_H_
|
@ -21,6 +21,7 @@ EXPORTS.mozilla.gfx += [
|
||||
'Blur.h',
|
||||
'BorrowedContext.h',
|
||||
'DataSurfaceHelpers.h',
|
||||
'Helpers.h',
|
||||
'Matrix.h',
|
||||
'PathHelpers.h',
|
||||
'Point.h',
|
||||
|
@ -10,9 +10,12 @@
|
||||
#include "nsIWidget.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/Helpers.h"
|
||||
#include "gfxUtils.h"
|
||||
#include <algorithm>
|
||||
#include "ImageContainer.h"
|
||||
#define PIXMAN_DONT_DEFINE_STDINT
|
||||
#include "pixman.h" // for pixman_f_transform, etc
|
||||
|
||||
namespace mozilla {
|
||||
using namespace mozilla::gfx;
|
||||
@ -330,6 +333,84 @@ DrawSurfaceWithTextureCoords(DrawTarget *aDest,
|
||||
}
|
||||
}
|
||||
|
||||
static pixman_transform
|
||||
Matrix3DToPixman(const gfx3DMatrix& aMatrix)
|
||||
{
|
||||
pixman_f_transform transform;
|
||||
|
||||
transform.m[0][0] = aMatrix._11;
|
||||
transform.m[0][1] = aMatrix._21;
|
||||
transform.m[0][2] = aMatrix._41;
|
||||
transform.m[1][0] = aMatrix._12;
|
||||
transform.m[1][1] = aMatrix._22;
|
||||
transform.m[1][2] = aMatrix._42;
|
||||
transform.m[2][0] = aMatrix._14;
|
||||
transform.m[2][1] = aMatrix._24;
|
||||
transform.m[2][2] = aMatrix._44;
|
||||
|
||||
pixman_transform result;
|
||||
pixman_transform_from_pixman_f_transform(&result, &transform);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
PixmanTransform(DataSourceSurface* aDest,
|
||||
DataSourceSurface* aSource,
|
||||
const gfx3DMatrix& aTransform,
|
||||
gfxPoint aDestOffset)
|
||||
{
|
||||
IntSize destSize = aDest->GetSize();
|
||||
pixman_image_t* dest = pixman_image_create_bits(PIXMAN_a8r8g8b8,
|
||||
destSize.width,
|
||||
destSize.height,
|
||||
(uint32_t*)aDest->GetData(),
|
||||
aDest->Stride());
|
||||
|
||||
IntSize srcSize = aSource->GetSize();
|
||||
pixman_image_t* src = pixman_image_create_bits(PIXMAN_a8r8g8b8,
|
||||
srcSize.width,
|
||||
srcSize.height,
|
||||
(uint32_t*)aSource->GetData(),
|
||||
aSource->Stride());
|
||||
|
||||
NS_ABORT_IF_FALSE(src && dest, "Failed to create pixman images?");
|
||||
|
||||
pixman_transform pixTransform = Matrix3DToPixman(aTransform);
|
||||
pixman_transform pixTransformInverted;
|
||||
|
||||
// If the transform is singular then nothing would be drawn anyway, return here
|
||||
if (!pixman_transform_invert(&pixTransformInverted, &pixTransform)) {
|
||||
pixman_image_unref(dest);
|
||||
pixman_image_unref(src);
|
||||
return;
|
||||
}
|
||||
pixman_image_set_transform(src, &pixTransformInverted);
|
||||
|
||||
pixman_image_composite32(PIXMAN_OP_SRC,
|
||||
src,
|
||||
nullptr,
|
||||
dest,
|
||||
aDestOffset.x,
|
||||
aDestOffset.y,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
destSize.width,
|
||||
destSize.height);
|
||||
|
||||
pixman_image_unref(dest);
|
||||
pixman_image_unref(src);
|
||||
}
|
||||
|
||||
static inline IntRect
|
||||
RoundOut(Rect r)
|
||||
{
|
||||
r.RoundOut();
|
||||
return IntRect(r.x, r.y, r.width, r.height);
|
||||
}
|
||||
|
||||
void
|
||||
BasicCompositor::DrawQuad(const gfx::Rect& aRect,
|
||||
const gfx::Rect& aClipRect,
|
||||
@ -337,20 +418,51 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
|
||||
gfx::Float aOpacity,
|
||||
const gfx::Matrix4x4 &aTransform)
|
||||
{
|
||||
DrawTarget *dest = mRenderTarget->mDrawTarget;
|
||||
RefPtr<DrawTarget> buffer = mRenderTarget
|
||||
? mRenderTarget->mDrawTarget
|
||||
: mDrawTarget;
|
||||
|
||||
if (!aTransform.Is2D()) {
|
||||
NS_WARNING("Can't handle 3D transforms yet!");
|
||||
return;
|
||||
// For 2D drawing, |dest| and |buffer| are the same surface. For 3D drawing,
|
||||
// |dest| is a temporary surface.
|
||||
RefPtr<DrawTarget> dest = buffer;
|
||||
|
||||
buffer->PushClipRect(aClipRect);
|
||||
AutoSaveTransform autoSaveTransform(dest);
|
||||
|
||||
Matrix newTransform;
|
||||
Rect transformBounds;
|
||||
gfx3DMatrix new3DTransform;
|
||||
IntPoint offset = mRenderTarget->GetOrigin();
|
||||
|
||||
if (aTransform.Is2D()) {
|
||||
newTransform = aTransform.As2D();
|
||||
} else {
|
||||
// Create a temporary surface for the transform.
|
||||
dest = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(RoundOut(aRect).Size(), FORMAT_B8G8R8A8);
|
||||
if (!dest) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the bounds post-transform.
|
||||
To3DMatrix(aTransform, new3DTransform);
|
||||
gfxRect bounds = new3DTransform.TransformBounds(ThebesRect(aRect));
|
||||
bounds.IntersectRect(bounds, gfxRect(offset.x, offset.y, buffer->GetSize().width, buffer->GetSize().height));
|
||||
|
||||
transformBounds = ToRect(bounds);
|
||||
transformBounds.RoundOut();
|
||||
|
||||
// Propagate the coordinate offset to our 2D draw target.
|
||||
newTransform.Translate(transformBounds.x, transformBounds.y);
|
||||
|
||||
// When we apply the 3D transformation, we do it against a temporary
|
||||
// surface, so undo the coordinate offset.
|
||||
new3DTransform = new3DTransform * gfx3DMatrix::Translation(-transformBounds.x, -transformBounds.y, 0);
|
||||
|
||||
transformBounds.MoveTo(0, 0);
|
||||
}
|
||||
|
||||
dest->PushClipRect(aClipRect);
|
||||
|
||||
Matrix oldTransform = dest->GetTransform();
|
||||
Matrix newTransform = aTransform.As2D();
|
||||
IntPoint offset = mRenderTarget->GetOrigin();
|
||||
newTransform.Translate(-offset.x, -offset.y);
|
||||
dest->SetTransform(newTransform);
|
||||
buffer->SetTransform(newTransform);
|
||||
|
||||
RefPtr<SourceSurface> sourceMask;
|
||||
Matrix maskTransform;
|
||||
@ -414,13 +526,28 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
|
||||
}
|
||||
}
|
||||
|
||||
if (!aTransform.Is2D()) {
|
||||
dest->Flush();
|
||||
|
||||
RefPtr<SourceSurface> snapshot = dest->Snapshot();
|
||||
RefPtr<DataSourceSurface> source = snapshot->GetDataSurface();
|
||||
RefPtr<DataSourceSurface> temp =
|
||||
Factory::CreateDataSourceSurface(RoundOut(transformBounds).Size(), FORMAT_B8G8R8A8);
|
||||
if (!temp) {
|
||||
return;
|
||||
}
|
||||
|
||||
PixmanTransform(temp, source, new3DTransform, gfxPoint(0, 0));
|
||||
|
||||
buffer->DrawSurface(temp, transformBounds, transformBounds);
|
||||
}
|
||||
|
||||
if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) {
|
||||
EffectMask *effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EFFECT_MASK].get());
|
||||
static_cast<DeprecatedTextureHost*>(effectMask->mMaskTexture)->Unlock();
|
||||
}
|
||||
|
||||
dest->SetTransform(oldTransform);
|
||||
dest->PopClip();
|
||||
buffer->PopClip();
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user