1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "ExtendInputEffectD2D1.h"
8
9 #include "Logging.h"
10
11 #include "ShadersD2D1.h"
12 #include "HelpersD2D.h"
13
14 #include <vector>
15
16 #define TEXTW(x) L##x
17 #define XML(X) \
18 TEXTW(#X) // This macro creates a single string from multiple lines of text.
19
20 static const PCWSTR kXmlDescription =
21 XML(
22 <?xml version='1.0'?>
23 <Effect>
24 <!-- System Properties -->
25 <Property name='DisplayName' type='string' value='ExtendInputEffect'/>
26 <Property name='Author' type='string' value='Mozilla'/>
27 <Property name='Category' type='string' value='Utility Effects'/>
28 <Property name='Description' type='string' value='This effect is used to extend the output rect of any input effect to a specified rect.'/>
29 <Inputs>
30 <Input name='InputEffect'/>
31 </Inputs>
32 <Property name='OutputRect' type='vector4'>
33 <Property name='DisplayName' type='string' value='Output Rect'/>
34 </Property>
35 </Effect>
36 );
37
38 namespace mozilla {
39 namespace gfx {
40
ExtendInputEffectD2D1()41 ExtendInputEffectD2D1::ExtendInputEffectD2D1()
42 : mRefCount(0),
43 mOutputRect(D2D1::Vector4F(-FLT_MAX, -FLT_MAX, FLT_MAX, FLT_MAX)) {}
44
45 IFACEMETHODIMP
Initialize(ID2D1EffectContext * pContextInternal,ID2D1TransformGraph * pTransformGraph)46 ExtendInputEffectD2D1::Initialize(ID2D1EffectContext* pContextInternal,
47 ID2D1TransformGraph* pTransformGraph) {
48 HRESULT hr;
49 hr = pTransformGraph->SetSingleTransformNode(this);
50
51 if (FAILED(hr)) {
52 return hr;
53 }
54
55 return S_OK;
56 }
57
58 IFACEMETHODIMP
PrepareForRender(D2D1_CHANGE_TYPE changeType)59 ExtendInputEffectD2D1::PrepareForRender(D2D1_CHANGE_TYPE changeType) {
60 return S_OK;
61 }
62
63 IFACEMETHODIMP
SetGraph(ID2D1TransformGraph * pGraph)64 ExtendInputEffectD2D1::SetGraph(ID2D1TransformGraph* pGraph) {
65 return E_NOTIMPL;
66 }
67
IFACEMETHODIMP_(ULONG)68 IFACEMETHODIMP_(ULONG)
69 ExtendInputEffectD2D1::AddRef() { return ++mRefCount; }
70
IFACEMETHODIMP_(ULONG)71 IFACEMETHODIMP_(ULONG)
72 ExtendInputEffectD2D1::Release() {
73 if (!--mRefCount) {
74 delete this;
75 return 0;
76 }
77 return mRefCount;
78 }
79
80 IFACEMETHODIMP
QueryInterface(const IID & aIID,void ** aPtr)81 ExtendInputEffectD2D1::QueryInterface(const IID& aIID, void** aPtr) {
82 if (!aPtr) {
83 return E_POINTER;
84 }
85
86 if (aIID == IID_IUnknown) {
87 *aPtr = static_cast<IUnknown*>(static_cast<ID2D1EffectImpl*>(this));
88 } else if (aIID == IID_ID2D1EffectImpl) {
89 *aPtr = static_cast<ID2D1EffectImpl*>(this);
90 } else if (aIID == IID_ID2D1DrawTransform) {
91 *aPtr = static_cast<ID2D1DrawTransform*>(this);
92 } else if (aIID == IID_ID2D1Transform) {
93 *aPtr = static_cast<ID2D1Transform*>(this);
94 } else if (aIID == IID_ID2D1TransformNode) {
95 *aPtr = static_cast<ID2D1TransformNode*>(this);
96 } else {
97 return E_NOINTERFACE;
98 }
99
100 static_cast<IUnknown*>(*aPtr)->AddRef();
101 return S_OK;
102 }
103
ConvertFloatToLongRect(const D2D1_VECTOR_4F & aRect)104 static D2D1_RECT_L ConvertFloatToLongRect(const D2D1_VECTOR_4F& aRect) {
105 // Clamp values to LONG range. We can't use std::min/max here because we want
106 // the comparison to operate on a type that's different from the type of the
107 // result.
108 return D2D1::RectL(aRect.x <= LONG_MIN ? LONG_MIN : LONG(aRect.x),
109 aRect.y <= LONG_MIN ? LONG_MIN : LONG(aRect.y),
110 aRect.z >= LONG_MAX ? LONG_MAX : LONG(aRect.z),
111 aRect.w >= LONG_MAX ? LONG_MAX : LONG(aRect.w));
112 }
113
IntersectRect(const D2D1_RECT_L & aRect1,const D2D1_RECT_L & aRect2)114 static D2D1_RECT_L IntersectRect(const D2D1_RECT_L& aRect1,
115 const D2D1_RECT_L& aRect2) {
116 return D2D1::RectL(std::max(aRect1.left, aRect2.left),
117 std::max(aRect1.top, aRect2.top),
118 std::min(aRect1.right, aRect2.right),
119 std::min(aRect1.bottom, aRect2.bottom));
120 }
121
122 IFACEMETHODIMP
MapInputRectsToOutputRect(const D2D1_RECT_L * pInputRects,const D2D1_RECT_L * pInputOpaqueSubRects,UINT32 inputRectCount,D2D1_RECT_L * pOutputRect,D2D1_RECT_L * pOutputOpaqueSubRect)123 ExtendInputEffectD2D1::MapInputRectsToOutputRect(
124 const D2D1_RECT_L* pInputRects, const D2D1_RECT_L* pInputOpaqueSubRects,
125 UINT32 inputRectCount, D2D1_RECT_L* pOutputRect,
126 D2D1_RECT_L* pOutputOpaqueSubRect) {
127 // This transform only accepts one input, so there will only be one input
128 // rect.
129 if (inputRectCount != 1) {
130 return E_INVALIDARG;
131 }
132
133 // Set the output rect to the specified rect. This is the whole purpose of
134 // this effect.
135 *pOutputRect = ConvertFloatToLongRect(mOutputRect);
136 *pOutputOpaqueSubRect = IntersectRect(*pOutputRect, pInputOpaqueSubRects[0]);
137 return S_OK;
138 }
139
140 IFACEMETHODIMP
MapOutputRectToInputRects(const D2D1_RECT_L * pOutputRect,D2D1_RECT_L * pInputRects,UINT32 inputRectCount) const141 ExtendInputEffectD2D1::MapOutputRectToInputRects(const D2D1_RECT_L* pOutputRect,
142 D2D1_RECT_L* pInputRects,
143 UINT32 inputRectCount) const {
144 if (inputRectCount != 1) {
145 return E_INVALIDARG;
146 }
147
148 *pInputRects = *pOutputRect;
149 return S_OK;
150 }
151
152 IFACEMETHODIMP
MapInvalidRect(UINT32 inputIndex,D2D1_RECT_L invalidInputRect,D2D1_RECT_L * pInvalidOutputRect) const153 ExtendInputEffectD2D1::MapInvalidRect(UINT32 inputIndex,
154 D2D1_RECT_L invalidInputRect,
155 D2D1_RECT_L* pInvalidOutputRect) const {
156 MOZ_ASSERT(inputIndex == 0);
157
158 *pInvalidOutputRect = invalidInputRect;
159 return S_OK;
160 }
161
162 HRESULT
Register(ID2D1Factory1 * aFactory)163 ExtendInputEffectD2D1::Register(ID2D1Factory1* aFactory) {
164 D2D1_PROPERTY_BINDING bindings[] = {
165 D2D1_VALUE_TYPE_BINDING(L"OutputRect",
166 &ExtendInputEffectD2D1::SetOutputRect,
167 &ExtendInputEffectD2D1::GetOutputRect),
168 };
169 HRESULT hr = aFactory->RegisterEffectFromString(
170 CLSID_ExtendInputEffect, kXmlDescription, bindings, 1, CreateEffect);
171
172 if (FAILED(hr)) {
173 gfxWarning() << "Failed to register extend input effect.";
174 }
175 return hr;
176 }
177
Unregister(ID2D1Factory1 * aFactory)178 void ExtendInputEffectD2D1::Unregister(ID2D1Factory1* aFactory) {
179 aFactory->UnregisterEffect(CLSID_ExtendInputEffect);
180 }
181
CreateEffect(IUnknown ** aEffectImpl)182 HRESULT __stdcall ExtendInputEffectD2D1::CreateEffect(IUnknown** aEffectImpl) {
183 *aEffectImpl = static_cast<ID2D1EffectImpl*>(new ExtendInputEffectD2D1());
184 (*aEffectImpl)->AddRef();
185
186 return S_OK;
187 }
188
189 } // namespace gfx
190 } // namespace mozilla
191