зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1617396 - Implement conic-gradient for Direct2D graphics backend. r=gfx-reviewers,nical
Differential Revision: https://phabricator.services.mozilla.com/D66305
This commit is contained in:
Родитель
60847b9c4e
Коммит
021198d745
|
@ -0,0 +1,375 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#include "ConicGradientEffectD2D1.h"
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
#include "ShadersD2D1.h"
|
||||
#include "HelpersD2D.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define TEXTW(x) L##x
|
||||
#define XML(X) \
|
||||
TEXTW(#X) // This macro creates a single string from multiple lines of text.
|
||||
|
||||
static const PCWSTR kXmlDescription =
|
||||
XML(
|
||||
<?xml version='1.0'?>
|
||||
<Effect>
|
||||
<!-- System Properties -->
|
||||
<Property name='DisplayName' type='string' value='ConicGradientEffect'/>
|
||||
<Property name='Author' type='string' value='Mozilla'/>
|
||||
<Property name='Category' type='string' value='Pattern effects'/>
|
||||
<Property name='Description' type='string' value='This effect is used to render CSS conic gradients.'/>
|
||||
<Inputs>
|
||||
<Input name='Geometry'/>
|
||||
</Inputs>
|
||||
<Property name='StopCollection' type='iunknown'>
|
||||
<Property name='DisplayName' type='string' value='Gradient stop collection'/>
|
||||
</Property>
|
||||
<Property name='Center' type='vector2'>
|
||||
<Property name='DisplayName' type='string' value='Gradient center'/>
|
||||
</Property>
|
||||
<Property name='Angle' type='vector2'>
|
||||
<Property name='DisplayName' type='string' value='Gradient angle'/>
|
||||
</Property>
|
||||
<Property name='StartOffset' type='float'>
|
||||
<Property name='DisplayName' type='string' value='Start stop offset'/>
|
||||
</Property>
|
||||
<Property name='EndOffset' type='float'>
|
||||
<Property name='DisplayName' type='string' value='End stop offset'/>
|
||||
</Property>
|
||||
<Property name='Transform' type='matrix3x2'>
|
||||
<Property name='DisplayName' type='string' value='Transform applied to the pattern'/>
|
||||
</Property>
|
||||
|
||||
</Effect>
|
||||
);
|
||||
|
||||
// {091fda1d-857e-4b1e-828f-1c839d9b7897}
|
||||
static const GUID GUID_SampleConicGradientPS = {
|
||||
0x091fda1d,
|
||||
0x857e,
|
||||
0x4b1e,
|
||||
{0x82, 0x8f, 0x1c, 0x83, 0x9d, 0x9b, 0x78, 0x97}};
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
ConicGradientEffectD2D1::ConicGradientEffectD2D1()
|
||||
: mRefCount(0),
|
||||
mCenter(D2D1::Vector2F(0, 0)),
|
||||
mAngle(0),
|
||||
mStartOffset(0),
|
||||
mEndOffset(0),
|
||||
mTransform(D2D1::IdentityMatrix())
|
||||
|
||||
{}
|
||||
|
||||
IFACEMETHODIMP
|
||||
ConicGradientEffectD2D1::Initialize(ID2D1EffectContext* pContextInternal,
|
||||
ID2D1TransformGraph* pTransformGraph) {
|
||||
HRESULT hr;
|
||||
|
||||
hr = pContextInternal->LoadPixelShader(GUID_SampleConicGradientPS,
|
||||
SampleConicGradientPS,
|
||||
sizeof(SampleConicGradientPS));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = pTransformGraph->SetSingleTransformNode(this);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
mEffectContext = pContextInternal;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP
|
||||
ConicGradientEffectD2D1::PrepareForRender(D2D1_CHANGE_TYPE changeType) {
|
||||
if (changeType == D2D1_CHANGE_TYPE_NONE) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// We'll need to inverse transform our pixel, precompute inverse here.
|
||||
Matrix mat = ToMatrix(mTransform);
|
||||
if (!mat.Invert()) {
|
||||
// Singular
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (!mStopCollection) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT hr = mDrawInfo->SetPixelShader(GUID_SampleConicGradientPS);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
RefPtr<ID2D1ResourceTexture> tex = CreateGradientTexture();
|
||||
hr = mDrawInfo->SetResourceTexture(1, tex);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
struct PSConstantBuffer {
|
||||
float center[2];
|
||||
float angle;
|
||||
float start_offset;
|
||||
float end_offset;
|
||||
float repeat_correct;
|
||||
float allow_odd;
|
||||
float padding[1];
|
||||
float transform[8];
|
||||
};
|
||||
|
||||
PSConstantBuffer buffer = {
|
||||
{mCenter.x, mCenter.y},
|
||||
mAngle,
|
||||
mStartOffset,
|
||||
mEndOffset,
|
||||
mStopCollection->GetExtendMode() != D2D1_EXTEND_MODE_CLAMP ? 1.0f : 0.0f,
|
||||
mStopCollection->GetExtendMode() == D2D1_EXTEND_MODE_MIRROR ? 1.0f : 0.0f,
|
||||
{0.0f},
|
||||
{mat._11, mat._21, mat._31, 0.0f, mat._12, mat._22, mat._32, 0.0f}};
|
||||
|
||||
hr = mDrawInfo->SetPixelShaderConstantBuffer((BYTE*)&buffer, sizeof(buffer));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP
|
||||
ConicGradientEffectD2D1::SetGraph(ID2D1TransformGraph* pGraph) {
|
||||
return pGraph->SetSingleTransformNode(this);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG)
|
||||
ConicGradientEffectD2D1::AddRef() { return ++mRefCount; }
|
||||
|
||||
IFACEMETHODIMP_(ULONG)
|
||||
ConicGradientEffectD2D1::Release() {
|
||||
if (!--mRefCount) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRefCount;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP
|
||||
ConicGradientEffectD2D1::QueryInterface(const IID& aIID, void** aPtr) {
|
||||
if (!aPtr) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (aIID == IID_IUnknown) {
|
||||
*aPtr = static_cast<IUnknown*>(static_cast<ID2D1EffectImpl*>(this));
|
||||
} else if (aIID == IID_ID2D1EffectImpl) {
|
||||
*aPtr = static_cast<ID2D1EffectImpl*>(this);
|
||||
} else if (aIID == IID_ID2D1DrawTransform) {
|
||||
*aPtr = static_cast<ID2D1DrawTransform*>(this);
|
||||
} else if (aIID == IID_ID2D1Transform) {
|
||||
*aPtr = static_cast<ID2D1Transform*>(this);
|
||||
} else if (aIID == IID_ID2D1TransformNode) {
|
||||
*aPtr = static_cast<ID2D1TransformNode*>(this);
|
||||
} else {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static_cast<IUnknown*>(*aPtr)->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP
|
||||
ConicGradientEffectD2D1::MapInputRectsToOutputRect(
|
||||
const D2D1_RECT_L* pInputRects, const D2D1_RECT_L* pInputOpaqueSubRects,
|
||||
UINT32 inputRectCount, D2D1_RECT_L* pOutputRect,
|
||||
D2D1_RECT_L* pOutputOpaqueSubRect) {
|
||||
if (inputRectCount != 1) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*pOutputRect = *pInputRects;
|
||||
*pOutputOpaqueSubRect = *pInputOpaqueSubRects;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP
|
||||
ConicGradientEffectD2D1::MapOutputRectToInputRects(
|
||||
const D2D1_RECT_L* pOutputRect, D2D1_RECT_L* pInputRects,
|
||||
UINT32 inputRectCount) const {
|
||||
if (inputRectCount != 1) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*pInputRects = *pOutputRect;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP
|
||||
ConicGradientEffectD2D1::MapInvalidRect(UINT32 inputIndex,
|
||||
D2D1_RECT_L invalidInputRect,
|
||||
D2D1_RECT_L* pInvalidOutputRect) const {
|
||||
MOZ_ASSERT(inputIndex == 0);
|
||||
|
||||
*pInvalidOutputRect = invalidInputRect;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP
|
||||
ConicGradientEffectD2D1::SetDrawInfo(ID2D1DrawInfo* pDrawInfo) {
|
||||
mDrawInfo = pDrawInfo;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
ConicGradientEffectD2D1::Register(ID2D1Factory1* aFactory) {
|
||||
D2D1_PROPERTY_BINDING bindings[] = {
|
||||
D2D1_VALUE_TYPE_BINDING(L"StopCollection",
|
||||
&ConicGradientEffectD2D1::SetStopCollection,
|
||||
&ConicGradientEffectD2D1::GetStopCollection),
|
||||
D2D1_VALUE_TYPE_BINDING(L"Center", &ConicGradientEffectD2D1::SetCenter,
|
||||
&ConicGradientEffectD2D1::GetCenter),
|
||||
D2D1_VALUE_TYPE_BINDING(L"Angle", &ConicGradientEffectD2D1::SetAngle,
|
||||
&ConicGradientEffectD2D1::GetAngle),
|
||||
D2D1_VALUE_TYPE_BINDING(L"StartOffset",
|
||||
&ConicGradientEffectD2D1::SetStartOffset,
|
||||
&ConicGradientEffectD2D1::GetStartOffset),
|
||||
D2D1_VALUE_TYPE_BINDING(L"EndOffset",
|
||||
&ConicGradientEffectD2D1::SetEndOffset,
|
||||
&ConicGradientEffectD2D1::GetEndOffset),
|
||||
D2D1_VALUE_TYPE_BINDING(L"Transform",
|
||||
&ConicGradientEffectD2D1::SetTransform,
|
||||
&ConicGradientEffectD2D1::GetTransform)};
|
||||
HRESULT hr = aFactory->RegisterEffectFromString(
|
||||
CLSID_ConicGradientEffect, kXmlDescription, bindings, ARRAYSIZE(bindings),
|
||||
CreateEffect);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to register radial gradient effect.";
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
void ConicGradientEffectD2D1::Unregister(ID2D1Factory1* aFactory) {
|
||||
aFactory->UnregisterEffect(CLSID_ConicGradientEffect);
|
||||
}
|
||||
|
||||
HRESULT __stdcall ConicGradientEffectD2D1::CreateEffect(
|
||||
IUnknown** aEffectImpl) {
|
||||
*aEffectImpl = static_cast<ID2D1EffectImpl*>(new ConicGradientEffectD2D1());
|
||||
(*aEffectImpl)->AddRef();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
ConicGradientEffectD2D1::SetStopCollection(IUnknown* aStopCollection) {
|
||||
if (SUCCEEDED(aStopCollection->QueryInterface(
|
||||
(ID2D1GradientStopCollection**)getter_AddRefs(mStopCollection)))) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
already_AddRefed<ID2D1ResourceTexture>
|
||||
ConicGradientEffectD2D1::CreateGradientTexture() {
|
||||
std::vector<D2D1_GRADIENT_STOP> rawStops;
|
||||
rawStops.resize(mStopCollection->GetGradientStopCount());
|
||||
mStopCollection->GetGradientStops(&rawStops.front(), rawStops.size());
|
||||
|
||||
std::vector<unsigned char> textureData;
|
||||
textureData.resize(4096 * 4);
|
||||
unsigned char* texData = &textureData.front();
|
||||
|
||||
float prevColorPos = 0;
|
||||
float nextColorPos = rawStops[0].position;
|
||||
D2D1_COLOR_F prevColor = rawStops[0].color;
|
||||
D2D1_COLOR_F nextColor = prevColor;
|
||||
uint32_t stopPosition = 1;
|
||||
|
||||
// Not the most optimized way but this will do for now.
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
// The 4095 seems a little counter intuitive, but we want the gradient
|
||||
// color at offset 0 at the first pixel, and at offset 1.0f at the last
|
||||
// pixel.
|
||||
float pos = float(i) / 4095;
|
||||
|
||||
while (pos > nextColorPos) {
|
||||
prevColor = nextColor;
|
||||
prevColorPos = nextColorPos;
|
||||
if (rawStops.size() > stopPosition) {
|
||||
nextColor = rawStops[stopPosition].color;
|
||||
nextColorPos = rawStops[stopPosition++].position;
|
||||
} else {
|
||||
nextColorPos = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
float interp;
|
||||
|
||||
if (nextColorPos != prevColorPos) {
|
||||
interp = (pos - prevColorPos) / (nextColorPos - prevColorPos);
|
||||
} else {
|
||||
interp = 0;
|
||||
}
|
||||
|
||||
DeviceColor newColor(prevColor.r + (nextColor.r - prevColor.r) * interp,
|
||||
prevColor.g + (nextColor.g - prevColor.g) * interp,
|
||||
prevColor.b + (nextColor.b - prevColor.b) * interp,
|
||||
prevColor.a + (nextColor.a - prevColor.a) * interp);
|
||||
|
||||
// Note D2D expects RGBA here!!
|
||||
texData[i * 4] = (char)(255.0f * newColor.r);
|
||||
texData[i * 4 + 1] = (char)(255.0f * newColor.g);
|
||||
texData[i * 4 + 2] = (char)(255.0f * newColor.b);
|
||||
texData[i * 4 + 3] = (char)(255.0f * newColor.a);
|
||||
}
|
||||
|
||||
RefPtr<ID2D1ResourceTexture> tex;
|
||||
|
||||
UINT32 width = 4096;
|
||||
UINT32 stride = 4096 * 4;
|
||||
D2D1_RESOURCE_TEXTURE_PROPERTIES props;
|
||||
// Older shader models do not support 1D textures. So just use a width x 1
|
||||
// texture.
|
||||
props.dimensions = 2;
|
||||
UINT32 dims[] = {width, 1};
|
||||
props.extents = dims;
|
||||
props.channelDepth = D2D1_CHANNEL_DEPTH_4;
|
||||
props.bufferPrecision = D2D1_BUFFER_PRECISION_8BPC_UNORM;
|
||||
props.filter = D2D1_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
D2D1_EXTEND_MODE extendMode[] = {mStopCollection->GetExtendMode(),
|
||||
mStopCollection->GetExtendMode()};
|
||||
props.extendModes = extendMode;
|
||||
|
||||
HRESULT hr = mEffectContext->CreateResourceTexture(
|
||||
nullptr, &props, &textureData.front(), &stride, 4096 * 4,
|
||||
getter_AddRefs(tex));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to create resource texture: " << hexa(hr);
|
||||
}
|
||||
|
||||
return tex.forget();
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,103 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_CONICGRADIENTEFFECTD2D1_H_
|
||||
#define MOZILLA_GFX_CONICGRADIENTEFFECTD2D1_H_
|
||||
|
||||
#include <d2d1_1.h>
|
||||
#include <d2d1effectauthor.h>
|
||||
#include <d2d1effecthelpers.h>
|
||||
|
||||
#include "2D.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
// {fa4e3246-be57-4052-8c8b-881cc3633287}
|
||||
DEFINE_GUID(CLSID_ConicGradientEffect, 0xfa4e3246, 0xbe57, 0x4052, 0x8c, 0x8b,
|
||||
0x88, 0x1c, 0xc3, 0x63, 0x32, 0x87);
|
||||
|
||||
// Macro to keep our class nice and clean.
|
||||
#define SIMPLE_PROP(type, name) \
|
||||
public: \
|
||||
HRESULT Set##name(type a##name) { \
|
||||
m##name = a##name; \
|
||||
return S_OK; \
|
||||
} \
|
||||
type Get##name() const { return m##name; } \
|
||||
\
|
||||
private: \
|
||||
type m##name;
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
enum {
|
||||
CONIC_PROP_STOP_COLLECTION = 0,
|
||||
CONIC_PROP_CENTER,
|
||||
CONIC_PROP_ANGLE,
|
||||
CONIC_PROP_START_OFFSET,
|
||||
CONIC_PROP_END_OFFSET,
|
||||
CONIC_PROP_TRANSFORM
|
||||
};
|
||||
|
||||
class ConicGradientEffectD2D1 final : public ID2D1EffectImpl,
|
||||
public ID2D1DrawTransform {
|
||||
public:
|
||||
// ID2D1EffectImpl
|
||||
IFACEMETHODIMP Initialize(ID2D1EffectContext* pContextInternal,
|
||||
ID2D1TransformGraph* pTransformGraph);
|
||||
IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE changeType);
|
||||
IFACEMETHODIMP SetGraph(ID2D1TransformGraph* pGraph);
|
||||
|
||||
// IUnknown
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppOutput);
|
||||
|
||||
// ID2D1Transform
|
||||
IFACEMETHODIMP MapInputRectsToOutputRect(
|
||||
const D2D1_RECT_L* pInputRects, const D2D1_RECT_L* pInputOpaqueSubRects,
|
||||
UINT32 inputRectCount, D2D1_RECT_L* pOutputRect,
|
||||
D2D1_RECT_L* pOutputOpaqueSubRect);
|
||||
IFACEMETHODIMP MapOutputRectToInputRects(const D2D1_RECT_L* pOutputRect,
|
||||
D2D1_RECT_L* pInputRects,
|
||||
UINT32 inputRectCount) const;
|
||||
IFACEMETHODIMP MapInvalidRect(UINT32 inputIndex, D2D1_RECT_L invalidInputRect,
|
||||
D2D1_RECT_L* pInvalidOutputRect) const;
|
||||
|
||||
// ID2D1TransformNode
|
||||
IFACEMETHODIMP_(UINT32) GetInputCount() const { return 1; }
|
||||
|
||||
// ID2D1DrawTransform
|
||||
IFACEMETHODIMP SetDrawInfo(ID2D1DrawInfo* pDrawInfo);
|
||||
|
||||
static HRESULT Register(ID2D1Factory1* aFactory);
|
||||
static void Unregister(ID2D1Factory1* aFactory);
|
||||
static HRESULT __stdcall CreateEffect(IUnknown** aEffectImpl);
|
||||
|
||||
HRESULT SetStopCollection(IUnknown* aStopCollection);
|
||||
IUnknown* GetStopCollection() const { return mStopCollection; }
|
||||
|
||||
private:
|
||||
already_AddRefed<ID2D1ResourceTexture> CreateGradientTexture();
|
||||
|
||||
ConicGradientEffectD2D1();
|
||||
|
||||
uint32_t mRefCount;
|
||||
RefPtr<ID2D1GradientStopCollection> mStopCollection;
|
||||
RefPtr<ID2D1EffectContext> mEffectContext;
|
||||
RefPtr<ID2D1DrawInfo> mDrawInfo;
|
||||
SIMPLE_PROP(D2D1_VECTOR_2F, Center);
|
||||
SIMPLE_PROP(FLOAT, Angle);
|
||||
SIMPLE_PROP(FLOAT, StartOffset);
|
||||
SIMPLE_PROP(FLOAT, EndOffset);
|
||||
SIMPLE_PROP(D2D_MATRIX_3X2_F, Transform);
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
#undef SIMPLE_PROP
|
||||
|
||||
#endif
|
|
@ -13,6 +13,7 @@
|
|||
#include "SourceSurfaceCapture.h"
|
||||
#include "SourceSurfaceD2D1.h"
|
||||
#include "SourceSurfaceDual.h"
|
||||
#include "ConicGradientEffectD2D1.h"
|
||||
#include "RadialGradientEffectD2D1.h"
|
||||
#include "PathCapture.h"
|
||||
|
||||
|
@ -1340,6 +1341,7 @@ RefPtr<ID2D1Factory1> DrawTargetD2D1::factory() {
|
|||
mFactory = factory1;
|
||||
|
||||
ExtendInputEffectD2D1::Register(mFactory);
|
||||
ConicGradientEffectD2D1::Register(mFactory);
|
||||
RadialGradientEffectD2D1::Register(mFactory);
|
||||
|
||||
return mFactory;
|
||||
|
@ -1351,6 +1353,7 @@ void DrawTargetD2D1::CleanupD2D() {
|
|||
|
||||
if (mFactory) {
|
||||
RadialGradientEffectD2D1::Unregister(mFactory);
|
||||
ConicGradientEffectD2D1::Unregister(mFactory);
|
||||
ExtendInputEffectD2D1::Unregister(mFactory);
|
||||
mFactory = nullptr;
|
||||
}
|
||||
|
@ -1655,6 +1658,45 @@ void DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp,
|
|||
return;
|
||||
}
|
||||
|
||||
if (aPattern.GetType() == PatternType::CONIC_GRADIENT) {
|
||||
const ConicGradientPattern* pat =
|
||||
static_cast<const ConicGradientPattern*>(&aPattern);
|
||||
|
||||
if (!pat->mStops) {
|
||||
// Draw nothing because of no color stops
|
||||
return;
|
||||
}
|
||||
RefPtr<ID2D1Effect> conicGradientEffect;
|
||||
|
||||
HRESULT hr = mDC->CreateEffect(CLSID_ConicGradientEffect,
|
||||
getter_AddRefs(conicGradientEffect));
|
||||
if (FAILED(hr) || !conicGradientEffect) {
|
||||
gfxWarning() << "Failed to create conic gradient effect. Code: "
|
||||
<< hexa(hr);
|
||||
return;
|
||||
}
|
||||
|
||||
conicGradientEffect->SetValue(
|
||||
CONIC_PROP_STOP_COLLECTION,
|
||||
static_cast<const GradientStopsD2D*>(pat->mStops.get())
|
||||
->mStopCollection);
|
||||
conicGradientEffect->SetValue(
|
||||
CONIC_PROP_CENTER, D2D1::Vector2F(pat->mCenter.x, pat->mCenter.y));
|
||||
conicGradientEffect->SetValue(CONIC_PROP_ANGLE, pat->mAngle);
|
||||
conicGradientEffect->SetValue(CONIC_PROP_START_OFFSET, pat->mStartOffset);
|
||||
conicGradientEffect->SetValue(CONIC_PROP_END_OFFSET, pat->mEndOffset);
|
||||
conicGradientEffect->SetValue(CONIC_PROP_TRANSFORM,
|
||||
D2DMatrix(pat->mMatrix * mTransform));
|
||||
conicGradientEffect->SetInput(0, source);
|
||||
|
||||
mDC->DrawImage(conicGradientEffect,
|
||||
D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR,
|
||||
D2DCompositionMode(aOp));
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aPattern.GetType() == PatternType::RADIAL_GRADIENT);
|
||||
|
||||
const RadialGradientPattern* pat =
|
||||
static_cast<const RadialGradientPattern*>(&aPattern);
|
||||
if (pat->mCenter1 == pat->mCenter2 && pat->mRadius1 == pat->mRadius2) {
|
||||
|
|
|
@ -311,6 +311,10 @@ static inline D2D1_PRIMITIVE_BLEND D2DPrimitiveBlendMode(CompositionOp aOp) {
|
|||
}
|
||||
|
||||
static inline bool IsPatternSupportedByD2D(const Pattern& aPattern) {
|
||||
if (aPattern.GetType() == PatternType::CONIC_GRADIENT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aPattern.GetType() != PatternType::RADIAL_GRADIENT) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,16 @@ cbuffer cb2
|
|||
float sq_radius1;
|
||||
}
|
||||
|
||||
cbuffer cb3
|
||||
{
|
||||
float3x3 DeviceSpaceToUserSpace_cb3;
|
||||
float2 dimensions_cb3;
|
||||
float2 center;
|
||||
float angle;
|
||||
float start_offset;
|
||||
float end_offset;
|
||||
}
|
||||
|
||||
struct VS_OUTPUT
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
|
@ -51,6 +61,13 @@ struct VS_RADIAL_OUTPUT
|
|||
float2 PixelCoord : TEXCOORD1;
|
||||
};
|
||||
|
||||
struct VS_CONIC_OUTPUT
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float2 MaskTexCoord : TEXCOORD0;
|
||||
float2 PixelCoord : TEXCOORD1;
|
||||
};
|
||||
|
||||
struct PS_TEXT_OUTPUT
|
||||
{
|
||||
float4 color;
|
||||
|
@ -175,6 +192,25 @@ VS_RADIAL_OUTPUT SampleRadialVS(float3 pos : POSITION)
|
|||
return Output;
|
||||
}
|
||||
|
||||
VS_CONIC_OUTPUT SampleConicVS(float3 pos : POSITION)
|
||||
{
|
||||
VS_CONIC_OUTPUT Output;
|
||||
Output.Position.w = 1.0f;
|
||||
Output.Position.x = pos.x * QuadDesc.z + QuadDesc.x;
|
||||
Output.Position.y = pos.y * QuadDesc.w + QuadDesc.y;
|
||||
Output.Position.z = 0;
|
||||
Output.MaskTexCoord.x = pos.x * MaskTexCoords.z + MaskTexCoords.x;
|
||||
Output.MaskTexCoord.y = pos.y * MaskTexCoords.w + MaskTexCoords.y;
|
||||
|
||||
// For the conic gradient pixel shader we need to pass in the pixel's
|
||||
// coordinates in user space for the color to be correctly determined.
|
||||
|
||||
Output.PixelCoord.x = ((Output.Position.x + 1.0f) / 2.0f) * dimensions_cb3.x;
|
||||
Output.PixelCoord.y = ((1.0f - Output.Position.y) / 2.0f) * dimensions_cb3.y;
|
||||
Output.PixelCoord.xy = mul(float3(Output.PixelCoord.x, Output.PixelCoord.y, 1.0f), DeviceSpaceToUserSpace_cb3).xy;
|
||||
return Output;
|
||||
}
|
||||
|
||||
float Screen(float a, float b)
|
||||
{
|
||||
return 1 - ((1 - a)*(1 - b));
|
||||
|
@ -521,6 +557,23 @@ float4 SampleRadialGradientA0PS( VS_RADIAL_OUTPUT In, uniform sampler aSampler )
|
|||
return output;
|
||||
};
|
||||
|
||||
float4 SampleConicGradientPS(VS_CONIC_OUTPUT In, uniform sampler aSampler) : SV_Target
|
||||
{
|
||||
float2 current_dir = In.PixelCoord - center;
|
||||
float current_angle = atan2(current_dir.y, current_dir.x) + (3.141592 / 2.0 - angle);
|
||||
float offset = fmod(current_angle / (2.0 * 3.141592), 1.0) - start_offset;
|
||||
offset = offset / (end_offset - start_offset);
|
||||
|
||||
float upper_t = lerp(0, 1, offset);
|
||||
|
||||
float4 output = tex.Sample(aSampler, float2(upper_t, 0.5));
|
||||
// Premultiply
|
||||
output.rgb *= output.a;
|
||||
// Multiply the output color by the input mask for the operation.
|
||||
output *= mask.Sample(sMaskSampler, In.MaskTexCoord).a;
|
||||
return output;
|
||||
};
|
||||
|
||||
float4 SampleShadowHPS( VS_OUTPUT In) : SV_Target
|
||||
{
|
||||
float outputStrength = 0;
|
||||
|
@ -682,6 +735,31 @@ technique10 SampleRadialGradient
|
|||
}
|
||||
}
|
||||
|
||||
technique10 SampleConicGradient
|
||||
{
|
||||
pass APos
|
||||
{
|
||||
SetRasterizerState(TextureRast);
|
||||
SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleConicVS()));
|
||||
SetGeometryShader(NULL);
|
||||
SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleConicGradientPS( sSampler )));
|
||||
}
|
||||
pass APosWrap
|
||||
{
|
||||
SetRasterizerState(TextureRast);
|
||||
SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleConicVS()));
|
||||
SetGeometryShader(NULL);
|
||||
SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleConicGradientPS( sWrapSampler )));
|
||||
}
|
||||
pass APosMirror
|
||||
{
|
||||
SetRasterizerState(TextureRast);
|
||||
SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleConicVS()));
|
||||
SetGeometryShader(NULL);
|
||||
SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleConicGradientPS( sMirrorSampler )));
|
||||
}
|
||||
}
|
||||
|
||||
technique10 SampleMaskedTexture
|
||||
{
|
||||
pass P0
|
||||
|
|
26874
gfx/2d/ShadersD2D.h
26874
gfx/2d/ShadersD2D.h
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
2607
gfx/2d/ShadersD2D1.h
2607
gfx/2d/ShadersD2D1.h
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,7 +8,7 @@ SamplerState InputSampler : register(s0);
|
|||
Texture2D GradientTexture : register(t1);
|
||||
SamplerState GradientSampler : register(s1);
|
||||
|
||||
cbuffer constants : register(b0)
|
||||
cbuffer radialGradientConstants : register(b0)
|
||||
{
|
||||
// Precalculate as much as we can!
|
||||
float3 diff : packoffset(c0.x);
|
||||
|
@ -26,6 +26,51 @@ cbuffer constants : register(b0)
|
|||
float3x2 transform : packoffset(c3.x);
|
||||
}
|
||||
|
||||
cbuffer conicGradientConstants : register(b0)
|
||||
{
|
||||
float2 center : packoffset(c0.x);
|
||||
float angle : packoffset(c0.z);
|
||||
float start_offset : packoffset(c0.w);
|
||||
float end_offset : packoffset(c1.x);
|
||||
|
||||
// The next two values are used for a hack to compensate for an apparent
|
||||
// bug in D2D where the GradientSampler SamplerState doesn't get the
|
||||
// correct addressing modes.
|
||||
float repeat_correct_conic : packoffset(c1.y);
|
||||
float allow_odd_conic : packoffset(c1.z);
|
||||
|
||||
float3x2 transform_conic : packoffset(c2.x);
|
||||
}
|
||||
|
||||
|
||||
static const float M_PI = 3.14159265f;
|
||||
|
||||
float4 SampleConicGradientPS(
|
||||
float4 clipSpaceOutput : SV_POSITION,
|
||||
float4 sceneSpaceOutput : SCENE_POSITION,
|
||||
float4 texelSpaceInput0 : TEXCOORD0
|
||||
) : SV_Target
|
||||
{
|
||||
float2 p = float2(sceneSpaceOutput.x * transform_conic._11 + sceneSpaceOutput.y * transform_conic._21 + transform_conic._31,
|
||||
sceneSpaceOutput.x * transform_conic._12 + sceneSpaceOutput.y * transform_conic._22 + transform_conic._32);
|
||||
float2 dir = float2(
|
||||
-(center.y - p.y),
|
||||
(center.x - p.x));
|
||||
float vstart = start_offset;
|
||||
float vend = end_offset;
|
||||
float n = 1/(vend-vstart);
|
||||
float current_angle = atan2(dir.y, dir.x)-angle;
|
||||
float lambda = fmod(n*current_angle/M_PI/2+vend-vstart+.5,1);
|
||||
float offset = lambda;
|
||||
float4 output = GradientTexture.Sample(GradientSampler, float2(offset, 0.5));
|
||||
// Premultiply
|
||||
output.rgb *= output.a;
|
||||
// Multiply the output color by the input mask for the operation.
|
||||
output *= InputTexture.Sample(InputSampler, texelSpaceInput0.xy);
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
float4 SampleRadialGradientPS(
|
||||
float4 clipSpaceOutput : SV_POSITION,
|
||||
float4 sceneSpaceOutput : SCENE_POSITION,
|
||||
|
|
|
@ -7,4 +7,6 @@ fxc ShadersD2D1.hlsl -ESampleRadialGradientPS -nologo -Tps_4_0_level_9_3 -Fhtmpf
|
|||
cat tmpfile > ShadersD2D1.h
|
||||
fxc ShadersD2D1.hlsl -ESampleRadialGradientA0PS -nologo -Tps_4_0_level_9_3 -Fhtmpfile -VnSampleRadialGradientA0PS
|
||||
cat tmpfile >> ShadersD2D1.h
|
||||
fxc ShadersD2D1.hlsl -ESampleConicGradientPS -nologo -Tps_4_0_level_9_3 -Fhtmpfile -VnSampleConicGradientPS
|
||||
cat tmpfile >> ShadersD2D1.h
|
||||
rm tmpfile
|
||||
|
|
|
@ -80,6 +80,7 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
|||
'UnscaledFontGDI.h',
|
||||
]
|
||||
SOURCES += [
|
||||
'ConicGradientEffectD2D1.cpp',
|
||||
'DrawTargetD2D1.cpp',
|
||||
'ExtendInputEffectD2D1.cpp',
|
||||
'FilterNodeD2D1.cpp',
|
||||
|
|
Загрузка…
Ссылка в новой задаче