/* -*- 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 #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( ); 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(static_cast(this)); } else if (aIID == IID_ID2D1EffectImpl) { *aPtr = static_cast(this); } else if (aIID == IID_ID2D1DrawTransform) { *aPtr = static_cast(this); } else if (aIID == IID_ID2D1Transform) { *aPtr = static_cast(this); } else if (aIID == IID_ID2D1TransformNode) { *aPtr = static_cast(this); } else { return E_NOINTERFACE; } static_cast(*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(new ExtendInputEffectD2D1()); (*aEffectImpl)->AddRef(); return S_OK; } } // namespace gfx } // namespace mozilla