diff options
Diffstat (limited to 'gfx/2d/ExtendInputEffectD2D1.cpp')
-rw-r--r-- | gfx/2d/ExtendInputEffectD2D1.cpp | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/gfx/2d/ExtendInputEffectD2D1.cpp b/gfx/2d/ExtendInputEffectD2D1.cpp new file mode 100644 index 0000000000..1203df9a4f --- /dev/null +++ b/gfx/2d/ExtendInputEffectD2D1.cpp @@ -0,0 +1,190 @@ +/* -*- 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 "ExtendInputEffectD2D1.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='ExtendInputEffect'/> + <Property name='Author' type='string' value='Mozilla'/> + <Property name='Category' type='string' value='Utility Effects'/> + <Property name='Description' type='string' value='This effect is used to extend the output rect of any input effect to a specified rect.'/> + <Inputs> + <Input name='InputEffect'/> + </Inputs> + <Property name='OutputRect' type='vector4'> + <Property name='DisplayName' type='string' value='Output Rect'/> + </Property> + </Effect> + ); + +namespace mozilla { +namespace gfx { + +ExtendInputEffectD2D1::ExtendInputEffectD2D1() + : mRefCount(0), + mOutputRect(D2D1::Vector4F(-FLT_MAX, -FLT_MAX, FLT_MAX, FLT_MAX)) {} + +IFACEMETHODIMP +ExtendInputEffectD2D1::Initialize(ID2D1EffectContext* pContextInternal, + ID2D1TransformGraph* pTransformGraph) { + HRESULT hr; + hr = pTransformGraph->SetSingleTransformNode(this); + + if (FAILED(hr)) { + return hr; + } + + return S_OK; +} + +IFACEMETHODIMP +ExtendInputEffectD2D1::PrepareForRender(D2D1_CHANGE_TYPE changeType) { + return S_OK; +} + +IFACEMETHODIMP +ExtendInputEffectD2D1::SetGraph(ID2D1TransformGraph* pGraph) { + return E_NOTIMPL; +} + +IFACEMETHODIMP_(ULONG) +ExtendInputEffectD2D1::AddRef() { return ++mRefCount; } + +IFACEMETHODIMP_(ULONG) +ExtendInputEffectD2D1::Release() { + if (!--mRefCount) { + delete this; + return 0; + } + return mRefCount; +} + +IFACEMETHODIMP +ExtendInputEffectD2D1::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; +} + +static D2D1_RECT_L ConvertFloatToLongRect(const D2D1_VECTOR_4F& aRect) { + // Clamp values to LONG range. We can't use std::min/max here because we want + // the comparison to operate on a type that's different from the type of the + // result. + return D2D1::RectL(aRect.x <= float(LONG_MIN) ? LONG_MIN : LONG(aRect.x), + aRect.y <= float(LONG_MIN) ? LONG_MIN : LONG(aRect.y), + aRect.z >= float(LONG_MAX) ? LONG_MAX : LONG(aRect.z), + aRect.w >= float(LONG_MAX) ? LONG_MAX : LONG(aRect.w)); +} + +static D2D1_RECT_L IntersectRect(const D2D1_RECT_L& aRect1, + const D2D1_RECT_L& aRect2) { + return D2D1::RectL(std::max(aRect1.left, aRect2.left), + std::max(aRect1.top, aRect2.top), + std::min(aRect1.right, aRect2.right), + std::min(aRect1.bottom, aRect2.bottom)); +} + +IFACEMETHODIMP +ExtendInputEffectD2D1::MapInputRectsToOutputRect( + const D2D1_RECT_L* pInputRects, const D2D1_RECT_L* pInputOpaqueSubRects, + UINT32 inputRectCount, D2D1_RECT_L* pOutputRect, + D2D1_RECT_L* pOutputOpaqueSubRect) { + // This transform only accepts one input, so there will only be one input + // rect. + if (inputRectCount != 1) { + return E_INVALIDARG; + } + + // Set the output rect to the specified rect. This is the whole purpose of + // this effect. + *pOutputRect = ConvertFloatToLongRect(mOutputRect); + *pOutputOpaqueSubRect = IntersectRect(*pOutputRect, pInputOpaqueSubRects[0]); + return S_OK; +} + +IFACEMETHODIMP +ExtendInputEffectD2D1::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 +ExtendInputEffectD2D1::MapInvalidRect(UINT32 inputIndex, + D2D1_RECT_L invalidInputRect, + D2D1_RECT_L* pInvalidOutputRect) const { + MOZ_ASSERT(inputIndex == 0); + + *pInvalidOutputRect = invalidInputRect; + return S_OK; +} + +HRESULT +ExtendInputEffectD2D1::Register(ID2D1Factory1* aFactory) { + D2D1_PROPERTY_BINDING bindings[] = { + D2D1_VALUE_TYPE_BINDING(L"OutputRect", + &ExtendInputEffectD2D1::SetOutputRect, + &ExtendInputEffectD2D1::GetOutputRect), + }; + HRESULT hr = aFactory->RegisterEffectFromString( + CLSID_ExtendInputEffect, kXmlDescription, bindings, 1, CreateEffect); + + if (FAILED(hr)) { + gfxWarning() << "Failed to register extend input effect."; + } + return hr; +} + +void ExtendInputEffectD2D1::Unregister(ID2D1Factory1* aFactory) { + aFactory->UnregisterEffect(CLSID_ExtendInputEffect); +} + +HRESULT __stdcall ExtendInputEffectD2D1::CreateEffect(IUnknown** aEffectImpl) { + *aEffectImpl = static_cast<ID2D1EffectImpl*>(new ExtendInputEffectD2D1()); + (*aEffectImpl)->AddRef(); + + return S_OK; +} + +} // namespace gfx +} // namespace mozilla |