DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Header

Mercurial (a4e764f8dda4)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 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 <= LONG_MIN ? LONG_MIN : LONG(aRect.x),
                     aRect.y <= LONG_MIN ? LONG_MIN : LONG(aRect.y),
                     aRect.z >= LONG_MAX ? LONG_MAX : LONG(aRect.z),
                     aRect.w >= 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