BackingStoreBackendDirect2DImpl.cpp   [plain text]


/*
 * Copyright (C) 2019 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "BackingStoreBackendDirect2DImpl.h"

#if USE(DIRECT2D)

#include "Direct2DUtilities.h"
#include "FloatPoint.h"
#include "FloatSize.h"
#include "ImageDecoderDirect2D.h"
#include "IntRect.h"
#include "IntSize.h"
#include <d3d11_1.h>
#include <wincodec.h>

namespace WebCore {

static const Seconds scrollHysteresisDuration { 300_ms };

BackingStoreBackendDirect2DImpl::BackingStoreBackendDirect2DImpl(const IntSize& size, float deviceScaleFactor, ID3D11Device1* device)
    : BackingStoreBackendDirect2D(size, device)
    , m_scrolledHysteresis([this](PAL::HysteresisState state) {
        if (state == PAL::HysteresisState::Stopped)
            m_scrollSurface = nullptr;
        }, scrollHysteresisDuration)
{
    IntSize scaledSize = m_size;
    scaledSize.scale(deviceScaleFactor);

    m_dxSurface = WebCore::Direct2D::createDXGISurfaceOfSize(scaledSize, m_device.get(), false);
    m_renderTarget = WebCore::Direct2D::createSurfaceRenderTarget(m_dxSurface.get());

    auto bitmapProperties = Direct2D::bitmapProperties();
    HRESULT hr = m_renderTarget->CreateSharedBitmap(__uuidof(IDXGISurface1), reinterpret_cast<void*>(m_dxSurface.get()), &bitmapProperties, &m_surface);
    RELEASE_ASSERT(SUCCEEDED(hr));
}

BackingStoreBackendDirect2DImpl::~BackingStoreBackendDirect2DImpl()
{
}

void BackingStoreBackendDirect2DImpl::scroll(const IntRect& scrollRect, const IntSize& scrollOffset)
{
    IntRect sourceRect = scrollRect;
    sourceRect.move(-scrollOffset);
    sourceRect.intersect(scrollRect);

    if (sourceRect.isEmpty())
        return;

    if (!m_scrollSurface || scrollRect.size() != m_scrollSurfaceSize) {
#ifndef _NDEBUG
        ASSERT(m_size.width() >= scrollRect.size().width());
        ASSERT(m_size.height() >= scrollRect.size().height());
#endif
        m_scrollSurfaceSize = sourceRect.size();
        m_dxScrollSurface = WebCore::Direct2D::createDXGISurfaceOfSize(m_scrollSurfaceSize, m_device.get(), false);

        m_scrollSurface = nullptr;
        auto bitmapProperties = Direct2D::bitmapProperties();
        HRESULT hr = m_renderTarget->CreateSharedBitmap(__uuidof(IDXGISurface1), reinterpret_cast<void*>(m_dxScrollSurface.get()), &bitmapProperties, &m_scrollSurface);
        RELEASE_ASSERT(SUCCEEDED(hr));
    }

    auto sourceRectLocation = IntSize(sourceRect.x(), sourceRect.y());
    auto destRectLocation = IntSize(); // Top left corner of scroll surface
    Direct2D::copyRectFromOneSurfaceToAnother(m_surface.get(), m_scrollSurface.get(), sourceRectLocation, sourceRect, destRectLocation);

    IntRect destRect = scrollRect;
    destRect.setHeight(sourceRect.height());
    destRect.setWidth(sourceRect.width());

    IntSize destPosition;
    if (scrollOffset.width() > 0 || scrollOffset.height() > 0) {
        destPosition.setWidth(std::min(scrollRect.width(), scrollOffset.width()));
        destPosition.setHeight(std::min(scrollRect.height(), scrollOffset.height()));
    }

    auto sourceScrollSurfaceLocation = IntSize(); // Top left corner of scroll surface
    Direct2D::copyRectFromOneSurfaceToAnother(m_scrollSurface.get(), m_surface.get(), sourceScrollSurfaceLocation, destRect, destPosition);

    m_scrolledHysteresis.impulse();
}

ID2D1BitmapBrush* BackingStoreBackendDirect2DImpl::bitmapBrush()
{
    if (!m_renderTarget || !m_surface)
        return nullptr;

    if (!m_bitmapBrush) {
        auto bitmapBrushProperties = D2D1::BitmapBrushProperties();
        auto brushProperties = D2D1::BrushProperties();

        HRESULT hr = m_renderTarget->CreateBitmapBrush(m_surface.get(), &bitmapBrushProperties, &brushProperties, &m_bitmapBrush);
        ASSERT(SUCCEEDED(hr));
    }

    return m_bitmapBrush.get();
}

} // namespace WebCore

#endif // USE(DIRECT2D)